~ubuntu-branches/ubuntu/karmic/eric/karmic

« back to all changes in this revision

Viewing changes to eric/Project/ProjectSourcesBrowser.py

  • Committer: Bazaar Package Importer
  • Author(s): Scott Kitterman
  • Date: 2008-01-28 18:02:25 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080128180225-6nrox6yrworh2c4v
Tags: 4.0.4-1ubuntu1
* Add python-qt3 to build-depends becuase that's where Ubuntu puts 
  pyqtconfig
* Change maintainer to MOTU

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
 
 
3
# Copyright (c) 2002 - 2007 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
import os
 
11
import sys
 
12
 
 
13
from PyQt4.QtCore import *
 
14
from PyQt4.QtGui import *
 
15
 
 
16
from KdeQt import KQMessageBox, KQInputDialog
 
17
from KdeQt.KQApplication import e4App
 
18
 
 
19
from Checks import Checkers
 
20
 
 
21
from UI.BrowserModel import BrowserClassItem, BrowserMethodItem
 
22
from UI.DeleteFilesConfirmationDialog import DeleteFilesConfirmationDialog
 
23
import UI.PixmapCache
 
24
 
 
25
from DataViews.CodeMetricsDialog import CodeMetricsDialog
 
26
from DataViews.PyCoverageDialog import PyCoverageDialog
 
27
from DataViews.PyProfileDialog import PyProfileDialog
 
28
 
 
29
from Graphics.UMLClassDiagram import UMLClassDiagram
 
30
from Graphics.ImportsDiagram import ImportsDiagram
 
31
from Graphics.ApplicationDiagram import ApplicationDiagram
 
32
from Graphics.PackageDiagram import PackageDiagram
 
33
 
 
34
from ProjectBrowserModel import ProjectBrowserFileItem, \
 
35
    ProjectBrowserSimpleDirectoryItem, ProjectBrowserDirectoryItem, \
 
36
    ProjectBrowserSourceType
 
37
from ProjectBaseBrowser import ProjectBaseBrowser
 
38
 
 
39
import Utilities
 
40
 
 
41
class ProjectSourcesBrowser(ProjectBaseBrowser):
 
42
    """
 
43
    A class used to display the Sources part of the project. 
 
44
    
 
45
    @signal closeSourceWindow(string) emitted after a file has been removed/deleted 
 
46
            from the project
 
47
    """
 
48
    def __init__(self, project, parent = None):
 
49
        """
 
50
        Constructor
 
51
        
 
52
        @param project reference to the project object
 
53
        @param parent parent widget of this browser (QWidget)
 
54
        """
 
55
        self.checkers = Checkers(self, parent)
 
56
        
 
57
        ProjectBaseBrowser.__init__(self, project, ProjectBrowserSourceType, parent)
 
58
        
 
59
        self.selectedItemsFilter = \
 
60
            [ProjectBrowserFileItem, ProjectBrowserSimpleDirectoryItem]
 
61
        
 
62
        self.setWindowTitle(self.trUtf8('Sources'))
 
63
 
 
64
        self.setWhatsThis(self.trUtf8(
 
65
            """<b>Project Sources Browser</b>"""
 
66
            """<p>This allows to easily see all sources contained in the current"""
 
67
            """ project. Several actions can be executed via the context menu.</p>"""
 
68
        ))
 
69
        
 
70
        self.connect(project, SIGNAL("prepareRepopulateItem"), 
 
71
            self._prepareRepopulateItem)
 
72
        self.connect(project, SIGNAL("completeRepopulateItem"),
 
73
            self._completeRepopulateItem)
 
74
        
 
75
        self.codemetrics        = None
 
76
        self.codecoverage       = None
 
77
        self.profiledata        = None
 
78
        self.classDiagram       = None
 
79
        self.importsDiagram     = None
 
80
        self.packageDiagram     = None
 
81
        self.applicationDiagram = None
 
82
        
 
83
    def __closeAllWindows(self):
 
84
        """
 
85
        Private method to close all project related windows.
 
86
        """
 
87
        self.codemetrics        and self.codemetrics.close()
 
88
        self.codecoverage       and self.codecoverage.close()
 
89
        self.profiledata        and self.profiledata.close()
 
90
        self.checkers.closeAllWindows()
 
91
        self.classDiagram       and self.classDiagram.close()
 
92
        self.importsDiagram     and self.importsDiagram.close()
 
93
        self.packageDiagram     and self.packageDiagram.close()
 
94
        self.applicationDiagram and self.applicationDiagram.close()
 
95
        
 
96
    def _projectClosed(self):
 
97
        """
 
98
        Protected slot to handle the projectClosed signal.
 
99
        """
 
100
        self.__closeAllWindows()
 
101
        ProjectBaseBrowser._projectClosed(self)
 
102
        
 
103
    def _createPopupMenus(self):
 
104
        """
 
105
        Protected overloaded method to generate the popup menu.
 
106
        """
 
107
        ProjectBaseBrowser._createPopupMenus(self)
 
108
        self.sourceMenuActions = {}
 
109
        
 
110
        if self.project.pdata["PROGLANGUAGE"][0] == "Python":
 
111
            self.__createPythonPopupMenus()
 
112
        elif self.project.pdata["PROGLANGUAGE"][0] == "Ruby":
 
113
            self.__createRubyPopupMenus()
 
114
        
 
115
    def __createPythonPopupMenus(self):
 
116
        """
 
117
        Privat method to generate the popup menus for a Python project.
 
118
        """
 
119
        self.checkers.initActions()
 
120
        self.checksMenu = self.checkers.initMenu()
 
121
        self.checksMenu.setTitle(self.trUtf8('Check'))
 
122
        
 
123
        self.showMenu = QMenu(self.trUtf8('Show'))
 
124
        self.showMenu.addAction(self.trUtf8('Code metrics...'), self.__showCodeMetrics)
 
125
        self.coverageMenuAction = self.showMenu.addAction(\
 
126
            self.trUtf8('Code coverage...'), self.__showCodeCoverage)
 
127
        self.profileMenuAction = self.showMenu.addAction(\
 
128
            self.trUtf8('Profile data...'), self.__showProfileData)
 
129
        self.cyclopsMenuAction = self.showMenu.addAction(\
 
130
            self.trUtf8('Cyclops report...'), self.__showCyclopsReport)
 
131
        self.removeCyclopsMenuAction = self.showMenu.addAction(\
 
132
            self.trUtf8('Remove cyclops report'), self.__removeCyclopsReport)
 
133
        self.connect(self.showMenu,SIGNAL('aboutToShow()'),self.__showShowMenu)
 
134
        
 
135
        self.graphicsMenu = QMenu(self.trUtf8('Diagrams'))
 
136
        self.classDiagramAction = self.graphicsMenu.addAction(\
 
137
            self.trUtf8("Class Diagram..."), self.__showClassDiagram)
 
138
        self.graphicsMenu.addAction(\
 
139
            self.trUtf8("Package Diagram..."), self.__showPackageDiagram)
 
140
        self.importsDiagramAction = self.graphicsMenu.addAction(\
 
141
            self.trUtf8("Imports Diagram..."), self.__showImportsDiagram)
 
142
        self.graphicsMenu.addAction(\
 
143
            self.trUtf8("Application Diagram..."), self.__showApplicationDiagram)
 
144
        
 
145
        self.unittestAction = self.sourceMenu.addAction(\
 
146
            self.trUtf8('Run unittest...'), self.handleUnittest)
 
147
        self.sourceMenu.addSeparator()
 
148
        act = self.sourceMenu.addAction(self.trUtf8('Rename file'), self._renameFile)
 
149
        self.menuActions.append(act)
 
150
        act = self.sourceMenu.addAction(self.trUtf8('Remove from project'), 
 
151
            self._removeFile)
 
152
        self.menuActions.append(act)
 
153
        act = self.sourceMenu.addAction(self.trUtf8('Delete'), self.__deleteFile)
 
154
        self.menuActions.append(act)
 
155
        self.sourceMenu.addSeparator()
 
156
        self.sourceMenu.addAction(self.trUtf8('Add source files...'), 
 
157
            self.__addSourceFiles)
 
158
        self.sourceMenu.addAction(self.trUtf8('Add source directory...'), 
 
159
            self.__addSourceDirectory)
 
160
        self.sourceMenu.addSeparator()
 
161
        act = self.sourceMenu.addMenu(self.graphicsMenu)
 
162
        self.sourceMenu.addSeparator()
 
163
        self.sourceMenuActions["Check"] = \
 
164
            self.sourceMenu.addMenu(self.checksMenu)
 
165
        self.sourceMenu.addSeparator()
 
166
        self.sourceMenuActions["Show"] = \
 
167
            self.sourceMenu.addMenu(self.showMenu)
 
168
        self.sourceMenu.addSeparator()
 
169
        self.sourceMenu.addAction(self.trUtf8('Expand all directories'), 
 
170
            self._expandAllDirs)
 
171
        self.sourceMenu.addAction(self.trUtf8('Collapse all directories'), 
 
172
            self._collapseAllDirs)
 
173
 
 
174
        self.menu.addSeparator()
 
175
        self.menu.addAction(self.trUtf8('Add source files...'), self.__addSourceFiles)
 
176
        self.menu.addAction(self.trUtf8('Add source directory...'), 
 
177
            self.__addSourceDirectory)
 
178
        self.menu.addSeparator()
 
179
        self.menu.addAction(self.trUtf8('Expand all directories'), 
 
180
            self._expandAllDirs)
 
181
        self.menu.addAction(self.trUtf8('Collapse all directories'), 
 
182
            self._collapseAllDirs)
 
183
 
 
184
        self.backMenu = QMenu(self)
 
185
        self.backMenu.addAction(self.trUtf8('Add source files...'), 
 
186
            self.project.addSourceFiles)
 
187
        self.backMenu.addAction(self.trUtf8('Add source directory...'), 
 
188
            self.project.addSourceDir)
 
189
        self.backMenu.addSeparator()
 
190
        self.backMenu.addAction(self.trUtf8('Expand all directories'), 
 
191
            self._expandAllDirs)
 
192
        self.backMenu.addAction(self.trUtf8('Collapse all directories'), 
 
193
            self._collapseAllDirs)
 
194
        self.backMenu.setEnabled(False)
 
195
        
 
196
        self.multiMenu.addSeparator()
 
197
        act = self.multiMenu.addAction(self.trUtf8('Remove from project'), 
 
198
            self._removeFile)
 
199
        self.multiMenuActions.append(act)
 
200
        act = self.multiMenu.addAction(self.trUtf8('Delete'), self.__deleteFile)
 
201
        self.multiMenuActions.append(act)
 
202
        self.multiMenu.addSeparator()
 
