Example #1
0
class AddAuthorized(QMainWindow):
    """
    This class represents window, to manage access rights.
    User can add specified accounts to a list, which will be passed to
    a smart contract.
    """
    def __init__(self, on_exit):
        super(AddAuthorized, self).__init__()
        self.on_exit = on_exit
        self.address_list = []

        self.resize(gc.ADD_AUTHORIZED_WIDTH, gc.ADD_AUTHORIZED_HEIGHT)

        self.address = QLineEdit(self)
        self.address.resize(QSize(300, 30))
        self.address.move(MARGIN, 0)

        self.add = QPushButton(self)
        self.add.resize(QSize(self.add.width(), 30))
        self.add.setText("Add")
        self.add.clicked.connect(self.add_address)
        self.add.move(self.address.width() + 2 * MARGIN, 0)

        self.list = QListWidget(self)
        self.list.resize(
            QSize(self.address.width() + self.add.width() + MARGIN, 100))
        self.list.move(MARGIN, self.add.height() + MARGIN)

        self.checkbox = QCheckBox(self)
        self.checkbox.move(MARGIN, self.list.pos().y() + self.list.height())
        self.checkbox.setChecked(True)

        self.include_me = QLabel(self)
        self.include_me.setText("Include me")
        self.include_me.move(self.checkbox.pos().x() + 2 * MARGIN,
                             self.checkbox.pos().y())

        self.ok = QPushButton(self)
        self.ok.setText("OK")
        self.ok.clicked.connect(self.exit)
        self.ok.move(self.width() / 2 - self.ok.width() / 2,
                     self.address.height() + self.list.height() + 3 * MARGIN)

    def add_address(self):
        address = self.address.text().strip()
        if BlockchainDB.is_address_valid(address):
            self.list.addItem(address)
            self.address_list.append(address)
        else:
            self.warning_box = QMessageBox()
            self.warning_box.setIcon(QMessageBox.Warning)
            self.warning_box.setStandardButtons(QMessageBox.Ok)
            self.warning_box.setText("Address is ill-formed")
            self.warning_box.setWindowTitle("Invalid address")
            self.warning_box.exec()

    def exit(self):
        self.close()
        self.on_exit(self.address_list, self.checkbox.isChecked())
class MultiSelectComboBox(QComboBox):
    search_bar_index = 0

    updated = pyqtSignal()

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

        self.list_widget = QListWidget(self)
        self.line_edit = QLineEdit(self)
        self.search_bar = QLineEdit(self)

        current_item = QListWidgetItem(self.list_widget)
        self.search_bar.setPlaceholderText("Search...")
        self.search_bar.setClearButtonEnabled(True)
        # First item in the list is the SEARCH BAR
        self.list_widget.addItem(current_item)
        self.list_widget.setItemWidget(current_item, self.search_bar)

        self.line_edit.setReadOnly(True)
        self.line_edit.installEventFilter(self)

        self.setModel(self.list_widget.model())
        self.setView(self.list_widget)
        self.setLineEdit(self.line_edit)

        self.search_bar.textChanged.connect(self.onSearch)
        self.activated.connect(self.itemClicked)

    def hidePopup(self):
        width = self.width()
        height = self.list_widget.height()
        x = QCursor.pos().x() - self.mapToGlobal(
            self.geometry().topLeft()).x() + self.geometry().x()
        y = QCursor.pos().y() - self.mapToGlobal(
            self.geometry().topLeft()).y() + self.geometry().y()

        if x >= 0 and x <= width and y >= self.height(
        ) and y <= height + self.height():
            pass  # Item was clicked do not hide popup
        else:
            super().hidePopup()

    def stateChanged(self, state=None):
        # state is unused
        selected_data = []
        count = self.list_widget.count()

        for i in range(1, count):
            check_box = self.list_widget.itemWidget(self.list_widget.item(i))
            if check_box.isChecked():
                selected_data.append(check_box.text())

        if selected_data:
            self.line_edit.setText(', '.join(selected_data))
        else:
            self.line_edit.clear()
        self.updated.emit()

    def addItem(self, text, user_data=None):
        # user_data is unused
        list_widget_item = QListWidgetItem(self.list_widget)
        check_box = QCheckBox(self)
        check_box.setText(text)
        self.list_widget.addItem(list_widget_item)
        self.list_widget.setItemWidget(list_widget_item, check_box)
        check_box.stateChanged.connect(self.stateChanged)

    def currentText(self):
        if self.line_edit.text():
            return [_.strip() for _ in self.line_edit.text().split(",")]
        return []

    def addItems(self, texts):
        for s in texts:
            self.addItem(s)

    def count(self):
        return max(0,
                   self.list_widget.count() - 1)  # Do not count the search bar

    def onSearch(self, s):
        for i in range(self.list_widget.count()):
            check_box = self.list_widget.itemWidget(self.list_widget.item(i))
            if s.lower() in check_box.text().lower():
                self.list_widget.item(i).setHidden(False)
            else:
                self.list_widget.item(i).setHidden(True)

    def itemClicked(self, index):
        if index != self.search_bar_index:
            check_box = self.list_widget.itemWidget(
                self.list_widget.item(index))
            check_box.setChecked(not check_box.isChecked())

    def setSearchBarPlaceholderText(self, placeholder_text):
        self.search_bar.setPlaceholderText(placeholder_text)

    def setPlaceholderText(self, placeholder_text):
        self.line_edit.setPlaceholderText(placeholder_text)

    def clear(self):
        self.list_widget.clear()
        current_item = QListWidgetItem(self.list_widget)
        self.search_bar = QLineEdit(self)
        self.search_bar.setPlaceholderText("Search...")
        self.search_bar.setClearButtonEnabled(True)
        self.list_widget.addItem(current_item)
        self.list_widget.setItemWidget(current_item, self.search_bar)

        self.search_bar.textChanged.connect(self.onSearch)

    def wheelEvent(self, wheel_event):
        pass  # Do not handle the wheel event

    def setCurrentText(self, text):
        pass

    def setCurrentTexts(self, texts):
        count = self.list_widget.count()

        for i in range(1, count):
            check_box = self.list_widget.itemWidget(self.list_widget.item(i))
            check_box_string = check_box.text()
            if check_box_string in texts:
                check_box.setChecked(True)

    def ResetSelection(self):
        count = self.list_widget.count()

        for i in range(1, count):
            check_box = self.list_widget.itemWidget(self.list_widget.item(i))
            check_box.setChecked(False)
