def appendMessage(self, text, timeoutMs=10000): """Append message to the queue. It will be shown as non-modal at the bottom of the window. Use such notifications, which are too long or too important for status bar but, not so important, to interrupt an user with QMessageBox """ if self._queuedMessageToolBar is None: from enki.core.QueuedMessageToolBar import QueuedMessageToolBar self._queuedMessageToolBar = QueuedMessageToolBar(self) self.addToolBar(Qt.BottomToolBarArea, self._queuedMessageToolBar) self._queuedMessageToolBar.setVisible(False) self._queuedMessageToolBar.appendMessage(text, timeoutMs)
def appendMessage(self, text, timeoutMs=10000): """Append message to the queue. It will be shown as non-modal at the bottom of the window. Use such notifications, which are too long or too important for status bar but, not so important, to interrupt an user with QMessageBox """ if self._queuedMessageToolBar is None: from enki.core.QueuedMessageToolBar import QueuedMessageToolBar self._queuedMessageToolBar = QueuedMessageToolBar(self) self.addToolBar(Qt.BottomToolBarArea, self._queuedMessageToolBar) self._queuedMessageToolBar.setVisible( False ) self._queuedMessageToolBar.appendMessage(text, timeoutMs)
class MainWindow(QMainWindow): """ Main UI window Class creates window elements, fills main menu with items. If you need to access to some existing menu items - check action path in the class constructor, than use next code: :: core.actionManager().action( "mFile/aOpen" ).setEnabled(True) core.actionManager().action( "mFile/aOpen" ).triggered.connect(self.myCoolMethod) MainWindow instance is accessible as: :: from enki.core.core import core core.mainwindow() Created by the core """ hideAllWindows = pyqtSignal() """ hideAllWindows() **Signal** emitted, when user toggled "Hide all" . Dock widgets are closed automatically, but other widgets, i.e. search widget, must catch this signal and close themselves. """ # pylint: disable=W0105 directoryDropt = pyqtSignal(unicode) """ directoryDropt() **Signal** emitted, when user drag-n-dropt directory to main windowd. FileBrowser shows directory """ # pylint: disable=W0105 _STATE_FILE = os.path.join(enki.core.defines.CONFIG_DIR, "main_window_state.bin") _GEOMETRY_FILE = os.path.join(enki.core.defines.CONFIG_DIR, "main_window_geometry.json") def __init__(self): QMainWindow.__init__(self) self._queuedMessageToolBar = None self._createdMenuPathes = [] self._createdActions = [] self.setUnifiedTitleAndToolBarOnMac( True ) self.setIconSize( QSize( 16, 16 ) ) self.setAcceptDrops( True ) # Set corner settings for dock widgets self.setCorner( Qt.TopLeftCorner, Qt.LeftDockWidgetArea ) self.setCorner( Qt.TopRightCorner, Qt.RightDockWidgetArea ) self.setCorner( Qt.BottomLeftCorner, Qt.LeftDockWidgetArea ) self.setCorner( Qt.BottomRightCorner, Qt.RightDockWidgetArea ) self.setWindowTitle(self.defaultTitle()) # overwriten by workspace when file or it's modified state changes self.setWindowIcon( QIcon(':/enkiicons/logo/32x32/enki.png') ) # Create top tool bar self._topToolBar = self.addToolBar("topToolBar") self._topToolBar.setObjectName("topToolBar") self._topToolBar.setMovable(False) self._topToolBar.setIconSize(QSize(16, 16)) toolBarStyleSheet = "QToolBar {border: 0; border-bottom-width: 0.5; border-bottom-style: solid}""" self._topToolBar.setStyleSheet(toolBarStyleSheet) # Create menu bar self._menuBar = ActionMenuBar(self, core.actionManager()) self._menuBar.setAutoFillBackground(False) menuBarStyleSheet = """ QMenuBar {background-color: transparent; color: %s} QMenuBar::item:!selected {background: transparent;} """ % self.palette().color(QPalette.WindowText).name() self._menuBar.setStyleSheet(menuBarStyleSheet) self._menuBar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) if 'UBUNTU_MENUPROXY' in os.environ: self.setMenuBar(self._menuBar) else: self._topToolBar.addWidget(self._menuBar) self._topToolBar.addSeparator() # Create status bar self._statusBar = _StatusBar(self) self._topToolBar.addWidget(self._statusBar) self._createMenuStructure() # create central layout widget = QWidget(self) self._centralLayout = QVBoxLayout(widget) self._centralLayout.setMargin(0) self.setCentralWidget(widget) def del_(self): """Explicitly called destructor """ if self._queuedMessageToolBar: self.removeToolBar(self._queuedMessageToolBar) del self._queuedMessageToolBar for act in self._createdActions: core.actionManager().removeAction(act, False) for menuPath in self._createdMenuPathes[::-1]: core.actionManager().removeMenu(menuPath) def _initTopWidget(self): """Create top widget and put it on its place """ def _createMenuStructure(self): """Fill menu bar with items. The majority of items are not connected to the slots, Connections made by module, which implements menu item functionality, but, all items are in one place, because it's easier to create clear menu layout """ # create menubar menus and actions def menu(path, name, icon): """Subfunction for create a menu in the main menu""" menuObject = core.actionManager().addMenu(path, name) if icon: menuObject.setIcon(QIcon(':/enkiicons/' + icon)) self._createdMenuPathes.append(path) def action(path, name, icon, shortcut, tooltip, enabled): # pylint: disable=R0913 """Subfunction for create an action in the main menu""" if icon: # has icon actObject = core.actionManager().addAction(path, name, QIcon(':/enkiicons/' + icon), shortcut) else: actObject = core.actionManager().addAction(path, name, shortcut=shortcut) actObject.setStatusTip(tooltip) actObject.setEnabled(enabled) self._createdActions.append(actObject) def separator(menu): """Subfunction for insert separator to the menu""" core.actionManager().action(menu).menu().addSeparator() # pylint: disable=C0301 # enable long lines for menu items # Menu or action path Name Icon Shortcut Hint Action enabled tr = self.tr # pylint: disable=C0103 menu ("mFile", tr("File" ), "" ) action("mFile/aOpen", tr("&Open..." ), "open.png", "Ctrl+O" , tr("Open a file" ), True ) menu ("mFile/mUndoClose", tr("Undo Close" ), "recents.png" ) menu ("mFile/mSave", tr("&Save" ), "save.png" ) action("mFile/mSave/aCurrent", tr("&Save" ), "save.png" , "Ctrl+S" , tr("Save the current file" ), False) action("mFile/mSave/aSaveAs", tr("Save As..." ), "save.png" , "Ctrl+Alt+S" , "" , False) action("mFile/mSave/aAll", tr("Save &All" ), "saveall.png", 'Shift+Ctrl+S', tr("Save all files" ), False) menu ("mFile/mReload", tr("&Reload" ), "reload.png" ) action("mFile/mReload/aCurrent", tr("Reload" ), "reload.png" , 'F5', tr("Reload the current file"), False) action("mFile/mReload/aAll", tr("Reload All" ), "reload.png" , 'Shift+F5', tr("Reload all files" ), True) action("mFile/aNew", tr("&New file..." ), "new.png", 'Ctrl+N', tr("New file" ), True ) menu ("mFile/mClose", tr("&Close" ), "close.png" ) action("mFile/mClose/aCurrent", tr("&Close" ), "close.png", "Ctrl+W", tr("Close the current file" ), False) action("mFile/mClose/aAll", tr("Close &All" ), "closeall.png", 'Shift+Ctrl+W', tr("Close all files" ), False) action("mFile/aPrint", tr("&Print..." ), "print.png" , "Ctrl+P", tr("Print the current file" ), False) menu ("mView", tr("View" ), "" ) menu ("mView/mZoom", tr("&Zoom" ), "search.png" ) menu ("mView/mHighlighting", tr("Highlighting" ), "" ) separator("mView") action("mView/aHideAll", tr("Hide all widgets" ), "", "Shift+Esc", tr("Hide all widgets" ), True) menu ("mEdit", tr("Edit" ), "" ) menu ("mNavigation", tr("Navigation" ), "" ) action("mNavigation/aFocusCurrentDocument", tr("Focus to editor" ), "text.png", "Ctrl+Return", tr("Focus current document" ), False) menu ("mNavigation/mSearchReplace", tr("&Search && Replace" ), "search-replace-directory.png") menu ("mNavigation/mBookmarks", tr("&Bookmarks" ), "bookmark.png") action("mNavigation/aNext", tr("&Next file" ), "next.png", "Ctrl+PgDown", tr("Next file" ), False) action("mNavigation/aPrevious", tr("&Previous file" ), "previous.png", "Ctrl+PgUp", tr("Previous file" ), False) action("mNavigation/aGoto", tr("Go go line..." ), "goto.png", "Ctrl+G", tr("Go to line..." ), False) menu ("mNavigation/mFileBrowser", tr("File browser" ), ':/enkiicons/open.png') menu ("mSettings", tr("Settings" ), "" ) menu ("mHelp", tr("Help" ), "" ) # docks core.actionManager().action( "mView/aHideAll" ).triggered.connect(self._onHideAllWindows) def menuBar(self): """Reference to menuBar """ return self._menuBar def topToolBar(self): """Top tool bar. Contains main menu, position indicator, etc """ return self._topToolBar def statusBar(self): """Return main window status bar. It is located on the top tool bar """ return self._statusBar def setWorkspace(self, workspace): """Set central widget of the main window. Normally called only by core when initializing system """ self._centralLayout.addWidget(workspace) self.setFocusProxy(workspace) def defaultTitle(self): """Default title. Contains name and version """ return "%s v.%s" % (enki.core.defines.PACKAGE_NAME, enki.core.defines.PACKAGE_VERSION) def centralLayout(self): """Layout of the central widget. Contains Workspace and search widget """ return self._centralLayout def appendMessage(self, text, timeoutMs=10000): """Append message to the queue. It will be shown as non-modal at the bottom of the window. Use such notifications, which are too long or too important for status bar but, not so important, to interrupt an user with QMessageBox """ if self._queuedMessageToolBar is None: from enki.core.QueuedMessageToolBar import QueuedMessageToolBar self._queuedMessageToolBar = QueuedMessageToolBar(self) self.addToolBar(Qt.BottomToolBarArea, self._queuedMessageToolBar) self._queuedMessageToolBar.setVisible( False ) self._queuedMessageToolBar.appendMessage(text, timeoutMs) def closeEvent( self, event ): """NOT A PUBLIC API Close event handler. Shows save files dialog. Cancels close, if dialog was rejected """ # request close all documents if not core.workspace().askToCloseAll(): event.ignore() return core.aboutToTerminate.emit() self.hide() core.workspace().forceCloseAllDocuments() self._saveState() self._saveGeometry() return QMainWindow.closeEvent(self, event) def _onHideAllWindows(self): """Close all visible windows for get as much space on the screen, as possible """ self.hideAllWindows.emit() for dock in self.findChildren(DockWidget): dock.hide() def _saveState(self): """Save window state to main_window_state.bin file in the config directory """ state = self.saveState() try: with open(self._STATE_FILE, 'w') as f: f.write(state) except (OSError, IOError), ex: error = unicode(str(ex), 'utf8') QMessageBox.critical(None, self.tr("Cannot save main window state"), self.tr( "Cannot create file '%s'\nError: %s" % (path, error))) return
class MainWindow(QMainWindow): """ Main UI window Class creates window elements, fills main menu with items. If you need to access to some existing menu items - check action path in the class constructor, than use next code: :: core.actionManager().action( "mFile/aOpen" ).setEnabled(True) core.actionManager().action( "mFile/aOpen" ).triggered.connect(self.myCoolMethod) MainWindow instance is accessible as: :: from enki.core.core import core core.mainwindow() Created by the core """ hideAllWindows = pyqtSignal() """ hideAllWindows() **Signal** emitted, when user toggled "Hide all" . Dock widgets are closed automatically, but other widgets, i.e. search widget, must catch this signal and close themselves. """ # pylint: disable=W0105 directoryDropt = pyqtSignal(unicode) """ directoryDropt() **Signal** emitted, when user drag-n-dropt directory to main windowd. FileBrowser shows directory """ # pylint: disable=W0105 stateRestored = pyqtSignal() """ stateRestored() **Signal** emitted, after state has been restored Plugin might want to change docks visibility. Do not do it, unless necessary. """ # pylint: disable=W0105 _STATE_FILE = os.path.join(enki.core.defines.CONFIG_DIR, "main_window_state.bin") _GEOMETRY_FILE = os.path.join(enki.core.defines.CONFIG_DIR, "main_window_geometry.json") def __init__(self): QMainWindow.__init__(self) self._queuedMessageToolBar = None self._createdMenuPathes = [] self._createdActions = [] self.setUnifiedTitleAndToolBarOnMac(True) self.setIconSize(QSize(16, 16)) self.setAcceptDrops(True) # Set corner settings for dock widgets self.setCorner(Qt.TopLeftCorner, Qt.LeftDockWidgetArea) self.setCorner(Qt.TopRightCorner, Qt.RightDockWidgetArea) self.setCorner(Qt.BottomLeftCorner, Qt.LeftDockWidgetArea) self.setCorner(Qt.BottomRightCorner, Qt.RightDockWidgetArea) self.setWindowTitle(self.defaultTitle( )) # overwriten by workspace when file or it's modified state changes self.setWindowIcon(QIcon(':/enkiicons/logo/32x32/enki.png')) # Create top tool bar self._topToolBar = QToolBar("topToolBar") self._topToolBar.setObjectName("topToolBar") self._topToolBar.setMovable(False) self._topToolBar.setIconSize(QSize(16, 16)) # Create menu bar self._menuBar = ActionMenuBar(self, core.actionManager()) self._initMenubarAndStatusBarLayout() self._createMenuStructure() # create central layout widget = QWidget(self) self._centralLayout = QVBoxLayout(widget) self._centralLayout.setMargin(0) self.setCentralWidget(widget) def del_(self): """Explicitly called destructor """ if self._queuedMessageToolBar: self.removeToolBar(self._queuedMessageToolBar) del self._queuedMessageToolBar for act in self._createdActions: core.actionManager().removeAction(act, False) for menuPath in self._createdMenuPathes[::-1]: core.actionManager().removeMenu(menuPath) @staticmethod def _isMenuEmbeddedToTaskBar(): """On Unity (Ubuntu) and MacOS menu bar is embedded to task bar """ return 'UBUNTU_MENUPROXY' in os.environ or \ 'darwin' == sys.platform def _initMenubarAndStatusBarLayout(self): """Create top widget and put it on its place """ if not 'darwin' == sys.platform: # on Ubuntu toolbar, docs and editor area look as one widget. Ugly # Therefore it is separated with line. On Mac seems OK # I can't predict, how it will look on other platforms, therefore line is used for all, except Mac toolBarStyleSheet = "QToolBar {border: 0; border-bottom-width: 1; border-bottom-style: solid}" "" self._topToolBar.setStyleSheet(toolBarStyleSheet) if self._isMenuEmbeddedToTaskBar(): # separate menu bar self.addToolBar(self._topToolBar) self.setMenuBar(self._menuBar) else: # menubar, statusbar and editor tool bar on one line self._menuBar.setAutoFillBackground(False) menuBarStyleSheet = """ QMenuBar {background-color: transparent; color: %s} QMenuBar::item:!selected {background: transparent;} """ % self.palette().color(QPalette.WindowText).name() self._menuBar.setStyleSheet(menuBarStyleSheet) self._menuBar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.addToolBar(self._topToolBar) self._topToolBar.addWidget(self._menuBar) # Create status bar self._statusBar = _StatusBar(self) self._topToolBar.addWidget(self._statusBar) def _createMenuStructure(self): """Fill menu bar with items. The majority of items are not connected to the slots, Connections made by module, which implements menu item functionality, but, all items are in one place, because it's easier to create clear menu layout """ # create menubar menus and actions def menu(path, name, icon): """Subfunction for create a menu in the main menu""" menuObject = core.actionManager().addMenu(path, name) if icon: menuObject.setIcon(QIcon(':/enkiicons/' + icon)) self._createdMenuPathes.append(path) def action(path, name, icon, shortcut, tooltip, enabled): # pylint: disable=R0913 """Subfunction for create an action in the main menu""" if icon: # has icon actObject = core.actionManager().addAction( path, name, QIcon(':/enkiicons/' + icon), shortcut) else: actObject = core.actionManager().addAction(path, name, shortcut=shortcut) actObject.setStatusTip(tooltip) actObject.setEnabled(enabled) self._createdActions.append(actObject) def separator(menu): """Subfunction for insert separator to the menu""" core.actionManager().action(menu).menu().addSeparator() # pylint: disable=C0301 # enable long lines for menu items # Menu or action path Name Icon Shortcut Hint Action enabled tr = self.tr # pylint: disable=C0103 menu("mFile", "File", "") menu("mFile/mUndoClose", "Undo Close", "recents.png") separator("mFile") action("mFile/aNew", "&New file...", "new.png", 'Ctrl+N', "New file", True) action("mFile/aOpen", "&Open...", "open.png", "Ctrl+O", "Open a file", True) menu("mFile/mSave", "&Save", "save.png") action("mFile/mSave/aCurrent", "&Save", "save.png", "Ctrl+S", "Save the current file", False) action("mFile/mSave/aSaveAs", "Save As...", "save.png", "Ctrl+Alt+S", "", False) action("mFile/mSave/aAll", "Save &All", "saveall.png", 'Shift+Ctrl+S', "Save all files", False) menu("mFile/mReload", "&Reload", "reload.png") action("mFile/mReload/aCurrent", "Reload", "reload.png", 'F5', "Reload the current file", False) action("mFile/mReload/aAll", "Reload All", "reload.png", 'Shift+F5', "Reload all files", True) menu("mFile/mClose", "&Close", "close.png") action("mFile/mClose/aCurrent", "&Close", "close.png", "Ctrl+W", "Close the current file", False) action("mFile/mClose/aAll", "Close &All", "closeall.png", 'Shift+Ctrl+W', "Close all files", False) separator("mFile") menu("mView", "View", "") action("mView/aHideAll", "Hide all / Restore", "", "Shift+Esc", "Hide all widgets", True) menu("mEdit", "Edit", "") menu("mEdit/mCopyPasteLines", "Copy-paste lines", "") menu("mNavigation", "Navigation", "") action("mNavigation/aFocusCurrentDocument", "Focus to editor", "text.png", "Ctrl+Return", "Focus current document", False) menu("mNavigation/mSearchReplace", "&Search && Replace", "search-replace-directory.png") menu("mNavigation/mBookmarks", "&Bookmarks", "bookmark.png") separator("mNavigation"), action("mNavigation/aNext", "&Next file", "next.png", "Ctrl+PgDown", "Next file", False) action("mNavigation/aPrevious", "&Previous file", "previous.png", "Ctrl+PgUp", "Previous file", False) separator("mNavigation") action("mNavigation/aGoto", "Go go line...", "goto.png", "Ctrl+G", "Go to line...", False) menu("mNavigation/mFileBrowser", "File browser", ':/enkiicons/open.png') menu("mNavigation/mScroll", "Scroll file", '') menu("mSettings", "Settings", "") menu("mHelp", "Help", "") def menuBar(self): """Reference to menuBar """ return self._menuBar def topToolBar(self): """Top tool bar. Contains main menu, position indicator, etc """ return self._topToolBar def statusBar(self): """Return main window status bar. It is located on the top tool bar """ return self._statusBar def setWorkspace(self, workspace): """Set central widget of the main window. Normally called only by core when initializing system """ self._centralLayout.addWidget(workspace) self.setFocusProxy(workspace) def defaultTitle(self): """Default title. Contains name and version """ return "%s v.%s" % (enki.core.defines.PACKAGE_NAME, enki.core.defines.PACKAGE_VERSION) def centralLayout(self): """Layout of the central widget. Contains Workspace and search widget """ return self._centralLayout def appendMessage(self, text, timeoutMs=10000): """Append message to the queue. It will be shown as non-modal at the bottom of the window. Use such notifications, which are too long or too important for status bar but, not so important, to interrupt an user with QMessageBox """ if self._queuedMessageToolBar is None: from enki.core.QueuedMessageToolBar import QueuedMessageToolBar self._queuedMessageToolBar = QueuedMessageToolBar(self) self.addToolBar(Qt.BottomToolBarArea, self._queuedMessageToolBar) self._queuedMessageToolBar.setVisible(False) self._queuedMessageToolBar.appendMessage(text, timeoutMs) def closeEvent(self, event): """NOT A PUBLIC API Close event handler. Shows save files dialog. Cancels close, if dialog was rejected """ # saving geometry BEFORE closing widgets, because state might be changed, when docks are closed self._saveState() self._saveGeometry() # request close all documents if not core.workspace().askToCloseAll(): event.ignore() return core.aboutToTerminate.emit() self.hide() core.workspace().forceCloseAllDocuments() return QMainWindow.closeEvent(self, event) def _saveState(self): """Save window state to main_window_state.bin file in the config directory """ state = self.saveState() try: with open(self._STATE_FILE, 'wb') as f: f.write(state) except (OSError, IOError), ex: error = unicode(str(ex), 'utf8') QMessageBox.critical( None, self.tr("Cannot save main window state"), self.tr("Cannot create file '%s'\nError: %s" % (path, error))) return