203
        self.multiMenu.addAction(self.trUtf8('Expand all directories'), 
 
204
            self._expandAllDirs)
 
205
        self.multiMenu.addAction(self.trUtf8('Collapse all directories'), 
 
206
            self._collapseAllDirs)
 
207
        
 
208
        self.dirMenu = QMenu(self)
 
209
        act = self.dirMenu.addAction(self.trUtf8('Remove from project'), self._removeDir)
 
210
        self.dirMenuActions.append(act)
 
211
        self.dirMenu.addSeparator()
 
212
        self.dirMenu.addAction(self.trUtf8('Add source files...'), self.__addSourceFiles)
 
213
        self.dirMenu.addAction(self.trUtf8('Add source directory...'), 
 
214
            self.__addSourceDirectory)
 
215
        self.dirMenu.addSeparator()
 
216
        act = self.dirMenu.addMenu(self.graphicsMenu)        
 
217
        self.dirMenu.addSeparator()
 
218
        self.dirMenu.addMenu(self.checksMenu)
 
219
        self.dirMenu.addSeparator()
 
220
        self.dirMenu.addAction(self.trUtf8('Expand all directories'), 
 
221
            self._expandAllDirs)
 
222
        self.dirMenu.addAction(self.trUtf8('Collapse all directories'), 
 
223
            self._collapseAllDirs)
 
224
        
 
225
        self.dirMultiMenu = QMenu(self)
 
226
        self.dirMultiMenu.addAction(self.trUtf8('Expand all directories'), 
 
227
            self._expandAllDirs)
 
228
        self.dirMultiMenu.addAction(self.trUtf8('Collapse all directories'), 
 
229
            self._collapseAllDirs)
 
230
        
 
231
        self.connect(self.sourceMenu, SIGNAL('aboutToShow()'),
 
232
            self.__showPopupMenu)
 
233
        self.connect(self.multiMenu, SIGNAL('aboutToShow()'),
 
234
            self.__showPopupMenuMulti)
 
235
        self.connect(self.dirMenu, SIGNAL('aboutToShow()'),
 
236
            self.__showPopupMenuDir)
 
237
        self.connect(self.dirMultiMenu, SIGNAL('aboutToShow()'),
 
238
            self.__showPopupMenuDirMulti)
 
239
        self.mainMenu = self.sourceMenu
 
240
        
 
241
    def __createRubyPopupMenus(self):
 
242
        """
 
243
        Privat method to generate the popup menus for a Ruby project.
 
244
        """
 
245
        self.graphicsMenu = QMenu(self.trUtf8('Diagrams'))
 
246
        self.classDiagramAction = self.graphicsMenu.addAction(\
 
247
            self.trUtf8("Class Diagram..."), self.__showClassDiagram)
 
248
        self.graphicsMenu.addAction(self.trUtf8("Package Diagram..."), 
 
249
            self.__showPackageDiagram)
 
250
        self.graphicsMenu.addAction(self.trUtf8("Application Diagram..."), 
 
251
            self.__showApplicationDiagram)
 
252
        
 
253
        self.sourceMenu.addSeparator()
 
254
        act = self.sourceMenu.addAction(self.trUtf8('Rename file'), self._renameFile)
 
255
        self.menuActions.append(act)
 
256
        act = self.sourceMenu.addAction(self.trUtf8('Remove from project'), 
 
257
            self._removeFile)
 
258
        self.menuActions.append(act)
 
259
        act = self.sourceMenu.addAction(self.trUtf8('Delete'), self.__deleteFile)
 
260
        self.menuActions.append(act)
 
261
        self.sourceMenu.addSeparator()
 
262
        self.sourceMenu.addAction(self.trUtf8('Add source files...'), 
 
263
            self.__addSourceFiles)
 
264
        self.sourceMenu.addAction(self.trUtf8('Add source directory...'), 
 
265
            self.__addSourceDirectory)
 
266
        self.sourceMenu.addSeparator()
 
267
        act = self.sourceMenu.addMenu(self.graphicsMenu)
 
268
        self.sourceMenu.addSeparator()
 
269
        self.sourceMenu.addAction(self.trUtf8('Expand all directories'), 
 
270
            self._expandAllDirs)
 
271
        self.sourceMenu.addAction(self.trUtf8('Collapse all directories'), 
 
272
            self._collapseAllDirs)
 
273
 
 
274
        self.menu.addSeparator()
 
275
        self.menu.addAction(self.trUtf8('Add source files...'), self.__addSourceFiles)
 
276
        self.menu.addAction(self.trUtf8('Add source directory...'), 
 
277
            self.__addSourceDirectory)
 
278
        self.menu.addSeparator()
 
279
        self.menu.addAction(self.trUtf8('Expand all directories'), 
 
280
            self._expandAllDirs)
 
281
        self.menu.addAction(self.trUtf8('Collapse all directories'), 
 
282
            self._collapseAllDirs)
 
283
 
 
284
        self.backMenu = QMenu(self)
 
285
        self.backMenu.addAction(self.trUtf8('Add source files...'), 
 
286
            self.project.addSourceFiles)
 
287
        self.backMenu.addAction(self.trUtf8('Add source directory...'), 
 
288
            self.project.addSourceDir)
 
289
        self.backMenu.addSeparator()
 
290
        self.backMenu.addAction(self.trUtf8('Expand all directories'), 
 
291
            self._expandAllDirs)
 
