class PDFWidget(QWidget): scaleFactors = [0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 2.0] scalePercents = ["25%", "50%", "75%", "100%", "125%", "150%", "200%"] def __init__(self): QWidget.__init__(self) self.hboxLayout = QVBoxLayout() self.setLayout(self.hboxLayout) self.setMenu() self.setPDFLabelScrollArea() self.connect(self.pageLineEdit, SIGNAL("valueChanged(int)"), self.pdfLabel.setPage) self.connect(self.pdfLabel, SIGNAL("pageChanged"), self.pageLineEdit.setPageNumberValue) self.connect(self.pdfLabel, SIGNAL("pageChanged"), self.scrollToTop) self.connect(self.scaleComboBox, SIGNAL("currentIndexChanged(int)"), self.scaleDocument) self.connect(self.searchLineEdit, SIGNAL("returnPressed()"), self.searchDocument) self.connect(self.findButton, SIGNAL("clicked()"), self.searchDocument) self.connect(self.clearButton, SIGNAL("clicked()"), self.pdfLabel.setPage) self.connect(self.searchLineEdit, SIGNAL("textChanged(QString)"), self.checkSearchText) self.connect(self, SIGNAL("setDocument"), self.setDocument) def setMenu(self): self.menuLayout = QHBoxLayout() self.hboxLayout.addLayout(self.menuLayout) self.pageLineEdit = PageLineEdit() self.pageLineEdit.setEnabled(False) self.menuLayout.addLayout(self.pageLineEdit) spacer = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.menuLayout.addItem(spacer) self.searchLayout = QHBoxLayout() self.menuLayout.addLayout(self.searchLayout) self.searchLabel = QLabel(self.tr("Search:")) self.searchLabel.setTextFormat(Qt.AutoText) self.searchLayout.addWidget(self.searchLabel) self.searchLineEdit = QLineEdit() self.searchLineEdit.setEnabled(False) self.searchLabel.setBuddy(self.searchLineEdit) self.searchLayout.addWidget(self.searchLineEdit) self.searchComboBox = QComboBox() self.searchComboBox.setEnabled(False) self.searchComboBox.insertItems(0, ["Forwards", "Backwards"]) self.searchLayout.addWidget(self.searchComboBox) self.findButton = QPushButton("Find") self.findButton.setEnabled(False) self.searchLayout.addWidget(self.findButton) self.clearButton = QPushButton("Clear") self.clearButton.setEnabled(False) self.searchLayout.addWidget(self.clearButton) spacer = QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.menuLayout.addItem(spacer) self.scaleLabel = QLabel("Scale:") self.menuLayout.addWidget(self.scaleLabel) self.scaleComboBox = QComboBox() self.scaleComboBox.setEnabled(False) self.scaleComboBox.insertItems(0, self.scalePercents) self.scaleComboBox.setCurrentIndex(3) self.scaleLabel.setBuddy(self.scaleComboBox) self.menuLayout.addWidget(self.scaleComboBox) def setPDFLabelScrollArea(self): self.pdfLabel = PDFLabel(self) self.scrollArea = QScrollArea() self.scrollArea.setWidgetResizable(True) self.scrollArea.setAlignment(Qt.AlignCenter) self.scrollArea.setWidget(self.pdfLabel) self.hboxLayout.addWidget(self.scrollArea) def scrollToTop(self, value): self.scrollArea.verticalScrollBar().setValue(0) def setDocument(self, data): if self.pdfLabel.setDocument(data): self.searchLineEdit.setEnabled(True) self.searchComboBox.setEnabled(True) self.findButton.setEnabled(True) self.clearButton.setEnabled(True) self.scaleComboBox.setEnabled(True) self.pageLineEdit.setEnabled(True) self.pageLineEdit.setPageNumberValue(1) self.pageLineEdit.setMaximumPageNumber( self.pdfLabel.document().numPages()) def setError(self, errorMessage): self.pdfLabel.setError(errorMessage) def setMessage(self, message): self.pdfLabel.setText(message) def checkSearchText(self, text): if text == "": self.pdfLabel.setPage() def scaleDocument(self, index): self.pdfLabel.setScale(self.scaleFactors[index]) def searchDocument(self): if self.searchComboBox.currentIndex() == 0: location = self.pdfLabel.searchForwards(self.searchLineEdit.text()) else: location = self.pdfLabel.searchBackwards( self.searchLineEdit.text()) target = self.pdfLabel.matrix().mapRect(location).center().toPoint() self.scrollArea.ensureVisible(target.x(), target.y())
class PylintViewer( QWidget ): " Pylint tab widget " # Limits to colorize the final score BadLimit = 8.5 GoodLimit = 9.5 # Options of providing a report SingleFile = 0 DirectoryFiles = 1 ProjectFiles = 2 SingleBuffer = 3 updatePylintTooltip = pyqtSignal( str ) def __init__( self, parent = None ): QWidget.__init__( self, parent ) self.__reportUUID = "" self.__reportFileName = "" self.__reportOption = -1 self.__reportShown = False self.__report = None self.__widgets = [] # Prepare members for reuse if GlobalData().pylintAvailable: self.__noneLabel = QLabel( "\nNo results available" ) else: self.__noneLabel = QLabel( "\nPylint is not available" ) self.__noneLabel.setAutoFillBackground( True ) noneLabelPalette = self.__noneLabel.palette() noneLabelPalette.setColor( QPalette.Background, GlobalData().skin.nolexerPaper ) self.__noneLabel.setPalette( noneLabelPalette ) self.__noneLabel.setFrameShape( QFrame.StyledPanel ) self.__noneLabel.setAlignment( Qt.AlignHCenter ) self.__headerFont = self.__noneLabel.font() self.__headerFont.setPointSize( self.__headerFont.pointSize() + 4 ) self.__noneLabel.setFont( self.__headerFont ) self.__createLayout( parent ) self.__updateButtonsStatus() self.resizeEvent() return def __createLayout( self, parent ): " Creates the toolbar and layout " # Buttons self.printButton = QAction( PixmapCache().getIcon( 'printer.png' ), 'Print', self ) #printButton.setShortcut( 'Ctrl+' ) self.printButton.triggered.connect( self.__onPrint ) self.printButton.setVisible( False ) self.printPreviewButton = QAction( PixmapCache().getIcon( 'printpreview.png' ), 'Print preview', self ) #printPreviewButton.setShortcut( 'Ctrl+' ) self.printPreviewButton.triggered.connect( self.__onPrintPreview ) self.printPreviewButton.setVisible( False ) spacer = QWidget() spacer.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Expanding ) self.clearButton = QAction( PixmapCache().getIcon( 'trash.png' ), 'Clear', self ) self.clearButton.triggered.connect( self.__clear ) # The toolbar self.toolbar = QToolBar( self ) self.toolbar.setOrientation( Qt.Vertical ) self.toolbar.setMovable( False ) self.toolbar.setAllowedAreas( Qt.RightToolBarArea ) self.toolbar.setIconSize( QSize( 16, 16 ) ) self.toolbar.setFixedWidth( 28 ) self.toolbar.setContentsMargins( 0, 0, 0, 0 ) self.toolbar.addAction( self.printPreviewButton ) self.toolbar.addAction( self.printButton ) self.toolbar.addWidget( spacer ) self.toolbar.addAction( self.clearButton ) self.__vLayout = QVBoxLayout() self.__vLayout.setContentsMargins( 5, 5, 5, 5 ) self.__vLayout.setSpacing( 0 ) self.__vLayout.setSizeConstraint( QLayout.SetFixedSize ) self.__bodyFrame = QFrame( self ) # self.__bodyFrame.setFrameShape( QFrame.StyledPanel ) self.__bodyFrame.setFrameShape( QFrame.NoFrame ) # self.__bodyFrame.setSizePolicy( QSizePolicy.Maximum, # QSizePolicy.Expanding ) self.__bodyFrame.setLayout( self.__vLayout ) self.bodyWidget = QScrollArea( self ) self.bodyWidget.setFocusPolicy( Qt.NoFocus ) self.bodyWidget.setWidget( self.__bodyFrame ) self.bodyWidget.hide() self.__hLayout = QHBoxLayout() self.__hLayout.setContentsMargins( 0, 0, 0, 0 ) self.__hLayout.setSpacing( 0 ) self.__hLayout.addWidget( self.toolbar ) self.__hLayout.addWidget( self.__noneLabel ) self.__hLayout.addWidget( self.bodyWidget ) self.setLayout( self.__hLayout ) return def __updateButtonsStatus( self ): " Updates the buttons status " self.printButton.setEnabled( self.__reportShown ) self.printPreviewButton.setEnabled( self.__reportShown ) self.clearButton.setEnabled( self.__reportShown ) return def __onPrint( self ): " Triggered when the print button is pressed " pass def __onPrintPreview( self ): " triggered when the print preview button is pressed " pass def setFocus( self ): " Overridden setFocus " self.__vLayout.setFocus() return def __clear( self ): " Clears the content of the vertical layout " if not self.__reportShown: return self.__removeAll() self.bodyWidget.hide() self.__noneLabel.show() self.__report = None self.__reportShown = False self.__updateButtonsStatus() self.resizeEvent() self.__updateTooltip() return def __removeAll( self ): " Removes all the items from the report " for item in self.__widgets: item.hide() self.__vLayout.removeWidget( item ) del item self.__widgets = [] return def __createScoreLabel( self, score, previousScore, showFileName, fileName ): " Creates the score label " txt = "Score: " + str( score ) if previousScore != "": txt += " / Previous score: " + str( previousScore ) if not showFileName: txt += " for " + os.path.basename( fileName ) scoreLabel = QLabel( txt ) scoreLabel.setFrameShape( QFrame.StyledPanel ) scoreLabel.setFont( self.__headerFont ) scoreLabel.setAutoFillBackground( True ) palette = scoreLabel.palette() if score < self.BadLimit: palette.setColor( QPalette.Background, QColor( 255, 127, 127 ) ) palette.setColor( QPalette.Foreground, QColor( 0, 0, 0 ) ) elif score > self.GoodLimit: palette.setColor( QPalette.Background, QColor( 220, 255, 220 ) ) palette.setColor( QPalette.Foreground, QColor( 0, 0, 0 ) ) else: palette.setColor( QPalette.Background, QColor( 255, 255, 127 ) ) palette.setColor( QPalette.Foreground, QColor( 0, 0, 0 ) ) scoreLabel.setPalette( palette ) return scoreLabel @staticmethod def __setTableHeight( table ): " Auxiliary function to set the table height " # Height - it is ugly and approximate however I am tired of # calculating the proper height. Why is this so hard, huh? lastRowHeight = table.itemDelegate().lastHeight height = lastRowHeight * ( table.topLevelItemCount() + 1 ) + 10 table.setFixedHeight( height ) return @staticmethod def __shouldShowFileName( messages ): " Decides if the file name column should be supressed " if len( messages ) == 0: return False firstName = messages[ 0 ].fileName for index in range( 1, len( messages ) ): if firstName != messages[ index ].fileName: return True return False def __addErrorsTable( self, messages, showFileName ): " Creates the messages table " errTable = QTreeWidget( self.bodyWidget ) errTable.setAlternatingRowColors( True ) errTable.setRootIsDecorated( False ) errTable.setItemsExpandable( False ) errTable.setSortingEnabled( True ) errTable.setItemDelegate( NoOutlineHeightDelegate( 4 ) ) errTable.setUniformRowHeights( True ) errTable.itemActivated.connect( self.__errorActivated ) headerLabels = [ "File name", "Line", "Message ID", "Object", "Message" ] errTable.setHeaderLabels( headerLabels ) for item in messages: if item.position is None: lineNumber = str( item.lineNumber ) else: lineNumber = str( item.lineNumber ) + ":" + str( item.position ) values = [ item.fileName, lineNumber, item.messageID, item.objectName, item.message ] errTable.addTopLevelItem( ErrorTableItem( values, 1 ) ) # Hide the file name column if required if not showFileName: errTable.setColumnHidden( 0, True ) # Resizing errTable.header().resizeSections( QHeaderView.ResizeToContents ) errTable.header().setStretchLastSection( True ) # Sort indicator if showFileName: sortIndex = 0 # By file names else: sortIndex = 1 # By line number because this is from the same file errTable.header().setSortIndicator( sortIndex, Qt.AscendingOrder ) errTable.sortItems( sortIndex, errTable.header().sortIndicatorOrder() ) # Height self.__setTableHeight( errTable ) self.__vLayout.addWidget( errTable ) self.__widgets.append( errTable ) return def __addSimilarity( self, similarity, titleText ): " Adds a similarity " # Label title = QLabel( titleText ) title.setFont( self.__headerFont ) self.__vLayout.addWidget( title ) self.__widgets.append( title ) # List of files simTable = QTreeWidget( self.bodyWidget ) simTable.setAlternatingRowColors( True ) simTable.setRootIsDecorated( False ) simTable.setItemsExpandable( False ) simTable.setSortingEnabled( False ) simTable.setItemDelegate( NoOutlineHeightDelegate( 4 ) ) simTable.setUniformRowHeights( True ) simTable.itemActivated.connect( self.__similarityActivated ) simTable.setHeaderLabels( [ "File name", "Line" ] ) for item in similarity.files: values = [ item[ 0 ], str( item[ 1 ] ) ] simTable.addTopLevelItem( QTreeWidgetItem( values ) ) # Resizing simTable.header().resizeSections( QHeaderView.ResizeToContents ) simTable.header().setStretchLastSection( True ) # Height self.__setTableHeight( simTable ) self.__vLayout.addWidget( simTable ) self.__widgets.append( simTable ) # The fragment itself if len( similarity.fragment ) > 10: # Take first 9 lines text = "\n".join( similarity.fragment[ : 9 ] ) + "\n ..." toolTip = "\n".join( similarity.fragment ) else: text = "\n".join( similarity.fragment ) toolTip = "" fragmentLabel = QLabel( "<pre>" + self.__htmlEncode( text ) + "</pre>" ) if toolTip != "": fragmentLabel.setToolTip( "<pre>" + self.__htmlEncode( toolTip ) + "</pre>" ) palette = fragmentLabel.palette() palette.setColor( QPalette.Background, QColor( 250, 250, 175 ) ) palette.setColor( QPalette.Foreground, QColor( 0, 0, 0 ) ) fragmentLabel.setPalette( palette ) fragmentLabel.setFrameShape( QFrame.StyledPanel ) fragmentLabel.setAutoFillBackground( True ) labelFont = fragmentLabel.font() labelFont.setFamily( GlobalData().skin.baseMonoFontFace ) fragmentLabel.setFont( labelFont ) self.__vLayout.addWidget( fragmentLabel ) self.__widgets.append( fragmentLabel ) return @staticmethod def __htmlEncode( string ): " Encodes HTML " return string.replace( "&", "&" ) \ .replace( ">", ">" ) \ .replace( "<", "<" ) def __addSectionSpacer( self ): " Adds a fixed height spacer to the VBox layout " spacer = QWidget() spacer.setFixedHeight( 10 ) self.__vLayout.addWidget( spacer ) self.__widgets.append( spacer ) return def __addGenericTable( self, table ): " Adds a generic table to the report " theTable = QTreeWidget( self.bodyWidget ) theTable.setAlternatingRowColors( True ) theTable.setRootIsDecorated( False ) theTable.setItemsExpandable( False ) theTable.setSortingEnabled( False ) theTable.setItemDelegate( NoOutlineHeightDelegate( 4 ) ) theTable.setUniformRowHeights( True ) headerLabels = [] for index in range( 0, len( table.header ) ): headerLabels.append( table.header[ index ] ) theTable.setHeaderLabels( headerLabels ) for item in table.body: row = [] for index in range( 0, len( table.header ) ): row.append( item[ index ] ) theTable.addTopLevelItem( QTreeWidgetItem( row ) ) theTable.setFocusPolicy( Qt.NoFocus ) # Resizing theTable.header().resizeSections( QHeaderView.ResizeToContents ) theTable.header().setStretchLastSection( True ) # Height self.__setTableHeight( theTable ) self.__vLayout.addWidget( theTable ) self.__widgets.append( theTable ) return def __addGenericTableTitle( self, table ): " Adds a generic table title " tableTitle = QLabel( table.title ) tableTitle.setFont( self.__headerFont ) self.__vLayout.addWidget( tableTitle ) self.__widgets.append( tableTitle ) return def __updateTooltip( self ): " Generates a signal with appropriate string message " if not self.__reportShown: tooltip = "No results available" elif self.__reportOption == self.DirectoryFiles: tooltip = "Report generated for directory: " + \ self.__reportFileName elif self.__reportOption == self.ProjectFiles: tooltip = "Report generated for the whole project" elif self.__reportOption == self.SingleFile: tooltip = "Report generated for file: " + self.__reportFileName elif self.__reportOption == self.SingleBuffer: tooltip = "Report generated for unsaved file: " + \ self.__reportFileName else: tooltip = "" self.updatePylintTooltip.emit( tooltip ) return def showReport( self, lint, reportOption, fileName, uuid ): " Shows the pylint results " self.__removeAll() self.__noneLabel.hide() self.__report = lint self.__reportUUID = uuid self.__reportFileName = fileName self.__reportOption = reportOption showFileName = self.__shouldShowFileName( lint.errorMessages ) scoreLabel = self.__createScoreLabel( lint.score, lint.previousScore, showFileName, fileName ) self.__vLayout.addWidget( scoreLabel ) self.__widgets.append( scoreLabel ) if len( lint.errorMessages ) > 0: self.__addSectionSpacer() self.__addErrorsTable( lint.errorMessages, showFileName ) index = 0 for similarity in lint.similarities: self.__addSectionSpacer() self.__addSimilarity( similarity, "Similarity #" + str( index ) ) index += 1 for table in lint.tables: self.__addSectionSpacer() self.__addGenericTableTitle( table ) self.__addGenericTable( table ) self.bodyWidget.show() self.bodyWidget.ensureVisible( 0, 0, 0, 0 ) self.__reportShown = True self.__updateButtonsStatus() self.__updateTooltip() # It helps, but why do I have flickering? QApplication.processEvents() self.__resizeBodyFrame() return def __errorActivated( self, item, column ): " Handles the double click (or Enter) on the item " linePos = str( item.text( 1 ) ) if ":" in linePos: parts = linePos.split( ":" ) lineNumber = int( parts[ 0 ] ) pos = int( parts[ 1 ] ) else: lineNumber = int( linePos ) pos = 0 if self.__reportOption in [ self.SingleFile, self.DirectoryFiles, self.ProjectFiles ]: fileName = str( item.text( 0 ) ) else: # SingleBuffer if self.__reportFileName != "": if os.path.isabs( self.__reportFileName ): fileName = self.__reportFileName else: # Could be unsaved buffer, so try to search by the mainWindow = GlobalData().mainWindow widget = mainWindow.getWidgetByUUID( self.__reportUUID ) if widget is None: logging.error( "The unsaved buffer has been closed" ) return # The widget was found, so jump to the required editor = widget.getEditor() editor.gotoLine( lineNumber, pos ) editor.setFocus() return GlobalData().mainWindow.openFile( fileName, lineNumber, pos ) return def __resizeBodyFrame( self ): " Resizing the frame to occupy all available width " size = self.bodyWidget.maximumViewportSize() self.__bodyFrame.setMinimumWidth( size.width() - 16 ) self.__bodyFrame.setMinimumHeight( size.height() ) return def showEvent( self, showEv = None ): " Called when the widget is shown " self.__resizeBodyFrame() return def resizeEvent( self, resizeEv = None ): " Called when the main window gets resized " self.__resizeBodyFrame() return def onFileUpdated( self, fileName, uuid ): " Called when a buffer is saved or saved as " if not self.__reportShown: return if self.__reportUUID != uuid: return # Currently shown report is for the saved buffer # File name is expected being absolute self.__reportFileName = fileName self.updatePylintTooltip.emit( "Report generated for buffer saved as " + fileName ) return def __similarityActivated( self, item, column ): " Triggered when a similarity is activated " fileName = str( item.text( 0 ) ) lineNumber = int( item.text( 1 ) ) GlobalData().mainWindow.openFile( fileName, lineNumber ) return
class PylintViewer(QWidget): " Pylint tab widget " # Limits to colorize the final score BadLimit = 8.5 GoodLimit = 9.5 # Options of providing a report SingleFile = 0 DirectoryFiles = 1 ProjectFiles = 2 SingleBuffer = 3 updatePylintTooltip = pyqtSignal(str) def __init__(self, parent=None): QWidget.__init__(self, parent) self.__reportUUID = "" self.__reportFileName = "" self.__reportOption = -1 self.__reportShown = False self.__report = None self.__widgets = [] # Prepare members for reuse if GlobalData().pylintAvailable: self.__noneLabel = QLabel("\nNo results available") else: self.__noneLabel = QLabel("\nPylint is not available") self.__noneLabel.setAutoFillBackground(True) noneLabelPalette = self.__noneLabel.palette() noneLabelPalette.setColor(QPalette.Background, GlobalData().skin.nolexerPaper) self.__noneLabel.setPalette(noneLabelPalette) self.__noneLabel.setFrameShape(QFrame.StyledPanel) self.__noneLabel.setAlignment(Qt.AlignHCenter) self.__headerFont = self.__noneLabel.font() self.__headerFont.setPointSize(self.__headerFont.pointSize() + 4) self.__noneLabel.setFont(self.__headerFont) self.__createLayout(parent) self.__updateButtonsStatus() self.resizeEvent() return def __createLayout(self, parent): " Creates the toolbar and layout " # Buttons self.printButton = QAction(PixmapCache().getIcon('printer.png'), 'Print', self) #printButton.setShortcut( 'Ctrl+' ) self.printButton.triggered.connect(self.__onPrint) self.printButton.setVisible(False) self.printPreviewButton = QAction( PixmapCache().getIcon('printpreview.png'), 'Print preview', self) #printPreviewButton.setShortcut( 'Ctrl+' ) self.printPreviewButton.triggered.connect(self.__onPrintPreview) self.printPreviewButton.setVisible(False) spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.clearButton = QAction(PixmapCache().getIcon('trash.png'), 'Clear', self) self.clearButton.triggered.connect(self.__clear) # The toolbar self.toolbar = QToolBar(self) self.toolbar.setOrientation(Qt.Vertical) self.toolbar.setMovable(False) self.toolbar.setAllowedAreas(Qt.RightToolBarArea) self.toolbar.setIconSize(QSize(16, 16)) self.toolbar.setFixedWidth(28) self.toolbar.setContentsMargins(0, 0, 0, 0) self.toolbar.addAction(self.printPreviewButton) self.toolbar.addAction(self.printButton) self.toolbar.addWidget(spacer) self.toolbar.addAction(self.clearButton) self.__vLayout = QVBoxLayout() self.__vLayout.setContentsMargins(5, 5, 5, 5) self.__vLayout.setSpacing(0) self.__vLayout.setSizeConstraint(QLayout.SetFixedSize) self.__bodyFrame = QFrame(self) # self.__bodyFrame.setFrameShape( QFrame.StyledPanel ) self.__bodyFrame.setFrameShape(QFrame.NoFrame) # self.__bodyFrame.setSizePolicy( QSizePolicy.Maximum, # QSizePolicy.Expanding ) self.__bodyFrame.setLayout(self.__vLayout) self.bodyWidget = QScrollArea(self) self.bodyWidget.setFocusPolicy(Qt.NoFocus) self.bodyWidget.setWidget(self.__bodyFrame) self.bodyWidget.hide() self.__hLayout = QHBoxLayout() self.__hLayout.setContentsMargins(0, 0, 0, 0) self.__hLayout.setSpacing(0) self.__hLayout.addWidget(self.toolbar) self.__hLayout.addWidget(self.__noneLabel) self.__hLayout.addWidget(self.bodyWidget) self.setLayout(self.__hLayout) return def __updateButtonsStatus(self): " Updates the buttons status " self.printButton.setEnabled(self.__reportShown) self.printPreviewButton.setEnabled(self.__reportShown) self.clearButton.setEnabled(self.__reportShown) return def __onPrint(self): " Triggered when the print button is pressed " pass def __onPrintPreview(self): " triggered when the print preview button is pressed " pass def setFocus(self): " Overridden setFocus " self.__vLayout.setFocus() return def __clear(self): " Clears the content of the vertical layout " if not self.__reportShown: return self.__removeAll() self.bodyWidget.hide() self.__noneLabel.show() self.__report = None self.__reportShown = False self.__updateButtonsStatus() self.resizeEvent() self.__updateTooltip() return def __removeAll(self): " Removes all the items from the report " for item in self.__widgets: item.hide() self.__vLayout.removeWidget(item) del item self.__widgets = [] return def __createScoreLabel(self, score, previousScore, showFileName, fileName): " Creates the score label " txt = "Score: " + str(score) if previousScore != "": txt += " / Previous score: " + str(previousScore) if not showFileName: txt += " for " + os.path.basename(fileName) scoreLabel = QLabel(txt) scoreLabel.setFrameShape(QFrame.StyledPanel) scoreLabel.setFont(self.__headerFont) scoreLabel.setAutoFillBackground(True) palette = scoreLabel.palette() if score < self.BadLimit: palette.setColor(QPalette.Background, QColor(255, 127, 127)) palette.setColor(QPalette.Foreground, QColor(0, 0, 0)) elif score > self.GoodLimit: palette.setColor(QPalette.Background, QColor(220, 255, 220)) palette.setColor(QPalette.Foreground, QColor(0, 0, 0)) else: palette.setColor(QPalette.Background, QColor(255, 255, 127)) palette.setColor(QPalette.Foreground, QColor(0, 0, 0)) scoreLabel.setPalette(palette) return scoreLabel @staticmethod def __setTableHeight(table): " Auxiliary function to set the table height " # Height - it is ugly and approximate however I am tired of # calculating the proper height. Why is this so hard, huh? lastRowHeight = table.itemDelegate().lastHeight height = lastRowHeight * (table.topLevelItemCount() + 1) + 10 table.setFixedHeight(height) return @staticmethod def __shouldShowFileName(messages): " Decides if the file name column should be supressed " if len(messages) == 0: return False firstName = messages[0].fileName for index in range(1, len(messages)): if firstName != messages[index].fileName: return True return False def __addErrorsTable(self, messages, showFileName): " Creates the messages table " errTable = QTreeWidget(self.bodyWidget) errTable.setAlternatingRowColors(True) errTable.setRootIsDecorated(False) errTable.setItemsExpandable(False) errTable.setSortingEnabled(True) errTable.setItemDelegate(NoOutlineHeightDelegate(4)) errTable.setUniformRowHeights(True) errTable.itemActivated.connect(self.__errorActivated) headerLabels = ["File name", "Line", "Message ID", "Object", "Message"] errTable.setHeaderLabels(headerLabels) for item in messages: if item.position is None: lineNumber = str(item.lineNumber) else: lineNumber = str(item.lineNumber) + ":" + str(item.position) values = [ item.fileName, lineNumber, item.messageID, item.objectName, item.message ] errTable.addTopLevelItem(ErrorTableItem(values, 1)) # Hide the file name column if required if not showFileName: errTable.setColumnHidden(0, True) # Resizing errTable.header().resizeSections(QHeaderView.ResizeToContents) errTable.header().setStretchLastSection(True) # Sort indicator if showFileName: sortIndex = 0 # By file names else: sortIndex = 1 # By line number because this is from the same file errTable.header().setSortIndicator(sortIndex, Qt.AscendingOrder) errTable.sortItems(sortIndex, errTable.header().sortIndicatorOrder()) # Height self.__setTableHeight(errTable) self.__vLayout.addWidget(errTable) self.__widgets.append(errTable) return def __addSimilarity(self, similarity, titleText): " Adds a similarity " # Label title = QLabel(titleText) title.setFont(self.__headerFont) self.__vLayout.addWidget(title) self.__widgets.append(title) # List of files simTable = QTreeWidget(self.bodyWidget) simTable.setAlternatingRowColors(True) simTable.setRootIsDecorated(False) simTable.setItemsExpandable(False) simTable.setSortingEnabled(False) simTable.setItemDelegate(NoOutlineHeightDelegate(4)) simTable.setUniformRowHeights(True) simTable.itemActivated.connect(self.__similarityActivated) simTable.setHeaderLabels(["File name", "Line"]) for item in similarity.files: values = [item[0], str(item[1])] simTable.addTopLevelItem(QTreeWidgetItem(values)) # Resizing simTable.header().resizeSections(QHeaderView.ResizeToContents) simTable.header().setStretchLastSection(True) # Height self.__setTableHeight(simTable) self.__vLayout.addWidget(simTable) self.__widgets.append(simTable) # The fragment itself if len(similarity.fragment) > 10: # Take first 9 lines text = "\n".join(similarity.fragment[:9]) + "\n ..." toolTip = "\n".join(similarity.fragment) else: text = "\n".join(similarity.fragment) toolTip = "" fragmentLabel = QLabel("<pre>" + self.__htmlEncode(text) + "</pre>") if toolTip != "": fragmentLabel.setToolTip("<pre>" + self.__htmlEncode(toolTip) + "</pre>") palette = fragmentLabel.palette() palette.setColor(QPalette.Background, QColor(250, 250, 175)) palette.setColor(QPalette.Foreground, QColor(0, 0, 0)) fragmentLabel.setPalette(palette) fragmentLabel.setFrameShape(QFrame.StyledPanel) fragmentLabel.setAutoFillBackground(True) labelFont = fragmentLabel.font() labelFont.setFamily(GlobalData().skin.baseMonoFontFace) fragmentLabel.setFont(labelFont) self.__vLayout.addWidget(fragmentLabel) self.__widgets.append(fragmentLabel) return @staticmethod def __htmlEncode(string): " Encodes HTML " return string.replace( "&", "&" ) \ .replace( ">", ">" ) \ .replace( "<", "<" ) def __addSectionSpacer(self): " Adds a fixed height spacer to the VBox layout " spacer = QWidget() spacer.setFixedHeight(10) self.__vLayout.addWidget(spacer) self.__widgets.append(spacer) return def __addGenericTable(self, table): " Adds a generic table to the report " theTable = QTreeWidget(self.bodyWidget) theTable.setAlternatingRowColors(True) theTable.setRootIsDecorated(False) theTable.setItemsExpandable(False) theTable.setSortingEnabled(False) theTable.setItemDelegate(NoOutlineHeightDelegate(4)) theTable.setUniformRowHeights(True) headerLabels = [] for index in range(0, len(table.header)): headerLabels.append(table.header[index]) theTable.setHeaderLabels(headerLabels) for item in table.body: row = [] for index in range(0, len(table.header)): row.append(item[index]) theTable.addTopLevelItem(QTreeWidgetItem(row)) theTable.setFocusPolicy(Qt.NoFocus) # Resizing theTable.header().resizeSections(QHeaderView.ResizeToContents) theTable.header().setStretchLastSection(True) # Height self.__setTableHeight(theTable) self.__vLayout.addWidget(theTable) self.__widgets.append(theTable) return def __addGenericTableTitle(self, table): " Adds a generic table title " tableTitle = QLabel(table.title) tableTitle.setFont(self.__headerFont) self.__vLayout.addWidget(tableTitle) self.__widgets.append(tableTitle) return def __updateTooltip(self): " Generates a signal with appropriate string message " if not self.__reportShown: tooltip = "No results available" elif self.__reportOption == self.DirectoryFiles: tooltip = "Report generated for directory: " + \ self.__reportFileName elif self.__reportOption == self.ProjectFiles: tooltip = "Report generated for the whole project" elif self.__reportOption == self.SingleFile: tooltip = "Report generated for file: " + self.__reportFileName elif self.__reportOption == self.SingleBuffer: tooltip = "Report generated for unsaved file: " + \ self.__reportFileName else: tooltip = "" self.updatePylintTooltip.emit(tooltip) return def showReport(self, lint, reportOption, fileName, uuid): " Shows the pylint results " self.__removeAll() self.__noneLabel.hide() self.__report = lint self.__reportUUID = uuid self.__reportFileName = fileName self.__reportOption = reportOption showFileName = self.__shouldShowFileName(lint.errorMessages) scoreLabel = self.__createScoreLabel(lint.score, lint.previousScore, showFileName, fileName) self.__vLayout.addWidget(scoreLabel) self.__widgets.append(scoreLabel) if len(lint.errorMessages) > 0: self.__addSectionSpacer() self.__addErrorsTable(lint.errorMessages, showFileName) index = 0 for similarity in lint.similarities: self.__addSectionSpacer() self.__addSimilarity(similarity, "Similarity #" + str(index)) index += 1 for table in lint.tables: self.__addSectionSpacer() self.__addGenericTableTitle(table) self.__addGenericTable(table) self.bodyWidget.show() self.bodyWidget.ensureVisible(0, 0, 0, 0) self.__reportShown = True self.__updateButtonsStatus() self.__updateTooltip() # It helps, but why do I have flickering? QApplication.processEvents() self.__resizeBodyFrame() return def __errorActivated(self, item, column): " Handles the double click (or Enter) on the item " linePos = str(item.text(1)) if ":" in linePos: parts = linePos.split(":") lineNumber = int(parts[0]) pos = int(parts[1]) else: lineNumber = int(linePos) pos = 0 if self.__reportOption in [ self.SingleFile, self.DirectoryFiles, self.ProjectFiles ]: fileName = str(item.text(0)) else: # SingleBuffer if self.__reportFileName != "": if os.path.isabs(self.__reportFileName): fileName = self.__reportFileName else: # Could be unsaved buffer, so try to search by the mainWindow = GlobalData().mainWindow widget = mainWindow.getWidgetByUUID(self.__reportUUID) if widget is None: logging.error("The unsaved buffer has been closed") return # The widget was found, so jump to the required editor = widget.getEditor() editor.gotoLine(lineNumber, pos) editor.setFocus() return GlobalData().mainWindow.openFile(fileName, lineNumber, pos) return def __resizeBodyFrame(self): " Resizing the frame to occupy all available width " size = self.bodyWidget.maximumViewportSize() self.__bodyFrame.setMinimumWidth(size.width() - 16) self.__bodyFrame.setMinimumHeight(size.height()) return def showEvent(self, showEv=None): " Called when the widget is shown " self.__resizeBodyFrame() return def resizeEvent(self, resizeEv=None): " Called when the main window gets resized " self.__resizeBodyFrame() return def onFileUpdated(self, fileName, uuid): " Called when a buffer is saved or saved as " if not self.__reportShown: return if self.__reportUUID != uuid: return # Currently shown report is for the saved buffer # File name is expected being absolute self.__reportFileName = fileName self.updatePylintTooltip.emit("Report generated for buffer saved as " + fileName) return def __similarityActivated(self, item, column): " Triggered when a similarity is activated " fileName = str(item.text(0)) lineNumber = int(item.text(1)) GlobalData().mainWindow.openFile(fileName, lineNumber) return