From 65e8eef87fdc0ae47fadca8b1def4607e73c0e73 Mon Sep 17 00:00:00 2001 From: SomberNight Date: Sat, 8 Dec 2018 04:22:53 +0100 Subject: [PATCH] qt history list: use OrderedDictWithIndex for txns --- electrum/gui/qt/history_list.py | 54 +++++++++++++++++++-------------- electrum/util.py | 26 ++++++++++------ 2 files changed, 48 insertions(+), 32 deletions(-) diff --git a/electrum/gui/qt/history_list.py b/electrum/gui/qt/history_list.py index aefd4e2cf..a05e9f31e 100644 --- a/electrum/gui/qt/history_list.py +++ b/electrum/gui/qt/history_list.py @@ -32,7 +32,7 @@ import threading from electrum.address_synchronizer import TX_HEIGHT_LOCAL from electrum.i18n import _ from electrum.util import (block_explorer_URL, profiler, print_error, TxMinedInfo, - PrintError) + OrderedDictWithIndex, PrintError) from .util import * @@ -71,14 +71,16 @@ class HistorySortModel(QSortFilterProxyModel): class HistoryModel(QAbstractItemModel, PrintError): + NUM_COLUMNS = 8 + def __init__(self, parent): super().__init__(parent) self.parent = parent - self.transactions = [] + self.transactions = OrderedDictWithIndex() self.tx_status_cache = {} # type: Dict[str, Tuple[int, str]] def columnCount(self, parent: QModelIndex): - return 8 + return self.NUM_COLUMNS def rowCount(self, parent: QModelIndex): return len(self.transactions) @@ -92,15 +94,15 @@ class HistoryModel(QAbstractItemModel, PrintError): # assert self.checkIndex(index, indexIsValid) assert index.isValid() col = index.column() - tx_item = self.transactions[index.row()] + tx_item = self.transactions.value_from_pos(index.row()) tx_hash = tx_item['txid'] conf = tx_item['confirmations'] txpos = tx_item['txpos_in_block'] or 0 try: status, status_str = self.tx_status_cache[tx_hash] except KeyError: - tx_mined_status = TxMinedInfo(height=tx_item['height'], conf=conf, timestamp=tx_item['timestamp']) - status, status_str = self.parent.wallet.get_tx_status(tx_hash, tx_mined_status) + tx_mined_info = self.tx_mined_info_from_tx_item(tx_item) + status, status_str = self.parent.wallet.get_tx_status(tx_hash, tx_mined_info) if role == Qt.UserRole: # for sorting d = { @@ -164,7 +166,7 @@ class HistoryModel(QAbstractItemModel, PrintError): return not index.isValid() def update_label(self, row): - tx_item = self.transactions[row] + tx_item = self.transactions.value_from_pos(row) tx_item['label'] = self.parent.wallet.get_label(tx_item['txid']) topLeft = bottomRight = self.createIndex(row, 2) self.dataChanged.emit(topLeft, bottomRight, [Qt.DisplayRole]) @@ -183,7 +185,7 @@ class HistoryModel(QAbstractItemModel, PrintError): fx = self.parent.fx if fx: fx.history_used_spot = False r = self.parent.wallet.get_full_history(domain=self.get_domain(), from_timestamp=None, to_timestamp=None, fx=fx) - if r['transactions'] == self.transactions: + if r['transactions'] == list(self.transactions.values()): return old_length = len(self.transactions) if old_length != 0: @@ -191,7 +193,9 @@ class HistoryModel(QAbstractItemModel, PrintError): self.transactions.clear() self.endRemoveRows() self.beginInsertRows(QModelIndex(), 0, len(r['transactions'])-1) - self.transactions = r['transactions'] + for tx_item in r['transactions']: + txid = tx_item['txid'] + self.transactions[txid] = tx_item self.endInsertRows() if selected_row: self.parent.history_list.selectionModel().select(self.createIndex(selected_row, 0), QItemSelectionModel.Rows | QItemSelectionModel.SelectCurrent) @@ -204,18 +208,15 @@ class HistoryModel(QAbstractItemModel, PrintError): start_date = date.today() end_date = date.today() if len(self.transactions) > 0: - start_date = self.transactions[0].get('date') or start_date - end_date = self.transactions[-1].get('date') or end_date + start_date = self.transactions.value_from_pos(0).get('date') or start_date + end_date = self.transactions.value_from_pos(len(self.transactions) - 1).get('date') or end_date self.parent.history_list.years = [str(i) for i in range(start_date.year, end_date.year + 1)] self.parent.history_list.period_combo.insertItems(1, self.parent.history_list.years) # update tx_status_cache self.tx_status_cache.clear() - for tx_item in self.transactions: - txid = tx_item['txid'] - tx_mined_status = TxMinedInfo(height=tx_item['height'], - conf=tx_item['confirmations'], - timestamp=tx_item['timestamp']) - self.tx_status_cache[txid] = self.parent.wallet.get_tx_status(txid, tx_mined_status) + for txid, tx_item in self.transactions.items(): + tx_mined_info = self.tx_mined_info_from_tx_item(tx_item) + self.tx_status_cache[txid] = self.parent.wallet.get_tx_status(txid, tx_mined_info) history = self.parent.fx.show_history() cap_gains = self.parent.fx.get_history_capital_gains_config() @@ -235,7 +236,7 @@ class HistoryModel(QAbstractItemModel, PrintError): hide(7) def update_fiat(self, row, idx): - tx_item = self.transactions[row] + tx_item = self.transactions.value_from_pos(row) key = tx_item['txid'] fee = tx_item.get('fee') value = tx_item['value'].value @@ -276,12 +277,19 @@ class HistoryModel(QAbstractItemModel, PrintError): extra_flags |= Qt.ItemIsEditable return super().flags(idx) | extra_flags + @staticmethod + def tx_mined_info_from_tx_item(tx_item): + tx_mined_info = TxMinedInfo(height=tx_item['height'], + conf=tx_item['confirmations'], + timestamp=tx_item['timestamp']) + return tx_mined_info + class HistoryList(MyTreeView, AcceptFileDragDrop): filter_columns = [1, 2, 3] # Date, Description, Amount def tx_item_from_proxy_row(self, proxy_row): hm_idx = self.model().mapToSource(self.model().index(proxy_row, 0)) - return self.hm.transactions[hm_idx.row()] + return self.hm.transactions.value_from_pos(hm_idx.row()) def should_hide(self, proxy_row): if self.start_timestamp and self.end_timestamp: @@ -439,7 +447,7 @@ class HistoryList(MyTreeView, AcceptFileDragDrop): _("Perhaps some dependencies are missing...") + " (matplotlib?)") return try: - plt = plot_history(list(self.transactions.values())) + plt = plot_history(list(self.hm.transactions.values())) plt.show() except NothingToPlotException as e: self.parent.show_message(str(e)) @@ -447,7 +455,7 @@ class HistoryList(MyTreeView, AcceptFileDragDrop): def on_edited(self, index, user_role, text): index = self.model().mapToSource(index) row, column = index.row(), index.column() - tx_item = self.hm.transactions[row] + tx_item = self.hm.transactions.value_from_pos(row) key = tx_item['txid'] # fixme if column == 2: @@ -485,7 +493,7 @@ class HistoryList(MyTreeView, AcceptFileDragDrop): if not idx.isValid(): # can happen e.g. before list is populated for the first time return - tx_item = self.hm.transactions[idx.row()] + tx_item = self.hm.transactions.value_from_pos(idx.row()) column = idx.column() if column == 0: column_title = _('Transaction ID') @@ -614,5 +622,5 @@ class HistoryList(MyTreeView, AcceptFileDragDrop): def text_txid_from_coordinate(self, row, col): idx = self.model().mapToSource(self.model().index(row, col)) - tx_item = self.hm.transactions[idx.row()] + tx_item = self.hm.transactions.value_from_pos(idx.row()) return self.hm.data(idx, Qt.DisplayRole).value(), tx_item['txid'] diff --git a/electrum/util.py b/electrum/util.py index d2ca64a0f..f158d9d0f 100644 --- a/electrum/util.py +++ b/electrum/util.py @@ -1010,46 +1010,54 @@ class OrderedDictWithIndex(OrderedDict): def __init__(self): super().__init__() self._key_to_pos = {} + self._pos_to_key = {} - def _recalc_key_to_pos(self): + def _recalc_index(self): self._key_to_pos = {key: pos for (pos, key) in enumerate(self.keys())} + self._pos_to_key = {pos: key for (pos, key) in enumerate(self.keys())} - def get_pos_of_key(self, key): + def pos_from_key(self, key): return self._key_to_pos[key] + def value_from_pos(self, pos): + key = self._pos_to_key[pos] + return self[key] + def popitem(self, *args, **kwargs): ret = super().popitem(*args, **kwargs) - self._recalc_key_to_pos() + self._recalc_index() return ret def move_to_end(self, *args, **kwargs): ret = super().move_to_end(*args, **kwargs) - self._recalc_key_to_pos() + self._recalc_index() return ret def clear(self): ret = super().clear() - self._recalc_key_to_pos() + self._recalc_index() return ret def pop(self, *args, **kwargs): ret = super().pop(*args, **kwargs) - self._recalc_key_to_pos() + self._recalc_index() return ret def update(self, *args, **kwargs): ret = super().update(*args, **kwargs) - self._recalc_key_to_pos() + self._recalc_index() return ret def __delitem__(self, *args, **kwargs): ret = super().__delitem__(*args, **kwargs) - self._recalc_key_to_pos() + self._recalc_index() return ret def __setitem__(self, key, *args, **kwargs): is_new_key = key not in self ret = super().__setitem__(key, *args, **kwargs) if is_new_key: - self._key_to_pos[key] = len(self) - 1 + pos = len(self) - 1 + self._key_to_pos[key] = pos + self._pos_to_key[pos] = key return ret