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


qt_gui
Author(s): Dirk Thomas
autogenerated on Fri Aug 28 2015 12:15:40