--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric6/QScintilla/EditorOutline.py Wed Sep 02 18:13:12 2020 +0200 @@ -0,0 +1,175 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2020 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing an outline widget for source code navigation of the editor. +""" + +from PyQt5.QtCore import Qt +from PyQt5.QtWidgets import QTreeView, QAbstractItemView + +from UI.BrowserSortFilterProxyModel import BrowserSortFilterProxyModel +from UI.BrowserModel import BrowserImportsItem, BrowserGlobalsItem + +from .EditorOutlineModel import EditorOutlineModel + + +# TODO: implement context menu +class EditorOutlineView(QTreeView): + """ + Class implementing an outline widget for source code navigation of the + editor. + """ + def __init__(self, editor, parent=None): + """ + Constructor + + @param editor reference to the editor widget + @type Editor + @param parent reference to the parent widget + @type QWidget + """ + super(EditorOutlineView, self).__init__(parent) + + self.__editor = editor + + self.__model = EditorOutlineModel(editor) + self.__sortModel = BrowserSortFilterProxyModel() + self.__sortModel.setSourceModel(self.__model) + self.setModel(self.__sortModel) + + self.setRootIsDecorated(True) + self.setAlternatingRowColors(True) + + header = self.header() + header.setSortIndicator(0, Qt.AscendingOrder) + header.setSortIndicatorShown(True) + header.setSectionsClickable(True) + + self.setSortingEnabled(True) + + self.setSelectionMode(QAbstractItemView.SingleSelection) + self.setSelectionBehavior(QAbstractItemView.SelectRows) + + self.activated.connect(self.__gotoItem) + self.expanded.connect(self.__resizeColumns) + self.collapsed.connect(self.__resizeColumns) + + self.__resizeColumns() + + self.__expandedNames = [] + self.__currentItemName = "" + + def __resizeColumns(self): + """ + Private slot to resize the view when items get expanded or collapsed. + """ + self.resizeColumnToContents(0) + + def isPopulated(self): + """ + Public method to check, if the model is populated. + + @return flag indicating a populated model + @rtype bool + """ + return self.__model.isPopulated() + + def repopulate(self): + """ + Public slot to repopulate the model. + """ + if self.isPopulated(): + self.__prepareRepopulate() + self.__model.repopulate() + self.__completeRepopulate() + + def __prepareRepopulate(self): + """ + Private slot to prepare to repopulate the outline view. + """ + itm = self.__currentItem() + if itm is not None: + self.__currentItemName = itm.data(0) + + self.__expandedNames = [] + + childIndex = self.model().index(0, 0) + while childIndex.isValid(): + if self.isExpanded(childIndex): + self.__expandedNames.append( + self.model().item(childIndex).data(0)) + childIndex = self.indexBelow(childIndex) + + def __completeRepopulate(self): + """ + Private slot to complete the repopulate of the outline view. + """ + childIndex = self.model().index(0, 0) + while childIndex.isValid(): + name = self.model().item(childIndex).data(0) + if (self.__currentItemName and self.__currentItemName == name): + self.setCurrentIndex(childIndex) + if name in self.__expandedNames: + self.setExpanded(childIndex, True) + childIndex = self.indexBelow(childIndex) + + self.__expandedNames = [] + self.__currentItemName = "" + + def isSupportedLanguage(self, language): + """ + Public method to check, if outlining a given language is supported. + + @param language source language to be checked + @type str + @return flag indicating support + @rtype bool + """ + return language in EditorOutlineModel.SupportedLanguages + + def __gotoItem(self, index): + """ + Private slot to set the editor cursor. + + @param index index of the item to set the cursor for + @type QModelIndex + """ + if index.isValid(): + itm = self.model().item(index) + if itm: + try: + lineno = itm.lineno() + self.__editor.gotoLine(lineno) + except AttributeError: + # don't care + pass + + def mouseDoubleClickEvent(self, mouseEvent): + """ + Protected method of QAbstractItemView. + + Reimplemented to disable expanding/collapsing of items when + double-clicking. Instead the double-clicked entry is opened. + + @param mouseEvent the mouse event (QMouseEvent) + """ + index = self.indexAt(mouseEvent.pos()) + if index.isValid(): + itm = self.model().item(index) + if isinstance(itm, (BrowserImportsItem, BrowserGlobalsItem)): + self.setExpanded(index, not self.isExpanded(index)) + else: + self.__gotoItem(index) + + def __currentItem(self): + """ + Private method to get a reference to the current item. + + @return reference to the current item + @rtype BrowserItem + """ + itm = self.model().item(self.currentIndex()) + return itm