示例#1
0
    def __init__(self, application):
        """
        The main window
        @param parent: The QObject parent, in this case it should be the QApp
        @param files_to_open: The set of files to be opened when the window is shown in the screen.
        """
        QtGui.QMainWindow.__init__(self)
        self.application = application
        self.setupUi(self)
        
        self.setupDialogs()
        self.setupDockToolBars()
        self.setupMenu()
        
        self.setStatusBar(PMXStatusBar(self))
        
        # Connect Signals
        self.splitTabWidget.currentWidgetChanged.connect(self.on_currentWidgetChanged)
        self.splitTabWidget.currentWidgetChanged.connect(self.setWindowTitleForEditor)
        self.splitTabWidget.tabCloseRequest.connect(self.closeEditor)
        self.splitTabWidget.tabCreateRequest.connect(self.addEmptyEditor)
        self.application.supportManager.bundleItemTriggered.connect(self.insertBundleItem)
        
        utils.centerWidget(self, scale = (0.9, 0.8))
        self.dockers = []
        self.customEditorActions = {}
        self.customDockActions = {}

        self.setAcceptDrops(True)
        
        self.setMainWindowAsActionParent()
        self.setupHelpMenuMiscConnections()
        self.commandProcessor = MainWindowCommandProcessor(self)
示例#2
0
    def __init__(self, application):
        """
        The main window
        @param parent: The QObject parent, in this case it should be the QApp
        @param files_to_open: The set of files to be opened when the window is shown in the screen.
        """
        QtGui.QMainWindow.__init__(self)
        self.application = application
        self.setupUi(self)

        self.setWindowIcon(resources.getIcon("prymatex"))

        self.setupDialogs()
        self.setupDockToolBars()
        self.setupMenu()

        self.setStatusBar(PMXStatusBar(self))

        # Connect Signals
        self.splitTabWidget.currentWidgetChanged.connect(
            self.on_currentWidgetChanged)
        self.splitTabWidget.currentWidgetChanged.connect(
            self.setWindowTitleForEditor)
        self.splitTabWidget.tabCloseRequest.connect(self.closeEditor)
        self.splitTabWidget.tabCreateRequest.connect(self.addEmptyEditor)
        self.application.supportManager.bundleItemTriggered.connect(
            self.on_bundleItemTriggered)

        center_widget(self, scale=(0.9, 0.8))
        self.dockers = []
        self.customEditorActions = {}
        self.customDockActions = {}

        self.setAcceptDrops(True)

        #self.setMainWindowAsActionParent()
        self.setupHelpMenuMiscConnections()

        self.popupMessage = PopupMessageWidget(self)

        #Processor de comandos local a la main window
        self.commandProcessor = MainWindowCommandProcessor(self)
        self.bundleItem_handler = self.insertBundleItem