292
        self.backMenu.addAction(self.trUtf8('Collapse all directories'), 
 
293
            self._collapseAllDirs)
 
294
        self.backMenu.setEnabled(False)
 
295
        
 
296
        self.multiMenu.addSeparator()
 
297
        act = self.multiMenu.addAction(self.trUtf8('Remove from project'), 
 
298
            self._removeFile)
 
299
        self.multiMenuActions.append(act)
 
300
        act = self.multiMenu.addAction(self.trUtf8('Delete'), self.__deleteFile)
 
301
        self.multiMenuActions.append(act)
 
302
        self.multiMenu.addSeparator()
 
303
        self.multiMenu.addAction(self.trUtf8('Expand all directories'), 
 
304
            self._expandAllDirs)
 
305
        self.multiMenu.addAction(self.trUtf8('Collapse all directories'), 
 
306
            self._collapseAllDirs)
 
307
        
 
308
        self.dirMenu = QMenu(self)
 
309
        act = self.dirMenu.addAction(self.trUtf8('Remove from project'), self._removeDir)
 
310
        self.dirMenuActions.append(act)
 
311
        self.dirMenu.addSeparator()
 
312
        self.dirMenu.addAction(self.trUtf8('Add source files...'), self.__addSourceFiles)
 
313
        self.dirMenu.addAction(self.trUtf8('Add source directory...'), 
 
314
            self.__addSourceDirectory)
 
315
        self.dirMenu.addSeparator()
 
316
        act = self.dirMenu.addMenu(self.graphicsMenu)        
 
317
        self.dirMenu.addSeparator()
 
318
        self.dirMenu.addAction(self.trUtf8('Expand all directories'), 
 
319
            self._expandAllDirs)
 
320
        self.dirMenu.addAction(self.trUtf8('Collapse all directories'), 
 
321
            self._collapseAllDirs)
 
322
        
 
323
        self.dirMultiMenu = QMenu(self)
 
324
        self.dirMultiMenu.addAction(self.trUtf8('Expand all directories'), 
 
325
            self._expandAllDirs)
 
326
        self.dirMultiMenu.addAction(self.trUtf8('Collapse all directories'), 
 
327
            self._collapseAllDirs)
 
328
        
 
329
        self.connect(self.sourceMenu, SIGNAL('aboutToShow()'),
 
330
            self.__showPopupMenu)
 
331
        self.connect(self.multiMenu, SIGNAL('aboutToShow()'),
 
332
            self.__showPopupMenuMulti)
 
333
        self.connect(self.dirMenu, SIGNAL('aboutToShow()'),
 
334
            self.__showPopupMenuDir)
 
335
        self.connect(self.dirMultiMenu, SIGNAL('aboutToShow()'),
 
336
            self.__showPopupMenuDirMulti)
 
337
        self.mainMenu = self.sourceMenu
 
338
        
 
339
    def _showContextMenu(self, coord):
 
340
        """
 
341
        Protected slot to show the context menu.
 
342
        
 
343
        @param coord the position of the mouse pointer (QPoint)
 
344
        """
 
345
        if not self.project.isOpen():
 
346
            return
 
347
        
 
348
        try:
 
349
            categories = self.getSelectedItemsCountCategorized(\
 
350
                [ProjectBrowserFileItem, BrowserClassItem, 
 
351
                 BrowserMethodItem, ProjectBrowserSimpleDirectoryItem])
 
352
            cnt = categories["sum"]
 
353
            if cnt <= 1:
 
354
                index = self.indexAt(coord)
 
355
                if index.isValid():
 
356
                    self._selectSingleItem(index)
 
357
                    categories = self.getSelectedItemsCountCategorized(\
 
358
                        [ProjectBrowserFileItem, BrowserClassItem, 
 
359
                         BrowserMethodItem, ProjectBrowserSimpleDirectoryItem])
 
360
                    cnt = categories["sum"]
 
361
            
 
362
            bfcnt = categories[unicode(ProjectBrowserFileItem)]
 
363
            cmcnt = categories[unicode(BrowserClassItem)] + \
 
364
                    categories[unicode(BrowserMethodItem)]
 
365
            sdcnt = categories[unicode(ProjectBrowserSimpleDirectoryItem)]
 
366
            if cnt > 1 and cnt == bfcnt:
 
367
                self.multiMenu.popup(self.mapToGlobal(coord))
 
368
            elif cnt > 1 and cnt == sdcnt:
 
369
                self.dirMultiMenu.popup(self.mapToGlobal(coord))
 
370
            else:
 
371
                index = self.indexAt(coord)
 
372
                if cnt == 1 and index.isValid():
 
373
                    if bfcnt == 1 or cmcnt == 1:
 
374
                        itm = self.model().item(index)
 
375
                        if isinstance(itm, ProjectBrowserFileItem):
 
376
                            fn = itm.fileName()
 
377
                            if self.project.pdata["PROGLANGUAGE"][0] == "Python":
 
378
                                if fn.endswith('.py') or fn.endswith('.pyw'):
 
379
                                    for act in self.sourceMenuActions.values():
 
380
                                        act.setEnabled(True)
 
381
                                    self.sourceMenuActions["Check"].setEnabled(True)
 
382
                                    self.classDiagramAction.setEnabled(True)
 
383
                                    self.importsDiagramAction.setEnabled(True)
 
384
                                    self.unittestAction.setEnabled(True)
 
385
                                elif fn.endswith('.ptl'):
 
