Tools/TRPreviewer.py

changeset 0
de9c2efb9d02
child 7
c679fb30c8f3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Tools/TRPreviewer.py	Mon Dec 28 16:03:33 2009 +0000
@@ -0,0 +1,861 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2004 - 2009 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the TR Previewer main window.
+"""
+
+import sys
+import os
+
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+from PyQt4 import uic
+
+from TRSingleApplication import TRSingleApplicationServer
+
+import Preferences
+import UI.PixmapCache
+import UI.Config
+
+
+noTranslationName = QApplication.translate("TRPreviewer", "<No translation>")
+
+class TRPreviewer(QMainWindow):
+    """
+    Class implementing the UI Previewer main window.
+    """
+    def __init__(self, filenames = [], parent = None, name = None):
+        """
+        Constructor
+        
+        @param filenames filenames of form and/or translation files to load
+        @param parent parent widget of this window (QWidget)
+        @param name name of this window (string)
+        """
+        self.mainWidget = None
+        self.currentFile = QDir.currentPath()
+        
+        QMainWindow.__init__(self, parent)
+        if not name:
+            self.setObjectName("TRPreviewer")
+        else:
+            self.setObjectName(name)
+        self.resize(QSize(800, 600).expandedTo(self.minimumSizeHint()))
+        self.setAttribute(Qt.WA_DeleteOnClose)
+        self.statusBar()
+        
+        self.setWindowIcon(UI.PixmapCache.getIcon("eric.png"))
+        self.setWindowTitle(self.trUtf8("Translations Previewer"))
+
+        self.cw = QWidget(self)
+        self.cw.setObjectName("qt_central_widget")
+        
+        self.TRPreviewerLayout = QVBoxLayout(self.cw)
+        self.TRPreviewerLayout.setMargin(6)
+        self.TRPreviewerLayout.setSpacing(6)
+        self.TRPreviewerLayout.setObjectName("TRPreviewerLayout")
+
+        self.languageLayout = QHBoxLayout()
+        self.languageLayout.setMargin(0)
+        self.languageLayout.setSpacing(6)
+        self.languageLayout.setObjectName("languageLayout")
+
+        self.languageLabel = QLabel(self.trUtf8("Select language file"), self.cw)
+        self.languageLabel.setObjectName("languageLabel")
+        self.languageLayout.addWidget(self.languageLabel)
+
+        self.languageCombo = QComboBox(self.cw)
+        self.languageCombo.setObjectName("languageCombo")
+        self.languageCombo.setEditable(False)
+        self.languageCombo.setToolTip(self.trUtf8("Select language file"))
+        self.languageCombo.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
+        self.languageLayout.addWidget(self.languageCombo)
+        
+        languageSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
+        self.languageLayout.addItem(languageSpacer)
+        self.TRPreviewerLayout.addLayout(self.languageLayout)
+
+        self.preview = WidgetWorkspace(self.cw)
+        self.preview.setObjectName("preview")
+        self.TRPreviewerLayout.addWidget(self.preview)
+        self.connect(self.preview, SIGNAL('lastWidgetClosed'), self.__updateActions)
+
+        self.setCentralWidget(self.cw)
+        
+        self.connect(self.languageCombo,SIGNAL("activated(const QString&)"),
+                     self.setTranslation)
+        
+        self.translations = TranslationsDict(self.languageCombo, self)
+        self.connect(self.translations, SIGNAL('translationChanged'),
+                     self.preview, SIGNAL('rebuildWidgets'))
+        
+        self.__initActions()
+        self.__initMenus()
+        self.__initToolbars()
+        
+        self.__updateActions()
+        
+        # fire up the single application server
+        self.SAServer = TRSingleApplicationServer(self)
+        self.connect(self.SAServer, SIGNAL('loadForm'), self.preview.loadWidget)
+        self.connect(self.SAServer, SIGNAL('loadTranslation'), self.translations.add)
+        
+        # defere loading of a UI file until we are shown
+        self.filesToLoad = filenames[:]
+        
+    def show(self):
+        """
+        Public slot to show this dialog.
+        
+        This overloaded slot loads a UI file to be previewed after
+        the main window has been shown. This way, previewing a dialog
+        doesn't interfere with showing the main window.
+        """
+        QMainWindow.show(self)
+        if self.filesToLoad:
+            filenames, self.filesToLoad = (self.filesToLoad[:], [])
+            first = True
+            for fn in filenames:
+                fi = QFileInfo(fn)
+                if fi.suffix().lower() == 'ui':
+                    self.preview.loadWidget(fn)
+                elif fi.suffix().lower()== 'qm':
+                    self.translations.add(fn, first)
+                    first = False
+            
+            self.__updateActions()
+        
+    def closeEvent(self, event):
+        """
+        Private event handler for the close event.
+        
+        @param event close event (QCloseEvent)
+        """
+        if self.SAServer is not None:
+            self.SAServer.shutdown()
+            self.SAServer = None
+        event.accept()
+        
+    def __initActions(self):
+        """
+        Private method to define the user interface actions.
+        """
+        self.openUIAct = QAction(UI.PixmapCache.getIcon("openUI.png"), 
+                        self.trUtf8('&Open UI Files...'), self)
+        self.openUIAct.setStatusTip(self.trUtf8('Open UI files for display'))
+        self.openUIAct.setWhatsThis(self.trUtf8(
+                """<b>Open UI Files</b>"""
+                """<p>This opens some UI files for display.</p>"""
+        ))
+        self.connect(self.openUIAct, SIGNAL('triggered()'), self.__openWidget)
+        
+        self.openQMAct = QAction(UI.PixmapCache.getIcon("openQM.png"), 
+                        self.trUtf8('Open &Translation Files...'), self)
+        self.openQMAct.setStatusTip(self.trUtf8('Open Translation files for display'))
+        self.openQMAct.setWhatsThis(self.trUtf8(
+                """<b>Open Translation Files</b>"""
+                """<p>This opens some translation files for display.</p>"""
+        ))
+        self.connect(self.openQMAct, SIGNAL('triggered()'), self.__openTranslation)
+        
+        self.reloadAct = QAction(UI.PixmapCache.getIcon("reload.png"), 
+                        self.trUtf8('&Reload Translations'), self)
+        self.reloadAct.setStatusTip(self.trUtf8('Reload the loaded translations'))
+        self.reloadAct.setWhatsThis(self.trUtf8(
+                """<b>Reload Translations</b>"""
+                """<p>This reloads the translations for the loaded languages.</p>"""
+        ))
+        self.connect(self.reloadAct, SIGNAL('triggered()'), self.translations.reload)
+        
+        self.exitAct = QAction(UI.PixmapCache.getIcon("exit.png"), 
+                        self.trUtf8('&Quit'), self)
+        self.exitAct.setShortcut(QKeySequence(self.trUtf8("Ctrl+Q","File|Quit")))
+        self.exitAct.setStatusTip(self.trUtf8('Quit the application'))
+        self.exitAct.setWhatsThis(self.trUtf8(
+                """<b>Quit</b>"""
+                """<p>Quit the application.</p>"""
+        ))
+        self.connect(self.exitAct, SIGNAL('triggered()'), 
+                     qApp, SLOT('closeAllWindows()'))
+        
+        self.whatsThisAct = QAction(UI.PixmapCache.getIcon("whatsThis.png"),
+                                self.trUtf8('&What\'s This?'), self)
+        self.whatsThisAct.setShortcut(QKeySequence(self.trUtf8("Shift+F1")))
+        self.whatsThisAct.setStatusTip(self.trUtf8('Context sensitive help'))
+        self.whatsThisAct.setWhatsThis(self.trUtf8(
+                """<b>Display context sensitive help</b>"""
+                """<p>In What's This? mode, the mouse cursor shows an arrow with a"""
+                """ question mark, and you can click on the interface elements to get"""
+                """ a short description of what they do and how to use them. In"""
+                """ dialogs, this feature can be accessed using the context help"""
+                """ button in the titlebar.</p>"""
+        ))
+        self.connect(self.whatsThisAct,SIGNAL('triggered()'),self.__whatsThis)
+
+        self.aboutAct = QAction(self.trUtf8('&About'), self)
+        self.aboutAct.setStatusTip(self.trUtf8('Display information about this software'))
+        self.aboutAct.setWhatsThis(self.trUtf8(
+                """<b>About</b>"""
+                """<p>Display some information about this software.</p>"""
+        ))
+        self.connect(self.aboutAct,SIGNAL('triggered()'),self.__about)
+        
+        self.aboutQtAct = QAction(self.trUtf8('About &Qt'), self)
+        self.aboutQtAct.setStatusTip(\
+            self.trUtf8('Display information about the Qt toolkit'))
+        self.aboutQtAct.setWhatsThis(self.trUtf8(
+                """<b>About Qt</b>"""
+                """<p>Display some information about the Qt toolkit.</p>"""
+        ))
+        self.connect(self.aboutQtAct,SIGNAL('triggered()'),self.__aboutQt)
+        
+        self.tileAct = QAction(self.trUtf8('&Tile'), self)
+        self.tileAct.setStatusTip(self.trUtf8('Tile the windows'))
+        self.tileAct.setWhatsThis(self.trUtf8(
+                """<b>Tile the windows</b>"""
+                """<p>Rearrange and resize the windows so that they are tiled.</p>"""
+        ))
+        self.connect(self.tileAct, SIGNAL('triggered()'),self.preview.tile)
+        
+        self.cascadeAct = QAction(self.trUtf8('&Cascade'), self)
+        self.cascadeAct.setStatusTip(self.trUtf8('Cascade the windows'))
+        self.cascadeAct.setWhatsThis(self.trUtf8(
+                """<b>Cascade the windows</b>"""
+                """<p>Rearrange and resize the windows so that they are cascaded.</p>"""
+        ))
+        self.connect(self.cascadeAct, SIGNAL('triggered()'),self.preview.cascade)
+        
+        self.closeAct = QAction(UI.PixmapCache.getIcon("close.png"),
+                            self.trUtf8('&Close'), self)
+        self.closeAct.setShortcut(QKeySequence(self.trUtf8("Ctrl+W","File|Close")))
+        self.closeAct.setStatusTip(self.trUtf8('Close the current window'))
+        self.closeAct.setWhatsThis(self.trUtf8(
+                """<b>Close Window</b>"""
+                """<p>Close the current window.</p>"""
+        ))
+        self.connect(self.closeAct, SIGNAL('triggered()'),self.preview.closeWidget)
+        
+        self.closeAllAct = QAction(self.trUtf8('Clos&e All'), self)
+        self.closeAllAct.setStatusTip(self.trUtf8('Close all windows'))
+        self.closeAllAct.setWhatsThis(self.trUtf8(
+                """<b>Close All Windows</b>"""
+                """<p>Close all windows.</p>"""
+        ))
+        self.connect(self.closeAllAct, SIGNAL('triggered()'),
+                     self.preview.closeAllWidgets)
+
+    def __initMenus(self):
+        """
+        Private method to create the menus.
+        """
+        mb = self.menuBar()
+
+        menu = mb.addMenu(self.trUtf8('&File'))
+        menu.setTearOffEnabled(True)
+        menu.addAction(self.openUIAct)
+        menu.addAction(self.openQMAct)
+        menu.addAction(self.reloadAct)
+        menu.addSeparator()
+        menu.addAction(self.closeAct)
+        menu.addAction(self.closeAllAct)
+        menu.addSeparator()
+        menu.addAction(self.exitAct)
+        
+        self.windowMenu = mb.addMenu(self.trUtf8('&Window'))
+        self.windowMenu.setTearOffEnabled(True)
+        self.connect(self.windowMenu, SIGNAL('aboutToShow()'), self.__showWindowMenu)
+        self.connect(self.windowMenu, SIGNAL('triggered(QAction *)'),
+                     self.preview.toggleSelectedWidget)
+        
+        mb.addSeparator()
+        
+        menu = mb.addMenu(self.trUtf8('&Help'))
+        menu.setTearOffEnabled(True)
+        menu.addAction(self.aboutAct)
+        menu.addAction(self.aboutQtAct)
+        menu.addSeparator()
+        menu.addAction(self.whatsThisAct)
+
+    def __initToolbars(self):
+        """
+        Private method to create the toolbars.
+        """
+        filetb = self.addToolBar(self.trUtf8("File"))
+        filetb.setIconSize(UI.Config.ToolBarIconSize)
+        filetb.addAction(self.openUIAct)
+        filetb.addAction(self.openQMAct)
+        filetb.addAction(self.reloadAct)
+        filetb.addSeparator()
+        filetb.addAction(self.closeAct)
+        filetb.addSeparator()
+        filetb.addAction(self.exitAct)
+        
+        helptb = self.addToolBar(self.trUtf8("Help"))
+        helptb.setIconSize(UI.Config.ToolBarIconSize)
+        helptb.addAction(self.whatsThisAct)
+    
+    def __whatsThis(self):
+        """
+        Private slot called in to enter Whats This mode.
+        """
+        QWhatsThis.enterWhatsThisMode()
+        
+    def __updateActions(self):
+        """
+        Private slot to update the actions state.
+        """
+        if self.preview.hasWidgets():
+            self.closeAct.setEnabled(True)
+            self.closeAllAct.setEnabled(True)
+            self.tileAct.setEnabled(True)
+            self.cascadeAct.setEnabled(True)
+        else:
+            self.closeAct.setEnabled(False)
+            self.closeAllAct.setEnabled(False)
+            self.tileAct.setEnabled(False)
+            self.cascadeAct.setEnabled(False)
+        
+        if self.translations.hasTranslations():
+            self.reloadAct.setEnabled(True)
+        else:
+            self.reloadAct.setEnabled(False)
+
+    def __about(self):
+        """
+        Private slot to show the about information.
+        """
+        QMessageBox.about(self, self.trUtf8("TR Previewer"), self.trUtf8(
+            """<h3> About TR Previewer </h3>"""
+            """<p>The TR Previewer loads and displays Qt User-Interface files"""
+            """ and translation files and shows dialogs for a selected language.</p>"""
+        ))
+    
+    def __aboutQt(self):
+        """
+        Private slot to show info about Qt.
+        """
+        QMessageBox.aboutQt(self, self.trUtf8("TR Previewer"))
+    
+    def __openWidget(self):
+        """
+        Private slot to handle the Open Dialog action.
+        """
+        fileNameList = QFileDialog.getOpenFileNames(
+            None,
+            self.trUtf8("Select UI files"),
+            "",
+            self.trUtf8("Qt User-Interface Files (*.ui)"))
+        
+        for fileName in fileNameList:
+            self.preview.loadWidget(fileName)
+        
+        self.__updateActions()
+    
+    def __openTranslation(self):
+        """
+        Private slot to handle the Open Translation action.
+        """
+        fileNameList = QFileDialog.getOpenFileNames(
+            None,
+            self.trUtf8("Select translation files"),
+            "",
+            self.trUtf8("Qt Translation Files (*.qm)"))
+        
+        first = True
+        for fileName in fileNameList:
+            self.translations.add(fileName, first)
+            first = False
+        
+        self.__updateActions()
+    
+    def setTranslation(self, name):
+        """
+        Public slot to activate a translation.
+        
+        @param name name (language) of the translation (string or QString)
+        """
+        self.translations.set(name)
+    
+    def __showWindowMenu(self):
+        """
+        Private slot to handle the aboutToShow signal of the window menu.
+        """
+        self.windowMenu.clear()
+        self.windowMenu.addAction(self.tileAct)
+        self.windowMenu.addAction(self.cascadeAct)
+        self.windowMenu.addSeparator()
+
+        self.preview.showWindowMenu(self.windowMenu)
+    
+    def reloadTranslations(self):
+        """
+        Public slot to reload all translations.
+        """
+        self.translations.reload()
+
+class Translation(object):
+    """
+    Class to store the properties of a translation
+    """
+    def __init__(self):
+        """
+        Constructor
+        """
+        self.fileName = None
+        self.name = None
+        self.translator = None
+
+class TranslationsDict(QObject):
+    """
+    Class to store all loaded translations.
+    
+    @signal translationChanged() emit after a translator was set
+    """
+    def __init__(self, selector, parent):
+        """
+        Constructor
+        
+        @param selector reference to the QComboBox used to show the
+            available languages (QComboBox)
+        @param parent parent widget (QWidget)
+        """
+        QObject.__init__(self, parent)
+        
+        self.selector = selector
+        self.currentTranslator = None
+        self.selector.addItem(noTranslationName)
+        self.translations = [] # list of Translation objects
+    
+    def add(self, fileName, setTranslation = True):
+        """
+        Public method to add a translation to the list.
+        
+        If the translation file (*.qm) has not been loaded yet, it will
+        be loaded automatically.
+        
+        @param fileName name of the translation file to be added (string)
+        @param setTranslation flag indicating, if this should be set as the active
+            translation (boolean)
+        """
+        if not self.__haveFileName(fileName):
+            ntr = Translation()
+            ntr.fileName = fileName
+            ntr.name = self.__uniqueName(fileName)
+            if ntr.name is None:
+                QMessageBox.warning(None,
+                    self.trUtf8("Set Translator"),
+                    self.trUtf8("""<p>The translation filename <b>{0}</b>"""
+                        """ is invalid.</p>""").format(fileName))
+                return
+            
+            ntr.translator = self.loadTransFile(fileName)
+            if ntr.translator is None:
+                return
+            
+            self.selector.addItem(ntr.name)
+            self.translations.append(ntr)
+        
+        if setTranslation:
+            tr = self.__findFileName(fileName)
+            self.set(tr.name)
+    
+    def set(self, name):
+        """
+        Public slot to set a translator by name.
+        
+        @param name name (language) of the translator to set (string)
+        """
+        nTranslator = None
+        
+        if name != noTranslationName:
+            trans = self.__findName(name)
+            if trans is None:
+                QMessageBox.warning(None,
+                    self.trUtf8("Set Translator"),
+                    self.trUtf8("""<p>The translator <b>{0}</b> is not known.</p>""")\
+                        .format(name))
+                return
+                
+            nTranslator = trans.translator
+        
+        if nTranslator == self.currentTranslator:
+            return
+        
+        if self.currentTranslator is not None:
+            QApplication.removeTranslator(self.currentTranslator)
+        if nTranslator is not None:
+            QApplication.installTranslator(nTranslator)
+        self.currentTranslator = nTranslator
+        
+        self.selector.blockSignals(True)
+        self.selector.setCurrentIndex(self.selector.findText(name))
+        self.selector.blockSignals(False)
+        
+        self.emit(SIGNAL('translationChanged'))
+    
+    def reload(self):
+        """
+        Public method to reload all translators.
+        """
+        cname = self.selector.currentText()
+        if self.currentTranslator is not None:
+            QApplication.removeTranslator(self.currentTranslator)
+            self.currentTranslator = None
+        
+        fileNames = []
+        for trans in self.translations:
+            trans.translator = None
+            fileNames.append(trans.fileName)
+        self.translations = []
+        self.selector.clear()
+        
+        self.selector.addItem(noTranslationName)
+        
+        for fileName in fileNames:
+            self.add(fileName, False)
+        
+        if self.__haveName(cname):
+            self.set(cname)
+        else:
+            self.set(noTranslationName)
+    
+    def __findFileName(self, transFileName):
+        """
+        Private method to find a translation by file name.
+        
+        @param transFileName file name of the translation file (string)
+        @return reference to a translation object or None
+        """
+        for trans in self.translations:
+            if trans.fileName == transFileName:
+                return trans
+        return None
+    
+    def __findName(self, name):
+        """
+        Private method to find a translation by name.
+        
+        @param name name (language) of the translation (string)
+        @return reference to a translation object or None
+        """
+        for trans in self.translations:
+            if trans.name == name:
+                return trans
+        return None
+    
+    def __haveFileName(self, transFileName):
+        """
+        Private method to check for the presence of a translation.
+        
+        @param transFileName file name of the translation file (string)
+        @return flag indicating the presence of the translation (boolean)
+        """
+        return self.__findFileName(transFileName) is not None
+    
+    def __haveName(self, name):
+        """
+        Private method to check for the presence of a named translation.
+        
+        @param name name (language) of the translation (string)
+        @return flag indicating the presence of the translation (boolean)
+        """
+        return self.__findName(name) is not None
+    
+    def __uniqueName(self, transFileName):
+        """
+        Private method to generate a unique name.
+        
+        @param transFileName file name of the translation file (string)
+        @return unique name (string or None)
+        """
+        name = os.path.basename(transFileName)
+        if not name:
+            return None
+        
+        uname = name
+        cnt = 1
+        while self.__haveName(uname):
+            cnt += 1
+            uname = "{0} <{1}>".format(name, cnt)
+        
+        return uname
+    
+    def __del(self, name):
+        """
+        Private method to delete a translator from the list of available translators.
+        
+        @param name name of the translator to delete (string or QString)
+        """
+        if name == noTranslationName:
+            return
+        
+        trans = self.__findName(name)
+        if trans is None:
+            return
+        
+        if self.selector().currentText() == name:
+            self.set(noTranslationName)
+        
+        self.translations.remove(trans)
+        del trans
+    
+    def loadTransFile(self, transFileName):
+        """
+        Public slot to load a translation file.
+        
+        @param transFileName file name of the translation file (string)
+        @return reference to the new translator object (QTranslator)
+        """
+        tr = QTranslator()
+        if tr.load(transFileName):
+            return tr
+        
+        QMessageBox.warning(None,
+            self.trUtf8("Load Translator"),
+            self.trUtf8("""<p>The translation file <b>{0}</b> could not be loaded.</p>""")\
+                .format(transFileName))
+        return None
+
+    def hasTranslations(self):
+        """
+        Public method to check for loaded translations.
+        
+        @return flag signaling if any translation was loaded (boolean)
+        """
+        return len(self.translations) > 0
+
+class WidgetView(QWidget):
+    """
+    Class to show a dynamically loaded widget (or dialog).
+    """
+    def __init__(self, uiFileName, parent = None, name = None):
+        """
+        Constructor
+        
+        @param uiFileName name of the UI file to load (string)
+        @param parent parent widget (QWidget)
+        @param name name of this widget (string)
+        """
+        QWidget.__init__(self, parent)
+        if name:
+            self.setObjectName(name)
+            self.setWindowTitle(name)
+        self.setAttribute(Qt.WA_DeleteOnClose)
+        
+        self.__widget = None
+        self.__uiFileName = uiFileName
+        self.__layout = QHBoxLayout(self)
+        self.__valid = False
+        self.__timer = QTimer(self)
+        self.__timer.setSingleShot(True)
+        self.connect(self.__timer, SIGNAL('timeout()'), self.buildWidget)
+    
+    def isValid(self):
+        """
+        Public method to return the validity of this widget view.
+        
+        @return flag indicating the validity (boolean)
+        """
+        return self.__valid
+    
+    def uiFileName(self):
+        """
+        Public method to retrieve the name of the UI file.
+        
+        @return filename of the loaded UI file (string)
+        """
+        return self.__uiFileName
+    
+    def buildWidget(self):
+        """
+        Public slot to load a UI file.
+        """
+        if self.__widget:
+            self.__widget.close()
+            self.__layout.removeWidget(self.__widget)
+            del self.__widget
+            self.__widget = None
+        
+        try:
+            self.__widget = uic.loadUi(self.__uiFileName)
+        except:
+            pass
+        
+        if not self.__widget:
+            QMessageBox.warning(None,
+                self.trUtf8("Load UI File"),
+                self.trUtf8("""<p>The file <b>{0}</b> could not be loaded.</p>""")\
+                    .format(self.__uiFileName))
+            self.__valid = False
+            return
+        
+        self.__widget.setParent(self)
+        self.__layout.addWidget(self.__widget)
+        self.__widget.show()
+        self.__valid = True
+        self.adjustSize()
+        
+        self.__timer.stop()
+    
+    def __rebuildWidget(self):
+        """
+        Private method to schedule a rebuild of the widget.
+        """
+        self.__timer.start(0)
+
+class WidgetWorkspace(QWorkspace):
+    """
+    Specialized workspace to show the loaded widgets.
+    
+    @signal lastWidgetClosed() emitted after last widget was closed
+    """
+    def __init__(self, parent = None):
+        """
+        Constructor
+        
+        @param parent parent widget (QWidget)
+        """
+        QWorkspace.__init__(self, parent)
+        
+        self.setScrollBarsEnabled(True)
+        
+        self.widgets = []
+    
+    def loadWidget(self, uiFileName):
+        """
+        Public slot to load a UI file.
+        
+        @param uiFileName name of the UI file to load (string)
+        """
+        widget = self.__findWidget(uiFileName)
+        if widget is None:
+            name = os.path.basename(uiFileName)
+            if not name:
+                QMessageBox.warning(None,
+                    self.trUtf8("Load UI File"),
+                    self.trUtf8("""<p>The file <b>{0}</b> could not be loaded.</p>""")\
+                        .format(uiFileName))
+                return
+            
+            uname = name
+            cnt = 1
+            while self.findChild(WidgetView, uname) is not None:
+                cnt += 1
+                uname = "{0} <{1}>".format(name, cnt)
+            name = uname
+            
+            wview = WidgetView(uiFileName, self, name)
+            wview.buildWidget()
+            if not wview.isValid():
+                del wview
+                return
+            
+            self.connect(self, SIGNAL("rebuildWidgets"), wview.buildWidget)
+            wview.installEventFilter(self)
+            
+            self.addWindow(wview)
+            self.widgets.append(wview)
+        
+        wview.showNormal()
+    
+    def eventFilter(self, obj, ev):
+        """
+        Protected method called to filter an event.
+        
+        @param object object, that generated the event (QObject)
+        @param event the event, that was generated by object (QEvent)
+        @return flag indicating if event was filtered out
+        """
+        if not isinstance(obj, QWidget):
+            return False
+        
+        if not obj in self.widgets:
+            return False
+            
+        if ev.type() == QEvent.Close:
+            try:
+                self.widgets.remove(obj)
+                if len(self.widgets) == 0:
+                    self.emit(SIGNAL('lastWidgetClosed'))
+            except ValueError:
+                pass
+        
+        return False
+    
+    def __findWidget(self, uiFileName):
+        """
+        Private method to find a specific widget view.
+        
+        @param uiFileName filename of the loaded UI file (string)
+        @return reference to the widget (WidgetView) or None
+        """
+        wviewList = self.findChildren(WidgetView)
+        if wviewList is None:
+            return None
+        
+        for wview in wviewList:
+            if wview.uiFileName() == uiFileName:
+                return wview
+        
+        return None
+    
+    def closeWidget(self):
+        """
+        Public slot to close the active window.
+        """
+        aw = self.activeWindow()
+        if aw is not None:
+            aw.close()
+    
+    def closeAllWidgets(self):
+        """
+        Public slot to close all windows.
+        """
+        for w in self.widgets[:]:
+            w.close()
+    
+    def showWindowMenu(self, windowMenu):
+        """
+        Public method to set up the widgets part of the Window menu.
+        
+        @param windowMenu reference to the window menu
+        """
+        idx = 0
+        for wid in self.widgets:
+            act = windowMenu.addAction(wid.windowTitle())
+            act.setData(QVariant(idx))
+            act.setCheckable(True)
+            act.setChecked(not wid.isHidden())
+            idx = idx + 1
+    
+    def toggleSelectedWidget(self, act):
+        """
+        Public method to handle the toggle of a window.
+        
+        @param act reference to the action that triggered (QAction)
+        """
+        idx, ok = act.data().toInt()
+        if ok:
+            self.__toggleWidget(self.widgets[idx])
+    
+    def __toggleWidget(self, w):
+        """
+        Private method to toggle a workspace window.
+        
+        @param w window to be toggled
+        """
+        if w.isHidden():
+            w.show()
+        else:
+            w.hide()
+    
+    def hasWidgets(self):
+        """
+        Public method to check for loaded widgets.
+        
+        @return flag signaling if any widget was loaded (boolean)
+        """
+        return len(self.widgets) > 0

eric ide

mercurial