Continued implementing the editor outline widget.

Wed, 02 Sep 2020 19:57:37 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Wed, 02 Sep 2020 19:57:37 +0200
changeset 7686
379d402162ca
parent 7685
0b6e8c0d6403
child 7687
4d372f1354d6

Continued implementing the editor outline widget.

docs/changelog file | annotate | diff | comparison | revisions
eric6/QScintilla/EditorOutline.py file | annotate | diff | comparison | revisions
eric6/QScintilla/EditorOutlineModel.py file | annotate | diff | comparison | revisions
--- 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

eric ide

mercurial