386
                                    for act in self.sourceMenuActions.values():
 
387
                                        act.setEnabled(False)
 
388
                                    self.sourceMenuActions["Check"].setEnabled(True)
 
389
                                    self.classDiagramAction.setEnabled(True)
 
390
                                    self.importsDiagramAction.setEnabled(True)
 
391
                                    self.unittestAction.setEnabled(False)
 
392
                                elif fn.endswith('.rb'):  # entry for mixed mode programs
 
393
                                    for act in self.sourceMenuActions.values():
 
394
                                        act.setEnabled(False)
 
395
                                    self.sourceMenuActions["Check"].setEnabled(False)
 
396
                                    self.classDiagramAction.setEnabled(True)
 
397
                                    self.importsDiagramAction.setEnabled(False)
 
398
                                    self.unittestAction.setEnabled(False)
 
399
                                else:
 
400
                                    for act in self.sourceMenuActions.values():
 
401
                                        act.setEnabled(False)
 
402
                                    self.sourceMenuActions["Check"].setEnabled(False)
 
403
                                    self.classDiagramAction.setEnabled(False)
 
404
                                    self.importsDiagramAction.setEnabled(False)
 
405
                                    self.unittestAction.setEnabled(False)
 
406
                            self.sourceMenu.popup(self.mapToGlobal(coord))
 
407
                        elif isinstance(itm, BrowserClassItem) or \
 
408
                                isinstance(itm, BrowserMethodItem):
 
409
                            self.menu.popup(self.mapToGlobal(coord))
 
410
                        else:
 
411
                            self.backMenu.popup(self.mapToGlobal(coord))
 
412
                    elif sdcnt == 1:
 
413
                        self.classDiagramAction.setEnabled(False)
 
414
                        self.dirMenu.popup(self.mapToGlobal(coord))
 
415
                    else:
 
416
                        self.backMenu.popup(self.mapToGlobal(coord))
 
417
                else:
 
418
                    self.backMenu.popup(self.mapToGlobal(coord))
 
419
        except:
 
420
            pass
 
421
        
 
422
    def __showPopupMenu(self):
 
423
        """
 
424
        Private slot called by the sourceMenu aboutToShow signal.
 
425
        """
 
426
        ProjectBaseBrowser._showPopupMenu(self, self.sourceMenu)
 
427
        
 
428
    def __showPopupMenuMulti(self):
 
429
        """
 
430
        Private slot called by the multiMenu aboutToShow signal.
 
431
        """
 
432
        ProjectBaseBrowser._showPopupMenuMulti(self, self.multiMenu)
 
433
        
 
434
    def __showPopupMenuDir(self):
 
435
        """
 
436
        Private slot called by the dirMenu aboutToShow signal.
 
437
        """
 
438
        ProjectBaseBrowser._showPopupMenuDir(self, self.dirMenu)
 
439
        
 
440
    def __showPopupMenuDirMulti(self):
 
441
        """
 
442
        Private slot called by the dirMultiMenu aboutToShow signal.
 
443
        """
 
444
        ProjectBaseBrowser._showPopupMenuDirMulti(self, self.dirMultiMenu)
 
445
        
 
446
    def __showShowMenu(self):
 
447
        """
 
448
        Private slot called before the show menu is shown.
 
449
        """
 
450
        prEnable = False
 
451
        coEnable = False
 
452
        cyEnable = False
 
453
        
 
454
        # first check if the file belongs to a project and there is
 
455
        # a project coverage file
 
456
        fn = self.project.getMainScript(True)
 
457
        if fn is not None:
 
458
            tfn = Utilities.getTestFileName(fn)
 
459
            basename = os.path.splitext(fn)[0]
 
460
            tbasename = os.path.splitext(tfn)[0]
 
461
            prEnable = prEnable or \
 
462
                os.path.isfile("%s.profile" % basename) or \
 
463
                os.path.isfile("%s.profile" % tbasename)
 
464
            coEnable = coEnable or \
 
465
                os.path.isfile("%s.coverage" % basename) or \
 
466
                os.path.isfile("%s.coverage" % tbasename)
 
467
            cyEnable = cyEnable or \
 
468
                os.path.isfile("%s.cycles.html" % basename) or \
 
469
                os.path.isfile("%s.cycles.html" % tbasename)
 
470
        
 
471
        # now check the selected item
 
472
        itm = self.model().item(self.currentIndex())
 
473
        fn = unicode(itm.fileName())
 
474
        if fn is not None:
 
475
            basename = os.path.splitext(fn)[0]
 
476
            prEnable = prEnable or \
 
477
                os.path.isfile("%s.profile" % basename)
 
478
            coEnable = coEnable or \
 
479
                os.path.isfile("%s.coverage" % basename)
 
480
            cyEnable = cyEnable or \
 
481
                os.path.isfile("%s.cycles.html" % basename)
 
482
        
 
483
        self.profileMenuAction.setEnabled(prEnable)
 
484
        self.coverageMenuAction.setEnabled(coEnable)
 
485
        self.cyclopsMenuAction.setEnabled(cyEnable)
 
486
        self.removeCyclopsMenuAction.setEnabled(cyEnable)
 
487
        
 
488
    def __addSourceFiles(self):
 
489
        """
 
490
        Private method to add a source file to the project.
 
491
        """
 
492
        itm = self.model().item(self.currentIndex())
 
493
        if isinstance(itm, ProjectBrowserFileItem) or \
 
494
           isinstance(itm, BrowserClassItem) or \
 
