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