Source code for lib_openmolar.common.qt4.widgets.main_window

#! /usr/bin/env python
# -*- coding: utf-8 -*-

###############################################################################
##                                                                           ##
##  Copyright 2010, Neil Wallace <rowinggolfer@googlemail.com>               ##
##                                                                           ##
##  This program is free software: you can redistribute it and/or modify     ##
##  it under the terms of the GNU General Public License as published by     ##
##  the Free Software Foundation, either version 3 of the License, or        ##
##  (at your option) any later version.                                      ##
##                                                                           ##
##  This program is distributed in the hope that it will be useful,          ##
##  but WITHOUT ANY WARRANTY; without even the implied warranty of           ##
##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            ##
##  GNU General Public License for more details.                             ##
##                                                                           ##
##  You should have received a copy of the GNU General Public License        ##
##  along with this program.  If not, see <http://www.gnu.org/licenses/>.    ##
##                                                                           ##
###############################################################################

'''
provides the BaseMainWindow class
a basic re-implementation of QtGui.QMainWindow that can save state etc..
'''
import logging
import sys
import traceback

from PyQt4 import QtGui, QtCore
from lib_openmolar.common.qt4.widgets import Advisor, DockableMenuBar

logging.basicConfig(level=logging.DEBUG)

[docs]class BaseMainWindow(QtGui.QMainWindow, Advisor): ''' This class is a MainWindow, with menu, toolbar and statusbar. Some of the layout signals/slots already connected. Provides about, about QT and license dialogs. ''' log = logging.getLogger() _toolbars = []
[docs] def __init__(self, parent=None): QtGui.QMainWindow.__init__(self, parent) Advisor.__init__(self, parent) sys.excepthook = self.excepthook self.setMinimumSize(300, 300) ##### setup menu and headers #### #: a pointer to the main toolbar self.main_toolbar = QtGui.QToolBar() self.main_toolbar.setObjectName("Main Toolbar") self.main_toolbar.toggleViewAction().setText(_("Toolbar")) #: a pointer to the :doc:`DockableMenuBar` menubar = DockableMenuBar(self) ## add them to the app self.setMenuBar(menubar) self.addToolBar(QtCore.Qt.TopToolBarArea, self.main_toolbar) #### setup a statusbar with a label #### #: a pointer to the QtGui.QStatusBar self.statusbar = QtGui.QStatusBar() self.setStatusBar(self.statusbar) #: a pointer to the label in the statusbar self.status_label = QtGui.QLabel() self.statusbar.addPermanentWidget(self.status_label) #: a pointer to the File menu self.menu_file = QtGui.QMenu(_("&File"), self) menubar.addMenu(self.menu_file) #: a pointer to the Edit menu self.menu_edit = QtGui.QMenu(_("&Edit"), self) menubar.addMenu(self.menu_edit) #: a pointer to the View menu of :attr:`menubar` self.menu_view = menubar.menu_view #: a pointer to the Help menu self.menu_help = QtGui.QMenu(_("&Help"), self) menubar.addMenu(self.menu_help) #### file menu #### icon = QtGui.QIcon.fromTheme("application-exit") #: a pointer to the quit qaction self.action_quit = QtGui.QAction(icon, _("Quit"), self) self.menu_file.addSeparator() self.menu_file.addAction(self.action_quit) #### edit menu #### icon = QtGui.QIcon.fromTheme("preferences-desktop") #: a pointer to the preferences qAction self.action_preferences = QtGui.QAction(icon, _("&Preferences"), self) self.menu_edit.addAction(self.action_preferences) #### view menu #### #: a pointer to the show statusbar qaction self.action_show_statusbar = QtGui.QAction(_("Show Status&bar"), self) self.action_show_statusbar.setCheckable(True) self.action_show_statusbar.setChecked(True) icon = QtGui.QIcon.fromTheme("view-fullscreen") #: a pointer to the fullscreen mode qaction self.action_fullscreen = QtGui.QAction(icon, _("FullScreen Mode"), self) self.action_fullscreen.setCheckable(True) self.action_fullscreen.setShortcut("f11") self.menu_view.addSeparator() self.menu_view.addAction(self.action_show_statusbar) self.menu_view.addAction(self.action_fullscreen) #### about menu #### icon = QtGui.QIcon.fromTheme("help-about") #: a pointer to the about qaction self.action_about = QtGui.QAction(icon, _("About"), self) #: a pointer to the about qt qaction self.action_about_qt = QtGui.QAction(icon, _("About Qt"), self) #: a pointer to the license qaction self.action_license = QtGui.QAction(icon, _("License"), self) icon = QtGui.QIcon.fromTheme("help", QtGui.QIcon("icons/help.png")) #: a pointer to the help qaction self.action_help = QtGui.QAction(icon, _("Help"), self) self.menu_help.addAction(self.action_about) self.menu_help.addAction(self.action_license) self.menu_help.addAction(self.action_about_qt) self.menu_help.addSeparator() self.menu_help.addAction(self.action_help) #### toolbar #### #### add selected menu items to the toolbar #### #: self.help_toolbar = QtGui.QToolBar() self.help_toolbar.setObjectName("help toolbar") self.help_toolbar.toggleViewAction().setText(_("Help Toolbar")) self.help_toolbar.addAction(self.action_help) self.addToolBar(self.help_toolbar) self.connect_default_signals()
[docs] def connect_default_signals(self): ''' this function connects the triggered signals from the default menu it should not need to be called, as it is called during the :func:`__init__` ''' self.connect(self.action_quit, QtCore.SIGNAL("triggered()"), QtGui.QApplication.instance().closeAllWindows) self.action_preferences.triggered.connect(self.show_preferences_dialog) self.action_show_statusbar.triggered.connect(self.show_statusbar) self.action_fullscreen.triggered.connect(self.fullscreen) self.action_fullscreen.triggered.connect(self.fullscreen) self.action_about.triggered.connect(self.show_about) self.action_license.triggered.connect(self.show_license) self.connect(self.action_about_qt, QtCore.SIGNAL("triggered()"), QtGui.qApp, QtCore.SLOT("aboutQt()")) self.action_help.triggered.connect(self.show_help)
[docs] def excepthook(self, exc_type, exc_val, tracebackobj): ''' PyQt4 prints unhandled exceptions to stdout and carries on regardless I don't want this to happen. so sys.excepthook is passed to this ''' message = "" for l in traceback.format_exception(exc_type, exc_val, tracebackobj): message += l self.log.error('UNHANDLED EXCEPTION!\n\n%s\n'% message) self.advise('UNHANDLED EXCEPTION!<hr /><pre>%s'% message, 2)
[docs] def resizeEvent(self, event): ''' this function is overwritten so that the advisor popup can be put in the correct place ''' QtGui.QMainWindow.resizeEvent(self, event) self.setBriefMessageLocation()
[docs] def setBriefMessageLocation(self): ''' make the Advisor sub class aware of the windows geometry. set it top right, and right_to_left ''' widg = self.menuBar() brief_pos_x = (widg.pos().x() + widg.width()) brief_pos_y = (widg.pos().y() + widg.height()) brief_pos = QtCore.QPoint(brief_pos_x, brief_pos_y) self.setBriefMessagePosition(brief_pos, True)
[docs] def addToolBar(self, *args): QtGui.QMainWindow.addToolBar(self, *args) if self.menuWidget(): self.menuBar().update_toolbars()
@property
[docs] def toolbar_list(self): ''' yield all toolbars of the application ''' for child in self.children(): if type(child) == QtGui.QToolBar: yield child
[docs] def insertToolBar(self, *args): QtGui.QMainWindow.insertToolBar(self, *args) if self.menuWidget(): self.menuBar().update_toolbars()
[docs] def insertMenu_(self, menu): ''' a convenience function that slots new actions in just before the "help" menu item on the menubar ''' insertpoint = self.menu_help.menuAction() return self.menuBar().insertMenu(insertpoint, menu)
[docs] def insertToolBarWidget(self, action, sep=False): ''' a convenience function that slots new widgets in just before the "help" menu item on the main Toolbar. accepts either a QAction, or a widget. If option 2nd argument (sep) is True, a separator is also added. ''' added = [] insertpoint = self.action_help if sep: insertpoint = self.main_toolbar.insertSeparator(insertpoint) added.append(insertpoint) if type(action) == QtGui.QAction: added.append(self.main_toolbar.insertAction(insertpoint, action)) else: added.append(self.main_toolbar.insertWidget(insertpoint, action)) return added
[docs] def loadSettings(self): ''' load settings from QtCore.QSettings. ''' settings = QtCore.QSettings() #Qt settings self.restoreGeometry(settings.value("geometry").toByteArray()) self.restoreState(settings.value("windowState").toByteArray()) statusbar_hidden = settings.value("statusbar_hidden").toBool() self.statusbar.setVisible(not statusbar_hidden) self.action_show_statusbar.setChecked(not self.statusbar.isHidden()) font = settings.value("Font").toPyObject() if font: QtGui.QApplication.instance().setFont(font) toolbar_set = settings.value( "Toolbar", QtCore.Qt.ToolButtonTextUnderIcon).toInt()[0] for tb in self.toolbar_list: tb.setToolButtonStyle(toolbar_set) tiny_menu = settings.value("TinyMenu").toBool() if tiny_menu: self.menuBar().toggle_visability(True) self.menuBar().menu_toolbar.toggleViewAction().setChecked(True)
[docs] def saveSettings(self): ''' save settings from QtCore.QSettings ''' settings = QtCore.QSettings() #Qt settings settings.setValue("geometry", self.saveGeometry()) settings.setValue("windowState", self.saveState()) settings.setValue("statusbar_hidden", self.statusbar.isHidden()) settings.setValue("Font", self.font()) settings.setValue("Toolbar", self.main_toolbar.toolButtonStyle()) settings.setValue("TinyMenu", not self.menuBar().isVisible())
[docs] def show_toolbar(self): if self.action_show_toolbar.isChecked(): self.main_toolbar.show() else: self.main_toolbar.hide()
[docs] def show_statusbar(self): if self.action_show_statusbar.isChecked(): self.statusbar.show() else: self.statusbar.hide()
[docs] def reimplement_needed(self, func_name): QtGui.QMessageBox.information(self, "please re-implement", '''please overwrite function <b>'%s'</b><br /> in any class which inherits from 'BaseMainWindow' '''% func_name)
[docs] def show_preferences_dialog(self): self.reimplement_needed('show_preferences_dialog')
[docs] def show_about(self): self.reimplement_needed('show_about')
[docs] def show_help(self): self.reimplement_needed('show_help')
[docs] def show_license(self): ''' attempts to read and show the license text from file COPYRIGHT.txt in the apps directory on failure, gives a simple message box with link. ''' message = ''' GPLv3 - see <a href='http://www.gnu.org/licenses/gpl.html'> http://www.gnu.org/licenses/gpl.html</a>''' try: f = open("../COPYING.txt") data = f.read() f.close() dl = QtGui.QDialog(self) dl.setWindowTitle(_("License")) dl.setFixedSize(400, 400) layout = QtGui.QVBoxLayout(dl) buttonBox = QtGui.QDialogButtonBox(dl) buttonBox.setOrientation(QtCore.Qt.Horizontal) buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok) te = QtGui.QTextBrowser() te.setText(data) label = QtGui.QLabel(message) label.setWordWrap(True) layout.addWidget(te) layout.addWidget(label) layout.addWidget(buttonBox) buttonBox.accepted.connect(dl.accept) dl.exec_() except IOError: QtGui.QMessageBox.information(self, _("License"), message)
[docs] def fullscreen(self): if self.action_fullscreen.isChecked(): self.setWindowState(QtCore.Qt.WindowFullScreen) else: self.setWindowState(QtCore.Qt.WindowNoState)
[docs] def closeEvent(self, event=None): ''' re-implement the close event of QtGui.QMainWindow, and check the user really meant to do this. ''' if self.get_confirm(_("Quit Application?"), "yes", "no"): self.saveSettings() else: event.ignore()
[docs] def get_confirm(self, message, accept="ok", reject="cancel", default="accept"): ''' a convenience function to raise a dialog for confirmation of an action ''' if accept == "ok": accept_but = QtGui.QMessageBox.Ok elif accept == "yes": accept_but = QtGui.QMessageBox.Yes if reject == "cancel": reject_but = QtGui.QMessageBox.Cancel elif reject == "no": reject_but = QtGui.QMessageBox.No buttons = accept_but|reject_but default_but = accept_but if default == "accept" else reject_but return QtGui.QMessageBox.question(self,_("Confirm"), message, buttons, default_but) == accept_but
if __name__ == "__main__": import gettext gettext.install("") app = QtGui.QApplication([]) mw = BaseMainWindow() mw.main_toolbar.addAction(QtGui.QAction("Placeholder", mw)) mw.show() app.exec_()