# -*- coding: utf-8 -*-

# Copyright (c) 2002 - 2007 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing a class used to display the Sources part of the project.
"""

import os
import sys

from PyQt4.QtCore import *
from PyQt4.QtGui import *

from KdeQt import KQMessageBox, KQInputDialog
from KdeQt.KQApplication import e4App

from Checks import Checkers

from UI.BrowserModel import BrowserClassItem, BrowserMethodItem
from UI.DeleteFilesConfirmationDialog import DeleteFilesConfirmationDialog
import UI.PixmapCache

from DataViews.CodeMetricsDialog import CodeMetricsDialog
from DataViews.PyCoverageDialog import PyCoverageDialog
from DataViews.PyProfileDialog import PyProfileDialog

from Graphics.UMLClassDiagram import UMLClassDiagram
from Graphics.ImportsDiagram import ImportsDiagram
from Graphics.ApplicationDiagram import ApplicationDiagram
from Graphics.PackageDiagram import PackageDiagram

from ProjectBrowserModel import ProjectBrowserFileItem, \
    ProjectBrowserSimpleDirectoryItem, ProjectBrowserDirectoryItem, \
    ProjectBrowserSourceType
from ProjectBaseBrowser import ProjectBaseBrowser

import Utilities

class ProjectSourcesBrowser(ProjectBaseBrowser):
    """
    A class used to display the Sources part of the project. 
    
    @signal closeSourceWindow(string) emitted after a file has been removed/deleted 
            from the project
    """
    def __init__(self, project, parent = None):
        """
        Constructor
        
        @param project reference to the project object
        @param parent parent widget of this browser (QWidget)
        """
        self.checkers = Checkers(self, parent)
        
        ProjectBaseBrowser.__init__(self, project, ProjectBrowserSourceType, parent)
        
        self.selectedItemsFilter = \
            [ProjectBrowserFileItem, ProjectBrowserSimpleDirectoryItem]
        
        self.setWindowTitle(self.trUtf8('Sources'))

        self.setWhatsThis(self.trUtf8(
            """<b>Project Sources Browser</b>"""
            """<p>This allows to easily see all sources contained in the current"""
            """ project. Several actions can be executed via the context menu.</p>"""
        ))
        
        self.connect(project, SIGNAL("prepareRepopulateItem"), 
            self._prepareRepopulateItem)
        self.connect(project, SIGNAL("completeRepopulateItem"),
            self._completeRepopulateItem)
        
        self.codemetrics        = None
        self.codecoverage       = None
        self.profiledata        = None
        self.classDiagram       = None
        self.importsDiagram     = None
        self.packageDiagram     = None
        self.applicationDiagram = None
        
    def __closeAllWindows(self):
        """
        Private method to close all project related windows.
        """
        self.codemetrics        and self.codemetrics.close()
        self.codecoverage       and self.codecoverage.close()
        self.profiledata        and self.profiledata.close()
        self.checkers.closeAllWindows()
        self.classDiagram       and self.classDiagram.close()
        self.importsDiagram     and self.importsDiagram.close()
        self.packageDiagram     and self.packageDiagram.close()
        self.applicationDiagram and self.applicationDiagram.close()
        
    def _projectClosed(self):
        """
        Protected slot to handle the projectClosed signal.
        """
        self.__closeAllWindows()
        ProjectBaseBrowser._projectClosed(self)
        
    def _createPopupMenus(self):
        """
        Protected overloaded method to generate the popup menu.
        """
        ProjectBaseBrowser._createPopupMenus(self)
        self.sourceMenuActions = {}
        
        if self.project.pdata["PROGLANGUAGE"][0] == "Python":
            self.__createPythonPopupMenus()
        elif self.project.pdata["PROGLANGUAGE"][0] == "Ruby":
            self.__createRubyPopupMenus()
        
    def __createPythonPopupMenus(self):
        """
        Privat method to generate the popup menus for a Python project.
        """
        self.checkers.initActions()
        self.checksMenu = self.checkers.initMenu()
        self.checksMenu.setTitle(self.trUtf8('Check'))
        
        self.showMenu = QMenu(self.trUtf8('Show'))
        self.showMenu.addAction(self.trUtf8('Code metrics...'), self.__showCodeMetrics)
        self.coverageMenuAction = self.showMenu.addAction(\
            self.trUtf8('Code coverage...'), self.__showCodeCoverage)
        self.profileMenuAction = self.showMenu.addAction(\
            self.trUtf8('Profile data...'), self.__showProfileData)
        self.cyclopsMenuAction = self.showMenu.addAction(\
            self.trUtf8('Cyclops report...'), self.__showCyclopsReport)
        self.removeCyclopsMenuAction = self.showMenu.addAction(\
            self.trUtf8('Remove cyclops report'), self.__removeCyclopsReport)
        self.connect(self.showMenu,SIGNAL('aboutToShow()'),self.__showShowMenu)
        
        self.graphicsMenu = QMenu(self.trUtf8('Diagrams'))
        self.classDiagramAction = self.graphicsMenu.addAction(\
            self.trUtf8("Class Diagram..."), self.__showClassDiagram)
        self.graphicsMenu.addAction(\
            self.trUtf8("Package Diagram..."), self.__showPackageDiagram)
        self.importsDiagramAction = self.graphicsMenu.addAction(\
            self.trUtf8("Imports Diagram..."), self.__showImportsDiagram)
        self.graphicsMenu.addAction(\
            self.trUtf8("Application Diagram..."), self.__showApplicationDiagram)
        
        self.unittestAction = self.sourceMenu.addAction(\
            self.trUtf8('Run unittest...'), self.handleUnittest)
        self.sourceMenu.addSeparator()
        act = self.sourceMenu.addAction(self.trUtf8('Rename file'), self._renameFile)
        self.menuActions.append(act)
        act = self.sourceMenu.addAction(self.trUtf8('Remove from project'), 
            self._removeFile)
        self.menuActions.append(act)
        act = self.sourceMenu.addAction(self.trUtf8('Delete'), self.__deleteFile)
        self.menuActions.append(act)
        self.sourceMenu.addSeparator()
        self.sourceMenu.addAction(self.trUtf8('Add source files...'), 
            self.__addSourceFiles)
        self.sourceMenu.addAction(self.trUtf8('Add source directory...'), 
            self.__addSourceDirectory)
        self.sourceMenu.addSeparator()
        act = self.sourceMenu.addMenu(self.graphicsMenu)
        self.sourceMenu.addSeparator()
        self.sourceMenuActions["Check"] = \
            self.sourceMenu.addMenu(self.checksMenu)
        self.sourceMenu.addSeparator()
        self.sourceMenuActions["Show"] = \
            self.sourceMenu.addMenu(self.showMenu)
        self.sourceMenu.addSeparator()
        self.sourceMenu.addAction(self.trUtf8('Expand all directories'), 
            self._expandAllDirs)
        self.sourceMenu.addAction(self.trUtf8('Collapse all directories'), 
            self._collapseAllDirs)

        self.menu.addSeparator()
        self.menu.addAction(self.trUtf8('Add source files...'), self.__addSourceFiles)
        self.menu.addAction(self.trUtf8('Add source directory...'), 
            self.__addSourceDirectory)
        self.menu.addSeparator()
        self.menu.addAction(self.trUtf8('Expand all directories'), 
            self._expandAllDirs)
        self.menu.addAction(self.trUtf8('Collapse all directories'), 
            self._collapseAllDirs)

        self.backMenu = QMenu(self)
        self.backMenu.addAction(self.trUtf8('Add source files...'), 
            self.project.addSourceFiles)
        self.backMenu.addAction(self.trUtf8('Add source directory...'), 
            self.project.addSourceDir)
        self.backMenu.addSeparator()
        self.backMenu.addAction(self.trUtf8('Expand all directories'), 
            self._expandAllDirs)
        self.backMenu.addAction(self.trUtf8('Collapse all directories'), 
            self._collapseAllDirs)
        self.backMenu.setEnabled(False)
        
        self.multiMenu.addSeparator()
        act = self.multiMenu.addAction(self.trUtf8('Remove from project'), 
            self._removeFile)
        self.multiMenuActions.append(act)
        act = self.multiMenu.addAction(self.trUtf8('Delete'), self.__deleteFile)
        self.multiMenuActions.append(act)
        self.multiMenu.addSeparator()
        self.multiMenu.addAction(self.trUtf8('Expand all directories'), 
            self._expandAllDirs)
        self.multiMenu.addAction(self.trUtf8('Collapse all directories'), 
            self._collapseAllDirs)
        
        self.dirMenu = QMenu(self)
        act = self.dirMenu.addAction(self.trUtf8('Remove from project'), self._removeDir)
        self.dirMenuActions.append(act)
        self.dirMenu.addSeparator()
        self.dirMenu.addAction(self.trUtf8('Add source files...'), self.__addSourceFiles)
        self.dirMenu.addAction(self.trUtf8('Add source directory...'), 
            self.__addSourceDirectory)
        self.dirMenu.addSeparator()
        act = self.dirMenu.addMenu(self.graphicsMenu)        
        self.dirMenu.addSeparator()
        self.dirMenu.addMenu(self.checksMenu)
        self.dirMenu.addSeparator()
        self.dirMenu.addAction(self.trUtf8('Expand all directories'), 
            self._expandAllDirs)
        self.dirMenu.addAction(self.trUtf8('Collapse all directories'), 
            self._collapseAllDirs)
        
        self.dirMultiMenu = QMenu(self)
        self.dirMultiMenu.addAction(self.trUtf8('Expand all directories'), 
            self._expandAllDirs)
        self.dirMultiMenu.addAction(self.trUtf8('Collapse all directories'), 
            self._collapseAllDirs)
        
        self.connect(self.sourceMenu, SIGNAL('aboutToShow()'),
            self.__showPopupMenu)
        self.connect(self.multiMenu, SIGNAL('aboutToShow()'),
            self.__showPopupMenuMulti)
        self.connect(self.dirMenu, SIGNAL('aboutToShow()'),
            self.__showPopupMenuDir)
        self.connect(self.dirMultiMenu, SIGNAL('aboutToShow()'),
            self.__showPopupMenuDirMulti)
        self.mainMenu = self.sourceMenu
        
    def __createRubyPopupMenus(self):
        """
        Privat method to generate the popup menus for a Ruby project.
        """
        self.graphicsMenu = QMenu(self.trUtf8('Diagrams'))
        self.classDiagramAction = self.graphicsMenu.addAction(\
            self.trUtf8("Class Diagram..."), self.__showClassDiagram)
        self.graphicsMenu.addAction(self.trUtf8("Package Diagram..."), 
            self.__showPackageDiagram)
        self.graphicsMenu.addAction(self.trUtf8("Application Diagram..."), 
            self.__showApplicationDiagram)
        
        self.sourceMenu.addSeparator()
        act = self.sourceMenu.addAction(self.trUtf8('Rename file'), self._renameFile)
        self.menuActions.append(act)
        act = self.sourceMenu.addAction(self.trUtf8('Remove from project'), 
            self._removeFile)
        self.menuActions.append(act)
        act = self.sourceMenu.addAction(self.trUtf8('Delete'), self.__deleteFile)
        self.menuActions.append(act)
        self.sourceMenu.addSeparator()
        self.sourceMenu.addAction(self.trUtf8('Add source files...'), 
            self.__addSourceFiles)
        self.sourceMenu.addAction(self.trUtf8('Add source directory...'), 
            self.__addSourceDirectory)
        self.sourceMenu.addSeparator()
        act = self.sourceMenu.addMenu(self.graphicsMenu)
        self.sourceMenu.addSeparator()
        self.sourceMenu.addAction(self.trUtf8('Expand all directories'), 
            self._expandAllDirs)
        self.sourceMenu.addAction(self.trUtf8('Collapse all directories'), 
            self._collapseAllDirs)

        self.menu.addSeparator()
        self.menu.addAction(self.trUtf8('Add source files...'), self.__addSourceFiles)
        self.menu.addAction(self.trUtf8('Add source directory...'), 
            self.__addSourceDirectory)
        self.menu.addSeparator()
        self.menu.addAction(self.trUtf8('Expand all directories'), 
            self._expandAllDirs)
        self.menu.addAction(self.trUtf8('Collapse all directories'), 
            self._collapseAllDirs)

        self.backMenu = QMenu(self)
        self.backMenu.addAction(self.trUtf8('Add source files...'), 
            self.project.addSourceFiles)
        self.backMenu.addAction(self.trUtf8('Add source directory...'), 
            self.project.addSourceDir)
        self.backMenu.addSeparator()
        self.backMenu.addAction(self.trUtf8('Expand all directories'), 
            self._expandAllDirs)
        self.backMenu.addAction(self.trUtf8('Collapse all directories'), 
            self._collapseAllDirs)
        self.backMenu.setEnabled(False)
        
        self.multiMenu.addSeparator()
        act = self.multiMenu.addAction(self.trUtf8('Remove from project'), 
            self._removeFile)
        self.multiMenuActions.append(act)
        act = self.multiMenu.addAction(self.trUtf8('Delete'), self.__deleteFile)
        self.multiMenuActions.append(act)
        self.multiMenu.addSeparator()
        self.multiMenu.addAction(self.trUtf8('Expand all directories'), 
            self._expandAllDirs)
        self.multiMenu.addAction(self.trUtf8('Collapse all directories'), 
            self._collapseAllDirs)
        
        self.dirMenu = QMenu(self)
        act = self.dirMenu.addAction(self.trUtf8('Remove from project'), self._removeDir)
        self.dirMenuActions.append(act)
        self.dirMenu.addSeparator()
        self.dirMenu.addAction(self.trUtf8('Add source files...'), self.__addSourceFiles)
        self.dirMenu.addAction(self.trUtf8('Add source directory...'), 
            self.__addSourceDirectory)
        self.dirMenu.addSeparator()
        act = self.dirMenu.addMenu(self.graphicsMenu)        
        self.dirMenu.addSeparator()
        self.dirMenu.addAction(self.trUtf8('Expand all directories'), 
            self._expandAllDirs)
        self.dirMenu.addAction(self.trUtf8('Collapse all directories'), 
            self._collapseAllDirs)
        
        self.dirMultiMenu = QMenu(self)
        self.dirMultiMenu.addAction(self.trUtf8('Expand all directories'), 
            self._expandAllDirs)
        self.dirMultiMenu.addAction(self.trUtf8('Collapse all directories'), 
            self._collapseAllDirs)
        
        self.connect(self.sourceMenu, SIGNAL('aboutToShow()'),
            self.__showPopupMenu)
        self.connect(self.multiMenu, SIGNAL('aboutToShow()'),
            self.__showPopupMenuMulti)
        self.connect(self.dirMenu, SIGNAL('aboutToShow()'),
            self.__showPopupMenuDir)
        self.connect(self.dirMultiMenu, SIGNAL('aboutToShow()'),
            self.__showPopupMenuDirMulti)
        self.mainMenu = self.sourceMenu
        
    def _showContextMenu(self, coord):
        """
        Protected slot to show the context menu.
        
        @param coord the position of the mouse pointer (QPoint)
        """
        if not self.project.isOpen():
            return
        
        try:
            categories = self.getSelectedItemsCountCategorized(\
                [ProjectBrowserFileItem, BrowserClassItem, 
                 BrowserMethodItem, ProjectBrowserSimpleDirectoryItem])
            cnt = categories["sum"]
            if cnt <= 1:
                index = self.indexAt(coord)
                if index.isValid():
                    self._selectSingleItem(index)
                    categories = self.getSelectedItemsCountCategorized(\
                        [ProjectBrowserFileItem, BrowserClassItem, 
                         BrowserMethodItem, ProjectBrowserSimpleDirectoryItem])
                    cnt = categories["sum"]
            
            bfcnt = categories[unicode(ProjectBrowserFileItem)]
            cmcnt = categories[unicode(BrowserClassItem)] + \
                    categories[unicode(BrowserMethodItem)]
            sdcnt = categories[unicode(ProjectBrowserSimpleDirectoryItem)]
            if cnt > 1 and cnt == bfcnt:
                self.multiMenu.popup(self.mapToGlobal(coord))
            elif cnt > 1 and cnt == sdcnt:
                self.dirMultiMenu.popup(self.mapToGlobal(coord))
            else:
                index = self.indexAt(coord)
                if cnt == 1 and index.isValid():
                    if bfcnt == 1 or cmcnt == 1:
                        itm = self.model().item(index)
                        if isinstance(itm, ProjectBrowserFileItem):
                            fn = itm.fileName()
                            if self.project.pdata["PROGLANGUAGE"][0] == "Python":
                                if fn.endswith('.py') or fn.endswith('.pyw'):
                                    for act in self.sourceMenuActions.values():
                                        act.setEnabled(True)
                                    self.sourceMenuActions["Check"].setEnabled(True)
                                    self.classDiagramAction.setEnabled(True)
                                    self.importsDiagramAction.setEnabled(True)
                                    self.unittestAction.setEnabled(True)
                                elif fn.endswith('.ptl'):
                                    for act in self.sourceMenuActions.values():
                                        act.setEnabled(False)
                                    self.sourceMenuActions["Check"].setEnabled(True)
                                    self.classDiagramAction.setEnabled(True)
                                    self.importsDiagramAction.setEnabled(True)
                                    self.unittestAction.setEnabled(False)
                                elif fn.endswith('.rb'):  # entry for mixed mode programs
                                    for act in self.sourceMenuActions.values():
                                        act.setEnabled(False)
                                    self.sourceMenuActions["Check"].setEnabled(False)
                                    self.classDiagramAction.setEnabled(True)
                                    self.importsDiagramAction.setEnabled(False)
                                    self.unittestAction.setEnabled(False)
                                else:
                                    for act in self.sourceMenuActions.values():
                                        act.setEnabled(False)
                                    self.sourceMenuActions["Check"].setEnabled(False)
                                    self.classDiagramAction.setEnabled(False)
                                    self.importsDiagramAction.setEnabled(False)
                                    self.unittestAction.setEnabled(False)
                            self.sourceMenu.popup(self.mapToGlobal(coord))
                        elif isinstance(itm, BrowserClassItem) or \
                                isinstance(itm, BrowserMethodItem):
                            self.menu.popup(self.mapToGlobal(coord))
                        else:
                            self.backMenu.popup(self.mapToGlobal(coord))
                    elif sdcnt == 1:
                        self.classDiagramAction.setEnabled(False)
                        self.dirMenu.popup(self.mapToGlobal(coord))
                    else:
                        self.backMenu.popup(self.mapToGlobal(coord))
                else:
                    self.backMenu.popup(self.mapToGlobal(coord))
        except:
            pass
        
    def __showPopupMenu(self):
        """
        Private slot called by the sourceMenu aboutToShow signal.
        """
        ProjectBaseBrowser._showPopupMenu(self, self.sourceMenu)
        
    def __showPopupMenuMulti(self):
        """
        Private slot called by the multiMenu aboutToShow signal.
        """
        ProjectBaseBrowser._showPopupMenuMulti(self, self.multiMenu)
        
    def __showPopupMenuDir(self):
        """
        Private slot called by the dirMenu aboutToShow signal.
        """
        ProjectBaseBrowser._showPopupMenuDir(self, self.dirMenu)
        
    def __showPopupMenuDirMulti(self):
        """
        Private slot called by the dirMultiMenu aboutToShow signal.
        """
        ProjectBaseBrowser._showPopupMenuDirMulti(self, self.dirMultiMenu)
        
    def __showShowMenu(self):
        """
        Private slot called before the show menu is shown.
        """
        prEnable = False
        coEnable = False
        cyEnable = False
        
        # first check if the file belongs to a project and there is
        # a project coverage file
        fn = self.project.getMainScript(True)
        if fn is not None:
            tfn = Utilities.getTestFileName(fn)
            basename = os.path.splitext(fn)[0]
            tbasename = os.path.splitext(tfn)[0]
            prEnable = prEnable or \
                os.path.isfile("%s.profile" % basename) or \
                os.path.isfile("%s.profile" % tbasename)
            coEnable = coEnable or \
                os.path.isfile("%s.coverage" % basename) or \
                os.path.isfile("%s.coverage" % tbasename)
            cyEnable = cyEnable or \
                os.path.isfile("%s.cycles.html" % basename) or \
                os.path.isfile("%s.cycles.html" % tbasename)
        
        # now check the selected item
        itm = self.model().item(self.currentIndex())
        fn = unicode(itm.fileName())
        if fn is not None:
            basename = os.path.splitext(fn)[0]
            prEnable = prEnable or \
                os.path.isfile("%s.profile" % basename)
            coEnable = coEnable or \
                os.path.isfile("%s.coverage" % basename)
            cyEnable = cyEnable or \
                os.path.isfile("%s.cycles.html" % basename)
        
        self.profileMenuAction.setEnabled(prEnable)
        self.coverageMenuAction.setEnabled(coEnable)
        self.cyclopsMenuAction.setEnabled(cyEnable)
        self.removeCyclopsMenuAction.setEnabled(cyEnable)
        
    def __addSourceFiles(self):
        """
        Private method to add a source file to the project.
        """
        itm = self.model().item(self.currentIndex())
        if isinstance(itm, ProjectBrowserFileItem) or \
           isinstance(itm, BrowserClassItem) or \
           isinstance(itm, BrowserMethodItem):
            dn = os.path.dirname(unicode(itm.fileName()))
        elif isinstance(itm, ProjectBrowserSimpleDirectoryItem) or \
             isinstance(itm, ProjectBrowserDirectoryItem):
            dn = unicode(itm.dirName())
        else:
            dn = None
        self.project.addFiles('source', dn)
        
    def __addSourceDirectory(self):
        """
        Private method to add source files of a directory to the project.
        """
        itm = self.model().item(self.currentIndex())
        if isinstance(itm, ProjectBrowserFileItem) or \
           isinstance(itm, BrowserClassItem) or \
           isinstance(itm, BrowserMethodItem):
            dn = os.path.dirname(unicode(itm.fileName()))
        elif isinstance(itm, ProjectBrowserSimpleDirectoryItem) or \
             isinstance(itm, ProjectBrowserDirectoryItem):
            dn = unicode(itm.dirName())
        else:
            dn = None
        self.project.addDirectory('source', dn)
        
    def __deleteFile(self):
        """
        Private method to delete files from the project.
        """
        itmList = self.getSelectedItems()
        
        files = []
        fullNames = []
        for itm in itmList:
            fn2 = unicode(itm.fileName())
            fullNames.append(fn2)
            fn = fn2.replace(self.project.ppath+os.sep, '')
            files.append(fn)
        
        dlg = DeleteFilesConfirmationDialog(self.parent(),
            self.trUtf8("Delete files"),
            self.trUtf8("Do you really want to delete these files from the project?"),
            files)
        
        if dlg.exec_() == QDialog.Accepted:
            for fn2, fn in zip(fullNames, files):
                self.emit(SIGNAL('closeSourceWindow'), fn2)
                self.project.deleteFile(fn)
    
    ############################################################################
    ## Methods for the Checks submenu
    ############################################################################
    
    def handleTabnanny(self):
        """
        Public method to handle the tabnanny context menu action.
        """
        itm = self.model().item(self.currentIndex())
        try:
            fn = itm.fileName()
        except AttributeError:
            fn = itm.dirName()
        if os.path.isdir(fn):
            fn = [f for f in self.project.getSources(True) if f.startswith(fn)] 
        
        self.checkers.tabnanny(fn)
    
    def handleSyntaxCheck(self):
        """
        Public method to handle the syntax check context menu action.
        """
        itm = self.model().item(self.currentIndex())
        try:
            fn = itm.fileName()
        except AttributeError:
            fn = itm.dirName()
        if os.path.isdir(fn):
            fn = [f for f in self.project.getSources(True) if f.startswith(fn)] 
        
        self.checkers.syntaxCheck(fn)
        
    def handlePyLint(self):
        """
        Public method to handle the syntax check context menu action.
        """
        itm = self.model().item(self.currentIndex())
        try:
            fn = itm.fileName()
        except AttributeError:
            fn = itm.dirName()
        self.checkers.pyLint(self.project, fn)
    
    ############################################################################
    ## Methods for the Show submenu
    ############################################################################
    
    def __showCodeMetrics(self):
        """
        Private method to handle the code metrics context menu action.
        """
        itm = self.model().item(self.currentIndex())
        fn = itm.fileName()
        
        self.codemetrics = CodeMetricsDialog()
        self.codemetrics.show()
        self.codemetrics.start(fn)
    
    def __showCodeCoverage(self):
        """
        Private method to handle the code coverage context menu action.
        """
        itm = self.model().item(self.currentIndex())
        fn = itm.fileName()
        pfn = self.project.getMainScript(True)
        
        files = []
        
        if pfn is not None:
            tpfn = Utilities.getTestFileName(pfn)
            basename = os.path.splitext(pfn)[0]
            tbasename = os.path.splitext(tpfn)[0]
            
            f = "%s.coverage" % basename
            tf = "%s.coverage" % tbasename
            if os.path.isfile(f):
                files.append(f)
            if os.path.isfile(tf):
                files.append(tf)
        
        if fn is not None:
            tfn = Utilities.getTestFileName(fn)
            basename = os.path.splitext(fn)[0]
            tbasename = os.path.splitext(tfn)[0]
            
            f = "%s.coverage" % basename
            tf = "%s.coverage" % tbasename
            if os.path.isfile(f) and not f in files:
                files.append(f)
            if os.path.isfile(tf) and not tf in files:
                files.append(tf)
                
        if files:
            if len(files) > 1:
                filelist = QStringList()
                for f in files:
                    filelist.append(f)
                pfn, ok = KQInputDialog.getItem(\
                    None,
                    self.trUtf8("Code Coverage"),
                    self.trUtf8("Please select a coverage file"),
                    filelist,
                    0, False)
                if not ok:
                    return
                pfn = unicode(pfn)
            else:
                pfn = files[0]
        else:
            return
            
        self.codecoverage = PyCoverageDialog()
        self.codecoverage.show()
        self.codecoverage.start(pfn, fn)
    
    def __showProfileData(self):
        """
        Private method to handle the show profile data context menu action.
        """
        itm = self.model().item(self.currentIndex())
        fn = itm.fileName()
        pfn = self.project.getMainScript(True)
        
        files = []
        
        if pfn is not None:
            tpfn = Utilities.getTestFileName(pfn)
            basename = os.path.splitext(pfn)[0]
            tbasename = os.path.splitext(tpfn)[0]
            
            f = "%s.profile" % basename
            tf = "%s.profile" % tbasename
            if os.path.isfile(f):
                files.append(f)
            if os.path.isfile(tf):
                files.append(tf)
        
        if fn is not None:
            tfn = Utilities.getTestFileName(fn)
            basename = os.path.splitext(fn)[0]
            tbasename = os.path.splitext(tfn)[0]
            
            f = "%s.profile" % basename
            tf = "%s.profile" % tbasename
            if os.path.isfile(f) and not f in files:
                files.append(f)
            if os.path.isfile(tf) and not tf in files:
                files.append(tf)
                
        if files:
            if len(files) > 1:
                filelist = QStringList()
                for f in files:
                    filelist.append(f)
                pfn, ok = KQInputDialog.getItem(\
                    None,
                    self.trUtf8("Profile Data"),
                    self.trUtf8("Please select a profile file"),
                    filelist,
                    0, False)
                if not ok:
                    return
                pfn = unicode(pfn)
            else:
                pfn = files[0]
        else:
            return
            
        self.profiledata = PyProfileDialog()
        self.profiledata.show()
        self.profiledata.start(pfn, fn)
        
    def __showCyclopsReport(self):
        """
        Private method to handle the show cyclops report context menu action.
        """
        itm = self.model().item(self.currentIndex())
        fn = itm.fileName()
        pfn = self.project.getMainScript(True)
        
        files = []
        
        if pfn is not None:
            tpfn = Utilities.getTestFileName(pfn)
            basename = os.path.splitext(pfn)[0]
            tbasename = os.path.splitext(tpfn)[0]
            
            f = "%s.cycles.html" % basename
            tf = "%s.cycles.html" % tbasename
            if os.path.isfile(f):
                files.append(f)
            if os.path.isfile(tf):
                files.append(tf)
        
        if fn is not None:
            tfn = Utilities.getTestFileName(fn)
            basename = os.path.splitext(fn)[0]
            tbasename = os.path.splitext(tfn)[0]
            
            f = "%s.cycles.html" % basename
            tf = "%s.cycles.html" % tbasename
            if os.path.isfile(f) and not f in files:
                files.append(f)
            if os.path.isfile(tf) and not tf in files:
                files.append(tf)
                
        if files:
            if len(files) > 1:
                filelist = QStringList()
                for f in files:
                    filelist.append(f)
                pfn, ok = KQInputDialog.getItem(\
                    None,
                    self.trUtf8("Cyclops Report"),
                    self.trUtf8("Please select a Cyclops report file"),
                    filelist,
                    0, False)
                if not ok:
                    return
                pfn = unicode(pfn)
            else:
                pfn = files[0]
        else:
            return
            
        e4App().getObject("UserInterface").launchHelpViewer(pfn)
        
    def __removeCyclopsReport(self):
        """
        Private method to handle the Remove Cyclops report context menu action.
        """
        itm = self.model().item(self.currentIndex())
        fn = itm.fileName()
        pfn = self.project.getMainScript(1)
        
        files = []
        
        if pfn is not None:
            tpfn = Utilities.getTestFileName(pfn)
            basename = os.path.splitext(pfn)[0]
            tbasename = os.path.splitext(tpfn)[0]
            
            f = "%s.cycles.html" % basename
            tf = "%s.cycles.html" % tbasename
            if os.path.isfile(f):
                files.append(f)
            if os.path.isfile(tf):
                files.append(tf)
        
        if fn is not None:
            tfn = Utilities.getTestFileName(fn)
            basename = os.path.splitext(fn)[0]
            tbasename = os.path.splitext(tfn)[0]
            
            f = "%s.cycles.html" % basename
            tf = "%s.cycles.html" % tbasename
            if os.path.isfile(f) and not f in files:
                files.append(f)
            if os.path.isfile(tf) and not tf in files:
                files.append(tf)
                
        if files:
            if len(files) > 1:
                filelist = QStringList()
                for f in files:
                    filelist.append(f)
                pfn, ok = KQInputDialog.getItem(\
                    None,
                    self.trUtf8("Remove Cyclops Report"),
                    self.trUtf8("Please select a Cyclops report file to be removed"),
                    filelist,
                    0, False)
                if not ok:
                    return
                pfn = unicode(pfn)
            else:
                pfn = files[0]
        else:
            return
            
        if os.path.exists(pfn):
            os.remove(pfn)
        
    
    ############################################################################
    ## Methods for the Graphics submenu
    ############################################################################
    
    def __showClassDiagram(self):
        """
        Private method to handle the class diagram context menu action.
        """
        itm = self.model().item(self.currentIndex())
        try:
            fn = itm.fileName()
        except AttributeError:
            fn = itm.dirName()
        res = KQMessageBox.question(None,
            self.trUtf8("Class Diagram"),
            self.trUtf8("""Include class attributes?"""),
            QMessageBox.StandardButtons(\
                QMessageBox.No | \
                QMessageBox.Yes),
            QMessageBox.Yes)
        self.classDiagram = UMLClassDiagram(fn, self, 
            noAttrs = (res != QMessageBox.Yes))
        self.classDiagram.show()
        
    def __showImportsDiagram(self):
        """
        Private method to handle the imports diagram context menu action.
        """
        itm = self.model().item(self.currentIndex())
        try:
            fn = itm.fileName()
        except AttributeError:
            fn = itm.dirName()
        package = os.path.isdir(fn) and fn or os.path.dirname(fn)
        self.importsDiagram = ImportsDiagram(package, self)
        self.importsDiagram.show()
        
    def __showPackageDiagram(self):
        """
        Private method to handle the package diagram context menu action.
        """
        itm = self.model().item(self.currentIndex())
        try:
            fn = itm.fileName()
        except AttributeError:
            fn = itm.dirName()
        package = os.path.isdir(fn) and fn or os.path.dirname(fn)
        res = KQMessageBox.question(None,
            self.trUtf8("Package Diagram"),
            self.trUtf8("""Include class attributes?"""),
            QMessageBox.StandardButtons(\
                QMessageBox.No | \
                QMessageBox.Yes),
            QMessageBox.Yes)
        self.packageDiagram = PackageDiagram(package, self, 
            noAttrs = (res != QMessageBox.Yes))
        self.packageDiagram.show()
        
    def __showApplicationDiagram(self):
        """
        Private method to handle the application diagram context menu action.
        """
        res = KQMessageBox.question(None,
            self.trUtf8("Application Diagram"),
            self.trUtf8("""Include module names?"""),
            QMessageBox.StandardButtons(\
                QMessageBox.No | \
                QMessageBox.Yes),
            QMessageBox.Yes)
        self.applicationDiagram = ApplicationDiagram(self.project, self, 
            noModules = (res != QMessageBox.Yes))
        self.applicationDiagram.show()
