--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Project/ProjectInterfacesBrowser.py Mon Dec 28 16:03:33 2009 +0000 @@ -0,0 +1,586 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2002 - 2009 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the a class used to display the interfaces (IDL) part of the project. +""" + +import os +import sys +import glob + +from PyQt4.QtCore import * +from PyQt4.QtGui import * + +from E4Gui.E4Application import e4App + +from ProjectBrowserModel import ProjectBrowserFileItem, \ + ProjectBrowserSimpleDirectoryItem, ProjectBrowserDirectoryItem, \ + ProjectBrowserInterfaceType +from ProjectBaseBrowser import ProjectBaseBrowser + +from UI.BrowserModel import BrowserFileItem, BrowserClassItem, BrowserMethodItem, \ + BrowserClassAttributeItem +from UI.DeleteFilesConfirmationDialog import DeleteFilesConfirmationDialog +import UI.PixmapCache + +import Preferences +import Utilities + +class ProjectInterfacesBrowser(ProjectBaseBrowser): + """ + A class used to display the interfaces (IDL) part of the project. + + @signal closeSourceWindow(string) emitted after a file has been removed/deleted + from the project + @signal appendStdout(string) emitted after something was received from + a QProcess on stdout + @signal appendStderr(string) emitted after something was received from + a QProcess on stderr + @signal showMenu(string, QMenu) emitted when a menu is about to be shown. The name + of the menu and a reference to the menu are given. + """ + def __init__(self, project, parent = None): + """ + Constructor + + @param project reference to the project object + @param parent parent widget of this browser (QWidget) + """ + self.omniidl = Preferences.getCorba("omniidl") + if self.omniidl == "": + self.omniidl = Utilities.isWindowsPlatform() and "omniidl.exe" or "omniidl" + if not Utilities.isinpath(self.omniidl): + self.omniidl = None + + ProjectBaseBrowser.__init__(self, project, ProjectBrowserInterfaceType, parent) + + self.selectedItemsFilter = \ + [ProjectBrowserFileItem, ProjectBrowserSimpleDirectoryItem] + + self.setWindowTitle(self.trUtf8('Interfaces (IDL)')) + + self.setWhatsThis(self.trUtf8( + """<b>Project Interfaces Browser</b>""" + """<p>This allows to easily see all interfaces (CORBA IDL files)""" + """ 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) + + def _createPopupMenus(self): + """ + Protected overloaded method to generate the popup menu. + """ + self.menuActions = [] + self.multiMenuActions = [] + self.dirMenuActions = [] + self.dirMultiMenuActions = [] + + self.sourceMenu = QMenu(self) + if self.omniidl is not None: + self.sourceMenu.addAction(self.trUtf8('Compile interface'), + self.__compileInterface) + self.sourceMenu.addAction(self.trUtf8('Compile all interfaces'), + self.__compileAllInterfaces) + self.sourceMenu.addAction(self.trUtf8('Open'), self._openItem) + 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 interfaces...'), + self.__addInterfaceFiles) + self.sourceMenu.addAction(self.trUtf8('Add interfaces directory...'), + self.__addInterfacesDirectory) + self.sourceMenu.addSeparator() + self.sourceMenu.addAction(self.trUtf8('Copy Path to Clipboard'), + self._copyToClipboard) + self.sourceMenu.addSeparator() + self.sourceMenu.addAction(self.trUtf8('Expand all directories'), + self._expandAllDirs) + self.sourceMenu.addAction(self.trUtf8('Collapse all directories'), + self._collapseAllDirs) + self.sourceMenu.addSeparator() + self.sourceMenu.addAction(self.trUtf8('Configure...'), self._configure) + self.sourceMenu.addAction(self.trUtf8('Configure CORBA...'), self.__configureCorba) + + self.menu = QMenu(self) + if self.omniidl is not None: + self.menu.addAction(self.trUtf8('Compile interface'), self.__compileInterface) + self.menu.addAction(self.trUtf8('Compile all interfaces'), + self.__compileAllInterfaces) + self.menu.addAction(self.trUtf8('Open'), self._openItem) + self.menu.addSeparator() + self.menu.addAction(self.trUtf8('Add interfaces...'), self.__addInterfaceFiles) + self.menu.addAction(self.trUtf8('Add interfaces directory...'), + self.__addInterfacesDirectory) + self.menu.addSeparator() + self.menu.addAction(self.trUtf8('Expand all directories'), + self._expandAllDirs) + self.menu.addAction(self.trUtf8('Collapse all directories'), + self._collapseAllDirs) + self.menu.addSeparator() + self.menu.addAction(self.trUtf8('Configure...'), self._configure) + self.menu.addAction(self.trUtf8('Configure CORBA...'), self.__configureCorba) + + self.backMenu = QMenu(self) + if self.omniidl is not None: + self.backMenu.addAction(self.trUtf8('Compile all interfaces'), + self.__compileAllInterfaces) + self.backMenu.addSeparator() + self.backMenu.addAction(self.trUtf8('Add interfaces...'), + self.project.addIdlFiles) + self.backMenu.addAction(self.trUtf8('Add interfaces directory...'), + self.project.addIdlDir) + 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.addSeparator() + self.backMenu.addAction(self.trUtf8('Configure...'), self._configure) + self.backMenu.addAction(self.trUtf8('Configure CORBA...'), self.__configureCorba) + self.backMenu.setEnabled(False) + + # create the menu for multiple selected files + self.multiMenu = QMenu(self) + if self.omniidl is not None: + self.multiMenu.addAction(self.trUtf8('Compile interfaces'), + self.__compileSelectedInterfaces) + self.multiMenu.addAction(self.trUtf8('Open'), self._openItem) + 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.multiMenu.addSeparator() + self.multiMenu.addAction(self.trUtf8('Configure...'), self._configure) + self.multiMenu.addAction(self.trUtf8('Configure CORBA...'), self.__configureCorba) + + self.dirMenu = QMenu(self) + if self.omniidl is not None: + self.dirMenu.addAction(self.trUtf8('Compile all interfaces'), + self.__compileAllInterfaces) + self.dirMenu.addSeparator() + act = self.dirMenu.addAction(self.trUtf8('Remove from project'), self._removeFile) + self.dirMenuActions.append(act) + self.dirMenu.addSeparator() + self.dirMenu.addAction(self.trUtf8('Add interfaces...'), self.__addInterfaceFiles) + self.dirMenu.addAction(self.trUtf8('Add interfaces directory...'), + self.__addInterfacesDirectory) + self.dirMenu.addSeparator() + self.dirMenu.addAction(self.trUtf8('Copy Path to Clipboard'), + self._copyToClipboard) + self.dirMenu.addSeparator() + self.dirMenu.addAction(self.trUtf8('Expand all directories'), + self._expandAllDirs) + self.dirMenu.addAction(self.trUtf8('Collapse all directories'), + self._collapseAllDirs) + self.dirMenu.addSeparator() + self.dirMenu.addAction(self.trUtf8('Configure...'), self._configure) + self.dirMenu.addAction(self.trUtf8('Configure CORBA...'), self.__configureCorba) + + self.dirMultiMenu = QMenu(self) + if self.omniidl is not None: + self.dirMultiMenu.addAction(self.trUtf8('Compile all interfaces'), + self.__compileAllInterfaces) + self.dirMultiMenu.addSeparator() + self.dirMultiMenu.addAction(self.trUtf8('Add interfaces...'), + self.project.addIdlFiles) + self.dirMultiMenu.addAction(self.trUtf8('Add interfaces directory...'), + self.project.addIdlDir) + self.dirMultiMenu.addSeparator() + self.dirMultiMenu.addAction(self.trUtf8('Expand all directories'), + self._expandAllDirs) + self.dirMultiMenu.addAction(self.trUtf8('Collapse all directories'), + self._collapseAllDirs) + self.dirMultiMenu.addSeparator() + self.dirMultiMenu.addAction(self.trUtf8('Configure...'), self._configure) + self.dirMultiMenu.addAction(self.trUtf8('Configure CORBA...'), + self.__configureCorba) + + self.connect(self.sourceMenu, SIGNAL('aboutToShow()'), + self.__showContextMenu) + self.connect(self.multiMenu, SIGNAL('aboutToShow()'), + self.__showContextMenuMulti) + self.connect(self.dirMenu, SIGNAL('aboutToShow()'), + self.__showContextMenuDir) + self.connect(self.dirMultiMenu, SIGNAL('aboutToShow()'), + self.__showContextMenuDirMulti) + self.connect(self.backMenu, SIGNAL('aboutToShow()'), + self.__showContextMenuBack) + self.mainMenu = self.sourceMenu + + def _contextMenuRequested(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): + 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.dirMenu.popup(self.mapToGlobal(coord)) + else: + self.backMenu.popup(self.mapToGlobal(coord)) + else: + self.backMenu.popup(self.mapToGlobal(coord)) + except: + pass + + def __showContextMenu(self): + """ + Private slot called by the menu aboutToShow signal. + """ + ProjectBaseBrowser._showContextMenu(self, self.menu) + + self.emit(SIGNAL("showMenu"), "Main", self.menu) + + def __showContextMenuMulti(self): + """ + Private slot called by the multiMenu aboutToShow signal. + """ + ProjectBaseBrowser._showContextMenuMulti(self, self.multiMenu) + + self.emit(SIGNAL("showMenu"), "MainMulti", self.multiMenu) + + def __showContextMenuDir(self): + """ + Private slot called by the dirMenu aboutToShow signal. + """ + ProjectBaseBrowser._showContextMenuDir(self, self.dirMenu) + + self.emit(SIGNAL("showMenu"), "MainDir", self.dirMenu) + + def __showContextMenuDirMulti(self): + """ + Private slot called by the dirMultiMenu aboutToShow signal. + """ + ProjectBaseBrowser._showContextMenuDirMulti(self, self.dirMultiMenu) + + self.emit(SIGNAL("showMenu"), "MainDirMulti", self.dirMultiMenu) + + def __showContextMenuBack(self): + """ + Private slot called by the backMenu aboutToShow signal. + """ + ProjectBaseBrowser._showContextMenuBack(self, self.backMenu) + + self.emit(SIGNAL("showMenu"), "MainBack", self.backMenu) + + def _openItem(self): + """ + Protected slot to handle the open popup menu entry. + """ + itmList = self.getSelectedItems(\ + [BrowserFileItem, BrowserClassItem, BrowserMethodItem, + BrowserClassAttributeItem]) + + for itm in itmList: + if isinstance(itm, BrowserFileItem): + self.emit(SIGNAL('sourceFile'), itm.fileName()) + elif isinstance(itm, BrowserClassItem): + self.emit(SIGNAL('sourceFile'), itm.fileName(), + itm.classObject().lineno) + elif isinstance(itm,BrowserMethodItem): + self.emit(SIGNAL('sourceFile'), itm.fileName(), + itm.functionObject().lineno) + elif isinstance(itm, BrowserClassAttributeItem): + self.emit(SIGNAL('sourceFile'), itm.fileName(), + itm.attributeObject().lineno) + + def __addInterfaceFiles(self): + """ + Private method to add interface files 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(itm.fileName()) + elif isinstance(itm, ProjectBrowserSimpleDirectoryItem) or \ + isinstance(itm, ProjectBrowserDirectoryItem): + dn = itm.dirName() + else: + dn = None + self.project.addFiles('interface', dn) + + def __addInterfacesDirectory(self): + """ + Private method to add interface 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(itm.fileName()) + elif isinstance(itm, ProjectBrowserSimpleDirectoryItem) or \ + isinstance(itm, ProjectBrowserDirectoryItem): + dn = itm.dirName() + else: + dn = None + self.project.addDirectory('interface', dn) + + def __deleteFile(self): + """ + Private method to delete files from the project. + """ + itmList = self.getSelectedItems() + + files = [] + fullNames = [] + for itm in itmList: + fn2 = itm.fileName() + fullNames.append(fn2) + fn = fn2.replace(self.project.ppath+os.sep, '') + files.append(fn) + + dlg = DeleteFilesConfirmationDialog(self.parent(), + self.trUtf8("Delete interfaces"), + self.trUtf8("Do you really want to delete these interfaces 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 to handle the various compile commands + ############################################################################ + + def __readStdout(self): + """ + Private slot to handle the readyReadStandardOutput signal of the omniidl process. + """ + if self.compileProc is None: + return + + ioEncoding = str(Preferences.getSystem("IOEncoding")) + + self.compileProc.setReadChannel(QProcess.StandardOutput) + while self.compileProc and self.compileProc.canReadLine(): + s = 'omniidl: ' + output = unicode(self.compileProc.readLine(), + ioEncoding, 'replace') + s += output + self.emit(SIGNAL('appendStdout'), s) + + def __readStderr(self): + """ + Private slot to handle the readyReadStandardError signal of the omniidl process. + """ + if self.compileProc is None: + return + + ioEncoding = str(Preferences.getSystem("IOEncoding")) + + self.compileProc.setReadChannel(QProcess.StandardError) + while self.compileProc and self.compileProc.canReadLine(): + s = 'omniidl: ' + error = unicode(self.compileProc.readLine(), + ioEncoding, 'replace') + s += error + self.emit(SIGNAL('appendStderr'), s) + + def __compileIDLDone(self, exitCode, exitStatus): + """ + Private slot to handle the finished signal of the omniidl process. + + @param exitCode exit code of the process (integer) + @param exitStatus exit status of the process (QProcess.ExitStatus) + """ + self.compileRunning = False + if exitStatus == QProcess.NormalExit and exitCode == 0: + path = os.path.dirname(self.idlFile) + poaList = glob.glob(os.path.join(path, "*__POA")) + npoaList = [f.replace("__POA", "") for f in poaList] + fileList = glob.glob(os.path.join(path, "*_idl.py")) + for dir in poaList + npoaList: + fileList += Utilities.direntries(dir, True, "*.py") + for file in fileList: + self.project.appendFile(file) + if not self.noDialog: + QMessageBox.information(None, + self.trUtf8("Interface Compilation"), + self.trUtf8("The compilation of the interface file was successful.")) + else: + if not self.noDialog: + QMessageBox.information(None, + self.trUtf8("Interface Compilation"), + self.trUtf8("The compilation of the interface file failed.")) + self.compileProc = None + + def __compileIDL(self, fn, noDialog = False, progress = None): + """ + Privat method to compile a .idl file to python. + + @param fn filename of the .idl file to be compiled (string) + @param noDialog flag indicating silent operations (boolean) + @param progress reference to the progress dialog (QProgressDialog) + @return reference to the compile process (QProcess) + """ + self.compileProc = QProcess() + args = [] + + args.append("-bpython") + args.append("-I.") + + fn = os.path.join(self.project.ppath, fn) + self.idlFile = fn + args.append("-C%s" % os.path.dirname(fn)) + args.append(fn) + + self.connect(self.compileProc, SIGNAL('finished(int, QProcess::ExitStatus)'), + self.__compileIDLDone) + self.connect(self.compileProc, SIGNAL('readyReadStandardOutput()'), + self.__readStdout) + self.connect(self.compileProc, SIGNAL('readyReadStandardError()'), + self.__readStderr) + + self.noDialog = noDialog + self.compileProc.start(self.omniidl, args) + procStarted = self.compileProc.waitForStarted() + if procStarted: + self.compileRunning = True + return self.compileProc + else: + self.compileRunning = False + if progress is not None: + progress.cancel() + QMessageBox.critical(self, + self.trUtf8('Process Generation Error'), + self.trUtf8( + '<p>Could not start {0}.<br>' + 'Ensure that it is in the search path.</p>' + ).format(self.omniidl)) + return None + + def __compileInterface(self): + """ + Private method to compile an interface to python. + """ + if self.omniidl is not None: + itm = self.model().item(self.currentIndex()) + fn2 = itm.fileName() + fn = fn2.replace(self.project.ppath+os.sep, '') + self.__compileIDL(fn) + + def __compileAllInterfaces(self): + """ + Private method to compile all interfaces to python. + """ + if self.omniidl is not None: + numIDLs = len(self.project.pdata["INTERFACES"]) + progress = QProgressDialog(self.trUtf8("Compiling interfaces..."), + self.trUtf8("Abort"), 0, numIDLs, self) + progress.setModal(True) + progress.setMinimumDuration(0) + i = 0 + + for fn in self.project.pdata["INTERFACES"]: + progress.setValue(i) + if progress.wasCanceled(): + break + proc = self.__compileIDL(fn, True, progress) + if proc is not None: + while proc.state() == QProcess.Running: + QApplication.processEvents() + QThread.msleep(300) + QApplication.processEvents() + else: + break + i += 1 + + progress.setValue(numIDLs) + + def __compileSelectedInterfaces(self): + """ + Private method to compile selected interfaces to python. + """ + if self.omniidl is not None: + items = self.getSelectedItems() + + files = [itm.fileName().replace(self.project.ppath+os.sep, '') \ + for itm in items] + numIDLs = len(files) + progress = QProgressDialog(self.trUtf8("Compiling interfaces..."), + self.trUtf8("Abort"), 0, numIDLs, self) + progress.setModal(True) + progress.setMinimumDuration(0) + i = 0 + + for fn in files: + progress.setValue(i) + if progress.wasCanceled(): + break + proc = self.__compileIDL(fn, True, progress) + if proc is not None: + while proc.state() == QProcess.Running: + QApplication.processEvents() + QThread.msleep(300) + QApplication.processEvents() + else: + break + i += 1 + + progress.setValue(numIDLs) + + def __configureCorba(self): + """ + Private method to open the configuration dialog. + """ + e4App().getObject("UserInterface").showPreferences("corbaPage")