electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit bfae04e6f00579645a8f970bc4604fdc400b48ca
parent 438bc94dcedcede8aa657d0b162a888f78f7ea01
Author: ThomasV <thomasv@gitorious>
Date:   Sun, 16 Aug 2015 11:35:39 +0200

Improved in network callbacks:
 * Pass arguments
 * Don't redraw history when a tx is verified.
 * Fix new tx notifications.

Diffstat:
Mgui/qt/history_widget.py | 51+++++++++++++++++++++++++++++++--------------------
Mgui/qt/lite_window.py | 6+++---
Mgui/qt/main_window.py | 49+++++++++++++++++++++++++++----------------------
Mlib/network_proxy.py | 10++++++----
Mlib/synchronizer.py | 8+++-----
Mlib/wallet.py | 6+++---
6 files changed, 73 insertions(+), 57 deletions(-)

diff --git a/gui/qt/history_widget.py b/gui/qt/history_widget.py @@ -28,10 +28,27 @@ from electrum.plugins import run_hook class HistoryWidget(MyTreeWidget): def __init__(self, parent=None): - MyTreeWidget.__init__(self, parent, self.create_menu, [ '', _('Date'), _('Description') , _('Amount'), _('Balance')], 2) + MyTreeWidget.__init__(self, parent, self.create_menu, ['', '', _('Date'), _('Description') , _('Amount'), _('Balance')], 3) + self.setColumnHidden(1, True) self.config = self.parent.config self.setSortingEnabled(False) + def get_icon(self, conf, timestamp): + time_str = _("unknown") + if conf > 0: + time_str = format_time(timestamp) + if conf == -1: + time_str = 'unverified' + icon = QIcon(":icons/unconfirmed.png") + elif conf == 0: + time_str = 'pending' + icon = QIcon(":icons/unconfirmed.png") + elif conf < 6: + icon = QIcon(":icons/clock%d.png"%conf) + else: + icon = QIcon(":icons/confirmed.png") + return icon, time_str + def update(self, h): self.wallet = self.parent.wallet item = self.currentItem() @@ -39,41 +56,35 @@ class HistoryWidget(MyTreeWidget): self.clear() for item in h: tx_hash, conf, value, timestamp, balance = item - time_str = _("unknown") if conf is None and timestamp is None: continue # skip history in offline mode - if conf > 0: - time_str = format_time(timestamp) - if conf == -1: - time_str = 'unverified' - icon = QIcon(":icons/unconfirmed.png") - elif conf == 0: - time_str = 'pending' - icon = QIcon(":icons/unconfirmed.png") - elif conf < 6: - icon = QIcon(":icons/clock%d.png"%conf) - else: - icon = QIcon(":icons/confirmed.png") + icon, time_str = self.get_icon(conf, timestamp) v_str = self.parent.format_amount(value, True, whitespaces=True) balance_str = self.parent.format_amount(balance, whitespaces=True) label, is_default_label = self.wallet.get_label(tx_hash) - item = QTreeWidgetItem( [ '', time_str, label, v_str, balance_str] ) - item.setFont(2, QFont(MONOSPACE_FONT)) + item = QTreeWidgetItem(['', tx_hash, time_str, label, v_str, balance_str]) + item.setIcon(0, icon) item.setFont(3, QFont(MONOSPACE_FONT)) item.setFont(4, QFont(MONOSPACE_FONT)) + item.setFont(5, QFont(MONOSPACE_FONT)) if value < 0: - item.setForeground(3, QBrush(QColor("#BC1E1E"))) + item.setForeground(4, QBrush(QColor("#BC1E1E"))) if tx_hash: item.setData(0, Qt.UserRole, tx_hash) if is_default_label: - item.setForeground(2, QBrush(QColor('grey'))) - item.setIcon(0, icon) + item.setForeground(3, QBrush(QColor('grey'))) self.insertTopLevelItem(0, item) if current_tx == tx_hash: self.setCurrentItem(item) - run_hook('history_tab_update') + def update_item(self, tx_hash, conf, timestamp): + icon, time_str = self.get_icon(conf, timestamp) + items = self.findItems(tx_hash, Qt.UserRole|Qt.MatchContains|Qt.MatchRecursive, column=1) + if items: + item = items[0] + item.setIcon(0, icon) + item.setText(2, time_str) def create_menu(self, position): self.selectedIndexes() diff --git a/gui/qt/lite_window.py b/gui/qt/lite_window.py @@ -792,9 +792,9 @@ class MiniDriver(QObject): self.network = main_window.network self.window = mini_window - if self.network: - self.network.register_callback('updated',self.update_callback) - self.network.register_callback('status', self.update_callback) + #if self.network: + # self.network.register_callback('updated',self.update_callback) + # self.network.register_callback('status', self.update_callback) self.state = None diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py @@ -163,23 +163,19 @@ class ElectrumWindow(QMainWindow): for i in range(tabs.count()): QShortcut(QKeySequence("Alt+" + str(i + 1)), self, lambda i=i: tabs.setCurrentIndex(i)) - self.connect(self, QtCore.SIGNAL('stop'), self.close) - self.connect(self, QtCore.SIGNAL('update_status'), self.update_status) - self.connect(self, QtCore.SIGNAL('banner_signal'), lambda: self.console.showMessage(self.network.banner) ) - self.connect(self, QtCore.SIGNAL('transaction_signal'), lambda: self.notify_transactions() ) self.connect(self, QtCore.SIGNAL('payment_request_ok'), self.payment_request_ok) self.connect(self, QtCore.SIGNAL('payment_request_error'), self.payment_request_error) self.labelsChanged.connect(self.update_tabs) - self.history_list.setFocus(True) # network callbacks if self.network: self.network.register_callback('updated', lambda: self.need_update.set()) - self.network.register_callback('banner', lambda: self.emit(QtCore.SIGNAL('banner_signal'))) - self.network.register_callback('status', lambda: self.emit(QtCore.SIGNAL('update_status'))) - self.network.register_callback('new_transaction', lambda: self.emit(QtCore.SIGNAL('transaction_signal'))) - self.network.register_callback('stop', lambda: self.emit(QtCore.SIGNAL('stop'))) + self.network.register_callback('new_transaction', self.new_transaction) + self.register_callback('status', self.update_status) + self.register_callback('close', self.close) + self.register_callback('banner', self.console.showMessage) + self.register_callback('verified', self.history_list.update_item) # set initial message self.console.showMessage(self.network.banner) @@ -190,6 +186,14 @@ class ElectrumWindow(QMainWindow): self.pluginsdialog = None self.fetch_alias() self.require_fee_update = False + self.tx_notifications = [] + + + def register_callback(self, name, method): + """ run callback in the qt thread """ + self.connect(self, QtCore.SIGNAL(name), method) + self.network.register_callback(name, lambda *params: self.emit(QtCore.SIGNAL(name), *params)) + def fetch_alias(self): self.alias_info = None @@ -461,30 +465,31 @@ class ElectrumWindow(QMainWindow): _("Please report any bugs as issues on github:")+" <a href=\"https://github.com/spesmilo/electrum/issues\">https://github.com/spesmilo/electrum/issues</a>") + def new_transaction(self, tx): + print "new tx", tx + self.tx_notifications.append(tx) + def notify_transactions(self): if not self.network or not self.network.is_connected(): return - print_error("Notifying GUI") - if len(self.network.pending_transactions_for_notifications) > 0: + if len(self.tx_notifications) > 0: # Combine the transactions if there are more then three - tx_amount = len(self.network.pending_transactions_for_notifications) + tx_amount = len(self.tx_notifications) if(tx_amount >= 3): total_amount = 0 - for tx in self.network.pending_transactions_for_notifications: - is_relevant, is_mine, v, fee = self.wallet.get_tx_value(tx) + for tx in self.tx_notifications: + is_relevant, is_mine, v, fee = self.wallet.get_wallet_delta(tx) if(v > 0): total_amount += v - self.notify(_("%(txs)s new transactions received. Total amount received in the new transactions %(amount)s %(unit)s") \ - % { 'txs' : tx_amount, 'amount' : self.format_amount(total_amount), 'unit' : self.base_unit()}) - - self.network.pending_transactions_for_notifications = [] + % { 'txs' : tx_amount, 'amount' : self.format_amount(total_amount), 'unit' : self.base_unit()}) + self.tx_notifications = [] else: - for tx in self.network.pending_transactions_for_notifications: + for tx in self.tx_notifications: if tx: - self.network.pending_transactions_for_notifications.remove(tx) - is_relevant, is_mine, v, fee = self.wallet.get_tx_value(tx) + self.tx_notifications.remove(tx) + is_relevant, is_mine, v, fee = self.wallet.get_wallet_delta(tx) if(v > 0): self.notify(_("New transaction received. %(amount)s %(unit)s") % { 'amount' : self.format_amount(v), 'unit' : self.base_unit()}) @@ -1858,7 +1863,7 @@ class ElectrumWindow(QMainWindow): def do_search(self, t): i = self.tabs.currentIndex() if i == 0: - self.history_list.filter(t, [1, 2, 3]) # Date, Description, Amount + self.history_list.filter(t, [2, 3, 4]) # Date, Description, Amount elif i == 1: self.invoices_list.filter(t, [0, 1, 2, 3]) # Date, Requestor, Description, Amount elif i == 2: diff --git a/lib/network_proxy.py b/lib/network_proxy.py @@ -40,7 +40,6 @@ class NetworkProxy(util.DaemonThread): self.subscriptions = {} self.debug = False self.lock = threading.Lock() - self.pending_transactions_for_notifications = [] self.callbacks = {} if socket: @@ -100,7 +99,10 @@ class NetworkProxy(util.DaemonThread): self.servers = value elif key == 'interfaces': self.interfaces = value - self.trigger_callback(key) + if key in ['status', 'updated']: + self.trigger_callback(key) + else: + self.trigger_callback(key, (value,)) return msg_id = response.get('id') @@ -227,8 +229,8 @@ class NetworkProxy(util.DaemonThread): self.callbacks[event] = [] self.callbacks[event].append(callback) - def trigger_callback(self, event): + def trigger_callback(self, event, params=()): with self.lock: callbacks = self.callbacks.get(event,[])[:] if callbacks: - [callback() for callback in callbacks] + [callback(*params) for callback in callbacks] diff --git a/lib/synchronizer.py b/lib/synchronizer.py @@ -126,16 +126,14 @@ class WalletSynchronizer(): except Exception: self.print_msg("cannot deserialize transaction, skipping", tx_hash) return - self.wallet.receive_tx_callback(tx_hash, tx, tx_height) self.requested_tx.remove((tx_hash, tx_height)) self.print_error("received tx:", tx_hash, len(tx.raw)) + # callbacks + self.network.trigger_callback('new_transaction', (tx,)) if not self.requested_tx: self.network.trigger_callback('updated') - # Updated gets called too many times from other places as - # well; if we used that signal we get the notification - # three times - self.network.trigger_callback("new_transaction") + def request_missing_txs(self, hist): # "hist" is a list of [tx_hash, tx_height] lists diff --git a/lib/wallet.py b/lib/wallet.py @@ -424,7 +424,9 @@ class Abstract_Wallet(object): with self.lock: self.verified_tx[tx_hash] = info # (tx_height, timestamp, pos) self.storage.put('verified_tx3', self.verified_tx, True) - self.network.trigger_callback('updated') + + conf, timestamp = self.get_confirmations(tx_hash) + self.network.trigger_callback('verified', (tx_hash, conf, timestamp)) def get_unverified_txs(self): '''Returns a list of tuples (tx_hash, height) that are unverified and not beyond local height''' @@ -771,12 +773,10 @@ class Abstract_Wallet(object): def receive_tx_callback(self, tx_hash, tx, tx_height): self.add_transaction(tx_hash, tx) - #self.network.pending_transactions_for_notifications.append(tx) self.add_unverified_tx(tx_hash, tx_height) def receive_history_callback(self, addr, hist): - with self.lock: old_hist = self.history.get(addr, []) for tx_hash, height in old_hist: