URI: 
       tqt plugins dialog: fix caching "settings" button - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 4d8fcded4b42fd673bbb61f85aa99dc329be28a4
   DIR parent ac63444cfc7c7bca6c4b2a670da435e9b109269e
  HTML 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:
         M electrum/gui/qt/main_window.py      |      16 ++++++++++------
         M electrum/plugin.py                  |      22 +++++++++++++---------
       
       2 files changed, 23 insertions(+), 15 deletions(-)
       ---
   DIR diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py
       t@@ -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,
       t@@ -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)
   DIR diff --git a/electrum/plugin.py b/electrum/plugin.py
       t@@ -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__)
       t@@ -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}'
       t@@ -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:
       t@@ -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
       t@@ -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 = []
       t@@ -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):
       t@@ -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