main.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 # Copyright (c) 2011, Dirk Thomas, Dorian Scholz, TU Darmstadt
00004 # All rights reserved.
00005 #
00006 # Redistribution and use in source and binary forms, with or without
00007 # modification, are permitted provided that the following conditions
00008 # are met:
00009 #
00010 #   * Redistributions of source code must retain the above copyright
00011 #     notice, this list of conditions and the following disclaimer.
00012 #   * Redistributions in binary form must reproduce the above
00013 #     copyright notice, this list of conditions and the following
00014 #     disclaimer in the documentation and/or other materials provided
00015 #     with the distribution.
00016 #   * Neither the name of the TU Darmstadt nor the names of its
00017 #     contributors may be used to endorse or promote products derived
00018 #     from this software without specific prior written permission.
00019 #
00020 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00024 # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00027 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00028 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00030 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00031 # POSSIBILITY OF SUCH DAMAGE.
00032 
00033 from __future__ import print_function
00034 
00035 from argparse import ArgumentParser, SUPPRESS
00036 import os
00037 import platform
00038 import signal
00039 import sys
00040 
00041 
00042 class Main(object):
00043 
00044     main_filename = None
00045 
00046     def __init__(self, qtgui_path, invoked_filename=None, settings_filename=None):
00047         self._qtgui_path = qtgui_path
00048         if invoked_filename is None:
00049             invoked_filename = os.path.abspath(__file__)
00050         Main.main_filename = invoked_filename
00051         if settings_filename is None:
00052             settings_filename = 'qt_gui'
00053         self._settings_filename = settings_filename
00054 
00055         self.plugin_providers = []
00056         self._options = None
00057 
00058         # check if DBus is available
00059         self._dbus_available = False
00060         try:
00061             # use qt/glib mainloop integration to get dbus mainloop working
00062             from dbus.mainloop.glib import DBusGMainLoop
00063             DBusGMainLoop(set_as_default=True)
00064             import dbus
00065             try:
00066                 # before being able to check if a session bus is available the dbus mainloop must be set up
00067                 dbus.SessionBus()
00068                 self._dbus_available = True
00069             except dbus.exceptions.DBusException:
00070                 pass
00071         except ImportError:
00072             pass
00073 
00074     def add_arguments(self, parser, standalone=False, plugin_argument_provider=None):
00075         common_group = parser.add_argument_group('Options for GUI instance')
00076         common_group.add_argument('-b', '--qt-binding', dest='qt_binding', type=str, metavar='BINDING',
00077             help='choose Qt bindings to be used [pyqt|pyside]')
00078         common_group.add_argument('--clear-config', dest='clear_config', default=False, action='store_true',
00079             help='clear the configuration (including all perspectives and plugin settings)')
00080         common_group.add_argument('-d', '--disable-init-threads', dest='disable_init_threads', default=False, action='store_true',
00081             help='do not set Qt.AA_X11InitThreads')
00082         if not standalone:
00083             common_group.add_argument('-f', '--freeze-layout', dest='freeze_layout', action='store_true',
00084                 help='freeze the layout of the GUI (prevent rearranging widgets, disable undock/redock)')
00085         common_group.add_argument('--force-discover', dest='force_discover', default=False, action='store_true',
00086             help='force a rediscover of plugins')
00087         common_group.add_argument('-h', '--help', action='help',
00088             help='show this help message and exit')
00089         if not standalone:
00090             common_group.add_argument('-l', '--lock-perspective', dest='lock_perspective', action='store_true',
00091                 help='lock the GUI to the used perspective (hide menu bar and close buttons of plugins)')
00092             common_group.add_argument('-m', '--multi-process', dest='multi_process', default=False, action='store_true',
00093                 help='use separate processes for each plugin instance (currently only supported under X11)')
00094             common_group.add_argument('-p', '--perspective', dest='perspective', type=str, metavar='PERSPECTIVE',
00095                 help='start with this named perspective')
00096             common_group.add_argument('--perspective-file', dest='perspective_file', type=str, metavar='PERSPECTIVE_FILE',
00097                 help='start with a perspective loaded from a file')
00098         common_group.add_argument('--reload-import', dest='reload_import', default=False, action='store_true',
00099             help='reload every imported module')
00100         if not standalone:
00101             common_group.add_argument('-s', '--standalone', dest='standalone_plugin', type=str, metavar='PLUGIN',
00102                 help='start only this plugin (implies -l). To pass arguments to the plugin use --args')
00103         common_group.add_argument('-t', '--on-top', dest='on_top', default=False, action='store_true',
00104             help='set window mode to always on top')
00105         common_group.add_argument('-v', '--verbose', dest='verbose', default=False, action='store_true',
00106             help='output qDebug messages')
00107 
00108         if not standalone:
00109             common_group.add_argument('--args', dest='plugin_args', nargs='*', type=str,
00110                 help='arbitrary arguments which are passes to the plugin (only with -s, --command-start-plugin or --embed-plugin). It must be the last option since it collects all following options.')
00111 
00112             group = parser.add_argument_group('Options to query information without starting a GUI instance',
00113                 'These options can be used to query information about valid arguments for various options.')
00114             group.add_argument('--list-perspectives', dest='list_perspectives', action='store_true',
00115                 help='list available perspectives')
00116             group.add_argument('--list-plugins', dest='list_plugins', action='store_true',
00117                 help='list available plugins')
00118             parser.add_argument_group(group)
00119 
00120             group = parser.add_argument_group('Options to operate on a running GUI instance',
00121                 'These options can be used to perform actions on a running GUI instance.')
00122             group.add_argument('--command-pid', dest='command_pid', type=int, metavar='PID',
00123                 help='pid of the GUI instance to operate on, defaults to oldest running GUI instance')
00124             group.add_argument('--command-start-plugin', dest='command_start_plugin', type=str, metavar='PLUGIN',
00125                 help='start plugin')
00126             group.add_argument('--command-switch-perspective', dest='command_switch_perspective', type=str, metavar='PERSPECTIVE',
00127                 help='switch perspective')
00128             if not self._dbus_available:
00129                 group.description = 'These options are not available since DBus is available!'
00130                 for o in group._group_actions:
00131                     o.help = SUPPRESS
00132             parser.add_argument_group(group)
00133 
00134             group = parser.add_argument_group('Special options for embedding widgets from separate processes',
00135                 'These options should never be used on the CLI but only from the GUI code itself.')
00136             group.add_argument('--embed-plugin', dest='embed_plugin', type=str, metavar='PLUGIN',
00137                 help='embed a plugin into an already running GUI instance (requires all other --embed-* options)')
00138             group.add_argument('--embed-plugin-serial', dest='embed_plugin_serial', type=int, metavar='SERIAL',
00139                 help='serial number of plugin to be embedded (requires all other --embed-* options)')
00140             group.add_argument('--embed-plugin-address', dest='embed_plugin_address', type=str, metavar='ADDRESS',
00141                 help='dbus server address of the GUI instance to embed plugin into (requires all other --embed-* options)')
00142             for o in group._group_actions:
00143                 o.help = SUPPRESS
00144             parser.add_argument_group(group)
00145 
00146         if plugin_argument_provider:
00147             plugin_argument_provider(parser)
00148 
00149         return common_group
00150 
00151     def _add_plugin_providers(self):
00152         pass
00153 
00154     def _add_reload_paths(self, reload_importer):
00155         reload_importer.add_reload_path(os.path.join(os.path.dirname(__file__), *('..',) * 4))
00156 
00157     def _check_icon_theme_compliance(self):
00158         from python_qt_binding.QtGui import QIcon
00159         # TODO find a better way to verify Theme standard compliance
00160         if QIcon.themeName() == '' or \
00161            QIcon.fromTheme('document-save').isNull() or \
00162            QIcon.fromTheme('document-open').isNull() or \
00163            QIcon.fromTheme('edit-cut').isNull() or \
00164            QIcon.fromTheme('object-flip-horizontal').isNull():
00165             if 'darwin' in platform.platform().lower() and '/usr/local/share/icons' not in QIcon.themeSearchPaths():
00166                 QIcon.setThemeSearchPaths(QIcon.themeSearchPaths() + ['/usr/local/share/icons'])
00167             original_theme = QIcon.themeName()
00168             QIcon.setThemeName('Tango')
00169             if QIcon.fromTheme('document-save').isNull():
00170                 QIcon.setThemeName(original_theme)
00171 
00172     def create_application(self, argv):
00173         from python_qt_binding.QtCore import Qt
00174         from python_qt_binding.QtGui import QApplication
00175         if not self._options.disable_init_threads:
00176             QApplication.setAttribute(Qt.AA_X11InitThreads, True)
00177         app = QApplication(argv)
00178         app.setAttribute(Qt.AA_DontShowIconsInMenus, False)
00179         return app
00180 
00181     def main(self, argv=None, standalone=None, plugin_argument_provider=None, plugin_manager_settings_prefix=''):
00182         if argv is None:
00183             argv = sys.argv
00184 
00185         # extract --args and everything behind manually since argparse can not handle that
00186         arguments = argv[1:]
00187 
00188         # extract plugin specific args when not being invoked in standalone mode programmatically
00189         if not standalone:
00190             plugin_args = []
00191             if '--args' in arguments:
00192                 index = arguments.index('--args')
00193                 plugin_args = arguments[index + 1:]
00194                 arguments = arguments[0:index + 1]
00195 
00196         parser = ArgumentParser(os.path.basename(Main.main_filename), add_help=False)
00197         self.add_arguments(parser, standalone=bool(standalone), plugin_argument_provider=plugin_argument_provider)
00198         self._options = parser.parse_args(arguments)
00199 
00200         if standalone:
00201             # rerun parsing to separate common arguments from plugin specific arguments
00202             parser = ArgumentParser(os.path.basename(Main.main_filename), add_help=False)
00203             self.add_arguments(parser, standalone=bool(standalone))
00204             self._options, plugin_args = parser.parse_known_args(arguments)
00205         self._options.plugin_args = plugin_args
00206 
00207         # set default values for options not available in standalone mode
00208         if standalone:
00209             self._options.freeze_layout = False
00210             self._options.lock_perspective = False
00211             self._options.multi_process = False
00212             self._options.perspective = None
00213             self._options.perspective_file = None
00214             self._options.standalone_plugin = standalone
00215             self._options.list_perspectives = False
00216             self._options.list_plugins = False
00217             self._options.command_pid = None
00218             self._options.command_start_plugin = None
00219             self._options.command_switch_perspective = None
00220             self._options.embed_plugin = None
00221             self._options.embed_plugin_serial = None
00222             self._options.embed_plugin_address = None
00223 
00224         # check option dependencies
00225         try:
00226             if self._options.plugin_args and not self._options.standalone_plugin and not self._options.command_start_plugin and not self._options.embed_plugin:
00227                 raise RuntimeError('Option --args can only be used together with either --standalone, --command-start-plugin or --embed-plugin option')
00228 
00229             if self._options.freeze_layout and not self._options.lock_perspective:
00230                 raise RuntimeError('Option --freeze_layout can only be used together with the --lock_perspective option')
00231 
00232             list_options = (self._options.list_perspectives, self._options.list_plugins)
00233             list_options_set = [opt for opt in list_options if opt is not False]
00234             if len(list_options_set) > 1:
00235                 raise RuntimeError('Only one --list-* option can be used at a time')
00236 
00237             command_options = (self._options.command_start_plugin, self._options.command_switch_perspective)
00238             command_options_set = [opt for opt in command_options if opt is not None]
00239             if len(command_options_set) > 0 and not self._dbus_available:
00240                 raise RuntimeError('Without DBus support the --command-* options are not available')
00241             if len(command_options_set) > 1:
00242                 raise RuntimeError('Only one --command-* option can be used at a time (except --command-pid which is optional)')
00243             if len(command_options_set) == 0 and self._options.command_pid is not None:
00244                 raise RuntimeError('Option --command_pid can only be used together with an other --command-* option')
00245 
00246             embed_options = (self._options.embed_plugin, self._options.embed_plugin_serial, self._options.embed_plugin_address)
00247             embed_options_set = [opt for opt in embed_options if opt is not None]
00248             if len(command_options_set) > 0 and not self._dbus_available:
00249                 raise RuntimeError('Without DBus support the --embed-* options are not available')
00250             if len(embed_options_set) > 0 and len(embed_options_set) < len(embed_options):
00251                 raise RuntimeError('Missing option(s) - all \'--embed-*\' options must be set')
00252 
00253             if len(embed_options_set) > 0 and self._options.clear_config:
00254                 raise RuntimeError('Option --clear-config can only be used without any --embed-* option')
00255 
00256             groups = (list_options_set, command_options_set, embed_options_set)
00257             groups_set = [opt for opt in groups if len(opt) > 0]
00258             if len(groups_set) > 1:
00259                 raise RuntimeError('Options from different groups (--list, --command, --embed) can not be used together')
00260 
00261             perspective_options = (self._options.perspective, self._options.perspective_file)
00262             perspective_options_set = [opt for opt in perspective_options if opt is not None]
00263             if len(perspective_options_set) > 1:
00264                 raise RuntimeError('Only one --perspective-* option can be used at a time')
00265 
00266             if self._options.perspective_file is not None and not os.path.isfile(self._options.perspective_file):
00267                 raise RuntimeError('Option --perspective-file must reference existing file')
00268 
00269         except RuntimeError as e:
00270             print(str(e))
00271             #parser.parse_args(['--help'])
00272             # calling --help will exit
00273             return 1
00274 
00275         # set implicit option dependencies
00276         if self._options.standalone_plugin is not None:
00277             self._options.lock_perspective = True
00278 
00279         # create application context containing various relevant information
00280         from .application_context import ApplicationContext
00281         context = ApplicationContext()
00282         context.qtgui_path = self._qtgui_path
00283         context.options = self._options
00284 
00285         if self._dbus_available:
00286             from dbus import DBusException, Interface, SessionBus
00287 
00288         # non-special applications provide various dbus interfaces
00289         if self._dbus_available:
00290             context.provide_app_dbus_interfaces = len(groups_set) == 0
00291             context.dbus_base_bus_name = 'org.ros.qt_gui'
00292             if context.provide_app_dbus_interfaces:
00293                 context.dbus_unique_bus_name = context.dbus_base_bus_name + '.pid%d' % os.getpid()
00294 
00295                 # provide pid of application via dbus
00296                 from .application_dbus_interface import ApplicationDBusInterface
00297                 _dbus_server = ApplicationDBusInterface(context.dbus_base_bus_name)
00298 
00299         # determine host bus name, either based on pid given on command line or via dbus application interface if any other instance is available
00300         if len(command_options_set) > 0 or len(embed_options_set) > 0:
00301             host_pid = None
00302             if self._options.command_pid is not None:
00303                 host_pid = self._options.command_pid
00304             else:
00305                 try:
00306                     remote_object = SessionBus().get_object(context.dbus_base_bus_name, '/Application')
00307                 except DBusException:
00308                     pass
00309                 else:
00310                     remote_interface = Interface(remote_object, context.dbus_base_bus_name + '.Application')
00311                     host_pid = remote_interface.get_pid()
00312             if host_pid is not None:
00313                 context.dbus_host_bus_name = context.dbus_base_bus_name + '.pid%d' % host_pid
00314 
00315         # execute command on host application instance
00316         if len(command_options_set) > 0:
00317             if self._options.command_start_plugin is not None:
00318                 try:
00319                     remote_object = SessionBus().get_object(context.dbus_host_bus_name, '/PluginManager')
00320                 except DBusException:
00321                     (rc, msg) = (1, 'unable to communicate with GUI instance "%s"' % context.dbus_host_bus_name)
00322                 else:
00323                     remote_interface = Interface(remote_object, context.dbus_base_bus_name + '.PluginManager')
00324                     (rc, msg) = remote_interface.start_plugin(self._options.command_start_plugin, ' '.join(self._options.plugin_args))
00325                 if rc == 0:
00326                     print('qt_gui_main() started plugin "%s" in GUI "%s"' % (msg, context.dbus_host_bus_name))
00327                 else:
00328                     print('qt_gui_main() could not start plugin "%s" in GUI "%s": %s' % (self._options.command_start_plugin, context.dbus_host_bus_name, msg))
00329                 return rc
00330             elif self._options.command_switch_perspective is not None:
00331                 remote_object = SessionBus().get_object(context.dbus_host_bus_name, '/PerspectiveManager')
00332                 remote_interface = Interface(remote_object, context.dbus_base_bus_name + '.PerspectiveManager')
00333                 remote_interface.switch_perspective(self._options.command_switch_perspective)
00334                 print('qt_gui_main() switched to perspective "%s" in GUI "%s"' % (self._options.command_switch_perspective, context.dbus_host_bus_name))
00335                 return 0
00336             raise RuntimeError('Unknown command not handled')
00337 
00338         # choose selected or default qt binding
00339         setattr(sys, 'SELECT_QT_BINDING', self._options.qt_binding)
00340         from python_qt_binding import QT_BINDING
00341 
00342         from python_qt_binding.QtCore import qDebug, qInstallMsgHandler, QSettings, Qt, QtCriticalMsg, QtDebugMsg, QtFatalMsg, QTimer, QtWarningMsg
00343         from python_qt_binding.QtGui import QAction, QIcon, QMenuBar
00344 
00345         from .about_handler import AboutHandler
00346         from .composite_plugin_provider import CompositePluginProvider
00347         from .container_manager import ContainerManager
00348         from .help_provider import HelpProvider
00349         from .icon_loader import get_icon
00350         from .main_window import MainWindow
00351         from .minimized_dock_widgets_toolbar import MinimizedDockWidgetsToolbar
00352         from .perspective_manager import PerspectiveManager
00353         from .plugin_manager import PluginManager
00354 
00355         def message_handler(type_, msg):
00356             colored_output = 'TERM' in os.environ and 'ANSI_COLORS_DISABLED' not in os.environ
00357             cyan_color = '\033[36m' if colored_output else ''
00358             red_color = '\033[31m' if colored_output else ''
00359             reset_color = '\033[0m' if colored_output else ''
00360             if type_ == QtDebugMsg and self._options.verbose:
00361                 print(msg, file=sys.stderr)
00362             elif type_ == QtWarningMsg:
00363                 print(cyan_color + msg + reset_color, file=sys.stderr)
00364             elif type_ == QtCriticalMsg:
00365                 print(red_color + msg + reset_color, file=sys.stderr)
00366             elif type_ == QtFatalMsg:
00367                 print(red_color + msg + reset_color, file=sys.stderr)
00368                 sys.exit(1)
00369         qInstallMsgHandler(message_handler)
00370 
00371         app = self.create_application(argv)
00372 
00373         self._check_icon_theme_compliance()
00374 
00375         settings = QSettings(QSettings.IniFormat, QSettings.UserScope, 'ros.org', self._settings_filename)
00376         if len(embed_options_set) == 0:
00377             if self._options.clear_config:
00378                 settings.clear()
00379 
00380             main_window = MainWindow()
00381             if self._options.on_top:
00382                 main_window.setWindowFlags(Qt.WindowStaysOnTopHint)
00383 
00384             main_window.statusBar()
00385 
00386             def sigint_handler(*args):
00387                 qDebug('\nsigint_handler()')
00388                 main_window.close()
00389             signal.signal(signal.SIGINT, sigint_handler)
00390             # the timer enables triggering the sigint_handler
00391             timer = QTimer()
00392             timer.start(500)
00393             timer.timeout.connect(lambda: None)
00394 
00395             # create own menu bar to share one menu bar on Mac
00396             menu_bar = QMenuBar()
00397             if 'darwin' in platform.platform().lower():
00398                 menu_bar.setNativeMenuBar(True)
00399             else:
00400                 menu_bar.setNativeMenuBar(False)
00401             if not self._options.lock_perspective:
00402                 main_window.setMenuBar(menu_bar)
00403 
00404             file_menu = menu_bar.addMenu(menu_bar.tr('&File'))
00405             action = QAction(file_menu.tr('&Quit'), file_menu)
00406             action.setIcon(QIcon.fromTheme('application-exit'))
00407             action.triggered.connect(main_window.close)
00408             file_menu.addAction(action)
00409 
00410         else:
00411             app.setQuitOnLastWindowClosed(False)
00412 
00413             main_window = None
00414             menu_bar = None
00415 
00416         self._add_plugin_providers()
00417 
00418         # setup plugin manager
00419         plugin_provider = CompositePluginProvider(self.plugin_providers)
00420         plugin_manager = PluginManager(plugin_provider, settings, context, settings_prefix=plugin_manager_settings_prefix)
00421 
00422         if self._options.list_plugins:
00423             # output available plugins
00424             print('\n'.join(sorted(plugin_manager.get_plugins().values())))
00425             return 0
00426 
00427         help_provider = HelpProvider()
00428         plugin_manager.plugin_help_signal.connect(help_provider.plugin_help_request)
00429 
00430         # setup perspective manager
00431         if main_window is not None:
00432             perspective_manager = PerspectiveManager(settings, context)
00433 
00434             if self._options.list_perspectives:
00435                 # output available perspectives
00436                 print('\n'.join(sorted(perspective_manager.perspectives)))
00437                 return 0
00438         else:
00439             perspective_manager = None
00440 
00441         if main_window is not None:
00442             container_manager = ContainerManager(main_window, plugin_manager)
00443             plugin_manager.set_main_window(main_window, menu_bar, container_manager)
00444 
00445             if not self._options.freeze_layout:
00446                 minimized_dock_widgets_toolbar = MinimizedDockWidgetsToolbar(container_manager, main_window)
00447                 main_window.addToolBar(Qt.BottomToolBarArea, minimized_dock_widgets_toolbar)
00448                 plugin_manager.set_minimized_dock_widgets_toolbar(minimized_dock_widgets_toolbar)
00449 
00450         if menu_bar is not None:
00451             perspective_menu = menu_bar.addMenu(menu_bar.tr('P&erspectives'))
00452             perspective_manager.set_menu(perspective_menu)
00453 
00454         # connect various signals and slots
00455         if perspective_manager is not None and main_window is not None:
00456             # signal changed perspective to update window title
00457             perspective_manager.perspective_changed_signal.connect(main_window.perspective_changed)
00458             # signal new settings due to changed perspective
00459             perspective_manager.save_settings_signal.connect(main_window.save_settings)
00460             perspective_manager.restore_settings_signal.connect(main_window.restore_settings)
00461             perspective_manager.restore_settings_without_plugin_changes_signal.connect(main_window.restore_settings)
00462 
00463         if perspective_manager is not None and plugin_manager is not None:
00464             perspective_manager.save_settings_signal.connect(plugin_manager.save_settings)
00465             plugin_manager.save_settings_completed_signal.connect(perspective_manager.save_settings_completed)
00466             perspective_manager.restore_settings_signal.connect(plugin_manager.restore_settings)
00467             perspective_manager.restore_settings_without_plugin_changes_signal.connect(plugin_manager.restore_settings_without_plugins)
00468 
00469         if plugin_manager is not None and main_window is not None:
00470             # signal before changing plugins to save window state
00471             plugin_manager.plugins_about_to_change_signal.connect(main_window.save_setup)
00472             # signal changed plugins to restore window state
00473             plugin_manager.plugins_changed_signal.connect(main_window.restore_state)
00474             # signal save settings to store plugin setup on close
00475             main_window.save_settings_before_close_signal.connect(plugin_manager.close_application)
00476             # signal save and shutdown called for all plugins, trigger closing main window again
00477             plugin_manager.close_application_signal.connect(main_window.close, type=Qt.QueuedConnection)
00478 
00479         if main_window is not None and menu_bar is not None:
00480             about_handler = AboutHandler(context.qtgui_path, main_window)
00481             help_menu = menu_bar.addMenu(menu_bar.tr('&Help'))
00482             action = QAction(file_menu.tr('&About'), help_menu)
00483             action.setIcon(QIcon.fromTheme('help-about'))
00484             action.triggered.connect(about_handler.show)
00485             help_menu.addAction(action)
00486 
00487         # set initial size - only used without saved configuration
00488         if main_window is not None:
00489             main_window.resize(600, 450)
00490             main_window.move(100, 100)
00491 
00492         # ensure that qt_gui/src is in sys.path
00493         src_path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
00494         if src_path not in sys.path:
00495             sys.path.append(src_path)
00496 
00497         # load specific plugin
00498         plugin = None
00499         plugin_serial = None
00500         if self._options.embed_plugin is not None:
00501             plugin = self._options.embed_plugin
00502             plugin_serial = self._options.embed_plugin_serial
00503         elif self._options.standalone_plugin is not None:
00504             plugin = self._options.standalone_plugin
00505             plugin_serial = 0
00506         if plugin is not None:
00507             plugins = plugin_manager.find_plugins_by_name(plugin)
00508             if len(plugins) == 0:
00509                 print('qt_gui_main() found no plugin matching "%s"' % plugin)
00510                 return 1
00511             elif len(plugins) > 1:
00512                 print('qt_gui_main() found multiple plugins matching "%s"\n%s' % (plugin, '\n'.join(plugins.values())))
00513                 return 1
00514             plugin = plugins.keys()[0]
00515 
00516         qDebug('QtBindingHelper using %s' % QT_BINDING)
00517 
00518         plugin_manager.discover()
00519 
00520         if self._options.reload_import:
00521             qDebug('ReloadImporter() automatically reload all subsequent imports')
00522             from .reload_importer import ReloadImporter
00523             _reload_importer = ReloadImporter()
00524             self._add_reload_paths(_reload_importer)
00525             _reload_importer.enable()
00526 
00527         # switch perspective
00528         if perspective_manager is not None:
00529             if plugin:
00530                 perspective_manager.set_perspective(plugin, hide_and_without_plugin_changes=True)
00531             elif self._options.perspective_file:
00532                 perspective_manager.import_perspective_from_file(self._options.perspective_file, perspective_manager.HIDDEN_PREFIX + '__cli_perspective_from_file')
00533             else:
00534                 perspective_manager.set_perspective(self._options.perspective)
00535 
00536         # load specific plugin
00537         if plugin:
00538             plugin_manager.load_plugin(plugin, plugin_serial, self._options.plugin_args)
00539             running = plugin_manager.is_plugin_running(plugin, plugin_serial)
00540             if not running:
00541                 return 1
00542             if self._options.standalone_plugin:
00543                 # use icon of standalone plugin (if available) for application
00544                 plugin_descriptor = plugin_manager.get_plugin_descriptor(plugin)
00545                 action_attributes = plugin_descriptor.action_attributes()
00546                 if 'icon' in action_attributes and action_attributes['icon'] is not None:
00547                     base_path = plugin_descriptor.attributes().get('plugin_path')
00548                     try:
00549                         icon = get_icon(action_attributes['icon'], action_attributes.get('icontype', None), base_path)
00550                     except UserWarning:
00551                         pass
00552                     else:
00553                         app.setWindowIcon(icon)
00554 
00555         if main_window is not None:
00556             main_window.show()
00557             if sys.platform == 'darwin':
00558                 main_window.raise_()
00559 
00560         return app.exec_()
00561 
00562 
00563 if __name__ == '__main__':
00564     main = Main()
00565     sys.exit(main.main())


qt_gui
Author(s): Dirk Thomas
autogenerated on Thu Jun 6 2019 18:07:34