示例#3
0
class PMXMainWindow(QtGui.QMainWindow, Ui_MainWindow, MainWindowActions):
    """Prymatex main window"""
    #=========================================================
    # Signals
    #=========================================================
    currentEditorChanged = QtCore.pyqtSignal(object)

    #=========================================================
    # Settings
    #=========================================================
    SETTINGS_GROUP = 'MainWindow'

    @pmxConfigPorperty(default = "$PMX_APP_NAME ($PMX_VERSION)")
    def windowTitleTemplate(self, titleTemplate):
         self.titleTemplate = Template(titleTemplate)
    
    @pmxConfigPorperty(default = True)
    def showMenuBar(self, value):
        self._showMenuBar = value
        self.menuBar().setShown(value)
    
    _editorHistory = []
    _editorHistoryIndex = 0
    
    # Constructor
    def __init__(self, application):
        """
        The main window
        @param parent: The QObject parent, in this case it should be the QApp
        @param files_to_open: The set of files to be opened when the window is shown in the screen.
        """
        QtGui.QMainWindow.__init__(self)
        self.application = application
        self.setupUi(self)
        
        self.setupDialogs()
        self.setupDockToolBars()
        self.setupMenu()
        
        self.setStatusBar(PMXStatusBar(self))
        
        # Connect Signals
        self.splitTabWidget.currentWidgetChanged.connect(self.on_currentWidgetChanged)
        self.splitTabWidget.currentWidgetChanged.connect(self.setWindowTitleForEditor)
        self.splitTabWidget.tabCloseRequest.connect(self.closeEditor)
        self.splitTabWidget.tabCreateRequest.connect(self.addEmptyEditor)
        self.application.supportManager.bundleItemTriggered.connect(self.insertBundleItem)
        
        utils.centerWidget(self, scale = (0.9, 0.8))
        self.dockers = []
        self.customEditorActions = {}
        self.customDockActions = {}

        self.setAcceptDrops(True)
        
        self.setMainWindowAsActionParent()
        self.setupHelpMenuMiscConnections()
        self.commandProcessor = MainWindowCommandProcessor(self)

    #==========================================================================
    # Bundle Items
    #==========================================================================
    def insertBundleItem(self, bundleItem, **processorSettings):
        '''Insert selected bundle item in current editor if possible'''
        editor = self.currentEditor()
        if editor is not None:
            self.currentEditor().insertBundleItem(bundleItem)
        elif not bundleItem.isEditorNeeded():
            print "vamos con nuestro processor"
            self.commandProcessor.configure(processorSettings)
            bundleItem.execute(self.commandProcessor)
        else:
            QtGui.QMessageBox.information(self, _("No editor open"), 
                                          _("%s needs an editor to run") % bundleItem.name)

    def buildEnvironment(self, env = {}):
        env.update({})
        return env

    @classmethod
    def contributeToSettings(cls):
        from prymatex.gui.settings.general import PMXGeneralWidget
        return [ PMXGeneralWidget ]
        
    #============================================================
    # Setups
    #============================================================
    def setupDialogs(self):
        from prymatex.gui.dialogs.selector import PMXSelectorDialog
                
        # Create dialogs
        self.bundleSelectorDialog = PMXSelectorDialog(self, title = _("Select Bundle Item"))
        # TODO: Connect these selectors 
        self.tabSelectorDialog = PMXSelectorDialog(self, title = _("Select tab"))
        self.symbolSelectorDialog = PMXSelectorDialog(self, title = _("Select Symbol"))
        self.bookmarkSelectorDialog = PMXSelectorDialog(self, title = _("Select Bookmark"))
    
    def setupDockToolBars(self):
        self.dockToolBars = {
            QtCore.Qt.LeftDockWidgetArea: DockWidgetToolBar("Left Dockers", QtCore.Qt.LeftDockWidgetArea, self),
            QtCore.Qt.RightDockWidgetArea: DockWidgetToolBar("Right Dockers", QtCore.Qt.RightDockWidgetArea, self),
            QtCore.Qt.TopDockWidgetArea: DockWidgetToolBar("Top Dockers", QtCore.Qt.TopDockWidgetArea, self),
            QtCore.Qt.BottomDockWidgetArea: DockWidgetToolBar("Bottom Dockers", QtCore.Qt.BottomDockWidgetArea, self),
        }
        for dockArea, toolBar in self.dockToolBars.iteritems():
            self.addToolBar(DockWidgetToolBar.DOCK_AREA_TO_TB[dockArea], toolBar)
            toolBar.hide()

    def toggleDockToolBarVisibility(self):
        for toolBar in self.dockToolBars.values():
            if toolBar.isVisible():
                toolBar.hide()
            else:
                toolBar.show()

    #============================================================
    # Componer la mainWindow
    #============================================================
    def addStatusBar(self, statusBar):
        self.statusBar().addPermanentWidget(statusBar)
    
    # Dockers    
    def addDock(self, dock, area):
        self.addDockWidget(area, dock)
        toggleAction = dock.toggleViewAction()
        self.menuPanels.addAction(toggleAction)
        self.addAction(toggleAction)
        titleBar = DockWidgetTitleBar(dock)
        titleBar.collpaseAreaRequest.connect(self.on_dockWidgetTitleBar_collpaseAreaRequest)
        dock.setTitleBarWidget(titleBar)
        dock.hide()
        self.dockers.append(dock)
    
    def on_dockWidgetTitleBar_collpaseAreaRequest(self, dock):
        if not dock.isFloating():
            area = self.dockWidgetArea(dock)
            self.dockToolBars[area].show()
        
    def addEditor(self, editor, focus = True):
        self.splitTabWidget.addTab(editor)
        if focus:
            self.setCurrentEditor(editor)
            
    def createCustomEditorMainMenu(self, name):
        menu = QtGui.QMenu(name, self.menubar)
        objectName = textToObjectName(name, prefix = "menu")
        menu.setObjectName(objectName)
        setattr(self, objectName, menu)
        action = self.menubar.insertMenu(self.menuNavigation.children()[0], menu)
        return menu, action

    def contributeToMainMenu(self, name, settings):
        actions = []
        menu = getattr(self, "menu" + name, None)
        if menu is None:
            menu, action = self.createCustomEditorMainMenu(name)
            actions.append(action)
        if 'items' in settings:
            actions.extend(extendQMenu(menu, settings['items']))
        return actions

    def registerEditorClassActions(self, editorClass, actions):
        self.logger.debug("%s, actions: %d" % (str(editorClass), len(actions)))
        #Conect Actions
        for action in actions:
            if hasattr(action, 'callback'):
                receiver = lambda checked, action = action: self.currentEditorActionDispatcher(checked, action)
                self.connect(action, QtCore.SIGNAL('triggered(bool)'), receiver)
        self.customEditorActions[editorClass] = actions
    
    def registerDockClassActions(self, dockClass, actions):
        self.logger.debug("%s, actions: %d" % (str(dockClass), len(actions)))
        #Conect Actions
        for action in actions:
            if hasattr(action, 'callback'):
                receiver = lambda checked, action = action: self.dockActionDispatcher(checked, action)
                self.connect(action, QtCore.SIGNAL('triggered(bool)'), receiver)
        self.customDockActions[dockClass] = actions
        
    def registerStatusClassActions(self, statusClass, actions):
        self.statusBar().registerStatusClassActions(statusClass, actions)
    
    def dockActionDispatcher(self, checked, action):
        #Find class for action
        dockClasses = filter(lambda (cls, actions): action in actions, self.customDockActions.items())
        assert len(dockClasses) == 1, "More than one dock class for action %s" % action
        dockClass = dockClasses[0][0]
        #Find instance
        dockInstance = filter(lambda status: status.__class__ == dockClass, self.dockers)
        assert len(dockInstance) == 1, "More than one instance for class %s" % dockClass
        dockInstance = dockInstance[0]
        
        callbackArgs = [ dockInstance ]
        if action.isCheckable():
            callbackArgs.append(checked)
        action.callback(*callbackArgs)
        
    def currentEditorActionDispatcher(self, checked, action):
        callbackArgs = [self.currentEditor()]
        if action.isCheckable():
            callbackArgs.append(checked)
        action.callback(*callbackArgs)
    
    def updateMenuForEditor(self, editor):
        if editor is None:
            for editorClass, actions in self.customEditorActions.iteritems():
                map(lambda action: action.setVisible(False), actions)
        else:
            currentEditorClass = editor.__class__ 
            
            for editorClass, actions in self.customEditorActions.iteritems():
                for action in actions:
                    action.setVisible(editorClass == currentEditorClass)
                    if editorClass == currentEditorClass and action.isCheckable() and hasattr(action, 'testChecked'):
                        action.setChecked(action.testChecked(editor))

    def showMessage(self, message):
        #Busca el show message en el editor sino ver otra forma de mostrar el mensaje
        self.currentEditor().showMessage(message)
    
    #============================================================
    # Create and manage editors
    #============================================================
    def addEmptyEditor(self):
        editor = self.application.getEditorInstance(parent = self)
        self.addEditor(editor)
        return editor
        
    def removeEditor(self, editor):
        self.splitTabWidget.removeTab(editor)
        del editor

    def findEditorForFile(self, filePath):
        # Find open editor for fileInfo
        for editor in self.splitTabWidget.allWidgets():
            if editor.filePath == filePath:
                return editor

    def editors(self):
        return self.splitTabWidget.allWidgets()
        
    def setCurrentEditor(self, editor):
        self.splitTabWidget.setCurrentWidget(editor)
    
    def currentEditor(self):
        return self.splitTabWidget.currentWidget()
    
    def on_currentWidgetChanged(self, editor):
        #Update Menu
        self.updateMenuForEditor(editor)        
        
        #Avisar al manager si tenemos editor
        self.application.supportManager.setEditorAvailable(editor != None)
        
        #Emitir señal de cambio
        self.currentEditorChanged.emit(editor)

        if editor is not None:
            self.addEditorToHistory(editor)
            editor.setFocus()
            self.application.checkExternalAction(self, editor)

    def setWindowTitleForEditor(self, editor):
        #Set Window Title for editor, editor can be None
        titleChunks = [ self.titleTemplate.safe_substitute(**self.application.supportManager.buildEnvironment()) ]
        if editor is not None:
            titleChunks.insert(0, editor.tabTitle())
        self.setWindowTitle(" - ".join(titleChunks))
        
    def saveEditor(self, editor = None, saveAs = False):
        editor = editor or self.currentEditor()
        if editor.isExternalChanged():
            message = "The file '%s' has been changed on the file system, Do you want save the file with other name?"
            result = QtGui.QMessageBox.question(editor, _("File changed"),
                _(message) % editor.filePath,
                buttons = QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
                defaultButton = QtGui.QMessageBox.Yes)
            if result == QtGui.QMessageBox.Yes:
                saveAs = True
        if editor.isNew() or saveAs:
            fileDirectory = self.application.fileManager.getDirectory(self.projects.currentPath()) if editor.isNew() else editor.fileDirectory()
            fileName = editor.fileName()
            fileFilters = editor.fileFilters()
            filePath = dialogs.getSaveFile( fileDirectory, title = "Save file as" if saveAs else "Save file", 
                                            filters = fileFilters, 
                                            name = fileName)
        else:
            filePath = editor.filePath

        if filePath is not None:
            editor.save(filePath)
    
    def closeEditor(self, editor = None, cancel = False):
        editor = editor or self.currentEditor()
        buttons = QtGui.QMessageBox.Ok | QtGui.QMessageBox.No
        if cancel:
            buttons |= QtGui.QMessageBox.Cancel
        if editor is None: return
        while editor and editor.isModified():
            response = QtGui.QMessageBox.question(self, "Save", 
                "Save %s" % editor.tabTitle(), 
                buttons = buttons, 
                defaultButton = QtGui.QMessageBox.Ok)
            if response == QtGui.QMessageBox.Ok:
                self.saveEditor(editor = editor)
            elif response == QtGui.QMessageBox.No:
                break
            elif response == QtGui.QMessageBox.Cancel:
                raise exceptions.UserCancelException()
        editor.close()
        self.removeEditor(editor)
    
    def tryCloseEmptyEditor(self, editor = None):
        editor = editor or self.currentEditor()
        if editor is not None and editor.isNew() and not editor.isModified():
            self.closeEditor(editor)
    
    #=========================================================
    # Handle history
    #=========================================================
    def addEditorToHistory(self, editor):
        if self._editorHistory and self._editorHistory[self._editorHistoryIndex] == editor:
            return
        self._editorHistory.insert(self._editorHistoryIndex, editor)
        
    #===========================================================================
    # MainWindow Events
    #===========================================================================
    def closeEvent(self, event):
        for editor in self.editors():
            while editor and editor.isModified():
                response = QtGui.QMessageBox.question(self, "Save", 
                    "Save %s" % editor.tabTitle(), 
                    buttons = QtGui.QMessageBox.Ok | QtGui.QMessageBox.No | QtGui.QMessageBox.Cancel, 
                    defaultButton = QtGui.QMessageBox.Ok)
                if response == QtGui.QMessageBox.Ok:
                    self.saveEditor(editor = editor)
                elif response == QtGui.QMessageBox.No:
                    break
                elif response == QtGui.QMessageBox.Cancel:
                    event.ignore()
                    return
        
    #===========================================================================
    # MainWindow State
    #===========================================================================
    def saveState(self):
        #Documentos abiertos
        openDocumentsOnQuit = []
        for editor in self.editors():
            if not editor.isNew():
                openDocumentsOnQuit.append((editor.filePath, editor.cursorPosition()))
        state = {
            "self": QtGui.QMainWindow.saveState(self),
            "dockers": dict(map(lambda dock: (dock.objectName(), dock.saveState()), self.dockers)),
            "documents": openDocumentsOnQuit,
            "geometry": self.saveGeometry(),
        }
        return state

    def restoreState(self, state):
        try:
            map(lambda dock: dock.restoreState(state["dockers"][dock.objectName()]), self.dockers)
            self.restoreGeometry(state["geometry"])
            for doc in state["documents"]:
                self.application.openFile(*doc, mainWindow = self)
            QtGui.QMainWindow.restoreState(self, state["self"])
            
        except (TypeError, ValueError) as e:
            self.logger.error("Could not restore state for %s. Reason %s" % (self, e))

    #===========================================================================
    # Drag and Drop
    #===========================================================================
    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls():
            event.acceptProposedAction()
    
    def dropEvent(self, event):
        def collectFiles(paths):
            from glob import glob
            '''Recursively collect fileInfos'''
            for path in paths:
                if os.path.isfile(path):
                    yield path
                elif os.path.isdir(path):
                    dirSubEntries = glob(os.path.join(path, '*'))
                    for entry in collectFiles(dirSubEntries):
                        yield entry
                        
        urls = map(lambda url: url.toLocalFile(), event.mimeData().urls())
        
        for path in collectFiles(urls):
            # TODO: Take this code somewhere else, this should change as more editor are added
            if not self.canBeOpened(path):
                self.logger.debug("Skipping dropped element %s" % path)
                continue
            self.logger.debug("Opening dropped file %s" % path)
            #self.openFile(QtCore.QFileInfo(path), focus = False)
            self.application.openFile(path)

    FILE_SIZE_THERESHOLD = 1024 ** 2 # 1MB file is enough, ain't it?
    STARTSWITH_BLACKLIST = ['.', '#', ]
    ENDSWITH_BLACKLIST = ['~', 'pyc', 'bak', 'old', 'tmp', 'swp', '#', ]
    
    def canBeOpened(self, path):
        # Is there any support for it?
        if not self.application.supportManager.findSyntaxByFileType(path):
            return False
        for start in self.STARTSWITH_BLACKLIST:
            if path.startswith(start):
                return False
        for end in self.ENDSWITH_BLACKLIST:
            if path.endswith(end):
                return False
        if os.path.getsize(path) > self.FILE_SIZE_THERESHOLD:
            return False
        return True
        
