diff --git a/electrum/exchange_rate.py b/electrum/exchange_rate.py index e3bdcc79e..801ce47a8 100644 --- a/electrum/exchange_rate.py +++ b/electrum/exchange_rate.py @@ -651,13 +651,16 @@ class FxThread(ThreadJob, EventListener): def fiat_value(self, satoshis, rate) -> Decimal: return Decimal('NaN') if satoshis is None else Decimal(satoshis) / COIN * Decimal(rate) - def value_str(self, satoshis, rate) -> str: - return self.format_fiat(self.fiat_value(satoshis, rate)) + def value_str(self, satoshis, rate, *, add_thousands_sep: bool = None) -> str: + fiat_val = self.fiat_value(satoshis, rate) + return self.format_fiat(fiat_val, add_thousands_sep=add_thousands_sep) - def format_fiat(self, value: Decimal) -> str: + def format_fiat(self, value: Decimal, *, add_thousands_sep: bool = None) -> str: if value.is_nan(): return _("No data") - return self.ccy_amount_str(value, add_thousands_sep=True) + if add_thousands_sep is None: + add_thousands_sep = True + return self.ccy_amount_str(value, add_thousands_sep=add_thousands_sep) def history_rate(self, d_t: Optional[datetime]) -> Decimal: if d_t is None: diff --git a/electrum/gui/qt/address_list.py b/electrum/gui/qt/address_list.py index ef9545fab..470448837 100644 --- a/electrum/gui/qt/address_list.py +++ b/electrum/gui/qt/address_list.py @@ -250,19 +250,24 @@ class AddressList(MyTreeView): c, u, x = self.wallet.get_addr_balance(address) balance = c + u + x balance_text = self.main_window.format_amount(balance, whitespaces=True) + balance_text_nots = self.main_window.format_amount(balance, whitespaces=False, add_thousands_sep=False) # create item fx = self.main_window.fx if self.should_show_fiat(): rate = fx.exchange_rate() - fiat_balance_str = fx.value_str(balance, rate) + fiat_balance_str = fx.value_str(balance, rate, add_thousands_sep=True) + fiat_balance_str_nots = fx.value_str(balance, rate, add_thousands_sep=False) else: fiat_balance_str = '' + fiat_balance_str_nots = '' address_item = [self.std_model.item(row, col) for col in self.Columns] address_item[self.Columns.LABEL].setText(label) address_item[self.Columns.COIN_BALANCE].setText(balance_text) address_item[self.Columns.COIN_BALANCE].setData(balance, self.ROLE_SORT_ORDER) + address_item[self.Columns.COIN_BALANCE].setData(balance_text_nots, self.ROLE_CLIPBOARD_DATA) address_item[self.Columns.FIAT_BALANCE].setText(fiat_balance_str) address_item[self.Columns.FIAT_BALANCE].setData(balance, self.ROLE_SORT_ORDER) + address_item[self.Columns.FIAT_BALANCE].setData(fiat_balance_str_nots, self.ROLE_CLIPBOARD_DATA) address_item[self.Columns.NUM_TXS].setText("%d"%num) c = ColorScheme.BLUE.as_color(True) if self.wallet.is_frozen_address(address) else self._default_bg_brush address_item[self.Columns.ADDRESS].setBackground(c) diff --git a/electrum/gui/qt/history_list.py b/electrum/gui/qt/history_list.py index ce4951fef..3151db04a 100644 --- a/electrum/gui/qt/history_list.py +++ b/electrum/gui/qt/history_list.py @@ -156,7 +156,7 @@ class HistoryNode(CustomNode): return QVariant(d[col]) if role == MyTreeView.ROLE_EDIT_KEY: return QVariant(get_item_key(tx_item)) - if role not in (Qt.DisplayRole, Qt.EditRole): + if role not in (Qt.DisplayRole, Qt.EditRole, MyTreeView.ROLE_CLIPBOARD_DATA): if col == HistoryColumns.STATUS and role == Qt.DecorationRole: icon = "lightning" if is_lightning else TX_ICONS[status] return QVariant(read_QIcon(icon)) @@ -189,6 +189,13 @@ class HistoryNode(CustomNode): blue_brush = QBrush(QColor("#1E1EFF")) return QVariant(blue_brush) return QVariant() + + add_thousands_sep = None + whitespaces = True + if role == MyTreeView.ROLE_CLIPBOARD_DATA: + add_thousands_sep = False + whitespaces = False + if col == HistoryColumns.STATUS: return QVariant(status_str) elif col == HistoryColumns.DESCRIPTION and 'label' in tx_item: @@ -197,23 +204,23 @@ class HistoryNode(CustomNode): bc_value = tx_item['bc_value'].value if 'bc_value' in tx_item else 0 ln_value = tx_item['ln_value'].value if 'ln_value' in tx_item else 0 value = bc_value + ln_value - v_str = window.format_amount(value, is_diff=True, whitespaces=True) + v_str = window.format_amount(value, is_diff=True, whitespaces=whitespaces, add_thousands_sep=add_thousands_sep) return QVariant(v_str) elif col == HistoryColumns.BALANCE: balance = tx_item['balance'].value - balance_str = window.format_amount(balance, whitespaces=True) + balance_str = window.format_amount(balance, whitespaces=whitespaces, add_thousands_sep=add_thousands_sep) return QVariant(balance_str) elif col == HistoryColumns.FIAT_VALUE and 'fiat_value' in tx_item: - value_str = window.fx.format_fiat(tx_item['fiat_value'].value) + value_str = window.fx.format_fiat(tx_item['fiat_value'].value, add_thousands_sep=add_thousands_sep) return QVariant(value_str) elif col == HistoryColumns.FIAT_ACQ_PRICE and \ tx_item['value'].value < 0 and 'acquisition_price' in tx_item: # fixme: should use is_mine acq = tx_item['acquisition_price'].value - return QVariant(window.fx.format_fiat(acq)) + return QVariant(window.fx.format_fiat(acq, add_thousands_sep=add_thousands_sep)) elif col == HistoryColumns.FIAT_CAP_GAINS and 'capital_gain' in tx_item: cg = tx_item['capital_gain'].value - return QVariant(window.fx.format_fiat(cg)) + return QVariant(window.fx.format_fiat(cg, add_thousands_sep=add_thousands_sep)) elif col == HistoryColumns.TXID: return QVariant(tx_hash) if not is_lightning else QVariant('') elif col == HistoryColumns.SHORT_ID: @@ -733,10 +740,12 @@ class HistoryList(MyTreeView, AcceptFileDragDrop): continue column_title = self.hm.headerData(column, Qt.Horizontal, Qt.DisplayRole) idx2 = idx.sibling(idx.row(), column) - column_data = (self.hm.data(idx2, Qt.DisplayRole).value() or '').strip() + clipboard_data = self.hm.data(idx2, self.ROLE_CLIPBOARD_DATA).value() + if clipboard_data is None: + clipboard_data = (self.hm.data(idx2, Qt.DisplayRole).value() or '').strip() cc.addAction( column_title, - lambda text=column_data, title=column_title: + lambda text=clipboard_data, title=column_title: self.place_text_on_clipboard(text, title=title)) return cc diff --git a/electrum/gui/qt/invoice_list.py b/electrum/gui/qt/invoice_list.py index 3e641e2fe..946d92ef2 100644 --- a/electrum/gui/qt/invoice_list.py +++ b/electrum/gui/qt/invoice_list.py @@ -120,6 +120,7 @@ class InvoiceList(MyTreeView): status = self.wallet.get_invoice_status(item) amount = item.get_amount_sat() amount_str = self.main_window.format_amount(amount, whitespaces=True) if amount else "" + amount_str_nots = self.main_window.format_amount(amount, whitespaces=True, add_thousands_sep=False) if amount else "" timestamp = item.time or 0 labels = [""] * len(self.Columns) labels[self.Columns.DATE] = format_time(timestamp) if timestamp else _('Unknown') @@ -133,6 +134,7 @@ class InvoiceList(MyTreeView): items[self.Columns.DATE].setData(key, role=ROLE_REQUEST_ID) #items[self.Columns.DATE].setData(item.type, role=ROLE_REQUEST_TYPE) items[self.Columns.DATE].setData(timestamp, role=ROLE_SORT_ORDER) + items[self.Columns.AMOUNT].setData(amount_str_nots.strip(), role=self.ROLE_CLIPBOARD_DATA) self.std_model.insertRow(idx, items) self.filter() self.proxy.setDynamicSortFilter(True) diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py index b6f9ef4e6..afaecfb68 100644 --- a/electrum/gui/qt/main_window.py +++ b/electrum/gui/qt/main_window.py @@ -857,7 +857,8 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener): amount_sat, is_diff=False, whitespaces=False, - ignore_thousands_sep: bool = False, + *, + add_thousands_sep: bool = None, ) -> str: """Formats amount as string, converting to desired unit. E.g. 500_000 -> '0.005' @@ -866,7 +867,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener): amount_sat, is_diff=is_diff, whitespaces=whitespaces, - ignore_thousands_sep=ignore_thousands_sep, + add_thousands_sep=add_thousands_sep, ) def format_amount_and_units(self, amount_sat, *, timestamp: int = None) -> str: diff --git a/electrum/gui/qt/my_treeview.py b/electrum/gui/qt/my_treeview.py index d617d3eb2..25b4de01d 100644 --- a/electrum/gui/qt/my_treeview.py +++ b/electrum/gui/qt/my_treeview.py @@ -452,13 +452,6 @@ class MyTreeView(QTreeView): return cc def place_text_on_clipboard(self, text: str, *, title: str = None) -> None: - if title in { - "Amount", - "Balance", - } or title.endswith(" Value") or title.endswith(" Acquisition price") or title.endswith(" Capital Gains"): - with contextlib.suppress(Exception): - # remove formatting for numbers - text = text.replace(" ", "") self.main_window.do_copy(text, title=title) def showEvent(self, e: 'QShowEvent'): diff --git a/electrum/gui/qt/request_list.py b/electrum/gui/qt/request_list.py index 730010c0b..55514915b 100644 --- a/electrum/gui/qt/request_list.py +++ b/electrum/gui/qt/request_list.py @@ -145,6 +145,7 @@ class RequestList(MyTreeView): message = req.get_message() date = format_time(timestamp) amount_str = self.main_window.format_amount(amount) if amount else "" + amount_str_nots = self.main_window.format_amount(amount, add_thousands_sep=False) if amount else "" labels = [""] * len(self.Columns) labels[self.Columns.DATE] = date labels[self.Columns.DESCRIPTION] = message @@ -157,6 +158,7 @@ class RequestList(MyTreeView): #items[self.Columns.DATE].setData(request_type, ROLE_REQUEST_TYPE) items[self.Columns.DATE].setData(key, ROLE_KEY) items[self.Columns.DATE].setData(timestamp, ROLE_SORT_ORDER) + items[self.Columns.AMOUNT].setData(amount_str_nots.strip(), self.ROLE_CLIPBOARD_DATA) items[self.Columns.STATUS].setIcon(read_QIcon(pr_icons.get(status))) self.std_model.insertRow(self.std_model.rowCount(), items) self.filter() diff --git a/electrum/gui/qt/transaction_dialog.py b/electrum/gui/qt/transaction_dialog.py index 59a43bf36..579a08e25 100644 --- a/electrum/gui/qt/transaction_dialog.py +++ b/electrum/gui/qt/transaction_dialog.py @@ -314,7 +314,7 @@ class TxInOutWidget(QWidget): copy_list += [(_("Copy Address"), lambda: self.main_window.do_copy(addr))] txin_value = self.wallet.adb.get_txin_value(txin) if txin_value: - value_str = self.main_window.format_amount(txin_value, ignore_thousands_sep=True) + value_str = self.main_window.format_amount(txin_value, add_thousands_sep=False) copy_list += [(_("Copy Amount"), lambda: self.main_window.do_copy(value_str))] for item in show_list: @@ -356,7 +356,7 @@ class TxInOutWidget(QWidget): show_list += [(_("Address Details"), lambda: self.main_window.show_address(addr, parent=self))] copy_list += [(_("Copy Address"), lambda: self.main_window.do_copy(addr))] txout_value = self.tx.outputs()[txout_idx].value - value_str = self.main_window.format_amount(txout_value, ignore_thousands_sep=True) + value_str = self.main_window.format_amount(txout_value, add_thousands_sep=False) copy_list += [(_("Copy Amount"), lambda: self.main_window.do_copy(value_str))] for item in show_list: diff --git a/electrum/gui/qt/utxo_list.py b/electrum/gui/qt/utxo_list.py index adb966383..7f8bdc3d3 100644 --- a/electrum/gui/qt/utxo_list.py +++ b/electrum/gui/qt/utxo_list.py @@ -101,12 +101,17 @@ class UTXOList(MyTreeView): name = utxo.prevout.to_str() self._utxo_dict[name] = utxo labels = [""] * len(self.Columns) + amount_str = self.main_window.format_amount( + utxo.value_sats(), whitespaces=True) + amount_str_nots = self.main_window.format_amount( + utxo.value_sats(), whitespaces=False, add_thousands_sep=False) labels[self.Columns.OUTPOINT] = str(utxo.short_id) labels[self.Columns.ADDRESS] = utxo.address - labels[self.Columns.AMOUNT] = self.main_window.format_amount(utxo.value_sats(), whitespaces=True) + labels[self.Columns.AMOUNT] = amount_str utxo_item = [QStandardItem(x) for x in labels] self.set_editability(utxo_item) utxo_item[self.Columns.OUTPOINT].setData(name, self.ROLE_PREVOUT_STR) + utxo_item[self.Columns.AMOUNT].setData(amount_str_nots, self.ROLE_CLIPBOARD_DATA) utxo_item[self.Columns.ADDRESS].setFont(QFont(MONOSPACE_FONT)) utxo_item[self.Columns.AMOUNT].setFont(QFont(MONOSPACE_FONT)) utxo_item[self.Columns.PARENTS].setFont(QFont(MONOSPACE_FONT)) diff --git a/electrum/simple_config.py b/electrum/simple_config.py index 91b6d940d..d97c8d8ef 100644 --- a/electrum/simple_config.py +++ b/electrum/simple_config.py @@ -785,10 +785,12 @@ class SimpleConfig(Logger): is_diff=False, whitespaces=False, precision=None, - ignore_thousands_sep: bool=False, + add_thousands_sep: bool = None, ) -> str: if precision is None: precision = self.amt_precision_post_satoshi + if add_thousands_sep is None: + add_thousands_sep = self.amt_add_thousands_sep return format_satoshis( amount_sat, num_zeros=self.num_zeros, @@ -796,7 +798,7 @@ class SimpleConfig(Logger): is_diff=is_diff, whitespaces=whitespaces, precision=precision, - add_thousands_sep=False if ignore_thousands_sep else self.amt_add_thousands_sep, + add_thousands_sep=add_thousands_sep, ) def format_amount_and_units(self, *args, **kwargs) -> str: