main.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 # Copyright (c) 2011, Dirk Thomas, Dorian Scholz, TU Darmstadt
4 # All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 #
10 # * Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # * Redistributions in binary form must reproduce the above
13 # copyright notice, this list of conditions and the following
14 # disclaimer in the documentation and/or other materials provided
15 # with the distribution.
16 # * Neither the name of the TU Darmstadt nor the names of its
17 # contributors may be used to endorse or promote products derived
18 # from this software without specific prior written permission.
19 #
20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 # POSSIBILITY OF SUCH DAMAGE.
32 
33 from __future__ import print_function
34 
35 from argparse import ArgumentParser, SUPPRESS
36 import os
37 import platform
38 import signal
39 import sys
40 
41 
42 class Main(object):
43 
44  main_filename = None
45 
46  def __init__(self, qtgui_path, invoked_filename=None, settings_filename=None):
47  self._qtgui_path = qtgui_path
48  if invoked_filename is None:
49  invoked_filename = os.path.abspath(__file__)
50  Main.main_filename = invoked_filename
51  if settings_filename is None:
52  settings_filename = 'qt_gui'
53  self._settings_filename = settings_filename
54 
55  self.plugin_providers = []
56  self._options = None
57 
58  # check if DBus is available
59  self._dbus_available = False
60  try:
61  # use qt/glib mainloop integration to get dbus mainloop working
62  from dbus.mainloop.glib import DBusGMainLoop
63  DBusGMainLoop(set_as_default=True)
64  import dbus
65  try:
66  # before being able to check if a session bus is available the dbus
67  # mainloop must be set up
68  dbus.SessionBus()
69  self._dbus_available = True
70  except dbus.exceptions.DBusException:
71  pass
72  except ImportError:
73  pass
74 
75  def add_arguments(self, parser, standalone=False, plugin_argument_provider=None):
76  common_group = parser.add_argument_group('Options for GUI instance')
77  common_group.add_argument(
78  '-b', '--qt-binding', dest='qt_binding', type=str, metavar='BINDING',
79  help='choose Qt bindings to be used [pyqt|pyside]')
80  common_group.add_argument(
81  '--clear-config', dest='clear_config', default=False, action='store_true',
82  help='clear the configuration (including all perspectives and plugin settings)')
83  if not standalone:
84  common_group.add_argument(
85  '-f', '--freeze-layout', dest='freeze_layout', action='store_true',
86  help='freeze the layout of the GUI (prevent rearranging widgets, disable '
87  'undock/redock)')
88  common_group.add_argument(
89  '--force-discover', dest='force_discover', default=False, action='store_true',
90  help='force a rediscover of plugins')
91  common_group.add_argument(
92  '-h', '--help', action='help', help='show this help message and exit')
93  if not standalone:
94  common_group.add_argument(
95  '-l', '--lock-perspective', dest='lock_perspective', action='store_true',
96  help='lock the GUI to the used perspective (hide menu bar and close buttons of '
97  'plugins)')
98  common_group.add_argument(
99  '-ht', '--hide-title', dest='hide_title', action='store_true',
100  help='hide the title label, the icon, and the help button (combine with -l and -f '
101  'to eliminate the entire title bar and reclaim the space)')
102 
103  common_group.add_argument(
104  '-p', '--perspective', dest='perspective', type=str, metavar='PERSPECTIVE',
105  help='start with this named perspective')
106  common_group.add_argument(
107  '--perspective-file', dest='perspective_file', type=str,
108  metavar='PERSPECTIVE_FILE', help='start with a perspective loaded from a file')
109  common_group.add_argument(
110  '--reload-import', dest='reload_import', default=False, action='store_true',
111  help='reload every imported module')
112  if not standalone:
113  common_group.add_argument(
114  '-s', '--standalone', dest='standalone_plugin', type=str, metavar='PLUGIN',
115  help='start only this plugin (implies -l). To pass arguments to the plugin use '
116  '--args')
117  common_group.add_argument(
118  '-t', '--on-top', dest='on_top', default=False, action='store_true',
119  help='set window mode to always on top')
120  common_group.add_argument(
121  '-v', '--verbose', dest='verbose', default=False, action='store_true',
122  help='output qDebug messages')
123 
124  if not standalone:
125  common_group.add_argument(
126  '--args', dest='plugin_args', nargs='*', type=str,
127  help='arbitrary arguments which are passes to the plugin '
128  '(only with -s, --command-start-plugin or --embed-plugin). '
129  'It must be the last option since it collects all following options.')
130 
131  group = parser.add_argument_group(
132  'Options to query information without starting a GUI instance',
133  'These options can be used to query information about valid arguments for various '
134  'options.')
135  group.add_argument(
136  '--list-perspectives', dest='list_perspectives', action='store_true',
137  help='list available perspectives')
138  group.add_argument(
139  '--list-plugins', dest='list_plugins', action='store_true',
140  help='list available plugins')
141  parser.add_argument_group(group)
142 
143  group = parser.add_argument_group(
144  'Options to operate on a running GUI instance',
145  'These options can be used to perform actions on a running GUI instance.')
146  group.add_argument(
147  '--command-pid', dest='command_pid', type=int, metavar='PID',
148  help='pid of the GUI instance to operate on, defaults to oldest running GUI '
149  'instance')
150  group.add_argument(
151  '--command-start-plugin', dest='command_start_plugin', type=str, metavar='PLUGIN',
152  help='start plugin')
153  group.add_argument(
154  '--command-switch-perspective', dest='command_switch_perspective', type=str,
155  metavar='PERSPECTIVE', help='switch perspective')
156  if not self._dbus_available:
157  group.description = 'These options are not available since DBus is not available!'
158  for o in group._group_actions:
159  o.help = SUPPRESS
160  parser.add_argument_group(group)
161 
162  group = parser.add_argument_group(
163  'Special options for embedding widgets from separate processes',
164  'These options should never be used on the CLI but only from the GUI code itself.')
165  group.add_argument(
166  '--embed-plugin', dest='embed_plugin', type=str, metavar='PLUGIN',
167  help='embed a plugin into an already running GUI instance (requires all other '
168  '--embed-* options)')
169  group.add_argument(
170  '--embed-plugin-serial', dest='embed_plugin_serial', type=int, metavar='SERIAL',
171  help='serial number of plugin to be embedded '
172  '(requires all other --embed-* options)')
173  group.add_argument(
174  '--embed-plugin-address', dest='embed_plugin_address', type=str, metavar='ADDRESS',
175  help='dbus server address of the GUI instance to embed plugin into '
176  '(requires all other --embed-* options)')
177  for o in group._group_actions:
178  o.help = SUPPRESS
179  parser.add_argument_group(group)
180 
181  if plugin_argument_provider:
182  plugin_argument_provider(parser)
183 
184  return common_group
185 
187  pass
188 
189  def _add_reload_paths(self, reload_importer):
190  reload_importer.add_reload_path(os.path.join(os.path.dirname(__file__), *('..',) * 4))
191 
193  from python_qt_binding.QtGui import QIcon
194  # TODO find a better way to verify Theme standard compliance
195  if QIcon.themeName() == '' or \
196  QIcon.fromTheme('document-save').isNull() or \
197  QIcon.fromTheme('document-open').isNull() or \
198  QIcon.fromTheme('edit-cut').isNull() or \
199  QIcon.fromTheme('object-flip-horizontal').isNull():
200  if 'darwin' in platform.platform().lower() and \
201  '/usr/local/share/icons' not in QIcon.themeSearchPaths():
202  QIcon.setThemeSearchPaths(QIcon.themeSearchPaths() + ['/usr/local/share/icons'])
203  original_theme = QIcon.themeName()
204  QIcon.setThemeName('Tango')
205  if QIcon.fromTheme('document-save').isNull():
206  QIcon.setThemeName(original_theme)
207 
208  def create_application(self, argv):
209  from python_qt_binding.QtCore import Qt
210  from python_qt_binding.QtWidgets import QApplication
211  app = QApplication(argv)
212  app.setAttribute(Qt.AA_DontShowIconsInMenus, False)
213  return app
214 
215  def main(self, argv=None, standalone=None, plugin_argument_provider=None,
216  plugin_manager_settings_prefix=''):
217  if argv is None:
218  argv = sys.argv
219 
220  # extract --args and everything behind manually since argparse can not handle that
221  arguments = argv[1:]
222 
223  # extract plugin specific args when not being invoked in standalone mode programmatically
224  if not standalone:
225  plugin_args = []
226  if '--args' in arguments:
227  index = arguments.index('--args')
228  plugin_args = arguments[index + 1:]
229  arguments = arguments[0:index + 1]
230 
231  parser = ArgumentParser(os.path.basename(Main.main_filename), add_help=False)
232  self.add_arguments(parser, standalone=bool(standalone),
233  plugin_argument_provider=plugin_argument_provider)
234  self._options = parser.parse_args(arguments)
235 
236  if standalone:
237  # rerun parsing to separate common arguments from plugin specific arguments
238  parser = ArgumentParser(os.path.basename(Main.main_filename), add_help=False)
239  self.add_arguments(parser, standalone=bool(standalone))
240  self._options, plugin_args = parser.parse_known_args(arguments)
241  self._options.multi_process = False # not supported anymore
242  self._options.plugin_args = plugin_args
243 
244  # set default values for options not available in standalone mode
245  if standalone:
246  self._options.freeze_layout = False
247  self._options.lock_perspective = False
248  self._options.hide_title = False
249  self._options.perspective = None
250  self._options.perspective_file = None
251  self._options.standalone_plugin = standalone
252  self._options.list_perspectives = False
253  self._options.list_plugins = False
254  self._options.command_pid = None
255  self._options.command_start_plugin = None
256  self._options.command_switch_perspective = None
257  self._options.embed_plugin = None
258  self._options.embed_plugin_serial = None
259  self._options.embed_plugin_address = None
260 
261  # check option dependencies
262  try:
263  if self._options.plugin_args and \
264  not self._options.standalone_plugin and \
265  not self._options.command_start_plugin and \
266  not self._options.embed_plugin:
267  raise RuntimeError(
268  'Option --args can only be used together with either --standalone, '
269  '--command-start-plugin or --embed-plugin option')
270 
271  if self._options.freeze_layout and not self._options.lock_perspective:
272  raise RuntimeError(
273  'Option --freeze_layout can only be used together with the '
274  '--lock_perspective option')
275 
276  list_options = (self._options.list_perspectives, self._options.list_plugins)
277  list_options_set = [opt for opt in list_options if opt is not False]
278  if len(list_options_set) > 1:
279  raise RuntimeError('Only one --list-* option can be used at a time')
280 
281  command_options = (
282  self._options.command_start_plugin, self._options.command_switch_perspective)
283  command_options_set = [opt for opt in command_options if opt is not None]
284  if len(command_options_set) > 0 and not self._dbus_available:
285  raise RuntimeError(
286  'Without DBus support the --command-* options are not available')
287  if len(command_options_set) > 1:
288  raise RuntimeError(
289  'Only one --command-* option can be used at a time (except --command-pid '
290  'which is optional)')
291  if len(command_options_set) == 0 and self._options.command_pid is not None:
292  raise RuntimeError(
293  'Option --command_pid can only be used together with an other --command-* '
294  'option')
295 
296  embed_options = (
297  self._options.embed_plugin, self._options.embed_plugin_serial,
298  self._options.embed_plugin_address)
299  embed_options_set = [opt for opt in embed_options if opt is not None]
300  if len(command_options_set) > 0 and not self._dbus_available:
301  raise RuntimeError('Without DBus support the --embed-* options are not available')
302  if len(embed_options_set) > 0 and len(embed_options_set) < len(embed_options):
303  raise RuntimeError('Missing option(s) - all \'--embed-*\' options must be set')
304 
305  if len(embed_options_set) > 0 and self._options.clear_config:
306  raise RuntimeError(
307  'Option --clear-config can only be used without any --embed-* option')
308 
309  groups = (list_options_set, command_options_set, embed_options_set)
310  groups_set = [opt for opt in groups if len(opt) > 0]
311  if len(groups_set) > 1:
312  raise RuntimeError(
313  'Options from different groups (--list, --command, --embed) can not be used '
314  'together')
315 
316  perspective_options = (self._options.perspective, self._options.perspective_file)
317  perspective_options_set = [opt for opt in perspective_options if opt is not None]
318  if len(perspective_options_set) > 1:
319  raise RuntimeError('Only one --perspective-* option can be used at a time')
320 
321  if self._options.perspective_file is not None and \
322  not os.path.isfile(self._options.perspective_file):
323  raise RuntimeError('Option --perspective-file must reference existing file')
324 
325  except RuntimeError as e:
326  print(str(e))
327  # parser.parse_args(['--help'])
328  # calling --help will exit
329  return 1
330 
331  # set implicit option dependencies
332  if self._options.standalone_plugin is not None:
333  self._options.lock_perspective = True
334 
335  # create application context containing various relevant information
336  from .application_context import ApplicationContext
337  context = ApplicationContext()
338  context.qtgui_path = self._qtgui_path
339  context.options = self._options
340 
341  if self._dbus_available:
342  from dbus import DBusException, Interface, SessionBus
343 
344  # non-special applications provide various dbus interfaces
345  if self._dbus_available:
346  context.provide_app_dbus_interfaces = len(groups_set) == 0
347  context.dbus_base_bus_name = 'org.ros.qt_gui'
348  if context.provide_app_dbus_interfaces:
349  context.dbus_unique_bus_name = context.dbus_base_bus_name + '.pid%d' % os.getpid()
350 
351  # provide pid of application via dbus
352  from .application_dbus_interface import ApplicationDBusInterface
353  _dbus_server = ApplicationDBusInterface(context.dbus_base_bus_name) # noqa: F841
354 
355  # determine host bus name, either based on pid given on command line or
356  # via dbus application interface if any other instance is available
357  if len(command_options_set) > 0 or len(embed_options_set) > 0:
358  host_pid = None
359  if self._options.command_pid is not None:
360  host_pid = self._options.command_pid
361  else:
362  try:
363  remote_object = SessionBus().get_object(
364  context.dbus_base_bus_name, '/Application')
365  except DBusException:
366  pass
367  else:
368  remote_interface = Interface(
369  remote_object, context.dbus_base_bus_name + '.Application')
370  host_pid = remote_interface.get_pid()
371  if host_pid is not None:
372  context.dbus_host_bus_name = context.dbus_base_bus_name + '.pid%d' % host_pid
373 
374  # execute command on host application instance
375  if len(command_options_set) > 0:
376  if self._options.command_start_plugin is not None:
377  try:
378  remote_object = SessionBus().get_object(
379  context.dbus_host_bus_name, '/PluginManager')
380  except DBusException:
381  (rc, msg) = (1, 'unable to communicate with GUI instance "%s"' %
382  context.dbus_host_bus_name)
383  else:
384  remote_interface = Interface(
385  remote_object, context.dbus_base_bus_name + '.PluginManager')
386  (rc, msg) = remote_interface.start_plugin(
387  self._options.command_start_plugin, ' '.join(self._options.plugin_args))
388  if rc == 0:
389  print('qt_gui_main() started plugin "%s" in GUI "%s"' %
390  (msg, context.dbus_host_bus_name))
391  else:
392  print('qt_gui_main() could not start plugin "%s" in GUI "%s": %s' %
393  (self._options.command_start_plugin, context.dbus_host_bus_name, msg))
394  return rc
395  elif self._options.command_switch_perspective is not None:
396  remote_object = SessionBus().get_object(
397  context.dbus_host_bus_name, '/PerspectiveManager')
398  remote_interface = Interface(
399  remote_object, context.dbus_base_bus_name + '.PerspectiveManager')
400  remote_interface.switch_perspective(self._options.command_switch_perspective)
401  print('qt_gui_main() switched to perspective "%s" in GUI "%s"' %
402  (self._options.command_switch_perspective, context.dbus_host_bus_name))
403  return 0
404  raise RuntimeError('Unknown command not handled')
405 
406  # choose selected or default qt binding
407  setattr(sys, 'SELECT_QT_BINDING', self._options.qt_binding)
408  from python_qt_binding import QT_BINDING
409 
410  from python_qt_binding.QtCore import (qDebug, qInstallMessageHandler,
411  QSettings, Qt, QtCriticalMsg, QtDebugMsg)
412  from python_qt_binding.QtCore import QtFatalMsg, QTimer, QtWarningMsg
413 
414  from python_qt_binding.QtGui import QIcon
415  from python_qt_binding.QtWidgets import QAction
416 
417  from .about_handler import AboutHandler
418  from .composite_plugin_provider import CompositePluginProvider
419  from .container_manager import ContainerManager
420  from .help_provider import HelpProvider
421  from .icon_loader import get_icon
422  from .main_window import MainWindow
423  from .minimized_dock_widgets_toolbar import MinimizedDockWidgetsToolbar
424  from .perspective_manager import PerspectiveManager
425  from .plugin_manager import PluginManager
426 
427  # TODO PySide2 segfaults when invoking this custom message handler atm
428  if QT_BINDING != 'pyside':
429  def message_handler(type_, context, msg):
430  colored_output = 'TERM' in os.environ and 'ANSI_COLORS_DISABLED' not in os.environ
431  cyan_color = '\033[36m' if colored_output else ''
432  red_color = '\033[31m' if colored_output else ''
433  reset_color = '\033[0m' if colored_output else ''
434  if type_ == QtDebugMsg and self._options.verbose:
435  print(msg, file=sys.stderr)
436  elif type_ == QtWarningMsg:
437  print(cyan_color + msg + reset_color, file=sys.stderr)
438  elif type_ == QtCriticalMsg:
439  print(red_color + msg + reset_color, file=sys.stderr)
440  elif type_ == QtFatalMsg:
441  print(red_color + msg + reset_color, file=sys.stderr)
442  sys.exit(1)
443  qInstallMessageHandler(message_handler)
444 
445  app = self.create_application(argv)
446 
448 
449  settings = QSettings(
450  QSettings.IniFormat, QSettings.UserScope, 'ros.org', self._settings_filename)
451  if len(embed_options_set) == 0:
452  if self._options.clear_config:
453  settings.clear()
454 
455  main_window = MainWindow()
456  if self._options.on_top:
457  main_window.setWindowFlags(Qt.WindowStaysOnTopHint)
458 
459  main_window.statusBar()
460 
461  def sigint_handler(*args):
462  qDebug('\nsigint_handler()')
463  main_window.close()
464  signal.signal(signal.SIGINT, sigint_handler)
465  # the timer enables triggering the sigint_handler
466  timer = QTimer()
467  timer.start(500)
468  timer.timeout.connect(lambda: None)
469 
470  if not self._options.lock_perspective:
471  menu_bar = main_window.menuBar()
472  file_menu = menu_bar.addMenu(menu_bar.tr('&File'))
473  action = QAction(file_menu.tr('&Quit'), file_menu)
474  action.setIcon(QIcon.fromTheme('application-exit'))
475  action.triggered.connect(main_window.close)
476  file_menu.addAction(action)
477  else:
478  menu_bar = None
479 
480  else:
481  app.setQuitOnLastWindowClosed(False)
482 
483  main_window = None
484  menu_bar = None
485 
486  self._add_plugin_providers()
487 
488  # setup plugin manager
489  plugin_provider = CompositePluginProvider(self.plugin_providers)
490  plugin_manager = PluginManager(
491  plugin_provider, settings, context, settings_prefix=plugin_manager_settings_prefix)
492 
493  if self._options.list_plugins:
494  # output available plugins
495  print('\n'.join(sorted(plugin_manager.get_plugins().values())))
496  return 0
497 
498  help_provider = HelpProvider()
499  plugin_manager.plugin_help_signal.connect(help_provider.plugin_help_request)
500 
501  # setup perspective manager
502  if main_window is not None:
503  perspective_manager = PerspectiveManager(settings, context)
504 
505  if self._options.list_perspectives:
506  # output available perspectives
507  print('\n'.join(sorted(perspective_manager.perspectives)))
508  return 0
509  else:
510  perspective_manager = None
511 
512  if main_window is not None:
513  container_manager = ContainerManager(main_window, plugin_manager)
514  plugin_manager.set_main_window(main_window, menu_bar, container_manager)
515 
516  if not self._options.freeze_layout:
517  minimized_dock_widgets_toolbar = MinimizedDockWidgetsToolbar(
518  container_manager, main_window)
519  main_window.addToolBar(Qt.BottomToolBarArea, minimized_dock_widgets_toolbar)
520  plugin_manager.set_minimized_dock_widgets_toolbar(minimized_dock_widgets_toolbar)
521 
522  if menu_bar is not None:
523  perspective_menu = menu_bar.addMenu(menu_bar.tr('P&erspectives'))
524  perspective_manager.set_menu(perspective_menu)
525 
526  # connect various signals and slots
527  if perspective_manager is not None and main_window is not None:
528  # signal changed perspective to update window title
529  perspective_manager.perspective_changed_signal.connect(main_window.perspective_changed)
530  # signal new settings due to changed perspective
531  perspective_manager.save_settings_signal.connect(main_window.save_settings)
532  perspective_manager.restore_settings_signal.connect(main_window.restore_settings)
533  perspective_manager.restore_settings_without_plugin_changes_signal.connect(
534  main_window.restore_settings)
535 
536  if perspective_manager is not None and plugin_manager is not None:
537  perspective_manager.save_settings_signal.connect(plugin_manager.save_settings)
538  plugin_manager.save_settings_completed_signal.connect(
539  perspective_manager.save_settings_completed)
540  perspective_manager.restore_settings_signal.connect(plugin_manager.restore_settings)
541  perspective_manager.restore_settings_without_plugin_changes_signal.connect(
542  plugin_manager.restore_settings_without_plugins)
543 
544  if plugin_manager is not None and main_window is not None:
545  # signal before changing plugins to save window state
546  plugin_manager.plugins_about_to_change_signal.connect(main_window.save_setup)
547  # signal changed plugins to restore window state
548  plugin_manager.plugins_changed_signal.connect(main_window.restore_state)
549  # signal save settings to store plugin setup on close
550  main_window.save_settings_before_close_signal.connect(plugin_manager.close_application)
551  # signal save and shutdown called for all plugins, trigger closing main window again
552  plugin_manager.close_application_signal.connect(
553  main_window.close, type=Qt.QueuedConnection)
554 
555  if main_window is not None and menu_bar is not None:
556  about_handler = AboutHandler(context.qtgui_path, main_window)
557  help_menu = menu_bar.addMenu(menu_bar.tr('&Help'))
558  action = QAction(help_menu.tr('&About'), help_menu)
559  action.setIcon(QIcon.fromTheme('help-about'))
560  action.triggered.connect(about_handler.show)
561  help_menu.addAction(action)
562 
563  # set initial size - only used without saved configuration
564  if main_window is not None:
565  main_window.resize(600, 450)
566  main_window.move(100, 100)
567 
568  # ensure that qt_gui/src is in sys.path
569  src_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
570  if src_path not in sys.path:
571  sys.path.append(src_path)
572 
573  # load specific plugin
574  plugin = None
575  plugin_serial = None
576  if self._options.embed_plugin is not None:
577  plugin = self._options.embed_plugin
578  plugin_serial = self._options.embed_plugin_serial
579  elif self._options.standalone_plugin is not None:
580  plugin = self._options.standalone_plugin
581  plugin_serial = 0
582  if plugin is not None:
583  plugins = plugin_manager.find_plugins_by_name(plugin)
584  if len(plugins) == 0:
585  print('qt_gui_main() found no plugin matching "%s"' % plugin)
586  print('try passing the option "--force-discover"')
587  return 1
588  elif len(plugins) > 1:
589  print('qt_gui_main() found multiple plugins matching "%s"\n%s' %
590  (plugin, '\n'.join(plugins.values())))
591  return 1
592  plugin = list(plugins.keys())[0]
593 
594  qDebug('QtBindingHelper using %s' % QT_BINDING)
595 
596  plugin_manager.discover()
597 
598  if self._options.reload_import:
599  qDebug('ReloadImporter() automatically reload all subsequent imports')
600  from .reload_importer import ReloadImporter
601  _reload_importer = ReloadImporter()
602  self._add_reload_paths(_reload_importer)
603  _reload_importer.enable()
604 
605  # switch perspective
606  if perspective_manager is not None:
607  if plugin:
608  perspective_manager.set_perspective(plugin, hide_and_without_plugin_changes=True)
609  elif self._options.perspective_file:
610  perspective_manager.import_perspective_from_file(
611  self._options.perspective_file,
612  perspective_manager.HIDDEN_PREFIX + os.path.basename(
613  self._options.perspective_file))
614  else:
615  perspective_manager.set_perspective(self._options.perspective)
616 
617  # load specific plugin
618  if plugin:
619  plugin_manager.load_plugin(plugin, plugin_serial, self._options.plugin_args)
620  running = plugin_manager.is_plugin_running(plugin, plugin_serial)
621  if not running:
622  return 1
623  if self._options.standalone_plugin:
624  # use icon of standalone plugin (if available) for application
625  plugin_descriptor = plugin_manager.get_plugin_descriptor(plugin)
626  action_attributes = plugin_descriptor.action_attributes()
627  if 'icon' in action_attributes and action_attributes['icon'] is not None:
628  base_path = plugin_descriptor.attributes().get('plugin_path')
629  try:
630  icon = get_icon(
631  action_attributes['icon'],
632  action_attributes.get('icontype', None),
633  base_path)
634  except UserWarning:
635  pass
636  else:
637  app.setWindowIcon(icon)
638 
639  if main_window is not None:
640  main_window.show()
641  if sys.platform == 'darwin':
642  main_window.raise_()
643 
644  return app.exec_()
645 
646 
647 if __name__ == '__main__':
648  main = Main()
649  sys.exit(main.main())
def _add_plugin_providers(self)
Definition: main.py:186
def create_application(self, argv)
Definition: main.py:208
_settings_filename
Definition: main.py:53
def main(self, argv=None, standalone=None, plugin_argument_provider=None, plugin_manager_settings_prefix='')
Definition: main.py:216
def __init__(self, qtgui_path, invoked_filename=None, settings_filename=None)
Definition: main.py:46
def add_arguments(self, parser, standalone=False, plugin_argument_provider=None)
Definition: main.py:75
def _check_icon_theme_compliance(self)
Definition: main.py:192
def _add_reload_paths(self, reload_importer)
Definition: main.py:189
def get_icon(name, type_=None, base_path=None)
Definition: icon_loader.py:39


qt_gui
Author(s): Dirk Thomas
autogenerated on Thu Jun 6 2019 19:54:27