Example #3
0
class TabBase(QWidget):
    def __init__(self, parent, category):
        super().__init__(parent)
        self.category = category
        self.app = parent.app
        self.status_bar = parent.status_bar
        self._measures = {
            name: {
                "measure": measure,
                "url": QUrl(measure.description()),
            }
            for name, measure in self.collect_measures()
        }

        self.descripion_browser = QWebEngineView()
        useragent = self.descripion_browser.page().profile().httpUserAgent()
        self.descripion_browser.page().profile().setHttpUserAgent(
            f"{useragent} FRDS")
        self.descripion_browser.setZoomFactor(0.75)

        layout = QVBoxLayout()

        # Control button
        self.all_measures_btn = QCheckBox("All Measures")
        self.all_measures_btn.setCheckState(Qt.Checked)
        self.start_btn = QPushButton("Start")
        (ctrl_layout := QHBoxLayout()).addWidget(self.start_btn)
        # Measure selection
        self.list_of_measures = QListWidget()
        self.measure_selection = self.create_measure_selection_layout()
        # Description and measure params
        self.measure_params = self.create_measure_params_widget()
        measure_selection_and_params = QGridLayout()
        measure_selection_and_params.addWidget(self.measure_selection, 1, 1, 1,
                                               1)
        measure_selection_and_params.addWidget(self.measure_params, 1, 2, 1, 2)

        layout.addLayout(measure_selection_and_params)
        layout.addLayout(ctrl_layout)
        self.setLayout(layout)

        # Connect
        self.start_btn.clicked.connect(self.on_start_btn_clicked)
        self.all_measures_btn.clicked.connect(self.on_all_measures_btn_clicked)

    def collect_measures(self):
        for name, measure in inspect.getmembers(frds.measures,
                                                inspect.isclass):
            if (not inspect.isabstract(measure)
                    and hasattr(measure, "category")
                    and measure.category() is self.category):
                yield name, measure

    def on_all_measures_btn_clicked(self) -> None:
        """Select and deselect all measures"""
        checked = self.all_measures_btn.isChecked()
        for i in range(self.list_of_measures.count()):
            item = self.list_of_measures.item(i)
            item.setCheckState(Qt.Checked if checked else Qt.Unchecked)

    def create_measure_params_widget(self) -> QGroupBox:
        layout = QVBoxLayout()
        layout.addWidget(self.descripion_browser)
        measures_params = QGroupBox("Description")
        measures_params.setLayout(layout)
        return measures_params

    def create_measure_selection_layout(self) -> QGroupBox:
        layout = QVBoxLayout()
        layout.addWidget(self.all_measures_btn)
        for name, _ in self.collect_measures():
            self.list_of_measures.addItem(name)
        h = self.list_of_measures.height()
        for i in range(self.list_of_measures.count()):
            item = self.list_of_measures.item(i)
            item.setSizeHint(QSize(0, int(h / 20)))
            item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
            item.setCheckState(Qt.Checked)
        self.list_of_measures.itemPressed.connect(self.on_measure_selected)
        layout.addWidget(self.list_of_measures)
        measure_selection = QGroupBox("Measures")
        measure_selection.setLayout(layout)
        measure_selection.setMaximumWidth(MAIN_WINDOW_WIDTH // 3 - 20)
        measure_selection.setMinimumHeight(int(MAIN_WINDOW_HEIGHT * 0.7))
        return measure_selection

    def on_measure_selected(self, item: QListWidgetItem) -> None:
        measure_name = item.text()
        url = self._measures.get(measure_name).get("url")
        self.descripion_browser.setUrl(url)

    def on_start_btn_clicked(self) -> None:
        """Start running estimation"""
        self.app.stopped = False
        self.measure_selection.setDisabled(True)
        self.start_btn.setDisabled(True)
        self.start_btn.setText("Running")
        measures_to_estimate = []
        for i in range(self.list_of_measures.count()):
            item = self.list_of_measures.item(i)
            if item.checkState() == Qt.Checked:
                measures_to_estimate.append(item.text())
        worker = Worker(
            frds.run.main,
            measures_to_estimate=measures_to_estimate,
            gui=True,
        )
        worker.signals.finished.connect(self.on_completed)
        worker.signals.progress.connect(self.update_progress)
        worker.signals.error.connect(self.update_progress)
        self.app.threadpool.start(worker)

    def on_completed(self) -> None:
        """Callback when estimation is completed"""
        self.measure_selection.setDisabled(False)
        self.start_btn.setDisabled(False)
        self.start_btn.setText("Start")

    def update_progress(self, msg: str) -> None:
        """Update progress"""
        self.status_bar.showMessage(msg)