def __init__(self, parent=None): QWidget.__init__(self, parent) self.__results = QStackedWidget(self) self.__bufferChangeConnected = False # Prepare members for reuse self.__noneLabel = QLabel("\nNo results available") self.__noneLabel.setFrameShape(QFrame.StyledPanel) self.__noneLabel.setAlignment(Qt.AlignHCenter) self.__headerFont = self.__noneLabel.font() self.__headerFont.setPointSize(self.__headerFont.pointSize() + 4) self.__noneLabel.setFont(self.__headerFont) self.__noneLabel.setAutoFillBackground(True) noneLabelPalette = self.__noneLabel.palette() noneLabelPalette.setColor(QPalette.Background, GlobalData().skin['nolexerPaper']) self.__noneLabel.setPalette(noneLabelPalette) self.__createLayout(parent) self.__updateButtonsStatus() GlobalData().project.sigProjectChanged.connect(self.__onProjectChanged)
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) # 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)
def __createLayout(self, varName, varType, varValue, isGlobal): """Creates the dialog layout""" varTypeParts = varType.split() if varTypeParts[0].lower() in ["string", "unicode", "qstring"]: length = str(len(varValue)) lines = str(len(varValue.splitlines())) varType = varType.split("(")[0].strip() + \ " (lines: " + lines + ", characters: " + length + ")" self.resize(600, 250) self.setSizeGripEnabled(True) # Top level layout layout = QVBoxLayout(self) gridLayout = QGridLayout() gridLayout.setSpacing(4) varScopeLabel = QLabel("Scope:", self) gridLayout.addWidget(varScopeLabel, 0, 0, Qt.AlignCenter) varScopeValue = HeaderLabel('Global' if isGlobal else 'Local', parent=self) varScopeValue.setToolTip("Double click to copy") font = varScopeValue.font() font.setFamily(GlobalData().skin['monoFont'].family()) gridLayout.addWidget(varScopeValue, 0, 1) varNameLabel = QLabel("Name:", self) gridLayout.addWidget(varNameLabel, 1, 0, Qt.AlignCenter) varNameValue = HeaderLabel(varName, parent=self) varNameValue.setToolTip("Double click to copy") gridLayout.addWidget(varNameValue, 1, 1) varTypeLabel = QLabel("Type:", self) gridLayout.addWidget(varTypeLabel, 2, 0, Qt.AlignCenter) varTypeValue = HeaderLabel(varType, parent=self) varTypeValue.setToolTip("Double click to copy") gridLayout.addWidget(varTypeValue, 2, 1) varValueLabel = QLabel("Value:", self) gridLayout.addWidget(varValueLabel, 3, 0, Qt.AlignTop) varValueValue = QTextEdit() varValueValue.setReadOnly(True) varValueValue.setFont(getZoomedMonoFont()) # varValueValue.setLineWrapMode(QTextEdit.NoWrap) varValueValue.setAcceptRichText(False) varValueValue.setPlainText(varValue) gridLayout.addWidget(varValueValue, 3, 1) layout.addLayout(gridLayout) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok) self.__OKButton = buttonBox.button(QDialogButtonBox.Ok) self.__OKButton.setDefault(True) buttonBox.accepted.connect(self.close) buttonBox.rejected.connect(self.close) layout.addWidget(buttonBox) varValueValue.setFocus()
class PathElement: """Single path element""" def __init__(self, parent=None): self.icon = QLabel() self.icon.setPixmap(getPixmap('nbsep.png')) self.combo = NavBarComboBox(parent)
def __createLayout(self): """Creates the widget layout""" verticalLayout = QVBoxLayout(self) verticalLayout.setContentsMargins(0, 0, 0, 0) verticalLayout.setSpacing(0) self.headerFrame = QFrame() self.headerFrame.setObjectName('stackheader') self.headerFrame.setStyleSheet('QFrame#stackheader {' + getLabelStyle(self) + '}') self.headerFrame.setFixedHeight(HEADER_HEIGHT) self.__stackLabel = QLabel("Stack") expandingSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) self.__showHideButton = QToolButton() self.__showHideButton.setAutoRaise(True) self.__showHideButton.setIcon(getIcon('less.png')) self.__showHideButton.setFixedSize(HEADER_BUTTON, HEADER_BUTTON) self.__showHideButton.setToolTip("Hide frames list") self.__showHideButton.setFocusPolicy(Qt.NoFocus) self.__showHideButton.clicked.connect(self.__onShowHide) headerLayout = QHBoxLayout() headerLayout.setContentsMargins(0, 0, 0, 0) headerLayout.addSpacing(3) headerLayout.addWidget(self.__stackLabel) headerLayout.addSpacerItem(expandingSpacer) headerLayout.addWidget(self.__showHideButton) self.headerFrame.setLayout(headerLayout) self.__framesList = QTreeWidget(self) self.__framesList.setSortingEnabled(False) # I might not need that because of two reasons: # - the window has no focus # - the window has custom current indicator # self.__framesList.setAlternatingRowColors(True) self.__framesList.setRootIsDecorated(False) self.__framesList.setItemsExpandable(False) self.__framesList.setUniformRowHeights(True) self.__framesList.setSelectionMode(QAbstractItemView.NoSelection) self.__framesList.setSelectionBehavior(QAbstractItemView.SelectRows) self.__framesList.setItemDelegate(NoOutlineHeightDelegate(4)) self.__framesList.setFocusPolicy(Qt.NoFocus) self.__framesList.setContextMenuPolicy(Qt.CustomContextMenu) self.__framesList.itemClicked.connect(self.__onFrameClicked) self.__framesList.itemDoubleClicked.connect( self.__onFrameDoubleClicked) self.__framesList.customContextMenuRequested.connect( self.__showContextMenu) self.__framesList.setHeaderLabels( ["", "File:line", "Function", "Arguments", "Full path"]) verticalLayout.addWidget(self.headerFrame) verticalLayout.addWidget(self.__framesList)
def __createLayout(self): """Creates the widget layout""" verticalLayout = QVBoxLayout(self) verticalLayout.setContentsMargins(0, 0, 0, 0) self.__titleLabel = QLabel() self.__titleLabel.setAutoFillBackground(True) self.__titleLabel.setFrameShape(QFrame.StyledPanel) self.__titleLabel.setStyleSheet('padding: 2px') verticalLayout.addWidget(self.__titleLabel)
def __createLayout(self): """Creates the tooltip layout""" verticalLayout = QVBoxLayout(self) verticalLayout.setContentsMargins(0, 0, 0, 0) self.info = QLabel() self.info.setAutoFillBackground(True) self.info.setFont(getZoomedMonoFont()) self.info.setFrameShape(QFrame.StyledPanel) self.info.setStyleSheet('padding: 4px') verticalLayout.addWidget(self.info) self.location = QLabel()
def __createLayout(self): """Creates the widget layout""" totalCalls = self.__stats.total_calls # The calls were not induced via recursion totalPrimitiveCalls = self.__stats.prim_calls totalTime = self.__stats.total_tt txt = "<b>Script:</b> " + self.__script + " " + \ self.__params['arguments'] + "<br/>" \ "<b>Run at:</b> " + self.__reportTime + "<br/>" + \ str(totalCalls) + " function calls (" + \ str(totalPrimitiveCalls) + " primitive calls) in " + \ FLOAT_FORMAT % totalTime + " CPU seconds" summary = QLabel(txt) summary.setToolTip(txt) summary.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed) summary.setStyleSheet('QLabel {' + getLabelStyle(self) + '}') self.__scene = QGraphicsScene() self.__viewer = DiagramWidget() self.__viewer.sigEscapePressed.connect(self.__onESC) vLayout = QVBoxLayout() vLayout.setContentsMargins(0, 0, 0, 0) vLayout.setSpacing(0) vLayout.addWidget(summary) vLayout.addWidget(self.__viewer) self.setLayout(vLayout)
def __createLayout(self): """Creates the dialog layout""" self.resize(450, 20) self.setSizeGripEnabled(True) verticalLayout = QVBoxLayout(self) self.__infoLabel = QLabel("Retrieving log of '" + self.__path + "'...") verticalLayout.addWidget(self.__infoLabel) buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Close) verticalLayout.addWidget(buttonBox) buttonBox.rejected.connect(self.__onClose)
def __createLayout(self, paths, ignoredPaths): """Creates the dialog layout""" self.resize(640, 420) self.setSizeGripEnabled(True) vboxLayout = QVBoxLayout(self) # Paths to commit part vboxLayout.addWidget(QLabel("Paths (total: " + str(len(paths)) + ")")) self.__pathView = QTreeWidget() self.__pathView.setAlternatingRowColors(True) self.__pathView.setRootIsDecorated(False) self.__pathView.setItemsExpandable(False) self.__pathView.setSortingEnabled(True) self.__pathView.setItemDelegate(NoOutlineHeightDelegate(4)) self.__pathView.setUniformRowHeights(True) self.__pathHeader = QTreeWidgetItem(["", "Path", "Status", "Message"]) self.__pathView.setHeaderItem(self.__pathHeader) self.__pathView.header().setSortIndicator(1, Qt.AscendingOrder) vboxLayout.addWidget(self.__pathView) # Paths to ignore part vboxLayout.addWidget(QLabel("Ignored paths (total: " + str(len(ignoredPaths)) + ")")) self.__ignoredPathView = QTreeWidget() self.__ignoredPathView.setAlternatingRowColors(True) self.__ignoredPathView.setRootIsDecorated(False) self.__ignoredPathView.setItemsExpandable(False) self.__ignoredPathView.setSortingEnabled(True) self.__ignoredPathView.setItemDelegate(NoOutlineHeightDelegate(4)) self.__ignoredPathView.setUniformRowHeights(True) pathToIgnoreHeader = QTreeWidgetItem(["Path", "Status"]) self.__ignoredPathView.setHeaderItem(pathToIgnoreHeader) self.__ignoredPathView.header().setSortIndicator(0, Qt.AscendingOrder) vboxLayout.addWidget(self.__ignoredPathView) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok) buttonBox.button(QDialogButtonBox.Ok).setDefault(True) buttonBox.accepted.connect(self.accept) vboxLayout.addWidget(buttonBox)
def __createLayout(self, pathsToAdd): """Creates the dialog layout""" self.resize(640, 480) self.setSizeGripEnabled(True) vboxLayout = QVBoxLayout(self) # Paths to add part vboxLayout.addWidget( QLabel("Paths to add (total: " + str(len(pathsToAdd)) + ")")) self.__pathToAddView = QTreeWidget() self.__configTable(self.__pathToAddView) self.__pathToAddHeader = QTreeWidgetItem(["", "Path"]) self.__pathToAddView.setHeaderItem(self.__pathToAddHeader) self.__pathToAddView.header().setSortIndicator(PATH_COL, Qt.AscendingOrder) self.__pathToAddView.itemChanged.connect(self.__onAddPathChanged) vboxLayout.addWidget(self.__pathToAddView) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.__OKButton = buttonBox.button(QDialogButtonBox.Ok) self.__OKButton.setText("Add") buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) buttonBox.accepted.connect(self.userAccept) buttonBox.rejected.connect(self.close) vboxLayout.addWidget(buttonBox)
def __createLayout(self, labelText): """Creates the dialog layout""" self.resize(600, 250) self.setSizeGripEnabled(True) # Top level layout layout = QVBoxLayout(self) layout.addWidget(QLabel(labelText)) self.__newCaption = QTextEdit() self.__newCaption.setFont(getZoomedMonoFont()) self.__newCaption.setAcceptRichText(False) layout.addWidget(self.__newCaption) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok) self.__OKButton = buttonBox.button(QDialogButtonBox.Ok) self.__OKButton.setDefault(True) buttonBox.accepted.connect(self.accept) buttonBox.rejected.connect(self.close) layout.addWidget(buttonBox) self.__newCaption.setFocus()
def draw(self, label): """Draws the indicator as members tell. label is QLabel""" label.setPalette(QLabel().palette()) if self.isPixmap(): label.setAutoFillBackground(False) label.setFrameStyle(QLabel().frameStyle()) label.setPixmap(self.pixmap) else: label.setFrameStyle(QFrame.StyledPanel) label.setAutoFillBackground(True) palette = label.palette() if self.backgroundColor is not None: palette.setColor(QPalette.Background, self.backgroundColor) if self.foregroundColor is not None: palette.setColor(QPalette.Foreground, self.foregroundColor) label.setPalette(palette) label.setText(self.text)
def __createLayout(self): """Creates the dialog layout""" self.setMinimumWidth(300) self.setMinimumHeight(250) self.resize(400, 300) self.setSizeGripEnabled(True) verticalLayout = QVBoxLayout(self) verticalLayout.setContentsMargins(5, 5, 5, 5) gridLayout = QGridLayout() bgLabel = QLabel('Select background color:', self) gridLayout.addWidget(bgLabel, 0, 0, 1, 1) self.__bgColorButton = ColorButton('', self) gridLayout.addWidget(self.__bgColorButton, 0, 1, 1, 1) fgLabel = QLabel('Select foreground color:', self) gridLayout.addWidget(fgLabel, 1, 0, 1, 1) self.__fgColorButton = ColorButton('', self) gridLayout.addWidget(self.__fgColorButton, 1, 1, 1, 1) borderLabel = QLabel('Select border color (*):', self) gridLayout.addWidget(borderLabel, 2, 0, 1, 1) self.__borderColorButton = ColorButton('', self) gridLayout.addWidget(self.__borderColorButton, 2, 1, 1, 1) verticalLayout.addLayout(gridLayout) verticalLayout.addWidget( QLabel('(*): docstrings use it only when shown as badges')) # Sample area self.__scene = QGraphicsScene() self.__view = QGraphicsView() self.__view.setScene(self.__scene) verticalLayout.addWidget(self.__view) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) verticalLayout.addWidget(buttonBox) buttonBox.accepted.connect(self.accept) buttonBox.rejected.connect(self.reject)
def __createLayout(self): """Creates the layout""" self.__layout = QHBoxLayout(self) self.__layout.setContentsMargins(0, 0, 0, 0) # Create info icon self.__infoIcon = QLabel(self) self.__infoIcon.setPixmap(getPixmap('cfunknown.png')) self.__layout.addWidget(self.__infoIcon) self.__warningsIcon = QLabel(self) self.__warningsIcon.setPixmap(getPixmap('cfwarning.png')) self.__layout.addWidget(self.__warningsIcon) self.clearWarnings() # Create the path label self.__pathLabel = HeaderFitLabel(self) self.__pathLabel.setTextFormat(Qt.PlainText) self.__pathLabel.setAlignment(Qt.AlignLeft) self.__pathLabel.setWordWrap(False) self.__pathLabel.setTextInteractionFlags(Qt.NoTextInteraction) self.__pathLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.__pathLabel.setMinimumWidth(40) self.__layout.addWidget(self.__pathLabel) self.__spacer = ToolBarExpandingSpacer(self) self.__spacer.setMinimumWidth(0) self.__layout.addWidget(self.__spacer) # Create the selection label self.__selectionLabel = HeaderLabel('', None, self) self.__selectionLabel.setTextFormat(Qt.PlainText) self.__selectionLabel.setAlignment(Qt.AlignCenter) self.__selectionLabel.setWordWrap(False) self.__selectionLabel.setTextInteractionFlags(Qt.NoTextInteraction) self.__selectionLabel.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.__selectionLabel.setMinimumWidth(40) self.__layout.addWidget(self.__selectionLabel) self.setSelectionLabel(0, None)
def __init__(self, ide, pluginHomeDir, parent=None): QWidget.__init__(self, parent) self.__results = None self.__ide = ide self.__pluginHomeDir = pluginHomeDir self.__noneLabel = QLabel("\nNo results available") self.__noneLabel.setFrameShape(QFrame.StyledPanel) self.__noneLabel.setAlignment(Qt.AlignHCenter) font = self.__noneLabel.font() font.setPointSize(font.pointSize() + 4) self.__noneLabel.setFont(font) self.__noneLabel.setAutoFillBackground(True) noneLabelPalette = self.__noneLabel.palette() noneLabelPalette.setColor(QPalette.Background, GlobalData().skin['nolexerPaper']) self.__noneLabel.setPalette(noneLabelPalette) self.__createLayout(self.__pluginHomeDir)
def __createLayout(self): """Creates the layout""" self.setFixedHeight(24) self.__layout = QHBoxLayout(self) self.__layout.setContentsMargins(0, 0, 0, 0) # Set the background color # Create info icon self.__infoIcon = QLabel() self.__layout.addWidget(self.__infoIcon) self.__globalScopeCombo = NavBarComboBox(self) self.__globalScopeCombo.jumpToLine.connect(self.__onJumpToLine) self.__layout.addWidget(self.__globalScopeCombo) self.__spacer = QWidget() self.__spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.__layout.addWidget(self.__spacer)
def __createLayout(self): """Creates the layout""" self.setFixedHeight(24) self.__layout = QHBoxLayout(self) self.__layout.setContentsMargins(0, 0, 0, 0) # Create info icon self.__infoIcon = QLabel() self.__infoIcon.setPixmap(getPixmap('cfunknown.png')) self.__layout.addWidget(self.__infoIcon) self.__warningsIcon = QLabel() self.__warningsIcon.setPixmap(getPixmap('cfwarning.png')) self.__layout.addWidget(self.__warningsIcon) self.clearWarnings() self.__spacer = QWidget() self.__spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.__spacer.setMinimumWidth(0) self.__layout.addWidget(self.__spacer)
def getLabelStyle(owner): """Creates a label stylesheet for the given owner widget""" modelLabel = QLabel(owner) bgColor = modelLabel.palette().color(modelLabel.backgroundRole()) del modelLabel red = bgColor.red() green = bgColor.green() blue = bgColor.blue() delta = 60 borderColor = QColor(max(red - delta, 0), max(green - delta, 0), max(blue - delta, 0)) bgColor = QColor(min(red + delta, 255), min(green + delta, 255), min(blue + delta, 255)) props = [ 'border-radius: 3px', 'padding: 4px', 'background-color: ' + colorAsString(bgColor, True), 'border: 1px solid ' + colorAsString(borderColor, True) ] return '; '.join(props)
def __createLayout(self): """Creates the dialog layout""" self.resize(450, 150) self.setSizeGripEnabled(True) verticalLayout = QVBoxLayout(self) gridLayout = QGridLayout() # Link gridLayout.addWidget(QLabel('Link', self), 0, 0, 1, 1) self.linkEdit = QLineEdit(self) self.linkEdit.setClearButtonEnabled(True) self.linkEdit.setToolTip( 'A link to a file or to an external web resource') gridLayout.addWidget(self.linkEdit, 0, 1, 1, 1) self.linkEdit.textChanged.connect(self.__validate) self.fileButton = QPushButton(self) self.fileButton.setText('...') self.fileButton.setToolTip('Select an existing or non existing file') gridLayout.addWidget(self.fileButton, 0, 2, 1, 1) self.fileButton.clicked.connect(self.__onSelectPath) self.createCheckBox = QCheckBox( 'Create a markdown file if does not exist', self) self.createCheckBox.setChecked(False) gridLayout.addWidget(self.createCheckBox, 1, 1, 1, 1) self.createCheckBox.stateChanged.connect(self.__validate) # Anchor gridLayout.addWidget(QLabel('Anchor', self), 2, 0, 1, 1) self.anchorEdit = QLineEdit(self) self.anchorEdit.setClearButtonEnabled(True) gridLayout.addWidget(self.anchorEdit, 2, 1, 1, 1) self.anchorEdit.textChanged.connect(self.__validate) # Title titleLabel = QLabel('Title', self) titleLabel.setAlignment(Qt.AlignTop) gridLayout.addWidget(titleLabel, 3, 0, 1, 1) self.titleEdit = QTextEdit() self.titleEdit.setTabChangesFocus(True) self.titleEdit.setAcceptRichText(False) self.titleEdit.setFont(getZoomedMonoFont()) self.titleEdit.setToolTip( 'If provided then will be displayed in the rectangle') gridLayout.addWidget(self.titleEdit, 3, 1, 1, 1) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok) self.__OKButton = buttonBox.button(QDialogButtonBox.Ok) self.__OKButton.setDefault(True) buttonBox.accepted.connect(self.accept) buttonBox.rejected.connect(self.close) verticalLayout.addLayout(gridLayout) verticalLayout.addWidget(buttonBox) self.linkEdit.setFocus()
def __createLayout(self): """Creates the layout""" self.setFixedHeight(24) self.__layout = QHBoxLayout(self) self.__layout.setContentsMargins(0, 0, 0, 0) # Create info icon self.__infoIcon = QLabel(self) self.__infoIcon.setPixmap(getPixmap('cfunknown.png')) self.__layout.addWidget(self.__infoIcon) self.__warningsIcon = QLabel(self) self.__warningsIcon.setPixmap(getPixmap('cfwarning.png')) self.__layout.addWidget(self.__warningsIcon) self.clearWarnings() labelStylesheet = 'QLabel {' + getLabelStyle(self.__infoIcon) + '}' # Create the path label self.__pathLabel = QLabel(self) self.__pathLabel.setStyleSheet(labelStylesheet) self.__pathLabel.setTextFormat(Qt.PlainText) self.__pathLabel.setAlignment(Qt.AlignLeft) self.__pathLabel.setWordWrap(False) self.__pathLabel.setTextInteractionFlags(Qt.NoTextInteraction) self.__pathLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.__layout.addWidget(self.__pathLabel) self.__spacer = QWidget() self.__spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.__spacer.setMinimumWidth(0) self.__layout.addWidget(self.__spacer) # Create the selection label self.__selectionLabel = QLabel(self) self.__selectionLabel.setStyleSheet(labelStylesheet) self.__selectionLabel.setTextFormat(Qt.PlainText) self.__selectionLabel.setAlignment(Qt.AlignCenter) self.__selectionLabel.setWordWrap(False) self.__selectionLabel.setTextInteractionFlags(Qt.NoTextInteraction) self.__selectionLabel.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.__selectionLabel.setMinimumWidth(40) self.__layout.addWidget(self.__selectionLabel) self.setSelectionLabel(0, None)
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)
def __createLayout(self, bpoint): """Creates the dialog layout""" self.resize(400, 150) self.setSizeGripEnabled(True) # Top level layout layout = QVBoxLayout(self) gridLayout = QGridLayout() fileLabel = QLabel("File name:") gridLayout.addWidget(fileLabel, 0, 0) fileValue = QLabel(bpoint.getAbsoluteFileName()) gridLayout.addWidget(fileValue, 0, 1) lineLabel = QLabel("Line:") gridLayout.addWidget(lineLabel, 1, 0) lineValue = QLabel(str(bpoint.getLineNumber())) gridLayout.addWidget(lineValue, 1, 1) conditionLabel = QLabel("Condition:") gridLayout.addWidget(conditionLabel, 2, 0) self.__conditionValue = CDMComboBox(True) self.__conditionValue.lineEdit().setText(bpoint.getCondition()) gridLayout.addWidget(self.__conditionValue, 2, 1) ignoreLabel = QLabel("Ignore count:") gridLayout.addWidget(ignoreLabel, 3, 0) self.__ignoreValue = QSpinBox() self.__ignoreValue.setMinimum(0) self.__ignoreValue.setValue(bpoint.getIgnoreCount()) gridLayout.addWidget(self.__ignoreValue, 3, 1) layout.addLayout(gridLayout) # Checkboxes part self.__tempCheckbox = QCheckBox("&Temporary") self.__tempCheckbox.setChecked(bpoint.isTemporary()) layout.addWidget(self.__tempCheckbox) self.__enabled = QCheckBox("&Enabled") self.__enabled.setChecked(bpoint.isEnabled()) layout.addWidget(self.__enabled) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.__OKButton = buttonBox.button(QDialogButtonBox.Ok) self.__OKButton.setDefault(True) buttonBox.accepted.connect(self.accept) buttonBox.rejected.connect(self.close) layout.addWidget(buttonBox) self.__conditionValue.setFocus()
def __createLayout(self): """Creates the dialog layout""" self.resize(400, 80) self.setSizeGripEnabled(True) vboxLayout = QVBoxLayout(self) hboxLayout = QHBoxLayout() hboxLayout.addWidget(QLabel("Status update interval, sec.")) self.__intervalEdit = QLineEdit() self.__intervalEdit.setValidator(QIntValidator(1, 3600, self)) self.__intervalEdit.setAlignment(Qt.AlignRight | Qt.AlignVCenter) hboxLayout.addWidget(self.__intervalEdit) # Buttons at the bottom self.__buttonBox = QDialogButtonBox(self) self.__buttonBox.setOrientation(Qt.Horizontal) self.__buttonBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.__buttonBox.accepted.connect(self.userAccept) self.__buttonBox.rejected.connect(self.close) vboxLayout.addLayout(hboxLayout) vboxLayout.addWidget(self.__buttonBox)
def __createLayout(self, bpointsModel): """Creates the widget layout""" verticalLayout = QVBoxLayout(self) verticalLayout.setContentsMargins(0, 0, 0, 0) verticalLayout.setSpacing(0) self.headerFrame = QFrame() self.headerFrame.setObjectName('bpheader') self.headerFrame.setStyleSheet('QFrame#bpheader {' + getLabelStyle(self) + '}') self.headerFrame.setFixedHeight(HEADER_HEIGHT) self.__breakpointLabel = QLabel("Breakpoints") headerLayout = QHBoxLayout() headerLayout.setContentsMargins(0, 0, 0, 0) headerLayout.addSpacing(3) headerLayout.addWidget(self.__breakpointLabel) self.headerFrame.setLayout(headerLayout) self.bpointsList = BreakPointView(self, bpointsModel) self.__editButton = QAction(getIcon('bpprops.png'), "Edit breakpoint properties", self) self.__editButton.triggered.connect(self.__onEdit) self.__editButton.setEnabled(False) self.__jumpToCodeButton = QAction(getIcon('gotoline.png'), "Jump to the code", self) self.__jumpToCodeButton.triggered.connect(self.__onJumpToCode) self.__jumpToCodeButton.setEnabled(False) self.__enableButton = QAction(getIcon('bpenable.png'), "Enable selected breakpoint", self) self.__enableButton.triggered.connect(self.__onEnableDisable) self.__enableButton.setEnabled(False) self.__disableButton = QAction(getIcon('bpdisable.png'), "Disable selected breakpoint", self) self.__disableButton.triggered.connect(self.__onEnableDisable) self.__disableButton.setEnabled(False) self.__enableAllButton = QAction(getIcon('bpenableall.png'), "Enable all the breakpoint", self) self.__enableAllButton.triggered.connect(self.__onEnableAll) self.__enableAllButton.setEnabled(False) self.__disableAllButton = QAction(getIcon('bpdisableall.png'), "Disable all the breakpoint", self) self.__disableAllButton.triggered.connect(self.__onDisableAll) self.__disableAllButton.setEnabled(False) self.__delButton = QAction(getIcon('delitem.png'), "Delete selected breakpoint", self) self.__delButton.triggered.connect(self.__onDel) self.__delButton.setEnabled(False) self.__delAllButton = QAction(getIcon('bpdelall.png'), "Delete all the breakpoint", self) self.__delAllButton.triggered.connect(self.__onDelAll) self.__delAllButton.setEnabled(False) # Toolbar self.toolbar = QToolBar() self.toolbar.setOrientation(Qt.Horizontal) self.toolbar.setMovable(False) self.toolbar.setAllowedAreas(Qt.TopToolBarArea) self.toolbar.setIconSize(QSize(16, 16)) self.toolbar.setFixedHeight(28) self.toolbar.setContentsMargins(0, 0, 0, 0) self.toolbar.addAction(self.__editButton) self.toolbar.addAction(self.__jumpToCodeButton) fixedSpacer2 = QWidget() fixedSpacer2.setFixedWidth(5) self.toolbar.addWidget(fixedSpacer2) self.toolbar.addAction(self.__enableButton) self.toolbar.addAction(self.__enableAllButton) fixedSpacer3 = QWidget() fixedSpacer3.setFixedWidth(5) self.toolbar.addWidget(fixedSpacer3) self.toolbar.addAction(self.__disableButton) self.toolbar.addAction(self.__disableAllButton) expandingSpacer = QWidget() expandingSpacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) fixedSpacer4 = QWidget() fixedSpacer4.setFixedWidth(5) self.toolbar.addWidget(fixedSpacer4) self.toolbar.addWidget(expandingSpacer) self.toolbar.addAction(self.__delButton) fixedSpacer5 = QWidget() fixedSpacer5.setFixedWidth(5) self.toolbar.addWidget(fixedSpacer5) self.toolbar.addAction(self.__delAllButton) verticalLayout.addWidget(self.headerFrame) verticalLayout.addWidget(self.toolbar) verticalLayout.addWidget(self.bpointsList)
class BreakPointViewer(QWidget): """Implements the break point viewer for a debugger""" def __init__(self, parent, bpointsModel): QWidget.__init__(self, parent) self.__currentItem = None self.__createLayout(bpointsModel) GlobalData().project.sigProjectChanged.connect(self.__onProjectChanged) GlobalData().project.sigProjectAboutToUnload.connect( self.__onProjectAboutToUnload) self.bpointsList.sigSelectionChanged.connect(self.__onSelectionChanged) bpointsModel.sigBreakpoinsChanged.connect(self.__onModelChanged) def setFocus(self): """Sets the widget focus""" self.bpointsList.setFocus() def __createLayout(self, bpointsModel): """Creates the widget layout""" verticalLayout = QVBoxLayout(self) verticalLayout.setContentsMargins(0, 0, 0, 0) verticalLayout.setSpacing(0) self.headerFrame = QFrame() self.headerFrame.setObjectName('bpheader') self.headerFrame.setStyleSheet('QFrame#bpheader {' + getLabelStyle(self) + '}') self.headerFrame.setFixedHeight(HEADER_HEIGHT) self.__breakpointLabel = QLabel("Breakpoints") headerLayout = QHBoxLayout() headerLayout.setContentsMargins(0, 0, 0, 0) headerLayout.addSpacing(3) headerLayout.addWidget(self.__breakpointLabel) self.headerFrame.setLayout(headerLayout) self.bpointsList = BreakPointView(self, bpointsModel) self.__editButton = QAction(getIcon('bpprops.png'), "Edit breakpoint properties", self) self.__editButton.triggered.connect(self.__onEdit) self.__editButton.setEnabled(False) self.__jumpToCodeButton = QAction(getIcon('gotoline.png'), "Jump to the code", self) self.__jumpToCodeButton.triggered.connect(self.__onJumpToCode) self.__jumpToCodeButton.setEnabled(False) self.__enableButton = QAction(getIcon('bpenable.png'), "Enable selected breakpoint", self) self.__enableButton.triggered.connect(self.__onEnableDisable) self.__enableButton.setEnabled(False) self.__disableButton = QAction(getIcon('bpdisable.png'), "Disable selected breakpoint", self) self.__disableButton.triggered.connect(self.__onEnableDisable) self.__disableButton.setEnabled(False) self.__enableAllButton = QAction(getIcon('bpenableall.png'), "Enable all the breakpoint", self) self.__enableAllButton.triggered.connect(self.__onEnableAll) self.__enableAllButton.setEnabled(False) self.__disableAllButton = QAction(getIcon('bpdisableall.png'), "Disable all the breakpoint", self) self.__disableAllButton.triggered.connect(self.__onDisableAll) self.__disableAllButton.setEnabled(False) self.__delButton = QAction(getIcon('delitem.png'), "Delete selected breakpoint", self) self.__delButton.triggered.connect(self.__onDel) self.__delButton.setEnabled(False) self.__delAllButton = QAction(getIcon('bpdelall.png'), "Delete all the breakpoint", self) self.__delAllButton.triggered.connect(self.__onDelAll) self.__delAllButton.setEnabled(False) # Toolbar self.toolbar = QToolBar() self.toolbar.setOrientation(Qt.Horizontal) self.toolbar.setMovable(False) self.toolbar.setAllowedAreas(Qt.TopToolBarArea) self.toolbar.setIconSize(QSize(16, 16)) self.toolbar.setFixedHeight(28) self.toolbar.setContentsMargins(0, 0, 0, 0) self.toolbar.addAction(self.__editButton) self.toolbar.addAction(self.__jumpToCodeButton) fixedSpacer2 = QWidget() fixedSpacer2.setFixedWidth(5) self.toolbar.addWidget(fixedSpacer2) self.toolbar.addAction(self.__enableButton) self.toolbar.addAction(self.__enableAllButton) fixedSpacer3 = QWidget() fixedSpacer3.setFixedWidth(5) self.toolbar.addWidget(fixedSpacer3) self.toolbar.addAction(self.__disableButton) self.toolbar.addAction(self.__disableAllButton) expandingSpacer = QWidget() expandingSpacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) fixedSpacer4 = QWidget() fixedSpacer4.setFixedWidth(5) self.toolbar.addWidget(fixedSpacer4) self.toolbar.addWidget(expandingSpacer) self.toolbar.addAction(self.__delButton) fixedSpacer5 = QWidget() fixedSpacer5.setFixedWidth(5) self.toolbar.addWidget(fixedSpacer5) self.toolbar.addAction(self.__delAllButton) verticalLayout.addWidget(self.headerFrame) verticalLayout.addWidget(self.toolbar) verticalLayout.addWidget(self.bpointsList) def clear(self): """Clears the content""" self.__onDelAll() self.__updateBreakpointsLabel() self.__currentItem = None def __updateBreakpointsLabel(self): """Updates the breakpoints header label""" enableCount, \ disableCount = self.bpointsList.model().sourceModel().getCounts() total = enableCount + disableCount if total > 0: self.__breakpointLabel.setText("Breakpoints (total: " + str(total) + ")") else: self.__breakpointLabel.setText("Breakpoints") def __onProjectChanged(self, what): """Triggered when a project is changed""" if what != CodimensionProject.CompleteProject: return self.clear() model = self.bpointsList.model().sourceModel() project = GlobalData().project if project.isLoaded(): bpoints = project.breakpoints else: bpoints = Settings().breakpoints for bpoint in bpoints: newBpoint = Breakpoint() try: if not newBpoint.deserialize(bpoint): # Non valid continue except: continue # Need to check if it still points to a breakable line line = newBpoint.getLineNumber() fileName = newBpoint.getAbsoluteFileName() breakableLines = getBreakpointLines(fileName, None, True) if breakableLines is not None and line in breakableLines: model.addBreakpoint(newBpoint) else: logging.warning("Breakpoint at " + fileName + ":" + str(line) + " does not point to a breakable " "line anymore (the file is invalid or was " "modified outside of the " "IDE etc.). The breakpoint is deleted.") def __onProjectAboutToUnload(self): """Triggered before the project is unloaded""" self.__serializeBreakpoints() def __serializeBreakpoints(self): """Saves the breakpoints into a file""" model = self.bpointsList.model().sourceModel() project = GlobalData().project if project.isLoaded(): project.breakpoints = model.serialize() else: Settings().breakpoints = model.serialize() def __onSelectionChanged(self, index): """Triggered when the current item is changed""" if index.isValid(): srcModel = self.bpointsList.model().sourceModel() sindex = self.bpointsList.toSourceIndex(index) self.__currentItem = srcModel.getBreakPointByIndex(sindex) else: self.__currentItem = None self.__updateButtons() def __updateButtons(self): """Updates the buttons status""" enableCount, \ disableCount = self.bpointsList.model().sourceModel().getCounts() if self.__currentItem is None: self.__editButton.setEnabled(False) self.__enableButton.setEnabled(False) self.__disableButton.setEnabled(False) self.__jumpToCodeButton.setEnabled(False) self.__delButton.setEnabled(False) else: self.__editButton.setEnabled(True) self.__enableButton.setEnabled(not self.__currentItem.isEnabled()) self.__disableButton.setEnabled(self.__currentItem.isEnabled()) self.__jumpToCodeButton.setEnabled(True) self.__delButton.setEnabled(True) self.__enableAllButton.setEnabled(disableCount > 0) self.__disableAllButton.setEnabled(enableCount > 0) self.__delAllButton.setEnabled(enableCount + disableCount > 0) def __onEnableDisable(self): """Triggered when a breakpoint should be enabled/disabled""" if self.__currentItem is not None: if self.__currentItem.isEnabled(): self.bpointsList.disableBreak() else: self.bpointsList.enableBreak() def __onEdit(self): """Triggered when a breakpoint should be edited""" if self.__currentItem is None: return dlg = BreakpointEditDialog(self.__currentItem) if dlg.exec_() == QDialog.Accepted: newBpoint = dlg.getData() if newBpoint == self.__currentItem: return model = self.bpointsList.model().sourceModel() index = model.getBreakPointIndex( self.__currentItem.getAbsoluteFileName(), self.__currentItem.getLineNumber()) model.setBreakPointByIndex(index, newBpoint) self.bpointsList.layoutDisplay() def __onJumpToCode(self): """Triggered when should jump to source""" if self.__currentItem is None: return self.bpointsList.jumpToCode(self.__currentItem.getAbsoluteFileName(), self.__currentItem.getLineNumber()) def __onEnableAll(self): """Triggered when all the breakpoints should be enabled""" self.bpointsList.enableAllBreaks() def __onDisableAll(self): """Triggered when all the breakpoints should be disabled""" self.bpointsList.disableAllBreaks() def __onDel(self): """Triggered when a breakpoint should be deleted""" if self.__currentItem is not None: self.bpointsList.deleteBreak() def __onDelAll(self): """Triggered when all the breakpoints should be deleted""" self.bpointsList.deleteAllBreaks() def __onModelChanged(self): """Triggered when something has changed in any of the breakpoints""" self.__updateBreakpointsLabel() self.__updateButtons() self.bpointsList.layoutDisplay() self.__serializeBreakpoints()
def __createToolbar(self): """Creates 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(30) self.__toolbar.setContentsMargins(0, 0, 0, 0) # Buttons saveAsMenu = QMenu(self) saveAsSVGAct = saveAsMenu.addAction(getIcon('filesvg.png'), 'Save as SVG...') saveAsSVGAct.triggered.connect(self.onSaveAsSVG) saveAsPDFAct = saveAsMenu.addAction(getIcon('filepdf.png'), 'Save as PDF...') saveAsPDFAct.triggered.connect(self.onSaveAsPDF) saveAsPNGAct = saveAsMenu.addAction(getIcon('filepixmap.png'), 'Save as PNG...') saveAsPNGAct.triggered.connect(self.onSaveAsPNG) saveAsMenu.addSeparator() saveAsCopyToClipboardAct = saveAsMenu.addAction( getIcon('copymenu.png'), 'Copy to clipboard') saveAsCopyToClipboardAct.triggered.connect(self.copyToClipboard) self.__saveAsButton = QToolButton(self) self.__saveAsButton.setIcon(getIcon('saveasmenu.png')) self.__saveAsButton.setToolTip('Save as') self.__saveAsButton.setPopupMode(QToolButton.InstantPopup) self.__saveAsButton.setMenu(saveAsMenu) self.__saveAsButton.setFocusPolicy(Qt.NoFocus) self.__levelUpButton = QToolButton(self) self.__levelUpButton.setFocusPolicy(Qt.NoFocus) self.__levelUpButton.setIcon(getIcon('levelup.png')) self.__levelUpButton.setToolTip('Smart zoom level up (Shift+wheel)') self.__levelUpButton.clicked.connect(self.onSmartZoomLevelUp) self.__levelIndicator = QLabel('<b>0</b>', self) self.__levelIndicator.setAlignment(Qt.AlignCenter) self.__levelDownButton = QToolButton(self) self.__levelDownButton.setFocusPolicy(Qt.NoFocus) self.__levelDownButton.setIcon(getIcon('leveldown.png')) self.__levelDownButton.setToolTip('Smart zoom level down (Shift+wheel)') self.__levelDownButton.clicked.connect(self.onSmartZoomLevelDown) fixedSpacer = QWidget() fixedSpacer.setFixedHeight(10) self.__hideDocstrings = QToolButton(self) self.__hideDocstrings.setCheckable(True) self.__hideDocstrings.setIcon(getIcon('hidedocstrings.png')) self.__hideDocstrings.setToolTip('Show/hide docstrings') self.__hideDocstrings.setFocusPolicy(Qt.NoFocus) self.__hideDocstrings.setChecked(Settings()['hidedocstrings']) self.__hideDocstrings.clicked.connect(self.__onHideDocstrings) self.__hideComments = QToolButton(self) self.__hideComments.setCheckable(True) self.__hideComments.setIcon(getIcon('hidecomments.png')) self.__hideComments.setToolTip('Show/hide comments') self.__hideComments.setFocusPolicy(Qt.NoFocus) self.__hideComments.setChecked(Settings()['hidecomments']) self.__hideComments.clicked.connect(self.__onHideComments) self.__hideExcepts = QToolButton(self) self.__hideExcepts.setCheckable(True) self.__hideExcepts.setIcon(getIcon('hideexcepts.png')) self.__hideExcepts.setToolTip('Show/hide except blocks') self.__hideExcepts.setFocusPolicy(Qt.NoFocus) self.__hideExcepts.setChecked(Settings()['hideexcepts']) self.__hideExcepts.clicked.connect(self.__onHideExcepts) spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.__toolbar.addWidget(self.__saveAsButton) self.__toolbar.addWidget(spacer) self.__toolbar.addWidget(self.__levelUpButton) self.__toolbar.addWidget(self.__levelIndicator) self.__toolbar.addWidget(self.__levelDownButton) self.__toolbar.addWidget(fixedSpacer) self.__toolbar.addWidget(self.__hideDocstrings) self.__toolbar.addWidget(self.__hideComments) self.__toolbar.addWidget(self.__hideExcepts) return self.__toolbar
class FlowUIWidget(QWidget): """The widget which goes along with the text editor""" def __init__(self, editor, parent): QWidget.__init__(self, parent) # It is always not visible at the beginning because there is no # editor content at the start self.setVisible(False) self.__editor = editor self.__parentWidget = parent self.__connected = False self.__needPathUpdate = False self.cflowSettings = getCflowSettings(self) self.__displayProps = (self.cflowSettings.hidedocstrings, self.cflowSettings.hidecomments, self.cflowSettings.hideexcepts, Settings()['smartZoom']) hLayout = QHBoxLayout() hLayout.setContentsMargins(0, 0, 0, 0) hLayout.setSpacing(0) vLayout = QVBoxLayout() vLayout.setContentsMargins(0, 0, 0, 0) vLayout.setSpacing(0) # Make pylint happy self.__toolbar = None self.__navBar = None self.__cf = None self.__canvas = None self.__validGroups = [] self.__allGroupId = set() # Create the update timer self.__updateTimer = QTimer(self) self.__updateTimer.setSingleShot(True) self.__updateTimer.timeout.connect(self.process) vLayout.addWidget(self.__createNavigationBar()) vLayout.addWidget(self.__createStackedViews()) hLayout.addLayout(vLayout) hLayout.addWidget(self.__createToolbar()) self.setLayout(hLayout) self.updateSettings() # Connect to the change file type signal self.__mainWindow = GlobalData().mainWindow editorsManager = self.__mainWindow.editorsManagerWidget.editorsManager editorsManager.sigFileTypeChanged.connect(self.__onFileTypeChanged) Settings().sigHideDocstringsChanged.connect( self.__onHideDocstringsChanged) Settings().sigHideCommentsChanged.connect(self.__onHideCommentsChanged) Settings().sigHideExceptsChanged.connect(self.__onHideExceptsChanged) Settings().sigSmartZoomChanged.connect(self.__onSmartZoomChanged) self.setSmartZoomLevel(Settings()['smartZoom']) def getParentWidget(self): return self.__parentWidget def view(self): """Provides a reference to the current view""" return self.smartViews.currentWidget() def scene(self): """Provides a reference to the current scene""" return self.view().scene def __createToolbar(self): """Creates 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(30) self.__toolbar.setContentsMargins(0, 0, 0, 0) # Buttons saveAsMenu = QMenu(self) saveAsSVGAct = saveAsMenu.addAction(getIcon('filesvg.png'), 'Save as SVG...') saveAsSVGAct.triggered.connect(self.onSaveAsSVG) saveAsPDFAct = saveAsMenu.addAction(getIcon('filepdf.png'), 'Save as PDF...') saveAsPDFAct.triggered.connect(self.onSaveAsPDF) saveAsPNGAct = saveAsMenu.addAction(getIcon('filepixmap.png'), 'Save as PNG...') saveAsPNGAct.triggered.connect(self.onSaveAsPNG) saveAsMenu.addSeparator() saveAsCopyToClipboardAct = saveAsMenu.addAction( getIcon('copymenu.png'), 'Copy to clipboard') saveAsCopyToClipboardAct.triggered.connect(self.copyToClipboard) self.__saveAsButton = QToolButton(self) self.__saveAsButton.setIcon(getIcon('saveasmenu.png')) self.__saveAsButton.setToolTip('Save as') self.__saveAsButton.setPopupMode(QToolButton.InstantPopup) self.__saveAsButton.setMenu(saveAsMenu) self.__saveAsButton.setFocusPolicy(Qt.NoFocus) self.__levelUpButton = QToolButton(self) self.__levelUpButton.setFocusPolicy(Qt.NoFocus) self.__levelUpButton.setIcon(getIcon('levelup.png')) self.__levelUpButton.setToolTip('Smart zoom level up (Shift+wheel)') self.__levelUpButton.clicked.connect(self.onSmartZoomLevelUp) self.__levelIndicator = QLabel('<b>0</b>', self) self.__levelIndicator.setAlignment(Qt.AlignCenter) self.__levelDownButton = QToolButton(self) self.__levelDownButton.setFocusPolicy(Qt.NoFocus) self.__levelDownButton.setIcon(getIcon('leveldown.png')) self.__levelDownButton.setToolTip('Smart zoom level down (Shift+wheel)') self.__levelDownButton.clicked.connect(self.onSmartZoomLevelDown) fixedSpacer = QWidget() fixedSpacer.setFixedHeight(10) self.__hideDocstrings = QToolButton(self) self.__hideDocstrings.setCheckable(True) self.__hideDocstrings.setIcon(getIcon('hidedocstrings.png')) self.__hideDocstrings.setToolTip('Show/hide docstrings') self.__hideDocstrings.setFocusPolicy(Qt.NoFocus) self.__hideDocstrings.setChecked(Settings()['hidedocstrings']) self.__hideDocstrings.clicked.connect(self.__onHideDocstrings) self.__hideComments = QToolButton(self) self.__hideComments.setCheckable(True) self.__hideComments.setIcon(getIcon('hidecomments.png')) self.__hideComments.setToolTip('Show/hide comments') self.__hideComments.setFocusPolicy(Qt.NoFocus) self.__hideComments.setChecked(Settings()['hidecomments']) self.__hideComments.clicked.connect(self.__onHideComments) self.__hideExcepts = QToolButton(self) self.__hideExcepts.setCheckable(True) self.__hideExcepts.setIcon(getIcon('hideexcepts.png')) self.__hideExcepts.setToolTip('Show/hide except blocks') self.__hideExcepts.setFocusPolicy(Qt.NoFocus) self.__hideExcepts.setChecked(Settings()['hideexcepts']) self.__hideExcepts.clicked.connect(self.__onHideExcepts) spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.__toolbar.addWidget(self.__saveAsButton) self.__toolbar.addWidget(spacer) self.__toolbar.addWidget(self.__levelUpButton) self.__toolbar.addWidget(self.__levelIndicator) self.__toolbar.addWidget(self.__levelDownButton) self.__toolbar.addWidget(fixedSpacer) self.__toolbar.addWidget(self.__hideDocstrings) self.__toolbar.addWidget(self.__hideComments) self.__toolbar.addWidget(self.__hideExcepts) return self.__toolbar def __createNavigationBar(self): """Creates the navigation bar""" self.__navBar = ControlFlowNavigationBar(self) return self.__navBar def __createStackedViews(self): """Creates the graphics view""" self.smartViews = QStackedWidget(self) self.smartViews.setContentsMargins(0, 0, 0, 0) self.smartViews.addWidget(CFGraphicsView(self.__navBar, self)) self.smartViews.addWidget(CFGraphicsView(self.__navBar, self)) return self.smartViews def process(self): """Parses the content and displays the results""" if not self.__connected: self.__connectEditorSignals() start = timer() cf = getControlFlowFromMemory(self.__editor.text) end = timer() if cf.errors: self.__navBar.updateInfoIcon(self.__navBar.STATE_BROKEN_UTD) errors = [] for err in cf.errors: if err[0] == -1 and err[1] == -1: errors.append(err[2]) elif err[1] == -1: errors.append('[' + str(err[0]) + ':] ' + err[2]) elif err[0] == -1: errors.append('[:' + str(err[1]) + '] ' + err[2]) else: errors.append('[' + str(err[0]) + ':' + str(err[1]) + '] ' + err[2]) self.__navBar.setErrors(errors) return self.__cf = cf if self.isDebugMode(): logging.info('Parsed file: %s', formatFlow(str(self.__cf))) logging.info('Parse timing: %f', end - start) # Collect warnings (parser + CML warnings) and valid groups self.__validGroups = [] self.__allGroupId = set() allWarnings = self.__cf.warnings + \ CMLVersion.validateCMLComments(self.__cf, self.__validGroups, self.__allGroupId) # That will clear the error tooltip as well self.__navBar.updateInfoIcon(self.__navBar.STATE_OK_UTD) if allWarnings: warnings = [] for warn in allWarnings: if warn[0] == -1 and warn[1] == -1: warnings.append(warn[2]) elif warn[1] == -1: warnings.append('[' + str(warn[0]) + ':] ' + warn[2]) elif warn[0] == -1: warnings.append('[:' + str(warn[1]) + '] ' + warn[2]) else: warnings.append('[' + str(warn[0]) + ':' + str(warn[1]) + '] ' + warn[2]) self.__navBar.setWarnings(warnings) else: self.__navBar.clearWarnings() self.redrawScene() def __cleanupCanvas(self): """Cleans up the canvas""" if self.__canvas is not None: self.__canvas.cleanup() self.__canvas = None for item in self.scene().items(): item.cleanup() self.scene().clear() def redrawScene(self): """Redraws the scene""" smartZoomLevel = Settings()['smartZoom'] self.cflowSettings = getCflowSettings(self) if self.dirty(): self.__displayProps = (self.cflowSettings.hidedocstrings, self.cflowSettings.hidecomments, self.cflowSettings.hideexcepts, smartZoomLevel) self.cflowSettings.itemID = 0 self.cflowSettings = tweakSmartSettings(self.cflowSettings, smartZoomLevel) try: fileName = self.__parentWidget.getFileName() if not fileName: fileName = self.__parentWidget.getShortName() collapsedGroups = getCollapsedGroups(fileName) # Top level canvas has no adress and no parent canvas self.__cleanupCanvas() self.__canvas = VirtualCanvas(self.cflowSettings, None, None, self.__validGroups, collapsedGroups, None) lStart = timer() self.__canvas.layoutModule(self.__cf) lEnd = timer() self.__canvas.setEditor(self.__editor) width, height = self.__canvas.render() rEnd = timer() self.scene().setSceneRect(0, 0, width, height) self.__canvas.draw(self.scene(), 0, 0) dEnd = timer() if self.isDebugMode(): logging.info('Redrawing is done. Size: %d x %d', width, height) logging.info('Layout timing: %f', lEnd - lStart) logging.info('Render timing: %f', rEnd - lEnd) logging.info('Draw timing: %f', dEnd - rEnd) except Exception as exc: logging.error(str(exc)) raise def onFlowZoomChanged(self): """Triggered when a flow zoom is changed""" if self.__cf: selection = self.scene().serializeSelection() firstOnScreen = self.scene().getFirstLogicalItem() self.cflowSettings.onFlowZoomChanged() self.redrawScene() self.updateNavigationToolbar('') self.scene().restoreSelectionByID(selection) self.__restoreScroll(firstOnScreen) def __onFileTypeChanged(self, fileName, uuid, newFileType): """Triggered when a buffer content type has changed""" if self.__parentWidget.getUUID() != uuid: return if not isPythonMime(newFileType): self.__disconnectEditorSignals() self.__updateTimer.stop() self.__cleanupCanvas() self.__cf = None self.__validGroups = [] self.setVisible(False) self.__navBar.updateInfoIcon(self.__navBar.STATE_UNKNOWN) return # Update the bar and show it self.setVisible(True) self.process() # The buffer type change event comes when the content is loaded first # time. So this is a good point to restore the position _, _, _, cflowHPos, cflowVPos = getFilePosition(fileName) self.setScrollbarPositions(cflowHPos, cflowVPos) def terminate(self): """Called when a tab is closed""" if self.__updateTimer.isActive(): self.__updateTimer.stop() self.__updateTimer.deleteLater() self.__disconnectEditorSignals() self.__mainWindow = GlobalData().mainWindow editorsManager = self.__mainWindow.editorsManagerWidget.editorsManager editorsManager.sigFileTypeChanged.disconnect(self.__onFileTypeChanged) Settings().sigHideDocstringsChanged.disconnect( self.__onHideDocstringsChanged) Settings().sigHideCommentsChanged.disconnect(self.__onHideCommentsChanged) Settings().sigHideExceptsChanged.disconnect(self.__onHideExceptsChanged) Settings().sigSmartZoomChanged.disconnect(self.__onSmartZoomChanged) # Helps GC to collect more self.__cleanupCanvas() for index in range(self.smartViews.count()): self.smartViews.widget(index).terminate() self.smartViews.widget(index).deleteLater() self.smartViews.deleteLater() self.__navBar.deleteLater() self.__cf = None self.__saveAsButton.menu().deleteLater() self.__saveAsButton.deleteLater() self.__levelUpButton.clicked.disconnect(self.onSmartZoomLevelUp) self.__levelUpButton.deleteLater() self.__levelDownButton.clicked.disconnect(self.onSmartZoomLevelDown) self.__levelDownButton.deleteLater() self.__hideDocstrings.clicked.disconnect(self.__onHideDocstrings) self.__hideDocstrings.deleteLater() self.__hideComments.clicked.disconnect(self.__onHideComments) self.__hideComments.deleteLater() self.__hideExcepts.clicked.disconnect(self.__onHideExcepts) self.__hideExcepts.deleteLater() self.__toolbar.deleteLater() self.__editor = None self.__parentWidget = None self.cflowSettings = None self.__displayProps = None def __connectEditorSignals(self): """When it is a python file - connect to the editor signals""" if not self.__connected: self.__editor.cursorPositionChanged.connect( self.__cursorPositionChanged) self.__editor.textChanged.connect(self.__onBufferChanged) self.__connected = True def __disconnectEditorSignals(self): """Disconnect the editor signals when the file is not a python one""" if self.__connected: self.__editor.cursorPositionChanged.disconnect( self.__cursorPositionChanged) self.__editor.textChanged.disconnect(self.__onBufferChanged) self.__connected = False def __cursorPositionChanged(self): """Cursor position changed""" # The timer should be reset only in case if the redrawing was delayed if self.__updateTimer.isActive(): self.__updateTimer.stop() self.__updateTimer.start(IDLE_TIMEOUT) def __onBufferChanged(self): """Triggered to update status icon and to restart the timer""" self.__updateTimer.stop() if self.__navBar.getCurrentState() in [self.__navBar.STATE_OK_UTD, self.__navBar.STATE_OK_CHN, self.__navBar.STATE_UNKNOWN]: self.__navBar.updateInfoIcon(self.__navBar.STATE_OK_CHN) else: self.__navBar.updateInfoIcon(self.__navBar.STATE_BROKEN_CHN) self.__updateTimer.start(IDLE_TIMEOUT) def redrawNow(self): """Redraw the diagram regardless of the timer""" if self.__updateTimer.isActive(): self.__updateTimer.stop() self.process() def generateNewGroupId(self): """Generates a new group ID (string)""" # It can also consider the current set of the groups: valid + invalid # and generate an integer id which is shorter for vacantGroupId in range(1000): groupId = str(vacantGroupId) if not groupId in self.__allGroupId: return groupId # Last resort return str(uuid.uuid1()) def updateNavigationToolbar(self, text): """Updates the toolbar text""" if self.__needPathUpdate: self.__navBar.setPath(text) def updateSettings(self): """Updates settings""" self.__needPathUpdate = Settings()['showCFNavigationBar'] self.__navBar.setPathVisible(self.__needPathUpdate) self.__navBar.setPath('') def highlightAtAbsPos(self, absPos, line, pos): """Scrolls the view to the item closest to absPos and selects it. line and pos are 1-based """ item, _ = self.scene().getNearestItem(absPos, line, pos) if item: GlobalData().mainWindow.setFocusToFloatingRenderer() self.scene().clearSelection() item.setSelected(True) self.view().scrollTo(item) self.setFocus() def setFocus(self): """Sets the focus""" self.view().setFocus() @staticmethod def __getDefaultSaveDir(): """Provides the default directory to save files to""" project = GlobalData().project if project.isLoaded(): return project.getProjectDir() return QDir.currentPath() def __selectFile(self, extension): """Picks a file of a certain extension""" dialog = QFileDialog(self, 'Save flowchart as') dialog.setFileMode(QFileDialog.AnyFile) dialog.setLabelText(QFileDialog.Accept, "Save") dialog.setNameFilter(extension.upper() + " files (*." + extension.lower() + ")") urls = [] for dname in QDir.drives(): urls.append(QUrl.fromLocalFile(dname.absoluteFilePath())) urls.append(QUrl.fromLocalFile(QDir.homePath())) project = GlobalData().project if project.isLoaded(): urls.append(QUrl.fromLocalFile(project.getProjectDir())) dialog.setSidebarUrls(urls) suggestedFName = self.__parentWidget.getFileName() if '.' in suggestedFName: dotIndex = suggestedFName.rindex('.') suggestedFName = suggestedFName[:dotIndex] dialog.setDirectory(self.__getDefaultSaveDir()) dialog.selectFile(suggestedFName + "." + extension.lower()) dialog.setOption(QFileDialog.DontConfirmOverwrite, False) dialog.setOption(QFileDialog.DontUseNativeDialog, True) if dialog.exec_() != QDialog.Accepted: return None fileNames = dialog.selectedFiles() fileName = os.path.abspath(str(fileNames[0])) if os.path.isdir(fileName): logging.error("A file must be selected") return None if "." not in fileName: fileName += "." + extension.lower() # Check permissions to write into the file or to a directory if os.path.exists(fileName): # Check write permissions for the file if not os.access(fileName, os.W_OK): logging.error("There is no write permissions for " + fileName) return None else: # Check write permissions to the directory dirName = os.path.dirname(fileName) if not os.access(dirName, os.W_OK): logging.error("There is no write permissions for the " "directory " + dirName) return None if os.path.exists(fileName): res = QMessageBox.warning( self, "Save flowchart as", "<p>The file <b>" + fileName + "</b> already exists.</p>", QMessageBox.StandardButtons(QMessageBox.Abort | QMessageBox.Save), QMessageBox.Abort) if res == QMessageBox.Abort or res == QMessageBox.Cancel: return None # All prerequisites are checked, return a file name return fileName def onSaveAsSVG(self): """Triggered on the 'Save as SVG' button""" fileName = self.__selectFile("svg") if fileName is None: return False try: self.__saveAsSVG(fileName) except Exception as excpt: logging.error(str(excpt)) return False return True def __saveAsSVG(self, fileName): """Saves the flowchart as an SVG file""" generator = QSvgGenerator() generator.setFileName(fileName) generator.setSize(QSize(self.scene().width(), self.scene().height())) painter = QPainter(generator) self.scene().render(painter) painter.end() def onSaveAsPDF(self): """Triggered on the 'Save as PDF' button""" fileName = self.__selectFile("pdf") if fileName is None: return False try: self.__saveAsPDF(fileName) except Exception as excpt: logging.error(str(excpt)) return False return True def __saveAsPDF(self, fileName): """Saves the flowchart as an PDF file""" printer = QPrinter() printer.setOutputFormat(QPrinter.PdfFormat) printer.setPaperSize(QSizeF(self.scene().width(), self.scene().height()), QPrinter.Point) printer.setFullPage(True) printer.setOutputFileName(fileName) painter = QPainter(printer) self.scene().render(painter) painter.end() def onSaveAsPNG(self): """Triggered on the 'Save as PNG' button""" fileName = self.__selectFile("png") if fileName is None: return False try: self.__saveAsPNG(fileName) except Exception as excpt: logging.error(str(excpt)) return False return True def __getPNG(self): """Renders the scene as PNG""" image = QImage(self.scene().width(), self.scene().height(), QImage.Format_ARGB32_Premultiplied) painter = QPainter(image) # It seems that the better results are without antialiasing # painter.setRenderHint( QPainter.Antialiasing ) self.scene().render(painter) painter.end() return image def __saveAsPNG(self, fileName): """Saves the flowchart as an PNG file""" image = self.__getPNG() image.save(fileName, "PNG") def copyToClipboard(self): """Copies the rendered scene to the clipboard as an image""" image = self.__getPNG() clip = QApplication.clipboard() clip.setImage(image) def getScrollbarPositions(self): """Provides the scrollbar positions""" hScrollBar = self.view().horizontalScrollBar() vScrollBar = self.view().verticalScrollBar() return hScrollBar.value(), vScrollBar.value() def setScrollbarPositions(self, hPos, vPos): """Sets the scrollbar positions for the view""" self.view().horizontalScrollBar().setValue(hPos) self.view().verticalScrollBar().setValue(vPos) def __onHideDocstrings(self): """Triggered when a hide docstring button is pressed""" Settings()['hidedocstrings'] = not Settings()['hidedocstrings'] def __onHideDocstringsChanged(self): """Signalled by settings""" selection = self.scene().serializeSelection() firstOnScreen = self.scene().getFirstLogicalItem() settings = Settings() self.__hideDocstrings.setChecked(settings['hidedocstrings']) if self.__checkNeedRedraw(): self.scene().restoreSelectionByID(selection) self.__restoreScroll(firstOnScreen) def __onHideComments(self): """Triggered when a hide comments button is pressed""" Settings()['hidecomments'] = not Settings()['hidecomments'] def __onHideCommentsChanged(self): """Signalled by settings""" selection = self.scene().serializeSelection() firstOnScreen = self.scene().getFirstLogicalItem() settings = Settings() self.__hideComments.setChecked(settings['hidecomments']) if self.__checkNeedRedraw(): self.scene().restoreSelectionByID(selection) self.__restoreScroll(firstOnScreen) def __onHideExcepts(self): """Triggered when a hide except blocks button is pressed""" Settings()['hideexcepts'] = not Settings()['hideexcepts'] def __onHideExceptsChanged(self): """Signalled by settings""" selection = self.scene().serializeSelection() firstOnScreen = self.scene().getFirstLogicalItem() settings = Settings() self.__hideExcepts.setChecked(settings['hideexcepts']) if self.__checkNeedRedraw(): self.scene().restoreSelectionByTooltip(selection) self.__restoreScroll(firstOnScreen) def __checkNeedRedraw(self): """Redraws the scene if necessary when a display setting is changed""" editorsManager = self.__mainWindow.editorsManagerWidget.editorsManager if self.__parentWidget == editorsManager.currentWidget(): self.updateNavigationToolbar('') self.process() return True return False def dirty(self): """True if some other tab has switched display settings""" settings = Settings() return self.__displayProps[0] != settings['hidedocstrings'] or \ self.__displayProps[1] != settings['hidecomments'] or \ self.__displayProps[2] != settings['hideexcepts'] or \ self.__displayProps[3] != settings['smartZoom'] def onSmartZoomLevelUp(self): """Triggered when an upper smart zoom level was requested""" Settings().onSmartZoomIn() def onSmartZoomLevelDown(self): """Triggered when an lower smart zoom level was requested""" Settings().onSmartZoomOut() def setSmartZoomLevel(self, smartZoomLevel): """Sets the new smart zoom level""" maxSmartZoom = Settings().MAX_SMART_ZOOM if smartZoomLevel < 0 or smartZoomLevel > maxSmartZoom: return self.__levelIndicator.setText('<b>' + str(smartZoomLevel) + '</b>') self.__levelIndicator.setToolTip( getSmartZoomDescription(smartZoomLevel)) self.__levelUpButton.setEnabled(smartZoomLevel < maxSmartZoom) self.__levelDownButton.setEnabled(smartZoomLevel > 0) self.smartViews.setCurrentIndex(smartZoomLevel) def __onSmartZoomChanged(self): """Triggered when a smart zoom changed""" selection = self.scene().serializeSelection() firstOnScreen = self.scene().getFirstLogicalItem() self.setSmartZoomLevel(Settings()['smartZoom']) if self.__checkNeedRedraw(): self.scene().restoreSelectionByTooltip(selection) self.__restoreScroll(firstOnScreen) def __restoreScroll(self, toItem): """Restores the view scrolling to the best possible position""" if toItem: lineRange = toItem.getLineRange() absPosRange = toItem.getAbsPosRange() item, _ = self.scene().getNearestItem(absPosRange[0], lineRange[0], 0) if item: self.view().scrollTo(item, True) self.view().horizontalScrollBar().setValue(0) def validateCollapsedGroups(self, fileName): """Checks that there are no collapsed groups which are invalid""" if self.__navBar.getCurrentState() != self.__navBar.STATE_OK_UTD: return collapsedGroups = getCollapsedGroups(fileName) if collapsedGroups: toBeDeleted = [] for groupId in collapsedGroups: for validId, start, end in self.__validGroups: del start del end if validId == groupId: break else: toBeDeleted.append(groupId) if toBeDeleted: for groupId in toBeDeleted: collapsedGroups.remove(groupId) setCollapsedGroups(fileName, collapsedGroups) else: setCollapsedGroups(fileName, []) def getDocItemByAnchor(self, anchor): """Provides the graphics item for the given anchor if so""" return self.scene().getDocItemByAnchor(anchor) @staticmethod def isDebugMode(): """True if it is a debug mode""" return GlobalData().skin['debug']
class ControlFlowNavigationBar(QFrame): """Navigation bar at the top of the flow UI widget""" STATE_OK_UTD = 0 # Parsed OK, control flow up to date STATE_OK_CHN = 1 # Parsed OK, control flow changed STATE_BROKEN_UTD = 2 # Parsed with errors, control flow up to date STATE_BROKEN_CHN = 3 # Parsed with errors, control flow changed STATE_UNKNOWN = 4 def __init__(self, parent): QFrame.__init__(self, parent) self.__infoIcon = None self.__warningsIcon = None self.__layout = None self.__pathLabel = None self.__createLayout() self.__currentIconState = self.STATE_UNKNOWN def __createLayout(self): """Creates the layout""" self.__layout = QHBoxLayout(self) self.__layout.setContentsMargins(0, 0, 0, 0) # Create info icon self.__infoIcon = QLabel(self) self.__infoIcon.setPixmap(getPixmap('cfunknown.png')) self.__layout.addWidget(self.__infoIcon) self.__warningsIcon = QLabel(self) self.__warningsIcon.setPixmap(getPixmap('cfwarning.png')) self.__layout.addWidget(self.__warningsIcon) self.clearWarnings() # Create the path label self.__pathLabel = HeaderFitLabel(self) self.__pathLabel.setTextFormat(Qt.PlainText) self.__pathLabel.setAlignment(Qt.AlignLeft) self.__pathLabel.setWordWrap(False) self.__pathLabel.setTextInteractionFlags(Qt.NoTextInteraction) self.__pathLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.__pathLabel.setMinimumWidth(40) self.__layout.addWidget(self.__pathLabel) self.__spacer = ToolBarExpandingSpacer(self) self.__spacer.setMinimumWidth(0) self.__layout.addWidget(self.__spacer) # Create the selection label self.__selectionLabel = HeaderLabel('', None, self) self.__selectionLabel.setTextFormat(Qt.PlainText) self.__selectionLabel.setAlignment(Qt.AlignCenter) self.__selectionLabel.setWordWrap(False) self.__selectionLabel.setTextInteractionFlags(Qt.NoTextInteraction) self.__selectionLabel.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.__selectionLabel.setMinimumWidth(40) self.__layout.addWidget(self.__selectionLabel) self.setSelectionLabel(0, None) def clearWarnings(self): """Clears the warnings""" self.__warningsIcon.setVisible(False) self.__warningsIcon.setToolTip("") def setWarnings(self, warnings): """Sets the warnings""" self.__warningsIcon.setToolTip('Control flow parser warnings:\n' + '\n'.join(warnings)) self.__warningsIcon.setVisible(True) def clearErrors(self): """Clears all the errors""" self.__infoIcon.setToolTip('') def setErrors(self, errors): """Sets the errors""" self.__infoIcon.setToolTip('Control flow parser errors:\n' + '\n'.join(errors)) def updateInfoIcon(self, state): """Updates the information icon""" if state == self.__currentIconState: return if state == self.STATE_OK_UTD: self.__infoIcon.setPixmap(getPixmap('cfokutd.png')) self.__infoIcon.setToolTip("Control flow is up to date") self.__currentIconState = self.STATE_OK_UTD elif state == self.STATE_OK_CHN: self.__infoIcon.setPixmap(getPixmap('cfokchn.png')) self.__infoIcon.setToolTip("Control flow is not up to date; " "will be updated on idle") self.__currentIconState = self.STATE_OK_CHN elif state == self.STATE_BROKEN_UTD: self.__infoIcon.setPixmap(getPixmap('cfbrokenutd.png')) self.__infoIcon.setToolTip("Control flow might be invalid " "due to invalid python code") self.__currentIconState = self.STATE_BROKEN_UTD elif state == self.STATE_BROKEN_CHN: self.__infoIcon.setPixmap(getPixmap('cfbrokenchn.png')) self.__infoIcon.setToolTip("Control flow might be invalid; " "will be updated on idle") self.__currentIconState = self.STATE_BROKEN_CHN else: # STATE_UNKNOWN self.__infoIcon.setPixmap(getPixmap('cfunknown.png')) self.__infoIcon.setToolTip("Control flow state is unknown") self.__currentIconState = self.STATE_UNKNOWN def getCurrentState(self): """Provides the current state""" return self.__currentIconState def setPath(self, txt): """Sets the path label content""" self.__pathLabel.setText(txt) def setPathVisible(self, switchOn): """Sets the path visible""" self.__pathLabel.setVisible(switchOn) self.__spacer.setVisible(not switchOn) def setSelectionLabel(self, text, tooltip): """Sets selection label""" self.__selectionLabel.setText(str(text)) if tooltip: self.__selectionLabel.setToolTip("Selected items:\n" + str(tooltip)) else: self.__selectionLabel.setToolTip("Number of selected items") def resizeEvent(self, event): """Editor has resized""" QFrame.resizeEvent(self, event)
class NotUsedAnalysisProgress(QDialog): """Progress of the not used analysis""" def __init__(self, path, newSearch=True): QDialog.__init__(self, GlobalData().mainWindow) path = os.path.abspath(path) if not os.path.exists(path): raise Exception('Dead code analysis path must exist. ' 'The provide path "' + path + '" does not.') self.__path = path self.__newSearch = newSearch self.candidates = None self.__cancelRequest = False self.__inProgress = False self.__infoLabel = None self.__foundLabel = None self.__found = 0 # Number of found self.__createLayout() title = 'Dead code analysis for ' if os.path.isdir(path): project = GlobalData().project if project.isLoaded() and project.getProjectDir() == path: title += 'all project files' else: title += 'dir ' + os.path.basename(os.path.normpath(path)) else: title += os.path.basename(path) if not self.__newSearch: title += ' (do again)' self.setWindowTitle(title) self.__updateFoundLabel() def exec_(self): """Executes the dialog""" QTimer.singleShot(1, self.__process) QDialog.exec_(self) def keyPressEvent(self, event): """Processes the ESC key specifically""" if event.key() == Qt.Key_Escape: self.__onClose() else: QDialog.keyPressEvent(self, event) def __updateFoundLabel(self): """Updates the found label""" text = "Found: " + str(self.__found) + " candidate" if self.__found != 1: text += "s" self.__foundLabel.setText(text) 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) # 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) def __onClose(self): """triggered when the close button is clicked""" self.__cancelRequest = True if not self.__inProgress: self.close() def __run(self): """Runs vulture""" errTmp = tempfile.mkstemp() errStream = os.fdopen(errTmp[0]) process = Popen(['vulture', self.__path], stdin=PIPE, stdout=PIPE, stderr=errStream) process.stdin.close() processStdout = process.stdout.read() process.stdout.close() errStream.seek(0) err = errStream.read() errStream.close() process.wait() try: os.unlink(errTmp[1]) except: pass return processStdout.decode(DEFAULT_ENCODING), err.strip() def __process(self): """Analysis process""" self.__inProgress = True mainWindow = GlobalData().mainWindow QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) # return code gives really nothing. So the error in running the utility # is detected by the stderr content. # Also, there could be a mix of messages for a project. Some files # could have syntax errors - there will be messages on stderr. The # other files are fine so there will be messages on stdout stdout, stderr = self.__run() self.candidates = [] for line in stdout.splitlines(): line = line.strip() if line: # Line is like file.py:2: unused variable 'a' (60% confidence) try: startIndex = line.find(':') if startIndex < 0: continue endIndex = line.find(':', startIndex + 1) if endIndex < 0: continue fileName = line[:startIndex] startIndex = line.find(':') if startIndex < 0: continue endIndex = line.find(':', startIndex + 1) if endIndex < 0: continue fileName = os.path.abspath(line[:startIndex]) lineno = int(line[startIndex + 1:endIndex]) message = line[endIndex + 1:].strip() except: continue index = getSearchItemIndex(self.candidates, fileName) if index < 0: widget = mainWindow.getWidgetForFileName(fileName) if widget is None: uuid = '' else: uuid = widget.getUUID() newItem = ItemToSearchIn(fileName, uuid) self.candidates.append(newItem) index = len(self.candidates) - 1 self.candidates[index].addMatch('', lineno, message) self.__found += 1 self.__updateFoundLabel() QApplication.processEvents() if self.__newSearch: # Do the action only for the new search. # Redo action will handle the results on its own if self.__found == 0: if stderr: logging.error('Error running vulture for ' + self.__path + ':\n' + stderr) else: logging.info('No unused candidates found') else: mainWindow.displayFindInFiles(VultureSearchProvider.getName(), self.candidates, {'path': self.__path}) QApplication.restoreOverrideCursor() self.__infoLabel.setText('Done') self.__inProgress = False self.accept()