From 0b09592ef1662501c9f940b770cd50954bcc55e3 Mon Sep 17 00:00:00 2001 From: Sander van Grieken Date: Sat, 14 Sep 2024 11:12:42 +0200 Subject: [PATCH] qt: move query_choice to MessageBoxMixin, document ChoiceWidget --- electrum/gui/qt/main_window.py | 22 +++---------------- electrum/gui/qt/util.py | 37 ++++++++++++++++++++++++++++---- electrum/gui/qt/wizard/wallet.py | 16 -------------- electrum/plugins/hw_wallet/qt.py | 6 +++--- 4 files changed, 39 insertions(+), 42 deletions(-) diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py index 0e5eb01be..9b8f7b4fb 100644 --- a/electrum/gui/qt/main_window.py +++ b/electrum/gui/qt/main_window.py @@ -34,7 +34,7 @@ import base64 from functools import partial import queue import asyncio -from typing import Optional, TYPE_CHECKING, Sequence, List, Union, Dict, Set, Mapping +from typing import Optional, TYPE_CHECKING, Sequence, Union, Dict, Mapping import concurrent.futures from PyQt5.QtGui import QPixmap, QKeySequence, QIcon, QCursor, QFont, QFontMetrics @@ -45,7 +45,7 @@ from PyQt5.QtWidgets import (QMessageBox, QSystemTrayIcon, QTabWidget, QHBoxLayout, QPushButton, QScrollArea, QTextEdit, QShortcut, QMainWindow, QInputDialog, QWidget, QSizePolicy, QStatusBar, QToolTip, - QMenu, QAction, QStackedWidget, QToolButton) + QMenu, QAction, QToolButton) import electrum from electrum.gui import messages @@ -88,7 +88,7 @@ from .util import (read_QIcon, ColorScheme, text_dialog, icon_path, WaitingDialo import_meta_gui, export_meta_gui, filename_field, address_field, char_width_in_lineedit, webopen, TRANSACTION_FILE_EXTENSION_FILTER_ANY, MONOSPACE_FONT, - getOpenFileName, getSaveFileName, BlockingWaitingDialog, font_height, ChoiceWidget) + getOpenFileName, getSaveFileName, BlockingWaitingDialog, font_height) from .util import ButtonsLineEdit, ShowQRLineEdit from .util import QtEventListener, qt_event_listener, event_listener from .wizard.wallet import WIF_HELP_TEXT @@ -1370,22 +1370,6 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener): else: self.show_message(message) - def query_choice(self, msg, choices, title=None, default_choice=None): - # Needed by QtHandler for hardware wallets - if title is None: - title = _('Question') - dialog = WindowModalDialog(self.top_level_window(), title=title) - dialog.setMinimumWidth(400) - choice_widget = ChoiceWidget(message=msg, choices=choices, selected=default_choice) - vbox = QVBoxLayout(dialog) - vbox.addWidget(choice_widget) - cancel_button = CancelButton(dialog) - vbox.addLayout(Buttons(cancel_button, OkButton(dialog))) - cancel_button.setFocus() - if not dialog.exec_(): - return None - return choice_widget.selected_key - def handle_payment_identifier(self, text: str): pi = PaymentIdentifier(self.wallet, text) if pi.is_valid(): diff --git a/electrum/gui/qt/util.py b/electrum/gui/qt/util.py index a508d1a9e..27c38bf11 100644 --- a/electrum/gui/qt/util.py +++ b/electrum/gui/qt/util.py @@ -283,6 +283,26 @@ class MessageBoxMixin(object): rich_text=rich_text, checkbox=checkbox) + def query_choice(self, + msg: Optional[str], + choices: Sequence[Tuple], + title: Optional[str] = None, + default_choice: Optional[Any] = None) -> Optional[Any]: + # Needed by QtHandler for hardware wallets + if title is None: + title = _('Question') + dialog = WindowModalDialog(self.top_level_window(), title=title) + dialog.setMinimumWidth(400) + choice_widget = ChoiceWidget(message=msg, choices=choices, selected=default_choice) + vbox = QVBoxLayout(dialog) + vbox.addWidget(choice_widget) + cancel_button = CancelButton(dialog) + vbox.addLayout(Buttons(cancel_button, OkButton(dialog))) + cancel_button.setFocus() + if not dialog.exec_(): + return None + return choice_widget.selected_key + def custom_message_box(*, icon, parent, title, text, buttons=QMessageBox.Ok, defaultButton=QMessageBox.NoButton, rich_text=False, @@ -423,9 +443,18 @@ def text_dialog( class ChoiceWidget(QWidget): + """Renders a list of tuples as a radiobuttons group. + The first element of each tuple is used as a key. + The second element of each tuple is used as user facing string. + The remainder of the tuple can be any additional data. + Callers can pre-select an item by key, through the 'selected' parameter. + The selected item is made available by index (selected_index), + by key (selected_key) and by whole tuple (selected_item). + """ + itemSelected = pyqtSignal([int], arguments=['index']) - def __init__(self, *, message=None, choices=None, selected=None): + def __init__(self, *, message: Optional[str] = None, choices: Sequence[Tuple] = None, selected: Optional[Any] = None): QWidget.__init__(self) vbox = QVBoxLayout() self.setLayout(vbox) @@ -433,9 +462,9 @@ class ChoiceWidget(QWidget): if choices is None: choices = [] - self.selected_index = -1 - self.selected_item = None - self.selected_key = None + self.selected_index = -1 # int + self.selected_item = None # Optional[Tuple] + self.selected_key = None # Optional[Any] self.choices = choices diff --git a/electrum/gui/qt/wizard/wallet.py b/electrum/gui/qt/wizard/wallet.py index b4da6beb3..f39e96959 100644 --- a/electrum/gui/qt/wizard/wallet.py +++ b/electrum/gui/qt/wizard/wallet.py @@ -237,22 +237,6 @@ class QENewWalletWizard(NewWalletWizard, QEAbstractWizard, MessageBoxMixin): if on_finished: on_finished() - def query_choice(self, msg, choices, title=None, default_choice=None): - # Needed by QtHandler for hardware wallets - if title is None: - title = _('Question') - dialog = WindowModalDialog(self.top_level_window(), title=title) - dialog.setMinimumWidth(400) - choice_widget = ChoiceWidget(message=msg, choices=choices, selected=default_choice) - vbox = QVBoxLayout(dialog) - vbox.addWidget(choice_widget) - cancel_button = CancelButton(dialog) - vbox.addLayout(Buttons(cancel_button, OkButton(dialog))) - cancel_button.setFocus() - if not dialog.exec_(): - return None - return choice_widget.selected_key - class WalletWizardComponent(WizardComponent, ABC): # ^ this class only exists to help with typing diff --git a/electrum/plugins/hw_wallet/qt.py b/electrum/plugins/hw_wallet/qt.py index aedd16d61..9656019a0 100644 --- a/electrum/plugins/hw_wallet/qt.py +++ b/electrum/plugins/hw_wallet/qt.py @@ -26,7 +26,7 @@ import threading from functools import partial -from typing import TYPE_CHECKING, Union, Optional +from typing import TYPE_CHECKING, Union, Optional, Sequence, Tuple from PyQt5.QtCore import QObject, pyqtSignal, Qt from PyQt5.QtWidgets import QVBoxLayout, QLineEdit, QHBoxLayout, QLabel @@ -95,7 +95,7 @@ class QtHandlerBase(HardwareHandlerBase, QObject, Logger): icon_name = button.icon_paired if paired else button.icon_unpaired button.setIcon(read_QIcon(icon_name)) - def query_choice(self, msg, labels): + def query_choice(self, msg: str, labels: Sequence[Tuple]): self.done.clear() self.query_signal.emit(msg, labels) self.done.wait() @@ -194,7 +194,7 @@ class QtHandlerBase(HardwareHandlerBase, QObject, Logger): self.dialog.accept() self.dialog = None - def win_query_choice(self, msg, labels): + def win_query_choice(self, msg: str, labels: Sequence[Tuple]): try: self.choice = self.win.query_choice(msg, labels) except UserCancelled: