ExtensionProtobuf/ProjectProtocolsBrowser.py

changeset 1
7157a39d4a0f
child 8
24fdd6e43cd7
equal deleted inserted replaced
0:f6cff7759b24 1:7157a39d4a0f
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2017 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the a class used to display the protocols (protobuf) part
8 of the project.
9 """
10
11 import contextlib
12 import functools
13 import glob
14 import os
15
16 from PyQt6.QtCore import QProcess, QThread, pyqtSignal
17 from PyQt6.QtWidgets import QApplication, QDialog, QMenu
18
19 from eric7 import Globals, Preferences, Utilities
20 from eric7.EricGui import EricPixmapCache
21 from eric7.EricWidgets import EricMessageBox
22 from eric7.EricWidgets.EricApplication import ericApp
23 from eric7.EricWidgets.EricProgressDialog import EricProgressDialog
24 from eric7.Project.FileCategoryRepositoryItem import FileCategoryRepositoryItem
25 from eric7.Project.ProjectBaseBrowser import ProjectBaseBrowser
26 from eric7.Project.ProjectBrowserModel import (
27 ProjectBrowserDirectoryItem,
28 ProjectBrowserFileItem,
29 ProjectBrowserSimpleDirectoryItem,
30 )
31 from eric7.Project.ProjectBrowserRepositoryItem import ProjectBrowserRepositoryItem
32 from eric7.UI.BrowserModel import (
33 BrowserClassAttributeItem,
34 BrowserClassItem,
35 BrowserFileItem,
36 BrowserMethodItem,
37 )
38 from eric7.UI.DeleteFilesConfirmationDialog import DeleteFilesConfirmationDialog
39 from eric7.UI.NotificationWidget import NotificationTypes
40
41
42 class ProjectProtocolsBrowser(ProjectBaseBrowser):
43 """
44 A class used to display the protocols (protobuf) part of the project.
45
46 @signal appendStdout(str) emitted after something was received from
47 a QProcess on stdout
48 @signal appendStderr(str) emitted after something was received from
49 a QProcess on stderr
50 @signal showMenu(str, QMenu) emitted when a menu is about to be shown.
51 The name of the menu and a reference to the menu are given.
52 """
53
54 appendStdout = pyqtSignal(str)
55 appendStderr = pyqtSignal(str)
56 showMenu = pyqtSignal(str, QMenu)
57
58 FileFilter = "proto"
59
60 def __init__(self, plugin, parent=None):
61 """
62 Constructor
63
64 @param plugin reference to the plugin object
65 @type ProtobufExtensionPlugin
66 @param parent parent widget of this browser
67 @type QWidget
68 """
69 project = ericApp().getObject("Project")
70 projectBrowser = ericApp().getObject("ProjectBrowser")
71
72 ProjectBaseBrowser.__init__(self, project, self.FileFilter, parent)
73
74 self.selectedItemsFilter = [
75 ProjectBrowserFileItem,
76 ProjectBrowserSimpleDirectoryItem,
77 ]
78
79 self.setWindowTitle(self.tr("Protocols (protobuf)"))
80
81 self.setWhatsThis(
82 self.tr(
83 """<b>Project Protocols Browser</b>"""
84 """<p>This allows to easily see all protocols (protobuf files)"""
85 """ contained in the current project. Several actions can be"""
86 """ executed via the context menu.</p>"""
87 )
88 )
89
90 self.__plugin = plugin
91
92 # Add the file category handled by the browser.
93 project.addFileCategory(
94 "PROTOCOLS",
95 FileCategoryRepositoryItem(
96 fileCategoryFilterTemplate=self.tr("Protobuf Files ({0})"),
97 fileCategoryUserString=self.tr("Protobuf Files"),
98 fileCategoryTyeString=self.tr("Protobuf Files"),
99 fileCategoryExtensions=["*.proto"],
100 ),
101 )
102
103 # Add the project browser type to the browser type repository.
104 projectBrowser.addTypedProjectBrowser(
105 "protocols",
106 ProjectBrowserRepositoryItem(
107 projectBrowser=self,
108 projectBrowserUserString=self.tr("Protocols (protobuf) Browser"),
109 priority=50,
110 fileCategory="PROTOCOLS",
111 fileFilter=self.FileFilter,
112 getIcon=self.getIcon,
113 ),
114 )
115
116 # Connect signals of Project.
117 project.prepareRepopulateItem.connect(self._prepareRepopulateItem)
118 project.completeRepopulateItem.connect(self._completeRepopulateItem)
119 project.projectClosed.connect(self._projectClosed)
120 project.projectOpened.connect(self._projectOpened)
121 project.newProject.connect(self._newProject)
122 project.reinitVCS.connect(self._initMenusAndVcs)
123 project.projectPropertiesChanged.connect(self._initMenusAndVcs)
124
125 # Connect signals of ProjectBrowser.
126 projectBrowser.preferencesChanged.connect(self.handlePreferencesChanged)
127
128 # Connect some of our own signals.
129 self.appendStderr.connect(projectBrowser.appendStderr)
130 self.appendStdout.connect(projectBrowser.appendStdout)
131 self.closeSourceWindow.connect(projectBrowser.closeSourceWindow)
132 self.sourceFile[str].connect(projectBrowser.sourceFile[str])
133 self.sourceFile[str, int].connect(projectBrowser.sourceFile[str, int])
134
135 def deactivate(self):
136 """
137 Public method to deactivate the browser.
138 """
139 project = ericApp().getObject("Project")
140 projectBrowser = ericApp().getObject("ProjectBrowser")
141
142 # Disconnect some of our own signals.
143 self.appendStderr.disconnect(projectBrowser.appendStderr)
144 self.appendStdout.disconnect(projectBrowser.appendStdout)
145 self.closeSourceWindow.disconnect(projectBrowser.closeSourceWindow)
146 self.sourceFile[str].disconnect(projectBrowser.sourceFile[str])
147 self.sourceFile[str, int].disconnect(projectBrowser.sourceFile[str, int])
148
149 # Disconnect signals of ProjectBrowser.
150 projectBrowser.preferencesChanged.disconnect(self.handlePreferencesChanged)
151
152 # Disconnect signals of Project.
153 project.prepareRepopulateItem.disconnect(self._prepareRepopulateItem)
154 project.completeRepopulateItem.disconnect(self._completeRepopulateItem)
155 project.projectClosed.disconnect(self._projectClosed)
156 project.projectOpened.disconnect(self._projectOpened)
157 project.newProject.disconnect(self._newProject)
158 project.reinitVCS.disconnect(self._initMenusAndVcs)
159 project.projectPropertiesChanged.disconnect(self._initMenusAndVcs)
160
161 # Remove the project browser type from the browser type repository.
162 projectBrowser.removeTypedProjectBrowser("protocols")
163
164 # Remove the file category handled by the browser.
165 project.removeFileCategory("PROTOCOLS")
166
167 def getIcon(self):
168 """
169 Public method to get an icon for the project browser.
170
171 @return icon for the browser
172 @rtype QIcon
173 """
174 return EricPixmapCache.getIcon(
175 os.path.join(os.path.dirname(__file__), "icons", "protobuf")
176 )
177
178 def _createPopupMenus(self):
179 """
180 Protected overloaded method to generate the popup menu.
181 """
182 self.menuActions = []
183 self.multiMenuActions = []
184 self.dirMenuActions = []
185 self.dirMultiMenuActions = []
186
187 self.sourceMenu = QMenu(self)
188 self.sourceMenu.addAction(self.tr("Compile protocol"), self.__compileProtocol)
189 self.sourceMenu.addAction(
190 self.tr("Compile all protocols"), self.__compileAllProtocols
191 )
192 self.sourceMenu.addSeparator()
193 self.sourceMenu.addAction(
194 self.tr("Compile protocol as gRPC"),
195 functools.partial(self.__compileProtocol, grpc=True),
196 )
197 self.sourceMenu.addAction(
198 self.tr("Compile all protocols as gRPC"),
199 functools.partial(self.__compileAllProtocols, grpc=True),
200 )
201 self.sourceMenu.addSeparator()
202 self.sourceMenu.addAction(self.tr("Open"), self._openItem)
203 self.sourceMenu.addSeparator()
204 act = self.sourceMenu.addAction(self.tr("Rename file"), self._renameFile)
205 self.menuActions.append(act)
206 act = self.sourceMenu.addAction(
207 self.tr("Remove from project"), self._removeFile
208 )
209 self.menuActions.append(act)
210 act = self.sourceMenu.addAction(self.tr("Delete"), self.__deleteFile)
211 self.menuActions.append(act)
212 self.sourceMenu.addSeparator()
213 self.sourceMenu.addAction(self.tr("Add protocols..."), self.__addProtocolFiles)
214 self.sourceMenu.addAction(
215 self.tr("Add protocols directory..."), self.__addProtocolsDirectory
216 )
217 self.sourceMenu.addSeparator()
218 self.sourceMenu.addAction(
219 self.tr("Copy Path to Clipboard"), self._copyToClipboard
220 )
221 self.sourceMenu.addSeparator()
222 self.sourceMenu.addAction(
223 self.tr("Expand all directories"), self._expandAllDirs
224 )
225 self.sourceMenu.addAction(
226 self.tr("Collapse all directories"), self._collapseAllDirs
227 )
228 self.sourceMenu.addSeparator()
229 self.sourceMenu.addAction(self.tr("Configure..."), self._configure)
230 self.sourceMenu.addAction(
231 self.tr("Configure Protobuf..."), self.__configureProtobuf
232 )
233
234 self.menu = QMenu(self)
235 self.menu.addAction(self.tr("Compile protocol"), self.__compileProtocol)
236 self.menu.addAction(
237 self.tr("Compile all protocols"), self.__compileAllProtocols
238 )
239 self.menu.addSeparator()
240 self.menu.addAction(
241 self.tr("Compile protocol as gRPC"),
242 functools.partial(self.__compileProtocol, grpc=True),
243 )
244 self.menu.addAction(
245 self.tr("Compile all protocols as gRPC"),
246 functools.partial(self.__compileAllProtocols, grpc=True),
247 )
248 self.menu.addSeparator()
249 self.menu.addAction(self.tr("Open"), self._openItem)
250 self.menu.addSeparator()
251 self.menu.addAction(self.tr("Add protocols..."), self.__addProtocolFiles)
252 self.menu.addAction(
253 self.tr("Add protocols directory..."), self.__addProtocolsDirectory
254 )
255 self.menu.addSeparator()
256 self.menu.addAction(self.tr("Expand all directories"), self._expandAllDirs)
257 self.menu.addAction(self.tr("Collapse all directories"), self._collapseAllDirs)
258 self.menu.addSeparator()
259 self.menu.addAction(self.tr("Configure..."), self._configure)
260 self.menu.addAction(self.tr("Configure Protobuf..."), self.__configureProtobuf)
261
262 self.backMenu = QMenu(self)
263 self.backMenu.addAction(
264 self.tr("Compile all protocols"), self.__compileAllProtocols
265 )
266 self.backMenu.addSeparator()
267 self.backMenu.addAction(
268 self.tr("Compile all protocols as gRPC"),
269 functools.partial(self.__compileAllProtocols, grpc=True),
270 )
271 self.backMenu.addSeparator()
272 self.backMenu.addAction(
273 self.tr("Add protocols..."), lambda: self.project.addFiles("PROTOCOLS")
274 )
275 self.backMenu.addAction(
276 self.tr("Add protocols directory..."),
277 lambda: self.project.addDirectory("PROTOCOLS"),
278 )
279 self.backMenu.addSeparator()
280 self.backMenu.addAction(self.tr("Expand all directories"), self._expandAllDirs)
281 self.backMenu.addAction(
282 self.tr("Collapse all directories"), self._collapseAllDirs
283 )
284 self.backMenu.addSeparator()
285 self.backMenu.addAction(self.tr("Configure..."), self._configure)
286 self.backMenu.addAction(
287 self.tr("Configure Protobuf..."), self.__configureProtobuf
288 )
289 self.backMenu.setEnabled(False)
290
291 # create the menu for multiple selected files
292 self.multiMenu = QMenu(self)
293 self.multiMenu.addAction(
294 self.tr("Compile protocols"), self.__compileSelectedProtocols
295 )
296 self.multiMenu.addSeparator()
297 self.multiMenu.addAction(
298 self.tr("Compile protocols as gRPC"),
299 functools.partial(self.__compileSelectedProtocols, grpc=True),
300 )
301 self.multiMenu.addSeparator()
302 self.multiMenu.addAction(self.tr("Open"), self._openItem)
303 self.multiMenu.addSeparator()
304 act = self.multiMenu.addAction(self.tr("Remove from project"), self._removeFile)
305 self.multiMenuActions.append(act)
306 act = self.multiMenu.addAction(self.tr("Delete"), self.__deleteFile)
307 self.multiMenuActions.append(act)
308 self.multiMenu.addSeparator()
309 self.multiMenu.addAction(self.tr("Expand all directories"), self._expandAllDirs)
310 self.multiMenu.addAction(
311 self.tr("Collapse all directories"), self._collapseAllDirs
312 )
313 self.multiMenu.addSeparator()
314 self.multiMenu.addAction(self.tr("Configure..."), self._configure)
315 self.multiMenu.addAction(
316 self.tr("Configure Protobuf..."), self.__configureProtobuf
317 )
318
319 self.dirMenu = QMenu(self)
320 self.dirMenu.addAction(
321 self.tr("Compile all protocols"), self.__compileAllProtocols
322 )
323 self.dirMenu.addSeparator()
324 self.dirMenu.addAction(
325 self.tr("Compile all protocols as gRPC"),
326 functools.partial(self.__compileAllProtocols, grpc=True),
327 )
328 act = self.dirMenu.addAction(self.tr("Remove from project"), self._removeFile)
329 self.dirMenuActions.append(act)
330 act = self.dirMenu.addAction(self.tr("Delete"), self._deleteDirectory)
331 self.dirMenuActions.append(act)
332 self.dirMenu.addSeparator()
333 self.dirMenu.addAction(self.tr("Add protocols..."), self.__addProtocolFiles)
334 self.dirMenu.addAction(
335 self.tr("Add protocols directory..."), self.__addProtocolsDirectory
336 )
337 self.dirMenu.addSeparator()
338 self.dirMenu.addAction(self.tr("Copy Path to Clipboard"), self._copyToClipboard)
339 self.dirMenu.addSeparator()
340 self.dirMenu.addAction(self.tr("Expand all directories"), self._expandAllDirs)
341 self.dirMenu.addAction(
342 self.tr("Collapse all directories"), self._collapseAllDirs
343 )
344 self.dirMenu.addSeparator()
345 self.dirMenu.addAction(self.tr("Configure..."), self._configure)
346 self.dirMenu.addAction(
347 self.tr("Configure Protobuf..."), self.__configureProtobuf
348 )
349
350 self.dirMultiMenu = QMenu(self)
351 self.dirMultiMenu.addAction(
352 self.tr("Compile all protocols"), self.__compileAllProtocols
353 )
354 self.dirMultiMenu.addSeparator()
355 self.dirMultiMenu.addAction(
356 self.tr("Compile all protocols as gRPC"),
357 functools.partial(self.__compileAllProtocols, grpc=True),
358 )
359 self.dirMultiMenu.addAction(
360 self.tr("Add protocols..."), lambda: self.project.addFiles("PROTOCOLS")
361 )
362 self.dirMultiMenu.addAction(
363 self.tr("Add protocols directory..."),
364 lambda: self.project.addDirectory("PROTOCOLS"),
365 )
366 self.dirMultiMenu.addSeparator()
367 self.dirMultiMenu.addAction(
368 self.tr("Expand all directories"), self._expandAllDirs
369 )
370 self.dirMultiMenu.addAction(
371 self.tr("Collapse all directories"), self._collapseAllDirs
372 )
373 self.dirMultiMenu.addSeparator()
374 self.dirMultiMenu.addAction(self.tr("Configure..."), self._configure)
375 self.dirMultiMenu.addAction(
376 self.tr("Configure Protobuf..."), self.__configureProtobuf
377 )
378
379 self.sourceMenu.aboutToShow.connect(self.__showContextMenu)
380 self.multiMenu.aboutToShow.connect(self.__showContextMenuMulti)
381 self.dirMenu.aboutToShow.connect(self.__showContextMenuDir)
382 self.dirMultiMenu.aboutToShow.connect(self.__showContextMenuDirMulti)
383 self.backMenu.aboutToShow.connect(self.__showContextMenuBack)
384 self.mainMenu = self.sourceMenu
385
386 def _contextMenuRequested(self, coord):
387 """
388 Protected slot to show the context menu.
389
390 @param coord the position of the mouse pointer (QPoint)
391 """
392 if not self.project.isOpen():
393 return
394
395 with contextlib.suppress(Exception): # secok
396 categories = self.getSelectedItemsCountCategorized(
397 [
398 ProjectBrowserFileItem,
399 BrowserClassItem,
400 BrowserMethodItem,
401 ProjectBrowserSimpleDirectoryItem,
402 ]
403 )
404 cnt = categories["sum"]
405 if cnt <= 1:
406 index = self.indexAt(coord)
407 if index.isValid():
408 self._selectSingleItem(index)
409 categories = self.getSelectedItemsCountCategorized(
410 [
411 ProjectBrowserFileItem,
412 BrowserClassItem,
413 BrowserMethodItem,
414 ProjectBrowserSimpleDirectoryItem,
415 ]
416 )
417 cnt = categories["sum"]
418
419 bfcnt = categories[str(ProjectBrowserFileItem)]
420 cmcnt = (
421 categories[str(BrowserClassItem)] + categories[str(BrowserMethodItem)]
422 )
423 sdcnt = categories[str(ProjectBrowserSimpleDirectoryItem)]
424 if cnt > 1 and cnt == bfcnt:
425 self.multiMenu.popup(self.mapToGlobal(coord))
426 elif cnt > 1 and cnt == sdcnt:
427 self.dirMultiMenu.popup(self.mapToGlobal(coord))
428 else:
429 index = self.indexAt(coord)
430 if cnt == 1 and index.isValid():
431 if bfcnt == 1 or cmcnt == 1:
432 itm = self.model().item(index)
433 if isinstance(itm, ProjectBrowserFileItem):
434 self.sourceMenu.popup(self.mapToGlobal(coord))
435 elif isinstance(itm, (BrowserClassItem, BrowserMethodItem)):
436 self.menu.popup(self.mapToGlobal(coord))
437 else:
438 self.backMenu.popup(self.mapToGlobal(coord))
439 elif sdcnt == 1:
440 self.dirMenu.popup(self.mapToGlobal(coord))
441 else:
442 self.backMenu.popup(self.mapToGlobal(coord))
443 else:
444 self.backMenu.popup(self.mapToGlobal(coord))
445
446 def __showContextMenu(self):
447 """
448 Private slot called by the menu aboutToShow signal.
449 """
450 ProjectBaseBrowser._showContextMenu(self, self.menu)
451
452 self.showMenu.emit("Main", self.menu)
453
454 def __showContextMenuMulti(self):
455 """
456 Private slot called by the multiMenu aboutToShow signal.
457 """
458 ProjectBaseBrowser._showContextMenuMulti(self, self.multiMenu)
459
460 self.showMenu.emit("MainMulti", self.multiMenu)
461
462 def __showContextMenuDir(self):
463 """
464 Private slot called by the dirMenu aboutToShow signal.
465 """
466 ProjectBaseBrowser._showContextMenuDir(self, self.dirMenu)
467
468 self.showMenu.emit("MainDir", self.dirMenu)
469
470 def __showContextMenuDirMulti(self):
471 """
472 Private slot called by the dirMultiMenu aboutToShow signal.
473 """
474 ProjectBaseBrowser._showContextMenuDirMulti(self, self.dirMultiMenu)
475
476 self.showMenu.emit("MainDirMulti", self.dirMultiMenu)
477
478 def __showContextMenuBack(self):
479 """
480 Private slot called by the backMenu aboutToShow signal.
481 """
482 ProjectBaseBrowser._showContextMenuBack(self, self.backMenu)
483
484 self.showMenu.emit("MainBack", self.backMenu)
485
486 def _openItem(self):
487 """
488 Protected slot to handle the open popup menu entry.
489 """
490 itmList = self.getSelectedItems(
491 [
492 BrowserFileItem,
493 BrowserClassItem,
494 BrowserMethodItem,
495 BrowserClassAttributeItem,
496 ]
497 )
498
499 for itm in itmList:
500 if isinstance(itm, BrowserFileItem):
501 self.sourceFile[str].emit(itm.fileName())
502 elif isinstance(itm, BrowserClassItem):
503 self.sourceFile[str, int].emit(itm.fileName(), itm.classObject().lineno)
504 elif isinstance(itm, BrowserMethodItem):
505 self.sourceFile[str, int].emit(
506 itm.fileName(), itm.functionObject().lineno
507 )
508 elif isinstance(itm, BrowserClassAttributeItem):
509 self.sourceFile[str, int].emit(
510 itm.fileName(), itm.attributeObject().lineno
511 )
512
513 def __addProtocolFiles(self):
514 """
515 Private method to add protocol files to the project.
516 """
517 itm = self.model().item(self.currentIndex())
518 if isinstance(
519 itm, (ProjectBrowserFileItem, BrowserClassItem, BrowserMethodItem)
520 ):
521 dn = os.path.dirname(itm.fileName())
522 elif isinstance(
523 itm, (ProjectBrowserSimpleDirectoryItem, ProjectBrowserDirectoryItem)
524 ):
525 dn = itm.dirName()
526 else:
527 dn = None
528 self.project.addFiles("protocol", dn)
529
530 def __addProtocolsDirectory(self):
531 """
532 Private method to add protocol files of a directory to the project.
533 """
534 itm = self.model().item(self.currentIndex())
535 if isinstance(
536 itm, (ProjectBrowserFileItem, BrowserClassItem, BrowserMethodItem)
537 ):
538 dn = os.path.dirname(itm.fileName())
539 elif isinstance(
540 itm, (ProjectBrowserSimpleDirectoryItem, ProjectBrowserDirectoryItem)
541 ):
542 dn = itm.dirName()
543 else:
544 dn = None
545 self.project.addDirectory("protocol", dn)
546
547 def __deleteFile(self):
548 """
549 Private method to delete files from the project.
550 """
551 itmList = self.getSelectedItems()
552
553 files = []
554 fullNames = []
555 for itm in itmList:
556 fn2 = itm.fileName()
557 fullNames.append(fn2)
558 fn = self.project.getRelativePath(fn2)
559 files.append(fn)
560
561 dlg = DeleteFilesConfirmationDialog(
562 self.parent(),
563 self.tr("Delete Protocols"),
564 self.tr(
565 "Do you really want to delete these protocol files from" " the project?"
566 ),
567 files,
568 )
569
570 if dlg.exec() == QDialog.DialogCode.Accepted:
571 for fn2, fn in zip(fullNames, files):
572 self.closeSourceWindow.emit(fn2)
573 self.project.deleteFile(fn)
574
575 ###########################################################################
576 ## Methods to handle the various compile commands
577 ###########################################################################
578
579 def __getCompilerCommand(self, grpc):
580 """
581 Private method to get the compiler command.
582
583 @param grpc flag indicating to get a gRPC command
584 @type bool
585 @return tuple giving the executable and its parameter list
586 @rtype tuple of (str, list of str)
587 """
588 exe = None
589 exeArgs = []
590
591 if grpc:
592 env = self.__plugin.getPreferences("grpcPythonEnv")
593 exe = ericApp().getObject("VirtualEnvManager").getVirtualenvInterpreter(env)
594 if not exe:
595 exe = Globals.getPythonExecutable()
596 exeArgs = ["-m", "grpc_tools.protoc"]
597 else:
598 exe = self.__plugin.getPreferences("protoc")
599 if exe == "":
600 exe = "protoc.exe" if Utilities.isWindowsPlatform() else "protoc"
601 if not Utilities.isinpath(exe):
602 exe = None
603
604 return exe, exeArgs
605
606 def __readStdout(self):
607 """
608 Private slot to handle the readyReadStandardOutput signal of the
609 protoc process.
610 """
611 if self.compileProc is None:
612 return
613
614 ioEncoding = Preferences.getSystem("IOEncoding")
615
616 self.compileProc.setReadChannel(QProcess.ProcessChannel.StandardOutput)
617 while self.compileProc and self.compileProc.canReadLine():
618 s = "protoc: "
619 output = str(self.compileProc.readLine(), ioEncoding, "replace")
620 s += output
621 self.appendStdout.emit(s)
622
623 def __readStderr(self):
624 """
625 Private slot to handle the readyReadStandardError signal of the
626 protoc process.
627 """
628 if self.compileProc is None:
629 return
630
631 ioEncoding = Preferences.getSystem("IOEncoding")
632
633 self.compileProc.setReadChannel(QProcess.ProcessChannel.StandardError)
634 while self.compileProc and self.compileProc.canReadLine():
635 s = "protoc: "
636 error = str(self.compileProc.readLine(), ioEncoding, "replace")
637 s += error
638 self.appendStderr.emit(s)
639
640 def __compileProtoDone(self, exitCode, exitStatus, grpc):
641 """
642 Private slot to handle the finished signal of the protoc process.
643
644 @param exitCode exit code of the process
645 @type int
646 @param exitStatus exit status of the process
647 @type QProcess.ExitStatus
648 @param grpc flag indicating to compile as gRPC files
649 @type bool
650 """
651 self.__compileRunning = False
652 ui = ericApp().getObject("UserInterface")
653 if exitStatus == QProcess.ExitStatus.NormalExit and exitCode == 0:
654 path = os.path.dirname(self.__protoFile)
655 fileList = glob.glob(os.path.join(path, "*_pb2.py"))
656 if grpc:
657 fileList += glob.glob(os.path.join(path, "*_pb2_grpc.py"))
658 for file in fileList:
659 self.project.appendFile(file)
660 if grpc:
661 icon = EricPixmapCache.getPixmap("gRPC48")
662 else:
663 icon = EricPixmapCache.getPixmap("protobuf48")
664 ui.showNotification(
665 icon,
666 self.tr("Protocol Compilation"),
667 self.tr("The compilation of the protocol file was" " successful."),
668 )
669 else:
670 if grpc:
671 icon = EricPixmapCache.getPixmap(
672 os.path.join(os.path.dirname(__file__), "icons", "gRPC48")
673 )
674 else:
675 icon = EricPixmapCache.getPixmap(
676 os.path.join(os.path.dirname(__file__), "icons", "protobuf48")
677 )
678 ui.showNotification(
679 icon,
680 self.tr("Protocol Compilation"),
681 self.tr("The compilation of the protocol file failed."),
682 kind=NotificationTypes.CRITICAL,
683 timeout=0,
684 )
685 self.compileProc = None
686
687 def __compileProto(self, fn, noDialog=False, progress=None, grpc=False):
688 """
689 Private method to compile a .proto file to Python.
690
691 @param fn filename of the .proto file to be compiled
692 @type str
693 @param noDialog flag indicating silent operations
694 @type bool
695 @param progress reference to the progress dialog
696 @type EricProgressDialog
697 @param grpc flag indicating to compile as gRPC files
698 @type bool
699 @return reference to the compile process
700 @rtype QProcess
701 """
702 exe, exeArgs = self.__getCompilerCommand(grpc)
703 if exe:
704 self.compileProc = QProcess()
705 args = []
706
707 fn = os.path.join(self.project.ppath, fn)
708 self.__protoFile = fn
709
710 srcPath = os.path.dirname(fn)
711 args.append("--proto_path={0}".format(srcPath))
712 args.append("--python_out={0}".format(srcPath))
713 if grpc:
714 args.append("--grpc_python_out={0}".format(srcPath))
715 args.append(fn)
716
717 self.compileProc.finished.connect(
718 lambda c, s: self.__compileProtoDone(c, s, grpc)
719 )
720 self.compileProc.readyReadStandardOutput.connect(self.__readStdout)
721 self.compileProc.readyReadStandardError.connect(self.__readStderr)
722
723 self.noDialog = noDialog
724 self.compileProc.start(exe, exeArgs + args)
725 procStarted = self.compileProc.waitForStarted(5000)
726 if procStarted:
727 self.__compileRunning = True
728 return self.compileProc
729 else:
730 self.__compileRunning = False
731 if progress is not None:
732 progress.cancel()
733 EricMessageBox.critical(
734 self,
735 self.tr("Process Generation Error"),
736 self.tr(
737 "<p>Could not start {0}.<br>"
738 "Ensure that it is in the search path.</p>"
739 ).format(exe),
740 )
741 return None
742 else:
743 EricMessageBox.critical(
744 self,
745 self.tr("Compiler Invalid"),
746 self.tr("The configured compiler is invalid."),
747 )
748 return None
749
750 def __compileProtocol(self, grpc=False):
751 """
752 Private method to compile a protocol to Python.
753
754 @param grpc flag indicating to compile as gRPC files
755 @type bool
756 """
757 if self.__getCompilerCommand(grpc)[0] is not None:
758 itm = self.model().item(self.currentIndex())
759 fn2 = itm.fileName()
760 fn = self.project.getRelativePath(fn2)
761 self.__compileProto(fn, grpc=grpc)
762
763 def __compileAllProtocols(self, grpc=False):
764 """
765 Private method to compile all protocols to Python.
766
767 @param grpc flag indicating to compile as gRPC files
768 @type bool
769 """
770 if self.__getCompilerCommand(grpc)[0] is not None:
771 numProtos = len(self.project.getProjectData(dataKey="PROTOCOLS"))
772 progress = EricProgressDialog(
773 self.tr("Compiling Protocols..."),
774 self.tr("Abort"),
775 0,
776 numProtos,
777 self.tr("%v/%m Protocols"),
778 self,
779 )
780 progress.setModal(True)
781 progress.setMinimumDuration(0)
782 progress.setWindowTitle(self.tr("Protocols"))
783
784 for prog, fn in enumerate(self.project.getProjectData(dataKey="PROTOCOLS")):
785 progress.setValue(prog)
786 if progress.wasCanceled():
787 break
788 proc = self.__compileProto(fn, True, progress, grpc=grpc)
789 if proc is not None:
790 while proc.state() == QProcess.ProcessState.Running:
791 QThread.msleep(100)
792 QApplication.processEvents()
793 else:
794 break
795 progress.setValue(numProtos)
796
797 def __compileSelectedProtocols(self, grpc=False):
798 """
799 Private method to compile selected protocols to Python.
800
801 @param grpc flag indicating to compile as gRPC files
802 @type bool
803 """
804 if self.__getCompilerCommand(grpc)[0] is not None:
805 items = self.getSelectedItems()
806
807 files = [self.project.getRelativePath(itm.fileName()) for itm in items]
808 numProtos = len(files)
809 progress = EricProgressDialog(
810 self.tr("Compiling Protocols..."),
811 self.tr("Abort"),
812 0,
813 numProtos,
814 self.tr("%v/%m Protocols"),
815 self,
816 )
817 progress.setModal(True)
818 progress.setMinimumDuration(0)
819 progress.setWindowTitle(self.tr("Protocols"))
820
821 for prog, fn in enumerate(files):
822 progress.setValue(prog)
823 if progress.wasCanceled():
824 break
825 proc = self.__compileProto(fn, True, progress, grpc=grpc)
826 if proc is not None:
827 while proc.state() == QProcess.ProcessState.Running:
828 QThread.msleep(100)
829 QApplication.processEvents()
830 else:
831 break
832 progress.setValue(numProtos)
833
834 def __configureProtobuf(self):
835 """
836 Private method to open the configuration dialog.
837 """
838 ericApp().getObject("UserInterface").showPreferences("protobufPage")

eric ide

mercurial