Source code for camelot.view.mainwindow

#  ============================================================================
#
#  Copyright (C) 2007-2013 Conceptive Engineering bvba. All rights reserved.
#  www.conceptive.be / info@conceptive.be
#
#  This file is part of the Camelot Library.
#
#  This file may be used under the terms of the GNU General Public
#  License version 2.0 as published by the Free Software Foundation
#  and appearing in the file license.txt included in the packaging of
#  this file.  Please review this information to ensure GNU
#  General Public Licensing requirements will be met.
#
#  If you are unsure which license is appropriate for your use, please
#  visit www.python-camelot.com or contact info@conceptive.be
#
#  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
#  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#
#  For use of this library in commercial applications, please contact
#  info@conceptive.be
#
#  ============================================================================

import logging
logger = logging.getLogger('camelot.view.mainwindow')

from PyQt4.QtCore import Qt
from PyQt4 import QtGui, QtCore

from camelot.view.controls.busy_widget import BusyWidget
from camelot.view.controls.navpane2 import NavigationPane
from camelot.view.model_thread import post

from camelot.core.utils import ugettext as _

[docs]class MainWindow(QtGui.QMainWindow): """Main window of a Desktop Camelot application :param gui_context: an :class:`camelot.admin.action.application_action.ApplicationActionGuiContext` object :param parent: a :class:`QtGui.QWidget` object or :class:`None` .. attribute:: splash_screen a :class:`QtGui.QWidget` that needs to be closed when the main window is shown. """ def __init__(self, gui_context, parent=None): from workspace import DesktopWorkspace logger.debug('initializing main window') QtGui.QMainWindow.__init__(self, parent) self.splash_screen = None self.toolbars = [] self.nav_pane = None self.app_admin = gui_context.admin.get_application_admin() logger.debug('setting up workspace') self.workspace = DesktopWorkspace( self.app_admin, self ) self.gui_context = gui_context self.gui_context.workspace = self.workspace logger.debug('setting child windows dictionary') logger.debug('setting central widget to our workspace') self.setCentralWidget( self.workspace ) self.workspace.change_view_mode_signal.connect( self.change_view_mode ) self.workspace.last_view_closed_signal.connect( self.unmaximize_view ) self.workspace.view_activated_signal.connect( self.view_activated ) logger.debug('creating navigation pane') post( self.app_admin.get_sections, self.set_sections ) logger.debug('creating the menus') post( self.app_admin.get_main_menu, self.set_main_menu ) logger.debug('creating the toolbars') post( self.app_admin.get_toolbar_actions, self.set_left_toolbar_actions, args = (Qt.LeftToolBarArea,) ) post( self.app_admin.get_toolbar_actions, self.set_right_toolbar_actions, args = (Qt.RightToolBarArea,) ) post( self.app_admin.get_toolbar_actions, self.set_top_toolbar_actions, args = (Qt.TopToolBarArea,) ) post( self.app_admin.get_toolbar_actions, self.set_bottom_toolbar_actions, args = (Qt.BottomToolBarArea,) ) post( self.app_admin.get_hidden_actions, self.set_hidden_actions ) logger.debug('reading saved settings') self.read_settings() windowtitle = self.app_admin.get_name() logger.debug( u'setting up window title: %s'%windowtitle ) self.setWindowTitle( windowtitle ) self.app_admin.title_changed_signal.connect( self.setWindowTitle ) logger.debug('initialization complete') @QtCore.pyqtSlot()
[docs] def show( self ): """This method wait until the main window is completely set up, and only then shows it. This is a workaround for a bug in Qt on OS X https://bugreports.qt.nokia.com/browse/QTBUG-18567 """ post( lambda:None, self._delayed_show )
@QtCore.pyqtSlot(object) def _delayed_show( self, _o ): """Call to the underlying :meth:`QMainWindow.show`, to be used in :meth:`MainWindow.show` """ super( MainWindow, self ).show() if self.splash_screen: self.splash_screen.close() @QtCore.pyqtSlot()
[docs] def unmaximize_view( self ): """Show the navigation pane and the menu bar if they exist """ if self.navpane: self.navpane.show() if self.menuBar(): self.menuBar().show()
@QtCore.pyqtSlot()
[docs] def change_view_mode( self ): """Switch between hidden or shown menubar and navigation pane""" if self.menuBar().isHidden(): if self.navpane: self.navpane.show() self.menuBar().show() else: if self.navpane: self.navpane.hide() self.menuBar().hide()
[docs] def read_settings( self ): """Restore the geometry of the main window to its last saved state""" settings = QtCore.QSettings() self.restoreGeometry(settings.value('geometry').toByteArray())
[docs] def write_settings(self): """Store the current geometry of the main window""" logger.debug('writing application settings') settings = QtCore.QSettings() settings.setValue('geometry', QtCore.QVariant(self.saveGeometry())) logger.debug('settings written')
@QtCore.pyqtSlot( object )
[docs] def set_main_menu( self, main_menu ): """Set the main menu :param main_menu: a list of :class:`camelot.admin.menu.Menu` objects, as returned by the :meth:`camelot.admin.application_admin.ApplicationAdmin.get_main_menu` method. """ from camelot.view.controls.action_widget import ActionAction if main_menu == None: return menu_bar = self.menuBar() for menu in main_menu: menu_bar.addMenu( menu.render( self.gui_context, menu_bar ) ) for qaction in menu_bar.findChildren( ActionAction ): qaction.triggered.connect( self.action_triggered )
[docs] def get_gui_context( self ): """Get the :class:`GuiContext` of the active view in the mainwindow, or the :class:`GuiContext` of the application. :return: a :class:`camelot.admin.action.base.GuiContext` """ active_view = self.gui_context.workspace.active_view() if active_view: return active_view.gui_context return self.gui_context
@QtCore.pyqtSlot( object, object )
[docs] def set_toolbar_actions( self, toolbar_area, toolbar_actions ): """Set the toolbar for a specific area :param toolbar_area: the area on which to put the toolbar, from :class:`Qt.LeftToolBarArea` through :class:`Qt.BottomToolBarArea` :param toolbar_actions: a list of :class:`camelot.admin.action..base.Action` objects, as returned by the :meth:`camelot.admin.application_admin.ApplicationAdmin.get_toolbar_actions` method. """ from camelot.view.controls.action_widget import ActionAction if toolbar_actions != None: # # gather menu bar actions to prevent duplication of QActions # qactions = dict() menu_bar = self.menuBar() if menu_bar: for qaction in menu_bar.findChildren( ActionAction ): qactions[qaction.action] = qaction toolbar = QtGui.QToolBar( _('Toolbar') ) self.addToolBar( toolbar_area, toolbar ) toolbar.setObjectName( 'MainWindowToolBar_%i'%toolbar_area ) toolbar.setMovable( False ) toolbar.setFloatable( False ) for action in toolbar_actions: qaction = qactions.get( action, None ) if qaction == None: qaction = action.render( self.gui_context, toolbar ) qaction.triggered.connect( self.action_triggered ) toolbar.addAction( qaction ) self.toolbars.append( toolbar ) toolbar.addWidget( BusyWidget() )
@QtCore.pyqtSlot( object ) def set_left_toolbar_actions( self, toolbar_actions ): self.set_toolbar_actions( Qt.LeftToolBarArea, toolbar_actions ) @QtCore.pyqtSlot( object ) def set_right_toolbar_actions( self, toolbar_actions ): self.set_toolbar_actions( Qt.RightToolBarArea, toolbar_actions ) @QtCore.pyqtSlot( object ) def set_top_toolbar_actions( self, toolbar_actions ): self.set_toolbar_actions( Qt.TopToolBarArea, toolbar_actions ) @QtCore.pyqtSlot( object ) def set_bottom_toolbar_actions( self, toolbar_actions ): self.set_toolbar_actions( Qt.BottomToolBarArea, toolbar_actions ) @QtCore.pyqtSlot( object ) def set_hidden_actions( self, hidden_actions ): from camelot.view.controls.action_widget import ActionAction for action in hidden_actions: action_action = ActionAction( action, self.gui_context, self ) action_action.triggered.connect( self.action_triggered ) self.addAction( action_action ) @QtCore.pyqtSlot()
[docs] def view_activated( self ): """Update the state of the actions when the active tab in the desktop widget has changed""" from camelot.view.controls.action_widget import ActionAction gui_context = self.get_gui_context() model_context = gui_context.create_model_context() for toolbar in self.toolbars: for qaction in toolbar.actions(): if isinstance( qaction, ActionAction ): post( qaction.action.get_state, qaction.set_state, args = ( model_context, ) ) menu_bar = self.menuBar() if menu_bar: for qaction in menu_bar.findChildren( ActionAction ): post( qaction.action.get_state, qaction.set_state, args = ( model_context, ) )
@QtCore.pyqtSlot( bool )
[docs] def action_triggered( self, _checked = False ): """Execute an action that was triggered somewhere in the main window, such as the toolbar or the main menu""" action_action = self.sender() gui_context = self.get_gui_context() action_action.action.gui_run( gui_context )
@QtCore.pyqtSlot( object )
[docs] def set_sections( self, sections ): """Set the sections of the navigation pane :param main_menu: a list of :class:`camelot.admin.section.Section` objects, as returned by the :meth:`camelot.admin.application_admin.ApplicationAdmin.get_sections` method. """ if sections != None: self.navpane = NavigationPane( self.app_admin, workspace=self.workspace, parent=self ) self.addDockWidget( Qt.LeftDockWidgetArea, self.navpane ) else: self.navpane = None
def closeEvent( self, event ): from camelot.view.model_thread import get_model_thread model_thread = get_model_thread() self.workspace.close_all_views() self.write_settings() logger.info( 'closing mainwindow' ) model_thread.stop() super( MainWindow, self ).closeEvent( event ) QtCore.QCoreApplication.exit(0)