def restore_splitter_sizes(window: QDialog, splitter: QSplitter): global cache if cache: symbol = window.__class__.__name__ + '_' + splitter.objectName() sizes = cache.get_value(symbol, None, list) if not isinstance(sizes, list) or len(sizes) != 2: sizes = [100, 100] if splitter.parent(): if splitter.orientation() == Qt.Vertical: sizes[0], sizes[1] = round(splitter.parent().height() / 2), round(splitter.parent().height() / 2) else: sizes[0], sizes[1] = round(splitter.parent().width() / 2), round(splitter.parent().width() / 2) splitter.setSizes(sizes)
def decorate(splitter: QSplitter, index: int = 1): gripLength = 35 gripWidth = 1 # may need to be 1 or 2 depending on theme gripSpacing = 0 grips = 3 splitter.setOpaqueResize(False) splitter.setChildrenCollapsible(False) splitter.setHandleWidth(7) handle = splitter.handle(index) orientation = splitter.orientation() layout = QHBoxLayout(handle) layout.setSpacing(gripSpacing) layout.setContentsMargins(0, 0, 0, 0) if orientation == Qt.Horizontal: for i in range(grips): line = QFrame(handle) line.setMinimumSize(gripWidth, gripLength) line.setMaximumSize(gripWidth, gripLength) line.setLineWidth(gripWidth) line.setFrameShape(line.StyledPanel) line.setStyleSheet("border: 1px solid lightgray;") layout.addWidget(line) else: # center the vertical grip by adding spacers before and after layout.addStretch() vBox = QVBoxLayout() for i in range(grips): line = QFrame(handle) line.setMinimumSize(gripLength, gripWidth) line.setMaximumSize(gripLength, gripWidth) line.setFrameShape(line.StyledPanel) line.setStyleSheet("border: 1px solid lightgray;") vBox.addWidget(line) layout.addLayout(vBox) layout.addStretch()
class Listspace(QSplitter, ViewManager): """ Class implementing the listspace viewmanager class. @signal changeCaption(str) emitted if a change of the caption is necessary @signal editorChanged(str) emitted when the current editor has changed @signal editorChangedEd(Editor) emitted when the current editor has changed @signal lastEditorClosed() emitted after the last editor window was closed @signal editorOpened(str) emitted after an editor window was opened @signal editorOpenedEd(Editor) emitted after an editor window was opened @signal editorClosed(str) emitted just before an editor window gets closed @signal editorClosedEd(Editor) emitted just before an editor window gets closed @signal editorRenamed(str) emitted after an editor was renamed @signal editorRenamedEd(Editor) emitted after an editor was renamed @signal editorSaved(str) emitted after an editor window was saved @signal editorSavedEd(Editor) emitted after an editor window was saved @signal checkActions(Editor) emitted when some actions should be checked for their status @signal cursorChanged(Editor) emitted after the cursor position of the active window has changed @signal breakpointToggled(Editor) emitted when a breakpoint is toggled. @signal bookmarkToggled(Editor) emitted when a bookmark is toggled. @signal syntaxerrorToggled(Editor) emitted when a syntax error is toggled. @signal previewStateChanged(bool) emitted to signal a change in the preview state @signal editorLanguageChanged(Editor) emitted to signal a change of an editors language @signal editorTextChanged(Editor) emitted to signal a change of an editor's text @signal editorLineChanged(str,int) emitted to signal a change of an editor's current line (line is given one based) """ changeCaption = pyqtSignal(str) editorChanged = pyqtSignal(str) editorChangedEd = pyqtSignal(Editor) lastEditorClosed = pyqtSignal() editorOpened = pyqtSignal(str) editorOpenedEd = pyqtSignal(Editor) editorClosed = pyqtSignal(str) editorClosedEd = pyqtSignal(Editor) editorRenamed = pyqtSignal(str) editorRenamedEd = pyqtSignal(Editor) editorSaved = pyqtSignal(str) editorSavedEd = pyqtSignal(Editor) checkActions = pyqtSignal(Editor) cursorChanged = pyqtSignal(Editor) breakpointToggled = pyqtSignal(Editor) bookmarkToggled = pyqtSignal(Editor) syntaxerrorToggled = pyqtSignal(Editor) previewStateChanged = pyqtSignal(bool) editorLanguageChanged = pyqtSignal(Editor) editorTextChanged = pyqtSignal(Editor) editorLineChanged = pyqtSignal(str, int) def __init__(self, parent): """ Constructor @param parent parent widget (QWidget) """ self.stacks = [] QSplitter.__init__(self, parent) ViewManager.__init__(self) self.setChildrenCollapsible(False) self.viewlist = QListWidget(self) policy = self.viewlist.sizePolicy() policy.setHorizontalPolicy(QSizePolicy.Ignored) self.viewlist.setSizePolicy(policy) self.addWidget(self.viewlist) self.viewlist.setContextMenuPolicy(Qt.CustomContextMenu) self.viewlist.currentRowChanged.connect(self.__showSelectedView) self.viewlist.customContextMenuRequested.connect(self.__showMenu) self.stackArea = QSplitter(self) self.stackArea.setChildrenCollapsible(False) self.addWidget(self.stackArea) self.stackArea.setOrientation(Qt.Vertical) stack = StackedWidget(self.stackArea) self.stackArea.addWidget(stack) self.stacks.append(stack) self.currentStack = stack stack.currentChanged.connect(self.__currentChanged) stack.installEventFilter(self) self.setSizes([int(self.width() * 0.2), int(self.width() * 0.8)]) # 20% for viewlist, 80% for the editors self.__inRemoveView = False self.__initMenu() self.contextMenuEditor = None self.contextMenuIndex = -1 def __initMenu(self): """ Private method to initialize the viewlist context menu. """ self.__menu = QMenu(self) self.__menu.addAction(UI.PixmapCache.getIcon("tabClose.png"), self.tr('Close'), self.__contextMenuClose) self.closeOthersMenuAct = self.__menu.addAction( UI.PixmapCache.getIcon("tabCloseOther.png"), self.tr("Close Others"), self.__contextMenuCloseOthers) self.__menu.addAction(self.tr('Close All'), self.__contextMenuCloseAll) self.__menu.addSeparator() self.saveMenuAct = self.__menu.addAction( UI.PixmapCache.getIcon("fileSave.png"), self.tr('Save'), self.__contextMenuSave) self.__menu.addAction(UI.PixmapCache.getIcon("fileSaveAs.png"), self.tr('Save As...'), self.__contextMenuSaveAs) self.__menu.addAction(UI.PixmapCache.getIcon("fileSaveAll.png"), self.tr('Save All'), self.__contextMenuSaveAll) self.__menu.addSeparator() self.openRejectionsMenuAct = self.__menu.addAction( self.tr("Open 'rejection' file"), self.__contextMenuOpenRejections) self.__menu.addSeparator() self.__menu.addAction(UI.PixmapCache.getIcon("print.png"), self.tr('Print'), self.__contextMenuPrintFile) self.__menu.addSeparator() self.copyPathAct = self.__menu.addAction( self.tr("Copy Path to Clipboard"), self.__contextMenuCopyPathToClipboard) def __showMenu(self, point): """ Private slot to handle the customContextMenuRequested signal of the viewlist. @param point position to open the menu at (QPoint) """ if self.editors: itm = self.viewlist.itemAt(point) if itm is not None: row = self.viewlist.row(itm) self.contextMenuEditor = self.editors[row] self.contextMenuIndex = row if self.contextMenuEditor: self.saveMenuAct.setEnabled( self.contextMenuEditor.isModified()) fileName = self.contextMenuEditor.getFileName() self.copyPathAct.setEnabled(bool(fileName)) if fileName: rej = "{0}.rej".format(fileName) self.openRejectionsMenuAct.setEnabled( os.path.exists(rej)) else: self.openRejectionsMenuAct.setEnabled(False) self.closeOthersMenuAct.setEnabled( self.viewlist.count() > 1) self.__menu.popup(self.viewlist.mapToGlobal(point)) def canCascade(self): """ Public method to signal if cascading of managed windows is available. @return flag indicating cascading of windows is available """ return False def canTile(self): """ Public method to signal if tiling of managed windows is available. @return flag indicating tiling of windows is available """ return False def canSplit(self): """ public method to signal if splitting of the view is available. @return flag indicating splitting of the view is available. """ return True def tile(self): """ Public method to tile the managed windows. """ pass def cascade(self): """ Public method to cascade the managed windows. """ pass def _removeAllViews(self): """ Protected method to remove all views (i.e. windows). """ self.viewlist.clear() for win in self.editors: for stack in self.stacks: if stack.hasEditor(win): stack.removeWidget(win) break win.closeIt() def _removeView(self, win): """ Protected method to remove a view (i.e. window). @param win editor window to be removed """ self.__inRemoveView = True ind = self.editors.index(win) itm = self.viewlist.takeItem(ind) if itm: del itm for stack in self.stacks: if stack.hasEditor(win): stack.removeWidget(win) break win.closeIt() self.__inRemoveView = False if ind > 0: ind -= 1 else: if len(self.editors) > 1: ind = 1 else: return stack.setCurrentWidget(stack.firstEditor()) self._showView(self.editors[ind].parent()) aw = self.activeWindow() fn = aw and aw.getFileName() or None if fn: self.changeCaption.emit(fn) self.editorChanged.emit(fn) self.editorLineChanged.emit(fn, aw.getCursorPosition()[0] + 1) else: self.changeCaption.emit("") self.editorChangedEd.emit(aw) def _addView(self, win, fn=None, noName="", next=False): """ Protected method to add a view (i.e. window). @param win editor assembly to be added @param fn filename of this editor (string) @param noName name to be used for an unnamed editor (string) @param next flag indicating to add the view next to the current view (bool) """ editor = win.getEditor() if fn is None: if not noName: self.untitledCount += 1 noName = self.tr("Untitled {0}").format(self.untitledCount) self.viewlist.addItem(noName) editor.setNoName(noName) else: txt = os.path.basename(fn) if not QFileInfo(fn).isWritable(): txt = self.tr("{0} (ro)").format(txt) itm = QListWidgetItem(txt) itm.setToolTip(fn) self.viewlist.addItem(itm) self.currentStack.addWidget(win) self.currentStack.setCurrentWidget(win) editor.captionChanged.connect(self.__captionChange) editor.cursorLineChanged.connect(self.__cursorLineChanged) index = self.editors.index(editor) self.viewlist.setCurrentRow(index) editor.setFocus() if fn: self.changeCaption.emit(fn) self.editorChanged.emit(fn) self.editorLineChanged.emit(fn, editor.getCursorPosition()[0] + 1) else: self.changeCaption.emit("") self.editorChangedEd.emit(editor) def __captionChange(self, cap, editor): """ Private method to handle caption change signals from the editor. Updates the listwidget text to reflect the new caption information. @param cap Caption for the editor (string) @param editor Editor to update the caption for """ fn = editor.getFileName() if fn: self.setEditorName(editor, fn) def __cursorLineChanged(self, lineno): """ Private slot to handle a change of the current editor's cursor line. @param lineno line number of the current editor's cursor (zero based) """ editor = self.sender() if editor: fn = editor.getFileName() if fn: self.editorLineChanged.emit(fn, lineno + 1) def _showView(self, win, fn=None): """ Protected method to show a view (i.e. window). @param win editor assembly to be shown @param fn filename of this editor (string) """ editor = win.getEditor() for stack in self.stacks: if stack.hasEditor(editor): stack.setCurrentWidget(win) self.currentStack = stack break index = self.editors.index(editor) self.viewlist.setCurrentRow(index) editor.setFocus() fn = editor.getFileName() if fn: self.changeCaption.emit(fn) self.editorChanged.emit(fn) self.editorLineChanged.emit(fn, editor.getCursorPosition()[0] + 1) else: self.changeCaption.emit("") self.editorChangedEd.emit(editor) def __showSelectedView(self, row): """ Private slot called to show a view selected in the list. @param row row number of the item clicked on (integer) """ if row != -1: self._showView(self.editors[row].parent()) self._checkActions(self.editors[row]) def activeWindow(self): """ Public method to return the active (i.e. current) window. @return reference to the active editor """ return self.currentStack.currentWidget() def showWindowMenu(self, windowMenu): """ Public method to set up the viewmanager part of the Window menu. @param windowMenu reference to the window menu """ pass def _initWindowActions(self): """ Protected method to define the user interface actions for window handling. """ pass def setEditorName(self, editor, newName): """ Public method to change the displayed name of the editor. @param editor editor window to be changed @param newName new name to be shown (string) """ if newName: currentRow = self.viewlist.currentRow() index = self.editors.index(editor) txt = os.path.basename(newName) if not QFileInfo(newName).isWritable(): txt = self.tr("{0} (ro)").format(txt) itm = self.viewlist.item(index) itm.setText(txt) itm.setToolTip(newName) self.viewlist.setCurrentRow(currentRow) self.changeCaption.emit(newName) def _modificationStatusChanged(self, m, editor): """ Protected slot to handle the modificationStatusChanged signal. @param m flag indicating the modification status (boolean) @param editor editor window changed """ currentRow = self.viewlist.currentRow() index = self.editors.index(editor) keys = [] if m: keys.append("fileModified.png") if editor.hasSyntaxErrors(): keys.append("syntaxError22.png") elif editor.hasWarnings(): keys.append("warning22.png") if not keys: keys.append("empty.png") self.viewlist.item(index).setIcon(UI.PixmapCache.getCombinedIcon(keys)) self.viewlist.setCurrentRow(currentRow) self._checkActions(editor) def _syntaxErrorToggled(self, editor): """ Protected slot to handle the syntaxerrorToggled signal. @param editor editor that sent the signal """ currentRow = self.viewlist.currentRow() index = self.editors.index(editor) keys = [] if editor.isModified(): keys.append("fileModified.png") if editor.hasSyntaxErrors(): keys.append("syntaxError22.png") elif editor.hasWarnings(): keys.append("warning22.png") if not keys: keys.append("empty.png") self.viewlist.item(index).setIcon(UI.PixmapCache.getCombinedIcon(keys)) self.viewlist.setCurrentRow(currentRow) ViewManager._syntaxErrorToggled(self, editor) def addSplit(self): """ Public method used to split the current view. """ stack = StackedWidget(self.stackArea) stack.show() self.stackArea.addWidget(stack) self.stacks.append(stack) self.currentStack = stack stack.currentChanged.connect(self.__currentChanged) stack.installEventFilter(self) if self.stackArea.orientation() == Qt.Horizontal: size = self.stackArea.width() else: size = self.stackArea.height() self.stackArea.setSizes([int(size / len(self.stacks))] * len(self.stacks)) self.splitRemoveAct.setEnabled(True) self.nextSplitAct.setEnabled(True) self.prevSplitAct.setEnabled(True) def removeSplit(self): """ Public method used to remove the current split view. @return flag indicating successfull removal """ if len(self.stacks) > 1: stack = self.currentStack res = True savedEditors = stack.editors[:] for editor in savedEditors: res &= self.closeEditor(editor) if res: try: i = self.stacks.index(stack) except ValueError: return True if i == len(self.stacks) - 1: i -= 1 self.stacks.remove(stack) stack.close() self.currentStack = self.stacks[i] if len(self.stacks) == 1: self.splitRemoveAct.setEnabled(False) self.nextSplitAct.setEnabled(False) self.prevSplitAct.setEnabled(False) return True return False def getSplitOrientation(self): """ Public method to get the orientation of the split view. @return orientation of the split (Qt.Horizontal or Qt.Vertical) """ return self.stackArea.orientation() def setSplitOrientation(self, orientation): """ Public method used to set the orientation of the split view. @param orientation orientation of the split (Qt.Horizontal or Qt.Vertical) """ self.stackArea.setOrientation(orientation) def nextSplit(self): """ Public slot used to move to the next split. """ aw = self.activeWindow() _hasFocus = aw and aw.hasFocus() ind = self.stacks.index(self.currentStack) + 1 if ind == len(self.stacks): ind = 0 self.currentStack = self.stacks[ind] if _hasFocus: aw = self.activeWindow() if aw: aw.setFocus() index = self.editors.index(self.currentStack.currentWidget()) self.viewlist.setCurrentRow(index) def prevSplit(self): """ Public slot used to move to the previous split. """ aw = self.activeWindow() _hasFocus = aw and aw.hasFocus() ind = self.stacks.index(self.currentStack) - 1 if ind == -1: ind = len(self.stacks) - 1 self.currentStack = self.stacks[ind] if _hasFocus: aw = self.activeWindow() if aw: aw.setFocus() index = self.editors.index(self.currentStack.currentWidget()) self.viewlist.setCurrentRow(index) def __contextMenuClose(self): """ Private method to close the selected editor. """ if self.contextMenuEditor: self.closeEditorWindow(self.contextMenuEditor) def __contextMenuCloseOthers(self): """ Private method to close the other editors. """ index = self.contextMenuIndex for i in list(range(self.viewlist.count() - 1, index, -1)) + \ list(range(index - 1, -1, -1)): editor = self.editors[i] self.closeEditorWindow(editor) def __contextMenuCloseAll(self): """ Private method to close all editors. """ savedEditors = self.editors[:] for editor in savedEditors: self.closeEditorWindow(editor) def __contextMenuSave(self): """ Private method to save the selected editor. """ if self.contextMenuEditor: self.saveEditorEd(self.contextMenuEditor) def __contextMenuSaveAs(self): """ Private method to save the selected editor to a new file. """ if self.contextMenuEditor: self.saveAsEditorEd(self.contextMenuEditor) def __contextMenuSaveAll(self): """ Private method to save all editors. """ self.saveEditorsList(self.editors) def __contextMenuOpenRejections(self): """ Private slot to open a rejections file associated with the selected editor. """ if self.contextMenuEditor: fileName = self.contextMenuEditor.getFileName() if fileName: rej = "{0}.rej".format(fileName) if os.path.exists(rej): self.openSourceFile(rej) def __contextMenuPrintFile(self): """ Private method to print the selected editor. """ if self.contextMenuEditor: self.printEditor(self.contextMenuEditor) def __contextMenuCopyPathToClipboard(self): """ Private method to copy the file name of the selected editor to the clipboard. """ if self.contextMenuEditor: fn = self.contextMenuEditor.getFileName() if fn: cb = QApplication.clipboard() cb.setText(fn) def __currentChanged(self, index): """ Private slot to handle the currentChanged signal. @param index index of the current editor """ if index == -1 or not self.editors: return editor = self.activeWindow() if editor is None: return self._checkActions(editor) editor.setFocus() fn = editor.getFileName() if fn: self.changeCaption.emit(fn) if not self.__inRemoveView: self.editorChanged.emit(fn) self.editorLineChanged.emit(fn, editor.getCursorPosition()[0] + 1) else: self.changeCaption.emit("") self.editorChangedEd.emit(editor) cindex = self.editors.index(editor) self.viewlist.setCurrentRow(cindex) def eventFilter(self, watched, event): """ Public method called to filter the event queue. @param watched the QObject being watched @param event the event that occurred @return flag indicating, if we handled the event """ if event.type() == QEvent.MouseButtonPress and \ not event.button() == Qt.RightButton: switched = True if isinstance(watched, QStackedWidget): switched = watched is not self.currentStack self.currentStack = watched elif isinstance(watched, QScintilla.Editor.Editor): for stack in self.stacks: if stack.hasEditor(watched): switched = stack is not self.currentStack self.currentStack = stack break currentWidget = self.currentStack.currentWidget() if currentWidget: index = self.editors.index(currentWidget) self.viewlist.setCurrentRow(index) aw = self.activeWindow() if aw is not None: self._checkActions(aw) aw.setFocus() fn = aw.getFileName() if fn: self.changeCaption.emit(fn) if switched: self.editorChanged.emit(fn) self.editorLineChanged.emit( fn, aw.getCursorPosition()[0] + 1) else: self.changeCaption.emit("") self.editorChangedEd.emit(aw) return False
class Tabview(ViewManager): """ Class implementing a tabbed viewmanager class embedded in a splitter. @signal changeCaption(str) emitted if a change of the caption is necessary @signal editorChanged(str) emitted when the current editor has changed @signal editorChangedEd(Editor) emitted when the current editor has changed @signal lastEditorClosed() emitted after the last editor window was closed @signal editorOpened(str) emitted after an editor window was opened @signal editorOpenedEd(Editor) emitted after an editor window was opened @signal editorClosed(str) emitted just before an editor window gets closed @signal editorClosedEd(Editor) emitted just before an editor window gets closed @signal editorRenamed(str) emitted after an editor was renamed @signal editorRenamedEd(Editor) emitted after an editor was renamed @signal editorSaved(str) emitted after an editor window was saved @signal editorSavedEd(Editor) emitted after an editor window was saved @signal checkActions(Editor) emitted when some actions should be checked for their status @signal cursorChanged(Editor) emitted after the cursor position of the active window has changed @signal breakpointToggled(Editor) emitted when a breakpoint is toggled. @signal bookmarkToggled(Editor) emitted when a bookmark is toggled. @signal syntaxerrorToggled(Editor) emitted when a syntax error is toggled. @signal previewStateChanged(bool) emitted to signal a change in the preview state @signal editorLanguageChanged(Editor) emitted to signal a change of an editors language @signal editorTextChanged(Editor) emitted to signal a change of an editor's text @signal editorLineChanged(str,int) emitted to signal a change of an editor's current line (line is given one based) """ changeCaption = pyqtSignal(str) editorChanged = pyqtSignal(str) editorChangedEd = pyqtSignal(Editor) lastEditorClosed = pyqtSignal() editorOpened = pyqtSignal(str) editorOpenedEd = pyqtSignal(Editor) editorClosed = pyqtSignal(str) editorClosedEd = pyqtSignal(Editor) editorRenamed = pyqtSignal(str) editorRenamedEd = pyqtSignal(Editor) editorSaved = pyqtSignal(str) editorSavedEd = pyqtSignal(Editor) checkActions = pyqtSignal(Editor) cursorChanged = pyqtSignal(Editor) breakpointToggled = pyqtSignal(Editor) bookmarkToggled = pyqtSignal(Editor) syntaxerrorToggled = pyqtSignal(Editor) previewStateChanged = pyqtSignal(bool) editorLanguageChanged = pyqtSignal(Editor) editorTextChanged = pyqtSignal(Editor) editorLineChanged = pyqtSignal(str, int) def __init__(self, parent): """ Constructor @param parent parent widget (QWidget) """ self.tabWidgets = [] self.__splitter = QSplitter(parent) ViewManager.__init__(self) self.__splitter.setChildrenCollapsible(False) tw = TabWidget(self) self.__splitter.addWidget(tw) self.tabWidgets.append(tw) self.currentTabWidget = tw self.currentTabWidget.showIndicator(True) tw.currentChanged.connect(self.__currentChanged) tw.installEventFilter(self) tw.tabBar().installEventFilter(self) self.__splitter.setOrientation(Qt.Vertical) self.__inRemoveView = False self.maxFileNameChars = Preferences.getUI( "TabViewManagerFilenameLength") self.filenameOnly = Preferences.getUI("TabViewManagerFilenameOnly") def mainWidget(self): """ Public method to return a reference to the main Widget of a specific view manager subclass. @return reference to the main widget @rtype QWidget """ return self.__splitter def canCascade(self): """ Public method to signal if cascading of managed windows is available. @return flag indicating cascading of windows is available """ return False def canTile(self): """ Public method to signal if tiling of managed windows is available. @return flag indicating tiling of windows is available """ return False def canSplit(self): """ public method to signal if splitting of the view is available. @return flag indicating splitting of the view is available. """ return True def tile(self): """ Public method to tile the managed windows. """ pass def cascade(self): """ Public method to cascade the managed windows. """ pass def _removeAllViews(self): """ Protected method to remove all views (i.e. windows). """ for win in self.editors: self._removeView(win) def _removeView(self, win): """ Protected method to remove a view (i.e. window). @param win editor window to be removed """ self.__inRemoveView = True for tw in self.tabWidgets: if tw.hasEditor(win): tw.removeWidget(win) break win.closeIt() self.__inRemoveView = False # if this was the last editor in this view, switch to the next, that # still has open editors for i in list(range(self.tabWidgets.index(tw), -1, -1)) + \ list(range(self.tabWidgets.index(tw) + 1, len(self.tabWidgets))): if self.tabWidgets[i].hasEditors(): self.currentTabWidget.showIndicator(False) self.currentTabWidget = self.tabWidgets[i] self.currentTabWidget.showIndicator(True) self.activeWindow().setFocus() break aw = self.activeWindow() fn = aw and aw.getFileName() or None if fn: self.changeCaption.emit(fn) self.editorChanged.emit(fn) self.editorLineChanged.emit(fn, aw.getCursorPosition()[0] + 1) else: self.changeCaption.emit("") self.editorChangedEd.emit(aw) def _addView(self, win, fn=None, noName="", next=False): """ Protected method to add a view (i.e. window). @param win editor assembly to be added @param fn filename of this editor (string) @param noName name to be used for an unnamed editor (string) @param next flag indicating to add the view next to the current view (bool) """ editor = win.getEditor() if fn is None: if not noName: self.untitledCount += 1 noName = self.tr("Untitled {0}").format(self.untitledCount) if next: index = self.currentTabWidget.currentIndex() + 1 self.currentTabWidget.insertWidget(index, win, noName) else: self.currentTabWidget.addTab(win, noName) editor.setNoName(noName) else: if self.filenameOnly: txt = os.path.basename(fn) else: txt = e5App().getObject("Project").getRelativePath(fn) if len(txt) > self.maxFileNameChars: txt = "...{0}".format(txt[-self.maxFileNameChars:]) if not QFileInfo(fn).isWritable(): txt = self.tr("{0} (ro)").format(txt) if next: index = self.currentTabWidget.currentIndex() + 1 self.currentTabWidget.insertWidget(index, win, txt) else: self.currentTabWidget.addTab(win, txt) index = self.currentTabWidget.indexOf(win) self.currentTabWidget.setTabToolTip(index, fn) self.currentTabWidget.setCurrentWidget(win) win.show() editor.setFocus() if fn: self.changeCaption.emit(fn) self.editorChanged.emit(fn) self.editorLineChanged.emit(fn, editor.getCursorPosition()[0] + 1) else: self.changeCaption.emit("") self.editorChangedEd.emit(editor) def insertView(self, win, tabWidget, index, fn=None, noName=""): """ Public method to add a view (i.e. window). @param win editor assembly to be inserted @param tabWidget reference to the tab widget to insert the editor into (TabWidget) @param index index position to insert at (integer) @param fn filename of this editor (string) @param noName name to be used for an unnamed editor (string) """ editor = win.getEditor() if fn is None: if not noName: self.untitledCount += 1 noName = self.tr("Untitled {0}").format(self.untitledCount) tabWidget.insertWidget(index, win, noName) editor.setNoName(noName) else: if self.filenameOnly: txt = os.path.basename(fn) else: txt = e5App().getObject("Project").getRelativePath(fn) if len(txt) > self.maxFileNameChars: txt = "...{0}".format(txt[-self.maxFileNameChars:]) if not QFileInfo(fn).isWritable(): txt = self.tr("{0} (ro)").format(txt) nindex = tabWidget.insertWidget(index, win, txt) tabWidget.setTabToolTip(nindex, fn) tabWidget.setCurrentWidget(win) win.show() editor.setFocus() if fn: self.changeCaption.emit(fn) self.editorChanged.emit(fn) self.editorLineChanged.emit(fn, editor.getCursorPosition()[0] + 1) else: self.changeCaption.emit("") self.editorChangedEd.emit(editor) self._modificationStatusChanged(editor.isModified(), editor) self._checkActions(editor) def _showView(self, win, fn=None): """ Protected method to show a view (i.e. window). @param win editor assembly to be shown @param fn filename of this editor (string) """ win.show() editor = win.getEditor() for tw in self.tabWidgets: if tw.hasEditor(editor): tw.setCurrentWidget(win) self.currentTabWidget.showIndicator(False) self.currentTabWidget = tw self.currentTabWidget.showIndicator(True) break editor.setFocus() def activeWindow(self): """ Public method to return the active (i.e. current) window. @return reference to the active editor """ cw = self.currentTabWidget.currentWidget() if cw: return cw.getEditor() else: return None def showWindowMenu(self, windowMenu): """ Public method to set up the viewmanager part of the Window menu. @param windowMenu reference to the window menu """ pass def _initWindowActions(self): """ Protected method to define the user interface actions for window handling. """ pass def setEditorName(self, editor, newName): """ Public method to change the displayed name of the editor. @param editor editor window to be changed @param newName new name to be shown (string) """ if newName: if self.filenameOnly: tabName = os.path.basename(newName) else: tabName = e5App().getObject("Project").getRelativePath(newName) if len(tabName) > self.maxFileNameChars: tabName = "...{0}".format(tabName[-self.maxFileNameChars:]) index = self.currentTabWidget.indexOf(editor) self.currentTabWidget.setTabText(index, tabName) self.currentTabWidget.setTabToolTip(index, newName) self.changeCaption.emit(newName) def _modificationStatusChanged(self, m, editor): """ Protected slot to handle the modificationStatusChanged signal. @param m flag indicating the modification status (boolean) @param editor editor window changed """ for tw in self.tabWidgets: if tw.hasEditor(editor): break index = tw.indexOf(editor) keys = [] if m: keys.append("fileModified.png") if editor.hasSyntaxErrors(): keys.append("syntaxError22.png") elif editor.hasWarnings(): keys.append("warning22.png") if not keys: keys.append("empty.png") tw.setTabIcon(index, UI.PixmapCache.getCombinedIcon(keys)) self._checkActions(editor) def _syntaxErrorToggled(self, editor): """ Protected slot to handle the syntaxerrorToggled signal. @param editor editor that sent the signal """ for tw in self.tabWidgets: if tw.hasEditor(editor): break index = tw.indexOf(editor) keys = [] if editor.isModified(): keys.append("fileModified.png") if editor.hasSyntaxErrors(): keys.append("syntaxError22.png") elif editor.hasWarnings(): keys.append("warning22.png") if not keys: keys.append("empty.png") tw.setTabIcon(index, UI.PixmapCache.getCombinedIcon(keys)) ViewManager._syntaxErrorToggled(self, editor) def addSplit(self): """ Public method used to split the current view. """ tw = TabWidget(self) tw.show() self.__splitter.addWidget(tw) self.tabWidgets.append(tw) self.currentTabWidget.showIndicator(False) self.currentTabWidget = self.tabWidgets[-1] self.currentTabWidget.showIndicator(True) tw.currentChanged.connect(self.__currentChanged) tw.installEventFilter(self) tw.tabBar().installEventFilter(self) if self.__splitter.orientation() == Qt.Horizontal: size = self.width() else: size = self.height() self.__splitter.setSizes([int(size / len(self.tabWidgets))] * len(self.tabWidgets)) self.splitRemoveAct.setEnabled(True) self.nextSplitAct.setEnabled(True) self.prevSplitAct.setEnabled(True) def removeSplit(self): """ Public method used to remove the current split view. @return flag indicating successfull removal """ if len(self.tabWidgets) > 1: tw = self.currentTabWidget res = True savedEditors = tw.editors[:] for editor in savedEditors: res &= self.closeEditor(editor) if res: try: i = self.tabWidgets.index(tw) except ValueError: return True if i == len(self.tabWidgets) - 1: i -= 1 self.tabWidgets.remove(tw) tw.close() self.currentTabWidget = self.tabWidgets[i] for tw in self.tabWidgets: tw.showIndicator(tw == self.currentTabWidget) if self.currentTabWidget is not None: assembly = self.currentTabWidget.currentWidget() if assembly is not None: editor = assembly.getEditor() if editor is not None: editor.setFocus(Qt.OtherFocusReason) if len(self.tabWidgets) == 1: self.splitRemoveAct.setEnabled(False) self.nextSplitAct.setEnabled(False) self.prevSplitAct.setEnabled(False) return True return False def getSplitOrientation(self): """ Public method to get the orientation of the split view. @return orientation of the split (Qt.Horizontal or Qt.Vertical) """ return self.__splitter.orientation() def setSplitOrientation(self, orientation): """ Public method used to set the orientation of the split view. @param orientation orientation of the split (Qt.Horizontal or Qt.Vertical) """ self.__splitter.setOrientation(orientation) def nextSplit(self): """ Public slot used to move to the next split. """ aw = self.activeWindow() _hasFocus = aw and aw.hasFocus() ind = self.tabWidgets.index(self.currentTabWidget) + 1 if ind == len(self.tabWidgets): ind = 0 self.currentTabWidget.showIndicator(False) self.currentTabWidget = self.tabWidgets[ind] self.currentTabWidget.showIndicator(True) if _hasFocus: aw = self.activeWindow() if aw: aw.setFocus() def prevSplit(self): """ Public slot used to move to the previous split. """ aw = self.activeWindow() _hasFocus = aw and aw.hasFocus() ind = self.tabWidgets.index(self.currentTabWidget) - 1 if ind == -1: ind = len(self.tabWidgets) - 1 self.currentTabWidget.showIndicator(False) self.currentTabWidget = self.tabWidgets[ind] self.currentTabWidget.showIndicator(True) if _hasFocus: aw = self.activeWindow() if aw: aw.setFocus() def __currentChanged(self, index): """ Private slot to handle the currentChanged signal. @param index index of the current tab (integer) """ if index == -1 or not self.editors: return editor = self.activeWindow() if editor is None: return self._checkActions(editor) editor.setFocus() fn = editor.getFileName() if fn: self.changeCaption.emit(fn) if not self.__inRemoveView: self.editorChanged.emit(fn) self.editorLineChanged.emit(fn, editor.getCursorPosition()[0] + 1) else: self.changeCaption.emit("") self.editorChangedEd.emit(editor) def eventFilter(self, watched, event): """ Public method called to filter the event queue. @param watched the QObject being watched (QObject) @param event the event that occurred (QEvent) @return always False """ if event.type() == QEvent.MouseButtonPress and \ not event.button() == Qt.RightButton: switched = True self.currentTabWidget.showIndicator(False) if isinstance(watched, E5TabWidget): switched = watched is not self.currentTabWidget self.currentTabWidget = watched elif isinstance(watched, QTabBar): switched = watched.parent() is not self.currentTabWidget self.currentTabWidget = watched.parent() if switched: index = self.currentTabWidget.selectTab(event.pos()) switched = self.currentTabWidget.widget(index) is \ self.activeWindow() elif isinstance(watched, QScintilla.Editor.Editor): for tw in self.tabWidgets: if tw.hasEditor(watched): switched = tw is not self.currentTabWidget self.currentTabWidget = tw break self.currentTabWidget.showIndicator(True) aw = self.activeWindow() if aw is not None: self._checkActions(aw) aw.setFocus() fn = aw.getFileName() if fn: self.changeCaption.emit(fn) if switched: self.editorChanged.emit(fn) self.editorLineChanged.emit( fn, aw.getCursorPosition()[0] + 1) else: self.changeCaption.emit("") self.editorChangedEd.emit(aw) return False def preferencesChanged(self): """ Public slot to handle the preferencesChanged signal. """ ViewManager.preferencesChanged(self) self.maxFileNameChars = Preferences.getUI( "TabViewManagerFilenameLength") self.filenameOnly = Preferences.getUI("TabViewManagerFilenameOnly") for tabWidget in self.tabWidgets: for index in range(tabWidget.count()): editor = tabWidget.widget(index) if isinstance(editor, QScintilla.Editor.Editor): fn = editor.getFileName() if fn: if self.filenameOnly: txt = os.path.basename(fn) else: txt = e5App().getObject("Project")\ .getRelativePath(fn) if len(txt) > self.maxFileNameChars: txt = "...{0}".format(txt[-self.maxFileNameChars:]) if not QFileInfo(fn).isWritable(): txt = self.tr("{0} (ro)").format(txt) tabWidget.setTabText(index, txt) def getTabWidgetById(self, id_): """ Public method to get a reference to a tab widget knowing its ID. @param id_ id of the tab widget (long) @return reference to the tab widget (TabWidget) """ for tw in self.tabWidgets: if id(tw) == id_: return tw return None
class _s_CentralWidget(QWidget): ############################################################################### # CentralWidget SIGNALS ############################################################################### """ splitterCentralRotated() """ splitterCentralRotated = pyqtSignal() ############################################################################### def __init__(self, parent=None): super(_s_CentralWidget, self).__init__(parent) self.parent = parent #This variables are used to save the splitter sizes before hide self._splitterMainSizes = None self._splitterAreaSizes = None self.lateralPanel = None hbox = QHBoxLayout(self) hbox.setContentsMargins(0, 0, 0, 0) hbox.setSpacing(0) #Create Splitters to divide the UI in: MainPanel, Explorer, Misc self._splitterArea = QSplitter(Qt.Horizontal) self._splitterMain = QSplitter(Qt.Vertical) #Create scrollbar for follow mode self.scrollBar = QScrollBar(Qt.Vertical, self) self.scrollBar.setFixedWidth(20) self.scrollBar.setToolTip('Follow Mode: Scroll the Editors together') self.scrollBar.hide() self.scrollBar.valueChanged[int].connect(self.move_follow_scrolls) #Add to Main Layout hbox.addWidget(self.scrollBar) hbox.addWidget(self._splitterArea) def insert_central_container(self, container): self.mainContainer = container self._splitterMain.insertWidget(0, container) def insert_lateral_container(self, container): self.lateralPanel = LateralPanel(container) self._splitterArea.insertWidget(0, self.lateralPanel) def insert_bottom_container(self, container): self.misc = container self._splitterMain.insertWidget(1, container) def showEvent(self, event): #Show Event QWidget.showEvent(self, event) #Avoid recalculate the panel sizes if they are already loaded if self._splitterArea.count() == 2: return #Rearrange widgets on Window self._splitterArea.insertWidget(0, self._splitterMain) if not event.spontaneous(): self.change_misc_visibility() if bin(settings.UI_LAYOUT)[-1] == '1': self.splitter_central_rotate() if bin(settings.UI_LAYOUT >> 1)[-1] == '1': self.splitter_misc_rotate() if bin(settings.UI_LAYOUT >> 2)[-1] == '1': self.splitter_central_orientation() qsettings = QSettings(resources.SETTINGS_PATH, QSettings.IniFormat) #Lists of sizes as list of QVariant- heightList = [QVariant, QVariant] heightList = list(qsettings.value("window/central/mainSize", [(self.height() / 3) * 2, self.height() / 3])) widthList = list(qsettings.value("window/central/areaSize", [(self.width() / 6) * 5, self.width() / 6])) self._splitterMainSizes = [int(heightList[0]), int(heightList[1])] self._splitterAreaSizes = [int(widthList[0]), int(widthList[1])] #Set the sizes to splitters #self._splitterMain.setSizes(self._splitterMainSizes) self._splitterMain.setSizes(self._splitterMainSizes) self._splitterArea.setSizes(self._splitterAreaSizes) self.misc.setVisible( qsettings.value("window/show_misc", False, type=bool)) def change_misc_visibility(self, on_start=False): if self.misc.isVisible(): self._splitterMainSizes = self._splitterMain.sizes() self.misc.hide() widget = self.mainContainer.get_actual_widget() if widget: widget.setFocus() else: self.misc.show() self.misc.gain_focus() def change_main_visibility(self): if self.mainContainer.isVisible(): self.mainContainer.hide() else: self.mainContainer.show() def change_explorer_visibility(self, force_hide=False): if self.lateralPanel.isVisible() or force_hide: self._splitterAreaSizes = self._splitterArea.sizes() self.lateralPanel.hide() else: self.lateralPanel.show() def splitter_central_rotate(self): w1, w2 = self._splitterArea.widget(0), self._splitterArea.widget(1) self._splitterArea.insertWidget(0, w2) self._splitterArea.insertWidget(1, w1) self.splitterCentralRotated.emit() def splitter_central_orientation(self): if self._splitterArea.orientation() == Qt.Horizontal: self._splitterArea.setOrientation(Qt.Vertical) else: self._splitterArea.setOrientation(Qt.Horizontal) def splitter_misc_rotate(self): w1, w2 = self._splitterMain.widget(0), self._splitterMain.widget(1) self._splitterMain.insertWidget(0, w2) self._splitterMain.insertWidget(1, w1) def splitter_misc_orientation(self): if self._splitterMain.orientation() == Qt.Horizontal: self._splitterMain.setOrientation(Qt.Vertical) else: self._splitterMain.setOrientation(Qt.Horizontal) def get_area_sizes(self): if self.lateralPanel.isVisible(): self._splitterAreaSizes = self._splitterArea.sizes() return self._splitterAreaSizes def get_main_sizes(self): if self.misc.isVisible(): self._splitterMainSizes = self._splitterMain.sizes() return self._splitterMainSizes def enable_follow_mode_scrollbar(self, val): if val: editorWidget = self.mainContainer.get_actual_editor() maxScroll = editorWidget.verticalScrollBar().maximum() position = editorWidget.verticalScrollBar().value() self.scrollBar.setMaximum(maxScroll) self.scrollBar.setValue(position) self.scrollBar.setVisible(val) def move_follow_scrolls(self, val): widget = self.mainContainer._tabMain.currentWidget() diff = widget._sidebarWidget.highest_line - val s1 = self.mainContainer._tabMain.currentWidget().verticalScrollBar() s2 = self.mainContainer._tabSecondary.\ currentWidget().verticalScrollBar() s1.setValue(val) s2.setValue(val + diff)
class Listspace(QSplitter, ViewManager): """ Class implementing the listspace viewmanager class. @signal changeCaption(str) emitted if a change of the caption is necessary @signal editorChanged(str) emitted when the current editor has changed @signal editorChangedEd(Editor) emitted when the current editor has changed @signal lastEditorClosed() emitted after the last editor window was closed @signal editorOpened(str) emitted after an editor window was opened @signal editorOpenedEd(Editor) emitted after an editor window was opened @signal editorClosed(str) emitted just before an editor window gets closed @signal editorClosedEd(Editor) emitted just before an editor window gets closed @signal editorRenamed(str) emitted after an editor was renamed @signal editorRenamedEd(Editor) emitted after an editor was renamed @signal editorSaved(str) emitted after an editor window was saved @signal editorSavedEd(Editor) emitted after an editor window was saved @signal checkActions(Editor) emitted when some actions should be checked for their status @signal cursorChanged(Editor) emitted after the cursor position of the active window has changed @signal breakpointToggled(Editor) emitted when a breakpoint is toggled. @signal bookmarkToggled(Editor) emitted when a bookmark is toggled. @signal syntaxerrorToggled(Editor) emitted when a syntax error is toggled. @signal previewStateChanged(bool) emitted to signal a change in the preview state @signal editorLanguageChanged(Editor) emitted to signal a change of an editors language @signal editorTextChanged(Editor) emitted to signal a change of an editor's text @signal editorLineChanged(str,int) emitted to signal a change of an editor's current line (line is given one based) """ changeCaption = pyqtSignal(str) editorChanged = pyqtSignal(str) editorChangedEd = pyqtSignal(Editor) lastEditorClosed = pyqtSignal() editorOpened = pyqtSignal(str) editorOpenedEd = pyqtSignal(Editor) editorClosed = pyqtSignal(str) editorClosedEd = pyqtSignal(Editor) editorRenamed = pyqtSignal(str) editorRenamedEd = pyqtSignal(Editor) editorSaved = pyqtSignal(str) editorSavedEd = pyqtSignal(Editor) checkActions = pyqtSignal(Editor) cursorChanged = pyqtSignal(Editor) breakpointToggled = pyqtSignal(Editor) bookmarkToggled = pyqtSignal(Editor) syntaxerrorToggled = pyqtSignal(Editor) previewStateChanged = pyqtSignal(bool) editorLanguageChanged = pyqtSignal(Editor) editorTextChanged = pyqtSignal(Editor) editorLineChanged = pyqtSignal(str, int) def __init__(self, parent): """ Constructor @param parent parent widget (QWidget) """ self.stacks = [] QSplitter.__init__(self, parent) ViewManager.__init__(self) self.setChildrenCollapsible(False) self.viewlist = QListWidget(self) policy = self.viewlist.sizePolicy() policy.setHorizontalPolicy(QSizePolicy.Ignored) self.viewlist.setSizePolicy(policy) self.addWidget(self.viewlist) self.viewlist.setContextMenuPolicy(Qt.CustomContextMenu) self.viewlist.currentRowChanged.connect(self.__showSelectedView) self.viewlist.customContextMenuRequested.connect(self.__showMenu) self.stackArea = QSplitter(self) self.stackArea.setChildrenCollapsible(False) self.addWidget(self.stackArea) self.stackArea.setOrientation(Qt.Vertical) stack = StackedWidget(self.stackArea) self.stackArea.addWidget(stack) self.stacks.append(stack) self.currentStack = stack stack.currentChanged.connect(self.__currentChanged) stack.installEventFilter(self) self.setSizes([int(self.width() * 0.2), int(self.width() * 0.8)]) # 20% for viewlist, 80% for the editors self.__inRemoveView = False self.__initMenu() self.contextMenuEditor = None self.contextMenuIndex = -1 def __initMenu(self): """ Private method to initialize the viewlist context menu. """ self.__menu = QMenu(self) self.__menu.addAction( UI.PixmapCache.getIcon("tabClose.png"), self.tr('Close'), self.__contextMenuClose) self.closeOthersMenuAct = self.__menu.addAction( UI.PixmapCache.getIcon("tabCloseOther.png"), self.tr("Close Others"), self.__contextMenuCloseOthers) self.__menu.addAction( self.tr('Close All'), self.__contextMenuCloseAll) self.__menu.addSeparator() self.saveMenuAct = self.__menu.addAction( UI.PixmapCache.getIcon("fileSave.png"), self.tr('Save'), self.__contextMenuSave) self.__menu.addAction( UI.PixmapCache.getIcon("fileSaveAs.png"), self.tr('Save As...'), self.__contextMenuSaveAs) self.__menu.addAction( UI.PixmapCache.getIcon("fileSaveAll.png"), self.tr('Save All'), self.__contextMenuSaveAll) self.__menu.addSeparator() self.openRejectionsMenuAct = self.__menu.addAction( self.tr("Open 'rejection' file"), self.__contextMenuOpenRejections) self.__menu.addSeparator() self.__menu.addAction( UI.PixmapCache.getIcon("print.png"), self.tr('Print'), self.__contextMenuPrintFile) self.__menu.addSeparator() self.copyPathAct = self.__menu.addAction( self.tr("Copy Path to Clipboard"), self.__contextMenuCopyPathToClipboard) def __showMenu(self, point): """ Private slot to handle the customContextMenuRequested signal of the viewlist. @param point position to open the menu at (QPoint) """ if self.editors: itm = self.viewlist.itemAt(point) if itm is not None: row = self.viewlist.row(itm) self.contextMenuEditor = self.editors[row] self.contextMenuIndex = row if self.contextMenuEditor: self.saveMenuAct.setEnabled( self.contextMenuEditor.isModified()) fileName = self.contextMenuEditor.getFileName() self.copyPathAct.setEnabled(bool(fileName)) if fileName: rej = "{0}.rej".format(fileName) self.openRejectionsMenuAct.setEnabled( os.path.exists(rej)) else: self.openRejectionsMenuAct.setEnabled(False) self.closeOthersMenuAct.setEnabled( self.viewlist.count() > 1) self.__menu.popup(self.viewlist.mapToGlobal(point)) def canCascade(self): """ Public method to signal if cascading of managed windows is available. @return flag indicating cascading of windows is available """ return False def canTile(self): """ Public method to signal if tiling of managed windows is available. @return flag indicating tiling of windows is available """ return False def canSplit(self): """ public method to signal if splitting of the view is available. @return flag indicating splitting of the view is available. """ return True def tile(self): """ Public method to tile the managed windows. """ pass def cascade(self): """ Public method to cascade the managed windows. """ pass def _removeAllViews(self): """ Protected method to remove all views (i.e. windows). """ self.viewlist.clear() for win in self.editors: for stack in self.stacks: if stack.hasEditor(win): stack.removeWidget(win) break win.closeIt() def _removeView(self, win): """ Protected method to remove a view (i.e. window). @param win editor window to be removed """ self.__inRemoveView = True ind = self.editors.index(win) itm = self.viewlist.takeItem(ind) if itm: del itm for stack in self.stacks: if stack.hasEditor(win): stack.removeWidget(win) break win.closeIt() self.__inRemoveView = False if ind > 0: ind -= 1 else: if len(self.editors) > 1: ind = 1 else: return stack.setCurrentWidget(stack.firstEditor()) self._showView(self.editors[ind].parent()) aw = self.activeWindow() fn = aw and aw.getFileName() or None if fn: self.changeCaption.emit(fn) self.editorChanged.emit(fn) self.editorLineChanged.emit(fn, aw.getCursorPosition()[0] + 1) else: self.changeCaption.emit("") self.editorChangedEd.emit(aw) def _addView(self, win, fn=None, noName="", next=False): """ Protected method to add a view (i.e. window). @param win editor assembly to be added @param fn filename of this editor (string) @param noName name to be used for an unnamed editor (string) @param next flag indicating to add the view next to the current view (bool) """ editor = win.getEditor() if fn is None: if not noName: self.untitledCount += 1 noName = self.tr("Untitled {0}").format(self.untitledCount) self.viewlist.addItem(noName) editor.setNoName(noName) else: txt = os.path.basename(fn) if not QFileInfo(fn).isWritable(): txt = self.tr("{0} (ro)").format(txt) itm = QListWidgetItem(txt) itm.setToolTip(fn) self.viewlist.addItem(itm) self.currentStack.addWidget(win) self.currentStack.setCurrentWidget(win) editor.captionChanged.connect(self.__captionChange) editor.cursorLineChanged.connect(self.__cursorLineChanged) index = self.editors.index(editor) self.viewlist.setCurrentRow(index) editor.setFocus() if fn: self.changeCaption.emit(fn) self.editorChanged.emit(fn) self.editorLineChanged.emit(fn, editor.getCursorPosition()[0] + 1) else: self.changeCaption.emit("") self.editorChangedEd.emit(editor) def __captionChange(self, cap, editor): """ Private method to handle caption change signals from the editor. Updates the listwidget text to reflect the new caption information. @param cap Caption for the editor (string) @param editor Editor to update the caption for """ fn = editor.getFileName() if fn: self.setEditorName(editor, fn) def __cursorLineChanged(self, lineno): """ Private slot to handle a change of the current editor's cursor line. @param lineno line number of the current editor's cursor (zero based) """ editor = self.sender() if editor: fn = editor.getFileName() if fn: self.editorLineChanged.emit(fn, lineno + 1) def _showView(self, win, fn=None): """ Protected method to show a view (i.e. window). @param win editor assembly to be shown @param fn filename of this editor (string) """ editor = win.getEditor() for stack in self.stacks: if stack.hasEditor(editor): stack.setCurrentWidget(win) self.currentStack = stack break index = self.editors.index(editor) self.viewlist.setCurrentRow(index) editor.setFocus() fn = editor.getFileName() if fn: self.changeCaption.emit(fn) self.editorChanged.emit(fn) self.editorLineChanged.emit(fn, editor.getCursorPosition()[0] + 1) else: self.changeCaption.emit("") self.editorChangedEd.emit(editor) def __showSelectedView(self, row): """ Private slot called to show a view selected in the list. @param row row number of the item clicked on (integer) """ if row != -1: self._showView(self.editors[row].parent()) self._checkActions(self.editors[row]) def activeWindow(self): """ Public method to return the active (i.e. current) window. @return reference to the active editor """ return self.currentStack.currentWidget() def showWindowMenu(self, windowMenu): """ Public method to set up the viewmanager part of the Window menu. @param windowMenu reference to the window menu """ pass def _initWindowActions(self): """ Protected method to define the user interface actions for window handling. """ pass def setEditorName(self, editor, newName): """ Public method to change the displayed name of the editor. @param editor editor window to be changed @param newName new name to be shown (string) """ if newName: currentRow = self.viewlist.currentRow() index = self.editors.index(editor) txt = os.path.basename(newName) if not QFileInfo(newName).isWritable(): txt = self.tr("{0} (ro)").format(txt) itm = self.viewlist.item(index) itm.setText(txt) itm.setToolTip(newName) self.viewlist.setCurrentRow(currentRow) self.changeCaption.emit(newName) def _modificationStatusChanged(self, m, editor): """ Protected slot to handle the modificationStatusChanged signal. @param m flag indicating the modification status (boolean) @param editor editor window changed """ currentRow = self.viewlist.currentRow() index = self.editors.index(editor) keys = [] if m: keys.append("fileModified.png") if editor.hasSyntaxErrors(): keys.append("syntaxError22.png") elif editor.hasWarnings(): keys.append("warning22.png") if not keys: keys.append("empty.png") self.viewlist.item(index).setIcon( UI.PixmapCache.getCombinedIcon(keys)) self.viewlist.setCurrentRow(currentRow) self._checkActions(editor) def _syntaxErrorToggled(self, editor): """ Protected slot to handle the syntaxerrorToggled signal. @param editor editor that sent the signal """ currentRow = self.viewlist.currentRow() index = self.editors.index(editor) keys = [] if editor.isModified(): keys.append("fileModified.png") if editor.hasSyntaxErrors(): keys.append("syntaxError22.png") elif editor.hasWarnings(): keys.append("warning22.png") if not keys: keys.append("empty.png") self.viewlist.item(index).setIcon( UI.PixmapCache.getCombinedIcon(keys)) self.viewlist.setCurrentRow(currentRow) ViewManager._syntaxErrorToggled(self, editor) def addSplit(self): """ Public method used to split the current view. """ stack = StackedWidget(self.stackArea) stack.show() self.stackArea.addWidget(stack) self.stacks.append(stack) self.currentStack = stack stack.currentChanged.connect(self.__currentChanged) stack.installEventFilter(self) if self.stackArea.orientation() == Qt.Horizontal: size = self.stackArea.width() else: size = self.stackArea.height() self.stackArea.setSizes( [int(size / len(self.stacks))] * len(self.stacks)) self.splitRemoveAct.setEnabled(True) self.nextSplitAct.setEnabled(True) self.prevSplitAct.setEnabled(True) def removeSplit(self): """ Public method used to remove the current split view. @return flag indicating successfull removal """ if len(self.stacks) > 1: stack = self.currentStack res = True savedEditors = stack.editors[:] for editor in savedEditors: res &= self.closeEditor(editor) if res: try: i = self.stacks.index(stack) except ValueError: return True if i == len(self.stacks) - 1: i -= 1 self.stacks.remove(stack) stack.close() self.currentStack = self.stacks[i] if len(self.stacks) == 1: self.splitRemoveAct.setEnabled(False) self.nextSplitAct.setEnabled(False) self.prevSplitAct.setEnabled(False) return True return False def getSplitOrientation(self): """ Public method to get the orientation of the split view. @return orientation of the split (Qt.Horizontal or Qt.Vertical) """ return self.stackArea.orientation() def setSplitOrientation(self, orientation): """ Public method used to set the orientation of the split view. @param orientation orientation of the split (Qt.Horizontal or Qt.Vertical) """ self.stackArea.setOrientation(orientation) def nextSplit(self): """ Public slot used to move to the next split. """ aw = self.activeWindow() _hasFocus = aw and aw.hasFocus() ind = self.stacks.index(self.currentStack) + 1 if ind == len(self.stacks): ind = 0 self.currentStack = self.stacks[ind] if _hasFocus: aw = self.activeWindow() if aw: aw.setFocus() index = self.editors.index(self.currentStack.currentWidget()) self.viewlist.setCurrentRow(index) def prevSplit(self): """ Public slot used to move to the previous split. """ aw = self.activeWindow() _hasFocus = aw and aw.hasFocus() ind = self.stacks.index(self.currentStack) - 1 if ind == -1: ind = len(self.stacks) - 1 self.currentStack = self.stacks[ind] if _hasFocus: aw = self.activeWindow() if aw: aw.setFocus() index = self.editors.index(self.currentStack.currentWidget()) self.viewlist.setCurrentRow(index) def __contextMenuClose(self): """ Private method to close the selected editor. """ if self.contextMenuEditor: self.closeEditorWindow(self.contextMenuEditor) def __contextMenuCloseOthers(self): """ Private method to close the other editors. """ index = self.contextMenuIndex for i in list(range(self.viewlist.count() - 1, index, -1)) + \ list(range(index - 1, -1, -1)): editor = self.editors[i] self.closeEditorWindow(editor) def __contextMenuCloseAll(self): """ Private method to close all editors. """ savedEditors = self.editors[:] for editor in savedEditors: self.closeEditorWindow(editor) def __contextMenuSave(self): """ Private method to save the selected editor. """ if self.contextMenuEditor: self.saveEditorEd(self.contextMenuEditor) def __contextMenuSaveAs(self): """ Private method to save the selected editor to a new file. """ if self.contextMenuEditor: self.saveAsEditorEd(self.contextMenuEditor) def __contextMenuSaveAll(self): """ Private method to save all editors. """ self.saveEditorsList(self.editors) def __contextMenuOpenRejections(self): """ Private slot to open a rejections file associated with the selected editor. """ if self.contextMenuEditor: fileName = self.contextMenuEditor.getFileName() if fileName: rej = "{0}.rej".format(fileName) if os.path.exists(rej): self.openSourceFile(rej) def __contextMenuPrintFile(self): """ Private method to print the selected editor. """ if self.contextMenuEditor: self.printEditor(self.contextMenuEditor) def __contextMenuCopyPathToClipboard(self): """ Private method to copy the file name of the selected editor to the clipboard. """ if self.contextMenuEditor: fn = self.contextMenuEditor.getFileName() if fn: cb = QApplication.clipboard() cb.setText(fn) def __currentChanged(self, index): """ Private slot to handle the currentChanged signal. @param index index of the current editor """ if index == -1 or not self.editors: return editor = self.activeWindow() if editor is None: return self._checkActions(editor) editor.setFocus() fn = editor.getFileName() if fn: self.changeCaption.emit(fn) if not self.__inRemoveView: self.editorChanged.emit(fn) self.editorLineChanged.emit( fn, editor.getCursorPosition()[0] + 1) else: self.changeCaption.emit("") self.editorChangedEd.emit(editor) cindex = self.editors.index(editor) self.viewlist.setCurrentRow(cindex) def eventFilter(self, watched, event): """ Public method called to filter the event queue. @param watched the QObject being watched @param event the event that occurred @return flag indicating, if we handled the event """ if event.type() == QEvent.MouseButtonPress and \ not event.button() == Qt.RightButton: switched = True if isinstance(watched, QStackedWidget): switched = watched is not self.currentStack self.currentStack = watched elif isinstance(watched, QScintilla.Editor.Editor): for stack in self.stacks: if stack.hasEditor(watched): switched = stack is not self.currentStack self.currentStack = stack break currentWidget = self.currentStack.currentWidget() if currentWidget: index = self.editors.index(currentWidget) self.viewlist.setCurrentRow(index) aw = self.activeWindow() if aw is not None: self._checkActions(aw) aw.setFocus() fn = aw.getFileName() if fn: self.changeCaption.emit(fn) if switched: self.editorChanged.emit(fn) self.editorLineChanged.emit( fn, aw.getCursorPosition()[0] + 1) else: self.changeCaption.emit("") self.editorChangedEd.emit(aw) return False