URI: 
       tqt coin selection: allow selecting an empty set - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 6f246a83b307a63b80b0d98c1f0f3c606e45170a
   DIR parent 11f54aee60d6de3413812318b8cc826365a43051
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Thu, 21 Nov 2019 17:46:00 +0100
       
       qt coin selection: allow selecting an empty set
       
       Using this, the user can force "bump fee" not to add new inputs.
       
       closes #5719
       
       Diffstat:
         M electrum/gui/qt/main_window.py      |      15 +++++++++++----
         M electrum/gui/qt/transaction_dialog… |       6 +++---
         M electrum/gui/qt/utxo_list.py        |      49 ++++++++++++++++++-------------
       
       3 files changed, 42 insertions(+), 28 deletions(-)
       ---
   DIR diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py
       t@@ -1475,11 +1475,18 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
                else:
                    raise Exception('unknown invoice type')
        
       -    def get_coins(self, *, nonlocal_only=False):
       +    def get_coins(self, *, nonlocal_only=False) -> Sequence[PartialTxInput]:
                coins = self.get_manually_selected_coins()
       -        return coins or self.wallet.get_spendable_coins(None, nonlocal_only=nonlocal_only)
       +        if coins is not None:
       +            return coins
       +        else:
       +            return self.wallet.get_spendable_coins(None, nonlocal_only=nonlocal_only)
        
       -    def get_manually_selected_coins(self) -> Sequence[PartialTxInput]:
       +    def get_manually_selected_coins(self) -> Optional[Sequence[PartialTxInput]]:
       +        """Return a list of selected coins or None.
       +        Note: None means selection is not being used,
       +              while an empty sequence means the user specifically selected that.
       +        """
                return self.utxo_list.get_spend_list()
        
            def pay_onchain_dialog(self, inputs: Sequence[PartialTxInput],
       t@@ -2009,7 +2016,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
                self.coincontrol_label.setTextInteractionFlags(Qt.TextSelectableByMouse)
                sb.addWidget(self.coincontrol_label)
        
       -        clear_cc_button = EnterButton(_('Reset'), lambda: self.utxo_list.set_spend_list([]))
       +        clear_cc_button = EnterButton(_('Reset'), lambda: self.utxo_list.set_spend_list(None))
                clear_cc_button.setStyleSheet("margin-right: 5px;")
                sb.addPermanentWidget(clear_cc_button)
        
   DIR diff --git a/electrum/gui/qt/transaction_dialog.py b/electrum/gui/qt/transaction_dialog.py
       t@@ -450,9 +450,9 @@ class BaseTxDialog(QDialog, MessageBoxMixin):
            def update_io(self):
                inputs_header_text = _("Inputs") + ' (%d)'%len(self.tx.inputs())
                if not self.finalized:
       -            num_utxos = len(self.main_window.get_manually_selected_coins())
       -            if num_utxos > 0:
       -                inputs_header_text += f"  -  " + _("Coin selection active ({} UTXOs selected)").format(num_utxos)
       +            selected_coins = self.main_window.get_manually_selected_coins()
       +            if selected_coins is not None:
       +                inputs_header_text += f"  -  " + _("Coin selection active ({} UTXOs selected)").format(len(selected_coins))
                self.inputs_header.setText(inputs_header_text)
                ext = QTextCharFormat()
                rec = QTextCharFormat()
   DIR diff --git a/electrum/gui/qt/utxo_list.py b/electrum/gui/qt/utxo_list.py
       t@@ -58,7 +58,7 @@ class UTXOList(MyTreeView):
                super().__init__(parent, self.create_menu,
                                 stretch_column=self.Columns.LABEL,
                                 editable_columns=[])
       -        self._spend_set = set()  # type: Set[str]  # coins selected by the user to spend from
       +        self._spend_set = None  # type: Optional[Set[str]]  # coins selected by the user to spend from
                self.setModel(QStandardItemModel(self))
                self.setSelectionMode(QAbstractItemView.ExtendedSelection)
                self.setSortingEnabled(True)
       t@@ -75,12 +75,12 @@ class UTXOList(MyTreeView):
                    self.insert_utxo(idx, utxo)
                self.filter()
                # update coincontrol status bar
       -        coins = [self.utxo_dict[x] for x in self._spend_set] or utxos
       -        coins = self._filter_frozen_coins(coins)
       -        amount = sum(x.value_sats() for x in coins)
       -        amount_str = self.parent.format_amount_and_units(amount)
       -        num_outputs_str = _("{} outputs available ({} total)").format(len(coins), len(utxos))
       -        if self._spend_set:
       +        if self._spend_set is not None:
       +            coins = [self.utxo_dict[x] for x in self._spend_set]
       +            coins = self._filter_frozen_coins(coins)
       +            amount = sum(x.value_sats() for x in coins)
       +            amount_str = self.parent.format_amount_and_units(amount)
       +            num_outputs_str = _("{} outputs available ({} total)").format(len(coins), len(utxos))
                    self.parent.set_coincontrol_msg(_("Coin control active") + f': {num_outputs_str}, {amount_str}')
                else:
                    self.parent.set_coincontrol_msg(None)
       t@@ -101,7 +101,7 @@ class UTXOList(MyTreeView):
                utxo_item[self.Columns.OUTPOINT].setFont(QFont(MONOSPACE_FONT))
                utxo_item[self.Columns.ADDRESS].setData(name, Qt.UserRole)
                SELECTED_TO_SPEND_TOOLTIP = _('Coin selected to be spent')
       -        if name in self._spend_set:
       +        if name in (self._spend_set or set()):
                    for col in utxo_item:
                        col.setBackground(ColorScheme.GREEN.as_color(True))
                        if col != self.Columns.OUTPOINT:
       t@@ -113,7 +113,7 @@ class UTXOList(MyTreeView):
                    utxo_item[self.Columns.OUTPOINT].setBackground(ColorScheme.BLUE.as_color(True))
                    utxo_item[self.Columns.OUTPOINT].setToolTip(f"{name}\n{_('Coin is frozen')}")
                else:
       -            tooltip = ("\n" + SELECTED_TO_SPEND_TOOLTIP) if name in self._spend_set else ""
       +            tooltip = ("\n" + SELECTED_TO_SPEND_TOOLTIP) if name in (self._spend_set or set()) else ""
                    utxo_item[self.Columns.OUTPOINT].setToolTip(name + tooltip)
                self.model().insertRow(idx, utxo_item)
        
       t@@ -121,8 +121,6 @@ class UTXOList(MyTreeView):
                if not self.model():
                    return None
                items = self.selected_in_column(self.Columns.ADDRESS)
       -        if not items:
       -            return None
                return [x.data(Qt.UserRole) for x in items]
        
            def _filter_frozen_coins(self, coins: List[PartialTxInput]) -> List[PartialTxInput]:
       t@@ -131,29 +129,39 @@ class UTXOList(MyTreeView):
                             not self.wallet.is_frozen_coin(utxo))]
                return coins
        
       -    def set_spend_list(self, coins: List[PartialTxInput]):
       -        coins = self._filter_frozen_coins(coins)
       -        self._spend_set = {utxo.prevout.to_str() for utxo in coins}
       +    def set_spend_list(self, coins: Optional[List[PartialTxInput]]):
       +        if coins is not None:
       +            coins = self._filter_frozen_coins(coins)
       +            self._spend_set = {utxo.prevout.to_str() for utxo in coins}
       +        else:
       +            self._spend_set = None
                self.update()
        
       -    def get_spend_list(self) -> Sequence[PartialTxInput]:
       +    def get_spend_list(self) -> Optional[Sequence[PartialTxInput]]:
       +        if self._spend_set is None:
       +            return None
                return [self.utxo_dict[x] for x in self._spend_set]
        
            def _maybe_reset_spend_list(self, current_wallet_utxos: Sequence[PartialTxInput]) -> None:
       +        if self._spend_set is None:
       +            return
                # if we spent one of the selected UTXOs, just reset selection
                utxo_set = {utxo.prevout.to_str() for utxo in current_wallet_utxos}
                if not all([prevout_str in utxo_set for prevout_str in self._spend_set]):
       -            self._spend_set = set()
       +            self._spend_set = None
        
            def create_menu(self, position):
                selected = self.get_selected_outpoints()
       -        if not selected:
       +        if selected is None:
                    return
                menu = QMenu()
                menu.setSeparatorsCollapsible(True)  # consecutive separators are merged together
                coins = [self.utxo_dict[name] for name in selected]
       -        menu.addAction(_("Spend"), lambda: self.set_spend_list(coins))
       -        assert len(coins) >= 1, len(coins)
       +        if len(coins) == 0:
       +            menu.addAction(_("Spend (select none)"), lambda: self.set_spend_list(coins))
       +        else:
       +            menu.addAction(_("Spend"), lambda: self.set_spend_list(coins))
       +
                if len(coins) == 1:
                    utxo = coins[0]
                    addr = utxo.address
       t@@ -184,8 +192,7 @@ class UTXOList(MyTreeView):
                        menu.addAction(_("Address is frozen"), lambda: None).setEnabled(False)
                        menu.addAction(_("Unfreeze Address"), lambda: self.parent.set_frozen_state_of_addresses([addr], False))
                        menu.addSeparator()
       -        else:
       -            # multiple items selected
       +        elif len(coins) > 1:  # multiple items selected
                    menu.addSeparator()
                    addrs = [utxo.address for utxo in coins]
                    is_coin_frozen = [self.wallet.is_frozen_coin(utxo) for utxo in coins]