495
           isinstance(itm, BrowserMethodItem):
 
496
            dn = os.path.dirname(unicode(itm.fileName()))
 
497
        elif isinstance(itm, ProjectBrowserSimpleDirectoryItem) or \
 
498
             isinstance(itm, ProjectBrowserDirectoryItem):
 
499
            dn = unicode(itm.dirName())
 
500
        else:
 
501
            dn = None
 
502
        self.project.addFiles('source', dn)
 
503
        
 
504
    def __addSourceDirectory(self):
 
505
        """
 
506
        Private method to add source files of a directory to the project.
 
507
        """
 
508
        itm = self.model().item(self.currentIndex())
 
509
        if isinstance(itm, ProjectBrowserFileItem) or \
 
510
           isinstance(itm, BrowserClassItem) or \
 
511
           isinstance(itm, BrowserMethodItem):
 
512
            dn = os.path.dirname(unicode(itm.fileName()))
 
513
        elif isinstance(itm, ProjectBrowserSimpleDirectoryItem) or \
 
514
             isinstance(itm, ProjectBrowserDirectoryItem):
 
515
            dn = unicode(itm.dirName())
 
516
        else:
 
517
            dn = None
 
518
        self.project.addDirectory('source', dn)
 
519
        
 
520
    def __deleteFile(self):
 
521
        """
 
522
        Private method to delete files from the project.
 
523
        """
 
524
        itmList = self.getSelectedItems()
 
525
        
 
526
        files = []
 
527
        fullNames = []
 
528
        for itm in itmList:
 
529
            fn2 = unicode(itm.fileName())
 
530
            fullNames.append(fn2)
 
531
            fn = fn2.replace(self.project.ppath+os.sep, '')
 
532
            files.append(fn)
 
533
        
 
534
        dlg = DeleteFilesConfirmationDialog(self.parent(),
 
535
            self.trUtf8("Delete files"),
 
536
            self.trUtf8("Do you really want to delete these files from the project?"),
 
537
            files)
 
538
        
 
539
        if dlg.exec_() == QDialog.Accepted:
 
540
            for fn2, fn in zip(fullNames, files):
 
541
                self.emit(SIGNAL('closeSourceWindow'), fn2)
 
542
                self.project.deleteFile(fn)
 
543
    
 
544
    ############################################################################
 
545
    ## Methods for the Checks submenu
 
546
    ############################################################################
 
547
    
 
548
    def handleTabnanny(self):
 
549
        """
 
550
        Public method to handle the tabnanny context menu action.
 
551
        """
 
552
        itm = self.model().item(self.currentIndex())
 
553
        try:
 
554
            fn = itm.fileName()
 
555
        except AttributeError:
 
556
            fn = itm.dirName()
 
557
        if os.path.isdir(fn):
 
558
            fn = [f for f in self.project.getSources(True) if f.startswith(fn)] 
 
559
        
 
560
        self.checkers.tabnanny(fn)
 
561
    
 
562
    def handleSyntaxCheck(self):
 
563
        """
 
564
        Public method to handle the syntax check context menu action.
 
565
        """
 
566
        itm = self.model().item(self.currentIndex())
 
567
        try:
 
568
            fn = itm.fileName()
 
569
        except AttributeError:
 
570
            fn = itm.dirName()
 
571
        if os.path.isdir(fn):
 
572
            fn = [f for f in self.project.getSources(True) if f.startswith(fn)] 
 
573
        
 
574
        self.checkers.syntaxCheck(fn)
 
575
        
 
576
    def handlePyLint(self):
 
577
        """
 
578
        Public method to handle the syntax check context menu action.
 
579
        """
 
580
        itm = self.model().item(self.currentIndex())
 
581
        try:
 
582
            fn = itm.fileName()
 
583
        except AttributeError:
 
584
            fn = itm.dirName()
 
585
        self.checkers.pyLint(self.project, fn)
 
586
    
 
587
    ############################################################################
 
588
    ## Methods for the Show submenu
 
589
    ############################################################################
 
590
    
 
591
    def __showCodeMetrics(self):
 
592
        """
 
593
        Private method to handle the code metrics context menu action.
 
594
        """
 
595
        itm = self.model().item(self.currentIndex())
 
596
        fn = itm.fileName()
 
597
        
 
598
        self.codemetrics = CodeMetricsDialog()
 
599
        self.codemetrics.show()
 
600
        self.codemetrics.start(fn)
 
601
    
 
602
    def __showCodeCoverage(self):
 
603
        """
 
604
        Private method to handle the code coverage context menu action.
 
605
        """
 
606
        itm = self.model().item(self.currentIndex())
 
607
        fn = itm.fileName()
 
608
        pfn = self.project.getMainScript(True)
 
609
        
 
610
        files = []
 
611
        
 
612
        if pfn is not None:
 
613
            tpfn = Utilities.getTestFileName(pfn)
 
614
            basename = os.path.splitext(pfn)[0]
 
615
            tbasename = os.path.splitext(tpfn)[0]
 
616
            
 
617
            f = "%s.coverage" % basename
 
618
            tf = "%s.coverage" % tbasename
 
619
            if os.path.isfile(f):
 
620
                files.append(f)
 
621
            if os.path.isfile(tf):
 
622
                files.append(tf)
 
623
        
 
624
        if fn is not None:
 
625
            tfn = Utilities.getTestFileName(fn)
 
626
            basename = os.path.splitext(fn)[0]
 
