Tue, 15 Nov 2022 11:06:27 +0100
Started refactoring of the project browser related code in order to extract some as plugins later on.
# -*- coding: utf-8 -*- # Copyright (c) 2002 - 2022 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing the project browser part of the eric UI. """ from PyQt6.QtCore import Qt, pyqtSignal from PyQt6.QtGui import QColor from PyQt6.QtWidgets import QApplication from eric7 import Preferences from eric7.EricGui import EricPixmapCache from eric7.EricWidgets.EricLed import EricClickableLed from eric7.EricWidgets.EricTabWidget import EricTabWidget from .ProjectBrowserFlags import ( AllBrowsersFlag, FormsBrowserFlag, InterfacesBrowserFlag, OthersBrowserFlag, ProtocolsBrowserFlag, ResourcesBrowserFlag, SourcesBrowserFlag, TranslationsBrowserFlag, ) from .ProjectFormsBrowser import ProjectFormsBrowser from .ProjectInterfacesBrowser import ProjectInterfacesBrowser from .ProjectOthersBrowser import ProjectOthersBrowser from .ProjectProtocolsBrowser import ProjectProtocolsBrowser from .ProjectResourcesBrowser import ProjectResourcesBrowser from .ProjectSourcesBrowser import ProjectSourcesBrowser from .ProjectTranslationsBrowser import ProjectTranslationsBrowser class ProjectBrowser(EricTabWidget): """ Class implementing the project browser part of the eric UI. It generates a widget with up to seven tabs. The individual tabs contain the project sources browser, the project forms browser, the project resources browser, the project translations browser, the project interfaces (IDL) browser and a browser for stuff, that doesn't fit these categories. Optionally it contains an additional tab with the file system browser. Note: The following signals are defined here to proxy the individual browser signals. @signal appendStderr(str) emitted after something was received from a QProcess on stderr @signal appendStdout(str) emitted after something was received from a QProcess on stdout @signal binaryFile(filename) emitted to open a file as binary (str) @signal closeSourceWindow(str) emitted to close a source file @signal designerFile(filename) emitted to open a Qt-Designer file (str) @signal linguistFile(filename) emitted to open a Qt-Linguist (*.ts) file (str) @signal pixmapEditFile(filename) emitted to edit a pixmap file (str) @signal pixmapFile(filename) emitted to open a pixmap file (str) @signal preferencesChanged() emitted when the preferences have been changed @signal sourceFile(filename) emitted to open a Python file at a line (str) @signal sourceFile(filename, lineno) emitted to open a Python file at a line (str, int) @signal sourceFile(filename, lineno, type) emitted to open a Python file at a line giving an explicit file type (str, int, str) @signal sourceFile(filename, linenos) emitted to open a Python file giving a list of lines(str, list) @signal svgFile(filename) emitted to open a SVG file (str) @signal testFile(filename) emitted to open a Python file for a unit test (str) @signal trpreview(filenames) emitted to preview Qt-Linguist (*.qm) files (list of str) @signal trpreview(filenames, ignore) emitted to preview Qt-Linguist (*.qm) files indicating whether non-existent files shall be ignored (list of str, bool) @signal uipreview(str) emitted to preview a forms file @signal umlFile(filename) emitted to open an eric UML file (str) """ appendStderr = pyqtSignal(str) appendStdout = pyqtSignal(str) binaryFile = pyqtSignal(str) closeSourceWindow = pyqtSignal(str) designerFile = pyqtSignal(str) linguistFile = pyqtSignal(str) pixmapEditFile = pyqtSignal(str) pixmapFile = pyqtSignal(str) preferencesChanged = pyqtSignal() sourceFile = pyqtSignal((str,), (str, int), (str, list), (str, int, str)) svgFile = pyqtSignal(str) testFile = pyqtSignal(str) trpreview = pyqtSignal((list,), (list, bool)) uipreview = pyqtSignal(str) umlFile = pyqtSignal(str) def __init__(self, project, parent=None): """ Constructor @param project reference to the project object @param parent parent widget (QWidget) """ EricTabWidget.__init__(self, parent) self.project = project self.setWindowIcon(EricPixmapCache.getIcon("eric")) self.setUsesScrollButtons(True) self.vcsStatusIndicator = EricClickableLed(self) self.setCornerWidget(self.vcsStatusIndicator, Qt.Corner.TopLeftCorner) self.vcsStatusIndicator.clicked.connect(self.__vcsStatusIndicatorClicked) self.vcsStatusColorNames = { "A": "VcsAdded", "M": "VcsModified", "O": "VcsRemoved", "R": "VcsReplaced", "U": "VcsUpdate", "Z": "VcsConflict", } self.vcsStatusText = { " ": self.tr("up to date"), "A": self.tr("files added"), "M": self.tr("local modifications"), "O": self.tr("files removed"), "R": self.tr("files replaced"), "U": self.tr("update required"), "Z": self.tr("conflict"), } self.__vcsStateChanged(" ") # create all the individual browsers self.__browsers = { # sources browser "sources": ProjectSourcesBrowser(self.project, self), # forms browser "forms": ProjectFormsBrowser(self.project, self), # resources browser "resources": ProjectResourcesBrowser(self.project, self), # translations browser "translations": ProjectTranslationsBrowser(self.project, self), # others browser "others": ProjectOthersBrowser(self.project, self), # interfaces (IDL) browser "interfaces": ProjectInterfacesBrowser(self.project, self), # protocols (protobuf) browser "protocols": ProjectProtocolsBrowser(self.project, self), } # add signal connection to ourselves self.project.projectOpened.connect(self.__projectOpened) self.project.projectClosed.connect(self.__projectClosed) self.project.newProject.connect(self.__newProject) self.project.projectPropertiesChanged.connect(self.__projectPropertiesChanged) self.currentChanged.connect(self.__currentChanged) self.project.getModel().vcsStateChanged.connect(self.__vcsStateChanged) self.__currentBrowsersFlags = 0 self.__projectPropertiesChanged() self.setCurrentIndex(0) def __setBrowsersAvailable(self, browserFlags): """ Private method to add selected browsers to the project browser. @param browserFlags flags indicating the browsers to add (integer) """ # step 1: remove all tabs while self.count() > 0: self.removeTab(0) # step 2: add browsers if browserFlags & SourcesBrowserFlag: index = self.addTab( self.__browsers["sources"], EricPixmapCache.getIcon("projectSources"), "", ) self.setTabToolTip(index, self.__browsers["sources"].windowTitle()) if browserFlags & FormsBrowserFlag: index = self.addTab( self.__browsers["forms"], EricPixmapCache.getIcon("projectForms"), "" ) self.setTabToolTip(index, self.__browsers["forms"].windowTitle()) if browserFlags & ResourcesBrowserFlag: index = self.addTab( self.__browsers["resources"], EricPixmapCache.getIcon("projectResources"), "", ) self.setTabToolTip(index, self.__browsers["resources"].windowTitle()) if browserFlags & TranslationsBrowserFlag: index = self.addTab( self.__browsers["translations"], EricPixmapCache.getIcon("projectTranslations"), "", ) self.setTabToolTip(index, self.__browsers["translations"].windowTitle()) if browserFlags & InterfacesBrowserFlag: index = self.addTab( self.__browsers["interfaces"], EricPixmapCache.getIcon("projectInterfaces"), "", ) self.setTabToolTip(index, self.__browsers["interfaces"].windowTitle()) if browserFlags & ProtocolsBrowserFlag: index = self.addTab( self.__browsers["protocols"], EricPixmapCache.getIcon("protobuf"), "" ) self.setTabToolTip(index, self.__browsers["protocols"].windowTitle()) if browserFlags & OthersBrowserFlag: index = self.addTab( self.__browsers["others"], EricPixmapCache.getIcon("projectOthers"), "" ) self.setTabToolTip(index, self.__browsers["others"].windowTitle()) QApplication.processEvents() def __currentChanged(self, index): """ Private slot to handle the currentChanged(int) signal. @param index index of the tab (integer) """ if index > -1: browser = self.widget(index) if browser is not None: browser.layoutDisplay() def __projectOpened(self): """ Private slot to handle the projectOpened signal. """ self.__projectPropertiesChanged() self.setCurrentIndex(0) self.__vcsStateChanged(" ") def __projectClosed(self): """ Private slot to handle the projectClosed signal. """ self.__projectPropertiesChanged() self.setCurrentIndex(0) self.__setSourcesIcon() self.__vcsStateChanged(" ") def __newProject(self): """ Private slot to handle the newProject signal. """ self.setCurrentIndex(0) self.__projectPropertiesChanged() def __projectPropertiesChanged(self): """ Private slot to handle the projectPropertiesChanged signal. """ flags = ( Preferences.getProjectBrowserFlags(self.project.getProjectType()) if self.project.isOpen() else AllBrowsersFlag ) if flags != self.__currentBrowsersFlags: self.__currentBrowsersFlags = flags self.__setBrowsersAvailable(flags) endIndex = self.count() for index in range(endIndex): self.setTabEnabled(index, self.project.isOpen()) self.__setSourcesIcon() def __setSourcesIcon(self): """ Private method to set the right icon for the sources browser tab. """ if not self.project.isOpen(): icon = EricPixmapCache.getIcon("projectSources") else: if self.project.getProjectLanguage() == "Python3": if self.project.isMixedLanguageProject(): icon = EricPixmapCache.getIcon("projectSourcesPyMixed") else: icon = EricPixmapCache.getIcon("projectSourcesPy") elif self.project.getProjectLanguage() == "MicroPython": icon = EricPixmapCache.getIcon("micropython") elif self.project.getProjectLanguage() == "Ruby": if self.project.isMixedLanguageProject(): icon = EricPixmapCache.getIcon("projectSourcesRbMixed") else: icon = EricPixmapCache.getIcon("projectSourcesRb") elif self.project.getProjectLanguage() == "JavaScript": icon = EricPixmapCache.getIcon("projectSourcesJavaScript") else: icon = EricPixmapCache.getIcon("projectSources") self.setTabIcon(self.indexOf(self.__browsers["sources"]), icon) def handleEditorChanged(self, fn): """ Public slot to handle the editorChanged signal. @param fn filename of the changed file (string) """ if Preferences.getProject("FollowEditor"): if self.project.isProjectSource(fn): self.__browsers["sources"].selectFile(fn) elif self.project.isProjectForm(fn): self.__browsers["forms"].selectFile(fn) elif self.project.isProjectResource(fn): self.__browsers["resources"].selectFile(fn) elif self.project.isProjectInterface(fn): self.__browsers["interfaces"].selectFile(fn) elif self.project.isProjectProtocol(fn): self.__browsers["protocols"].selectFile(fn) def handleEditorLineChanged(self, fn, lineno): """ Public slot to handle the editorLineChanged signal. @param fn filename of the changed file (string) @param lineno one based line number of the item (integer) """ if ( Preferences.getProject("FollowEditor") and Preferences.getProject("FollowCursorLine") and self.project.isProjectSource(fn) ): self.__browsers["sources"].selectFileLine(fn, lineno) def getProjectBrowsers(self): """ Public method to get references to the individual project browsers. @return list of references to project browsers @rtype list of ProjectBaseBrowser """ return list(self.__browsers.items()) def getProjectBrowser(self, name): """ Public method to get a reference to the named project browser. @param name name of the requested project browser. @type str @return reference to the requested browser or None @rtype ProjectBaseBrowser or None """ return self.__browsers.get(name, None) def getProjectBrowserNames(self): """ Public method to get the names of the various project browsers. @return list of project browser names @rtype list of str """ return list(self.__browsers.keys()) def handlePreferencesChanged(self): """ Public slot used to handle the preferencesChanged signal. """ self.__projectPropertiesChanged() self.__vcsStateChanged(self.currentVcsStatus) self.preferencesChanged.emit() # propagate the signal to the browsers def __vcsStateChanged(self, state): """ Private slot to handle a change in the vcs state. @param state new vcs state (string) """ self.currentVcsStatus = state if state == " " or state not in self.vcsStatusColorNames: self.vcsStatusIndicator.setColor(QColor(Qt.GlobalColor.lightGray)) else: self.vcsStatusIndicator.setColor( Preferences.getProjectBrowserColour(self.vcsStatusColorNames[state]) ) if state not in self.vcsStatusText: self.vcsStatusIndicator.setToolTip(self.tr("unknown status")) else: self.vcsStatusIndicator.setToolTip(self.vcsStatusText[state]) def __vcsStatusIndicatorClicked(self, pos): """ Private slot to react upon clicks on the VCS indicator LED. @param pos position of the click (QPoint) """ vcs = self.project.getVcs() if vcs: if self.currentVcsStatus == " ": # call log browser dialog vcs.vcsLogBrowser(self.project.getProjectPath()) else: # call status dialog vcs.vcsStatus(self.project.getProjectPath())