Source code for camelot.view.mainwindow

#  ============================================================================
#
#  Copyright (C) 2007-2016 Conceptive Engineering bvba.
#  www.conceptive.be / info@conceptive.be
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are met:
#      * Redistributions of source code must retain the above copyright
#        notice, this list of conditions and the following disclaimer.
#      * Redistributions in binary form must reproduce the above copyright
#        notice, this list of conditions and the following disclaimer in the
#        documentation and/or other materials provided with the distribution.
#      * Neither the name of Conceptive Engineering nor the
#        names of its contributors may be used to endorse or promote products
#        derived from this software without specific prior written permission.
#  
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
#  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
#  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
#  DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
#  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
#  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
#  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
#  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
#  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#  ============================================================================

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

from ..core.qt import Qt, QtWidgets, QtCore, py_to_variant, variant_to_py

from camelot.view.controls.busy_widget import BusyWidget
from camelot.view.controls.section_widget import NavigationPane

from camelot.core.utils import ugettext as _

[docs]class MainWindow(QtWidgets.QMainWindow): """Main window of a Desktop Camelot application :param gui_context: an :class:`camelot.admin.action.application_action.ApplicationActionGuiContext` object :param parent: a :class:`QtWidgets.QWidget` object or :class:`None` """ def __init__(self, gui_context, parent=None): from .workspace import DesktopWorkspace logger.debug('initializing main window') QtWidgets.QMainWindow.__init__(self, parent) self.toolbars = [] self.nav_pane = None self.app_admin = gui_context.admin.get_application_admin() logger.debug('setting up workspace') self.gui_context = gui_context self.workspace = DesktopWorkspace( self.app_admin, self ) 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('reading saved settings') self.read_settings() logger.debug('initialization complete') @QtCore.qt_slot()
[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.qt_slot()
[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() geometry = variant_to_py( settings.value('geometry') ) if geometry: self.restoreGeometry( geometry )
[docs] def write_settings(self): """Store the current geometry of the main window""" logger.debug('writing application settings') settings = QtCore.QSettings() settings.setValue('geometry', py_to_variant(self.saveGeometry())) logger.debug('settings written')
@QtCore.qt_slot( 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.qt_slot( 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 = QtWidgets.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: # the action already exists in the menu toolbar.addAction( qaction ) if qaction == None: rendered = action.render( self.gui_context, toolbar ) # both QWidgets and QActions can be put in a toolbar if isinstance(rendered, QtWidgets.QWidget): toolbar.addWidget(rendered) elif isinstance(rendered, QtWidgets.QAction): rendered.triggered.connect( self.action_triggered ) toolbar.addAction( rendered ) self.toolbars.append( toolbar ) toolbar.addWidget( BusyWidget() )
@QtCore.qt_slot( 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.qt_slot()
[docs] def view_activated( self ): """Update the state of the actions when the active tab in the desktop widget has changed""" from camelot.view.model_thread import post 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.qt_slot( 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.qt_slot( 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( workspace=self.workspace, parent=self ) self.addDockWidget( Qt.LeftDockWidgetArea, self.navpane ) self.navpane.set_sections(sections) 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)