Example #1
0
class Variables(QWidget):
    changed = Signal(object)

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        self.setMinimumWidth(500)

        self.table = QTableWidget()
        self.table.setSelectionMode(QTableWidget.SingleSelection)
        self.table.itemChanged.connect(self._item_changed)
        self.table.currentItemChanged.connect(self._current_item_changed)
        self.table.horizontalHeader().hide()
        self.table.verticalHeader().hide()
        self.table.setColumnCount(3)
        self.table.horizontalHeader().resizeSection(0, 200)
        self.table.horizontalHeader().resizeSection(1, 200)
        self.table.horizontalHeader().resizeSection(2, 20)

        self.new = QPushButton('New variable')
        self.new.clicked.connect(self._new)

        self.color = Color()
        self.color.changed.connect(self._color_changed)

        layout = QGridLayout(self)
        layout.addWidget(self.table)
        layout.addWidget(self.color)
        layout.addWidget(self.new)

    @property
    def variables(self):
        variables = dict()

        for row_index in range(self.table.rowCount()):
            name = self.table.item(row_index, 0).text()
            value = self.table.item(row_index, 1).text()

            if value.startswith('[') and value.endswith(']'):
                value = eval(value)  # OULA LA

            variables[name] = value

        return variables

    @variables.setter
    def variables(self, variables):
        self.table.blockSignals(True)
        self.table.clear()
        for name, value in variables.items():
            self._add_row(name, value)

        self.table.blockSignals(False)
        self.changed.emit(variables)

    def _item_changed(self, item):
        self.changed.emit(self.variables)
        self._current_item_changed(item)

    def _current_item_changed(self, item):
        self.color.setEnabled(False)

        if item is None or item.column() != 1:
            return

        text = item.text().strip()
        if not (text.startswith('[') and text.endswith(']')):
            return

        r, g, b = [int(channel.strip()) for channel in text[1:-1].split(',')]

        self.color.blockSignals(True)
        self.color.set_rgb(r, g, b)
        self.color.setEnabled(True)
        self.color.blockSignals(False)

    def _color_changed(self, r, g, b):
        self.table.blockSignals(True)
        self.table.currentItem().setText('[{}, {}, {}]'.format(r, g, b))
        self.table.blockSignals(False)
        self.changed.emit(self.variables)

    def _add_row(self, name, value):
        row = self.table.rowCount()
        self.table.setRowCount(row + 1)

        name = QTableWidgetItem(name)
        value = QTableWidgetItem(str(value))

        delete = QPushButton("X")
        delete.name_item = name
        delete.clicked.connect(self._delete)

        self.table.blockSignals(True)
        self.table.setItem(row, 0, name)
        self.table.setItem(row, 1, value)
        self.table.setCellWidget(row, 2, delete)
        self.table.blockSignals(False)

    def _new(self):
        self._add_row('new_variable', '[255, 255, 255]')
        self.changed.emit(self.variables)

    def _delete(self):
        name_item = self.sender().name_item
        self.table.removeRow(name_item.row())

        self.changed.emit(self.variables)
class Linter(ToolInstance):
    """
    tool to run python linters on files
    the UI has a list of files, an option to choose
    the linter, and a button to run the linter
    results are printed to the log
    """
    def __init__(self, session, name):
        super().__init__(session, name)

        self.tool_window = MainToolWindow(self)
        self.settings = _LinterSettings(self.session, name)

        self._build_ui()

    def _build_ui(self):
        layout = QFormLayout()

        self.table = QTableWidget()
        self.table.setColumnCount(2)
        self.table.setHorizontalHeaderLabels(["file", "remove"])
        self.table.horizontalHeader().setStretchLastSection(False)
        self.table.horizontalHeader().setSectionResizeMode(
            0, QHeaderView.Stretch)
        self.table.horizontalHeader().setSectionResizeMode(
            1, QHeaderView.Fixed)
        self.table.cellClicked.connect(self.table_clicked)
        layout.addRow(self.table)

        self.linters = QComboBox()
        self.linters.addItems([
            "pyflakes",
            "flake8",
            "mypy",
            "pydocstyle",
            "pylint",
        ])
        ndx = self.linters.findText(self.settings.linter, Qt.MatchExactly)
        self.linters.setCurrentIndex(ndx)
        layout.addRow(self.linters)

        lint = QPushButton("run linter")
        lint.clicked.connect(self.run_linter)
        layout.addRow(lint)

        self.add_files(loads(self.settings.files))

        self.tool_window.ui_area.setLayout(layout)

        self.tool_window.manage(None)

    def table_clicked(self, row, column):
        """
        if the last row is clicked, open a file browser and add
        the files to the list
        otherwise, if the 2nd column is clicked (the trash can),
        remove that row
        """
        if row == self.table.rowCount() - 1 or self.table.rowCount() == 1:
            filenames = QFileDialog.getOpenFileNames(
                filter="Python Files (*.py)")
            if filenames[0]:
                self.table.setRowCount(self.table.rowCount() - 1)
                self.add_files(filenames[0])
        elif column == 1:
            self.table.removeRow(row)

    def add_files(self, filenames):
        """add filenames (list(str)) to the table"""
        for f in filenames:
            row = self.table.rowCount()
            self.table.insertRow(row)

            file_item = QTableWidgetItem()
            file_item.setData(Qt.DisplayRole, f)
            self.table.setItem(row, 0, file_item)

            widget_that_lets_me_horizontally_align_an_icon = QWidget()
            widget_layout = QHBoxLayout(
                widget_that_lets_me_horizontally_align_an_icon)
            section_remove = QLabel()
            dim = int(1.5 *
                      section_remove.fontMetrics().boundingRect("Z").height())
            section_remove.setPixmap(
                QIcon(section_remove.style().standardIcon(
                    QStyle.SP_DialogDiscardButton)).pixmap(dim, dim))
            widget_layout.addWidget(section_remove, 0, Qt.AlignHCenter)
            widget_layout.setContentsMargins(0, 0, 0, 0)
            self.table.setCellWidget(
                row, 1, widget_that_lets_me_horizontally_align_an_icon)

        self.add_last_row()

    def add_last_row(self):
        """add the "add files" button to the bottom of the table"""
        row = self.table.rowCount()
        self.table.insertRow(row)

        add_row = QTableWidgetItem()
        add_row.setData(Qt.DisplayRole, "add files")
        self.table.setItem(row, 0, add_row)

    def run_linter(self):
        """execute linter"""
        previous_files = []
        linter = self.linters.currentText()
        for row in range(0, self.table.rowCount() - 1):
            fname = self.table.item(row, 0).text()
            previous_files.append(fname)

            run(self.session, "linter \"%s\" linter %s" % (fname, linter))

        self.settings.files = dumps(previous_files)
        self.settings.linter = linter