class InputDockWidget(QDockWidget): def __init__(self, *args): QDockWidget.__init__(self, *args) self.setupUi(self) self.setWindowIcon(QIcon(':/icons/qtsixa.png')) self.color = QColor(Qt.lightGray) self.setMinimumWidth(350) self.setContentsMargins(0, 0, 0, 0) self.adjustSize() def setupUi(self, QtSixAMainW): QtSixAMainW.setObjectName(_fromUtf8('QtSixAMainW')) QtSixAMainW.resize(935, 513) triggers = TiggersView(self) triggers.show() bumpers = BumpersView(self) bumpers.show() face = FaceButtonsView(self) face.show() dpad = DpadView(self) dpad.show() select = StartSelectView(self) select.show() sixaxis = SixAxisView(self) sixaxis.show() hbox = QHBoxLayout() hbox.addStretch(1) hbox.addWidget(triggers) hbox.addWidget(bumpers) hbox.addWidget(dpad) hbox.addWidget(face) hbox.addWidget(select) hbox.addWidget(sixaxis) vbox = QVBoxLayout() vbox.addStretch(1) vbox.addLayout(hbox) self.setLayout(vbox) self.progress = QProgressBar(self) self.progress.setGeometry(20, 2, 50, 20) self.progress.setTextVisible(False) self.progress.setOrientation(Qt.Vertical) self.progress.setValue(80) self.progress.move(60,28) self.progress.show() print self.style().objectName() QApplication.setStyle(QStyleFactory.create('Cleanlooks')) def paintEvent(self, event = None): pass
class NotUsedAnalysisProgress(QDialog): " Progress of the not used analysis " Functions = 0 Classes = 1 Globals = 2 def __init__(self, what, sourceModel, parent=None): QDialog.__init__(self, parent) if what not in [self.Functions, self.Classes, self.Globals]: raise Exception( "Unsupported unused analysis type: " + \ str( what ) ) self.__cancelRequest = False self.__inProgress = False self.__what = what # what is in source model self.__srcModel = sourceModel # source model of globals or # functions or classes # Avoid pylint complains self.__progressBar = None self.__infoLabel = None self.__foundLabel = None self.__found = 0 # Number of found self.__createLayout() self.setWindowTitle(self.__formTitle()) QTimer.singleShot(0, self.__process) return def keyPressEvent(self, event): " Processes the ESC key specifically " if event.key() == Qt.Key_Escape: self.__onClose() else: QDialog.keyPressEvent(self, event) return def __formTitle(self): " Forms the progress dialog title " title = "Unused " if self.__what == self.Functions: title += 'function' elif self.__what == self.Classes: title += 'class' else: title += 'globlal variable' return title + " analysis" def __formInfoLabel(self, name): " Forms the info label " if self.__what == self.Functions: return 'Function: ' + name if self.__what == self.Classes: return 'Class: ' + name return 'Globlal variable: ' + name def __whatAsString(self): " Provides 'what' as string " if self.__what == self.Functions: return 'function' if self.__what == self.Classes: return 'class' return 'global variable' def __updateFoundLabel(self): " Updates the found label " text = "Found: " + str(self.__found) + " candidate" if self.__found != 1: text += "s" self.__foundLabel.setText(text) return def __createLayout(self): """ Creates the dialog layout """ self.resize(450, 20) self.setSizeGripEnabled(True) verticalLayout = QVBoxLayout(self) # Note label noteLabel = QLabel( "<b>Note</b>: the analysis is " \ "suggestive and not precise. " \ "Use the results with caution.\n", self ) verticalLayout.addWidget(noteLabel) # Info label self.__infoLabel = QLabel(self) verticalLayout.addWidget(self.__infoLabel) # Progress bar self.__progressBar = QProgressBar(self) self.__progressBar.setValue(0) self.__progressBar.setOrientation(Qt.Horizontal) verticalLayout.addWidget(self.__progressBar) # Found label self.__foundLabel = QLabel(self) verticalLayout.addWidget(self.__foundLabel) # Buttons buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Close) verticalLayout.addWidget(buttonBox) buttonBox.rejected.connect(self.__onClose) return def __onClose(self): " triggered when the close button is clicked " self.__cancelRequest = True if not self.__inProgress: self.close() return def __process(self): " Analysis process " self.__inProgress = True mainWindow = GlobalData().mainWindow editorsManager = mainWindow.editorsManagerWidget.editorsManager modified = editorsManager.getModifiedList( True) # True - only project files if modified: modNames = [modItem[0] for modItem in modified] label = "File" if len(modified) >= 2: label += "s" label += ": " logging.warning( "The analisys is performed for the content of saved files. " \ "The unsaved modifications will not be taken into account. " \ + label + ", ".join( modNames ) ) self.__updateFoundLabel() self.__progressBar.setRange(0, len(self.__srcModel.rootItem.childItems)) QApplication.processEvents() QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) count = 0 candidates = [] for treeItem in self.__srcModel.rootItem.childItems: if self.__cancelRequest: break name = str(treeItem.data(0)).split('(')[0] path = os.path.realpath(treeItem.getPath()) lineNumber = int(treeItem.data(2)) absPosition = treeItem.sourceObj.absPosition count += 1 self.__progressBar.setValue(count) self.__infoLabel.setText(self.__formInfoLabel(name)) QApplication.processEvents() # Analyze the name found = False try: # True is for throwing exceptions locations = getOccurrences(path, absPosition, True) if len( locations ) == 1 and \ locations[ 0 ][ 1 ] == lineNumber: found = True index = getSearchItemIndex(candidates, path) if index < 0: widget = mainWindow.getWidgetForFileName(path) if widget is None: uuid = "" else: uuid = widget.getUUID() newItem = ItemToSearchIn(path, uuid) candidates.append(newItem) index = len(candidates) - 1 candidates[index].addMatch(name, lineNumber) except Exception, exc: # There is nothing interesting with exceptions here. # It seems to me that rope throws them in case if the same item # is declared multiple times in a file. I also suspect that # exceptions may come up in case of syntactic errors. # So I just suppress them. pass #logging.warning( "Error detected while analysing " + \ # self.__whatAsString() + " '" + name + \ # "'. Message: " + str( exc ) ) if found: self.__found += 1 self.__updateFoundLabel() QApplication.processEvents() if self.__found == 0: # The analysis could be interrupted if not self.__cancelRequest: logging.info("No unused candidates found") else: mainWindow.displayFindInFiles("", candidates) QApplication.restoreOverrideCursor() self.__infoLabel.setText('Done') self.__inProgress = False self.accept() return
class LineCounterDialog( QDialog, object ): """ line counter dialog implementation """ def __init__( self, fName = None, editor = None, parent = None ): QDialog.__init__( self, parent ) self.__cancelRequest = False self.__inProgress = False if fName is not None: self.__fName = fName.strip() else: self.__fName = None self.__editor = editor self.__createLayout() self.setWindowTitle( "Line counter" ) QTimer.singleShot( 0, self.__process ) return def __createLayout( self ): """ Creates the dialog layout """ self.resize( 450, 220 ) self.setSizeGripEnabled( True ) self.verticalLayout = QVBoxLayout( self ) # Info label self.infoLabel = FitPathLabel( self ) #sizePolicy = QSizePolicy( QSizePolicy.Expanding, # QSizePolicy.Preferred ) sizePolicy = QSizePolicy( QSizePolicy.Minimum, QSizePolicy.Preferred ) sizePolicy.setHorizontalStretch( 0 ) sizePolicy.setVerticalStretch( 0 ) sizePolicy.setHeightForWidth( self.infoLabel.sizePolicy().hasHeightForWidth() ) self.infoLabel.setSizePolicy( sizePolicy ) self.verticalLayout.addWidget( self.infoLabel ) # Progress bar self.progressBar = QProgressBar( self ) self.progressBar.setValue( 0 ) self.progressBar.setOrientation( Qt.Horizontal ) self.verticalLayout.addWidget( self.progressBar ) # Result window self.resultEdit = QTextEdit( self ) self.resultEdit.setTabChangesFocus( False ) self.resultEdit.setAcceptRichText( False ) self.resultEdit.setReadOnly( True ) self.resultEdit.setFontFamily( GlobalData().skin.baseMonoFontFace ) font = self.resultEdit.font() # Calculate the vertical size fontMetrics = QFontMetrics( font ) rect = fontMetrics.boundingRect( "W" ) # 6 lines, 5 line spacings, 2 frames self.resultEdit.setMinimumHeight( rect.height() * 7 + 4 * 5 + self.resultEdit.frameWidth() * 2 ) self.verticalLayout.addWidget( self.resultEdit ) # Buttons self.buttonBox = QDialogButtonBox( self ) self.buttonBox.setOrientation( Qt.Horizontal ) self.buttonBox.setStandardButtons( QDialogButtonBox.Close ) self.verticalLayout.addWidget( self.buttonBox ) self.buttonBox.rejected.connect( self.__onClose ) return def __scanDir( self, path, files ): " Recursively builds a list of python files " if path in self.__scannedDirs: return self.__scannedDirs.append( path ) for item in os.listdir( path ): if os.path.isdir( path + item ): nestedDir = os.path.realpath( path + item ) if not nestedDir.endswith( os.path.sep ): nestedDir += os.path.sep self.__scanDir( nestedDir, files ) else: candidate = os.path.realpath( path + item ) if candidate.endswith( ".py" ) or \ candidate.endswith( ".py3" ) or \ candidate.endswith( ".pyw" ): if not candidate in files: files.append( candidate ) return def __onClose( self ): " triggered when the close button is clicked " self.__cancelRequest = True if not self.__inProgress: self.close() return def __process( self ): " Accumulation process " self.__inProgress = True if self.__fName is not None: if os.path.exists( self.__fName ): if os.path.isdir( self.__fName ): self.__fName = os.path.realpath( self.__fName ) if not self.__fName.endswith( os.path.sep ): self.__fName += os.path.sep files = [] self.__scannedDirs = [] QApplication.setOverrideCursor( QCursor( Qt.WaitCursor ) ) self.__scanDir( self.__fName, files ) QApplication.restoreOverrideCursor() else: files = [ self.__fName ] else: files = [] elif self.__editor is not None: files = [ "buffer" ] else: files = GlobalData().project.filesList self.progressBar.setRange( 0, len( files ) ) accumulator = LinesCounter() current = LinesCounter() index = 1 for fileName in files: if self.__cancelRequest: self.__inProgress = False self.close() return self.infoLabel.setPath( 'Processing: ' + fileName ) processed = False if self.__editor is not None: current.getLinesInBuffer( self.__editor ) processed = True else: if (fileName.endswith( '.py' ) or \ fileName.endswith( '.py3' ) or \ fileName.endswith( '.pyw' )) and \ os.path.exists( fileName ): current.getLines( fileName ) processed = True if processed: accumulator.files += current.files accumulator.filesSize += current.filesSize accumulator.codeLines += current.codeLines accumulator.emptyLines += current.emptyLines accumulator.commentLines += current.commentLines accumulator.classes += current.classes self.progressBar.setValue( index ) index += 1 QApplication.processEvents() self.infoLabel.setPath( 'Done' ) self.__inProgress = False # Update text in the text window nFiles = splitThousands( str( accumulator.files ) ) filesSize = splitThousands( str( accumulator.filesSize ) ) classes = splitThousands( str( accumulator.classes ) ) codeLines = splitThousands( str( accumulator.codeLines ) ) emptyLines = splitThousands( str( accumulator.emptyLines ) ) commentLines = splitThousands( str( accumulator.commentLines ) ) totalLines = splitThousands( str( accumulator.codeLines + accumulator.emptyLines + accumulator.commentLines ) ) output = "Classes: " + classes + "\n" \ "Code lines: " + codeLines + "\n" \ "Empty lines: " + emptyLines + "\n" \ "Comment lines: " + commentLines + "\n" \ "Total lines: " + totalLines if self.__editor is None: output = "Number of python files: " + nFiles + "\n" \ "Total files size: " + filesSize + " bytes\n" + \ output else: output = "Number of characters: " + filesSize + "\n" + \ output self.resultEdit.setText( output ) return
class ImportsDiagramProgress( QDialog ): " Progress of the diagram generator " def __init__( self, what, options, path = "", buf = "", parent = None ): QDialog.__init__( self, parent ) self.__cancelRequest = False self.__inProgress = False self.__what = what self.__options = options self.__path = path # could be a dir or a file self.__buf = buf # content in case of a modified file # Working process data self.__participantFiles = [] # Collected list of files self.__projectImportDirs = [] self.__projectImportsCache = {} # utils.settings -> /full/path/to.py self.__dirsToImportsCache = {} # /dir/path -> { my.mod: path.py, ... } self.dataModel = ImportDiagramModel() self.scene = QGraphicsScene() # Avoid pylint complains self.progressBar = None self.infoLabel = None self.__createLayout() self.setWindowTitle( 'Imports/dependencies diagram generator' ) QTimer.singleShot( 0, self.__process ) return def keyPressEvent( self, event ): " Processes the ESC key specifically " if event.key() == Qt.Key_Escape: self.__onClose() else: QDialog.keyPressEvent( self, event ) return def __createLayout( self ): """ Creates the dialog layout """ self.resize( 450, 20 ) self.setSizeGripEnabled( True ) verticalLayout = QVBoxLayout( self ) # Info label self.infoLabel = QLabel( self ) verticalLayout.addWidget( self.infoLabel ) # Progress bar self.progressBar = QProgressBar( self ) self.progressBar.setValue( 0 ) self.progressBar.setOrientation( Qt.Horizontal ) verticalLayout.addWidget( self.progressBar ) # Buttons buttonBox = QDialogButtonBox( self ) buttonBox.setOrientation( Qt.Horizontal ) buttonBox.setStandardButtons( QDialogButtonBox.Close ) verticalLayout.addWidget( buttonBox ) buttonBox.rejected.connect( self.__onClose ) return def __onClose( self ): " triggered when the close button is clicked " self.__cancelRequest = True if not self.__inProgress: self.close() return def __buildParticipants( self ): " Builds a list of participating files and dirs " if self.__what in [ ImportsDiagramDialog.SingleBuffer, ImportsDiagramDialog.SingleFile ]: # File exists but could be modified self.__path = os.path.realpath( self.__path ) self.__participantFiles.append( self.__path ) return if self.__what == ImportsDiagramDialog.ProjectFiles: self.__scanProjectDirs() return # This is a recursive directory self.__path = os.path.realpath( self.__path ) self.__scanDirForPythonFiles( self.__path + os.path.sep ) return def __scanDirForPythonFiles( self, path ): " Scans the directory for the python files recursively " for item in os.listdir( path ): if item in [ ".svn", ".cvs" ]: continue if os.path.isdir( path + item ): self.__scanDirForPythonFiles( path + item + os.path.sep ) continue if item.endswith( ".py" ) or item.endswith( ".py3" ): fName = os.path.realpath( path + item ) # If it was a link, the target could be non-python if fName.endswith( ".py" ) or fName.endswith( ".py3" ): self.__participantFiles.append( fName ) return def __scanProjectDirs( self ): " Populates participant lists from the project files " for fName in GlobalData().project.filesList: if fName.endswith( ".py" ) or fName.endswith( ".py3" ): self.__participantFiles.append( fName ) return def isProjectImport( self, importString ): " Checks if it is a project import string and provides a path if so " if importString in self.__projectImportsCache: return self.__projectImportsCache[ importString ] subpath = importString.replace( '.', os.path.sep ) candidates = [ subpath + ".py", subpath + ".py3", subpath + os.path.sep + "__init__.py", subpath + os.path.sep + "__init__.py3" ] for path in self.__projectImportDirs: for item in candidates: fName = path + os.path.sep + item if os.path.isfile( fName ): self.__projectImportsCache[ importString ] = fName return fName return None def isLocalImport( self, dirName, importString ): " Checks if it is local dir import string and provides a path if so " dirFound = False if dirName in self.__dirsToImportsCache: dirFound = True importsDict = self.__dirsToImportsCache[ dirName ] if importString in importsDict: return importsDict[ importString ] subpath = importString.replace( '.', os.path.sep ) candidates = [ subpath + ".py", subpath + ".py3", subpath + os.path.sep + "__init__.py", subpath + os.path.sep + "__init__.py3" ] for item in candidates: fName = dirName + os.path.sep + item if os.path.isfile( fName ): # Found on the FS. Add to the dictionary if dirFound: importsDict[ importString ] = fName else: self.__dirsToImportsCache[ dirName ] = { importString: fName } return fName return None def isSystemWideImport( self, importString ): " Provides a path to the system wide import or None " # Systemwide modules may not have a path if it is a # built-in module, or to have a path to an .so library try: path = getSystemWideModules()[ importString ] if path is None: return True, None if path.endswith( ".py" ): return True, path if path.endswith( ".py3" ): return True, path return True, None except: return False, None def __addBoxInfo( self, box, info ): " Adds information to the given box if so configured " if info.docstring is not None: box.docstring = info.docstring.text if self.__options.includeClasses: for klass in info.classes: box.classes.append( klass ) if self.__options.includeFuncs: for func in info.functions: box.funcs.append( func ) if self.__options.includeGlobs: for glob in info.globals: box.globs.append( glob ) if self.__options.includeConnText: for imp in info.imports: box.imports.append( imp ) return def __addDocstringBox( self, info, fName, modBoxName ): " Adds a docstring box if needed " if self.__options.includeDocs: if info.docstring is not None: docBox = DgmDocstring() docBox.docstring = info.docstring docBox.refFile = fName # Add the box and its connection docBoxName = self.dataModel.addDocstringBox( docBox ) conn = DgmConnection() conn.kind = DgmConnection.ModuleDoc conn.source = modBoxName conn.target = docBoxName self.dataModel.addConnection( conn ) # Add rank for better layout rank = DgmRank() rank.firstObj = modBoxName rank.secondObj = docBoxName self.dataModel.addRank( rank ) return def __getSytemWideImportDocstring( self, path ): " Provides the system wide module docstring " if not path.endswith( '.py' ) and not path.endswith( '.py3' ): return "" try: info = GlobalData().briefModinfoCache.get( path ) if info.docstring is not None: return info.docstring.text return "" except: return "" @staticmethod def __getModuleTitle( fName ): " Extracts a module name out of the file name " baseTitle = os.path.basename( fName ).split( '.' )[ 0 ] if baseTitle != "__init__": return baseTitle # __init__ is not very descriptive. Add a top level dir. dirName = os.path.dirname( fName ) topDir = os.path.basename( dirName ) return topDir + "(" + baseTitle + ")" def __addSingleFileToDataModel( self, info, fName ): " Adds a single file to the data model " if fName.endswith( "__init__.py" ) or \ fName.endswith( "__init__.py3" ): if not info.classes and not info.functions and \ not info.globals and not info.imports: # Skip dummy init files return modBox = DgmModule() modBox.refFile = fName modBox.kind = DgmModule.ModuleOfInterest modBox.title = self.__getModuleTitle( fName ) self.__addBoxInfo( modBox, info ) modBoxName = self.dataModel.addModule( modBox ) self.__addDocstringBox( info, fName, modBoxName ) # Add what is imported isProjectFile = GlobalData().project.isProjectFile( fName ) for item in info.imports: impBox = DgmModule() importPath = None systemWideImportPath = None if isProjectFile: importPath = self.isProjectImport( item.name ) if importPath is None: importPath = self.isLocalImport( os.path.dirname( fName ), item.name ) if importPath is not None: impBox.kind = DgmModule.OtherProjectModule impBox.title = os.path.basename( importPath ).split( '.' )[ 0 ] impBox.refFile = importPath otherInfo = GlobalData().briefModinfoCache.get( importPath ) # It's a local or project import self.__addBoxInfo( impBox, otherInfo ) else: impBox.kind = DgmModule.UnknownModule impBox.title = item.name found, systemWideImportPath = self.isSystemWideImport( item.name ) if found: if systemWideImportPath is not None: impBox.kind = DgmModule.SystemWideModule impBox.refFile = systemWideImportPath impBox.docstring = \ self.__getSytemWideImportDocstring( \ systemWideImportPath ) else: impBox.kind = DgmModule.BuiltInModule impBoxName = self.dataModel.addModule( impBox ) impConn = DgmConnection() impConn.kind = DgmConnection.ModuleDependency impConn.source = modBoxName impConn.target = impBoxName if self.__options.includeConnText: for impWhat in item.what: if impWhat.name != "": impConn.labels.append( impWhat ) self.dataModel.addConnection( impConn ) return def __process( self ): " Accumulation process " # Intermediate working data self.__participantFiles = [] self.__projectImportDirs = [] self.__projectImportsCache = {} self.dataModel.clear() self.__inProgress = True try: self.infoLabel.setText( 'Building the list of files to analyze...' ) QApplication.processEvents() # Build the list of participating python files self.__buildParticipants() self.__projectImportDirs = \ GlobalData().project.getImportDirsAsAbsolutePaths() QApplication.processEvents() if self.__cancelRequest == True: QApplication.restoreOverrideCursor() self.close() return self.progressBar.setRange( 0, len( self.__participantFiles ) ) index = 1 # Now, parse the files and build the diagram data model if self.__what == ImportsDiagramDialog.SingleBuffer: info = getBriefModuleInfoFromMemory( str( self.__buf ) ) self.__addSingleFileToDataModel( info, self.__path ) else: infoSrc = GlobalData().briefModinfoCache for fName in self.__participantFiles: self.progressBar.setValue( index ) self.infoLabel.setText( 'Analyzing ' + fName + "..." ) QApplication.processEvents() if self.__cancelRequest == True: QApplication.restoreOverrideCursor() self.dataModel.clear() self.close() return info = infoSrc.get( fName ) self.__addSingleFileToDataModel( info, fName ) index += 1 # The import caches and other working data are not needed anymore self.__participantFiles = None self.__projectImportDirs = None self.__projectImportsCache = None # Generating the graphviz layout self.infoLabel.setText( 'Generating layout using graphviz...' ) QApplication.processEvents() graph = getGraphFromDescriptionData( self.dataModel.toGraphviz() ) graph.normalize( self.physicalDpiX(), self.physicalDpiY() ) QApplication.processEvents() if self.__cancelRequest == True: QApplication.restoreOverrideCursor() self.dataModel.clear() self.close() return # Generate graphics scene self.infoLabel.setText( 'Generating graphics scene...' ) QApplication.processEvents() self.__buildGraphicsScene( graph ) # Clear the data model self.dataModel = None except Exception, exc: QApplication.restoreOverrideCursor() logging.error( str( exc ) ) self.__inProgress = False self.__onClose() return QApplication.restoreOverrideCursor() self.infoLabel.setText( 'Done' ) QApplication.processEvents() self.__inProgress = False self.accept() return
class FindInFilesDialog(QDialog, object): """ find in files dialog implementation """ inProject = 0 inDirectory = 1 inOpenFiles = 2 def __init__(self, where, what="", dirPath="", filters=[], parent=None): QDialog.__init__(self, parent) mainWindow = GlobalData().mainWindow self.editorsManager = mainWindow.editorsManagerWidget.editorsManager self.__cancelRequest = False self.__inProgress = False self.searchRegexp = None self.searchResults = [] # Avoid pylint complains self.findCombo = None self.caseCheckBox = None self.wordCheckBox = None self.regexpCheckBox = None self.projectRButton = None self.openFilesRButton = None self.dirRButton = None self.dirEditCombo = None self.dirSelectButton = None self.filterCombo = None self.fileLabel = None self.progressBar = None self.findButton = None self.__createLayout() self.setWindowTitle("Find in files") # Restore the combo box values project = GlobalData().project if project.fileName != "": self.findFilesWhat = project.findFilesWhat self.findFilesDirs = project.findFilesDirs self.findFilesMasks = project.findFilesMasks else: settings = Settings() self.findFilesWhat = settings.findFilesWhat self.findFilesDirs = settings.findFilesDirs self.findFilesMasks = settings.findFilesMasks self.findCombo.addItems(self.findFilesWhat) self.findCombo.setEditText("") self.dirEditCombo.addItems(self.findFilesDirs) self.dirEditCombo.setEditText("") self.filterCombo.addItems(self.findFilesMasks) self.filterCombo.setEditText("") if where == self.inProject: self.setSearchInProject(what, filters) elif where == self.inDirectory: self.setSearchInDirectory(what, dirPath, filters) else: self.setSearchInOpenFiles(what, filters) return def __createLayout(self): """ Creates the dialog layout """ self.resize(600, 300) self.setSizeGripEnabled(True) verticalLayout = QVBoxLayout(self) gridLayout = QGridLayout() # Combo box for the text to search findLabel = QLabel(self) findLabel.setText("Find text:") self.findCombo = QComboBox(self) self.__tuneCombo(self.findCombo) self.findCombo.lineEdit().setToolTip( "Regular expression to search for") self.findCombo.editTextChanged.connect(self.__someTextChanged) gridLayout.addWidget(findLabel, 0, 0, 1, 1) gridLayout.addWidget(self.findCombo, 0, 1, 1, 1) verticalLayout.addLayout(gridLayout) # Check boxes horizontalCBLayout = QHBoxLayout() self.caseCheckBox = QCheckBox(self) self.caseCheckBox.setText("Match &case") horizontalCBLayout.addWidget(self.caseCheckBox) self.wordCheckBox = QCheckBox(self) self.wordCheckBox.setText("Match whole &word") horizontalCBLayout.addWidget(self.wordCheckBox) self.regexpCheckBox = QCheckBox(self) self.regexpCheckBox.setText("Regular &expression") horizontalCBLayout.addWidget(self.regexpCheckBox) verticalLayout.addLayout(horizontalCBLayout) # Files groupbox filesGroupbox = QGroupBox(self) filesGroupbox.setTitle("Find in") sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( filesGroupbox.sizePolicy().hasHeightForWidth()) filesGroupbox.setSizePolicy(sizePolicy) gridLayoutFG = QGridLayout(filesGroupbox) self.projectRButton = QRadioButton(filesGroupbox) self.projectRButton.setText("&Project") gridLayoutFG.addWidget(self.projectRButton, 0, 0) self.projectRButton.clicked.connect(self.__projectClicked) self.openFilesRButton = QRadioButton(filesGroupbox) self.openFilesRButton.setText("&Opened files only") gridLayoutFG.addWidget(self.openFilesRButton, 1, 0) self.openFilesRButton.clicked.connect(self.__openFilesOnlyClicked) self.dirRButton = QRadioButton(filesGroupbox) self.dirRButton.setText("&Directory tree") gridLayoutFG.addWidget(self.dirRButton, 2, 0) self.dirRButton.clicked.connect(self.__dirClicked) self.dirEditCombo = QComboBox(filesGroupbox) self.__tuneCombo(self.dirEditCombo) self.dirEditCombo.lineEdit().setToolTip("Directory to search in") gridLayoutFG.addWidget(self.dirEditCombo, 2, 1) self.dirEditCombo.editTextChanged.connect(self.__someTextChanged) self.dirSelectButton = QPushButton(filesGroupbox) self.dirSelectButton.setText("...") gridLayoutFG.addWidget(self.dirSelectButton, 2, 2) self.dirSelectButton.clicked.connect(self.__selectDirClicked) filterLabel = QLabel(filesGroupbox) filterLabel.setText("Files filter:") gridLayoutFG.addWidget(filterLabel, 3, 0) self.filterCombo = QComboBox(filesGroupbox) self.__tuneCombo(self.filterCombo) self.filterCombo.lineEdit().setToolTip("File names regular expression") gridLayoutFG.addWidget(self.filterCombo, 3, 1) self.filterCombo.editTextChanged.connect(self.__someTextChanged) verticalLayout.addWidget(filesGroupbox) # File label self.fileLabel = FitPathLabel(self) self.fileLabel.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed) verticalLayout.addWidget(self.fileLabel) # Progress bar self.progressBar = QProgressBar(self) self.progressBar.setValue(0) self.progressBar.setOrientation(Qt.Horizontal) verticalLayout.addWidget(self.progressBar) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Cancel) self.findButton = buttonBox.addButton("Find", QDialogButtonBox.AcceptRole) self.findButton.setDefault(True) self.findButton.clicked.connect(self.__process) verticalLayout.addWidget(buttonBox) buttonBox.rejected.connect(self.__onClose) return @staticmethod def __tuneCombo(comboBox): " Sets the common settings for a combo box " sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( \ comboBox.sizePolicy().hasHeightForWidth() ) comboBox.setSizePolicy(sizePolicy) comboBox.setEditable(True) comboBox.setInsertPolicy(QComboBox.InsertAtTop) comboBox.setAutoCompletion(False) comboBox.setDuplicatesEnabled(False) return def __onClose(self): " Triggered when the close button is clicked " self.__cancelRequest = True if not self.__inProgress: self.close() return 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 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 setSearchInDirectory(self, what="", dirPath="", filters=[]): " Sets search ready for the given directory " # Select radio buttons self.projectRButton.setEnabled(GlobalData().project.fileName != "") 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) self.dirEditCombo.setEditText(dirPath) self.setFilters(filters) self.findCombo.setEditText(what) self.findCombo.lineEdit().selectAll() self.findCombo.setFocus() # Check searchability self.__testSearchability() return def setFilters(self, filters): " Sets up the filters " # Set filters if provided if filters: self.filterCombo.setEditText(";".join(filters)) else: self.filterCombo.setEditText("") return 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 os.path.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: filterRe = re.compile(filtersText, re.IGNORECASE) 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 = filterRe.match(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 = filterRe.match(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, filterRe, 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") return @staticmethod def __matchInDir(path, filterRe, startTime): " Provides the 'match' and 'too long' statuses " matched = False tooLong = False for item in os.listdir(path): if time.time() - startTime > 0.1: tooLong = True return matched, tooLong if os.path.isdir(path + item): dname = path + item + sep matched, tooLong = FindInFilesDialog.__matchInDir( dname, filterRe, startTime) if matched or tooLong: return matched, tooLong continue if filterRe.match(path + item): matched = True return matched, tooLong return matched, tooLong def __projectClicked(self): " project radio button clicked " self.dirEditCombo.setEnabled(False) self.dirSelectButton.setEnabled(False) self.__testSearchability() return def __openFilesOnlyClicked(self): " open files only radio button clicked " self.dirEditCombo.setEnabled(False) self.dirSelectButton.setEnabled(False) self.__testSearchability() return def __dirClicked(self): " dir radio button clicked " self.dirEditCombo.setEnabled(True) self.dirSelectButton.setEnabled(True) self.dirEditCombo.setFocus() self.__testSearchability() return def __someTextChanged(self, text): " Text to search, filter or dir name has been changed " self.__testSearchability() return def __selectDirClicked(self): " The user selects a directory " dirName = QFileDialog.getExistingDirectory( self, "Select directory to search in", self.dirEditCombo.currentText(), QFileDialog.Options(QFileDialog.ShowDirsOnly)) if dirName: self.dirEditCombo.setEditText(os.path.normpath(dirName)) self.__testSearchability() 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 __openedFiles(self, filterRe): " Currently opened editor buffers " files = [] openedFiles = self.editorsManager.getTextEditors() for record in openedFiles: uuid = record[0] fname = record[1] if filterRe is None or filterRe.match(fname): files.append(ItemToSearchIn(fname, uuid)) QApplication.processEvents() if self.__cancelRequest: raise Exception("Cancel request") return files 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 __buildFilesList(self): " Builds the list of files to search in " filtersText = self.filterCombo.currentText().strip() if filtersText != "": filterRe = re.compile(filtersText, re.IGNORECASE) else: filterRe = None if self.projectRButton.isChecked(): return self.__projectFiles(filterRe) if self.openFilesRButton.isChecked(): return self.__openedFiles(filterRe) dirname = os.path.realpath(self.dirEditCombo.currentText().strip()) files = [] self.__dirFiles(dirname + sep, filterRe, files) return files def __process(self): " Search process " # Add entries to the combo box if required regexpText = self.findCombo.currentText() if regexpText in self.findFilesWhat: self.findFilesWhat.remove(regexpText) self.findFilesWhat.insert(0, regexpText) if len(self.findFilesWhat) > 32: self.findFilesWhat = self.findFilesWhat[:32] self.findCombo.clear() self.findCombo.addItems(self.findFilesWhat) filtersText = self.filterCombo.currentText().strip() if filtersText in self.findFilesMasks: self.findFilesMasks.remove(filtersText) self.findFilesMasks.insert(0, filtersText) if len(self.findFilesMasks) > 32: self.findFilesMasks = self.findFilesMasks[:32] self.filterCombo.clear() self.filterCombo.addItems(self.findFilesMasks) if self.dirRButton.isChecked(): dirText = self.dirEditCombo.currentText().strip() if dirText in self.findFilesDirs: self.findFilesDirs.remove(dirText) self.findFilesDirs.insert(0, dirText) if len(self.findFilesDirs) > 32: self.findFilesDirs = self.findFilesDirs[:32] self.dirEditCombo.clear() self.dirEditCombo.addItems(self.findFilesDirs) # Save the combo values for further usage if GlobalData().project.fileName != "": GlobalData().project.setFindInFilesHistory(self.findFilesWhat, self.findFilesDirs, self.findFilesMasks) else: Settings().findFilesWhat = self.findFilesWhat Settings().findFilesDirs = self.findFilesDirs Settings().findFilesMasks = self.findFilesMasks self.__inProgress = True numberOfMatches = 0 self.searchResults = [] self.searchRegexp = None # Form the regexp to search if not self.regexpCheckBox.isChecked(): regexpText = re.escape(regexpText) if self.wordCheckBox.isChecked(): regexpText = "\\b%s\\b" % regexpText flags = re.UNICODE | re.LOCALE if not self.caseCheckBox.isChecked(): flags |= re.IGNORECASE try: self.searchRegexp = re.compile(regexpText, flags) except: logging.error("Invalid search expression") self.close() return QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) self.fileLabel.setPath('Building list of files to search in...') QApplication.processEvents() try: files = self.__buildFilesList() except Exception, exc: if "Cancel request" in str(exc): QApplication.restoreOverrideCursor() self.close() return else: QApplication.restoreOverrideCursor() logging.error(str(exc)) self.close() return QApplication.restoreOverrideCursor() QApplication.processEvents() if len(files) == 0: self.fileLabel.setPath('No files to search in') return self.progressBar.setRange(0, len(files)) index = 1 for item in files: if self.__cancelRequest: self.__inProgress = False self.close() return self.fileLabel.setPath( 'Matches: ' + str( numberOfMatches ) + \ ' Processing: ' + item.fileName ) item.search(self.searchRegexp) found = len(item.matches) if found > 0: numberOfMatches += found self.searchResults.append(item) self.progressBar.setValue(index) index += 1 QApplication.processEvents() if numberOfMatches == 0: if len(files) == 1: self.fileLabel.setPath("No matches in 1 file.") else: self.fileLabel.setPath( "No matches in " + \ str( len( files ) ) + " files." ) self.__inProgress = False else: self.close() return
class ErrorLabel(QWidget): WARNING, ERROR = range(2) def __init__(self, parent): QWidget.__init__(self, parent) self.ticks = 5 self.elapsedTicks = 0 self.lastSeverity = None self.icon_label = QLabel() self.icon_label.setGeometry(0, 0, 48, 48) self.message_edit = QTextEdit() self.message_edit.setReadOnly(True) self.message_edit.setFrameStyle(QFrame.NoFrame) palette = self.message_edit.palette() palette.setBrush(QPalette.Base, QBrush()) self.message_edit.setPalette(palette) self.time_bar = QProgressBar() self.time_bar.setOrientation(Qt.Vertical) self.time_bar.setMaximum(self.ticks) self.time_bar.setTextVisible(False) self.pauseButton = QPushButton(QIcon(QPixmap(":/icons/images/pause.png")), "") self.pauseButton.setFixedSize(32, 32) self.connect(self.pauseButton, SIGNAL('clicked()'), self.stopTimer) self.stopButton = QPushButton(QIcon(QPixmap(":/icons/images/stop.png")), "") self.stopButton.setFixedSize(32, 32) self.connect(self.stopButton, SIGNAL('clicked()'), self.closeWidget) self.layout = QGridLayout(self) self.layout.addWidget(self.time_bar, 0, 0, 2, 1) self.layout.addWidget(self.icon_label, 0, 1, 2, 1) self.layout.addWidget(self.message_edit, 0, 2, 2, 1) self.layout.addWidget(self.pauseButton, 0, 3) self.layout.addWidget(self.stopButton, 1, 3) self.layout.setColumnStretch(2, 1) self.setAutoFillBackground(True) self.timer = QTimer() self.connect(self.timer, SIGNAL("timeout()"), self.decrementTime) def stopTimer(self): self.timer.stop() self.pauseButton.setEnabled(False) def closeWidget(self): self.timer.stop() QWidget.hide(self) @pyqtSlot() def decrementTime(self): if self.elapsedTicks == self.ticks: self.hide() self.timer.stop() else: self.elapsedTicks += 1 self.time_bar.setValue(self.ticks - self.elapsedTicks) def updatePosition(self): self.setGeometry(0, self.parent().height() - self.height(), self.width(), self.height()) def setSize(self, w, h): self.setGeometry(0, self.parent().height() - h, w, h) def setErrorMessage(self, msg): self.lastSeverity = self.ERROR self.icon_label.setPixmap(QApplication.style().standardIcon(QStyle.SP_MessageBoxCritical).pixmap(48, 48)) self._setMessage(msg) def setWarningMessage(self, msg): self.lastSeverity = self.WARNING self.icon_label.setPixmap(QApplication.style().standardIcon(QStyle.SP_MessageBoxWarning).pixmap(48, 48)) self._setMessage(msg) def _setMessage(self, msg): self.message_edit.setText(msg) self.updatePosition() self.elapsedTicks = 0 self.time_bar.setValue(self.ticks) self.timer.start(1000) self.pauseButton.setEnabled(True) self.show()
class ViewDataTools(QMainWindow): def __init__(self, parent=None): super(ViewDataTools, self).__init__(parent) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # DATATOOLS WINDOWS: # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ self.setWindowTitle(ui_strings.DATATOOLS_TITLE) self._width = 680 self._height = 560 self._left_margin = 10 self.resize(self._width, self._height) size_policy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) size_policy.setHorizontalStretch(0) size_policy.setVerticalStretch(0) size_policy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) self.setSizePolicy(size_policy) self.setMinimumSize(QtCore.QSize(self._width, self._height)) self.setMaximumSize(QtCore.QSize(self._width, self._height)) self.setWindowIcon(QIcon(resources.ICON_LOGO)) # central widget self.central_widget = QWidget(self) # DataTools description self.lbl_description = QLabel(self.central_widget) self.lbl_description.setGeometry(QtCore.QRect(0, 0, self._width, 30)) self.lbl_description.setAlignment(QtCore.Qt.AlignCenter) self.lbl_description.setText(ui_strings.DATATOOLS_DESCRIPTION) # group input files self.group_input_file = QGroupBox(self.central_widget) self.group_input_file.setGeometry(QtCore.QRect(self._left_margin, 30, 660, 80)) self.group_input_file.setTitle(ui_strings.DATATOOLS_GROUP_INPUT) # frame input files self.frame_inputs = QFrame(self.group_input_file) self.frame_inputs.setGeometry(QtCore.QRect(self._left_margin, 0, 270, 80)) self.frame_inputs.setFrameShape(QFrame.StyledPanel) self.frame_inputs.setFrameShadow(QFrame.Raised) # label input type self.lbl_input_type = QLabel(self.frame_inputs) self.lbl_input_type.setGeometry(QtCore.QRect(20, 20, 60, 15)) self.lbl_input_type.setText(ui_strings.DATATOOLS_INPUT_TYPE) # button xls self.btn_xls = QToolButton(self.frame_inputs) self.btn_xls.setGeometry(QtCore.QRect(20, 35, 35, 35)) icon_xls = QIcon() icon_xls.addPixmap(QPixmap(resources.ICON_XLS), QIcon.Normal, QIcon.Off) self.btn_xls.setIcon(icon_xls) self.btn_xls.setIconSize(QtCore.QSize(24, 24)) self.btn_xls.setCheckable(True) self.btn_xls.setAutoExclusive(True) self.btn_xls.setObjectName("xls_button") # button csv self.btn_csv = QToolButton(self.frame_inputs) self.btn_csv.setGeometry(QtCore.QRect(60, 35, 35, 35)) icon_csv = QIcon() icon_csv.addPixmap(QPixmap(resources.ICON_CSV), QIcon.Normal, QIcon.Off) self.btn_csv.setIcon(icon_csv) self.btn_csv.setIconSize(QtCore.QSize(24, 24)) self.btn_csv.setCheckable(True) self.btn_csv.setAutoExclusive(True) self.btn_csv.setObjectName("csv_button") # checkbox csv with headers self.chk_csv_headers = QCheckBox(ui_strings.DATATOOLS_WITH_HEADERS, self.frame_inputs) self.chk_csv_headers.setGeometry(QtCore.QRect(100, 45, 110, 15)) self.chk_csv_headers.setEnabled(False) # TextEdit + PushButton (FindFolder) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # lbl sheet name self.lbl_file_path = QLabel(self.group_input_file) self.lbl_file_path.setGeometry(QtCore.QRect(250, 20, 120, 15)) self.lbl_file_path.setText(ui_strings.DATATOOLS_SELECT_FILE) self.txt_file = QLineEdit(self.group_input_file) self.txt_file.setGeometry(QtCore.QRect(250, 35, 160, 20)) self.txt_file.setReadOnly(True) self.btn_path = QPushButton(self.group_input_file) self.btn_path.setGeometry(QtCore.QRect(410, 34, 50, 22)) self.btn_path.setText(ui_strings.DATATOOLS_SELECT_BUTTON) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # lbl sheet name self.lbl_sheet_name = QLabel(self.group_input_file) self.lbl_sheet_name.setGeometry(QtCore.QRect(500, 20, 120, 15)) self.lbl_sheet_name.setText(ui_strings.DATATOOLS_SHEET_NAME) # Combobox select sheet - initially does not contain values self.cbo_sheet = QComboBox(self.group_input_file) self.cbo_sheet.setGeometry(QtCore.QRect(500, 35, 130, 20)) # data grid to visualize error messages self.tbl_errors = QTableWidget(self.central_widget) self.tbl_errors.setGeometry(QtCore.QRect(self._left_margin, 420, 660, 100)) # data grid to visualize those records with errors. self.tbl_uploaded_data = QTableWidget(self.central_widget) self.tbl_uploaded_data.setGeometry(QtCore.QRect(self._left_margin, 120, 500, 220)) # group run options self.group_run_options = QGroupBox(self.central_widget) self.group_run_options.setGeometry(QtCore.QRect(520, 120, 150, 220)) self.group_run_options.setTitle(ui_strings.DATATOOLS_GROUP_RUN) # Errors summary: # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # group summary errors self.group_errors = QGroupBox(self.central_widget) self.group_errors.setGeometry(QtCore.QRect(self._left_margin, 350, 660, 60)) self.group_errors.setTitle(ui_strings.DATATOOLS_HEADER_ERRORS) # lbl records self.lbl_records = QLabel(self.group_errors) self.lbl_records.setGeometry(QtCore.QRect(165, 15, 80, 15)) self.lbl_records.setAlignment(QtCore.Qt.AlignCenter) self.lbl_records.setText(ui_strings.DATATOOLS_RECORDS) self.txt_records = QLineEdit(self.group_errors) self.txt_records.setGeometry(QtCore.QRect(165, 30, 80, 20)) self.txt_records.setAlignment(QtCore.Qt.AlignCenter) self.txt_records.setReadOnly(True) # lbl errors self.lbl_errors = QLabel(self.group_errors) self.lbl_errors.setGeometry(QtCore.QRect(275, 15, 80, 15)) self.lbl_errors.setAlignment(QtCore.Qt.AlignCenter) self.lbl_errors.setText(ui_strings.DATATOOLS_ERRORS) self.txt_errors = QLineEdit(self.group_errors) self.txt_errors.setGeometry(QtCore.QRect(275, 30, 80, 20)) self.txt_errors.setAlignment(QtCore.Qt.AlignCenter) self.txt_errors.setReadOnly(True) # lbl time self.lbl_time = QLabel(self.group_errors) self.lbl_time.setGeometry(QtCore.QRect(385, 15, 80, 15)) self.lbl_time.setAlignment(QtCore.Qt.AlignCenter) self.lbl_time.setText(ui_strings.DATATOOLS_TIME) self.txt_time = QLineEdit(self.group_errors) self.txt_time.setGeometry(QtCore.QRect(385, 30, 80, 20)) self.txt_time.setAlignment(QtCore.Qt.AlignCenter) self.txt_time.setReadOnly(True) # history button self.btn_history = QToolButton(self.group_errors) self.btn_history.setGeometry(QtCore.QRect(500, 25, 100, 25)) icon_history = QIcon() icon_history.addPixmap(QPixmap(resources.ICON_HISTORY), QIcon.Normal, QIcon.Off) self.btn_history.setIcon(icon_history) self.btn_history.setIconSize(QtCore.QSize(20, 20)) self.btn_history.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) self.btn_history.setText(ui_strings.DATATOOLS_HISTORY) self.btn_history.setCheckable(True) self.btn_history.setAutoExclusive(True) self.btn_history.setObjectName("history_button") # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # btn data uploader self.btn_data_uploader = QPushButton(ui_strings.DATATOOLS_DATA_UPLOADER, self.group_run_options) self.btn_data_uploader.setGeometry(QtCore.QRect(10, 120, 90, 25)) self.btn_data_uploader.setCheckable(True) self.btn_data_uploader.setAutoExclusive(True) self.btn_data_uploader.setFlat(False) # btn data testing self.btn_data_testing = QPushButton(ui_strings.DATATOOLS_DATA_TESTING, self.group_run_options) self.btn_data_testing.setEnabled(False) self.btn_data_testing.setGeometry(QtCore.QRect(10, 150, 90, 25)) self.btn_data_testing.setCheckable(True) self.btn_data_testing.setAutoExclusive(True) # btn data to database self.btn_data_db = QPushButton(ui_strings.DATATOOLS_DATA_DB, self.group_run_options) self.btn_data_db.setEnabled(False) self.btn_data_db.setGeometry(QtCore.QRect(10, 179, 91, 23)) self.btn_data_db.setCheckable(True) self.btn_data_db.setAutoExclusive(True) # frame run options self.frame_run = QFrame(self.group_run_options) self.frame_run.setGeometry(QtCore.QRect(10, 30, 130, 80)) self.frame_run.setFrameShape(QFrame.StyledPanel) self.frame_run.setFrameShadow(QFrame.Raised) # option process until first error self.rbtn_process_error = QRadioButton(ui_strings.DATATOOLS_PROCESS_ERROR, self.frame_run) self.rbtn_process_error.setGeometry(QtCore.QRect(0, 0, 150, 20)) # option process all data self.rbtn_process_all = QRadioButton(ui_strings.DATATOOLS_PROCESS_ALL, self.frame_run) self.rbtn_process_all.setGeometry(QtCore.QRect(0, 20, 150, 30)) # checkbox to filter by records with errors. #self.chk_filter_errors = QCheckBox(ui_strings.DATATOOLS_FILTER_ERRORS, self.frame_run) #self.chk_filter_errors.setGeometry(QtCore.QRect(0, 50, 100, 15)) #self.chk_filter_errors.setEnabled(False) # icons -> pass - error: Initially are empty labels # if not started -> ICON_MINI_WAIT # if error -> ICON_DELETE # if pass -> ICON_CHECK # state icon data uploader self.lbl_state_du = QLabel(self.group_run_options) self.lbl_state_du.setGeometry(QtCore.QRect(110, 120, 20, 20)) self.lbl_state_du.setPixmap(QPixmap(resources.ICON_MINI_WAIT)) self.lbl_state_du.setScaledContents(True) # state icon data to database self.lbl_state_dt = QLabel(self.group_run_options) self.lbl_state_dt.setGeometry(QtCore.QRect(110, 150, 20, 20)) self.lbl_state_dt.setPixmap(QPixmap(resources.ICON_MINI_WAIT)) self.lbl_state_dt.setScaledContents(True) # state icon data testing self.lbl_state_db = QLabel(self.group_run_options) self.lbl_state_db.setGeometry(QtCore.QRect(110, 180, 20, 20)) self.lbl_state_db.setPixmap(QPixmap(resources.ICON_MINI_WAIT)) self.lbl_state_db.setScaledContents(True) # progress bar self.progress_bar = QProgressBar(self.central_widget) self.progress_bar.setGeometry(QtCore.QRect(self._left_margin, 530, 660, 15)) self.progress_bar.setMaximum(100) self.progress_bar.setProperty("value", 0) self.progress_bar.setTextVisible(True) self.progress_bar.setOrientation(QtCore.Qt.Horizontal) self.progress_bar.setInvertedAppearance(False) self.progress_bar.setTextDirection(QProgressBar.TopToBottom) self.setCentralWidget(self.central_widget)
class NotUsedAnalysisProgress( QDialog ): " Progress of the not used analysis " Functions = 0 Classes = 1 Globals = 2 def __init__( self, what, sourceModel, parent = None ): QDialog.__init__( self, parent ) if what not in [ self.Functions, self.Classes, self.Globals ]: raise Exception( "Unsupported unused analysis type: " + \ str( what ) ) self.__cancelRequest = False self.__inProgress = False self.__what = what # what is in source model self.__srcModel = sourceModel # source model of globals or # functions or classes # Avoid pylint complains self.__progressBar = None self.__infoLabel = None self.__foundLabel = None self.__found = 0 # Number of found self.__createLayout() self.setWindowTitle( self.__formTitle() ) QTimer.singleShot( 0, self.__process ) return def keyPressEvent( self, event ): " Processes the ESC key specifically " if event.key() == Qt.Key_Escape: self.__onClose() else: QDialog.keyPressEvent( self, event ) return def __formTitle( self ): " Forms the progress dialog title " title = "Unused " if self.__what == self.Functions: title += 'function' elif self.__what == self.Classes: title += 'class' else: title += 'globlal variable' return title + " analysis" def __formInfoLabel( self, name ): " Forms the info label " if self.__what == self.Functions: return 'Function: ' + name if self.__what == self.Classes: return 'Class: ' + name return 'Globlal variable: ' + name def __whatAsString( self ): " Provides 'what' as string " if self.__what == self.Functions: return 'function' if self.__what == self.Classes: return 'class' return 'global variable' def __updateFoundLabel( self ): " Updates the found label " text = "Found: " + str( self.__found ) + " candidate" if self.__found != 1: text += "s" self.__foundLabel.setText( text ) return def __createLayout( self ): """ Creates the dialog layout """ self.resize( 450, 20 ) self.setSizeGripEnabled( True ) verticalLayout = QVBoxLayout( self ) # Note label noteLabel = QLabel( "<b>Note</b>: the analysis is " \ "suggestive and not precise. " \ "Use the results with caution.\n", self ) verticalLayout.addWidget( noteLabel ) # Info label self.__infoLabel = QLabel( self ) verticalLayout.addWidget( self.__infoLabel ) # Progress bar self.__progressBar = QProgressBar( self ) self.__progressBar.setValue( 0 ) self.__progressBar.setOrientation( Qt.Horizontal ) verticalLayout.addWidget( self.__progressBar ) # Found label self.__foundLabel = QLabel( self ) verticalLayout.addWidget( self.__foundLabel ) # Buttons buttonBox = QDialogButtonBox( self ) buttonBox.setOrientation( Qt.Horizontal ) buttonBox.setStandardButtons( QDialogButtonBox.Close ) verticalLayout.addWidget( buttonBox ) buttonBox.rejected.connect( self.__onClose ) return def __onClose( self ): " triggered when the close button is clicked " self.__cancelRequest = True if not self.__inProgress: self.close() return def __process( self ): " Analysis process " self.__inProgress = True mainWindow = GlobalData().mainWindow editorsManager = mainWindow.editorsManagerWidget.editorsManager modified = editorsManager.getModifiedList( True ) # True - only project files if modified: modNames = [ modItem[ 0 ] for modItem in modified ] label = "File" if len( modified ) >= 2: label += "s" label += ": " logging.warning( "The analisys is performed for the content of saved files. " \ "The unsaved modifications will not be taken into account. " \ + label + ", ".join( modNames ) ) self.__updateFoundLabel() self.__progressBar.setRange( 0, len( self.__srcModel.rootItem.childItems ) ) QApplication.processEvents() QApplication.setOverrideCursor( QCursor( Qt.WaitCursor ) ) count = 0 candidates = [] for treeItem in self.__srcModel.rootItem.childItems: if self.__cancelRequest: break name = str( treeItem.data( 0 ) ).split( '(' )[ 0 ] path = os.path.realpath( treeItem.getPath() ) lineNumber = int( treeItem.data( 2 ) ) absPosition = treeItem.sourceObj.absPosition count += 1 self.__progressBar.setValue( count ) self.__infoLabel.setText( self.__formInfoLabel( name ) ) QApplication.processEvents() # Analyze the name found = False try: # True is for throwing exceptions locations = getOccurrences( path, absPosition, True ) if len( locations ) == 1 and \ locations[ 0 ][ 1 ] == lineNumber: found = True index = getSearchItemIndex( candidates, path ) if index < 0: widget = mainWindow.getWidgetForFileName( path ) if widget is None: uuid = "" else: uuid = widget.getUUID() newItem = ItemToSearchIn( path, uuid ) candidates.append( newItem ) index = len( candidates ) - 1 candidates[ index ].addMatch( name, lineNumber ) except Exception, exc: # There is nothing interesting with exceptions here. # It seems to me that rope throws them in case if the same item # is declared multiple times in a file. I also suspect that # exceptions may come up in case of syntactic errors. # So I just suppress them. pass #logging.warning( "Error detected while analysing " + \ # self.__whatAsString() + " '" + name + \ # "'. Message: " + str( exc ) ) if found: self.__found += 1 self.__updateFoundLabel() QApplication.processEvents() if self.__found == 0: # The analysis could be interrupted if not self.__cancelRequest: logging.info( "No unused candidates found" ) else: mainWindow.displayFindInFiles( "", candidates ) QApplication.restoreOverrideCursor() self.__infoLabel.setText( 'Done' ) self.__inProgress = False self.accept() return
class ViewDataTools(QMainWindow): def __init__(self, parent=None): super(ViewDataTools, self).__init__(parent) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # DATATOOLS WINDOWS: # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ self.setWindowTitle(ui_strings.DATATOOLS_TITLE) self._width = 680 self._height = 560 self._left_margin = 10 self.resize(self._width, self._height) size_policy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) size_policy.setHorizontalStretch(0) size_policy.setVerticalStretch(0) size_policy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) self.setSizePolicy(size_policy) self.setMinimumSize(QtCore.QSize(self._width, self._height)) self.setMaximumSize(QtCore.QSize(self._width, self._height)) self.setWindowIcon(QIcon(resources.ICON_LOGO)) # central widget self.central_widget = QWidget(self) # DataTools description self.lbl_description = QLabel(self.central_widget) self.lbl_description.setGeometry(QtCore.QRect(0, 0, self._width, 30)) self.lbl_description.setAlignment(QtCore.Qt.AlignCenter) self.lbl_description.setText(ui_strings.DATATOOLS_DESCRIPTION) # group input files self.group_input_file = QGroupBox(self.central_widget) self.group_input_file.setGeometry( QtCore.QRect(self._left_margin, 30, 660, 80)) self.group_input_file.setTitle(ui_strings.DATATOOLS_GROUP_INPUT) # frame input files self.frame_inputs = QFrame(self.group_input_file) self.frame_inputs.setGeometry( QtCore.QRect(self._left_margin, 0, 270, 80)) self.frame_inputs.setFrameShape(QFrame.StyledPanel) self.frame_inputs.setFrameShadow(QFrame.Raised) # label input type self.lbl_input_type = QLabel(self.frame_inputs) self.lbl_input_type.setGeometry(QtCore.QRect(20, 20, 60, 15)) self.lbl_input_type.setText(ui_strings.DATATOOLS_INPUT_TYPE) # button xls self.btn_xls = QToolButton(self.frame_inputs) self.btn_xls.setGeometry(QtCore.QRect(20, 35, 35, 35)) icon_xls = QIcon() icon_xls.addPixmap(QPixmap(resources.ICON_XLS), QIcon.Normal, QIcon.Off) self.btn_xls.setIcon(icon_xls) self.btn_xls.setIconSize(QtCore.QSize(24, 24)) self.btn_xls.setCheckable(True) self.btn_xls.setAutoExclusive(True) self.btn_xls.setObjectName("xls_button") # button csv self.btn_csv = QToolButton(self.frame_inputs) self.btn_csv.setGeometry(QtCore.QRect(60, 35, 35, 35)) icon_csv = QIcon() icon_csv.addPixmap(QPixmap(resources.ICON_CSV), QIcon.Normal, QIcon.Off) self.btn_csv.setIcon(icon_csv) self.btn_csv.setIconSize(QtCore.QSize(24, 24)) self.btn_csv.setCheckable(True) self.btn_csv.setAutoExclusive(True) self.btn_csv.setObjectName("csv_button") # checkbox csv with headers self.chk_csv_headers = QCheckBox(ui_strings.DATATOOLS_WITH_HEADERS, self.frame_inputs) self.chk_csv_headers.setGeometry(QtCore.QRect(100, 45, 110, 15)) self.chk_csv_headers.setEnabled(False) # TextEdit + PushButton (FindFolder) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # lbl sheet name self.lbl_file_path = QLabel(self.group_input_file) self.lbl_file_path.setGeometry(QtCore.QRect(250, 20, 120, 15)) self.lbl_file_path.setText(ui_strings.DATATOOLS_SELECT_FILE) self.txt_file = QLineEdit(self.group_input_file) self.txt_file.setGeometry(QtCore.QRect(250, 35, 160, 20)) self.txt_file.setReadOnly(True) self.btn_path = QPushButton(self.group_input_file) self.btn_path.setGeometry(QtCore.QRect(410, 34, 50, 22)) self.btn_path.setText(ui_strings.DATATOOLS_SELECT_BUTTON) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # lbl sheet name self.lbl_sheet_name = QLabel(self.group_input_file) self.lbl_sheet_name.setGeometry(QtCore.QRect(500, 20, 120, 15)) self.lbl_sheet_name.setText(ui_strings.DATATOOLS_SHEET_NAME) # Combobox select sheet - initially does not contain values self.cbo_sheet = QComboBox(self.group_input_file) self.cbo_sheet.setGeometry(QtCore.QRect(500, 35, 130, 20)) # data grid to visualize error messages self.tbl_errors = QTableWidget(self.central_widget) self.tbl_errors.setGeometry( QtCore.QRect(self._left_margin, 420, 660, 100)) # data grid to visualize those records with errors. self.tbl_uploaded_data = QTableWidget(self.central_widget) self.tbl_uploaded_data.setGeometry( QtCore.QRect(self._left_margin, 120, 500, 220)) # group run options self.group_run_options = QGroupBox(self.central_widget) self.group_run_options.setGeometry(QtCore.QRect(520, 120, 150, 220)) self.group_run_options.setTitle(ui_strings.DATATOOLS_GROUP_RUN) # Errors summary: # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # group summary errors self.group_errors = QGroupBox(self.central_widget) self.group_errors.setGeometry( QtCore.QRect(self._left_margin, 350, 660, 60)) self.group_errors.setTitle(ui_strings.DATATOOLS_HEADER_ERRORS) # lbl records self.lbl_records = QLabel(self.group_errors) self.lbl_records.setGeometry(QtCore.QRect(165, 15, 80, 15)) self.lbl_records.setAlignment(QtCore.Qt.AlignCenter) self.lbl_records.setText(ui_strings.DATATOOLS_RECORDS) self.txt_records = QLineEdit(self.group_errors) self.txt_records.setGeometry(QtCore.QRect(165, 30, 80, 20)) self.txt_records.setAlignment(QtCore.Qt.AlignCenter) self.txt_records.setReadOnly(True) # lbl errors self.lbl_errors = QLabel(self.group_errors) self.lbl_errors.setGeometry(QtCore.QRect(275, 15, 80, 15)) self.lbl_errors.setAlignment(QtCore.Qt.AlignCenter) self.lbl_errors.setText(ui_strings.DATATOOLS_ERRORS) self.txt_errors = QLineEdit(self.group_errors) self.txt_errors.setGeometry(QtCore.QRect(275, 30, 80, 20)) self.txt_errors.setAlignment(QtCore.Qt.AlignCenter) self.txt_errors.setReadOnly(True) # lbl time self.lbl_time = QLabel(self.group_errors) self.lbl_time.setGeometry(QtCore.QRect(385, 15, 80, 15)) self.lbl_time.setAlignment(QtCore.Qt.AlignCenter) self.lbl_time.setText(ui_strings.DATATOOLS_TIME) self.txt_time = QLineEdit(self.group_errors) self.txt_time.setGeometry(QtCore.QRect(385, 30, 80, 20)) self.txt_time.setAlignment(QtCore.Qt.AlignCenter) self.txt_time.setReadOnly(True) # history button self.btn_history = QToolButton(self.group_errors) self.btn_history.setGeometry(QtCore.QRect(500, 25, 100, 25)) icon_history = QIcon() icon_history.addPixmap(QPixmap(resources.ICON_HISTORY), QIcon.Normal, QIcon.Off) self.btn_history.setIcon(icon_history) self.btn_history.setIconSize(QtCore.QSize(20, 20)) self.btn_history.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) self.btn_history.setText(ui_strings.DATATOOLS_HISTORY) self.btn_history.setCheckable(True) self.btn_history.setAutoExclusive(True) self.btn_history.setObjectName("history_button") # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # btn data uploader self.btn_data_uploader = QPushButton( ui_strings.DATATOOLS_DATA_UPLOADER, self.group_run_options) self.btn_data_uploader.setGeometry(QtCore.QRect(10, 120, 90, 25)) self.btn_data_uploader.setCheckable(True) self.btn_data_uploader.setAutoExclusive(True) self.btn_data_uploader.setFlat(False) # btn data testing self.btn_data_testing = QPushButton(ui_strings.DATATOOLS_DATA_TESTING, self.group_run_options) self.btn_data_testing.setEnabled(False) self.btn_data_testing.setGeometry(QtCore.QRect(10, 150, 90, 25)) self.btn_data_testing.setCheckable(True) self.btn_data_testing.setAutoExclusive(True) # btn data to database self.btn_data_db = QPushButton(ui_strings.DATATOOLS_DATA_DB, self.group_run_options) self.btn_data_db.setEnabled(False) self.btn_data_db.setGeometry(QtCore.QRect(10, 179, 91, 23)) self.btn_data_db.setCheckable(True) self.btn_data_db.setAutoExclusive(True) # frame run options self.frame_run = QFrame(self.group_run_options) self.frame_run.setGeometry(QtCore.QRect(10, 30, 130, 80)) self.frame_run.setFrameShape(QFrame.StyledPanel) self.frame_run.setFrameShadow(QFrame.Raised) # option process until first error self.rbtn_process_error = QRadioButton( ui_strings.DATATOOLS_PROCESS_ERROR, self.frame_run) self.rbtn_process_error.setGeometry(QtCore.QRect(0, 0, 150, 20)) # option process all data self.rbtn_process_all = QRadioButton(ui_strings.DATATOOLS_PROCESS_ALL, self.frame_run) self.rbtn_process_all.setGeometry(QtCore.QRect(0, 20, 150, 30)) # checkbox to filter by records with errors. #self.chk_filter_errors = QCheckBox(ui_strings.DATATOOLS_FILTER_ERRORS, self.frame_run) #self.chk_filter_errors.setGeometry(QtCore.QRect(0, 50, 100, 15)) #self.chk_filter_errors.setEnabled(False) # icons -> pass - error: Initially are empty labels # if not started -> ICON_MINI_WAIT # if error -> ICON_DELETE # if pass -> ICON_CHECK # state icon data uploader self.lbl_state_du = QLabel(self.group_run_options) self.lbl_state_du.setGeometry(QtCore.QRect(110, 120, 20, 20)) self.lbl_state_du.setPixmap(QPixmap(resources.ICON_MINI_WAIT)) self.lbl_state_du.setScaledContents(True) # state icon data to database self.lbl_state_dt = QLabel(self.group_run_options) self.lbl_state_dt.setGeometry(QtCore.QRect(110, 150, 20, 20)) self.lbl_state_dt.setPixmap(QPixmap(resources.ICON_MINI_WAIT)) self.lbl_state_dt.setScaledContents(True) # state icon data testing self.lbl_state_db = QLabel(self.group_run_options) self.lbl_state_db.setGeometry(QtCore.QRect(110, 180, 20, 20)) self.lbl_state_db.setPixmap(QPixmap(resources.ICON_MINI_WAIT)) self.lbl_state_db.setScaledContents(True) # progress bar self.progress_bar = QProgressBar(self.central_widget) self.progress_bar.setGeometry( QtCore.QRect(self._left_margin, 530, 660, 15)) self.progress_bar.setMaximum(100) self.progress_bar.setProperty("value", 0) self.progress_bar.setTextVisible(True) self.progress_bar.setOrientation(QtCore.Qt.Horizontal) self.progress_bar.setInvertedAppearance(False) self.progress_bar.setTextDirection(QProgressBar.TopToBottom) self.setCentralWidget(self.central_widget)
class MessageDialog(QWidget): def __init__(self, mailList, jobID = '', sec = 0, parent = None): QWidget.__init__(self, parent) self.prnt = parent self.jobID = jobID self.sec = sec self.frozen = False self.tr = self.prnt.prnt.tr self.setWindowTitle(self.tr._translate('M@il Checker : MailView Dialog')) self.setStyleSheet("QWidget {background: rgba(235,240,255,128);}") self.mailList = QLabel(mailList) self.layout = QVBoxLayout() self.buttonLayout = QHBoxLayout() self.ok = QPushButton(QIcon.fromTheme("dialog-ok"), "", self) self.cancel = QPushButton(QIcon.fromTheme("dialog-cancel"), "", self) self.freezMSG = QPushButton(QIcon.fromTheme("layer-visible-on"), '', self) self.freezMSG.setToolTip(self.tr._translate('Freez message')) self.ok.setMaximumHeight(15) self.freezMSG.setMaximumHeight(15) self.cancel.setMaximumHeight(15) self.ok.clicked.connect(self.accepted) self.freezMSG.clicked.connect(self.freez) self.cancel.clicked.connect(self.rejected) self.buttonLayout.addWidget(self.ok) self.buttonLayout.addWidget(self.freezMSG) self.buttonLayout.addWidget(self.cancel) self.layout.addWidget(self.mailList) if sec : self.lifetime = QProgressBar() self.lifetime.setOrientation(Qt.Horizontal) self.lifetime.setMinimum(0) self.lifetime.setMaximum(sec) self.lifetime.setValue(sec) self.lifetime.setMaximumHeight(7) self.layout.addWidget(self.lifetime) self.lifetimeID = self.startTimer(1000) self.layout.addItem(self.buttonLayout) self.setLayout(self.layout) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.setMinimumWidth(100) def accepted(self): self.prnt.prnt.viewJob.emit(self.jobID) if self.prnt.prnt.SoundEnabled : self.prnt.prnt.sound.Accepted.play() self.close() def rejected(self, common = False): if self.prnt.prnt.SoundEnabled and not common : self.prnt.prnt.sound.Cleared.play() self.close() def freez(self, common = False): if self.sec : self.killTimer(self.lifetimeID) self.setStyleSheet("QWidget {background: rgba(100,175,255,25);}") self.frozen = True self.freezMSG.setEnabled(False) if self.prnt.prnt.SoundEnabled and not common : self.prnt.prnt.sound.Frozen.play() def timerEvent(self, ev): if ev.type()==QEvent.Timer : value = self.lifetime.value() #print ev.timerId(), value if value > self.lifetime.minimum() : self.lifetime.setValue(value-1) else : self.close() def isFrozen(self): return self.frozen def closeEvent(self, ev): if ev.type()==QEvent.Close : if self.sec : self.killTimer(self.lifetimeID) self.prnt.checkEmpty.emit(self.jobID) self.prnt.prnt.clearJob.emit(self.jobID) ev.accept() else : ev.ignore()
class FindInFilesDialog( QDialog, object ): """ find in files dialog implementation """ inProject = 0 inDirectory = 1 inOpenFiles = 2 def __init__( self, where, what = "", dirPath = "", filters = [], parent = None ): QDialog.__init__( self, parent ) mainWindow = GlobalData().mainWindow self.editorsManager = mainWindow.editorsManagerWidget.editorsManager self.__cancelRequest = False self.__inProgress = False self.searchRegexp = None self.searchResults = [] # Avoid pylint complains self.findCombo = None self.caseCheckBox = None self.wordCheckBox = None self.regexpCheckBox = None self.projectRButton = None self.openFilesRButton = None self.dirRButton = None self.dirEditCombo = None self.dirSelectButton = None self.filterCombo = None self.fileLabel = None self.progressBar = None self.findButton = None self.__createLayout() self.setWindowTitle( "Find in files" ) # Restore the combo box values project = GlobalData().project if project.fileName != "": self.findFilesWhat = project.findFilesWhat self.findFilesDirs = project.findFilesDirs self.findFilesMasks = project.findFilesMasks else: settings = Settings() self.findFilesWhat = settings.findFilesWhat self.findFilesDirs = settings.findFilesDirs self.findFilesMasks = settings.findFilesMasks self.findCombo.addItems( self.findFilesWhat ) self.findCombo.setEditText( "" ) self.dirEditCombo.addItems( self.findFilesDirs ) self.dirEditCombo.setEditText( "" ) self.filterCombo.addItems( self.findFilesMasks ) self.filterCombo.setEditText( "" ) if where == self.inProject: self.setSearchInProject( what, filters ) elif where == self.inDirectory: self.setSearchInDirectory( what, dirPath, filters ) else: self.setSearchInOpenFiles( what, filters ) return def __createLayout( self ): """ Creates the dialog layout """ self.resize( 600, 300 ) self.setSizeGripEnabled( True ) verticalLayout = QVBoxLayout( self ) gridLayout = QGridLayout() # Combo box for the text to search findLabel = QLabel( self ) findLabel.setText( "Find text:" ) self.findCombo = QComboBox( self ) self.__tuneCombo( self.findCombo ) self.findCombo.lineEdit().setToolTip( "Regular expression to search for" ) self.findCombo.editTextChanged.connect( self.__someTextChanged ) gridLayout.addWidget( findLabel, 0, 0, 1, 1 ) gridLayout.addWidget( self.findCombo, 0, 1, 1, 1 ) verticalLayout.addLayout( gridLayout ) # Check boxes horizontalCBLayout = QHBoxLayout() self.caseCheckBox = QCheckBox( self ) self.caseCheckBox.setText( "Match &case" ) horizontalCBLayout.addWidget( self.caseCheckBox ) self.wordCheckBox = QCheckBox( self ) self.wordCheckBox.setText( "Match whole &word" ) horizontalCBLayout.addWidget( self.wordCheckBox ) self.regexpCheckBox = QCheckBox( self ) self.regexpCheckBox.setText( "Regular &expression" ) horizontalCBLayout.addWidget( self.regexpCheckBox ) verticalLayout.addLayout( horizontalCBLayout ) # Files groupbox filesGroupbox = QGroupBox( self ) filesGroupbox.setTitle( "Find in" ) sizePolicy = QSizePolicy( QSizePolicy.Expanding, QSizePolicy.Preferred ) sizePolicy.setHorizontalStretch( 0 ) sizePolicy.setVerticalStretch( 0 ) sizePolicy.setHeightForWidth( filesGroupbox.sizePolicy().hasHeightForWidth() ) filesGroupbox.setSizePolicy( sizePolicy ) gridLayoutFG = QGridLayout( filesGroupbox ) self.projectRButton = QRadioButton( filesGroupbox ) self.projectRButton.setText( "&Project" ) gridLayoutFG.addWidget( self.projectRButton, 0, 0 ) self.projectRButton.clicked.connect( self.__projectClicked ) self.openFilesRButton = QRadioButton( filesGroupbox ) self.openFilesRButton.setText( "&Opened files only" ) gridLayoutFG.addWidget( self.openFilesRButton, 1, 0 ) self.openFilesRButton.clicked.connect( self.__openFilesOnlyClicked ) self.dirRButton = QRadioButton( filesGroupbox ) self.dirRButton.setText( "&Directory tree" ) gridLayoutFG.addWidget( self.dirRButton, 2, 0 ) self.dirRButton.clicked.connect( self.__dirClicked ) self.dirEditCombo = QComboBox( filesGroupbox ) self.__tuneCombo( self.dirEditCombo ) self.dirEditCombo.lineEdit().setToolTip( "Directory to search in" ) gridLayoutFG.addWidget( self.dirEditCombo, 2, 1 ) self.dirEditCombo.editTextChanged.connect( self.__someTextChanged ) self.dirSelectButton = QPushButton( filesGroupbox ) self.dirSelectButton.setText( "..." ) gridLayoutFG.addWidget( self.dirSelectButton, 2, 2 ) self.dirSelectButton.clicked.connect( self.__selectDirClicked ) filterLabel = QLabel( filesGroupbox ) filterLabel.setText( "Files filter:" ) gridLayoutFG.addWidget( filterLabel, 3, 0 ) self.filterCombo = QComboBox( filesGroupbox ) self.__tuneCombo( self.filterCombo ) self.filterCombo.lineEdit().setToolTip( "File names regular expression" ) gridLayoutFG.addWidget( self.filterCombo, 3, 1 ) self.filterCombo.editTextChanged.connect( self.__someTextChanged ) verticalLayout.addWidget( filesGroupbox ) # File label self.fileLabel = FitPathLabel( self ) self.fileLabel.setSizePolicy( QSizePolicy.Ignored, QSizePolicy.Fixed ) verticalLayout.addWidget( self.fileLabel ) # Progress bar self.progressBar = QProgressBar( self ) self.progressBar.setValue( 0 ) self.progressBar.setOrientation( Qt.Horizontal ) verticalLayout.addWidget( self.progressBar ) # Buttons at the bottom buttonBox = QDialogButtonBox( self ) buttonBox.setOrientation( Qt.Horizontal ) buttonBox.setStandardButtons( QDialogButtonBox.Cancel ) self.findButton = buttonBox.addButton( "Find", QDialogButtonBox.AcceptRole ) self.findButton.setDefault( True ) self.findButton.clicked.connect( self.__process ) verticalLayout.addWidget( buttonBox ) buttonBox.rejected.connect( self.__onClose ) return @staticmethod def __tuneCombo( comboBox ): " Sets the common settings for a combo box " sizePolicy = QSizePolicy( QSizePolicy.Expanding, QSizePolicy.Fixed ) sizePolicy.setHorizontalStretch( 0 ) sizePolicy.setVerticalStretch( 0 ) sizePolicy.setHeightForWidth( \ comboBox.sizePolicy().hasHeightForWidth() ) comboBox.setSizePolicy( sizePolicy ) comboBox.setEditable( True ) comboBox.setInsertPolicy( QComboBox.InsertAtTop ) comboBox.setAutoCompletion( False ) comboBox.setDuplicatesEnabled( False ) return def __onClose( self ): " Triggered when the close button is clicked " self.__cancelRequest = True if not self.__inProgress: self.close() return 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 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 setSearchInDirectory( self, what = "", dirPath = "", filters = [] ): " Sets search ready for the given directory " # Select radio buttons self.projectRButton.setEnabled( GlobalData().project.fileName != "" ) 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 ) self.dirEditCombo.setEditText( dirPath ) self.setFilters( filters ) self.findCombo.setEditText( what ) self.findCombo.lineEdit().selectAll() self.findCombo.setFocus() # Check searchability self.__testSearchability() return def setFilters( self, filters ): " Sets up the filters " # Set filters if provided if filters: self.filterCombo.setEditText( ";".join( filters ) ) else: self.filterCombo.setEditText( "" ) return 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 os.path.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: filterRe = re.compile( filtersText, re.IGNORECASE ) 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 = filterRe.match( 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 = filterRe.match( 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, filterRe, 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" ) return @staticmethod def __matchInDir( path, filterRe, startTime ): " Provides the 'match' and 'too long' statuses " matched = False tooLong = False for item in os.listdir( path ): if time.time() - startTime > 0.1: tooLong = True return matched, tooLong if os.path.isdir( path + item ): dname = path + item + sep matched, tooLong = FindInFilesDialog.__matchInDir( dname, filterRe, startTime ) if matched or tooLong: return matched, tooLong continue if filterRe.match( path + item ): matched = True return matched, tooLong return matched, tooLong def __projectClicked( self ): " project radio button clicked " self.dirEditCombo.setEnabled( False ) self.dirSelectButton.setEnabled( False ) self.__testSearchability() return def __openFilesOnlyClicked( self ): " open files only radio button clicked " self.dirEditCombo.setEnabled( False ) self.dirSelectButton.setEnabled( False ) self.__testSearchability() return def __dirClicked( self ): " dir radio button clicked " self.dirEditCombo.setEnabled( True ) self.dirSelectButton.setEnabled( True ) self.dirEditCombo.setFocus() self.__testSearchability() return def __someTextChanged( self, text ): " Text to search, filter or dir name has been changed " self.__testSearchability() return def __selectDirClicked( self ): " The user selects a directory " dirName = QFileDialog.getExistingDirectory( self, "Select directory to search in", self.dirEditCombo.currentText(), QFileDialog.Options( QFileDialog.ShowDirsOnly ) ) if dirName: self.dirEditCombo.setEditText( os.path.normpath( dirName ) ) self.__testSearchability() 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 __openedFiles( self, filterRe ): " Currently opened editor buffers " files = [] openedFiles = self.editorsManager.getTextEditors() for record in openedFiles: uuid = record[ 0 ] fname = record[ 1 ] if filterRe is None or filterRe.match( fname ): files.append( ItemToSearchIn( fname, uuid ) ) QApplication.processEvents() if self.__cancelRequest: raise Exception( "Cancel request" ) return files 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 __buildFilesList( self ): " Builds the list of files to search in " filtersText = self.filterCombo.currentText().strip() if filtersText != "": filterRe = re.compile( filtersText, re.IGNORECASE ) else: filterRe = None if self.projectRButton.isChecked(): return self.__projectFiles( filterRe ) if self.openFilesRButton.isChecked(): return self.__openedFiles( filterRe ) dirname = os.path.realpath( self.dirEditCombo.currentText().strip() ) files = [] self.__dirFiles( dirname + sep, filterRe, files ) return files def __process( self ): " Search process " # Add entries to the combo box if required regexpText = self.findCombo.currentText() if regexpText in self.findFilesWhat: self.findFilesWhat.remove( regexpText ) self.findFilesWhat.insert( 0, regexpText ) if len( self.findFilesWhat ) > 32: self.findFilesWhat = self.findFilesWhat[ : 32 ] self.findCombo.clear() self.findCombo.addItems( self.findFilesWhat ) filtersText = self.filterCombo.currentText().strip() if filtersText in self.findFilesMasks: self.findFilesMasks.remove( filtersText ) self.findFilesMasks.insert( 0, filtersText ) if len( self.findFilesMasks ) > 32: self.findFilesMasks = self.findFilesMasks[ : 32 ] self.filterCombo.clear() self.filterCombo.addItems( self.findFilesMasks ) if self.dirRButton.isChecked(): dirText = self.dirEditCombo.currentText().strip() if dirText in self.findFilesDirs: self.findFilesDirs.remove( dirText ) self.findFilesDirs.insert( 0, dirText ) if len( self.findFilesDirs ) > 32: self.findFilesDirs = self.findFilesDirs[ : 32 ] self.dirEditCombo.clear() self.dirEditCombo.addItems( self.findFilesDirs ) # Save the combo values for further usage if GlobalData().project.fileName != "": GlobalData().project.setFindInFilesHistory( self.findFilesWhat, self.findFilesDirs, self.findFilesMasks ) else: Settings().findFilesWhat = self.findFilesWhat Settings().findFilesDirs = self.findFilesDirs Settings().findFilesMasks = self.findFilesMasks self.__inProgress = True numberOfMatches = 0 self.searchResults = [] self.searchRegexp = None # Form the regexp to search if not self.regexpCheckBox.isChecked(): regexpText = re.escape( regexpText ) if self.wordCheckBox.isChecked(): regexpText = "\\b%s\\b" % regexpText flags = re.UNICODE | re.LOCALE if not self.caseCheckBox.isChecked(): flags |= re.IGNORECASE try: self.searchRegexp = re.compile( regexpText, flags ) except: logging.error( "Invalid search expression" ) self.close() return QApplication.setOverrideCursor( QCursor( Qt.WaitCursor ) ) self.fileLabel.setPath( 'Building list of files to search in...' ) QApplication.processEvents() try: files = self.__buildFilesList() except Exception, exc: if "Cancel request" in str( exc ): QApplication.restoreOverrideCursor() self.close() return else: QApplication.restoreOverrideCursor() logging.error( str( exc ) ) self.close() return QApplication.restoreOverrideCursor() QApplication.processEvents() if len( files ) == 0: self.fileLabel.setPath( 'No files to search in' ) return self.progressBar.setRange( 0, len( files ) ) index = 1 for item in files: if self.__cancelRequest: self.__inProgress = False self.close() return self.fileLabel.setPath( 'Matches: ' + str( numberOfMatches ) + \ ' Processing: ' + item.fileName ) item.search( self.searchRegexp ) found = len( item.matches ) if found > 0: numberOfMatches += found self.searchResults.append( item ) self.progressBar.setValue( index ) index += 1 QApplication.processEvents() if numberOfMatches == 0: if len( files ) == 1: self.fileLabel.setPath( "No matches in 1 file." ) else: self.fileLabel.setPath( "No matches in " + \ str( len( files ) ) + " files." ) self.__inProgress = False else: self.close() return