示例#4
0
class PMXMainWindow(QtGui.QMainWindow, Ui_MainWindow, MainWindowActions):
    """Prymatex main window"""
    #=========================================================
    # Signals
    #=========================================================
    currentEditorChanged = QtCore.pyqtSignal(object)

    #=========================================================
    # Settings
    #=========================================================
    SETTINGS_GROUP = 'MainWindow'

    @pmxConfigPorperty(default="$PMX_APP_NAME ($PMX_VERSION)")
    def windowTitleTemplate(self, titleTemplate):
        self.titleTemplate = Template(titleTemplate)

    @pmxConfigPorperty(default=True)
    def showMenuBar(self, value):
        self._showMenuBar = value
        self.menuBar().setShown(value)

    _editorHistory = []
    _editorHistoryIndex = 0

    # Constructor
    def __init__(self, application):
        """
        The main window
        @param parent: The QObject parent, in this case it should be the QApp
        @param files_to_open: The set of files to be opened when the window is shown in the screen.
        """
        QtGui.QMainWindow.__init__(self)
        self.application = application
        self.setupUi(self)

        self.setWindowIcon(resources.getIcon("prymatex"))

        self.setupDialogs()
        self.setupDockToolBars()
        self.setupMenu()

        self.setStatusBar(PMXStatusBar(self))

        # Connect Signals
        self.splitTabWidget.currentWidgetChanged.connect(
            self.on_currentWidgetChanged)
        self.splitTabWidget.currentWidgetChanged.connect(
            self.setWindowTitleForEditor)
        self.splitTabWidget.tabCloseRequest.connect(self.closeEditor)
        self.splitTabWidget.tabCreateRequest.connect(self.addEmptyEditor)
        self.application.supportManager.bundleItemTriggered.connect(
            self.on_bundleItemTriggered)

        center_widget(self, scale=(0.9, 0.8))
        self.dockers = []
        self.customEditorActions = {}
        self.customDockActions = {}

        self.setAcceptDrops(True)

        #self.setMainWindowAsActionParent()
        self.setupHelpMenuMiscConnections()

        self.popupMessage = PopupMessageWidget(self)

        #Processor de comandos local a la main window
        self.commandProcessor = MainWindowCommandProcessor(self)
        self.bundleItem_handler = self.insertBundleItem

    #==========================================================================
    # Bundle Items
    #==========================================================================
    def on_bundleItemTriggered(self, bundleItem):
        if self.bundleItem_handler is not None:
            self.bundleItem_handler(bundleItem)

    def insertBundleItem(self, bundleItem, **processorSettings):
        '''Insert selected bundle item in current editor if possible'''
        assert not bundleItem.isEditorNeeded(), "Bundle Item needs editor"

        self.commandProcessor.configure(processorSettings)
        bundleItem.execute(self.commandProcessor)

    # Browser error
    def showErrorInBrowser(self, title, summary, exitcode=-1, **settings):
        from prymatex.support.utils import makeHyperlinks
        from prymatex.utils import html
        commandScript = '''
            source "$TM_SUPPORT_PATH/lib/webpreview.sh" 
            
            html_header "An error has occurred while executing command %(name)s"
            echo -e "<pre>%(output)s</pre>"
            echo -e "<p>Exit code was: %(exitcode)d</p>"
            html_footer
        ''' % {
            'name': html.escape(title),
            'output': html.escape(summary),
            'exitcode': exitcode
        }
        bundle = self.application.supportManager.getBundle(
            self.application.supportManager.defaultBundleForNewBundleItems)
        command = self.application.supportManager.buildAdHocCommand(
            commandScript,
            bundle,
            name="Error runing %s" % title,
            commandOutput='showAsHTML')
        self.bundleItem_handler(command, **settings)

    def environmentVariables(self):
        env = {}
        for docker in self.dockers:
            env.update(docker.environmentVariables())
        return env

    @classmethod
    def contributeToSettings(cls):
        from prymatex.gui.settings.general import GeneralSettingsWidget
        from prymatex.gui.settings.plugins import PluginsSettingsWidget
        return [GeneralSettingsWidget, PluginsSettingsWidget]

    #============================================================
    # Setups
    #============================================================
    def setupDialogs(self):
        from prymatex.gui.dialogs.selector import PMXSelectorDialog

        # Create dialogs
        self.bundleSelectorDialog = PMXSelectorDialog(
            self, title=_("Select Bundle Item"))
        # TODO: Connect these selectors
        self.tabSelectorDialog = PMXSelectorDialog(self, title=_("Select tab"))
        self.symbolSelectorDialog = PMXSelectorDialog(self,
                                                      title=_("Select Symbol"))
        self.bookmarkSelectorDialog = PMXSelectorDialog(
            self, title=_("Select Bookmark"))

    def setupDockToolBars(self):
        self.dockToolBars = {
            QtCore.Qt.LeftDockWidgetArea:
            DockWidgetToolBar("Left Dockers", QtCore.Qt.LeftDockWidgetArea,
                              self),
            QtCore.Qt.RightDockWidgetArea:
            DockWidgetToolBar("Right Dockers", QtCore.Qt.RightDockWidgetArea,
                              self),
            QtCore.Qt.TopDockWidgetArea:
            DockWidgetToolBar("Top Dockers", QtCore.Qt.TopDockWidgetArea,
                              self),
            QtCore.Qt.BottomDockWidgetArea:
            DockWidgetToolBar("Bottom Dockers", QtCore.Qt.BottomDockWidgetArea,
                              self),
        }
        for dockArea, toolBar in self.dockToolBars.iteritems():
            self.addToolBar(DockWidgetToolBar.DOCK_AREA_TO_TB[dockArea],
                            toolBar)
            toolBar.hide()

    def toggleDockToolBarVisibility(self):
        for toolBar in self.dockToolBars.values():
            if toolBar.isVisible():
                toolBar.hide()
            else:
                toolBar.show()

    #============================================================
    # Componer la mainWindow
    #============================================================
    def addStatusBar(self, statusBar):
        self.statusBar().addPermanentWidget(statusBar)

    # Dockers
    def addDock(self, dock, area):
        self.addDockWidget(area, dock)
        toggleAction = dock.toggleViewAction()
        self.menuPanels.addAction(toggleAction)
        self.addAction(toggleAction)
        titleBar = DockWidgetTitleBar(dock)
        titleBar.collpaseAreaRequest.connect(
            self.on_dockWidgetTitleBar_collpaseAreaRequest)
        dock.setTitleBarWidget(titleBar)
        dock.hide()
        self.dockers.append(dock)

    def on_dockWidgetTitleBar_collpaseAreaRequest(self, dock):
        if not dock.isFloating():
            area = self.dockWidgetArea(dock)
            self.dockToolBars[area].show()

    def contributeToMainMenu(self, name, settings):
        actions = []
        menuAttr = text2objectname(name, prefix="menu")
        menu = getattr(self, menuAttr, None)
        if menu is None:
            if "text" not in settings:
                settings["text"] = name
            menu, actions = create_menu(self.menubar, settings)
            setattr(self, menuAttr, menu)
            actions.insert(
                0,
                self.menubar.insertMenu(self.menuNavigation.children()[0],
                                        menu))
        elif 'items' in settings:
            actions = extend_menu(menu, settings['items'])
        return actions

    def registerEditorClassActions(self, editorClass, actions):
        self.logger.debug("%s, actions: %d" % (str(editorClass), len(actions)))
        #Conect Actions
        for action in actions:
            if hasattr(action, 'callback'):
                receiver = lambda checked, action=action: self.currentEditorActionDispatcher(
                    checked, action)
                self.connect(action, QtCore.SIGNAL('triggered(bool)'),
                             receiver)
        self.customEditorActions[editorClass] = actions

    def registerDockClassActions(self, dockClass, actions):
        self.logger.debug("%s, actions: %d" % (str(dockClass), len(actions)))
        #Conect Actions
        for action in actions:
            if hasattr(action, 'callback'):
                receiver = lambda checked, action=action: self.dockActionDispatcher(
                    checked, action)
                self.connect(action, QtCore.SIGNAL('triggered(bool)'),
                             receiver)
        self.customDockActions[dockClass] = actions

    def registerStatusClassActions(self, statusClass, actions):
        self.statusBar().registerStatusClassActions(statusClass, actions)

    def dockActionDispatcher(self, checked, action):
        #Find class for action
        dockClasses = filter(lambda (cls, actions): action in actions,
                             self.customDockActions.items())
        assert len(dockClasses
                   ) == 1, "More than one dock class for action %s" % action
        dockClass = dockClasses[0][0]
        #Find instance
        dockInstance = filter(lambda status: status.__class__ == dockClass,
                              self.dockers)
        assert len(dockInstance
                   ) == 1, "More than one instance for class %s" % dockClass
        dockInstance = dockInstance[0]

        callbackArgs = [dockInstance]
        if action.isCheckable():
            callbackArgs.append(checked)
        action.callback(*callbackArgs)

    def currentEditorActionDispatcher(self, checked, action):
        callbackArgs = [self.currentEditor()]
        if action.isCheckable():
            callbackArgs.append(checked)
        action.callback(*callbackArgs)

    def updateMenuForEditor(self, editor):
        if editor is None:
            for editorClass, actions in self.customEditorActions.iteritems():
                map(lambda action: action.setVisible(False), actions)
        else:
            currentEditorClass = editor.__class__

            for editorClass, actions in self.customEditorActions.iteritems():
                for action in actions:
                    action.setVisible(editorClass == currentEditorClass)
                    if editorClass == currentEditorClass and action.isCheckable(
                    ) and hasattr(action, 'testChecked'):
                        action.setChecked(action.testChecked(editor))

    def showMessage(self, *largs, **kwargs):
        self.popupMessage.showMessage(*largs, **kwargs)

    #============================================================
    # Create and manage editors
    #============================================================
    def addEmptyEditor(self):
        editor = self.application.createEditorInstance(parent=self)
        self.addEditor(editor)
        return editor

    def removeEditor(self, editor):
        self.disconnect(editor, QtCore.SIGNAL("newLocationMemento"),
                        self.on_newLocationMemento)
        self.splitTabWidget.removeTab(editor)
        # TODO Ver si el remove borra el editor y como acomoda el historial
        del editor

    def addEditor(self, editor, focus=True):
        self.splitTabWidget.addTab(editor)
        self.connect(editor, QtCore.SIGNAL("newLocationMemento"),
                     self.on_newLocationMemento)
        if focus:
            self.setCurrentEditor(editor)

    def findEditorForFile(self, filePath):
        # Find open editor for fileInfo
        for editor in self.splitTabWidget.allWidgets():
            if editor.filePath == filePath:
                return editor

    def editors(self):
        return self.splitTabWidget.allWidgets()

    def setCurrentEditor(self, editor):
        self.splitTabWidget.setCurrentWidget(editor)

    def currentEditor(self):
        return self.splitTabWidget.currentWidget()

    def on_currentWidgetChanged(self, editor):
        #Update Menu
        self.updateMenuForEditor(editor)

        #Avisar al manager si tenemos editor y preparar el handler
        self.application.supportManager.setEditorAvailable(editor is not None)
        self.bundleItem_handler = editor.bundleItemHandler(
        ) or self.insertBundleItem if editor is not None else self.insertBundleItem

        #Emitir señal de cambio
        self.currentEditorChanged.emit(editor)

        if editor is not None:
            self.addEditorToHistory(editor)
            editor.setFocus()
            self.application.checkExternalAction(self, editor)

    def setWindowTitleForEditor(self, editor):
        #Set Window Title for editor, editor can be None
        titleChunks = [
            self.titleTemplate.safe_substitute(
                **self.application.supportManager.buildEnvironment())
        ]
        if editor is not None:
            titleChunks.insert(0, editor.tabTitle())
        self.setWindowTitle(" - ".join(titleChunks))

    def saveEditor(self, editor=None, saveAs=False):
        editor = editor or self.currentEditor()
        if editor.isExternalChanged():
            message = "The file '%s' has been changed on the file system, Do you want save the file with other name?"
            result = QtGui.QMessageBox.question(
                editor,
                _("File changed"),
                _(message) % editor.filePath,
                buttons=QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
                defaultButton=QtGui.QMessageBox.Yes)
            if result == QtGui.QMessageBox.Yes:
                saveAs = True
        if editor.isNew() or saveAs:
            fileDirectory = self.application.fileManager.directory(
                self.projects.currentPath()) if editor.isNew(
                ) else editor.fileDirectory()
            fileName = editor.fileName()
            fileFilters = editor.fileFilters()
            # TODO Armar el archivo destino y no solo el basedir
            filePath, _ = getSaveFileName(
                self,
                caption="Save file as" if saveAs else "Save file",
                basedir=fileDirectory,
                filters=fileFilters)
        else:
            filePath = editor.filePath

        if filePath:
            editor.save(filePath)

    def closeEditor(self, editor=None, cancel=False):
        editor = editor or self.currentEditor()
        buttons = QtGui.QMessageBox.Ok | QtGui.QMessageBox.No
        if cancel:
            buttons |= QtGui.QMessageBox.Cancel
        if editor is None: return
        while editor and editor.isModified():
            response = QtGui.QMessageBox.question(
                self,
                "Save",
                "Save %s" % editor.tabTitle(),
                buttons=buttons,
                defaultButton=QtGui.QMessageBox.Ok)
            if response == QtGui.QMessageBox.Ok:
                self.saveEditor(editor=editor)
            elif response == QtGui.QMessageBox.No:
                break
            elif response == QtGui.QMessageBox.Cancel:
                raise exceptions.UserCancelException()
        editor.close()
        self.removeEditor(editor)

    def tryCloseEmptyEditor(self, editor=None):
        editor = editor or self.currentEditor()
        if editor is not None and editor.isNew() and not editor.isModified():
            self.closeEditor(editor)

    #=========================================================
    # Handle location history
    #=========================================================
    def on_newLocationMemento(self, memento):
        self.addHistoryEntry({"editor": self.sender(), "memento": memento})

    def addEditorToHistory(self, editor):
        if self._editorHistory and self._editorHistory[
                self._editorHistoryIndex]["editor"] == editor:
            return
        self.addHistoryEntry({"editor": editor})

    def addHistoryEntry(self, entry):
        self._editorHistory = [
            entry
        ] + self._editorHistory[self._editorHistoryIndex:]
        self._editorHistoryIndex = 0

    #===========================================================================
    # MainWindow Events
    #===========================================================================
    def closeEvent(self, event):
        for editor in self.editors():
            while editor and editor.isModified():
                response = QtGui.QMessageBox.question(
                    self,
                    "Save",
                    "Save %s" % editor.tabTitle(),
                    buttons=QtGui.QMessageBox.Ok | QtGui.QMessageBox.No
                    | QtGui.QMessageBox.Cancel,
                    defaultButton=QtGui.QMessageBox.Ok)
                if response == QtGui.QMessageBox.Ok:
                    self.saveEditor(editor=editor)
                elif response == QtGui.QMessageBox.No:
                    break
                elif response == QtGui.QMessageBox.Cancel:
                    event.ignore()
                    return

    #===========================================================================
    # MainWindow State
    #===========================================================================
    def saveState(self):
        #Documentos abiertos
        openDocumentsOnQuit = []
        for editor in self.editors():
            if not editor.isNew():
                openDocumentsOnQuit.append(
                    (editor.filePath, editor.cursorPosition()))
        state = {
            "self":
            QtGui.QMainWindow.saveState(self),
            "dockers":
            dict(
                map(lambda dock: (dock.objectName(), dock.saveState()),
                    self.dockers)),
            "documents":
            openDocumentsOnQuit,
            "geometry":
            self.saveGeometry(),
        }
        return state

    def restoreState(self, state):
        # Restore dockers
        for dock in self.dockers:
            dockName = dock.objectName()
            if dockName in state["dockers"]:
                dock.restoreState(state["dockers"][dockName])

        # Restore Main window
        self.restoreGeometry(state["geometry"])
        for doc in state["documents"]:
            self.application.openFile(*doc, mainWindow=self)
        QtGui.QMainWindow.restoreState(self, state["self"])

    #===========================================================================
    # Drag and Drop
    #===========================================================================
    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls():
            event.acceptProposedAction()

    def dropEvent(self, event):
        def collectFiles(paths):
            from glob import glob
            '''Recursively collect fileInfos'''
            for path in paths:
                if os.path.isfile(path):
                    yield path
                elif os.path.isdir(path):
                    dirSubEntries = glob(os.path.join(path, '*'))
                    for entry in collectFiles(dirSubEntries):
                        yield entry

        urls = map(lambda url: url.toLocalFile(), event.mimeData().urls())

        for path in collectFiles(urls):
            # TODO: Take this code somewhere else, this should change as more editor are added
            if not self.canBeOpened(path):
                self.logger.debug("Skipping dropped element %s" % path)
                continue
            self.logger.debug("Opening dropped file %s" % path)
            #self.openFile(QtCore.QFileInfo(path), focus = False)
            self.application.openFile(path)

    FILE_SIZE_THERESHOLD = 1024**2  # 1MB file is enough, ain't it?
    STARTSWITH_BLACKLIST = [
        '.',
        '#',
    ]
    ENDSWITH_BLACKLIST = [
        '~',
        'pyc',
        'bak',
        'old',
        'tmp',
        'swp',
        '#',
    ]

    def canBeOpened(self, path):
        # Is there any support for it?
        if not self.application.supportManager.findSyntaxByFileType(path):
            return False
        for start in self.STARTSWITH_BLACKLIST:
            if path.startswith(start):
                return False
        for end in self.ENDSWITH_BLACKLIST:
            if path.endswith(end):
                return False
        if os.path.getsize(path) > self.FILE_SIZE_THERESHOLD:
            return False
        return True