def __init__(self, parent=None): TextTabWidget.__init__(self, parent) self.setHTML(self.__getContent()) self.setFileName("") self.setShortName("Welcome") GlobalData().project.sigProjectChanged.connect(self.__onProjectChanged)
def onFileUpdated( self, fileName, uuid ): " Triggered when the file is updated " self.clViewer.onFileUpdated( fileName ) self.findNotUsedButton.setEnabled( GlobalData().project.isLoaded() and \ self.getItemCount() > 0 ) return
def __getBrokenHeaderBackground(self): " Returns thr broken header background color as a string useful for CSS " return self.__toCSSColor( GlobalData().skin.outdatedOutlineColor.getRgb())
def clearSearchIndicators(self): """Hides the search indicator""" self.resetHighlight() GlobalData().mainWindow.clearStatusBarMessage()
def __filterItemAdded( self ): " The filter item has been added " project = GlobalData().project if project.fileName != "": project.setFindClassHistory( self.filterEdit.getItems() ) return
def exceptionHook(excType, excValue, tracebackObj): """Catches unhandled exceptions""" globalData = GlobalData() # Keyboard interrupt is a special case if issubclass(excType, KeyboardInterrupt): if globalData.application is not None: globalData.application.quit() return error = '%s: %s' % (excType.__name__, excValue) stackTraceString = ''.join( traceback.format_exception(excType, excValue, tracebackObj)) # Save the traceback to a file explicitly together with a log window # content. excptFileName = SETTINGS_DIR + 'unhandledexceptions.log' try: savedOK = True with open(excptFileName, 'a', encoding=DEFAULT_ENCODING) as diskfile: diskfile.write('------ Unhandled exception report at ' + str(datetime.datetime.now()) + '\n') diskfile.write('Traceback:\n') diskfile.write(stackTraceString) diskfile.write('Log window:\n') if globalData.mainWindow is not None: # i.e. the log window is available, save its content too logWindowContent = globalData.mainWindow.getLogViewerContent() logWindowContent = logWindowContent.strip() if logWindowContent: diskfile.write(logWindowContent) diskfile.write('\n') else: diskfile.write('Nothing is there\n') else: diskfile.write('Has not been created yet\n') diskfile.write('------\n\n') except: savedOK = False # This output will be to a console if the application has not started yet # or to a log window otherwise. logging.error('Unhandled exception is caught\n%s', stackTraceString) # Display the message as a QT modal dialog box if the application # has started if globalData.application is not None: message = "<html><body>" if savedOK: message += "Stack trace and log window content saved in " + \ excptFileName + ".<br>" else: message += "Failed to save stack trace and log window " \ "content in " + excptFileName + ".<br>" lines = stackTraceString.split('\n') if len(lines) > 32: message += "First 32 lines of the stack trace " \ "(the rest is truncated):" \ "<pre>" + "\n".join(lines[:32]) + "<pre>" else: message += "Stack trace:" + \ "<pre>" + stackTraceString + "</pre>" message += "</body></html>" QMessageBox.critical(None, "Unhandled exception: " + error, message) globalData.application.exit(1)
def __findWhereUsed(self): """Find where used context menu handler""" if self.__contextItem is not None: GlobalData().mainWindow.findWhereUsed(self.__contextItem.getPath(), self.__contextItem.sourceObj)
class BrowserModelBase(QAbstractItemModel): " Class implementing the file system browser model " def __init__(self, headerData, parent=None): QAbstractItemModel.__init__(self, parent) self.rootItem = TreeViewItem(None, headerData) self.globalData = GlobalData() self.projectTopLevelDirs = [] self.showTooltips = True return def setTooltips(self, switchOn): " Sets the tooltip mode: to show or not to show them " self.showTooltips = switchOn return def columnCount(self, parent=QModelIndex()): " Provides the number of columns " if parent.isValid(): return parent.internalPointer().columnCount() return self.rootItem.columnCount() def updateRootData(self, column, value): " Updates the root entry, i.e. header " self.rootItem.setData(column, value) self.headerDataChanged.emit(Qt.Horizontal, column, column) return def data(self, index, role): " Provides data of an item " if not index.isValid(): return QVariant() column = index.column() if role == Qt.DisplayRole: item = index.internalPointer() if column < item.columnCount(): return QVariant(item.data(column)) if column == item.columnCount() and \ column < self.columnCount( self.parent( index ) ): # This is for the case when an item under a multi-column # parent doesn't have a value for all the columns return QVariant("") elif role == Qt.DecorationRole: if column == 0: return QVariant(index.internalPointer().getIcon()) elif role == Qt.ToolTipRole: item = index.internalPointer() if column == 1 and item.path is not None: return QVariant(item.path) if self.showTooltips and column == 0 and item.toolTip != "": return QVariant(item.toolTip) return QVariant() def flags(self, index): " Provides the item flags " if not index.isValid(): return Qt.ItemIsEnabled return Qt.ItemIsEnabled | Qt.ItemIsSelectable def headerData(self, section, orientation, role=Qt.DisplayRole): " Provides the header data " if orientation == Qt.Horizontal and role == Qt.DisplayRole: if section >= self.rootItem.columnCount(): return QVariant("") return self.rootItem.data(section) return QVariant() def index(self, row, column, parent=QModelIndex()): " Creates an index " # The model/view framework considers negative values out-of-bounds, # however in python they work when indexing into lists. So make sure # we return an invalid index for out-of-bounds row/col if row < 0 or column < 0 or \ row >= self.rowCount( parent ) or \ column >= self.columnCount( parent ): return QModelIndex() if parent.isValid(): parentItem = parent.internalPointer() else: parentItem = self.rootItem try: if not parentItem.populated: self.populateItem(parentItem) childItem = parentItem.child(row) except IndexError: return QModelIndex() if childItem: return self.createIndex(row, column, childItem) return QModelIndex() def buildIndex(self, rowPath): " Builds index for the path (path is like [ 1, 2, 1, 16 ]) " result = QModelIndex() for row in rowPath: result = self.index(row, 0, result) return result def parent(self, index): " Provides the index of the parent object " if not index.isValid(): return QModelIndex() childItem = index.internalPointer() parentItem = childItem.parent() if parentItem == self.rootItem: return QModelIndex() return self.createIndex(parentItem.row(), 0, parentItem) def totalRowCount(self): " Provides the total number of rows " return self.rootItem.childCount() def rowCount(self, parent=QModelIndex()): " Provides the number of rows " # Only the first column should have children if parent.column() > 0: return 0 if not parent.isValid(): return self.rootItem.childCount() parentItem = parent.internalPointer() if not parentItem.populated: # lazy population self.populateItem(parentItem) return parentItem.childCount() def hasChildren(self, parent=QModelIndex()): " Returns True if the parent has children " # Only the first column should have children if parent.column() > 0: return False if not parent.isValid(): return self.rootItem.childCount() > 0 if parent.internalPointer().lazyPopulation: return True return parent.internalPointer().childCount() > 0 def clear(self): " Clears the model " self.rootItem.removeChildren() self.reset() return def item(self, index): " Provides a reference to an item " if not index.isValid(): return None return index.internalPointer() @staticmethod def _addItem(itm, parentItem): " Adds an item " parentItem.appendChild(itm) return def addItem(self, itm, parent=QModelIndex()): " Adds an item " if not parent.isValid(): parentItem = self.rootItem else: parentItem = parent.internalPointer() cnt = parentItem.childCount() self.beginInsertRows(parent, cnt, cnt) self._addItem(itm, parentItem) self.endInsertRows() return def populateItem(self, parentItem, repopulate=False): " Populates an item's subtree " if parentItem.itemType == DirectoryItemType: self.populateDirectoryItem(parentItem, repopulate) elif parentItem.itemType == SysPathItemType: self.populateSysPathItem(parentItem, repopulate) elif parentItem.itemType == FileItemType: self.populateFileItem(parentItem, repopulate) elif parentItem.itemType == GlobalsItemType: self.populateGlobalsItem(parentItem, repopulate) elif parentItem.itemType == ImportsItemType: self.populateImportsItem(parentItem, repopulate) elif parentItem.itemType == FunctionsItemType: self.populateFunctionsItem(parentItem, repopulate) elif parentItem.itemType == ClassesItemType: self.populateClassesItem(parentItem, repopulate) elif parentItem.itemType == ClassItemType: self.populateClassItem(parentItem, repopulate) elif parentItem.itemType == StaticAttributesItemType: self.populateStaticAttributesItem(parentItem, repopulate) elif parentItem.itemType == InstanceAttributesItemType: self.populateInstanceAttributesItem(parentItem, repopulate) elif parentItem.itemType == FunctionItemType: self.populateFunctionItem(parentItem, repopulate) elif parentItem.itemType == ImportItemType: self.populateImportItem(parentItem, repopulate) parentItem.populated = True return def populateDirectoryItem(self, parentItem, repopulate=False): " Populates a directory item's subtree " path = parentItem.getPath() if not os.path.exists(path): return QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) try: items = os.listdir(path) except Exception, exc: QApplication.restoreOverrideCursor() logging.error("Cannot populate directory. " + str(exc)) return excludes = ['.svn', '.cvs', '.hg', '.git'] items = [itm for itm in items if itm not in excludes] if parentItem.needVCSStatus: # That's the project browser. Filter out what not needed. excludeFunctor = GlobalData().project.shouldExclude items = [itm for itm in items if not excludeFunctor(itm)] pathsToRequest = [] if items: infoSrc = self.globalData.briefModinfoCache if repopulate: self.beginInsertRows( self.createIndex(parentItem.row(), 0, parentItem), 0, len(items) - 1) path = os.path.realpath(path) + os.path.sep for item in items: fullPath = path + item if os.path.isdir(fullPath): node = TreeViewDirectoryItem(parentItem, fullPath, False) if parentItem.needVCSStatus: pathsToRequest.append(fullPath + os.path.sep) else: node = TreeViewFileItem(parentItem, fullPath) if parentItem.needVCSStatus: pathsToRequest.append(fullPath) if node.fileType in [PythonFileType, Python3FileType]: modInfo = infoSrc.get(fullPath) node.toolTip = "" if modInfo.docstring is not None: node.toolTip = modInfo.docstring.text if modInfo.isOK == False: # Substitute icon and change the tooltip node.icon = PixmapCache().getIcon( 'filepythonbroken.png') if node.toolTip != "": node.toolTip += "\n\n" node.toolTip += "Parsing errors:\n" + \ "\n".join( modInfo.lexerErrors + \ modInfo.errors ) node.parsingErrors = True if modInfo.encoding is None and \ not modInfo.imports and \ not modInfo.globals and \ not modInfo.functions and \ not modInfo.classes: node.populated = True node.lazyPopulation = False node.needVCSStatus = parentItem.needVCSStatus self._addItem(node, parentItem) if repopulate: self.endInsertRows() parentItem.populated = True # Request statuses of the populated items. The request must be sent # after the items are added, otherwise the status received by the model # before the items are populated thus not updated properly. for path in pathsToRequest: GlobalData().mainWindow.vcsManager.requestStatus(path) QApplication.restoreOverrideCursor() return
def __init__(self, scriptName, params, reportTime, dataFile, stats, parent=None): QWidget.__init__(self, parent) self.__table = ProfilerTreeWidget(self) self.__table.sigEscapePressed.connect(self.__onEsc) self.__script = scriptName 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.__table.setAlternatingRowColors(True) self.__table.setRootIsDecorated(False) self.__table.setItemsExpandable(False) self.__table.setSortingEnabled(True) self.__table.setItemDelegate(NoOutlineHeightDelegate(4)) self.__table.setUniformRowHeights(True) self.__table.setSelectionMode(QAbstractItemView.SingleSelection) self.__table.setSelectionBehavior(QAbstractItemView.SelectRows) headerLabels = [ "", "Calls", "Total time", "Per call", "Cum. time", "Per call", "File name:line", "Function", "Callers", "Callees" ] self.__table.setHeaderLabels(headerLabels) headerItem = self.__table.headerItem() headerItem.setToolTip(0, "Indication if it is an outside function") headerItem.setToolTip( 1, "Actual number of calls/primitive calls " "(not induced via recursion)") headerItem.setToolTip( 2, "Total time spent in function " "(excluding time made in calls " "to sub-functions)") headerItem.setToolTip( 3, "Total time divided by number " "of actual calls") headerItem.setToolTip( 4, "Total time spent in function and all " "subfunctions (from invocation till exit)") headerItem.setToolTip( 5, "Cumulative time divided by number " "of primitive calls") headerItem.setToolTip(6, "Function location") headerItem.setToolTip(7, "Function name") headerItem.setToolTip(8, "Function callers") headerItem.setToolTip(9, "Function callees") self.__table.itemActivated.connect(self.__activated) totalCalls = self.__stats.total_calls # The calls were not induced via recursion totalPrimitiveCalls = self.__stats.prim_calls totalTime = self.__stats.total_tt txt = "<b>Script:</b> " + self.__script + " " + \ params['arguments'] + "<br/>" \ "<b>Run at:</b> " + reportTime + "<br/>" + \ str(totalCalls) + " function calls (" + \ str(totalPrimitiveCalls) + " primitive calls) in " + \ FLOAT_FORMAT % totalTime + " CPU seconds" summary = HeaderFitLabel(self) summary.setText(txt) summary.setToolTip(txt) summary.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed) summary.setMinimumWidth(10) vLayout = QVBoxLayout() vLayout.setContentsMargins(0, 0, 0, 0) vLayout.setSpacing(0) vLayout.addWidget(summary) vLayout.addWidget(self.__table) self.setLayout(vLayout) self.__createContextMenu() self.__populate(totalTime)
def onFileUpdated(self, fileName, uuid): """Triggered when the file is updated""" del uuid # unused argument self.funcViewer.onFileUpdated(fileName) self.findNotUsedButton.setEnabled(GlobalData().project.isLoaded() and self.getItemCount() > 0)
def analyzeFile(self, path, pylintrc="", importDirs=[], workingDir=""): " run pylint for a certain file or files list " self.retCode = -1 self.errorMessages = [] self.tables = [] self.similarities = [] self.dependencies = None self.statementsAnalysed = 0 self.score = 0.0 self.previousScore = 0.0 self.__currentSection = [] if pylintrc != "" and not os.path.exists(pylintrc): # This is a buffer with an rc content tempDirName = tempfile.mkdtemp() if not tempDirName.endswith(os.path.sep): tempDirName += os.path.sep tempFileName = tempDirName + "temp_pylint.rc" temporaryStorage = open(tempFileName, "w") temporaryStorage.write(str(pylintrc)) temporaryStorage.close() if type(path) == type("a"): path = path.split() # Run pylint with a parseable output and with messages types try: rcArg = [] if pylintrc: if os.path.exists(pylintrc): rcArg = ["--rcfile=" + pylintrc] else: rcArg = ["--rcfile=" + tempFileName] initHook = ["--init-hook"] code = "" if importDirs: code = "import sys" for dirName in importDirs: code += ";sys.path.insert(0,'" + dirName + "')" # Dirty hack to support CGI files pylinting if code: code += ";\n" code += "try: from logilab.common import modutils;" \ "modutils.PY_SOURCE_EXTS=('py','cgi');\nexcept: pass" initHook.append(code) if GlobalData().pylintVersion < StrictVersion("1.0.0"): formatArg = ['-f', 'parseable', '-i', 'y'] else: formatArg = [ '--msg-template="{path}:{line}: [{msg_id}, {obj}] {msg}"' ] skipTillRecognised = False # print "Command line: pylint: " + " ".join( formatArg + initHook + rcArg + path ) # print "Dir: " + workingDir output = self.__run(['pylint'] + formatArg + initHook + rcArg + path, workingDir).split('\n') for index in xrange(len(output)): line = output[index] if skipTillRecognised: lineType, shouldSkip = self.__detectLineType(output, index) if lineType == self.Unknown: continue skipTillRecognised = shouldSkip else: lineType, skipTillRecognised = self.__detectLineType( output, index) if verbose: print str(lineType) + " -> " + line if lineType == self.Header: continue if lineType == self.Message: self.errorMessages.append( ErrorMessage(output, index, workingDir)) continue if lineType == self.Unknown: self.__currentSection.append(line) continue # Here: beginning of a section or beginning of a similarity # message self.__parseCurrentSection(path) self.__currentSection.append(line) # Final section parsing self.__parseCurrentSection(path) except Exception: if pylintrc != "" and not os.path.exists(pylintrc): os.unlink(tempFileName) os.rmdir(tempDirName) raise if pylintrc != "" and not os.path.exists(pylintrc): os.unlink(tempFileName) os.rmdir(tempDirName) return
def __findNotUsed(): """Runs the unused function analysis""" GlobalData().mainWindow.onNotUsedFunctions()
def _onAnchorClicked(self, link): """Handles a URL click""" fileName, anchorOrLine = self._resolveLink(link) if fileName: GlobalData().mainWindow.openFile(fileName, anchorOrLine)
def __createLayout(self, varName, varType, varValue, isGlobal): """ Creates the dialog layout """ varTypeParts = varType.split() if varTypeParts[0].lower() in ["string", "unicode", "qstring"]: length = str(len(varValue)) lines = str(len(varValue.splitlines())) varType = varType.split( "(" )[ 0 ].strip() + \ " (lines: " + lines + ", characters: " + length + ")" self.resize(600, 250) self.setSizeGripEnabled(True) # Top level layout layout = QVBoxLayout(self) gridLayout = QGridLayout() gridLayout.setSpacing(2) varScopeLabel = QLabel("Scope:") gridLayout.addWidget(varScopeLabel, 0, 0, Qt.AlignTop) if isGlobal: varScopeValue = FramedLabelWithDoubleClick("Global") else: varScopeValue = FramedLabelWithDoubleClick("Local") varScopeValue.setToolTip("Double click to copy") font = varScopeValue.font() font.setFamily(GlobalData().skin.baseMonoFontFace) varScopeValue.setFont(font) gridLayout.addWidget(varScopeValue, 0, 1) varNameLabel = QLabel("Name:") gridLayout.addWidget(varNameLabel, 1, 0, Qt.AlignTop) varNameValue = FramedLabelWithDoubleClick(varName) varNameValue.setToolTip("Double click to copy") varNameValue.setFont(font) gridLayout.addWidget(varNameValue, 1, 1) varTypeLabel = QLabel("Type:") gridLayout.addWidget(varTypeLabel, 2, 0, Qt.AlignTop) varTypeValue = FramedLabelWithDoubleClick(varType) varTypeValue.setToolTip("Double click to copy") varTypeValue.setFont(font) gridLayout.addWidget(varTypeValue, 2, 1) varValueLabel = QLabel("Value:") gridLayout.addWidget(varValueLabel, 3, 0, Qt.AlignTop) varValueValue = QTextEdit() varValueValue.setReadOnly(True) varValueValue.setFontFamily(GlobalData().skin.baseMonoFontFace) # varValueValue.setLineWrapMode( QTextEdit.NoWrap ) varValueValue.setAcceptRichText(False) varValueValue.setPlainText(varValue) gridLayout.addWidget(varValueValue, 3, 1) layout.addLayout(gridLayout) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok) self.__OKButton = buttonBox.button(QDialogButtonBox.Ok) self.__OKButton.setDefault(True) buttonBox.accepted.connect(self.close) buttonBox.rejected.connect(self.close) layout.addWidget(buttonBox) varValueValue.setFocus() return
def main(self): """The codimension driver""" usageMessage = 'Usage: %prog [options] [project file | python files]' parser = OptionParser(usage=usageMessage, version='%prog ' + VER) 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)') self.__options, self.__args = parser.parse_args() self.setupLogging() # 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 = VER # Loading settings - they have to be loaded before the application is # created. This is because the skin name is saved there. settings = Settings() self.copySkin() # Load the skin globalData.skin = Skin() globalData.skin.load(SETTINGS_DIR + 'skins' + os.path.sep + settings['skin']) self.__delayedWarnings += settings.validateZoom( globalData.skin.minTextZoom, globalData.skin.minCFlowZoom) # 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.%s', VER) try: # Process command line arguments self.__projectFile = self.processCommandLineArgs() except Exception as exc: logging.error(str(exc)) parser.print_help() return 1 # Show splash screen self.__splash = SplashScreen() screenSize = codimensionApp.desktop().screenGeometry() globalData.screenWidth = screenSize.width() globalData.screenHeight = screenSize.height() self.__splash.showMessage('Importing packages...') from ui.mainwindow import CodimensionMainWindow self.__splash.showMessage('Generating main window...') mainWindow = CodimensionMainWindow(self.__splash, settings) codimensionApp.setMainWindow(mainWindow) globalData.mainWindow = mainWindow codimensionApp.lastWindowClosed.connect(codimensionApp.quit) mainWindow.show() mainWindow.restoreWindowPosition() mainWindow.restoreSplitterSizes() # Launch the user interface QTimer.singleShot(1, self.launchUserInterface) # Run the application main cycle retVal = codimensionApp.exec_() return retVal
def __onDeadCode(self): """Triggered when vulture analysis is requested""" GlobalData().mainWindow.tabDeadCodeClicked()
def launchUserInterface(self): """UI launchpad""" globalData = GlobalData() self.__splash.showMessage('Loading plugins...') globalData.pluginManager.load() settings = Settings() mainWindow = globalData.mainWindow mainWindow.getToolbar().setVisible(settings['showMainToolBar']) needSignal = True if self.__options.cleanStart: # Codimension will not load anything. pass elif self.__projectFile: self.__splash.showMessage('Loading project...') globalData.project.loadProject(self.__projectFile) needSignal = False elif self.__args: # There are arguments and they are python files # The project should not be loaded but the files should # be opened for fName in self.__args: mainWindow.openFile(os.path.abspath(fName), -1) elif settings['projectLoaded']: if not settings['recentProjects']: # Some project was loaded but now it is not available. pass else: self.__splash.showMessage('Loading project...') if os.path.exists(settings['recentProjects'][0]): globalData.project.loadProject( settings['recentProjects'][0]) needSignal = False else: self.__delayedWarnings.append( 'Cannot open the most recent project: ' + settings['recentProjects'][0] + '. Ignore and continue.') else: mainWindow.em.restoreTabs(settings.tabStatus) # Signal for triggering browsers layout if needSignal: globalData.project.sigProjectChanged.emit( CodimensionProject.CompleteProject) # The editors positions can be restored properly only when the editors have # actually been drawn. Otherwise the first visible line is unknown. # So, I load the project first and let object browsers initialize # themselves and then manually call the main window handler to restore the # editors. The last step is to connect the signal. mainWindow.onProjectChanged(CodimensionProject.CompleteProject) globalData.project.sigProjectChanged.connect( mainWindow.onProjectChanged) self.__splash.finish(globalData.mainWindow) self.__splash = None del self.__splash for message in self.__delayedWarnings: logging.warning(message) # Some startup time objects could be collected here. In my test runs # there were around 700 objects. gc.collect()
def onRunScript(action=None): """Runs the script""" del action # unused argument GlobalData().mainWindow.onRunTab()
def __filterItemAdded(self): """The filter item has been added""" project = GlobalData().project if project.isLoaded(): project.findFunctionHistory = self.filterEdit.getItems()
def onRunScriptDlg(): """Shows the run parameters dialogue""" GlobalData().mainWindow.onRunTabDlg()
def __testSearchability(self): """Tests the searchability and sets the Find button status""" startTime = time.time() if self.findCombo.currentText().strip() == "": self.findButton.setEnabled(False) self.findButton.setToolTip("No text to search") return if self.dirRButton.isChecked(): dirname = self.dirEditCombo.currentText().strip() if dirname == "": self.findButton.setEnabled(False) self.findButton.setToolTip("No directory path") return if not isdir(dirname): self.findButton.setEnabled(False) self.findButton.setToolTip("Path is not a directory") return # Now we need to match file names if there is a filter filtersText = self.filterCombo.currentText().strip() if filtersText == "": self.findButton.setEnabled(True) self.findButton.setToolTip("Find in files") return # Need to check the files match try: filters = self.__compileFilters() except: self.findButton.setEnabled(False) self.findButton.setToolTip("Incorrect files " "filter regular expression") return matched = False tooLong = False if self.projectRButton.isChecked(): # Whole project for fname in GlobalData().project.filesList: if fname.endswith(sep): continue matched = self.__filterMatch(filters, fname) if matched: break # Check the time, it might took too long if time.time() - startTime > 0.1: tooLong = True break elif self.openFilesRButton.isChecked(): # Opened files openedFiles = self.editorsManager.getTextEditors() for record in openedFiles: matched = self.__filterMatch(filters, record[1]) if matched: break # Check the time, it might took too long if time.time() - startTime > 0.1: tooLong = True break else: # Search in the dir if not dirname.endswith(sep): dirname += sep matched, tooLong = self.__matchInDir(dirname, filters, startTime) if matched: self.findButton.setEnabled(True) self.findButton.setToolTip("Find in files") else: if tooLong: self.findButton.setEnabled(True) self.findButton.setToolTip("Find in files") else: self.findButton.setEnabled(False) self.findButton.setToolTip("No files matched to search in")
def onProfileScript(action=None): """Profiles the script""" del action # unused argument GlobalData().mainWindow.onProfileTab()
def __showStatusBarMessage(msg): """Shows a main window status bar message""" mainWindow = GlobalData().mainWindow mainWindow.showStatusBarMessage(msg, 8000)
def onProfileScriptDlg(): """Shows the profile parameters dialogue""" GlobalData().mainWindow.onProfileTabDlg()
def __findNotUsed( self ): " Runs the unused class analysis " GlobalData().mainWindow.onNotUsedClasses() return
def onDebugScript(action=None): """Starts debugging""" del action # unused argument GlobalData().mainWindow.onDebugTab()
def modelFilesChanged( self ): " Triggered when the source model has a file or files added or deleted " self.findNotUsedButton.setEnabled( GlobalData().project.isLoaded() and \ self.getItemCount() > 0 ) return
def onDebugScriptDlg(): """Shows the debug parameters dialogue""" GlobalData().mainWindow.onDebugTabDlg()
def __getImportedObjects(moduleName, fileName): " Provides a list of objects to be imported from " buildSystemWideModulesList() modulePath = None moduleName = str(moduleName) if moduleName in __systemwideModules: modulePath = __systemwideModules[moduleName] if modulePath is None or moduleName in Settings().dirSafeModules: # it could be a built-in module return getImportNames(moduleName) else: # Not a system wide, try search in the project # or current directories if moduleName.startswith("."): # That's a relative import if not fileName: # File name must be known for a relative import return set() dotCount = 0 while moduleName.startswith("."): dotCount += 1 moduleName = moduleName[1:] # Strip as many paths as dots instruct baseDir = os.path.dirname(fileName) while dotCount > 1: baseDir = os.path.dirname(baseDir) dotCount -= 1 specificModules = getProjectSpecificModules(baseDir, True) else: specificModules = getProjectSpecificModules(fileName) if moduleName in specificModules: modulePath = specificModules[moduleName] if modulePath is None: return set() binarySuffix = __isBinaryModule(modulePath) if binarySuffix is not None: try: modName = os.path.basename(modulePath) modObj = imp.load_module(modName, None, modulePath, binarySuffix) return set(dir(modObj)) except: # Failed to load a binary module return set() # It's not a binary module, so parse it and make a list of objects. # Check first if the module is loaded into the editor mainWindow = GlobalData().mainWindow editorsManager = mainWindow.editorsManagerWidget.editorsManager widget = editorsManager.getWidgetForFileName(modulePath) if widget is None: # Not loaded, so parse it from a file info = getBriefModuleInfoFromFile(modulePath) else: # Parse it from memory because it could be changed editor = widget.getEditor() info = getBriefModuleInfoFromMemory(editor.text()) return __getParsedModuleNames(info)
def __createLayout(self, parent): " Helper to create the viewer layout " # __textEdit list area self.__textEdit = QPlainTextEdit(parent) self.__textEdit.setLineWrapMode(QPlainTextEdit.NoWrap) self.__textEdit.setFont(QFont(GlobalData().skin.baseMonoFontFace)) self.__textEdit.setReadOnly(True) # Default font size is good enough for most of the systems. # 12.0 might be good only in case of the XServer on PC (Xming). # self.__textEdit.setFontPointSize( 12.0 ) # Buttons self.__selectAllButton = QAction( PixmapCache().getIcon('selectall.png'), 'Select all', self) self.__selectAllButton.triggered.connect(self.__textEdit.selectAll) self.__copyButton = QAction( PixmapCache().getIcon('copytoclipboard.png'), 'Copy to clipboard', self) self.__copyButton.triggered.connect(self.__textEdit.copy) spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.__clearButton = QAction(PixmapCache().getIcon('trash.png'), 'Clear all', self) self.__clearButton.triggered.connect(self.__clear) # Toolbar toolbar = QToolBar() toolbar.setOrientation(Qt.Vertical) toolbar.setMovable(False) toolbar.setAllowedAreas(Qt.LeftToolBarArea) toolbar.setIconSize(QSize(16, 16)) toolbar.setFixedWidth(28) toolbar.setContentsMargins(0, 0, 0, 0) toolbar.addAction(self.__selectAllButton) toolbar.addAction(self.__copyButton) toolbar.addWidget(spacer) toolbar.addAction(self.__clearButton) self.__header = QLabel("Signature: none") self.__header.setFrameStyle(QFrame.StyledPanel) self.__header.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed) self.__header.setAutoFillBackground(True) headerPalette = self.__header.palette() headerBackground = headerPalette.color(QPalette.Background) headerBackground.setRgb(min(headerBackground.red() + 30, 255), min(headerBackground.green() + 30, 255), min(headerBackground.blue() + 30, 255)) headerPalette.setColor(QPalette.Background, headerBackground) self.__header.setPalette(headerPalette) verticalLayout = QVBoxLayout() verticalLayout.setContentsMargins(2, 2, 2, 2) verticalLayout.setSpacing(2) verticalLayout.addWidget(self.__header) verticalLayout.addWidget(self.__textEdit) # layout layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(toolbar) layout.addLayout(verticalLayout) self.setLayout(layout) return