Wed, 02 Sep 2020 19:57:37 +0200
Continued implementing the editor outline widget.
--- a/docs/changelog Wed Sep 02 18:13:12 2020 +0200 +++ b/docs/changelog Wed Sep 02 19:57:37 2020 +0200 @@ -1,5 +1,10 @@ Change Log ---------- +Version 20.10: +- bug fixes +- Editor + -- added an outline widget showing the structure of the editor source code + Version 20.9: - bug fixes - File Browser
--- a/eric6/QScintilla/EditorOutline.py Wed Sep 02 18:13:12 2020 +0200 +++ b/eric6/QScintilla/EditorOutline.py Wed Sep 02 19:57:37 2020 +0200 @@ -7,16 +7,22 @@ Module implementing an outline widget for source code navigation of the editor. """ -from PyQt5.QtCore import Qt -from PyQt5.QtWidgets import QTreeView, QAbstractItemView +from PyQt5.QtCore import Qt, QCoreApplication, QItemSelectionModel +from PyQt5.QtWidgets import QTreeView, QAbstractItemView, QMenu, QApplication from UI.BrowserSortFilterProxyModel import BrowserSortFilterProxyModel -from UI.BrowserModel import BrowserImportsItem, BrowserGlobalsItem +from UI.BrowserModel import ( + BrowserImportsItem, BrowserGlobalsItem, BrowserClassAttributeItem, + BrowserImportItem +) from .EditorOutlineModel import EditorOutlineModel -# TODO: implement context menu +# TODO: handle editor signal 'cursorLineChanged' +# TODO: handle editor signal 'languageChanged' +# TODO: handle editor signal 'refreshed' +# TODO: handle editor signal 'editorRenamed' class EditorOutlineView(QTreeView): """ Class implementing an outline widget for source code navigation of the @@ -33,8 +39,6 @@ """ super(EditorOutlineView, self).__init__(parent) - self.__editor = editor - self.__model = EditorOutlineModel(editor) self.__sortModel = BrowserSortFilterProxyModel() self.__sortModel.setSourceModel(self.__model) @@ -47,12 +51,17 @@ header.setSortIndicator(0, Qt.AscendingOrder) header.setSortIndicatorShown(True) header.setSectionsClickable(True) + self.setHeaderHidden(True) self.setSortingEnabled(True) self.setSelectionMode(QAbstractItemView.SingleSelection) self.setSelectionBehavior(QAbstractItemView.SelectRows) + self.setContextMenuPolicy(Qt.CustomContextMenu) + self.customContextMenuRequested.connect(self.__contextMenuRequested) + self.__createPopupMenus() + self.activated.connect(self.__gotoItem) self.expanded.connect(self.__resizeColumns) self.collapsed.connect(self.__resizeColumns) @@ -142,7 +151,7 @@ if itm: try: lineno = itm.lineno() - self.__editor.gotoLine(lineno) + self.__model.editor().gotoLine(lineno) except AttributeError: # don't care pass @@ -173,3 +182,133 @@ """ itm = self.model().item(self.currentIndex()) return itm + + ####################################################################### + ## Context menu methods below + ####################################################################### + + def __createPopupMenus(self): + """ + Private method to generate the various popup menus. + """ + # create the popup menu for general use + self.__menu = QMenu(self) + self.__menu.addAction( + QCoreApplication.translate('EditorOutlineView', 'Goto'), + self.__goto) + self.__menu.addSeparator() + self.__menu.addAction( + QCoreApplication.translate('EditorOutlineView', 'Refresh'), + self.repopulate) + self.__menu.addSeparator() + self.__menu.addAction( + QCoreApplication.translate( + 'EditorOutlineView', 'Copy Path to Clipboard'), + self.__copyToClipboard) + + # create the attribute/import menu + self.__gotoMenu = QMenu( + QCoreApplication.translate('EditorOutlineView', "Goto"), + self) + self.__gotoMenu.aboutToShow.connect(self.__showGotoMenu) + self.__gotoMenu.triggered.connect(self.__gotoAttribute) + + self.__attributeMenu = QMenu(self) + self.__attributeMenu.addMenu(self.__gotoMenu) + self.__attributeMenu.addSeparator() + self.__attributeMenu.addAction( + QCoreApplication.translate('EditorOutlineView', 'Refresh'), + self.repopulate) + self.__attributeMenu.addSeparator() + self.__attributeMenu.addAction( + QCoreApplication.translate( + 'EditorOutlineView', 'Copy Path to Clipboard'), + self.__copyToClipboard) + + # create the background menu + self.__backMenu = QMenu(self) + self.__backMenu.addAction( + QCoreApplication.translate('EditorOutlineView', 'Refresh'), + self.repopulate) + self.__backMenu.addSeparator() + self.__backMenu.addAction( + QCoreApplication.translate( + 'EditorOutlineView', 'Copy Path to Clipboard'), + self.__copyToClipboard) + + def __contextMenuRequested(self, coord): + """ + Private slot to show the context menu. + + @param coord position of the mouse pointer + @type QPoint + """ + coord = self.mapToGlobal(coord) + index = self.indexAt(coord) + + if index.isValid(): + self.setCurrentIndex(index) + flags = QItemSelectionModel.SelectionFlags( + QItemSelectionModel.ClearAndSelect | + QItemSelectionModel.Rows) + self.selectionModel().select(index, flags) + + itm = self.model().item(index) + if isinstance( + itm, (BrowserClassAttributeItem, BrowserImportItem) + ): + self.__attributeMenu.popup(coord) + else: + self.__menu.popup(coord) + else: + self.__backMenu.popup(coord) + + def __showGotoMenu(self): + """ + Private slot to prepare the goto submenu of the attribute menu. + """ + self.__gotoMenu.clear() + + itm = self.model().item(self.currentIndex()) + try: + linenos = itm.linenos() + except AttributeError: + try: + linenos = [itm.lineno()] + except AttributeError: + return + + for lineno in sorted(linenos): + act = self.__gotoMenu.addAction( + QCoreApplication.translate( + 'EditorOutlineView', "Line {0}").format(lineno)) + act.setData(lineno) + + ####################################################################### + ## Context menu handlers below + ####################################################################### + + def __gotoAttribute(self, act): + """ + Private slot to handle the selection of the goto menu. + + @param act reference to the action (E5Action) + """ + lineno = act.data() + self.__model.editor().gotoLine(lineno) + + def __goto(self): + """ + Private slot to move the editor cursor to the line of the context item. + """ + self.__gotoItem(self.currentIndex()) + + def __copyToClipboard(self): + """ + Private slot to copy the file name of the editor to the clipboard. + """ + fn = self.__model.fileName() + + if fn: + cb = QApplication.clipboard() + cb.setText(fn)
--- a/eric6/QScintilla/EditorOutlineModel.py Wed Sep 02 18:13:12 2020 +0200 +++ b/eric6/QScintilla/EditorOutlineModel.py Wed Sep 02 19:57:37 2020 +0200 @@ -36,9 +36,6 @@ self.__editor = editor - self.__filename = self.__editor.getFileName() - self.__module = os.path.basename(self.__filename) - self.__populated = False rootData = QCoreApplication.translate("EditorOutlineModel", "Name") @@ -53,6 +50,9 @@ @param repopulate flag indicating a repopulation @type bool """ + self.__filename = self.__editor.getFileName() + self.__module = os.path.basename(self.__filename) + language = self.__editor.getLanguage() if language in EditorOutlineModel.SupportedLanguages: if language in ("Python3", "MicroPython"): @@ -145,3 +145,21 @@ """ self.clear() self.__populateModel(repopulate=True) + + def editor(self): + """ + Public method to retrieve a reference to the editor. + + @return reference to the editor + @rtype Editor + """ + return self.__editor + + def fileName(self): + """ + Public method to retrieve the file name of the editor. + + @return file name of the editor + @rtype str + """ + return self.__filename