def __updateFindHistory(self): " Updates the find history if required " if self.findtextCombo.currentText() != "": if self._addToHistory(self.findtextCombo, self.findHistory, self.findtextCombo.currentText()): prj = GlobalData().project prj.setFindHistory(self.findHistory) return
def getImportedNameDefinitionLine( path, name, info = None ): """ Searches for the given name in the given file and provides its line number. -1 if not found. Only top level names are searched through. """ if info is None: mainWindow = GlobalData().mainWindow widget = mainWindow.getWidgetForFileName( os.path.realpath( path ) ) if widget is None: # The file is not opened now info = getBriefModuleInfoFromFile( path ) else: editor = widget.getEditor() info = getBriefModuleInfoFromMemory( editor.text() ) # Check the object names for classObj in info.classes: if classObj.name == name: return classObj.line for funcObj in info.functions: if funcObj.name == name: return funcObj.line for globalObj in info.globals: if globalObj.name == name: return globalObj.line return -1
def __init__( self, fileName = None, lineNumber = None, condition = "", temporary = False, enabled = True, ignoreCount = 0 ): if fileName is None: self.__fileName = fileName elif os.path.isabs( fileName ): project = GlobalData().project if project.isLoaded(): if project.isProjectFile( fileName ): # This is a project file; strip the project dir self.__fileName = fileName.replace( project.getProjectDir(), "" ) else: # Not a project file, save as is self.__fileName = fileName else: # Pretty much impossible self.__fileName = fileName else: # Relative path, i.e. a project file self.__fileName = fileName self.__lineNumber = lineNumber self.__condition = condition self.__temporary = temporary self.__enabled = enabled self.__ignoreCount = ignoreCount return
def codimensionMain(): """ The codimension driver """ # Parse command line arguments parser = OptionParser( """ %prog [options] [project file | python files] Runs codimension UI """, version = "%prog " + __version__ ) parser.add_option( "--debug", action="store_true", dest="debug", default=False, help="switch on debug and info messages (default: Off)" ) parser.add_option( "--clean-start", action="store_true", dest="cleanStart", default=False, help="do not restore previous IDE state (default: Off)" ) options, args = parser.parse_args() # Configure logging setupLogging( options.debug ) # The default exception handler can be replaced sys.excepthook = exceptionHook # Create global data singleton. # It's unlikely to throw any exceptions. globalData = GlobalData() globalData.version = __version__ # Loading settings - they have to be loaded before the application is # created. This is because the skin name is saved there. settings = Settings() copySkin() # Load the skin globalData.skin = Skin() globalData.skin.load( settingsDir + "skins" + os.path.sep + settings.skin ) # QT on UBUNTU has a bug - the main menu bar does not generate the # 'aboutToHide' signal (though 'aboutToShow' is generated properly. This # prevents codimension working properly so this hack below disables the # global menu bar for codimension and makes it working properly. os.environ[ "QT_X11_NO_NATIVE_MENUBAR" ] = "1" # Create QT application codimensionApp = CodimensionApplication( sys.argv, settings.style ) globalData.application = codimensionApp logging.debug( "Starting codimension v." + __version__ ) try: # Process command line arguments projectFile = processCommandLineArgs( args ) except Exception, exc: logging.error( str( exc ) ) parser.print_help() return 1
def search( self, expression ): " Perform search within this item " self.matches = [] if self.bufferUUID != "": # Search item is the currently loaded buffer mainWindow = GlobalData().mainWindow widget = mainWindow.getWidgetByUUID( self.bufferUUID ) if widget is not None: # Search in the buffer content = widget.getEditor().text().splitlines() self.__lookThroughLines( content, expression ) return # Here: there were no buffer or have not found it # try searching in a file if not os.path.isabs( self.fileName ) or \ not os.path.exists( self.fileName ): # Unfortunately not all network file systems report the # fact that a file has been deleted from the disk so # let's simply ignore such files return # File exists, search in the file try: f = open( self.fileName ) content = f.read().split( "\n" ) f.close() self.__lookThroughLines( content, expression ) except: logging.error( "Cannot read " + self.fileName ) return
def __errorActivated( self, item, column ): " Handles the double click (or Enter) on the item " linePos = str( item.text( 1 ) ) if ":" in linePos: parts = linePos.split( ":" ) lineNumber = int( parts[ 0 ] ) pos = int( parts[ 1 ] ) else: lineNumber = int( linePos ) pos = 0 if self.__reportOption in [ self.SingleFile, self.DirectoryFiles, self.ProjectFiles ]: fileName = str( item.text( 0 ) ) else: # SingleBuffer if self.__reportFileName != "": if os.path.isabs( self.__reportFileName ): fileName = self.__reportFileName else: # Could be unsaved buffer, so try to search by the mainWindow = GlobalData().mainWindow widget = mainWindow.getWidgetByUUID( self.__reportUUID ) if widget is None: logging.error( "The unsaved buffer has been closed" ) return # The widget was found, so jump to the required editor = widget.getEditor() editor.gotoLine( lineNumber, pos ) editor.setFocus() return GlobalData().mainWindow.openFile( fileName, lineNumber, pos ) return
def __onProjectChanged( self, what ): " Triggered when a project is changed " if what != CodimensionProject.CompleteProject: return self.clear() model = self.bpointsList.model().sourceModel() project = GlobalData().project if project.isLoaded(): bpoints = project.breakpoints else: bpoints = Settings().breakpoints for bp in bpoints: newBpoint = Breakpoint() try: if not newBpoint.deserialize( bp ): # Non valid continue except: continue # Need to check if it still points to a breakable line line = newBpoint.getLineNumber() fileName = newBpoint.getAbsoluteFileName() breakableLines = getBreakpointLines( fileName, None, True ) if breakableLines is not None and line in breakableLines: model.addBreakpoint( newBpoint ) else: logging.warning( "Breakpoint at " + fileName + ":" + str( line ) + " does not point to a breakable " "line anymore (the file is invalid or was " "modified outside of the " "IDE etc.). The breakpoint is deleted." ) return
def getProjectSpecificModules( path = "", onlySpecified = False ): " Provides a dictionary of the project specific modules " specificModules = {} importDirs = [] if not onlySpecified: importDirs = GlobalData().getProjectImportDirs() for importPath in importDirs: specificModules.update( getModules( importPath ) ) projectFile = GlobalData().project.fileName if projectFile != "": basedir = os.path.dirname( projectFile ) if basedir not in importDirs: importDirs.append( basedir ) specificModules.update( getModules( basedir ) ) if path and os.path.isabs( path ): path = os.path.normpath( path ) basedir = "" if os.path.isfile( path ): basedir = os.path.dirname( path ) elif os.path.isdir( path ): basedir = path if basedir and basedir not in importDirs: specificModules.update( getModules( basedir ) ) return specificModules
def __updateReplaceHistory(self, text, replaceText): " Updates the history in the project and in the combo boxes " changedWhat = self._addToHistory(self.findtextCombo, self.findHistory, text) changedReplace = self._addToHistory(self.replaceCombo, self.replaceHistory, replaceText) if changedWhat or changedReplace: prj = GlobalData().project prj.setReplaceHistory(self.findHistory, self.replaceHistory) return
def __serializeBreakpoints( self ): " Saves the breakpoints into a file " model = self.bpointsList.model().sourceModel() project = GlobalData().project if project.isLoaded(): project.setBreakpoints( model.serialize() ) else: Settings().breakpoints = model.serialize() return
def keyPressEvent( self, event ): """ Handles the key press events """ if event.key() == Qt.Key_Escape: editorsManager = GlobalData().mainWindow.editorsManager() activeWindow = editorsManager.currentWidget() if activeWindow: activeWindow.setFocus() event.accept() self.hide() return
def __onRemoveAllFromIgnore( self ): " Triggered when all the ignored exceptions should be deleted " self.clear() project = GlobalData().project if project.isLoaded(): project.setExceptionFilters( [] ) else: Settings().setExceptionFilters( [] ) return
def __init__(self, items, tooltip): QTreeWidgetItem.__init__(self, items) self.__intColumn = 0 self.__tooltip = tooltip self.__fileModified = False # Memorize the screen width global screenWidth screenSize = GlobalData().application.desktop().screenGeometry() screenWidth = screenSize.width() return
def getAbsoluteFileName( self ): " Provides the absolute file name " if self.__fileName is None: return None if os.path.isabs( self.__fileName ): return self.__fileName project = GlobalData().project if project.isLoaded(): return project.getProjectDir() + self.__fileName return os.path.abspath( self.__fileName )
def getIndicatorPixmap(indicatorID): " Provides a pixmap or None " for descriptor in IND_DESCRIPTION: if descriptor[0] == indicatorID: return descriptor[1] if indicatorID < 0: # It is an IDE defined indicator vcsManager = GlobalData().mainWindow.vcsManager systemIndicator = vcsManager.getSystemIndicator(indicatorID) if systemIndicator: return systemIndicator.pixmap return None
def __openFile(self): """Handles 'open' file menu item""" self.__fileContextItem.updateIconAndTooltip() fName = self.__fileContextItem.getFilename() if not self.__fileContextItem.isValid(): logging.warning("Cannot open %s", fName) return mime, _, _ = getFileProperties(fName) if isImageViewable(mime): GlobalData().mainWindow.openPixmapFile(fName) else: GlobalData().mainWindow.openFile(fName, -1)
def __init__(self, parent, bpointsModel): QWidget.__init__(self, parent) self.__currentItem = None self.__createLayout(bpointsModel) GlobalData().project.projectChanged.connect(self.__onProjectChanged) self.connect(GlobalData().project, SIGNAL('projectAboutToUnload'), self.__onProjectAboutToUnload) self.connect(self.bpointsList, SIGNAL("selectionChanged"), self.__onSelectionChanged) self.connect(bpointsModel, SIGNAL('BreakpoinsChanged'), self.__onModelChanged) return
def _resolveLink(self, link): """Resolves the link to a file and optional anchor/line number""" scheme = link.scheme().lower() if scheme in ['http', 'https']: QDesktopServices.openUrl(link) return None, None if scheme == '': fileName = link.path() elif scheme == 'file': if link.isValid(): fileName = link.path() else: logging.error('Invalid link: ' + link.errorString()) return None, None elif scheme == 'action': if link.isValid(): # The action is stored in the host part action = link.host() # The actions are predefined. I did not find a generic way # to find what the key is bound to if action.lower() == 'embedded-help': GlobalData().mainWindow._onEmbeddedHelp() elif action.lower() == 'f1': GlobalData().mainWindow.em.onHelp() elif action.lower() == 'project-cocumentation': GlobalData().mainWindow.projectDocClicked() else: # must be a keyboard shortcut logging.error("Unsupported action '" + link.host() + "'") return None, None else: logging.error("Unsupported url scheme '" + link.scheme() + "'. Supported schemes are 'http', 'https', 'file' " "and an empty scheme for files") return None, None if not fileName: logging.error('Could not get a file name. Check the link format. ' 'Valid examples: file:./relative/fname or ' 'file:relative/fname or file:/absolute/fname or ' 'file:///absolute/fname') return None, None fileName, anchorOrLine = resolveLinkPath( fileName, self._parentWidget.getFileName()) if anchorOrLine is None: if link.hasFragment(): return fileName, link.fragment() return fileName, anchorOrLine
def getJediScript(source, line, column, srcPath, needSysPath=True): """Provides the jedi Script object considering the current project""" jedi.settings.additional_dynamic_modules = [] paths = sys.path[:] if needSysPath else [] # This make relative imports resolvable if os.path.isabs(srcPath): dirName = os.path.dirname(srcPath) if dirName not in paths: paths.append(dirName) project = GlobalData().project if not project.isLoaded(): # Add the other opened files if so mainWindow = GlobalData().mainWindow for path in mainWindow.editorsManager().getOpenedList(): if path[0]: if path[0].lower().endswith('.py'): jedi.settings.additional_dynamic_modules.append(path[0]) return jedi.Script(source, line, column, srcPath, sys_path=paths) for path in project.getImportDirsAsAbsolutePaths(): if path not in paths: paths.append(path) projectDir = project.getProjectDir() if projectDir not in paths: paths.append(projectDir) return jedi.Script(source, line, column, srcPath, sys_path=paths)
def __populateFromProject( self ): " Populates find name dialog from the project files " mainWindow = GlobalData().mainWindow for fname in GlobalData().project.filesList: if detectFileType( fname ) in [ PythonFileType, Python3FileType ]: widget = mainWindow.getWidgetForFileName( fname ) if widget is None: info = GlobalData().briefModinfoCache.get( fname ) else: content = widget.getEditor().text() info = getBriefModuleInfoFromMemory( content ) self.__populateInfo( info, fname ) return
def __onProjectChanged(self, what): """Triggered when a project is changed""" if what == CodimensionProject.CompleteProject: self.__contextItem = None self.__updateButtons() self.filterEdit.clear() project = GlobalData().project if project.isLoaded(): self.filterEdit.editTextChanged.disconnect( self.__filterChanged) self.filterEdit.addItems(project.findClassHistory) self.filterEdit.editTextChanged.connect(self.__filterChanged) self.filterEdit.clearEditText()
def __loadProject( self ): " handles 'Load' context menu item " if self.__projectContextItem is None: return if not self.__projectContextItem.isValid(): return if self.__debugMode: return projectFileName = self.__projectContextItem.getFilename() if self.__projectContextItem.isCurrent(): GlobalData().mainWindow.openFile( projectFileName, -1 ) return # This is the current project, open for text editing QApplication.processEvents() QApplication.setOverrideCursor( QCursor( Qt.WaitCursor ) ) if os.path.exists( projectFileName ): mainWin = GlobalData().mainWindow editorsManager = mainWin.editorsManagerWidget.editorsManager if editorsManager.closeRequest(): prj = GlobalData().project prj.setTabsStatus( editorsManager.getTabsStatus() ) editorsManager.closeAll() prj.loadProject( projectFileName ) mainWin.activateProjectTab() else: logging.error( "The project " + \ os.path.basename( projectFileName ) + \ " disappeared from the file system." ) self.__populateProjects() QApplication.restoreOverrideCursor() return
def run(self, path, needDialog): " Runs the given script with redirected IO " if needDialog: params = GlobalData().getRunParameters(path) termType = Settings().terminalType profilerParams = Settings().getProfilerSettings() debuggerParams = Settings().getDebuggerSettings() dlg = RunDialog(path, params, termType, profilerParams, debuggerParams, "Run", self.__mainWindow) if dlg.exec_() != QDialog.Accepted: return GlobalData().addRunParams(path, dlg.runParams) if dlg.termType != termType: Settings().terminalType = dlg.termType # The parameters for the run are ready. # Start the run business. remoteProc = RemoteProcess() remoteProc.isProfiling = False remoteProc.procWrapper = RemoteProcessWrapper( path, self.__tcpServer.serverPort()) if Settings().terminalType == TERM_REDIRECT: remoteProc.widget = RunConsoleTabWidget( remoteProc.procWrapper.procID()) self.connect(remoteProc.procWrapper, SIGNAL('ClientStdout'), remoteProc.widget.appendStdoutMessage) self.connect(remoteProc.procWrapper, SIGNAL('ClientStderr'), remoteProc.widget.appendStderrMessage) self.connect(remoteProc.procWrapper, SIGNAL('ClientRawInput'), remoteProc.widget.rawInput) self.connect(remoteProc.widget, SIGNAL('UserInput'), self.__onUserInput) else: remoteProc.widget = None self.connect(remoteProc.procWrapper, SIGNAL('Finished'), self.__onProcessFinished) self.__processes.append(remoteProc) if remoteProc.procWrapper.start() == False: # Failed to start - the fact is logged, just remove from the list procIndex = self.__getProcessIndex(remoteProc.procWrapper.procID()) if procIndex is not None: del self.__processes[procIndex] else: if Settings().terminalType != TERM_REDIRECT: if not self.__waitTimer.isActive(): self.__waitTimer.start(1000) return
def __init__(self, parent=None): QWidget.__init__(self, parent) self.filterEdit = None self.definitionButton = None self.findButton = None self.globalsViewer = None self.copyPathButton = None self.__createLayout() # create the context menu self.__menu = QMenu(self) self.__jumpMenuItem = self.__menu.addAction( getIcon('definition.png'), 'Jump to definition', self.__goToDefinition) self.__menu.addSeparator() self.__findMenuItem = self.__menu.addAction( getIcon('findusage.png'), 'Find occurence', self.__findWhereUsed) self.__menu.addSeparator() self.__copyMenuItem = self.__menu.addAction( getIcon('copymenu.png'), 'Copy path to clipboard', self.globalsViewer.copyToClipboard) self.globalsViewer.setContextMenuPolicy(Qt.CustomContextMenu) self.globalsViewer.customContextMenuRequested.connect( self.__handleShowContextMenu) GlobalData().project.sigProjectChanged.connect(self.__onProjectChanged) self.globalsViewer.sigSelectionChanged.connect(self.__selectionChanged) self.globalsViewer.sigOpeningItem.connect(self.itemActivated) self.globalsViewer.sigModelFilesChanged.connect(self.modelFilesChanged) self.filterEdit.lineEdit().setFocus() self.__contextItem = None
def __onDisasm(self, optimization): """Common implementation""" if self.isPythonBuffer(): if os.path.isabs(self._parent.getFileName()): if not self._parent.isModified(): GlobalData().mainWindow.showFileDisassembly( self._parent.getFileName(), optimization) return fileName = self._parent.getFileName() if not fileName: fileName = self._parent.getShortName() encoding = self.encoding if not encoding: encoding = detectNewFileWriteEncoding(self, fileName) GlobalData().mainWindow.showBufferDisassembly( self.text, encoding, fileName, optimization)
def setSearchInProject(self, what="", filters=[]): " Set search ready for the whole project " if GlobalData().project.fileName == "": # No project loaded, fallback to opened files self.setSearchInOpenFiles(what, filters) return # Select the project radio button self.projectRButton.setEnabled(True) self.projectRButton.setChecked(True) self.dirEditCombo.setEnabled(False) self.dirSelectButton.setEnabled(False) openedFiles = self.editorsManager.getTextEditors() self.openFilesRButton.setEnabled(len(openedFiles) != 0) self.setFilters(filters) self.findCombo.setEditText(what) self.findCombo.lineEdit().selectAll() self.findCombo.setFocus() # Check searchability self.__testSearchability() return
def checkConflict( self, cdmPlugin ): """ Checks for the conflict and returns a message if so. If there is no conflict then returns None """ # First, check the base class baseClasses = getBaseClassNames( cdmPlugin.getObject() ) category = None for registeredCategory in CATEGORIES: if registeredCategory in baseClasses: category = registeredCategory break if category is None: return "Plugin category is not recognised" # Second, IDE version compatibility from utils.globals import GlobalData try: if not cdmPlugin.getObject().isIDEVersionCompatible( GlobalData().version ): return "Plugin requires the other IDE version" except: # Could not successfully call the interface method return "Error checking IDE version compatibility" # Third, the other plugin with the same name is active if category in self.activePlugins: for plugin in self.activePlugins[ category ]: if plugin.getName() == cdmPlugin.getName(): return "Another plugin of the same name is active" return None
def onScopeBegin(self): """The user requested jumping to the current scope begin""" if self.isPythonBuffer(): info = getBriefModuleInfoFromMemory(self.text) context = getContext(self, info, True) if context.getScope() != context.GlobalScope: GlobalData().mainWindow.jumpToLine(context.getLastScopeLine())
def __init__(self, items, isOutside, funcIDs): QTreeWidgetItem.__init__(self, items) self.__isOutside = isOutside self.__funcIDs = funcIDs # Set the first column icon if isOutside: self.setIcon(OUTSIDE_COL_INDEX, getIcon('nonprojectentry.png')) self.setToolTip(OUTSIDE_COL_INDEX, 'Record of an outside function') else: self.setIcon(OUTSIDE_COL_INDEX, getIcon('empty.png')) self.setToolTip(OUTSIDE_COL_INDEX, '') # Set the function name tooltip fileName = self.getFileName() lineNumber = self.getLineNumber() if fileName != "" and lineNumber != 0: self.setToolTip( NAME_COL_INDEX, GlobalData().getFileLineDocstring(fileName, lineNumber)) # Sets the location/name columns self.updateLocation(False) self.setText(NAME_COL_INDEX, self.getFunctionName()) for column in [ CALLS_COL_INDEX, TOTALPERCALL_COL_INDEX, CUM_COL_INDEX, CUMPERCALL_COL_INDEX, CALLERS_COL_INDEX, CALLEES_COL_INDEX ]: self.setTextAlignment(column, Qt.AlignRight) self.setTextAlignment(TOTAL_COL_INDEX, Qt.AlignLeft)
def __activatePlugins( self, collectedPlugins ): " Activating the plugins " from utils.globals import GlobalData for category in collectedPlugins: for plugin in collectedPlugins[ category ]: try: plugin.getObject().activate( Settings(), GlobalData() ) if category in self.activePlugins: self.activePlugins[ category ].append( plugin ) else: self.activePlugins[ category ] = [ plugin ] self.sendPluginActivated( plugin ) except Exception as excpt: logging.error( "Error activating plugin at " + plugin.getPath() + ". The plugin disabled. Error message: \n" + str( excpt ) ) plugin.conflictType = CDMPluginManager.BAD_ACTIVATION plugin.conflictMessage = "Error activating the plugin" if category in self.inactivePlugins: self.inactivePlugins[ category ].append( plugin ) else: self.inactivePlugins[ category ] = [ plugin ] return
def __getFileTooltip(path): " Provides the python file docstring for a tooltip " path = os.path.normpath(path) modInfo = GlobalData().briefModinfoCache.get(path) if modInfo.docstring is not None: return modInfo.docstring.text return ""
def __init__(self, headerData, parent=None): QAbstractItemModel.__init__(self, parent) self.rootItem = TreeViewItem(None, headerData) self.globalData = GlobalData() self.projectTopLevelDirs = [] self.showTooltips = True
def __init__(self, editorsManager, parent=None): FindReplaceBase.__init__(self, editorsManager, parent) self.horizontalLayout = QHBoxLayout(self) self.horizontalLayout.setMargin(0) self.horizontalLayout.addWidget(self.closeButton) self.horizontalLayout.addWidget(self.findLabel) self.horizontalLayout.addWidget(self.findtextCombo) self.horizontalLayout.addWidget(self.findPrevButton) self.horizontalLayout.addWidget(self.findNextButton) self.horizontalLayout.addWidget(self.caseCheckBox) self.horizontalLayout.addWidget(self.wordCheckBox) self.horizontalLayout.addWidget(self.regexpCheckBox) self.setTabOrder(self.findtextCombo, self.caseCheckBox) self.setTabOrder(self.caseCheckBox, self.wordCheckBox) self.setTabOrder(self.wordCheckBox, self.regexpCheckBox) self.setTabOrder(self.regexpCheckBox, self.findNextButton) self.setTabOrder(self.findNextButton, self.findPrevButton) self.setTabOrder(self.findPrevButton, self.closeButton) GlobalData().project.projectChanged.connect(self.__onProjectChanged) self.findNextButton.clicked.connect(self.onNext) self.findPrevButton.clicked.connect(self.onPrev) return
def mouseDoubleClickEvent(self, event): " Open the clicked file as the new one " # Jump to the first import statement line = self.__modObj.imports[0].line GlobalData().mainWindow.openFile(self.__modObj.refFile, line) return
def __findWhereUsed(self): """Find where used context menu handler""" contextItem = self.__outlineBrowsers[self.__currentUUID].contentItem if contextItem is not None: GlobalData().mainWindow.findWhereUsed( contextItem.getPath(), contextItem.sourceObj)
def __init__(self, parent): QWidget.__init__(self, parent) # Margin data is: # {lineNo: [(text, tooltip, msgType),...], } # line number is 1 based, tooltip and fgColor could be None self.__data = {} extendInstance(self, MarginBase) MarginBase.__init__(self, parent, 'cdm_redirected_io_margin', 0) self.setMouseTracking(True) skin = GlobalData().skin self.__bgColor = skin['marginPaper'] self.__fgColor = skin['marginColor'] # default CDMRedirectedIOMargin.MSG_TYPE_PROPS[IOConsoleMsg.IDE_MESSAGE][1] = \ skin['ioconsoleMarginIDEMsgColor'] CDMRedirectedIOMargin.MSG_TYPE_PROPS[IOConsoleMsg.STDOUT_MESSAGE][1] = \ skin['ioconsoleMarginStdoutColor'] CDMRedirectedIOMargin.MSG_TYPE_PROPS[IOConsoleMsg.STDERR_MESSAGE][1] = \ skin['ioconsoleMarginStderrColor'] CDMRedirectedIOMargin.MSG_TYPE_PROPS[IOConsoleMsg.STDIN_MESSAGE][1] = \ skin['ioconsoleMarginStdinColor'] self.__width = self.__calculateWidth() self.onTextZoomChanged() # The width needs to be re-calculated when the margin is drawn the # first time. The problem is that if the widget is not on the screen # then the font metrics are not calculated properly and thus the width # is not shown right. What I observed is an offset up to 2 pixels. self.__firstTime = True
def updateTooltip(self): """Updates the item tooltip""" fileName = self.getFilename() # Check that the file exists if not os.path.exists(fileName): self.__isValid = False self.setToolTip(0, 'Project file does not exist') self.setToolTip(1, 'Project file does not exist') self.__markBroken() else: # Get the project properties try: tooltip = getProjectFileTooltip(fileName) if Settings()['recentTooltips']: self.setToolTip(1, tooltip) else: self.setToolTip(1, "") self.setText(0, "") if fileName == GlobalData().project.fileName: self.__markCurrent() except: # Cannot get project properties. Mark broken. self.__isValid = False self.setToolTip(0, 'Broken project file') self.setToolTip(1, 'Broken project file') self.__markBroken() self.setToolTip(2, self.getFilename())
def setSearchInOpenFiles(self, what="", filters=[]): " Sets search ready for the opened files " openedFiles = self.editorsManager.getTextEditors() if len(openedFiles) == 0: # No opened files, fallback to search in dir self.setSearchInDirectory(what, "", filters) return # Select the radio buttons self.projectRButton.setEnabled(GlobalData().project.fileName != "") self.openFilesRButton.setEnabled(True) self.openFilesRButton.setChecked(True) self.dirEditCombo.setEnabled(False) self.dirSelectButton.setEnabled(False) self.setFilters(filters) self.findCombo.setEditText(what) self.findCombo.lineEdit().selectAll() self.findCombo.setFocus() # Check searchability self.__testSearchability() return
def onShowCalltip(self, showMessage=True): """The user requested show calltip""" if self.__calltip is not None: self.__resetCalltip() return if not self.isPythonBuffer(): return QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) signatures = getCallSignatures(self, self._parent.getFileName()) QApplication.restoreOverrideCursor() if not signatures: if showMessage: GlobalData().mainWindow.showStatusBarMessage( "No calltip found") return # For the time being let's take only the first signature... calltipParams = [] for param in signatures[0].params: calltipParams.append(param.description[len(param.type) + 1:]) calltip = signatures[0].name + '(' + ', '.join(calltipParams) + ')' self.__calltip = Calltip(self) self.__calltip.showCalltip(calltip, signatures[0].index) line = signatures[0].bracket_start[0] column = signatures[0].bracket_start[1] self.__callPosition = self.mapToAbsPosition(line - 1, column)
def __init__(self, editor, parent): QWidget.__init__(self, parent) # It is always not visible at the beginning because there is no # editor content at the start self.setVisible(False) self.__editor = editor self.__parentWidget = parent self.__connected = False self.__needPathUpdate = False self.cflowSettings = getCflowSettings(self) self.__displayProps = (self.cflowSettings.hidedocstrings, self.cflowSettings.hidecomments, self.cflowSettings.hideexcepts, Settings()['smartZoom']) hLayout = QHBoxLayout() hLayout.setContentsMargins(0, 0, 0, 0) hLayout.setSpacing(0) vLayout = QVBoxLayout() vLayout.setContentsMargins(0, 0, 0, 0) vLayout.setSpacing(0) # Make pylint happy self.__toolbar = None self.__navBar = None self.__cf = None self.__canvas = None self.__validGroups = [] self.__allGroupId = set() # Create the update timer self.__updateTimer = QTimer(self) self.__updateTimer.setSingleShot(True) self.__updateTimer.timeout.connect(self.process) vLayout.addWidget(self.__createNavigationBar()) vLayout.addWidget(self.__createStackedViews()) hLayout.addLayout(vLayout) hLayout.addWidget(self.__createToolbar()) self.setLayout(hLayout) self.updateSettings() # Connect to the change file type signal self.__mainWindow = GlobalData().mainWindow editorsManager = self.__mainWindow.editorsManagerWidget.editorsManager editorsManager.sigFileTypeChanged.connect(self.__onFileTypeChanged) Settings().sigHideDocstringsChanged.connect( self.__onHideDocstringsChanged) Settings().sigHideCommentsChanged.connect(self.__onHideCommentsChanged) Settings().sigHideExceptsChanged.connect(self.__onHideExceptsChanged) Settings().sigSmartZoomChanged.connect(self.__onSmartZoomChanged) self.setSmartZoomLevel(Settings()['smartZoom'])
def __init__(self, editor, parent): QFrame.__init__(self, parent) self.__editor = editor self.__parentWidget = parent # It is always not visible at the beginning because there is no # editor content at the start self.setVisible(False) # There is no parser info used to display values self.__currentInfo = None self.__currentIconState = self.STATE_UNKNOWN self.__connected = False # List of PathElement starting after the global scope self.__path = [] self.__createLayout() # Create the update timer self.__updateTimer = QTimer(self) self.__updateTimer.setSingleShot(True) self.__updateTimer.timeout.connect(self.updateBar) # Connect to the change file type signal mainWindow = GlobalData().mainWindow editorsManager = mainWindow.editorsManagerWidget.editorsManager editorsManager.sigFileTypeChanged.connect(self.__onFileTypeChanged)
def __init__(self, node, fileName, lineNumber, outside, nodeFont): QGraphicsRectItem.__init__(self) self.__node = node self.__fileName = fileName self.__lineNumber = lineNumber self.__outside = outside self.__font = DEFAULT_FONT if nodeFont: self.__font = nodeFont posX = node.posX - node.width / 2.0 posY = node.posY - node.height / 2.0 QGraphicsRectItem.__init__(self, posX, posY, node.width, node.height) self.setRectanglePen() # node.color is like "#fe0400" if node.color.startswith("#"): color = QColor(int(node.color[1:3], 16), int(node.color[3:5], 16), int(node.color[5:], 16)) else: color = QColor(220, 255, 220) self.setBrush(color) # To make item selectable self.setFlag(QGraphicsItem.ItemIsSelectable, os.path.isabs(self.__fileName) and self.__lineNumber > 0) # Set tooltip as a function docstring if fileName != "" and lineNumber != 0: self.setToolTip(GlobalData().getFileLineDocstring( fileName, lineNumber))
def setSearchInOpenFiles(self, what=None): """Sets search ready for the opened files""" openedFiles = self.editorsManager.getTextEditors() if not openedFiles: # No opened files, fallback to search in dir self.setSearchInDirectory(what, None) return # Select the radio buttons self.projectRButton.setEnabled(GlobalData().project.isLoaded()) self.openFilesRButton.setEnabled(True) self.openFilesRButton.setChecked(True) self.dirEditCombo.setEnabled(False) self.dirSelectButton.setEnabled(False) if what: # Pick up the history values if so comboIndex, historyIndex = self.__historyIndexByWhat(what) if historyIndex is not None: self.__deserialize(self.__history[historyIndex]) self.findCombo.setCurrentIndex(comboIndex) else: self.findCombo.setCurrentText(what) self.findCombo.lineEdit().selectAll() self.findCombo.setFocus() # Check searchability self.__testSearchability()
def setSearchInDirectory(self, what=None, dirPath=None): """Sets search ready for the given directory""" # Select radio buttons self.projectRButton.setEnabled(GlobalData().project.isLoaded()) openedFiles = self.editorsManager.getTextEditors() self.openFilesRButton.setEnabled(len(openedFiles) != 0) self.dirRButton.setEnabled(True) self.dirRButton.setChecked(True) self.dirEditCombo.setEnabled(True) self.dirSelectButton.setEnabled(True) if what: # Pick up the history values if so comboIndex, historyIndex = self.__historyIndexByWhat(what) if historyIndex is not None: self.__deserialize(self.__history[historyIndex]) self.findCombo.setCurrentIndex(comboIndex) else: self.findCombo.setCurrentText(what) self.findCombo.lineEdit().selectAll() if dirPath: self.dirEditCombo.setEditText(dirPath) self.findCombo.setFocus() # Check searchability self.__testSearchability()
def onFileUpdated(self, fileName, uuid): """Triggered when the file is updated""" del uuid # unused argument mime, icon, _ = getFileProperties(fileName) if isPythonMime(mime): path = os.path.realpath(fileName) info = GlobalData().briefModinfoCache.get(path) if info.isOK: icon = getIcon('filepython.png') else: icon = getIcon('filepythonbroken.png') # For all root items for treeItem in self.model().sourceModel().rootItem.childItems: self.__walkTreeAndUpdate(treeItem, path, mime, icon, info) elif isCDMProjectMime(mime): path = os.path.realpath(fileName) # For all root items for treeItem in self.model().sourceModel().rootItem.childItems: self.__walkTreeAndUpdate(treeItem, path, mime, None, None) elif fileName.endswith(".cgi"): path = os.path.realpath(fileName) # For all root items for treeItem in self.model().sourceModel().rootItem.childItems: self.__walkTreeAndUpdate(treeItem, path, mime, icon, None)
def __init__(self, parent=None): QWidget.__init__(self, parent) self.__reportUUID = "" self.__reportFileName = "" self.__reportOption = -1 self.__reportShown = False self.__report = None # Prepare members for reuse self.__noneLabel = QLabel("\nNo results available") self.__noneLabel.setFrameShape(QFrame.StyledPanel) self.__noneLabel.setAlignment(Qt.AlignHCenter) self.__headerFont = self.__noneLabel.font() self.__headerFont.setPointSize(self.__headerFont.pointSize() + 4) self.__noneLabel.setFont(self.__headerFont) self.__noneLabel.setAutoFillBackground(True) noneLabelPalette = self.__noneLabel.palette() noneLabelPalette.setColor(QPalette.Background, GlobalData().skin.nolexerPaper) self.__noneLabel.setPalette(noneLabelPalette) self.__createLayout(parent) self.__updateButtonsStatus() return
def onFileUpdated(self, fileName, uuid): " Triggered when the file is updated " fileType = detectFileType(fileName) if fileType in [PythonFileType, Python3FileType]: path = os.path.realpath(fileName) info = GlobalData().briefModinfoCache.get(path) if info.isOK: icon = PixmapCache().getIcon('filepython.png') else: icon = PixmapCache().getIcon('filepythonbroken.png') # For all root items for treeItem in self.model().sourceModel().rootItem.childItems: self.__walkTreeAndUpdate(treeItem, path, fileType, icon, info) elif fileType == CodimensionProjectFileType: path = os.path.realpath(fileName) # For all root items for treeItem in self.model().sourceModel().rootItem.childItems: self.__walkTreeAndUpdate(treeItem, path, fileType, None, None) elif fileName.endswith(".cgi"): path = os.path.realpath(fileName) icon = getFileIcon(fileType) # For all root items for treeItem in self.model().sourceModel().rootItem.childItems: self.__walkTreeAndUpdate(treeItem, path, fileType, icon, None) return
def __onProjectChanged( self, what ): " Triggered when a project is changed " if what != CodimensionProject.CompleteProject: return self.clear() project = GlobalData().project if project.isLoaded(): self.__ignored = list( project.ignoredExcpt ) else: self.__ignored = list( Settings().ignoredExceptions ) for exceptionType in self.__ignored: item = QTreeWidgetItem( self.exceptionsList ) item.setText( 0, exceptionType ) self.__updateTitle() return
def __allItemActivated( self, item, column ): " Handles the double click (or Enter) in the total results tree " # We process only the error messages and McCabe items hiddenColumnText = str( item.text( 2 ) ) if not hiddenColumnText in [ "M", "E" ]: return fileName = self.__getTreeItemFileName( item ) lineNumber = 0 if hiddenColumnText == "M": # This is McCabe item objName = str( item.text( 0 ) ) self.__onMcCabeObject( objName, fileName ) return elif hiddenColumnText == "E": # This is an error message message = str( item.text( 0 ) ) pos = message.find( "at line" ) if pos == -1: logging.error( "Unknown format of the message. " "Please inform the developers." ) return parts = message[ pos: ].split() try: lineNumber = int( parts[ 2 ].replace( ',', '' ) ) except: logging.error( "Unknown format of the message. " "Please inform the developers." ) return if fileName == "": # This is an unsaved buffer, try to find the editor by UUID mainWindow = GlobalData().mainWindow widget = mainWindow.getWidgetByUUID( self.__reportUUID ) if widget is None: logging.error( "The unsaved buffer has been closed" ) return # The widget was found, so jump to the required editor = widget.getEditor() editor.gotoLine( lineNumber ) editor.setFocus() return GlobalData().mainWindow.openFile( fileName, lineNumber ) return
def defaultFont( self, style ): """ Provides the default font for a style """ if style in [ PYGMENTS_COMMENT, PYGMENTS_PREPROCESSOR ]: f = GlobalData().skin.nolexerFont if style == PYGMENTS_PREPROCESSOR: f.setItalic( True ) return f if style in [ PYGMENTS_STRING ]: return GlobalData().skin.nolexerFont if style in [ PYGMENTS_KEYWORD, PYGMENTS_OPERATOR, PYGMENTS_WORD, PYGMENTS_BUILTIN, PYGMENTS_ATTRIBUTE, PYGMENTS_FUNCTION, PYGMENTS_CLASS, PYGMENTS_NAMESPACE, PYGMENTS_EXCEPTION, PYGMENTS_ENTITY, PYGMENTS_TAG, PYGMENTS_SCALAR, PYGMENTS_ESCAPE, PYGMENTS_HEADING, PYGMENTS_SUBHEADING, PYGMENTS_STRONG, PYGMENTS_PROMPT ]: f = LexerContainer.defaultFont( self, style ) f.setBold( True ) return f if style in [ PYGMENTS_DOCSTRING, PYGMENTS_EMPHASIZE ]: f = LexerContainer.defaultFont( self, style ) f.setItalic( True ) return f return LexerContainer.defaultFont( self, style )
def __onProjectChanged( self, what ): " Triggered when a project is changed " if what == CodimensionProject.CompleteProject: self.__contextItem = None self.__updateButtons() self.filterEdit.clear() project = GlobalData().project if project.isLoaded(): self.filterEdit.editTextChanged.disconnect( self.__filterChanged ) self.filterEdit.addItems( project.findGlobalHistory ) self.filterEdit.editTextChanged.connect( self.__filterChanged ) self.findNotUsedButton.setEnabled( self.getItemCount() > 0 ) else: self.findNotUsedButton.setEnabled( False ) self.filterEdit.clearEditText() return
def isValid( self ): " True if the breakpoint is valid " if self.__fileName is None: return False if os.path.isabs( self.__fileName ): if not os.path.exists( self.__fileName ): return False else: project = GlobalData().project if project.isLoaded(): path = project.getProjectDir() + self.__fileName if not os.path.exists( path ): return False else: if not os.path.exists( self.__fileName ): return False return self.__lineNumber is not None and \ self.__lineNumber > 0
def addExceptionFilter( self, excType ): " Adds a new item into the ignored exceptions list " if excType == "": return if " " in excType: return if excType in self.__ignored: return item = QTreeWidgetItem( self.exceptionsList ) item.setText( 0, excType ) project = GlobalData().project if project.isLoaded(): project.addExceptionFilter( excType ) else: Settings().addExceptionFilter( excType ) self.__ignored.append( excType ) self.__updateTitle() return
def __projectFiles( self, filterRe ): " Project files list respecting the mask " mainWindow = GlobalData().mainWindow files = [] for fname in GlobalData().project.filesList: if fname.endswith( sep ): continue if filterRe is None or filterRe.match( fname ): widget = mainWindow.getWidgetForFileName( fname ) if widget is None: # Do not check for broken symlinks if isFileSearchable( fname, False ): files.append( ItemToSearchIn( fname, "" ) ) else: if widget.getType() in \ [ MainWindowTabWidgetBase.PlainTextEditor ]: files.append( ItemToSearchIn( fname, widget.getUUID() ) ) QApplication.processEvents() if self.__cancelRequest: raise Exception( "Cancel request" ) return files
def jumpToCode( self, fileName, line ): " Jumps to the source code " editorsManager = GlobalData().mainWindow.editorsManager() editorsManager.openFile( fileName, line ) editor = editorsManager.currentWidget().getEditor() editor.gotoLine( line ) editorsManager.currentWidget().setFocus() return
def __dirFiles( self, path, filterRe, files ): " Files recursively for the dir " for item in os.listdir( path ): QApplication.processEvents() if self.__cancelRequest: raise Exception( "Cancel request" ) if os.path.isdir( path + item ): if item in [ ".svn", ".cvs" ]: # It does not make sense to search in revision control dirs continue anotherDir, isLoop = resolveLink( path + item ) if not isLoop: self.__dirFiles( anotherDir + sep, filterRe, files ) continue if not os.path.isfile( path + item ): continue realItem, isLoop = resolveLink( path + item ) if isLoop: continue if filterRe is None or filterRe.match( realItem ): found = False for itm in files: if itm.fileName == realItem: found = True break if not found: mainWindow = GlobalData().mainWindow widget = mainWindow.getWidgetForFileName( realItem ) if widget is None: if isFileSearchable( realItem ): files.append( ItemToSearchIn( realItem, "" ) ) else: if widget.getType() in \ [ MainWindowTabWidgetBase.PlainTextEditor ]: files.append( ItemToSearchIn( realItem, widget.getUUID() ) ) return
def __onRemoveFromIgnore( self ): " Removes an item from the ignored exception types list " if self.__currentItem is None: return text = self.__currentItem.text( 0 ) # Find the item index and remove it index = 0 while True: if self.exceptionsList.topLevelItem( index ).text( 0 ) == text: self.exceptionsList.takeTopLevelItem( index ) break index += 1 project = GlobalData().project if project.isLoaded(): project.deleteExceptionFilter( text ) else: Settings().deleteExceptionFilter( text ) self.__ignored.remove( text ) self.__updateTitle() return
def __init__( self, scriptName, params, reportTime, dataFile, stats, parent = None ): QWidget.__init__( self, parent ) self.__dataFile = dataFile self.__script = scriptName self.__reportTime = reportTime self.__params = params self.__stats = stats project = GlobalData().project if project.isLoaded(): self.__projectPrefix = os.path.dirname( project.fileName ) else: self.__projectPrefix = os.path.dirname( scriptName ) if not self.__projectPrefix.endswith( os.path.sep ): self.__projectPrefix += os.path.sep self.__createLayout() self.__getDiagramLayout() self.__viewer.setScene( self.__scene ) return
def __populateFromProject( self ): " Populates find name dialog from the project files " mainWindow = GlobalData().mainWindow showTooltips = Settings().findFileTooltips for fname in GlobalData().project.filesList: if fname.endswith( os.path.sep ): continue fileType = detectFileType( fname ) tooltip = "" if showTooltips and fileType in [ PythonFileType, Python3FileType ]: widget = mainWindow.getWidgetForFileName( fname ) if widget is None: info = GlobalData().briefModinfoCache.get( fname ) else: content = widget.getEditor().text() info = getBriefModuleInfoFromMemory( content ) if info.docstring is not None: tooltip = info.docstring.text newItem = FileItem( self.rootItem, getFileIcon( fileType ), fname, tooltip ) self.rootItem.appendChild( newItem ) self.count += 1 return
def launchUserInterface(): """ UI launch pad """ globalData = GlobalData() if not globalData.splash is None: globalData.splash.finish( globalData.mainWindow ) splashScreen = globalData.splash globalData.splash = None del splashScreen for message in __delayedWarnings: logging.warning( message ) # Load the available plugins globalData.pluginManager.load() # Additional checks may come here globalData.mainWindow.installRedirectedIOConsole() globalData.mainWindow.getToolbar().setVisible( Settings().showMainToolBar ) # Some startup time objects could be collected here. In my test runs # there were around 700 objects. gc.collect() return