--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ExtensionProtobuf/ProjectProtocolsBrowser.py Sun Dec 04 14:32:07 2022 +0100 @@ -0,0 +1,838 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2017 - 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the a class used to display the protocols (protobuf) part +of the project. +""" + +import contextlib +import functools +import glob +import os + +from PyQt6.QtCore import QProcess, QThread, pyqtSignal +from PyQt6.QtWidgets import QApplication, QDialog, QMenu + +from eric7 import Globals, Preferences, Utilities +from eric7.EricGui import EricPixmapCache +from eric7.EricWidgets import EricMessageBox +from eric7.EricWidgets.EricApplication import ericApp +from eric7.EricWidgets.EricProgressDialog import EricProgressDialog +from eric7.Project.FileCategoryRepositoryItem import FileCategoryRepositoryItem +from eric7.Project.ProjectBaseBrowser import ProjectBaseBrowser +from eric7.Project.ProjectBrowserModel import ( + ProjectBrowserDirectoryItem, + ProjectBrowserFileItem, + ProjectBrowserSimpleDirectoryItem, +) +from eric7.Project.ProjectBrowserRepositoryItem import ProjectBrowserRepositoryItem +from eric7.UI.BrowserModel import ( + BrowserClassAttributeItem, + BrowserClassItem, + BrowserFileItem, + BrowserMethodItem, +) +from eric7.UI.DeleteFilesConfirmationDialog import DeleteFilesConfirmationDialog +from eric7.UI.NotificationWidget import NotificationTypes + + +class ProjectProtocolsBrowser(ProjectBaseBrowser): + """ + A class used to display the protocols (protobuf) part of the project. + + @signal appendStdout(str) emitted after something was received from + a QProcess on stdout + @signal appendStderr(str) emitted after something was received from + a QProcess on stderr + @signal showMenu(str, QMenu) emitted when a menu is about to be shown. + The name of the menu and a reference to the menu are given. + """ + + appendStdout = pyqtSignal(str) + appendStderr = pyqtSignal(str) + showMenu = pyqtSignal(str, QMenu) + + FileFilter = "proto" + + def __init__(self, plugin, parent=None): + """ + Constructor + + @param plugin reference to the plugin object + @type ProtobufExtensionPlugin + @param parent parent widget of this browser + @type QWidget + """ + project = ericApp().getObject("Project") + projectBrowser = ericApp().getObject("ProjectBrowser") + + ProjectBaseBrowser.__init__(self, project, self.FileFilter, parent) + + self.selectedItemsFilter = [ + ProjectBrowserFileItem, + ProjectBrowserSimpleDirectoryItem, + ] + + self.setWindowTitle(self.tr("Protocols (protobuf)")) + + self.setWhatsThis( + self.tr( + """<b>Project Protocols Browser</b>""" + """<p>This allows to easily see all protocols (protobuf files)""" + """ contained in the current project. Several actions can be""" + """ executed via the context menu.</p>""" + ) + ) + + self.__plugin = plugin + + # Add the file category handled by the browser. + project.addFileCategory( + "PROTOCOLS", + FileCategoryRepositoryItem( + fileCategoryFilterTemplate=self.tr("Protobuf Files ({0})"), + fileCategoryUserString=self.tr("Protobuf Files"), + fileCategoryTyeString=self.tr("Protobuf Files"), + fileCategoryExtensions=["*.proto"], + ), + ) + + # Add the project browser type to the browser type repository. + projectBrowser.addTypedProjectBrowser( + "protocols", + ProjectBrowserRepositoryItem( + projectBrowser=self, + projectBrowserUserString=self.tr("Protocols (protobuf) Browser"), + priority=50, + fileCategory="PROTOCOLS", + fileFilter=self.FileFilter, + getIcon=self.getIcon, + ), + ) + + # Connect signals of Project. + project.prepareRepopulateItem.connect(self._prepareRepopulateItem) + project.completeRepopulateItem.connect(self._completeRepopulateItem) + project.projectClosed.connect(self._projectClosed) + project.projectOpened.connect(self._projectOpened) + project.newProject.connect(self._newProject) + project.reinitVCS.connect(self._initMenusAndVcs) + project.projectPropertiesChanged.connect(self._initMenusAndVcs) + + # Connect signals of ProjectBrowser. + projectBrowser.preferencesChanged.connect(self.handlePreferencesChanged) + + # Connect some of our own signals. + self.appendStderr.connect(projectBrowser.appendStderr) + self.appendStdout.connect(projectBrowser.appendStdout) + self.closeSourceWindow.connect(projectBrowser.closeSourceWindow) + self.sourceFile[str].connect(projectBrowser.sourceFile[str]) + self.sourceFile[str, int].connect(projectBrowser.sourceFile[str, int]) + + def deactivate(self): + """ + Public method to deactivate the browser. + """ + project = ericApp().getObject("Project") + projectBrowser = ericApp().getObject("ProjectBrowser") + + # Disconnect some of our own signals. + self.appendStderr.disconnect(projectBrowser.appendStderr) + self.appendStdout.disconnect(projectBrowser.appendStdout) + self.closeSourceWindow.disconnect(projectBrowser.closeSourceWindow) + self.sourceFile[str].disconnect(projectBrowser.sourceFile[str]) + self.sourceFile[str, int].disconnect(projectBrowser.sourceFile[str, int]) + + # Disconnect signals of ProjectBrowser. + projectBrowser.preferencesChanged.disconnect(self.handlePreferencesChanged) + + # Disconnect signals of Project. + project.prepareRepopulateItem.disconnect(self._prepareRepopulateItem) + project.completeRepopulateItem.disconnect(self._completeRepopulateItem) + project.projectClosed.disconnect(self._projectClosed) + project.projectOpened.disconnect(self._projectOpened) + project.newProject.disconnect(self._newProject) + project.reinitVCS.disconnect(self._initMenusAndVcs) + project.projectPropertiesChanged.disconnect(self._initMenusAndVcs) + + # Remove the project browser type from the browser type repository. + projectBrowser.removeTypedProjectBrowser("protocols") + + # Remove the file category handled by the browser. + project.removeFileCategory("PROTOCOLS") + + def getIcon(self): + """ + Public method to get an icon for the project browser. + + @return icon for the browser + @rtype QIcon + """ + return EricPixmapCache.getIcon( + os.path.join(os.path.dirname(__file__), "icons", "protobuf") + ) + + def _createPopupMenus(self): + """ + Protected overloaded method to generate the popup menu. + """ + self.menuActions = [] + self.multiMenuActions = [] + self.dirMenuActions = [] + self.dirMultiMenuActions = [] + + self.sourceMenu = QMenu(self) + self.sourceMenu.addAction(self.tr("Compile protocol"), self.__compileProtocol) + self.sourceMenu.addAction( + self.tr("Compile all protocols"), self.__compileAllProtocols + ) + self.sourceMenu.addSeparator() + self.sourceMenu.addAction( + self.tr("Compile protocol as gRPC"), + functools.partial(self.__compileProtocol, grpc=True), + ) + self.sourceMenu.addAction( + self.tr("Compile all protocols as gRPC"), + functools.partial(self.__compileAllProtocols, grpc=True), + ) + self.sourceMenu.addSeparator() + self.sourceMenu.addAction(self.tr("Open"), self._openItem) + self.sourceMenu.addSeparator() + act = self.sourceMenu.addAction(self.tr("Rename file"), self._renameFile) + self.menuActions.append(act) + act = self.sourceMenu.addAction( + self.tr("Remove from project"), self._removeFile + ) + self.menuActions.append(act) + act = self.sourceMenu.addAction(self.tr("Delete"), self.__deleteFile) + self.menuActions.append(act) + self.sourceMenu.addSeparator() + self.sourceMenu.addAction(self.tr("Add protocols..."), self.__addProtocolFiles) + self.sourceMenu.addAction( + self.tr("Add protocols directory..."), self.__addProtocolsDirectory + ) + self.sourceMenu.addSeparator() + self.sourceMenu.addAction( + self.tr("Copy Path to Clipboard"), self._copyToClipboard + ) + self.sourceMenu.addSeparator() + self.sourceMenu.addAction( + self.tr("Expand all directories"), self._expandAllDirs + ) + self.sourceMenu.addAction( + self.tr("Collapse all directories"), self._collapseAllDirs + ) + self.sourceMenu.addSeparator() + self.sourceMenu.addAction(self.tr("Configure..."), self._configure) + self.sourceMenu.addAction( + self.tr("Configure Protobuf..."), self.__configureProtobuf + ) + + self.menu = QMenu(self) + self.menu.addAction(self.tr("Compile protocol"), self.__compileProtocol) + self.menu.addAction( + self.tr("Compile all protocols"), self.__compileAllProtocols + ) + self.menu.addSeparator() + self.menu.addAction( + self.tr("Compile protocol as gRPC"), + functools.partial(self.__compileProtocol, grpc=True), + ) + self.menu.addAction( + self.tr("Compile all protocols as gRPC"), + functools.partial(self.__compileAllProtocols, grpc=True), + ) + self.menu.addSeparator() + self.menu.addAction(self.tr("Open"), self._openItem) + self.menu.addSeparator() + self.menu.addAction(self.tr("Add protocols..."), self.__addProtocolFiles) + self.menu.addAction( + self.tr("Add protocols directory..."), self.__addProtocolsDirectory + ) + self.menu.addSeparator() + self.menu.addAction(self.tr("Expand all directories"), self._expandAllDirs) + self.menu.addAction(self.tr("Collapse all directories"), self._collapseAllDirs) + self.menu.addSeparator() + self.menu.addAction(self.tr("Configure..."), self._configure) + self.menu.addAction(self.tr("Configure Protobuf..."), self.__configureProtobuf) + + self.backMenu = QMenu(self) + self.backMenu.addAction( + self.tr("Compile all protocols"), self.__compileAllProtocols + ) + self.backMenu.addSeparator() + self.backMenu.addAction( + self.tr("Compile all protocols as gRPC"), + functools.partial(self.__compileAllProtocols, grpc=True), + ) + self.backMenu.addSeparator() + self.backMenu.addAction( + self.tr("Add protocols..."), lambda: self.project.addFiles("PROTOCOLS") + ) + self.backMenu.addAction( + self.tr("Add protocols directory..."), + lambda: self.project.addDirectory("PROTOCOLS"), + ) + self.backMenu.addSeparator() + self.backMenu.addAction(self.tr("Expand all directories"), self._expandAllDirs) + self.backMenu.addAction( + self.tr("Collapse all directories"), self._collapseAllDirs + ) + self.backMenu.addSeparator() + self.backMenu.addAction(self.tr("Configure..."), self._configure) + self.backMenu.addAction( + self.tr("Configure Protobuf..."), self.__configureProtobuf + ) + self.backMenu.setEnabled(False) + + # create the menu for multiple selected files + self.multiMenu = QMenu(self) + self.multiMenu.addAction( + self.tr("Compile protocols"), self.__compileSelectedProtocols + ) + self.multiMenu.addSeparator() + self.multiMenu.addAction( + self.tr("Compile protocols as gRPC"), + functools.partial(self.__compileSelectedProtocols, grpc=True), + ) + self.multiMenu.addSeparator() + self.multiMenu.addAction(self.tr("Open"), self._openItem) + self.multiMenu.addSeparator() + act = self.multiMenu.addAction(self.tr("Remove from project"), self._removeFile) + self.multiMenuActions.append(act) + act = self.multiMenu.addAction(self.tr("Delete"), self.__deleteFile) + self.multiMenuActions.append(act) + self.multiMenu.addSeparator() + self.multiMenu.addAction(self.tr("Expand all directories"), self._expandAllDirs) + self.multiMenu.addAction( + self.tr("Collapse all directories"), self._collapseAllDirs + ) + self.multiMenu.addSeparator() + self.multiMenu.addAction(self.tr("Configure..."), self._configure) + self.multiMenu.addAction( + self.tr("Configure Protobuf..."), self.__configureProtobuf + ) + + self.dirMenu = QMenu(self) + self.dirMenu.addAction( + self.tr("Compile all protocols"), self.__compileAllProtocols + ) + self.dirMenu.addSeparator() + self.dirMenu.addAction( + self.tr("Compile all protocols as gRPC"), + functools.partial(self.__compileAllProtocols, grpc=True), + ) + act = self.dirMenu.addAction(self.tr("Remove from project"), self._removeFile) + self.dirMenuActions.append(act) + act = self.dirMenu.addAction(self.tr("Delete"), self._deleteDirectory) + self.dirMenuActions.append(act) + self.dirMenu.addSeparator() + self.dirMenu.addAction(self.tr("Add protocols..."), self.__addProtocolFiles) + self.dirMenu.addAction( + self.tr("Add protocols directory..."), self.__addProtocolsDirectory + ) + self.dirMenu.addSeparator() + self.dirMenu.addAction(self.tr("Copy Path to Clipboard"), self._copyToClipboard) + self.dirMenu.addSeparator() + self.dirMenu.addAction(self.tr("Expand all directories"), self._expandAllDirs) + self.dirMenu.addAction( + self.tr("Collapse all directories"), self._collapseAllDirs + ) + self.dirMenu.addSeparator() + self.dirMenu.addAction(self.tr("Configure..."), self._configure) + self.dirMenu.addAction( + self.tr("Configure Protobuf..."), self.__configureProtobuf + ) + + self.dirMultiMenu = QMenu(self) + self.dirMultiMenu.addAction( + self.tr("Compile all protocols"), self.__compileAllProtocols + ) + self.dirMultiMenu.addSeparator() + self.dirMultiMenu.addAction( + self.tr("Compile all protocols as gRPC"), + functools.partial(self.__compileAllProtocols, grpc=True), + ) + self.dirMultiMenu.addAction( + self.tr("Add protocols..."), lambda: self.project.addFiles("PROTOCOLS") + ) + self.dirMultiMenu.addAction( + self.tr("Add protocols directory..."), + lambda: self.project.addDirectory("PROTOCOLS"), + ) + self.dirMultiMenu.addSeparator() + self.dirMultiMenu.addAction( + self.tr("Expand all directories"), self._expandAllDirs + ) + self.dirMultiMenu.addAction( + self.tr("Collapse all directories"), self._collapseAllDirs + ) + self.dirMultiMenu.addSeparator() + self.dirMultiMenu.addAction(self.tr("Configure..."), self._configure) + self.dirMultiMenu.addAction( + self.tr("Configure Protobuf..."), self.__configureProtobuf + ) + + self.sourceMenu.aboutToShow.connect(self.__showContextMenu) + self.multiMenu.aboutToShow.connect(self.__showContextMenuMulti) + self.dirMenu.aboutToShow.connect(self.__showContextMenuDir) + self.dirMultiMenu.aboutToShow.connect(self.__showContextMenuDirMulti) + self.backMenu.aboutToShow.connect(self.__showContextMenuBack) + self.mainMenu = self.sourceMenu + + def _contextMenuRequested(self, coord): + """ + Protected slot to show the context menu. + + @param coord the position of the mouse pointer (QPoint) + """ + if not self.project.isOpen(): + return + + with contextlib.suppress(Exception): # secok + categories = self.getSelectedItemsCountCategorized( + [ + ProjectBrowserFileItem, + BrowserClassItem, + BrowserMethodItem, + ProjectBrowserSimpleDirectoryItem, + ] + ) + cnt = categories["sum"] + if cnt <= 1: + index = self.indexAt(coord) + if index.isValid(): + self._selectSingleItem(index) + categories = self.getSelectedItemsCountCategorized( + [ + ProjectBrowserFileItem, + BrowserClassItem, + BrowserMethodItem, + ProjectBrowserSimpleDirectoryItem, + ] + ) + cnt = categories["sum"] + + bfcnt = categories[str(ProjectBrowserFileItem)] + cmcnt = ( + categories[str(BrowserClassItem)] + categories[str(BrowserMethodItem)] + ) + sdcnt = categories[str(ProjectBrowserSimpleDirectoryItem)] + if cnt > 1 and cnt == bfcnt: + self.multiMenu.popup(self.mapToGlobal(coord)) + elif cnt > 1 and cnt == sdcnt: + self.dirMultiMenu.popup(self.mapToGlobal(coord)) + else: + index = self.indexAt(coord) + if cnt == 1 and index.isValid(): + if bfcnt == 1 or cmcnt == 1: + itm = self.model().item(index) + if isinstance(itm, ProjectBrowserFileItem): + self.sourceMenu.popup(self.mapToGlobal(coord)) + elif isinstance(itm, (BrowserClassItem, BrowserMethodItem)): + self.menu.popup(self.mapToGlobal(coord)) + else: + self.backMenu.popup(self.mapToGlobal(coord)) + elif sdcnt == 1: + self.dirMenu.popup(self.mapToGlobal(coord)) + else: + self.backMenu.popup(self.mapToGlobal(coord)) + else: + self.backMenu.popup(self.mapToGlobal(coord)) + + def __showContextMenu(self): + """ + Private slot called by the menu aboutToShow signal. + """ + ProjectBaseBrowser._showContextMenu(self, self.menu) + + self.showMenu.emit("Main", self.menu) + + def __showContextMenuMulti(self): + """ + Private slot called by the multiMenu aboutToShow signal. + """ + ProjectBaseBrowser._showContextMenuMulti(self, self.multiMenu) + + self.showMenu.emit("MainMulti", self.multiMenu) + + def __showContextMenuDir(self): + """ + Private slot called by the dirMenu aboutToShow signal. + """ + ProjectBaseBrowser._showContextMenuDir(self, self.dirMenu) + + self.showMenu.emit("MainDir", self.dirMenu) + + def __showContextMenuDirMulti(self): + """ + Private slot called by the dirMultiMenu aboutToShow signal. + """ + ProjectBaseBrowser._showContextMenuDirMulti(self, self.dirMultiMenu) + + self.showMenu.emit("MainDirMulti", self.dirMultiMenu) + + def __showContextMenuBack(self): + """ + Private slot called by the backMenu aboutToShow signal. + """ + ProjectBaseBrowser._showContextMenuBack(self, self.backMenu) + + self.showMenu.emit("MainBack", self.backMenu) + + def _openItem(self): + """ + Protected slot to handle the open popup menu entry. + """ + itmList = self.getSelectedItems( + [ + BrowserFileItem, + BrowserClassItem, + BrowserMethodItem, + BrowserClassAttributeItem, + ] + ) + + for itm in itmList: + if isinstance(itm, BrowserFileItem): + self.sourceFile[str].emit(itm.fileName()) + elif isinstance(itm, BrowserClassItem): + self.sourceFile[str, int].emit(itm.fileName(), itm.classObject().lineno) + elif isinstance(itm, BrowserMethodItem): + self.sourceFile[str, int].emit( + itm.fileName(), itm.functionObject().lineno + ) + elif isinstance(itm, BrowserClassAttributeItem): + self.sourceFile[str, int].emit( + itm.fileName(), itm.attributeObject().lineno + ) + + def __addProtocolFiles(self): + """ + Private method to add protocol files to the project. + """ + itm = self.model().item(self.currentIndex()) + if isinstance( + itm, (ProjectBrowserFileItem, BrowserClassItem, BrowserMethodItem) + ): + dn = os.path.dirname(itm.fileName()) + elif isinstance( + itm, (ProjectBrowserSimpleDirectoryItem, ProjectBrowserDirectoryItem) + ): + dn = itm.dirName() + else: + dn = None + self.project.addFiles("protocol", dn) + + def __addProtocolsDirectory(self): + """ + Private method to add protocol files of a directory to the project. + """ + itm = self.model().item(self.currentIndex()) + if isinstance( + itm, (ProjectBrowserFileItem, BrowserClassItem, BrowserMethodItem) + ): + dn = os.path.dirname(itm.fileName()) + elif isinstance( + itm, (ProjectBrowserSimpleDirectoryItem, ProjectBrowserDirectoryItem) + ): + dn = itm.dirName() + else: + dn = None + self.project.addDirectory("protocol", dn) + + def __deleteFile(self): + """ + Private method to delete files from the project. + """ + itmList = self.getSelectedItems() + + files = [] + fullNames = [] + for itm in itmList: + fn2 = itm.fileName() + fullNames.append(fn2) + fn = self.project.getRelativePath(fn2) + files.append(fn) + + dlg = DeleteFilesConfirmationDialog( + self.parent(), + self.tr("Delete Protocols"), + self.tr( + "Do you really want to delete these protocol files from" " the project?" + ), + files, + ) + + if dlg.exec() == QDialog.DialogCode.Accepted: + for fn2, fn in zip(fullNames, files): + self.closeSourceWindow.emit(fn2) + self.project.deleteFile(fn) + + ########################################################################### + ## Methods to handle the various compile commands + ########################################################################### + + def __getCompilerCommand(self, grpc): + """ + Private method to get the compiler command. + + @param grpc flag indicating to get a gRPC command + @type bool + @return tuple giving the executable and its parameter list + @rtype tuple of (str, list of str) + """ + exe = None + exeArgs = [] + + if grpc: + env = self.__plugin.getPreferences("grpcPythonEnv") + exe = ericApp().getObject("VirtualEnvManager").getVirtualenvInterpreter(env) + if not exe: + exe = Globals.getPythonExecutable() + exeArgs = ["-m", "grpc_tools.protoc"] + else: + exe = self.__plugin.getPreferences("protoc") + if exe == "": + exe = "protoc.exe" if Utilities.isWindowsPlatform() else "protoc" + if not Utilities.isinpath(exe): + exe = None + + return exe, exeArgs + + def __readStdout(self): + """ + Private slot to handle the readyReadStandardOutput signal of the + protoc process. + """ + if self.compileProc is None: + return + + ioEncoding = Preferences.getSystem("IOEncoding") + + self.compileProc.setReadChannel(QProcess.ProcessChannel.StandardOutput) + while self.compileProc and self.compileProc.canReadLine(): + s = "protoc: " + output = str(self.compileProc.readLine(), ioEncoding, "replace") + s += output + self.appendStdout.emit(s) + + def __readStderr(self): + """ + Private slot to handle the readyReadStandardError signal of the + protoc process. + """ + if self.compileProc is None: + return + + ioEncoding = Preferences.getSystem("IOEncoding") + + self.compileProc.setReadChannel(QProcess.ProcessChannel.StandardError) + while self.compileProc and self.compileProc.canReadLine(): + s = "protoc: " + error = str(self.compileProc.readLine(), ioEncoding, "replace") + s += error + self.appendStderr.emit(s) + + def __compileProtoDone(self, exitCode, exitStatus, grpc): + """ + Private slot to handle the finished signal of the protoc process. + + @param exitCode exit code of the process + @type int + @param exitStatus exit status of the process + @type QProcess.ExitStatus + @param grpc flag indicating to compile as gRPC files + @type bool + """ + self.__compileRunning = False + ui = ericApp().getObject("UserInterface") + if exitStatus == QProcess.ExitStatus.NormalExit and exitCode == 0: + path = os.path.dirname(self.__protoFile) + fileList = glob.glob(os.path.join(path, "*_pb2.py")) + if grpc: + fileList += glob.glob(os.path.join(path, "*_pb2_grpc.py")) + for file in fileList: + self.project.appendFile(file) + if grpc: + icon = EricPixmapCache.getPixmap("gRPC48") + else: + icon = EricPixmapCache.getPixmap("protobuf48") + ui.showNotification( + icon, + self.tr("Protocol Compilation"), + self.tr("The compilation of the protocol file was" " successful."), + ) + else: + if grpc: + icon = EricPixmapCache.getPixmap( + os.path.join(os.path.dirname(__file__), "icons", "gRPC48") + ) + else: + icon = EricPixmapCache.getPixmap( + os.path.join(os.path.dirname(__file__), "icons", "protobuf48") + ) + ui.showNotification( + icon, + self.tr("Protocol Compilation"), + self.tr("The compilation of the protocol file failed."), + kind=NotificationTypes.CRITICAL, + timeout=0, + ) + self.compileProc = None + + def __compileProto(self, fn, noDialog=False, progress=None, grpc=False): + """ + Private method to compile a .proto file to Python. + + @param fn filename of the .proto file to be compiled + @type str + @param noDialog flag indicating silent operations + @type bool + @param progress reference to the progress dialog + @type EricProgressDialog + @param grpc flag indicating to compile as gRPC files + @type bool + @return reference to the compile process + @rtype QProcess + """ + exe, exeArgs = self.__getCompilerCommand(grpc) + if exe: + self.compileProc = QProcess() + args = [] + + fn = os.path.join(self.project.ppath, fn) + self.__protoFile = fn + + srcPath = os.path.dirname(fn) + args.append("--proto_path={0}".format(srcPath)) + args.append("--python_out={0}".format(srcPath)) + if grpc: + args.append("--grpc_python_out={0}".format(srcPath)) + args.append(fn) + + self.compileProc.finished.connect( + lambda c, s: self.__compileProtoDone(c, s, grpc) + ) + self.compileProc.readyReadStandardOutput.connect(self.__readStdout) + self.compileProc.readyReadStandardError.connect(self.__readStderr) + + self.noDialog = noDialog + self.compileProc.start(exe, exeArgs + args) + procStarted = self.compileProc.waitForStarted(5000) + if procStarted: + self.__compileRunning = True + return self.compileProc + else: + self.__compileRunning = False + if progress is not None: + progress.cancel() + EricMessageBox.critical( + self, + self.tr("Process Generation Error"), + self.tr( + "<p>Could not start {0}.<br>" + "Ensure that it is in the search path.</p>" + ).format(exe), + ) + return None + else: + EricMessageBox.critical( + self, + self.tr("Compiler Invalid"), + self.tr("The configured compiler is invalid."), + ) + return None + + def __compileProtocol(self, grpc=False): + """ + Private method to compile a protocol to Python. + + @param grpc flag indicating to compile as gRPC files + @type bool + """ + if self.__getCompilerCommand(grpc)[0] is not None: + itm = self.model().item(self.currentIndex()) + fn2 = itm.fileName() + fn = self.project.getRelativePath(fn2) + self.__compileProto(fn, grpc=grpc) + + def __compileAllProtocols(self, grpc=False): + """ + Private method to compile all protocols to Python. + + @param grpc flag indicating to compile as gRPC files + @type bool + """ + if self.__getCompilerCommand(grpc)[0] is not None: + numProtos = len(self.project.getProjectData(dataKey="PROTOCOLS")) + progress = EricProgressDialog( + self.tr("Compiling Protocols..."), + self.tr("Abort"), + 0, + numProtos, + self.tr("%v/%m Protocols"), + self, + ) + progress.setModal(True) + progress.setMinimumDuration(0) + progress.setWindowTitle(self.tr("Protocols")) + + for prog, fn in enumerate(self.project.getProjectData(dataKey="PROTOCOLS")): + progress.setValue(prog) + if progress.wasCanceled(): + break + proc = self.__compileProto(fn, True, progress, grpc=grpc) + if proc is not None: + while proc.state() == QProcess.ProcessState.Running: + QThread.msleep(100) + QApplication.processEvents() + else: + break + progress.setValue(numProtos) + + def __compileSelectedProtocols(self, grpc=False): + """ + Private method to compile selected protocols to Python. + + @param grpc flag indicating to compile as gRPC files + @type bool + """ + if self.__getCompilerCommand(grpc)[0] is not None: + items = self.getSelectedItems() + + files = [self.project.getRelativePath(itm.fileName()) for itm in items] + numProtos = len(files) + progress = EricProgressDialog( + self.tr("Compiling Protocols..."), + self.tr("Abort"), + 0, + numProtos, + self.tr("%v/%m Protocols"), + self, + ) + progress.setModal(True) + progress.setMinimumDuration(0) + progress.setWindowTitle(self.tr("Protocols")) + + for prog, fn in enumerate(files): + progress.setValue(prog) + if progress.wasCanceled(): + break + proc = self.__compileProto(fn, True, progress, grpc=grpc) + if proc is not None: + while proc.state() == QProcess.ProcessState.Running: + QThread.msleep(100) + QApplication.processEvents() + else: + break + progress.setValue(numProtos) + + def __configureProtobuf(self): + """ + Private method to open the configuration dialog. + """ + ericApp().getObject("UserInterface").showPreferences("protobufPage")