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.fromTheme('document-save').isNull() or \
196  QIcon.fromTheme('document-open').isNull() or \
197  QIcon.fromTheme('edit-cut').isNull() or \
198  QIcon.fromTheme('object-flip-horizontal').isNull():
199  if platform.system() == 'Darwin' and \
200  '/usr/local/share/icons' not in QIcon.themeSearchPaths():
201  QIcon.setThemeSearchPaths(QIcon.themeSearchPaths() + ['/usr/local/share/icons'])
202  original_theme = QIcon.themeName()
203  QIcon.setThemeName('Tango')
204  if QIcon.fromTheme('document-save').isNull():
205  QIcon.setThemeName(original_theme)
206 
207  def create_application(self, argv):
208  from python_qt_binding.QtCore import Qt
209  from python_qt_binding.QtWidgets import QApplication
210  app = QApplication(argv)
211  app.setAttribute(Qt.AA_DontShowIconsInMenus, False)
212  return app
213 
214  def main(self, argv=None, standalone=None, plugin_argument_provider=None,
215  plugin_manager_settings_prefix=''):
216  if argv is None:
217  argv = sys.argv
218 
219  # extract --args and everything behind manually since argparse can not handle that
220  arguments = argv[1:]
221 
222  # extract plugin specific args when not being invoked in standalone mode programmatically
223  if not standalone:
224  plugin_args = []
225  if '--args' in arguments:
226  index = arguments.index('--args')
227  plugin_args = arguments[index + 1:]
228  arguments = arguments[0:index + 1]
229 
230  parser = ArgumentParser(os.path.basename(Main.main_filename), add_help=False)
231  self.add_arguments(parser, standalone=bool(standalone),
232  plugin_argument_provider=plugin_argument_provider)
233  self._options = parser.parse_args(arguments)
234 
235  if standalone:
236  # rerun parsing to separate common arguments from plugin specific arguments
237  parser = ArgumentParser(os.path.basename(Main.main_filename), add_help=False)
238  self.add_arguments(parser, standalone=bool(standalone))
239  self._options, plugin_args = parser.parse_known_args(arguments)
240  self._options.multi_process = False # not supported anymore
241  self._options.plugin_args = plugin_args
242 
243  # set default values for options not available in standalone mode
244  if standalone:
245  self._options.freeze_layout = False
246  self._options.lock_perspective = False
247  self._options.hide_title = False
248  self._options.perspective = None
249  self._options.perspective_file = None
250  self._options.standalone_plugin = standalone
251  self._options.list_perspectives = False
252  self._options.list_plugins = False
253  self._options.command_pid = None
254  self._options.command_start_plugin = None
255  self._options.command_switch_perspective = None
256  self._options.embed_plugin = None
257  self._options.embed_plugin_serial = None
258  self._options.embed_plugin_address = None
259 
260  # check option dependencies
261  try:
262  if self._options.plugin_args and \
263  not self._options.standalone_plugin and \
264  not self._options.command_start_plugin and \
265  not self._options.embed_plugin:
266  raise RuntimeError(
267  'Option --args can only be used together with either --standalone, '
268  '--command-start-plugin or --embed-plugin option')
269 
270  if self._options.freeze_layout and not self._options.lock_perspective:
271  raise RuntimeError(
272  'Option --freeze_layout can only be used together with the '
273  '--lock_perspective option')
274 
275  list_options = (self._options.list_perspectives, self._options.list_plugins)
276  list_options_set = [opt for opt in list_options if opt is not False]
277  if len(list_options_set) > 1:
278  raise RuntimeError('Only one --list-* option can be used at a time')
279 
280  command_options = (
281  self._options.command_start_plugin, self._options.command_switch_perspective)
282  command_options_set = [opt for opt in command_options if opt is not None]
283  if len(command_options_set) > 0 and not self._dbus_available:
284  raise RuntimeError(
285  'Without DBus support the --command-* options are not available')
286  if len(command_options_set) > 1:
287  raise RuntimeError(
288  'Only one --command-* option can be used at a time (except --command-pid '
289  'which is optional)')
290  if len(command_options_set) == 0 and self._options.command_pid is not None:
291  raise RuntimeError(
292  'Option --command_pid can only be used together with an other --command-* '
293  'option')
294 
295  embed_options = (
296  self._options.embed_plugin, self._options.embed_plugin_serial,
297  self._options.embed_plugin_address)
298  embed_options_set = [opt for opt in embed_options if opt is not None]
299  if len(command_options_set) > 0 and not self._dbus_available:
300  raise RuntimeError('Without DBus support the --embed-* options are not available')
301  if len(embed_options_set) > 0 and len(embed_options_set) < len(embed_options):
302  raise RuntimeError('Missing option(s) - all \'--embed-*\' options must be set')
303 
304  if len(embed_options_set) > 0 and self._options.clear_config:
305  raise RuntimeError(
306  'Option --clear-config can only be used without any --embed-* option')
307 
308  groups = (list_options_set, command_options_set, embed_options_set)
309  groups_set = [opt for opt in groups if len(opt) > 0]
310  if len(groups_set) > 1:
311  raise RuntimeError(
312  'Options from different groups (--list, --command, --embed) can not be used '
313  'together')
314 
315  perspective_options = (self._options.perspective, self._options.perspective_file)
316  perspective_options_set = [opt for opt in perspective_options if opt is not None]
317  if len(perspective_options_set) > 1:
318  raise RuntimeError('Only one --perspective-* option can be used at a time')
319 
320  if self._options.perspective_file is not None and \
321  not os.path.isfile(self._options.perspective_file):
322  raise RuntimeError('Option --perspective-file must reference existing file')
323 
324  except RuntimeError as e:
325  print(str(e))
326  # parser.parse_args(['--help'])
327  # calling --help will exit
328  return 1
329 
330  # set implicit option dependencies
331  if self._options.standalone_plugin is not None:
332  self._options.lock_perspective = True
333 
334  # create application context containing various relevant information
335  from .application_context import ApplicationContext
336  context = ApplicationContext()
337  context.qtgui_path = self._qtgui_path
338  context.options = self._options
339 
340  if self._dbus_available:
341  from dbus import DBusException, Interface, SessionBus
342 
343  # non-special applications provide various dbus interfaces
344  if self._dbus_available:
345  context.provide_app_dbus_interfaces = len(groups_set) == 0
346  context.dbus_base_bus_name = 'org.ros.qt_gui'
347  if context.provide_app_dbus_interfaces:
348  context.dbus_unique_bus_name = context.dbus_base_bus_name + '.pid%d' % os.getpid()
349 
350  # provide pid of application via dbus
351  from .application_dbus_interface import ApplicationDBusInterface
352  _dbus_server = ApplicationDBusInterface(context.dbus_base_bus_name) # noqa: F841
353 
354  # determine host bus name, either based on pid given on command line or
355  # via dbus application interface if any other instance is available
356  if len(command_options_set) > 0 or len(embed_options_set) > 0:
357  host_pid = None
358  if self._options.command_pid is not None:
359  host_pid = self._options.command_pid
360  else:
361  try:
362  remote_object = SessionBus().get_object(
363  context.dbus_base_bus_name, '/Application')
364  except DBusException:
365  pass
366  else:
367  remote_interface = Interface(
368  remote_object, context.dbus_base_bus_name + '.Application')
369  host_pid = remote_interface.get_pid()
370  if host_pid is not None:
371  context.dbus_host_bus_name = context.dbus_base_bus_name + '.pid%d' % host_pid
372 
373  # execute command on host application instance
374  if len(command_options_set) > 0:
375  if self._options.command_start_plugin is not None:
376  try:
377  remote_object = SessionBus().get_object(
378  context.dbus_host_bus_name, '/PluginManager')
379  except DBusException:
380  (rc, msg) = (1, 'unable to communicate with GUI instance "%s"' %
381  context.dbus_host_bus_name)
382  else:
383  remote_interface = Interface(
384  remote_object, context.dbus_base_bus_name + '.PluginManager')
385  (rc, msg) = remote_interface.start_plugin(
386  self._options.command_start_plugin, ' '.join(self._options.plugin_args))
387  if rc == 0:
388  print('qt_gui_main() started plugin "%s" in GUI "%s"' %
389  (msg, context.dbus_host_bus_name))
390  else:
391  print('qt_gui_main() could not start plugin "%s" in GUI "%s": %s' %
392  (self._options.command_start_plugin, context.dbus_host_bus_name, msg))
393  return rc
394  elif self._options.command_switch_perspective is not None:
395  remote_object = SessionBus().get_object(
396  context.dbus_host_bus_name, '/PerspectiveManager')
397  remote_interface = Interface(
398  remote_object, context.dbus_base_bus_name + '.PerspectiveManager')
399  remote_interface.switch_perspective(self._options.command_switch_perspective)
400  print('qt_gui_main() switched to perspective "%s" in GUI "%s"' %
401  (self._options.command_switch_perspective, context.dbus_host_bus_name))
402  return 0
403  raise RuntimeError('Unknown command not handled')
404 
405  # choose selected or default qt binding
406  setattr(sys, 'SELECT_QT_BINDING', self._options.qt_binding)
407  from python_qt_binding import QT_BINDING
408 
409  from python_qt_binding.QtCore import (qDebug, qInstallMessageHandler,
410  QSettings, Qt, QtCriticalMsg, QtDebugMsg)
411  from python_qt_binding.QtCore import QtFatalMsg, QTimer, QtWarningMsg
412 
413  from python_qt_binding.QtGui import QIcon
414  from python_qt_binding.QtWidgets import QAction
415 
416  from .about_handler import AboutHandler
417  from .composite_plugin_provider import CompositePluginProvider
418  from .container_manager import ContainerManager
419  from .help_provider import HelpProvider
420  from .icon_loader import get_icon
421  from .main_window import MainWindow
422  from .minimized_dock_widgets_toolbar import MinimizedDockWidgetsToolbar
423  from .perspective_manager import PerspectiveManager
424  from .plugin_manager import PluginManager
425 
426  # TODO PySide2 segfaults when invoking this custom message handler atm
427  if QT_BINDING != 'pyside':
428  def message_handler(type_, context, msg):
429  colored_output = 'TERM' in os.environ and 'ANSI_COLORS_DISABLED' not in os.environ
430  cyan_color = '\033[36m' if colored_output else ''
431  red_color = '\033[31m' if colored_output else ''
432  reset_color = '\033[0m' if colored_output else ''
433  if type_ == QtDebugMsg and self._options.verbose:
434  print(msg, file=sys.stderr)
435  elif type_ == QtWarningMsg:
436  print(cyan_color + msg + reset_color, file=sys.stderr)
437  elif type_ == QtCriticalMsg:
438  print(red_color + msg + reset_color, file=sys.stderr)
439  elif type_ == QtFatalMsg:
440  print(red_color + msg + reset_color, file=sys.stderr)
441  sys.exit(1)
442  qInstallMessageHandler(message_handler)
443 
444  app = self.create_application(argv)
445 
447 
448  settings = QSettings(
449  QSettings.IniFormat, QSettings.UserScope, 'ros.org', self._settings_filename)
450  if len(embed_options_set) == 0:
451  if self._options.clear_config:
452  settings.clear()
453 
454  main_window = MainWindow()
455  if self._options.on_top:
456  main_window.setWindowFlags(Qt.WindowStaysOnTopHint)
457 
458  main_window.statusBar()
459 
460  def sigint_handler(*args):
461  qDebug('\nsigint_handler()')
462  main_window.close()
463  signal.signal(signal.SIGINT, sigint_handler)
464  # the timer enables triggering the sigint_handler
465  timer = QTimer()
466  timer.start(500)
467  timer.timeout.connect(lambda: None)
468 
469  if not self._options.lock_perspective:
470  menu_bar = main_window.menuBar()
471  file_menu = menu_bar.addMenu(menu_bar.tr('&File'))
472  action = QAction(file_menu.tr('&Quit'), file_menu)
473  action.setIcon(QIcon.fromTheme('application-exit'))
474  action.triggered.connect(main_window.close)
475  file_menu.addAction(action)
476  else:
477  menu_bar = None
478 
479  else:
480  app.setQuitOnLastWindowClosed(False)
481 
482  main_window = None
483  menu_bar = None
484 
485  self._add_plugin_providers()
486 
487  # setup plugin manager
488  plugin_provider = CompositePluginProvider(self.plugin_providers)
489  plugin_manager = PluginManager(
490  plugin_provider, settings, context, settings_prefix=plugin_manager_settings_prefix)
491 
492  if self._options.list_plugins:
493  # output available plugins
494  print('\n'.join(sorted(plugin_manager.get_plugins().values())))
495  return 0
496 
497  help_provider = HelpProvider()
498  plugin_manager.plugin_help_signal.connect(help_provider.plugin_help_request)
499 
500  # setup perspective manager
501  if main_window is not None:
502  perspective_manager = PerspectiveManager(settings, context)
503 
504  if self._options.list_perspectives:
505  # output available perspectives
506  print('\n'.join(sorted(perspective_manager.perspectives)))
507  return 0
508  else:
509  perspective_manager = None
510 
511  if main_window is not None:
512  container_manager = ContainerManager(main_window, plugin_manager)
513  plugin_manager.set_main_window(main_window, menu_bar, container_manager)
514 
515  if not self._options.freeze_layout:
516  minimized_dock_widgets_toolbar = MinimizedDockWidgetsToolbar(
517  container_manager, main_window)
518  main_window.addToolBar(Qt.BottomToolBarArea, minimized_dock_widgets_toolbar)
519  plugin_manager.set_minimized_dock_widgets_toolbar(minimized_dock_widgets_toolbar)
520 
521  if menu_bar is not None:
522  perspective_menu = menu_bar.addMenu(menu_bar.tr('P&erspectives'))
523  perspective_manager.set_menu(perspective_menu)
524 
525  # connect various signals and slots
526  if perspective_manager is not None and main_window is not None:
527  # signal changed perspective to update window title
528  perspective_manager.perspective_changed_signal.connect(main_window.perspective_changed)
529  # signal new settings due to changed perspective
530  perspective_manager.save_settings_signal.connect(main_window.save_settings)
531  perspective_manager.restore_settings_signal.connect(main_window.restore_settings)
532  perspective_manager.restore_settings_without_plugin_changes_signal.connect(
533  main_window.restore_settings)
534 
535  if perspective_manager is not None and plugin_manager is not None:
536  perspective_manager.save_settings_signal.connect(plugin_manager.save_settings)
537  plugin_manager.save_settings_completed_signal.connect(
538  perspective_manager.save_settings_completed)
539  perspective_manager.restore_settings_signal.connect(plugin_manager.restore_settings)
540  perspective_manager.restore_settings_without_plugin_changes_signal.connect(
541  plugin_manager.restore_settings_without_plugins)
542 
543  if plugin_manager is not None and main_window is not None:
544  # signal before changing plugins to save window state
545  plugin_manager.plugins_about_to_change_signal.connect(main_window.save_setup)
546  # signal changed plugins to restore window state
547  plugin_manager.plugins_changed_signal.connect(main_window.restore_state)
548  # signal save settings to store plugin setup on close
549  main_window.save_settings_before_close_signal.connect(plugin_manager.close_application)
550  # signal save and shutdown called for all plugins, trigger closing main window again
551  plugin_manager.close_application_signal.connect(
552  main_window.close, type=Qt.QueuedConnection)
553 
554  if main_window is not None and menu_bar is not None:
555  about_handler = AboutHandler(context.qtgui_path, main_window)
556  help_menu = menu_bar.addMenu(menu_bar.tr('&Help'))
557  action = QAction(help_menu.tr('&About'), help_menu)
558  action.setIcon(QIcon.fromTheme('help-about'))
559  action.triggered.connect(about_handler.show)
560  help_menu.addAction(action)
561 
562  # set initial size - only used without saved configuration
563  if main_window is not None:
564  # Adjust size to fit the widget if standalone (e.g. single plugin)
565  if standalone:
566  main_window.adjustSize()
567  # On "clean" startup set some size to fully display the menu bar
568  else:
569  main_window.resize(600, 450)
570  main_window.move(100, 100)
571 
572  # ensure that qt_gui/src is in sys.path
573  src_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
574  if src_path not in sys.path:
575  sys.path.append(src_path)
576 
577  # load specific plugin
578  plugin = None
579  plugin_serial = None
580  if self._options.embed_plugin is not None:
581  plugin = self._options.embed_plugin
582  plugin_serial = self._options.embed_plugin_serial
583  elif self._options.standalone_plugin is not None:
584  plugin = self._options.standalone_plugin
585  plugin_serial = 0
586  if plugin is not None:
587  plugins = plugin_manager.find_plugins_by_name(plugin)
588  if len(plugins) == 0:
589  print('qt_gui_main() found no plugin matching "%s"' % plugin)
590  print('try passing the option "--force-discover"')
591  return 1
592  elif len(plugins) > 1:
593  print('qt_gui_main() found multiple plugins matching "%s"\n%s' %
594  (plugin, '\n'.join(plugins.values())))
595  return 1
596  plugin = list(plugins.keys())[0]
597 
598  qDebug('QtBindingHelper using %s' % QT_BINDING)
599 
600  plugin_manager.discover()
601 
602  if self._options.reload_import:
603  qDebug('ReloadImporter() automatically reload all subsequent imports')
604  from .reload_importer import ReloadImporter
605  _reload_importer = ReloadImporter()
606  self._add_reload_paths(_reload_importer)
607  _reload_importer.enable()
608 
609  # switch perspective
610  if perspective_manager is not None:
611  if plugin:
612  perspective_manager.set_perspective(plugin, hide_and_without_plugin_changes=True)
613  elif self._options.perspective_file:
614  perspective_manager.import_perspective_from_file(
615  self._options.perspective_file,
616  perspective_manager.HIDDEN_PREFIX + os.path.basename(
617  self._options.perspective_file))
618  else:
619  perspective_manager.set_perspective(self._options.perspective)
620 
621  # load specific plugin
622  if plugin:
623  plugin_manager.load_plugin(plugin, plugin_serial, self._options.plugin_args)
624  running = plugin_manager.is_plugin_running(plugin, plugin_serial)
625  if not running:
626  return 1
627  if self._options.standalone_plugin:
628  # use icon of standalone plugin (if available) for application
629  plugin_descriptor = plugin_manager.get_plugin_descriptor(plugin)
630  action_attributes = plugin_descriptor.action_attributes()
631  if 'icon' in action_attributes and action_attributes['icon'] is not None:
632  base_path = plugin_descriptor.attributes().get('plugin_path')
633  try:
634  icon = get_icon(
635  action_attributes['icon'],
636  action_attributes.get('icontype', None),
637  base_path)
638  except UserWarning:
639  pass
640  else:
641  app.setWindowIcon(icon)
642 
643  if main_window is not None:
644  main_window.show()
645  if sys.platform == 'darwin':
646  main_window.raise_()
647 
648  return app.exec_()
649 
650 
651 if __name__ == '__main__':
652  main = Main()
653  sys.exit(main.main())
def _add_plugin_providers(self)
Definition: main.py:186
def create_application(self, argv)
Definition: main.py:207
_settings_filename
Definition: main.py:53
def main(self, argv=None, standalone=None, plugin_argument_provider=None, plugin_manager_settings_prefix='')
Definition: main.py:215
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 Tue Apr 13 2021 03:03:12