Browse Source

qt history list: use OrderedDictWithIndex for txns

master
SomberNight 7 years ago
parent
commit
65e8eef87f
No known key found for this signature in database
GPG Key ID: B33B5F232C6271E9
  1. 54
      electrum/gui/qt/history_list.py
  2. 26
      electrum/util.py

54
electrum/gui/qt/history_list.py

@ -32,7 +32,7 @@ import threading
from electrum.address_synchronizer import TX_HEIGHT_LOCAL from electrum.address_synchronizer import TX_HEIGHT_LOCAL
from electrum.i18n import _ from electrum.i18n import _
from electrum.util import (block_explorer_URL, profiler, print_error, TxMinedInfo, from electrum.util import (block_explorer_URL, profiler, print_error, TxMinedInfo,
PrintError) OrderedDictWithIndex, PrintError)
from .util import * from .util import *
@ -71,14 +71,16 @@ class HistorySortModel(QSortFilterProxyModel):
class HistoryModel(QAbstractItemModel, PrintError): class HistoryModel(QAbstractItemModel, PrintError):
NUM_COLUMNS = 8
def __init__(self, parent): def __init__(self, parent):
super().__init__(parent) super().__init__(parent)
self.parent = parent self.parent = parent
self.transactions = [] self.transactions = OrderedDictWithIndex()
self.tx_status_cache = {} # type: Dict[str, Tuple[int, str]] self.tx_status_cache = {} # type: Dict[str, Tuple[int, str]]
def columnCount(self, parent: QModelIndex): def columnCount(self, parent: QModelIndex):
return 8 return self.NUM_COLUMNS
def rowCount(self, parent: QModelIndex): def rowCount(self, parent: QModelIndex):
return len(self.transactions) return len(self.transactions)
@ -92,15 +94,15 @@ class HistoryModel(QAbstractItemModel, PrintError):
# assert self.checkIndex(index, indexIsValid) # assert self.checkIndex(index, indexIsValid)
assert index.isValid() assert index.isValid()
col = index.column() col = index.column()
tx_item = self.transactions[index.row()] tx_item = self.transactions.value_from_pos(index.row())
tx_hash = tx_item['txid'] tx_hash = tx_item['txid']
conf = tx_item['confirmations'] conf = tx_item['confirmations']
txpos = tx_item['txpos_in_block'] or 0 txpos = tx_item['txpos_in_block'] or 0
try: try:
status, status_str = self.tx_status_cache[tx_hash] status, status_str = self.tx_status_cache[tx_hash]
except KeyError: except KeyError:
tx_mined_status = TxMinedInfo(height=tx_item['height'], conf=conf, timestamp=tx_item['timestamp']) 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_status) status, status_str = self.parent.wallet.get_tx_status(tx_hash, tx_mined_info)
if role == Qt.UserRole: if role == Qt.UserRole:
# for sorting # for sorting
d = { d = {
@ -164,7 +166,7 @@ class HistoryModel(QAbstractItemModel, PrintError):
return not index.isValid() return not index.isValid()
def update_label(self, row): 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']) tx_item['label'] = self.parent.wallet.get_label(tx_item['txid'])
topLeft = bottomRight = self.createIndex(row, 2) topLeft = bottomRight = self.createIndex(row, 2)
self.dataChanged.emit(topLeft, bottomRight, [Qt.DisplayRole]) self.dataChanged.emit(topLeft, bottomRight, [Qt.DisplayRole])
@ -183,7 +185,7 @@ class HistoryModel(QAbstractItemModel, PrintError):
fx = self.parent.fx fx = self.parent.fx
if fx: fx.history_used_spot = False 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) 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 return
old_length = len(self.transactions) old_length = len(self.transactions)
if old_length != 0: if old_length != 0:
@ -191,7 +193,9 @@ class HistoryModel(QAbstractItemModel, PrintError):
self.transactions.clear() self.transactions.clear()
self.endRemoveRows() self.endRemoveRows()
self.beginInsertRows(QModelIndex(), 0, len(r['transactions'])-1) 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() self.endInsertRows()
if selected_row: if selected_row:
self.parent.history_list.selectionModel().select(self.createIndex(selected_row, 0), QItemSelectionModel.Rows | QItemSelectionModel.SelectCurrent) 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() start_date = date.today()
end_date = date.today() end_date = date.today()
if len(self.transactions) > 0: if len(self.transactions) > 0:
start_date = self.transactions[0].get('date') or start_date start_date = self.transactions.value_from_pos(0).get('date') or start_date
end_date = self.transactions[-1].get('date') or end_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.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) self.parent.history_list.period_combo.insertItems(1, self.parent.history_list.years)
# update tx_status_cache # update tx_status_cache
self.tx_status_cache.clear() self.tx_status_cache.clear()
for tx_item in self.transactions: for txid, tx_item in self.transactions.items():
txid = tx_item['txid'] tx_mined_info = self.tx_mined_info_from_tx_item(tx_item)
tx_mined_status = TxMinedInfo(height=tx_item['height'], self.tx_status_cache[txid] = self.parent.wallet.get_tx_status(txid, tx_mined_info)
conf=tx_item['confirmations'],
timestamp=tx_item['timestamp'])
self.tx_status_cache[txid] = self.parent.wallet.get_tx_status(txid, tx_mined_status)
history = self.parent.fx.show_history() history = self.parent.fx.show_history()
cap_gains = self.parent.fx.get_history_capital_gains_config() cap_gains = self.parent.fx.get_history_capital_gains_config()
@ -235,7 +236,7 @@ class HistoryModel(QAbstractItemModel, PrintError):
hide(7) hide(7)
def update_fiat(self, row, idx): def update_fiat(self, row, idx):
tx_item = self.transactions[row] tx_item = self.transactions.value_from_pos(row)
key = tx_item['txid'] key = tx_item['txid']
fee = tx_item.get('fee') fee = tx_item.get('fee')
value = tx_item['value'].value value = tx_item['value'].value
@ -276,12 +277,19 @@ class HistoryModel(QAbstractItemModel, PrintError):
extra_flags |= Qt.ItemIsEditable extra_flags |= Qt.ItemIsEditable
return super().flags(idx) | extra_flags 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): class HistoryList(MyTreeView, AcceptFileDragDrop):
filter_columns = [1, 2, 3] # Date, Description, Amount filter_columns = [1, 2, 3] # Date, Description, Amount
def tx_item_from_proxy_row(self, proxy_row): def tx_item_from_proxy_row(self, proxy_row):
hm_idx = self.model().mapToSource(self.model().index(proxy_row, 0)) 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): def should_hide(self, proxy_row):
if self.start_timestamp and self.end_timestamp: if self.start_timestamp and self.end_timestamp:
@ -439,7 +447,7 @@ class HistoryList(MyTreeView, AcceptFileDragDrop):
_("Perhaps some dependencies are missing...") + " (matplotlib?)") _("Perhaps some dependencies are missing...") + " (matplotlib?)")
return return
try: try:
plt = plot_history(list(self.transactions.values())) plt = plot_history(list(self.hm.transactions.values()))
plt.show() plt.show()
except NothingToPlotException as e: except NothingToPlotException as e:
self.parent.show_message(str(e)) self.parent.show_message(str(e))
@ -447,7 +455,7 @@ class HistoryList(MyTreeView, AcceptFileDragDrop):
def on_edited(self, index, user_role, text): def on_edited(self, index, user_role, text):
index = self.model().mapToSource(index) index = self.model().mapToSource(index)
row, column = index.row(), index.column() 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'] key = tx_item['txid']
# fixme # fixme
if column == 2: if column == 2:
@ -485,7 +493,7 @@ class HistoryList(MyTreeView, AcceptFileDragDrop):
if not idx.isValid(): if not idx.isValid():
# can happen e.g. before list is populated for the first time # can happen e.g. before list is populated for the first time
return return
tx_item = self.hm.transactions[idx.row()] tx_item = self.hm.transactions.value_from_pos(idx.row())
column = idx.column() column = idx.column()
if column == 0: if column == 0:
column_title = _('Transaction ID') column_title = _('Transaction ID')
@ -614,5 +622,5 @@ class HistoryList(MyTreeView, AcceptFileDragDrop):
def text_txid_from_coordinate(self, row, col): def text_txid_from_coordinate(self, row, col):
idx = self.model().mapToSource(self.model().index(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'] return self.hm.data(idx, Qt.DisplayRole).value(), tx_item['txid']

26
electrum/util.py

@ -1010,46 +1010,54 @@ class OrderedDictWithIndex(OrderedDict):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self._key_to_pos = {} 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._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] 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): def popitem(self, *args, **kwargs):
ret = super().popitem(*args, **kwargs) ret = super().popitem(*args, **kwargs)
self._recalc_key_to_pos() self._recalc_index()
return ret return ret
def move_to_end(self, *args, **kwargs): def move_to_end(self, *args, **kwargs):
ret = super().move_to_end(*args, **kwargs) ret = super().move_to_end(*args, **kwargs)
self._recalc_key_to_pos() self._recalc_index()
return ret return ret
def clear(self): def clear(self):
ret = super().clear() ret = super().clear()
self._recalc_key_to_pos() self._recalc_index()
return ret return ret
def pop(self, *args, **kwargs): def pop(self, *args, **kwargs):
ret = super().pop(*args, **kwargs) ret = super().pop(*args, **kwargs)
self._recalc_key_to_pos() self._recalc_index()
return ret return ret
def update(self, *args, **kwargs): def update(self, *args, **kwargs):
ret = super().update(*args, **kwargs) ret = super().update(*args, **kwargs)
self._recalc_key_to_pos() self._recalc_index()
return ret return ret
def __delitem__(self, *args, **kwargs): def __delitem__(self, *args, **kwargs):
ret = super().__delitem__(*args, **kwargs) ret = super().__delitem__(*args, **kwargs)
self._recalc_key_to_pos() self._recalc_index()
return ret return ret
def __setitem__(self, key, *args, **kwargs): def __setitem__(self, key, *args, **kwargs):
is_new_key = key not in self is_new_key = key not in self
ret = super().__setitem__(key, *args, **kwargs) ret = super().__setitem__(key, *args, **kwargs)
if is_new_key: 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 return ret

Loading…
Cancel
Save