627
            tbasename = os.path.splitext(tfn)[0]
 
628
            
 
629
            f = "%s.coverage" % basename
 
630
            tf = "%s.coverage" % tbasename
 
631
            if os.path.isfile(f) and not f in files:
 
632
                files.append(f)
 
633
            if os.path.isfile(tf) and not tf in files:
 
634
                files.append(tf)
 
635
                
 
636
        if files:
 
637
            if len(files) > 1:
 
638
                filelist = QStringList()
 
639
                for f in files:
 
640
                    filelist.append(f)
 
641
                pfn, ok = KQInputDialog.getItem(\
 
642
                    None,
 
643
                    self.trUtf8("Code Coverage"),
 
644
                    self.trUtf8("Please select a coverage file"),
 
645
                    filelist,
 
646
                    0, False)
 
647
                if not ok:
 
648
                    return
 
649
                pfn = unicode(pfn)
 
650
            else:
 
651
                pfn = files[0]
 
652
        else:
 
653
            return
 
654
            
 
655
        self.codecoverage = PyCoverageDialog()
 
656
        self.codecoverage.show()
 
657
        self.codecoverage.start(pfn, fn)
 
658
    
 
659
    def __showProfileData(self):
 
660
        """
 
661
        Private method to handle the show profile data context menu action.
 
662
        """
 
663
        itm = self.model().item(self.currentIndex())
 
664
        fn = itm.fileName()
 
665
        pfn = self.project.getMainScript(True)
 
666
        
 
667
        files = []
 
668
        
 
669
        if pfn is not None:
 
670
            tpfn = Utilities.getTestFileName(pfn)
 
671
            basename = os.path.splitext(pfn)[0]
 
672
            tbasename = os.path.splitext(tpfn)[0]
 
673
            
 
674
            f = "%s.profile" % basename
 
675
            tf = "%s.profile" % tbasename
 
676
            if os.path.isfile(f):
 
677
                files.append(f)
 
678
            if os.path.isfile(tf):
 
679
                files.append(tf)
 
680
        
 
681
        if fn is not None:
 
682
            tfn = Utilities.getTestFileName(fn)
 
683
            basename = os.path.splitext(fn)[0]
 
684
            tbasename = os.path.splitext(tfn)[0]
 
685
            
 
686
            f = "%s.profile" % basename
 
687
            tf = "%s.profile" % tbasename
 
688
            if os.path.isfile(f) and not f in files:
 
689
                files.append(f)
 
690
            if os.path.isfile(tf) and not tf in files:
 
691
                files.append(tf)
 
692
                
 
693
        if files:
 
694
            if len(files) > 1:
 
695
                filelist = QStringList()
 
696
                for f in files:
 
697
                    filelist.append(f)
 
698
                pfn, ok = KQInputDialog.getItem(\
 
699
                    None,
 
700
                    self.trUtf8("Profile Data"),
 
701
                    self.trUtf8("Please select a profile file"),
 
702
                    filelist,
 
703
                    0, False)
 
704
                if not ok:
 
705
                    return
 
706
                pfn = unicode(pfn)
 
707
            else:
 
708
                pfn = files[0]
 
709
        else:
 
710
            return
 
711
            
 
712
        self.profiledata = PyProfileDialog()
 
713
        self.profiledata.show()
 
714
        self.profiledata.start(pfn, fn)
 
715
        
 
716
    def __showCyclopsReport(self):
 
717
        """
 
718
        Private method to handle the show cyclops report context menu action.
 
719
        """
 
720
        itm = self.model().item(self.currentIndex())
 
721
        fn = itm.fileName()
 
722
        pfn = self.project.getMainScript(True)
 
723
        
 
724
        files = []
 
725
        
 
726
        if pfn is not None:
 
727
            tpfn = Utilities.getTestFileName(pfn)
 
728
            basename = os.path.splitext(pfn)[0]
 
729
            tbasename = os.path.splitext(tpfn)[0]
 
730
            
 
731
            f = "%s.cycles.html" % basename
 
732
            tf = "%s.cycles.html" % tbasename
 
733
            if os.path.isfile(f):
 
734
                files.append(f)
 
735
            if os.path.isfile(tf):
 
736
                files.append(tf)
 
737
        
 
738
        if fn is not None:
 
739
            tfn = Utilities.getTestFileName(fn)
 
740
            basename = os.path.splitext(fn)[0]
 
741
            tbasename = os.path.splitext(tfn)[0]
 
742
            
 
743
            f = "%s.cycles.html" % basename
 
744
            tf = "%s.cycles.html" % tbasename
 
745
            if os.path.isfile(f) and not f in files:
 
746
                files.append(f)
 
747
            if os.path.isfile(tf) and not tf in files:
 
748
                files.append(tf)
 
749
                
 
750
        if files:
 
751
            if len(files) > 1:
 
752
                filelist = QStringList()
 
753
                for f in files:
 
754
                    filelist.append(f)
 
755
                pfn, ok = KQInputDialog.getItem(\
 
756
                    None,
 
757
                    self.trUtf8("Cyclops Report"),
 
758
                    self.trUtf8("Please select a Cyclops report file"),
 
759
                    filelist,
 
760
                    0, False)
 
761
                if not ok:
 
762
                    return
 
763
                pfn = unicode(pfn)
 
764
            else:
 
765
                pfn = files[0]
 
766
        else:
 
767
            return
 
768
            
 
769
        e4App().getObject("UserInterface").launchHelpViewer(pfn)
 
770
        
 
771
    def __removeCyclopsReport(self):
 
772
        """
 
773
        Private method to handle the Remove Cyclops report context menu action.
 
774
        """
 
775
        itm = self.model().item(self.currentIndex())
 
776
        fn = itm.fileName()
 
777
        pfn = self.project.getMainScript(1)
 
778
        
 
779
        files = []
 
780
        
 
781
        if pfn is not None:
 
782
            tpfn = Utilities.getTestFileName(pfn)
 
783
            basename = os.path.splitext(pfn)[0]
 
784
            tbasename = os.path.splitext(tpfn)[0]
 
785
            
 
786
            f = "%s.cycles.html" % basename
 
787
            tf = "%s.cycles.html" % tbasename
 
788
            if os.path.isfile(f):
 
789
                files.append(f)
 
790
            if os.path.isfile(tf):
 
791
                files.append(tf)
 
792
        
 
793
        if fn is not None:
 
794
            tfn = Utilities.getTestFileName(fn)
 
795
            basename = os.path.splitext(fn)[0]
 
796
            tbasename = os.path.splitext(tfn)[0]
 
797
            
 
798
            f = "%s.cycles.html" % basename
 
799
            tf = "%s.cycles.html" % tbasename
 
800
            if os.path.isfile(f) and not f in files:
 
801
                files.append(f)
 
802
            if os.path.isfile(tf) and not tf in files:
 
803
                files.append(tf)
 
804
                
 
805
        if files:
 
806
            if len(files) > 1:
 
807
                filelist = QStringList()
 
808
                for f in files:
 
809
                    filelist.append(f)
 
810
                pfn, ok = KQInputDialog.getItem(\
 
811
                    None,
 
812
                    self.trUtf8("Remove Cyclops Report"),
 
813
                    self.trUtf8("Please select a Cyclops report file to be removed"),
 
814
                    filelist,
 
815
                    0, False)
 
816
                if not ok:
 
817
                    return
 
818
                pfn = unicode(pfn)
 
819
            else:
 
820
                pfn = files[0]
 
821
        else:
 
822
            return
 
823
            
 
824
        if os.path.exists(pfn):
 
825
            os.remove(pfn)
 
826
        
 
827
    
 
828
    ############################################################################
 
829
    ## Methods for the Graphics submenu
 
830
    ############################################################################
 
831
    
 
832
    def __showClassDiagram(self):
 
833
        """
 
834
        Private method to handle the class diagram context menu action.
 
835
        """
 
836
        itm = self.model().item(self.currentIndex())
 
837
        try:
 
838
            fn = itm.fileName()
 
839
        except AttributeError:
 
840
            fn = itm.dirName()
 
841
        res = KQMessageBox.question(None,
 
842
            self.trUtf8("Class Diagram"),
 
843
            self.trUtf8("""Include class attributes?"""),
 
844
            QMessageBox.StandardButtons(\
 
845
                QMessageBox.No | \
 
846
                QMessageBox.Yes),
 
847
            QMessageBox.Yes)
 
848
        self.classDiagram = UMLClassDiagram(fn, self, 
 
849
            noAttrs = (res != QMessageBox.Yes))
 
850
        self.classDiagram.show()
 
851
        
 
852
    def __showImportsDiagram(self):
 
853
        """
 
854
        Private method to handle the imports diagram context menu action.
 
855
        """
 
856
        itm = self.model().item(self.currentIndex())
 
857
        try:
 
858
            fn = itm.fileName()
 
859
        except AttributeError:
 
860
            fn = itm.dirName()
 
861
        package = os.path.isdir(fn) and fn or os.path.dirname(fn)
 
862
        self.importsDiagram = ImportsDiagram(package, self)
 
863
        self.importsDiagram.show()
 
864
        
 
865
    def __showPackageDiagram(self):
 
866
        """
 
867
        Private method to handle the package diagram context menu action.
 
868
        """
 
869
        itm = self.model().item(self.currentIndex())
 
870
        try:
 
871
            fn = itm.fileName()
 
872
        except AttributeError:
 
873
            fn = itm.dirName()
 
874
        package = os.path.isdir(fn) and fn or os.path.dirname(fn)
 
875
        res = KQMessageBox.question(None,
 
876
            self.trUtf8("Package Diagram"),
 
877
            self.trUtf8("""Include class attributes?"""),
 
878
            QMessageBox.StandardButtons(\
 
879
                QMessageBox.No | \
 
880
                QMessageBox.Yes),
 
881
            QMessageBox.Yes)
 
882
        self.packageDiagram = PackageDiagram(package, self, 
 
883
            noAttrs = (res != QMessageBox.Yes))
 
884
        self.packageDiagram.show()
 
885
        
 
886
    def __showApplicationDiagram(self):
 
887
        """
 
888
        Private method to handle the application diagram context menu action.
 
889
        """
 
890
        res = KQMessageBox.question(None,
 
891
            self.trUtf8("Application Diagram"),
 
892
            self.trUtf8("""Include module names?"""),
 
893
            QMessageBox.StandardButtons(\
 
894
                QMessageBox.No | \
 
895
                QMessageBox.Yes),
 
896
            QMessageBox.Yes)
 
897
        self.applicationDiagram = ApplicationDiagram(self.project, self, 
 
898
            noModules = (res != QMessageBox.Yes))
 
899
        self.applicationDiagram.show()