electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit 4d8fcded4b42fd673bbb61f85aa99dc329be28a4
parent ac63444cfc7c7bca6c4b2a670da435e9b109269e
Author: SomberNight <somber.night@protonmail.com>
Date:   Tue, 26 May 2020 00:54:22 +0200

qt plugins dialog: fix caching "settings" button

shesek reported on IRC:
> the button widget for opening plugins configuration gets cached in `settings_widgets`
> even after the plugin is disabled and re-enabled, which causes it to call `settings_dialog()`
> on the previous plugin instance that got unloaded instead of the new one.

Diffstat:
Melectrum/gui/qt/main_window.py | 16++++++++++------
Melectrum/plugin.py | 22+++++++++++++---------
2 files changed, 23 insertions(+), 15 deletions(-)

diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py @@ -52,7 +52,7 @@ import electrum from electrum import (keystore, ecc, constants, util, bitcoin, commands, paymentrequest) from electrum.bitcoin import COIN, is_address -from electrum.plugin import run_hook +from electrum.plugin import run_hook, BasePlugin from electrum.i18n import _ from electrum.util import (format_time, format_satoshis, format_fee_satoshis, format_satoshis_plain, @@ -2939,13 +2939,17 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger): settings_widgets = {} - def enable_settings_widget(p, name, i): - widget = settings_widgets.get(name) - if not widget and p and p.requires_settings(): + def enable_settings_widget(p: Optional['BasePlugin'], name: str, i: int): + widget = settings_widgets.get(name) # type: Optional[QWidget] + if widget and not p: + # plugin got disabled, rm widget + grid.removeWidget(widget) + widget.setParent(None) + settings_widgets.pop(name) + elif widget is None and p and p.requires_settings() and p.is_enabled(): + # plugin got enabled, add widget widget = settings_widgets[name] = p.settings_widget(d) grid.addWidget(widget, i, 1) - if widget: - widget.setEnabled(bool(p and p.is_enabled())) def do_toggle(cb, name, i): p = plugins.toggle(name) diff --git a/electrum/plugin.py b/electrum/plugin.py @@ -43,6 +43,7 @@ from .logging import get_logger, Logger if TYPE_CHECKING: from .plugins.hw_wallet import HW_PluginBase, HardwareClientBase, HardwareHandlerBase from .keystore import Hardware_KeyStore + from .wallet import Abstract_Wallet _logger = get_logger(__name__) @@ -107,7 +108,7 @@ class Plugins(DaemonThread): def count(self): return len(self.plugins) - def load_plugin(self, name): + def load_plugin(self, name) -> 'BasePlugin': if name in self.plugins: return self.plugins[name] full_name = f'electrum.plugins.{name}.{self.gui_name}' @@ -129,14 +130,14 @@ class Plugins(DaemonThread): def close_plugin(self, plugin): self.remove_jobs(plugin.thread_jobs()) - def enable(self, name): + def enable(self, name: str) -> 'BasePlugin': self.config.set_key('use_' + name, True, True) p = self.get(name) if p: return p return self.load_plugin(name) - def disable(self, name): + def disable(self, name: str) -> None: self.config.set_key('use_' + name, False, True) p = self.get(name) if not p: @@ -145,11 +146,11 @@ class Plugins(DaemonThread): p.close() self.logger.info(f"closed {name}") - def toggle(self, name): + def toggle(self, name: str) -> Optional['BasePlugin']: p = self.get(name) return self.disable(name) if p else self.enable(name) - def is_available(self, name, w): + def is_available(self, name: str, wallet: 'Abstract_Wallet') -> bool: d = self.descriptions.get(name) if not d: return False @@ -161,7 +162,7 @@ class Plugins(DaemonThread): self.logger.warning(f'Plugin {name} unavailable: {repr(e)}') return False requires = d.get('requires_wallet_type', []) - return not requires or w.wallet_type in requires + return not requires or wallet.wallet_type in requires def get_hardware_support(self): out = [] @@ -270,7 +271,7 @@ class BasePlugin(Logger): def on_close(self): pass - def requires_settings(self): + def requires_settings(self) -> bool: return False def thread_jobs(self): @@ -285,8 +286,11 @@ class BasePlugin(Logger): def can_user_disable(self): return True - def settings_dialog(self): - pass + def settings_widget(self, window): + raise NotImplementedError() + + def settings_dialog(self, window): + raise NotImplementedError() class DeviceUnpairableError(UserFacingException): pass