# -*- coding: utf-8 -*-

# Copyright (c) 2004 - 2006 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing the TR Previewer main window.
"""

import sys

from qt import *
from qtui import QWidgetFactory

from KdeQt import KQFileDialog, KQMessageBox
from KdeQt.KQPrinter import KQPrinter
import KdeQt

from TRSingleApplication import TRSingleApplicationServer

import Preferences
import UI.PixmapCache


noTranslationName = qApp.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 or QString)
        """
        self.mainWidget = None
        self.currentFile = QDir.homeDirPath()
        
        QMainWindow.__init__(self, parent, name, Qt.WDestructiveClose)
        self.statusBar()
        
        self.setIcon(UI.PixmapCache.getPixmap("eric.png"))
        self.setCaption(self.trUtf8("Translations Previewer"))

        if not name:
            self.setName("TRPreviewer")

        self.setCentralWidget(QWidget(self, "qt_central_widget"))
        TRPreviewerLayout = QVBoxLayout(self.centralWidget(), 6, 6, "TRPreviewerLayout")

        languageLayout = QHBoxLayout(None,0,6,"languageLayout")

        self.languageLabel = QLabel(self.trUtf8("Select language file"), 
            self.centralWidget(), "languageLabel")
        languageLayout.addWidget(self.languageLabel)

        self.languageCombo = QComboBox(0, self.centralWidget(), "languageCombo")
        QToolTip.add(self.languageCombo, self.trUtf8("Select language file"))
        languageLayout.addWidget(self.languageCombo)
        
        languageSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        languageLayout.addItem(languageSpacer)
        TRPreviewerLayout.addLayout(languageLayout)

        self.preview = WidgetWorkspace(self.centralWidget(), "preview")
        TRPreviewerLayout.addWidget(self.preview)
        self.connect(self.preview, PYSIGNAL('lastWidgetClosed'), self.updateActions)

        self.resize(QSize(800, 600).expandedTo(self.minimumSizeHint()))
        self.clearWState(Qt.WState_Polished)

        self.connect(self.languageCombo,SIGNAL("activated(const QString&)"),
                     self.setTranslation)
        
        self.translations = TranslationsDict(self.languageCombo, self)
        self.connect(self.translations, PYSIGNAL('translationChanged'),
                     self.preview, PYSIGNAL('rebuildWidgets'))
        
        self.initActions()
        self.initMenus()
        self.initToolbars()
        
        self.updateActions()
        
        # fire up the single application server
        self.SAServer = TRSingleApplicationServer(self)
        self.connect(self.SAServer, PYSIGNAL('loadForm'), self.preview.loadWidget)
        self.connect(self.SAServer, PYSIGNAL('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 = 1
            for fn in filenames:
                fi = QFileInfo(fn)
                if fi.extension().lower().compare('ui') == 0:
                    self.preview.loadWidget(fn)
                elif fi.extension().lower().compare('qm') == 0:
                    self.translations.add(fn, first)
                    first = 0
            
            self.updateActions()
        
    def closeEvent(self, event):
        """
        Private event handler for the close event.
        
        This event handler saves the preferences.
        
        @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(self.trUtf8('Open UI Files'), 
                        QIconSet(UI.PixmapCache.getPixmap("openUI.png")), 
                        self.trUtf8('&Open UI Files...'),
                        0, 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('activated()'), self.handleOpenWidget)
        
        self.openQMAct = QAction(self.trUtf8('Open Translation Files'), 
                        QIconSet(UI.PixmapCache.getPixmap("openQM.png")), 
                        self.trUtf8('Open &Translation Files...'),
                        0, 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('activated()'), self.handleOpenTranslation)
        
        self.reloadAct = QAction(self.trUtf8('Reload Translations'), 
                        QIconSet(UI.PixmapCache.getPixmap("reload.png")), 
                        self.trUtf8('&Reload Translations'),
                        0, 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('activated()'), self.translations.reload)
        
        self.exitAct = QAction(self.trUtf8('Quit'), 
                        QIconSet(UI.PixmapCache.getPixmap("exit.png")), 
                        self.trUtf8('&Quit'), 
                        QKeySequence(self.trUtf8("CTRL+Q","File|Quit")), 
                        self)
        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('activated()'), qApp, SLOT('closeAllWindows()'))
        
        self.whatsThisAct = QAction(self.trUtf8('What\'s This?'),
                                QIconSet(UI.PixmapCache.getPixmap("whatsThis.png")),
                                self.trUtf8('&What\'s This?'),
                                Qt.SHIFT+Qt.Key_F1,self)
        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('activated()'),self.whatsThis)

        self.aboutAct = QAction(self.trUtf8('About'),
                            self.trUtf8('&About'),0,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('activated()'),self.handleAbout)
        
        self.aboutQtAct = QAction(self.trUtf8('About Qt'),
                            self.trUtf8('About &Qt'),0,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('activated()'),self.handleAboutQt)
        
        self.tileAct = QAction(self.trUtf8('Tile'),
                            self.trUtf8('&Tile'),0,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('activated()'),self.preview.tile)
        
        self.cascadeAct = QAction(self.trUtf8('Cascade'),
                            self.trUtf8('&Cascade'),0,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('activated()'),self.preview.cascade)
        
        self.closeAct = QAction(self.trUtf8('Close'),
                            QIconSet(UI.PixmapCache.getPixmap("close.png")),
                            self.trUtf8('&Close'),
                            QKeySequence(self.trUtf8("CTRL+W","File|Close")),
                            self)
        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('activated()'),self.preview.handleClose)
        
        self.closeAllAct = QAction(self.trUtf8('Close All'),
                            self.trUtf8('Clos&e All'),0,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('activated()'),self.preview.handleCloseAll)

    def initMenus(self):
        """
        Private method to create the menus.
        """
        mb = self.menuBar()

        menu = QPopupMenu(self)
        mb.insertItem(self.trUtf8('&File'),menu)
        menu.insertTearOffHandle()
        self.openUIAct.addTo(menu)
        self.openQMAct.addTo(menu)
        self.reloadAct.addTo(menu)
        menu.insertSeparator()
        self.closeAct.addTo(menu)
        self.closeAllAct.addTo(menu)
        menu.insertSeparator()
        self.exitAct.addTo(menu)
        
        self.windowMenu = QPopupMenu(self)
        mb.insertItem(self.trUtf8('&Window'),self.windowMenu)
        self.connect(self.windowMenu, SIGNAL('aboutToShow()'), self.handleShowWindowMenu)
        
        mb.insertSeparator()
        
        menu = QPopupMenu(self)
        mb.insertItem(self.trUtf8('&Help'),menu)
        menu.insertTearOffHandle()
        self.aboutAct.addTo(menu)
        self.aboutQtAct.addTo(menu)
        menu.insertSeparator()
        self.whatsThisAct.addTo(menu)

    def initToolbars(self):
        """
        Private method to create the toolbars.
        """
        filetb = QToolBar(self)
        helptb = QToolBar(self)
        
        self.openUIAct.addTo(filetb)
        self.openQMAct.addTo(filetb)
        self.reloadAct.addTo(filetb)
        filetb.addSeparator()
        self.closeAct.addTo(filetb)
        filetb.addSeparator()
        self.exitAct.addTo(filetb)
        
        self.whatsThisAct.addTo(helptb)
    
    def updateActions(self):
        """
        Private slot to update the actions state.
        """
        if self.preview.hasWidgets():
            self.closeAct.setEnabled(1)
            self.closeAllAct.setEnabled(1)
            self.tileAct.setEnabled(1)
            self.cascadeAct.setEnabled(1)
        else:
            self.closeAct.setEnabled(0)
            self.closeAllAct.setEnabled(0)
            self.tileAct.setEnabled(0)
            self.cascadeAct.setEnabled(0)
        
        if self.translations.hasTranslations():
            self.reloadAct.setEnabled(1)
        else:
            self.reloadAct.setEnabled(0)

    def handleAbout(self):
        """
        Private slot to show the about information.
        """
        KQMessageBox.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 handleAboutQt(self):
        """
        Private slot to show info about Qt.
        """
        QMessageBox.aboutQt(self, self.trUtf8("TR Previewer"))
    
    def handleOpenWidget(self):
        """
        Private slot to handle the Open Dialog action.
        """
        fileNameList = KQFileDialog.getOpenFileNames(\
            self.trUtf8("Qt User-Interface Files (*.ui)"),
            QString.null, None, None,
            self.trUtf8("Select UI files"),
            None, 1)
        
        for fileName in fileNameList:
            self.preview.loadWidget(fileName)
        
        self.updateActions()
    
    def handleOpenTranslation(self):
        """
        Private slot to handle the Open Translation action.
        """
        fileNameList = KQFileDialog.getOpenFileNames(\
            self.trUtf8("Qt Translation Files (*.qm)"),
            QString.null, None, None,
            self.trUtf8("Select translation files"),
            None, 1)
        
        first = 1
        for fileName in fileNameList:
            self.translations.add(fileName, first)
            first = 0
        
        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 handleShowWindowMenu(self):
        """
        Private slot to handle the aboutToShow signal of the window menu.
        """
        self.windowMenu.clear()
        self.windowMenu.insertTearOffHandle()
        self.tileAct.addTo(self.windowMenu)
        self.cascadeAct.addTo(self.windowMenu)
        self.windowMenu.insertSeparator()
        
        self.preview.handleShowWindowMenu(self.windowMenu)
    
    def reloadTranslations(self):
        """
        Public slot to reload all translations.
        """
        self.translations.reload()

class Translation:
    """
    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.insertItem(noTranslationName)
        self.translations = [] # list of Translation objects
    
    def add(self, transFileName, setTranslation = 1):
        """
        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 transFileName name of the translation file to be added (string or QString)
        @param setTranslation flag indicating, if this should be set as the active
            translation (boolean)
        """
        fileName = QString(transFileName)
        if not self.__haveFileName(fileName):
            ntr = Translation()
            ntr.fileName = fileName
            ntr.name = self.__uniqueName(fileName)
            if ntr.name.isNull():
                KQMessageBox.warning(None,
                    self.trUtf8("Set Translator"),
                    self.trUtf8("""<p>The translation filename <b>%1</b> is invalid.</p>""")\
                        .arg(fileName),
                    self.trUtf8("&OK"),
                    QString.null,
                    QString.null,
                    0, -1)
                return
            
            ntr.translator = self.loadTransFile(fileName)
            if ntr.translator is None:
                return
            
            self.selector.insertItem(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 or QString)
        """
        name = QString(name)
        nTranslator = None
        
        if name.compare(noTranslationName) != 0:
            trans = self.__findName(name)
            if trans is None:
                KQMessageBox.warning(None,
                    self.trUtf8("Set Translator"),
                    self.trUtf8("""<p>The translator <b>%1</b> is not known.</p>""")\
                        .arg(name),
                    self.trUtf8("&OK"),
                    QString.null,
                    QString.null,
                    0, -1)
                return
                
            nTranslator = trans.translator
        
        if nTranslator == self.currentTranslator:
            return
        
        if self.currentTranslator is not None:
            qApp.removeTranslator(self.currentTranslator)
        if nTranslator is not None:
            qApp.installTranslator(nTranslator)
        self.currentTranslator = nTranslator
        
        self.selector.blockSignals(1)
        self.selector.setCurrentText(name)
        self.selector.blockSignals(0)
        
        self.emit(PYSIGNAL('translationChanged'), ())
    
    def reload(self):
        """
        Public method to reload all translators.
        """
        cname = self.selector.currentText()
        if self.currentTranslator is not None:
            qApp.removeTranslator(self.currentTranslator)
            self.currentTranslator = None
        
        fileNames = QStringList()
        for trans in self.translations:
            trans.translator = None
            fileNames.append(trans.fileName)
        self.translations = []
        self.selector.clear()
        
        self.selector.insertItem(noTranslationName)
        
        for fileName in fileNames:
            self.add(fileName, 0)
        
        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 or QString)
        @return reference to a translation object or None
        """
        for trans in self.translations:
            if trans.fileName.compare(transFileName) == 0:
                return trans
        return None
    
    def __findName(self, name):
        """
        Private method to find a translation by name.
        
        @param name name (language) of the translation (string or QString)
        @return reference to a translation object or None
        """
        for trans in self.translations:
            if trans.name.compare(name) == 0:
                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 or QString)
        @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 or QString)
        @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 or QString)
        @return unique name (QString)
        """
        name = _filename(transFileName)
        if name.isNull():
            return QString.null
        
        uname = QString(name)
        cnt = 1
        while self.__haveName(uname):
            cnt += 1
            uname = QString("%1 <%2>").arg(name).arg(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)
        """
        name = QString(name)
        if name.compare(noTranslationName) == 0:
            return
        
        trans = self.__findName(name)
        if trans is None:
            return
        
        if self.selector().currentText().compare(name) == 0:
            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 or QString)
        @return reference to the new translator object (QTranslator)
        """
        tr = QTranslator()
        if tr.load(transFileName):
            return tr
        
        KQMessageBox.warning(None,
            self.trUtf8("Load Translator"),
            self.trUtf8("""<p>The translation file <b>%1</b> could not be loaded.</p>""")\
                .arg(transFileName),
            self.trUtf8("&OK"),
            QString.null,
            QString.null,
            0, -1)
        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 or QString)
        @param parent parent widget (QWidget)
        @param name name of this widget (string)
        """
        QWidget.__init__(self, parent, str(name), Qt.WDestructiveClose)
        
        self.__widget = None
        self.__uiFileName = uiFileName
        self.__layout = QHBoxLayout(self)
        self.__valid = 0
        self.__timer = QTimer(self)
        self.connect(self.__timer, SIGNAL('timeout()'), self.buildWidget)
        
        self.setCaption(name)
    
    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 (QString)
        """
        return QString(self.__uiFileName)
    
    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 obj != self.__widget:
            return 0
            
        if ev.type() in [QEvent.Close, QEvent.Hide]:
            self.__rebuildWidget()
            
        return 0
    
    def buildWidget(self):
        """
        Public slot to load a UI file.
        """
        if self.__widget:
            self.__widget.close()
            self.__widget = None
        
        self.__widget = QWidgetFactory.create(self.__uiFileName)
        if not self.__widget:
            KQMessageBox.warning(None,
                self.trUtf8("Load UI File"),
                self.trUtf8("""<p>The file <b>%1</b> could not be loaded.</p>""")\
                    .arg(self.__uiFileName),
                self.trUtf8("&OK"),
                QString.null,
                QString.null,
                0, -1)
            self.__valid = 0
            return
            
        self.__widget.installEventFilter(self)
        self.__widget.reparent(self, 0, QPoint(0, 0))
        self.__layout.addWidget(self.__widget)
        self.__widget.show()
        self.__valid = 1
        self.adjustSize()
        
        self.__timer.stop()
    
    def __rebuildWidget(self):
        """
        Private method to schedule a rebuild of the widget.
        """
        self.__timer.start(0, 1)

class WidgetWorkspace(QWorkspace):
    """
    Specialized workspace to show the loaded widgets.
    """
    def __init__(self, parent = None, name = None):
        """
        Constructor
        
        @param parent parent widget (QWidget)
        @param name name of this widget (string)
        """
        QWorkspace.__init__(self, parent, name)
        
        self.setScrollBarsEnabled(1)
        
        self.widgets = []
    
    def loadWidget(self, uiFileName):
        """
        Public slot to load a UI file.
        
        @param uiFileName name of the UI file to load (string or QString)
        """
        widget = self.__findWidget(uiFileName)
        if widget is None:
            name = _filename(uiFileName)
            if name.isEmpty():
                KQMessageBox.warning(None,
                    self.trUtf8("Load UI File"),
                    self.trUtf8("""<p>The file <b>%1</b> could not be loaded.</p>""")\
                        .arg(uiFileName),
                    self.trUtf8("&OK"),
                    QString.null,
                    QString.null,
                    0, -1)
                return
            
            uname = QString(name)
            cnt = 1
            while self.child(str(uname)) is not None:
                cnt += 1
                uname = QString("%1 <%2>").arg(name).arg(cnt)
            name = QString(uname)
            
            wview = WidgetView(uiFileName, self, name)
            wview.buildWidget()
            if not wview.isValid():
                del wview
                return
            
            self.connect(self, PYSIGNAL("rebuildWidgets"), wview.buildWidget)
            wview.installEventFilter(self)
            
            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 0
        
        if not obj in self.widgets:
            return 0
            
        if ev.type() == QEvent.Close:
            try:
                self.widgets.remove(obj)
                if len(self.widgets) == 0:
                    self.emit(PYSIGNAL('lastWidgetClosed'), ())
            except ValueError:
                pass
        
        return 0
    
    def __findWidget(self, uiFileName):
        """
        Private method to find a specific widget view.
        
        @param uiFileName filename of the loaded UI file (string or QString)
        @return reference to the widget (WidgetView) or None
        """
        wviewList = self.queryList("WidgetView")
        if wviewList is None:
            return None
        
        for wview in wviewList:
            if wview.uiFileName().compare(uiFileName) == 0:
                return wview
        
        return None
    
    def handleClose(self):
        """
        Public slot to close the active window.
        """
        aw = self.activeWindow()
        if aw is not None:
            aw.close()
    
    def handleCloseAll(self):
        """
        Public slot to close all windows.
        """
        for w in self.widgets[:]:
            w.close()
    
    def handleShowWindowMenu(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:
            id = windowMenu.insertItem(wid.caption(), self.handleWidget)
            windowMenu.setItemParameter(id, idx)
            windowMenu.setItemChecked(id, not wid.isHidden())

            idx = idx + 1
    
    def handleWidget(self, idx):
        """
        Private method to handle the toggle of a window.
        
        @param idx index of the window to toggle (int)
        """
        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

def _filename(path):
    """
    Private module function to chop off the path.
    
    @param path path to extract the filename from (string or QString)
    @return extracted filename (QString)
    """
    path = QString(path)
    idx = path.findRev("/")
    if idx == -1:
        idx = path.findRev(QDir.separator())
    if idx == -1:
        return path
    else:
        return path.mid(idx + 1)
