eric6/Project/ProjectSourcesBrowser.py

changeset 6942
2602857055c5
parent 6645
ad476851d7e0
child 7229
53054eb5b15a
equal deleted inserted replaced
6941:f99d60d6b59b 6942:2602857055c5
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2002 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a class used to display the Sources part of the project.
8 """
9
10 from __future__ import unicode_literals
11
12 import os
13
14 from PyQt5.QtCore import pyqtSignal
15 from PyQt5.QtWidgets import QDialog, QInputDialog, QMenu
16
17 from E5Gui import E5MessageBox
18
19 from UI.BrowserModel import BrowserFileItem, BrowserClassItem, \
20 BrowserMethodItem, BrowserClassAttributeItem, BrowserImportItem
21
22 from .ProjectBrowserModel import ProjectBrowserFileItem, \
23 ProjectBrowserSimpleDirectoryItem, ProjectBrowserDirectoryItem, \
24 ProjectBrowserSourceType
25 from .ProjectBaseBrowser import ProjectBaseBrowser
26
27 import Utilities
28 import UI.PixmapCache
29
30
31 class ProjectSourcesBrowser(ProjectBaseBrowser):
32 """
33 A class used to display the Sources part of the project.
34
35 @signal showMenu(str, QMenu) emitted when a menu is about to be shown.
36 The name of the menu and a reference to the menu are given.
37 """
38 showMenu = pyqtSignal(str, QMenu)
39
40 def __init__(self, project, parent=None):
41 """
42 Constructor
43
44 @param project reference to the project object
45 @param parent parent widget of this browser (QWidget)
46 """
47 ProjectBaseBrowser.__init__(self, project, ProjectBrowserSourceType,
48 parent)
49
50 self.selectedItemsFilter = \
51 [ProjectBrowserFileItem, ProjectBrowserSimpleDirectoryItem]
52
53 self.setWindowTitle(self.tr('Sources'))
54
55 self.setWhatsThis(self.tr(
56 """<b>Project Sources Browser</b>"""
57 """<p>This allows to easily see all sources contained in the"""
58 """ current project. Several actions can be executed via the"""
59 """ context menu.</p>"""
60 ))
61
62 project.prepareRepopulateItem.connect(self._prepareRepopulateItem)
63 project.completeRepopulateItem.connect(self._completeRepopulateItem)
64
65 self.codemetrics = None
66 self.codecoverage = None
67 self.profiledata = None
68 self.classDiagram = None
69 self.importsDiagram = None
70 self.packageDiagram = None
71 self.applicationDiagram = None
72 self.loadedDiagram = None
73
74 def __closeAllWindows(self):
75 """
76 Private method to close all project related windows.
77 """
78 self.codemetrics and self.codemetrics.close()
79 self.codecoverage and self.codecoverage.close()
80 self.profiledata and self.profiledata.close()
81 self.classDiagram and self.classDiagram.close()
82 self.importsDiagram and self.importsDiagram.close()
83 self.packageDiagram and self.packageDiagram.close()
84 self.applicationDiagram and self.applicationDiagram.close()
85 self.loadedDiagram and self.loadedDiagram.close()
86
87 def _projectClosed(self):
88 """
89 Protected slot to handle the projectClosed signal.
90 """
91 self.__closeAllWindows()
92 ProjectBaseBrowser._projectClosed(self)
93
94 def _createPopupMenus(self):
95 """
96 Protected overloaded method to generate the popup menu.
97 """
98 ProjectBaseBrowser._createPopupMenus(self)
99 self.sourceMenuActions = {}
100
101 if self.project.isPythonProject():
102 self.__createPythonPopupMenus()
103 elif self.project.isRubyProject():
104 self.__createRubyPopupMenus()
105 elif self.project.isJavaScriptProject():
106 self.__createJavaScriptPopupMenus()
107
108 def __createPythonPopupMenus(self):
109 """
110 Private method to generate the popup menus for a Python project.
111 """
112 self.checksMenu = QMenu(self.tr('Check'))
113 self.checksMenu.aboutToShow.connect(self.__showContextMenuCheck)
114
115 self.menuShow = QMenu(self.tr('Show'))
116 self.menuShow.addAction(
117 self.tr('Code metrics...'), self.__showCodeMetrics)
118 self.coverageMenuAction = self.menuShow.addAction(
119 self.tr('Code coverage...'), self.__showCodeCoverage)
120 self.profileMenuAction = self.menuShow.addAction(
121 self.tr('Profile data...'), self.__showProfileData)
122 self.menuShow.aboutToShow.connect(self.__showContextMenuShow)
123
124 self.graphicsMenu = QMenu(self.tr('Diagrams'))
125 self.classDiagramAction = self.graphicsMenu.addAction(
126 self.tr("Class Diagram..."), self.__showClassDiagram)
127 self.graphicsMenu.addAction(
128 self.tr("Package Diagram..."), self.__showPackageDiagram)
129 self.importsDiagramAction = self.graphicsMenu.addAction(
130 self.tr("Imports Diagram..."), self.__showImportsDiagram)
131 self.graphicsMenu.addAction(
132 self.tr("Application Diagram..."),
133 self.__showApplicationDiagram)
134 self.graphicsMenu.addSeparator()
135 self.graphicsMenu.addAction(
136 UI.PixmapCache.getIcon("open.png"),
137 self.tr("Load Diagram..."), self.__loadDiagram)
138 self.graphicsMenu.aboutToShow.connect(self.__showContextMenuGraphics)
139
140 self.unittestAction = self.sourceMenu.addAction(
141 self.tr('Run unittest...'), self.handleUnittest)
142 self.sourceMenu.addSeparator()
143 act = self.sourceMenu.addAction(
144 self.tr('Rename file'), self._renameFile)
145 self.menuActions.append(act)
146 act = self.sourceMenu.addAction(
147 self.tr('Remove from project'), self._removeFile)
148 self.menuActions.append(act)
149 act = self.sourceMenu.addAction(
150 self.tr('Delete'), self.__deleteFile)
151 self.menuActions.append(act)
152 self.sourceMenu.addSeparator()
153 self.sourceMenu.addAction(
154 self.tr('New package...'), self.__addNewPackage)
155 self.sourceMenu.addAction(
156 self.tr('Add source files...'), self.__addSourceFiles)
157 self.sourceMenu.addAction(
158 self.tr('Add source directory...'), self.__addSourceDirectory)
159 self.sourceMenu.addSeparator()
160 act = self.sourceMenu.addMenu(self.graphicsMenu)
161 self.sourceMenu.addSeparator()
162 self.sourceMenu.addMenu(self.checksMenu)
163 self.sourceMenu.addSeparator()
164 self.sourceMenuActions["Show"] = self.sourceMenu.addMenu(self.menuShow)
165 self.sourceMenu.addSeparator()
166 self.sourceMenu.addAction(
167 self.tr('Copy Path to Clipboard'), self._copyToClipboard)
168 self.sourceMenu.addSeparator()
169 self.sourceMenu.addAction(
170 self.tr('Expand all directories'), self._expandAllDirs)
171 self.sourceMenu.addAction(
172 self.tr('Collapse all directories'), self._collapseAllDirs)
173 self.sourceMenu.addSeparator()
174 self.sourceMenu.addAction(self.tr('Configure...'), self._configure)
175
176 self.menu.addSeparator()
177 self.menu.addAction(
178 self.tr('New package...'), self.__addNewPackage)
179 self.menu.addAction(
180 self.tr('Add source files...'), self.__addSourceFiles)
181 self.menu.addAction(
182 self.tr('Add source directory...'), self.__addSourceDirectory)
183 self.menu.addSeparator()
184 self.menu.addAction(
185 self.tr('Expand all directories'), self._expandAllDirs)
186 self.menu.addAction(
187 self.tr('Collapse all directories'), self._collapseAllDirs)
188 self.menu.addSeparator()
189 self.menu.addAction(self.tr('Configure...'), self._configure)
190
191 # create the attribute menu
192 self.gotoMenu = QMenu(self.tr("Goto"), self)
193 self.gotoMenu.aboutToShow.connect(self._showGotoMenu)
194 self.gotoMenu.triggered.connect(self._gotoAttribute)
195
196 self.attributeMenu = QMenu(self)
197 self.attributeMenu.addMenu(self.gotoMenu)
198 self.attributeMenu.addSeparator()
199 self.attributeMenu.addAction(
200 self.tr('New package...'), self.__addNewPackage)
201 self.attributeMenu.addAction(
202 self.tr('Add source files...'), self.project.addSourceFiles)
203 self.attributeMenu.addAction(
204 self.tr('Add source directory...'), self.project.addSourceDir)
205 self.attributeMenu.addSeparator()
206 self.attributeMenu.addAction(
207 self.tr('Expand all directories'), self._expandAllDirs)
208 self.attributeMenu.addAction(
209 self.tr('Collapse all directories'), self._collapseAllDirs)
210 self.attributeMenu.addSeparator()
211 self.attributeMenu.addAction(
212 self.tr('Configure...'), self._configure)
213
214 self.backMenu = QMenu(self)
215 self.backMenu.addAction(
216 self.tr('New package...'), self.__addNewPackage)
217 self.backMenu.addAction(
218 self.tr('Add source files...'), self.project.addSourceFiles)
219 self.backMenu.addAction(
220 self.tr('Add source directory...'), self.project.addSourceDir)
221 self.backMenu.addSeparator()
222 self.backMenu.addAction(
223 self.tr('Expand all directories'), self._expandAllDirs)
224 self.backMenu.addAction(
225 self.tr('Collapse all directories'), self._collapseAllDirs)
226 self.backMenu.addSeparator()
227 self.backMenu.addAction(self.tr('Configure...'), self._configure)
228 self.backMenu.setEnabled(False)
229
230 self.multiMenu.addSeparator()
231 act = self.multiMenu.addAction(
232 self.tr('Remove from project'), self._removeFile)
233 self.multiMenuActions.append(act)
234 act = self.multiMenu.addAction(
235 self.tr('Delete'), self.__deleteFile)
236 self.multiMenuActions.append(act)
237 self.multiMenu.addSeparator()
238 self.multiMenu.addMenu(self.checksMenu)
239 self.multiMenu.addSeparator()
240 self.multiMenu.addAction(
241 self.tr('Expand all directories'), self._expandAllDirs)
242 self.multiMenu.addAction(
243 self.tr('Collapse all directories'), self._collapseAllDirs)
244 self.multiMenu.addSeparator()
245 self.multiMenu.addAction(self.tr('Configure...'), self._configure)
246
247 self.dirMenu = QMenu(self)
248 act = self.dirMenu.addAction(
249 self.tr('Remove from project'), self._removeDir)
250 self.dirMenuActions.append(act)
251 act = self.dirMenu.addAction(
252 self.tr('Delete'), self._deleteDirectory)
253 self.dirMenuActions.append(act)
254 self.dirMenu.addSeparator()
255 self.dirMenu.addAction(
256 self.tr('New package...'), self.__addNewPackage)
257 self.dirMenu.addAction(
258 self.tr('Add source files...'), self.__addSourceFiles)
259 self.dirMenu.addAction(
260 self.tr('Add source directory...'), self.__addSourceDirectory)
261 self.dirMenu.addSeparator()
262 act = self.dirMenu.addMenu(self.graphicsMenu)
263 self.dirMenu.addSeparator()
264 self.dirMenu.addMenu(self.checksMenu)
265 self.dirMenu.addSeparator()
266 self.dirMenu.addAction(
267 self.tr('Copy Path to Clipboard'), self._copyToClipboard)
268 self.dirMenu.addSeparator()
269 self.dirMenu.addAction(
270 self.tr('Expand all directories'), self._expandAllDirs)
271 self.dirMenu.addAction(
272 self.tr('Collapse all directories'), self._collapseAllDirs)
273 self.dirMenu.addSeparator()
274 self.dirMenu.addAction(self.tr('Configure...'), self._configure)
275
276 self.dirMultiMenu = QMenu(self)
277 self.dirMultiMenu.addAction(
278 self.tr('Expand all directories'), self._expandAllDirs)
279 self.dirMultiMenu.addAction(
280 self.tr('Collapse all directories'), self._collapseAllDirs)
281 self.dirMultiMenu.addSeparator()
282 self.dirMultiMenu.addAction(
283 self.tr('Configure...'), self._configure)
284
285 self.sourceMenu.aboutToShow.connect(self.__showContextMenu)
286 self.multiMenu.aboutToShow.connect(self.__showContextMenuMulti)
287 self.dirMenu.aboutToShow.connect(self.__showContextMenuDir)
288 self.dirMultiMenu.aboutToShow.connect(self.__showContextMenuDirMulti)
289 self.backMenu.aboutToShow.connect(self.__showContextMenuBack)
290 self.mainMenu = self.sourceMenu
291
292 def __createRubyPopupMenus(self):
293 """
294 Private method to generate the popup menus for a Ruby project.
295 """
296 self.graphicsMenu = QMenu(self.tr('Diagrams'))
297 self.classDiagramAction = self.graphicsMenu.addAction(
298 self.tr("Class Diagram..."), self.__showClassDiagram)
299 self.graphicsMenu.addAction(
300 self.tr("Package Diagram..."), self.__showPackageDiagram)
301 self.graphicsMenu.addAction(
302 self.tr("Application Diagram..."),
303 self.__showApplicationDiagram)
304 self.graphicsMenu.addSeparator()
305 self.graphicsMenu.addAction(
306 UI.PixmapCache.getIcon("fileOpen.png"),
307 self.tr("Load Diagram..."), self.__loadDiagram)
308
309 self.sourceMenu.addSeparator()
310 act = self.sourceMenu.addAction(
311 self.tr('Rename file'), self._renameFile)
312 self.menuActions.append(act)
313 act = self.sourceMenu.addAction(
314 self.tr('Remove from project'), self._removeFile)
315 self.menuActions.append(act)
316 act = self.sourceMenu.addAction(
317 self.tr('Delete'), self.__deleteFile)
318 self.menuActions.append(act)
319 self.sourceMenu.addSeparator()
320 self.sourceMenu.addAction(
321 self.tr('Add source files...'), self.__addSourceFiles)
322 self.sourceMenu.addAction(
323 self.tr('Add source directory...'), self.__addSourceDirectory)
324 self.sourceMenu.addSeparator()
325 act = self.sourceMenu.addMenu(self.graphicsMenu)
326 self.sourceMenu.addSeparator()
327 self.sourceMenu.addAction(
328 self.tr('Expand all directories'), self._expandAllDirs)
329 self.sourceMenu.addAction(
330 self.tr('Collapse all directories'), self._collapseAllDirs)
331 self.sourceMenu.addSeparator()
332 self.sourceMenu.addAction(self.tr('Configure...'), self._configure)
333
334 self.menu.addSeparator()
335 self.menu.addAction(
336 self.tr('Add source files...'), self.__addSourceFiles)
337 self.menu.addAction(
338 self.tr('Add source directory...'), self.__addSourceDirectory)
339 self.menu.addSeparator()
340 self.menu.addAction(
341 self.tr('Expand all directories'), self._expandAllDirs)
342 self.menu.addAction(
343 self.tr('Collapse all directories'), self._collapseAllDirs)
344 self.menu.addSeparator()
345 self.menu.addAction(self.tr('Configure...'), self._configure)
346
347 # create the attribute menu
348 self.gotoMenu = QMenu(self.tr("Goto"), self)
349 self.gotoMenu.aboutToShow.connect(self._showGotoMenu)
350 self.gotoMenu.triggered.connect(self._gotoAttribute)
351
352 self.attributeMenu = QMenu(self)
353 self.attributeMenu.addMenu(self.gotoMenu)
354 self.attributeMenu.addSeparator()
355 self.attributeMenu.addAction(
356 self.tr('Add source files...'), self.project.addSourceFiles)
357 self.attributeMenu.addAction(
358 self.tr('Add source directory...'), self.project.addSourceDir)
359 self.attributeMenu.addSeparator()
360 self.attributeMenu.addAction(
361 self.tr('Expand all directories'), self._expandAllDirs)
362 self.attributeMenu.addAction(
363 self.tr('Collapse all directories'), self._collapseAllDirs)
364 self.attributeMenu.addSeparator()
365 self.attributeMenu.addAction(
366 self.tr('Configure...'), self._configure)
367
368 self.backMenu = QMenu(self)
369 self.backMenu.addAction(
370 self.tr('Add source files...'), self.project.addSourceFiles)
371 self.backMenu.addAction(
372 self.tr('Add source directory...'), self.project.addSourceDir)
373 self.backMenu.addSeparator()
374 self.backMenu.addAction(
375 self.tr('Expand all directories'), self._expandAllDirs)
376 self.backMenu.addAction(
377 self.tr('Collapse all directories'), self._collapseAllDirs)
378 self.backMenu.setEnabled(False)
379 self.backMenu.addSeparator()
380 self.backMenu.addAction(self.tr('Configure...'), self._configure)
381
382 self.multiMenu.addSeparator()
383 act = self.multiMenu.addAction(
384 self.tr('Remove from project'), self._removeFile)
385 self.multiMenuActions.append(act)
386 act = self.multiMenu.addAction(
387 self.tr('Delete'), self.__deleteFile)
388 self.multiMenuActions.append(act)
389 self.multiMenu.addSeparator()
390 self.multiMenu.addAction(
391 self.tr('Expand all directories'), self._expandAllDirs)
392 self.multiMenu.addAction(
393 self.tr('Collapse all directories'), self._collapseAllDirs)
394 self.multiMenu.addSeparator()
395 self.multiMenu.addAction(self.tr('Configure...'), self._configure)
396
397 self.dirMenu = QMenu(self)
398 act = self.dirMenu.addAction(
399 self.tr('Remove from project'), self._removeDir)
400 self.dirMenuActions.append(act)
401 self.dirMenu.addSeparator()
402 self.dirMenu.addAction(
403 self.tr('Add source files...'), self.__addSourceFiles)
404 self.dirMenu.addAction(
405 self.tr('Add source directory...'), self.__addSourceDirectory)
406 self.dirMenu.addSeparator()
407 act = self.dirMenu.addMenu(self.graphicsMenu)
408 self.dirMenu.addSeparator()
409 self.dirMenu.addAction(
410 self.tr('Expand all directories'), self._expandAllDirs)
411 self.dirMenu.addAction(
412 self.tr('Collapse all directories'), self._collapseAllDirs)
413 self.dirMenu.addSeparator()
414 self.dirMenu.addAction(self.tr('Configure...'), self._configure)
415
416 self.dirMultiMenu = QMenu(self)
417 self.dirMultiMenu.addAction(
418 self.tr('Expand all directories'), self._expandAllDirs)
419 self.dirMultiMenu.addAction(
420 self.tr('Collapse all directories'), self._collapseAllDirs)
421 self.dirMultiMenu.addSeparator()
422 self.dirMultiMenu.addAction(
423 self.tr('Configure...'), self._configure)
424
425 self.sourceMenu.aboutToShow.connect(self.__showContextMenu)
426 self.multiMenu.aboutToShow.connect(self.__showContextMenuMulti)
427 self.dirMenu.aboutToShow.connect(self.__showContextMenuDir)
428 self.dirMultiMenu.aboutToShow.connect(self.__showContextMenuDirMulti)
429 self.backMenu.aboutToShow.connect(self.__showContextMenuBack)
430 self.mainMenu = self.sourceMenu
431
432 def __createJavaScriptPopupMenus(self):
433 """
434 Private method to generate the popup menus for a Python project.
435 """
436 self.checksMenu = QMenu(self.tr('Check'))
437 self.checksMenu.aboutToShow.connect(self.__showContextMenuCheck)
438
439 self.sourceMenu.addSeparator()
440 act = self.sourceMenu.addAction(
441 self.tr('Rename file'), self._renameFile)
442 self.menuActions.append(act)
443 act = self.sourceMenu.addAction(
444 self.tr('Remove from project'), self._removeFile)
445 self.menuActions.append(act)
446 act = self.sourceMenu.addAction(
447 self.tr('Delete'), self.__deleteFile)
448 self.menuActions.append(act)
449 self.sourceMenu.addSeparator()
450 self.sourceMenu.addAction(
451 self.tr('Add source files...'), self.__addSourceFiles)
452 self.sourceMenu.addAction(
453 self.tr('Add source directory...'), self.__addSourceDirectory)
454 self.sourceMenu.addSeparator()
455 self.sourceMenu.addMenu(self.checksMenu)
456 self.sourceMenu.addSeparator()
457 self.sourceMenu.addAction(
458 self.tr('Copy Path to Clipboard'), self._copyToClipboard)
459 self.sourceMenu.addSeparator()
460 self.sourceMenu.addAction(
461 self.tr('Expand all directories'), self._expandAllDirs)
462 self.sourceMenu.addAction(
463 self.tr('Collapse all directories'), self._collapseAllDirs)
464 self.sourceMenu.addSeparator()
465 self.sourceMenu.addAction(self.tr('Configure...'), self._configure)
466
467 self.menu.addSeparator()
468 self.menu.addAction(
469 self.tr('Add source files...'), self.__addSourceFiles)
470 self.menu.addAction(
471 self.tr('Add source directory...'), self.__addSourceDirectory)
472 self.menu.addSeparator()
473 self.menu.addAction(
474 self.tr('Expand all directories'), self._expandAllDirs)
475 self.menu.addAction(
476 self.tr('Collapse all directories'), self._collapseAllDirs)
477 self.menu.addSeparator()
478 self.menu.addAction(self.tr('Configure...'), self._configure)
479
480 # create the attribute menu
481 self.gotoMenu = QMenu(self.tr("Goto"), self)
482 self.gotoMenu.aboutToShow.connect(self._showGotoMenu)
483 self.gotoMenu.triggered.connect(self._gotoAttribute)
484
485 self.attributeMenu = QMenu(self)
486 self.attributeMenu.addMenu(self.gotoMenu)
487 self.attributeMenu.addSeparator()
488 self.attributeMenu.addAction(
489 self.tr('Add source files...'), self.project.addSourceFiles)
490 self.attributeMenu.addAction(
491 self.tr('Add source directory...'), self.project.addSourceDir)
492 self.attributeMenu.addSeparator()
493 self.attributeMenu.addAction(
494 self.tr('Expand all directories'), self._expandAllDirs)
495 self.attributeMenu.addAction(
496 self.tr('Collapse all directories'), self._collapseAllDirs)
497 self.attributeMenu.addSeparator()
498 self.attributeMenu.addAction(
499 self.tr('Configure...'), self._configure)
500
501 self.backMenu = QMenu(self)
502 self.backMenu.addAction(
503 self.tr('Add source files...'), self.project.addSourceFiles)
504 self.backMenu.addAction(
505 self.tr('Add source directory...'), self.project.addSourceDir)
506 self.backMenu.addSeparator()
507 self.backMenu.addAction(
508 self.tr('Expand all directories'), self._expandAllDirs)
509 self.backMenu.addAction(
510 self.tr('Collapse all directories'), self._collapseAllDirs)
511 self.backMenu.addSeparator()
512 self.backMenu.addAction(self.tr('Configure...'), self._configure)
513 self.backMenu.setEnabled(False)
514
515 self.multiMenu.addSeparator()
516 act = self.multiMenu.addAction(
517 self.tr('Remove from project'), self._removeFile)
518 self.multiMenuActions.append(act)
519 act = self.multiMenu.addAction(
520 self.tr('Delete'), self.__deleteFile)
521 self.multiMenuActions.append(act)
522 self.multiMenu.addSeparator()
523 self.multiMenu.addMenu(self.checksMenu)
524 self.multiMenu.addSeparator()
525 self.multiMenu.addAction(
526 self.tr('Expand all directories'), self._expandAllDirs)
527 self.multiMenu.addAction(
528 self.tr('Collapse all directories'), self._collapseAllDirs)
529 self.multiMenu.addSeparator()
530 self.multiMenu.addAction(self.tr('Configure...'), self._configure)
531
532 self.dirMenu = QMenu(self)
533 act = self.dirMenu.addAction(
534 self.tr('Remove from project'), self._removeDir)
535 self.dirMenuActions.append(act)
536 act = self.dirMenu.addAction(
537 self.tr('Delete'), self._deleteDirectory)
538 self.dirMenuActions.append(act)
539 self.dirMenu.addSeparator()
540 self.dirMenu.addAction(
541 self.tr('Add source files...'), self.__addSourceFiles)
542 self.dirMenu.addAction(
543 self.tr('Add source directory...'), self.__addSourceDirectory)
544 self.dirMenu.addSeparator()
545 self.dirMenu.addMenu(self.checksMenu)
546 self.dirMenu.addSeparator()
547 self.dirMenu.addAction(
548 self.tr('Copy Path to Clipboard'), self._copyToClipboard)
549 self.dirMenu.addSeparator()
550 self.dirMenu.addAction(
551 self.tr('Expand all directories'), self._expandAllDirs)
552 self.dirMenu.addAction(
553 self.tr('Collapse all directories'), self._collapseAllDirs)
554 self.dirMenu.addSeparator()
555 self.dirMenu.addAction(self.tr('Configure...'), self._configure)
556
557 self.dirMultiMenu = QMenu(self)
558 self.dirMultiMenu.addAction(
559 self.tr('Expand all directories'), self._expandAllDirs)
560 self.dirMultiMenu.addAction(
561 self.tr('Collapse all directories'), self._collapseAllDirs)
562 self.dirMultiMenu.addSeparator()
563 self.dirMultiMenu.addAction(
564 self.tr('Configure...'), self._configure)
565
566 self.sourceMenu.aboutToShow.connect(self.__showContextMenu)
567 self.multiMenu.aboutToShow.connect(self.__showContextMenuMulti)
568 self.dirMenu.aboutToShow.connect(self.__showContextMenuDir)
569 self.dirMultiMenu.aboutToShow.connect(self.__showContextMenuDirMulti)
570 self.backMenu.aboutToShow.connect(self.__showContextMenuBack)
571 self.mainMenu = self.sourceMenu
572
573 def _contextMenuRequested(self, coord):
574 """
575 Protected slot to show the context menu.
576
577 @param coord the position of the mouse pointer (QPoint)
578 """
579 if not self.project.isOpen():
580 return
581
582 try:
583 categories = self.getSelectedItemsCountCategorized(
584 [ProjectBrowserFileItem, BrowserClassItem,
585 BrowserMethodItem, ProjectBrowserSimpleDirectoryItem,
586 BrowserClassAttributeItem, BrowserImportItem])
587 cnt = categories["sum"]
588 if cnt <= 1:
589 index = self.indexAt(coord)
590 if index.isValid():
591 self._selectSingleItem(index)
592 categories = self.getSelectedItemsCountCategorized(
593 [ProjectBrowserFileItem, BrowserClassItem,
594 BrowserMethodItem, ProjectBrowserSimpleDirectoryItem,
595 BrowserClassAttributeItem, BrowserImportItem])
596 cnt = categories["sum"]
597
598 bfcnt = categories[str(ProjectBrowserFileItem)]
599 cmcnt = categories[str(BrowserClassItem)] + \
600 categories[str(BrowserMethodItem)] + \
601 categories[str(BrowserClassAttributeItem)] + \
602 categories[str(BrowserImportItem)]
603 sdcnt = categories[str(ProjectBrowserSimpleDirectoryItem)]
604 if cnt > 1 and cnt == bfcnt:
605 self.multiMenu.popup(self.mapToGlobal(coord))
606 elif cnt > 1 and cnt == sdcnt:
607 self.dirMultiMenu.popup(self.mapToGlobal(coord))
608 else:
609 index = self.indexAt(coord)
610 if cnt == 1 and index.isValid():
611 if bfcnt == 1 or cmcnt == 1:
612 itm = self.model().item(index)
613 if isinstance(itm, ProjectBrowserFileItem):
614 fn = itm.fileName()
615 if self.project.isPythonProject():
616 if fn.endswith('.ptl'):
617 for act in self.sourceMenuActions.values():
618 act.setEnabled(False)
619 self.classDiagramAction.setEnabled(True)
620 self.importsDiagramAction.setEnabled(True)
621 self.unittestAction.setEnabled(False)
622 self.checksMenu.menuAction().setEnabled(
623 False)
624 elif fn.endswith('.rb'):
625 # entry for mixed mode programs
626 for act in self.sourceMenuActions.values():
627 act.setEnabled(False)
628 self.classDiagramAction.setEnabled(True)
629 self.importsDiagramAction.setEnabled(False)
630 self.unittestAction.setEnabled(False)
631 self.checksMenu.menuAction().setEnabled(
632 False)
633 elif fn.endswith('.js'):
634 # entry for mixed mode programs
635 for act in self.sourceMenuActions.values():
636 act.setEnabled(False)
637 self.unittestAction.setEnabled(False)
638 self.checksMenu.menuAction().setEnabled(
639 False)
640 self.graphicsMenu.menuAction().setEnabled(
641 False)
642 else:
643 # assume the source file is a Python file
644 for act in self.sourceMenuActions.values():
645 act.setEnabled(True)
646 self.classDiagramAction.setEnabled(True)
647 self.importsDiagramAction.setEnabled(True)
648 self.unittestAction.setEnabled(True)
649 self.checksMenu.menuAction().setEnabled(
650 True)
651 self.sourceMenu.popup(self.mapToGlobal(coord))
652 elif isinstance(itm, BrowserClassItem) or \
653 isinstance(itm, BrowserMethodItem) or \
654 isinstance(itm, BrowserImportItem):
655 self.menu.popup(self.mapToGlobal(coord))
656 elif isinstance(itm, BrowserClassAttributeItem):
657 self.attributeMenu.popup(self.mapToGlobal(coord))
658 else:
659 self.backMenu.popup(self.mapToGlobal(coord))
660 elif sdcnt == 1:
661 self.classDiagramAction.setEnabled(False)
662 self.dirMenu.popup(self.mapToGlobal(coord))
663 else:
664 self.backMenu.popup(self.mapToGlobal(coord))
665 else:
666 self.backMenu.popup(self.mapToGlobal(coord))
667 except Exception:
668 pass
669
670 def __showContextMenu(self):
671 """
672 Private slot called by the sourceMenu aboutToShow signal.
673 """
674 ProjectBaseBrowser._showContextMenu(self, self.sourceMenu)
675
676 self.showMenu.emit("Main", self.sourceMenu)
677
678 def __showContextMenuMulti(self):
679 """
680 Private slot called by the multiMenu aboutToShow signal.
681 """
682 ProjectBaseBrowser._showContextMenuMulti(self, self.multiMenu)
683
684 self.showMenu.emit("MainMulti", self.multiMenu)
685
686 def __showContextMenuDir(self):
687 """
688 Private slot called by the dirMenu aboutToShow signal.
689 """
690 ProjectBaseBrowser._showContextMenuDir(self, self.dirMenu)
691
692 self.showMenu.emit("MainDir", self.dirMenu)
693
694 def __showContextMenuDirMulti(self):
695 """
696 Private slot called by the dirMultiMenu aboutToShow signal.
697 """
698 ProjectBaseBrowser._showContextMenuDirMulti(self, self.dirMultiMenu)
699
700 self.showMenu.emit("MainDirMulti", self.dirMultiMenu)
701
702 def __showContextMenuBack(self):
703 """
704 Private slot called by the backMenu aboutToShow signal.
705 """
706 ProjectBaseBrowser._showContextMenuBack(self, self.backMenu)
707
708 self.showMenu.emit("MainBack", self.backMenu)
709
710 def __showContextMenuShow(self):
711 """
712 Private slot called before the show menu is shown.
713 """
714 prEnable = False
715 coEnable = False
716
717 # first check if the file belongs to a project and there is
718 # a project coverage file
719 fn = self.project.getMainScript(True)
720 if fn is not None:
721 tfn = Utilities.getTestFileName(fn)
722 basename = os.path.splitext(fn)[0]
723 tbasename = os.path.splitext(tfn)[0]
724 prEnable = prEnable or \
725 os.path.isfile("{0}.profile".format(basename)) or \
726 os.path.isfile("{0}.profile".format(tbasename))
727 coEnable = (coEnable or
728 os.path.isfile("{0}.coverage".format(basename)) or
729 os.path.isfile("{0}.coverage".format(tbasename))) and \
730 (self.project.isPy3Project() or self.project.isPy2Project())
731
732 # now check the selected item
733 itm = self.model().item(self.currentIndex())
734 fn = itm.fileName()
735 if fn is not None:
736 basename = os.path.splitext(fn)[0]
737 prEnable = prEnable or \
738 os.path.isfile("{0}.profile".format(basename))
739 coEnable = (coEnable or
740 os.path.isfile("{0}.coverage".format(basename))) and \
741 (itm.isPython3File() or itm.isPython2File())
742
743 self.profileMenuAction.setEnabled(prEnable)
744 self.coverageMenuAction.setEnabled(coEnable)
745
746 self.showMenu.emit("Show", self.menuShow)
747
748 def _openItem(self):
749 """
750 Protected slot to handle the open popup menu entry.
751 """
752 itmList = self.getSelectedItems(
753 [BrowserFileItem, BrowserClassItem, BrowserMethodItem,
754 BrowserClassAttributeItem, BrowserImportItem])
755
756 for itm in itmList:
757 if isinstance(itm, BrowserFileItem):
758 if itm.isPython2File():
759 self.sourceFile[str].emit(itm.fileName())
760 elif itm.isPython3File():
761 self.sourceFile[str].emit(itm.fileName())
762 elif itm.isRubyFile():
763 self.sourceFile[str, int, str].emit(
764 itm.fileName(), -1, "Ruby")
765 elif itm.isDFile():
766 self.sourceFile[str, int, str].emit(
767 itm.fileName(), -1, "D")
768 else:
769 self.sourceFile[str].emit(itm.fileName())
770 elif isinstance(itm, BrowserClassItem):
771 self.sourceFile[str, int].emit(
772 itm.fileName(), itm.classObject().lineno)
773 elif isinstance(itm, BrowserMethodItem):
774 self.sourceFile[str, int].emit(
775 itm.fileName(), itm.functionObject().lineno)
776 elif isinstance(itm, BrowserClassAttributeItem):
777 self.sourceFile[str, int].emit(
778 itm.fileName(), itm.attributeObject().lineno)
779 elif isinstance(itm, BrowserImportItem):
780 self.sourceFile[str, list].emit(
781 itm.fileName(), itm.linenos())
782
783 def __addNewPackage(self):
784 """
785 Private method to add a new package to the project.
786 """
787 itm = self.model().item(self.currentIndex())
788 if isinstance(itm, ProjectBrowserFileItem) or \
789 isinstance(itm, BrowserClassItem) or \
790 isinstance(itm, BrowserMethodItem):
791 dn = os.path.dirname(itm.fileName())
792 elif isinstance(itm, ProjectBrowserSimpleDirectoryItem) or \
793 isinstance(itm, ProjectBrowserDirectoryItem):
794 dn = itm.dirName()
795 else:
796 dn = ""
797
798 dn = self.project.getRelativePath(dn)
799 if dn.startswith(os.sep):
800 dn = dn[1:]
801 from .NewPythonPackageDialog import NewPythonPackageDialog
802 dlg = NewPythonPackageDialog(dn, self)
803 if dlg.exec_() == QDialog.Accepted:
804 packageName = dlg.getData()
805 nameParts = packageName.split(".")
806 packagePath = self.project.ppath
807 packageFile = ""
808 for name in nameParts:
809 packagePath = os.path.join(packagePath, name)
810 if not os.path.exists(packagePath):
811 try:
812 os.mkdir(packagePath)
813 except OSError as err:
814 E5MessageBox.critical(
815 self,
816 self.tr("Add new Python package"),
817 self.tr(
818 """<p>The package directory <b>{0}</b> could"""
819 """ not be created. Aborting...</p>"""
820 """<p>Reason: {1}</p>""")
821 .format(packagePath, str(err)))
822 return
823 packageFile = os.path.join(packagePath, "__init__.py")
824 if not os.path.exists(packageFile):
825 try:
826 f = open(packageFile, "w", encoding="utf-8")
827 f.close()
828 except IOError as err:
829 E5MessageBox.critical(
830 self,
831 self.tr("Add new Python package"),
832 self.tr(
833 """<p>The package file <b>{0}</b> could"""
834 """ not be created. Aborting...</p>"""
835 """<p>Reason: {1}</p>""")
836 .format(packageFile, str(err)))
837 return
838 self.project.appendFile(packageFile)
839 if packageFile:
840 self.sourceFile[str].emit(packageFile)
841
842 def __addSourceFiles(self):
843 """
844 Private method to add a source file to the project.
845 """
846 itm = self.model().item(self.currentIndex())
847 if isinstance(itm, ProjectBrowserFileItem) or \
848 isinstance(itm, BrowserClassItem) or \
849 isinstance(itm, BrowserMethodItem):
850 dn = os.path.dirname(itm.fileName())
851 elif isinstance(itm, ProjectBrowserSimpleDirectoryItem) or \
852 isinstance(itm, ProjectBrowserDirectoryItem):
853 dn = itm.dirName()
854 else:
855 dn = None
856 self.project.addFiles('source', dn)
857
858 def __addSourceDirectory(self):
859 """
860 Private method to add source files of a directory to the project.
861 """
862 itm = self.model().item(self.currentIndex())
863 if isinstance(itm, ProjectBrowserFileItem) or \
864 isinstance(itm, BrowserClassItem) or \
865 isinstance(itm, BrowserMethodItem):
866 dn = os.path.dirname(itm.fileName())
867 elif isinstance(itm, ProjectBrowserSimpleDirectoryItem) or \
868 isinstance(itm, ProjectBrowserDirectoryItem):
869 dn = itm.dirName()
870 else:
871 dn = None
872 self.project.addDirectory('source', dn)
873
874 def __deleteFile(self):
875 """
876 Private method to delete files from the project.
877 """
878 itmList = self.getSelectedItems()
879
880 files = []
881 fullNames = []
882 for itm in itmList:
883 fn2 = itm.fileName()
884 fullNames.append(fn2)
885 fn = self.project.getRelativePath(fn2)
886 files.append(fn)
887
888 from UI.DeleteFilesConfirmationDialog import \
889 DeleteFilesConfirmationDialog
890 dlg = DeleteFilesConfirmationDialog(
891 self.parent(),
892 self.tr("Delete files"),
893 self.tr(
894 "Do you really want to delete these files from the project?"),
895 files)
896
897 if dlg.exec_() == QDialog.Accepted:
898 for fn2, fn in zip(fullNames, files):
899 self.closeSourceWindow.emit(fn2)
900 self.project.deleteFile(fn)
901
902 ###########################################################################
903 ## Methods for the Checks submenu
904 ###########################################################################
905
906 def __showContextMenuCheck(self):
907 """
908 Private slot called before the checks menu is shown.
909 """
910 self.showMenu.emit("Checks", self.checksMenu)
911
912 ###########################################################################
913 ## Methods for the Show submenu
914 ###########################################################################
915
916 def __showCodeMetrics(self):
917 """
918 Private method to handle the code metrics context menu action.
919 """
920 itm = self.model().item(self.currentIndex())
921 fn = itm.fileName()
922
923 from DataViews.CodeMetricsDialog import CodeMetricsDialog
924 self.codemetrics = CodeMetricsDialog()
925 self.codemetrics.show()
926 self.codemetrics.start(fn)
927
928 def __showCodeCoverage(self):
929 """
930 Private method to handle the code coverage context menu action.
931 """
932 itm = self.model().item(self.currentIndex())
933 fn = itm.fileName()
934 pfn = self.project.getMainScript(True)
935
936 files = []
937
938 if pfn is not None:
939 tpfn = Utilities.getTestFileName(pfn)
940 basename = os.path.splitext(pfn)[0]
941 tbasename = os.path.splitext(tpfn)[0]
942
943 f = "{0}.coverage".format(basename)
944 tf = "{0}.coverage".format(tbasename)
945 if os.path.isfile(f):
946 files.append(f)
947 if os.path.isfile(tf):
948 files.append(tf)
949
950 if fn is not None:
951 tfn = Utilities.getTestFileName(fn)
952 basename = os.path.splitext(fn)[0]
953 tbasename = os.path.splitext(tfn)[0]
954
955 f = "{0}.coverage".format(basename)
956 tf = "{0}.coverage".format(tbasename)
957 if os.path.isfile(f) and f not in files:
958 files.append(f)
959 if os.path.isfile(tf) and tf not in files:
960 files.append(tf)
961
962 if files:
963 if len(files) > 1:
964 pfn, ok = QInputDialog.getItem(
965 None,
966 self.tr("Code Coverage"),
967 self.tr("Please select a coverage file"),
968 files,
969 0, False)
970 if not ok:
971 return
972 else:
973 pfn = files[0]
974 else:
975 return
976
977 from DataViews.PyCoverageDialog import PyCoverageDialog
978 self.codecoverage = PyCoverageDialog()
979 self.codecoverage.show()
980 self.codecoverage.start(pfn, fn)
981
982 def __showProfileData(self):
983 """
984 Private method to handle the show profile data context menu action.
985 """
986 itm = self.model().item(self.currentIndex())
987 fn = itm.fileName()
988 pfn = self.project.getMainScript(True)
989
990 files = []
991
992 if pfn is not None:
993 tpfn = Utilities.getTestFileName(pfn)
994 basename = os.path.splitext(pfn)[0]
995 tbasename = os.path.splitext(tpfn)[0]
996
997 f = "{0}.profile".format(basename)
998 tf = "{0}.profile".format(tbasename)
999 if os.path.isfile(f):
1000 files.append(f)
1001 if os.path.isfile(tf):
1002 files.append(tf)
1003
1004 if fn is not None:
1005 tfn = Utilities.getTestFileName(fn)
1006 basename = os.path.splitext(fn)[0]
1007 tbasename = os.path.splitext(tfn)[0]
1008
1009 f = "{0}.profile".format(basename)
1010 tf = "{0}.profile".format(tbasename)
1011 if os.path.isfile(f) and f not in files:
1012 files.append(f)
1013 if os.path.isfile(tf) and tf not in files:
1014 files.append(tf)
1015
1016 if files:
1017 if len(files) > 1:
1018 pfn, ok = QInputDialog.getItem(
1019 None,
1020 self.tr("Profile Data"),
1021 self.tr("Please select a profile file"),
1022 files,
1023 0, False)
1024 if not ok:
1025 return
1026 else:
1027 pfn = files[0]
1028 else:
1029 return
1030
1031 from DataViews.PyProfileDialog import PyProfileDialog
1032 self.profiledata = PyProfileDialog()
1033 self.profiledata.show()
1034 self.profiledata.start(pfn, fn)
1035
1036 ###########################################################################
1037 ## Methods for the Graphics submenu
1038 ###########################################################################
1039
1040 def __showContextMenuGraphics(self):
1041 """
1042 Private slot called before the checks menu is shown.
1043 """
1044 self.showMenu.emit("Graphics", self.graphicsMenu)
1045
1046 def __showClassDiagram(self):
1047 """
1048 Private method to handle the class diagram context menu action.
1049 """
1050 itm = self.model().item(self.currentIndex())
1051 try:
1052 fn = itm.fileName()
1053 except AttributeError:
1054 fn = itm.dirName()
1055 res = E5MessageBox.yesNo(
1056 self,
1057 self.tr("Class Diagram"),
1058 self.tr("""Include class attributes?"""),
1059 yesDefault=True)
1060 from Graphics.UMLDialog import UMLDialog
1061 self.classDiagram = UMLDialog(UMLDialog.ClassDiagram, self.project, fn,
1062 self, noAttrs=not res)
1063 self.classDiagram.show()
1064
1065 def __showImportsDiagram(self):
1066 """
1067 Private method to handle the imports diagram context menu action.
1068 """
1069 itm = self.model().item(self.currentIndex())
1070 try:
1071 fn = itm.fileName()
1072 except AttributeError:
1073 fn = itm.dirName()
1074 package = os.path.isdir(fn) and fn or os.path.dirname(fn)
1075 res = E5MessageBox.yesNo(
1076 self,
1077 self.tr("Imports Diagram"),
1078 self.tr("""Include imports from external modules?"""))
1079 from Graphics.UMLDialog import UMLDialog
1080 self.importsDiagram = UMLDialog(
1081 UMLDialog.ImportsDiagram, self.project, package,
1082 self, showExternalImports=res)
1083 self.importsDiagram.show()
1084
1085 def __showPackageDiagram(self):
1086 """
1087 Private method to handle the package diagram context menu action.
1088 """
1089 itm = self.model().item(self.currentIndex())
1090 try:
1091 fn = itm.fileName()
1092 except AttributeError:
1093 fn = itm.dirName()
1094 package = os.path.isdir(fn) and fn or os.path.dirname(fn)
1095 res = E5MessageBox.yesNo(
1096 self,
1097 self.tr("Package Diagram"),
1098 self.tr("""Include class attributes?"""),
1099 yesDefault=True)
1100 from Graphics.UMLDialog import UMLDialog
1101 self.packageDiagram = UMLDialog(
1102 UMLDialog.PackageDiagram, self.project, package,
1103 self, noAttrs=not res)
1104 self.packageDiagram.show()
1105
1106 def __showApplicationDiagram(self):
1107 """
1108 Private method to handle the application diagram context menu action.
1109 """
1110 res = E5MessageBox.yesNo(
1111 self,
1112 self.tr("Application Diagram"),
1113 self.tr("""Include module names?"""),
1114 yesDefault=True)
1115 from Graphics.UMLDialog import UMLDialog
1116 self.applicationDiagram = UMLDialog(
1117 UMLDialog.ApplicationDiagram, self.project,
1118 self, noModules=not res)
1119 self.applicationDiagram.show()
1120
1121 def __loadDiagram(self):
1122 """
1123 Private slot to load a diagram from file.
1124 """
1125 from Graphics.UMLDialog import UMLDialog
1126 self.loadedDiagram = None
1127 loadedDiagram = UMLDialog(
1128 UMLDialog.NoDiagram, self.project, parent=self)
1129 if loadedDiagram.load():
1130 self.loadedDiagram = loadedDiagram
1131 self.loadedDiagram.show(fromFile=True)

eric ide

mercurial