From 897f258d12a40bccd229cad54b13a6ca293ee494 Mon Sep 17 00:00:00 2001 From: Inso <insomniak.fr@gmail.com> Date: Mon, 4 May 2015 20:12:48 +0200 Subject: [PATCH] Fix bug with cache refreshing at cutecoin startup --- src/cutecoin/core/account.py | 2 +- src/cutecoin/core/wallet.py | 28 ++++-- src/cutecoin/gui/community_tab.py | 2 +- src/cutecoin/gui/currency_tab.py | 12 +++ src/cutecoin/gui/mainwindow.py | 2 +- src/cutecoin/gui/transactions_tab.py | 2 +- src/cutecoin/gui/wallets_tab.py | 2 +- src/cutecoin/models/txhistory.py | 137 +++++++++++++++++---------- 8 files changed, 125 insertions(+), 62 deletions(-) diff --git a/src/cutecoin/core/account.py b/src/cutecoin/core/account.py index de8f903a..0fb8e3ad 100644 --- a/src/cutecoin/core/account.py +++ b/src/cutecoin/core/account.py @@ -184,7 +184,7 @@ class Account(QObject): for w in self.wallets: w.refresh_progressed.connect(progressing, type=Qt.DirectConnection) for c in self.communities: - w.refresh_cache(c) + w.init_cache(c) loaded_wallets = loaded_wallets + 1 def set_display_referential(self, index): diff --git a/src/cutecoin/core/wallet.py b/src/cutecoin/core/wallet.py index 5479d48b..0ec707fd 100644 --- a/src/cutecoin/core/wallet.py +++ b/src/cutecoin/core/wallet.py @@ -10,7 +10,7 @@ from ucoinpy.documents.block import Block from ucoinpy.documents.transaction import InputSource, OutputSource, Transaction from ucoinpy.key import SigningKey -from ..tools.exceptions import NotEnoughMoneyError, NoPeerAvailable, PersonNotFoundError +from ..tools.exceptions import NotEnoughMoneyError, Error, NoPeerAvailable, PersonNotFoundError from .transfer import Transfer, Received from .person import Person @@ -21,12 +21,20 @@ import logging class Cache(): def __init__(self, wallet): - self.latest_block = 0 + self._latest_block = 0 self.wallet = wallet self._transfers = [] self.available_sources = [] + @property + def latest_block(self): + return self._latest_block + + @latest_block.setter + def latest_block(self, value): + self._latest_block = value + def load_from_json(self, data): self._transfers = [] @@ -118,6 +126,7 @@ class Cache(): metadata.copy())) def _parse_block(self, community, block_number): + logging.debug("Parsing block {0}".format(block_number)) block = community.request(bma.blockchain.Block, req_args={'number': block_number}) signed_raw = "{0}{1}\n".format(block['raw'], @@ -157,6 +166,7 @@ class Cache(): current_block + 1)) parsed_blocks = [n for n in parsed_blocks if n in with_tx['result']['blocks']] + logging.debug(parsed_blocks) self.wallet.refresh_progressed.emit(self.latest_block, current_block) for block_number in parsed_blocks: @@ -166,6 +176,7 @@ class Cache(): if current_block > self.latest_block: self.available_sources = self.wallet.sources(community) + self.latest_block = current_block for transfer in awaiting: transfer.check_refused(current_block) @@ -173,8 +184,6 @@ class Cache(): except NoPeerAvailable: return - self.latest_block = current_block - class Wallet(QObject): ''' @@ -249,14 +258,21 @@ class Wallet(QObject): data[currency] = self.caches[currency].jsonify() return data - def refresh_cache(self, community): + def init_cache(self, community): ''' - Refresh the cache of this wallet for the specified community. + Init the cache of this wallet for the specified community. :param community: The community to refresh its cache ''' if community.currency not in self.caches: self.caches[community.currency] = Cache(self) + + def refresh_cache(self, community): + ''' + Refresh the cache of this wallet for the specified community. + + :param community: The community to refresh its cache + ''' self.caches[community.currency].refresh(community) def check_password(self, salt, password): diff --git a/src/cutecoin/gui/community_tab.py b/src/cutecoin/gui/community_tab.py index 354142f0..f5009999 100644 --- a/src/cutecoin/gui/community_tab.py +++ b/src/cutecoin/gui/community_tab.py @@ -128,7 +128,7 @@ class CommunityTabWidget(QWidget, Ui_CommunityTabWidget): dialog.radio_pubkey.setChecked(True) if dialog.exec_() == QDialog.Accepted: currency_tab = self.window().currencies_tabwidget.currentWidget() - currency_tab.tab_history.table_history.model().invalidate() + currency_tab.tab_history.table_history.model().sourceModel().refresh_transfers() def certify_member(self, person): dialog = CertificationDialog(self.account, self.password_asker) diff --git a/src/cutecoin/gui/currency_tab.py b/src/cutecoin/gui/currency_tab.py index f1ab6025..ac53fd5c 100644 --- a/src/cutecoin/gui/currency_tab.py +++ b/src/cutecoin/gui/currency_tab.py @@ -54,6 +54,7 @@ class CurrencyTabWidget(QWidget, Ui_CurrencyTabWidget): persons_watcher.person_changed.connect(self.tab_community.refresh_person) bc_watcher = self.app.monitor.blockchain_watcher(self.community) bc_watcher.error.connect(self.display_error) + bc_watcher.watching_stopped.connect(self.refresh_data) person = Person.lookup(self.app.current_account.pubkey, self.community) try: @@ -151,6 +152,17 @@ class CurrencyTabWidget(QWidget, Ui_CurrencyTabWidget): self.app.monitor.persons_watcher(self.community).thread().start() self.refresh_status() + @pyqtSlot() + def refresh_data(self): + ''' + Refresh data when the blockchain watcher finished handling datas + ''' + if self.tab_wallets: + self.tab_wallets.refresh() + + if self.tab_history.table_history.model(): + self.tab_history.table_history.model().sourceModel().refresh_transfers() + @pyqtSlot() def refresh_status(self): logging.debug("Refresh status") diff --git a/src/cutecoin/gui/mainwindow.py b/src/cutecoin/gui/mainwindow.py index 632b6e1b..0319e0dd 100644 --- a/src/cutecoin/gui/mainwindow.py +++ b/src/cutecoin/gui/mainwindow.py @@ -190,7 +190,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): dialog.accepted.connect(self.refresh_wallets) if dialog.exec_() == QDialog.Accepted: currency_tab = self.currencies_tabwidget.currentWidget() - currency_tab.tab_history.table_history.model().invalidate() + currency_tab.tab_history.table_history.model().sourceModel().refresh_transfers() def open_certification_dialog(self): dialog = CertificationDialog(self.app.current_account, diff --git a/src/cutecoin/gui/transactions_tab.py b/src/cutecoin/gui/transactions_tab.py index 352b8f4d..1e10985e 100644 --- a/src/cutecoin/gui/transactions_tab.py +++ b/src/cutecoin/gui/transactions_tab.py @@ -115,7 +115,7 @@ class TransactionsTabWidget(QWidget, Ui_transactionsTabWidget): result = dialog.exec_() if result == QDialog.Accepted: transfer.drop() - self.table_history.model().invalidate() + self.table_history.model().sourceModel().refresh_transfers() def cancel_transfer(self): reply = QMessageBox.warning(self, "Warning", diff --git a/src/cutecoin/gui/wallets_tab.py b/src/cutecoin/gui/wallets_tab.py index 44f4c119..1ea04ee5 100644 --- a/src/cutecoin/gui/wallets_tab.py +++ b/src/cutecoin/gui/wallets_tab.py @@ -190,4 +190,4 @@ class WalletsTabWidget(QWidget, Ui_WalletsTab): dialog.radio_pubkey.setChecked(True) if dialog.exec_() == QDialog.Accepted: currency_tab = self.window().currencies_tabwidget.currentWidget() - currency_tab.tab_history.table_history.model().invalidate() + currency_tab.tab_history.table_history.model().sourceModel().refresh_transfers() diff --git a/src/cutecoin/models/txhistory.py b/src/cutecoin/models/txhistory.py index a20386f7..2305ef35 100644 --- a/src/cutecoin/models/txhistory.py +++ b/src/cutecoin/models/txhistory.py @@ -9,7 +9,7 @@ from ..core.transfer import Transfer, Received from ..core.person import Person from ..tools.exceptions import PersonNotFoundError from PyQt5.QtCore import QAbstractTableModel, Qt, QVariant, QSortFilterProxyModel, \ - QDateTime + QDateTime, QLocale, QModelIndex from PyQt5.QtGui import QFont, QColor @@ -20,6 +20,9 @@ class TxFilterProxyModel(QSortFilterProxyModel): self.account = None self.ts_from = ts_from self.ts_to = ts_to + # total by column + self.payments = 0 + self.deposits = 0 def set_period(self, ts_from, ts_to): """ @@ -32,10 +35,28 @@ class TxFilterProxyModel(QSortFilterProxyModel): def filterAcceptsRow(self, sourceRow, sourceParent): def in_period(date_ts): - return date_ts >= self.ts_from and date_ts <= self.ts_to - date_col = self.sourceModel().column_types.index('date') - source_index = self.sourceModel().index(sourceRow, date_col) - date = self.sourceModel().data(source_index, Qt.DisplayRole) + return date_ts in range(self.ts_from, self.ts_to) + + source_model = self.sourceModel() + date_col = source_model.column_types.index('date') + source_index = source_model.index(sourceRow, date_col) + date = source_model.data(source_index, Qt.DisplayRole) + if in_period(date): + # calculate sum total payments + payment = source_model.data( + source_model.index(sourceRow, source_model.column_types.index('payment')), + Qt.DisplayRole + ) + if payment: + self.payments += int(payment) + # calculate sum total deposits + deposit = source_model.data( + source_model.index(sourceRow, source_model.column_types.index('deposit')), + Qt.DisplayRole + ) + if deposit: + self.deposits += int(deposit) + return in_period(date) def columnCount(self, parent): @@ -50,8 +71,9 @@ class TxFilterProxyModel(QSortFilterProxyModel): """ Sort table by given column number. """ - left_data = self.sourceModel().data(left, Qt.DisplayRole) - right_data = self.sourceModel().data(right, Qt.DisplayRole) + source_model = self.sourceModel() + left_data = source_model.data(left, Qt.DisplayRole) + right_data = source_model.data(right, Qt.DisplayRole) if left_data == "": return self.sortOrder() == Qt.DescendingOrder elif right_data == "": @@ -61,28 +83,26 @@ class TxFilterProxyModel(QSortFilterProxyModel): def data(self, index, role): source_index = self.mapToSource(index) - source_data = self.sourceModel().data(source_index, role) - state_col = self.sourceModel().column_types.index('state') - state_index = self.sourceModel().index(source_index.row(), state_col) - state_data = self.sourceModel().data(state_index, Qt.DisplayRole) + model = self.sourceModel() + source_data = model.data(source_index, role) + state_col = model.column_types.index('state') + state_index = model.index(source_index.row(), state_col) + state_data = model.data(state_index, Qt.DisplayRole) if role == Qt.DisplayRole: - if source_index.column() == self.sourceModel().column_types.index('uid'): + if source_index.column() == model.column_types.index('uid'): return source_data - if source_index.column() == self.sourceModel().column_types.index('date'): + if source_index.column() == model.column_types.index('date'): date = QDateTime.fromTime_t(source_data) return date.date() - if source_index.column() == self.sourceModel().column_types.index('payment') or \ - source_index.column() == self.sourceModel().column_types.index('deposit'): + if source_index.column() == model.column_types.index('payment') or \ + source_index.column() == model.column_types.index('deposit'): if source_data is not "": amount_ref = self.account.units_to_diff_ref(source_data, self.community) - - if type(amount_ref) is int: - formatter = "{0}" + if isinstance(amount_ref, int): + return QLocale().toString(amount_ref) else: - formatter = "{0:.2f}" - - return formatter.format(amount_ref) + return QLocale().toString(amount_ref, 'f', 2) if role == Qt.FontRole: font = QFont() @@ -103,15 +123,20 @@ class TxFilterProxyModel(QSortFilterProxyModel): return QColor(Qt.blue) if role == Qt.TextAlignmentRole: - if source_index.column() == self.sourceModel().column_types.index('deposit') or source_index.column() == self.sourceModel().column_types.index('payment'): + if source_index.column() == self.sourceModel().column_types.index( + 'deposit') or source_index.column() == self.sourceModel().column_types.index('payment'): return Qt.AlignRight | Qt.AlignVCenter if source_index.column() == self.sourceModel().column_types.index('date'): return Qt.AlignCenter + + if role == Qt.ToolTipRole: + if source_index.column() == self.sourceModel().column_types.index('date'): + return QDateTime.fromTime_t(source_data).toString(Qt.SystemLocaleLongDate) + return source_data class HistoryTableModel(QAbstractTableModel): - ''' A Qt abstract item model to display communities in a tree ''' @@ -124,6 +149,8 @@ class HistoryTableModel(QAbstractTableModel): self.account = account self.community = community self.account.referential + self.transfers_data = [] + self.refresh_transfers() self.column_types = ( 'date', @@ -135,34 +162,18 @@ class HistoryTableModel(QAbstractTableModel): ) self.column_headers = ( - 'Date', - 'UID/Public key', - 'Payment', - 'Deposit', - 'Comment', - 'State' + self.tr('Date'), + self.tr('UID/Public key'), + self.tr('Payment'), + self.tr('Deposit'), + self.tr('Comment'), + self.tr('State') ) @property def transfers(self): return self.account.transfers(self.community) - def rowCount(self, parent): - return len(self.transfers) - - def columnCount(self, parent): - return len(self.column_types) - - def headerData(self, section, orientation, role): - if role == Qt.DisplayRole: - if self.column_types[section] == 'payment' or self.column_types[section] == 'deposit': - return '{:}\n({:})'.format( - self.column_headers[section], - self.account.diff_ref_name(self.community.short_currency) - ) - - return self.column_headers[section] - def data_received(self, transfer): amount = transfer.metadata['amount'] comment = "" @@ -183,7 +194,6 @@ class HistoryTableModel(QAbstractTableModel): comment = "" if transfer.txdoc: comment = transfer.txdoc.comment - if transfer.metadata['receiver_uid'] != "": receiver = transfer.metadata['receiver_uid'] else: @@ -195,6 +205,32 @@ class HistoryTableModel(QAbstractTableModel): return (date_ts, receiver, amount, "", comment, transfer.state) + def refresh_transfers(self): + self.beginResetModel() + self.transfers_data = [] + for transfer in self.transfers: + if type(transfer) is Received: + self.transfers_data.append(self.data_received(transfer)) + else: + self.transfers_data.append(self.data_sent(transfer)) + self.endResetModel() + + def rowCount(self, parent): + return len(self.transfers) + + def columnCount(self, parent): + return len(self.column_types) + + def headerData(self, section, orientation, role): + if role == Qt.DisplayRole: + if self.column_types[section] == 'payment' or self.column_types[section] == 'deposit': + return '{:}\n({:})'.format( + self.column_headers[section], + self.account.diff_ref_name(self.community.short_currency) + ) + + return self.column_headers[section] + def data(self, index, role): row = index.row() col = index.column() @@ -202,12 +238,11 @@ class HistoryTableModel(QAbstractTableModel): if not index.isValid(): return QVariant() - transfer = self.transfers[row] if role == Qt.DisplayRole: - if type(transfer) is Received: - return self.data_received(transfer)[col] - else: - return self.data_sent(transfer)[col] + return self.transfers_data[row][col] + + if role == Qt.ToolTipRole and col == 0: + return self.transfers[row].metadata['time'] def flags(self, index): return Qt.ItemIsSelectable | Qt.ItemIsEnabled -- GitLab