Improved in network callbacks:
* Pass arguments * Don't redraw history when a tx is verified. * Fix new tx notifications.
This commit is contained in:
parent
438bc94dce
commit
bfae04e6f0
|
@ -28,10 +28,27 @@ from electrum.plugins import run_hook
|
||||||
class HistoryWidget(MyTreeWidget):
|
class HistoryWidget(MyTreeWidget):
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
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.config = self.parent.config
|
||||||
self.setSortingEnabled(False)
|
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):
|
def update(self, h):
|
||||||
self.wallet = self.parent.wallet
|
self.wallet = self.parent.wallet
|
||||||
item = self.currentItem()
|
item = self.currentItem()
|
||||||
|
@ -39,41 +56,35 @@ class HistoryWidget(MyTreeWidget):
|
||||||
self.clear()
|
self.clear()
|
||||||
for item in h:
|
for item in h:
|
||||||
tx_hash, conf, value, timestamp, balance = item
|
tx_hash, conf, value, timestamp, balance = item
|
||||||
time_str = _("unknown")
|
|
||||||
if conf is None and timestamp is None:
|
if conf is None and timestamp is None:
|
||||||
continue # skip history in offline mode
|
continue # skip history in offline mode
|
||||||
if conf > 0:
|
icon, time_str = self.get_icon(conf, timestamp)
|
||||||
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")
|
|
||||||
v_str = self.parent.format_amount(value, True, whitespaces=True)
|
v_str = self.parent.format_amount(value, True, whitespaces=True)
|
||||||
balance_str = self.parent.format_amount(balance, whitespaces=True)
|
balance_str = self.parent.format_amount(balance, whitespaces=True)
|
||||||
label, is_default_label = self.wallet.get_label(tx_hash)
|
label, is_default_label = self.wallet.get_label(tx_hash)
|
||||||
item = QTreeWidgetItem( [ '', time_str, label, v_str, balance_str] )
|
item = QTreeWidgetItem(['', tx_hash, time_str, label, v_str, balance_str])
|
||||||
item.setFont(2, QFont(MONOSPACE_FONT))
|
item.setIcon(0, icon)
|
||||||
item.setFont(3, QFont(MONOSPACE_FONT))
|
item.setFont(3, QFont(MONOSPACE_FONT))
|
||||||
item.setFont(4, QFont(MONOSPACE_FONT))
|
item.setFont(4, QFont(MONOSPACE_FONT))
|
||||||
|
item.setFont(5, QFont(MONOSPACE_FONT))
|
||||||
if value < 0:
|
if value < 0:
|
||||||
item.setForeground(3, QBrush(QColor("#BC1E1E")))
|
item.setForeground(4, QBrush(QColor("#BC1E1E")))
|
||||||
if tx_hash:
|
if tx_hash:
|
||||||
item.setData(0, Qt.UserRole, tx_hash)
|
item.setData(0, Qt.UserRole, tx_hash)
|
||||||
if is_default_label:
|
if is_default_label:
|
||||||
item.setForeground(2, QBrush(QColor('grey')))
|
item.setForeground(3, QBrush(QColor('grey')))
|
||||||
item.setIcon(0, icon)
|
|
||||||
self.insertTopLevelItem(0, item)
|
self.insertTopLevelItem(0, item)
|
||||||
if current_tx == tx_hash:
|
if current_tx == tx_hash:
|
||||||
self.setCurrentItem(item)
|
self.setCurrentItem(item)
|
||||||
|
|
||||||
run_hook('history_tab_update')
|
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):
|
def create_menu(self, position):
|
||||||
self.selectedIndexes()
|
self.selectedIndexes()
|
||||||
|
|
|
@ -792,9 +792,9 @@ class MiniDriver(QObject):
|
||||||
self.network = main_window.network
|
self.network = main_window.network
|
||||||
self.window = mini_window
|
self.window = mini_window
|
||||||
|
|
||||||
if self.network:
|
#if self.network:
|
||||||
self.network.register_callback('updated',self.update_callback)
|
# self.network.register_callback('updated',self.update_callback)
|
||||||
self.network.register_callback('status', self.update_callback)
|
# self.network.register_callback('status', self.update_callback)
|
||||||
|
|
||||||
self.state = None
|
self.state = None
|
||||||
|
|
||||||
|
|
|
@ -163,23 +163,19 @@ class ElectrumWindow(QMainWindow):
|
||||||
for i in range(tabs.count()):
|
for i in range(tabs.count()):
|
||||||
QShortcut(QKeySequence("Alt+" + str(i + 1)), self, lambda i=i: tabs.setCurrentIndex(i))
|
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_ok'), self.payment_request_ok)
|
||||||
self.connect(self, QtCore.SIGNAL('payment_request_error'), self.payment_request_error)
|
self.connect(self, QtCore.SIGNAL('payment_request_error'), self.payment_request_error)
|
||||||
self.labelsChanged.connect(self.update_tabs)
|
self.labelsChanged.connect(self.update_tabs)
|
||||||
|
|
||||||
self.history_list.setFocus(True)
|
self.history_list.setFocus(True)
|
||||||
|
|
||||||
# network callbacks
|
# network callbacks
|
||||||
if self.network:
|
if self.network:
|
||||||
self.network.register_callback('updated', lambda: self.need_update.set())
|
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('new_transaction', self.new_transaction)
|
||||||
self.network.register_callback('status', lambda: self.emit(QtCore.SIGNAL('update_status')))
|
self.register_callback('status', self.update_status)
|
||||||
self.network.register_callback('new_transaction', lambda: self.emit(QtCore.SIGNAL('transaction_signal')))
|
self.register_callback('close', self.close)
|
||||||
self.network.register_callback('stop', lambda: self.emit(QtCore.SIGNAL('stop')))
|
self.register_callback('banner', self.console.showMessage)
|
||||||
|
self.register_callback('verified', self.history_list.update_item)
|
||||||
|
|
||||||
# set initial message
|
# set initial message
|
||||||
self.console.showMessage(self.network.banner)
|
self.console.showMessage(self.network.banner)
|
||||||
|
@ -190,6 +186,14 @@ class ElectrumWindow(QMainWindow):
|
||||||
self.pluginsdialog = None
|
self.pluginsdialog = None
|
||||||
self.fetch_alias()
|
self.fetch_alias()
|
||||||
self.require_fee_update = False
|
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):
|
def fetch_alias(self):
|
||||||
self.alias_info = None
|
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>")
|
_("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):
|
def notify_transactions(self):
|
||||||
if not self.network or not self.network.is_connected():
|
if not self.network or not self.network.is_connected():
|
||||||
return
|
return
|
||||||
|
|
||||||
print_error("Notifying GUI")
|
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
|
# 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):
|
if(tx_amount >= 3):
|
||||||
total_amount = 0
|
total_amount = 0
|
||||||
for tx in self.network.pending_transactions_for_notifications:
|
for tx in self.tx_notifications:
|
||||||
is_relevant, is_mine, v, fee = self.wallet.get_tx_value(tx)
|
is_relevant, is_mine, v, fee = self.wallet.get_wallet_delta(tx)
|
||||||
if(v > 0):
|
if(v > 0):
|
||||||
total_amount += v
|
total_amount += v
|
||||||
|
|
||||||
self.notify(_("%(txs)s new transactions received. Total amount received in the new transactions %(amount)s %(unit)s") \
|
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()})
|
% { 'txs' : tx_amount, 'amount' : self.format_amount(total_amount), 'unit' : self.base_unit()})
|
||||||
|
self.tx_notifications = []
|
||||||
self.network.pending_transactions_for_notifications = []
|
|
||||||
else:
|
else:
|
||||||
for tx in self.network.pending_transactions_for_notifications:
|
for tx in self.tx_notifications:
|
||||||
if tx:
|
if tx:
|
||||||
self.network.pending_transactions_for_notifications.remove(tx)
|
self.tx_notifications.remove(tx)
|
||||||
is_relevant, is_mine, v, fee = self.wallet.get_tx_value(tx)
|
is_relevant, is_mine, v, fee = self.wallet.get_wallet_delta(tx)
|
||||||
if(v > 0):
|
if(v > 0):
|
||||||
self.notify(_("New transaction received. %(amount)s %(unit)s") % { 'amount' : self.format_amount(v), 'unit' : self.base_unit()})
|
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):
|
def do_search(self, t):
|
||||||
i = self.tabs.currentIndex()
|
i = self.tabs.currentIndex()
|
||||||
if i == 0:
|
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:
|
elif i == 1:
|
||||||
self.invoices_list.filter(t, [0, 1, 2, 3]) # Date, Requestor, Description, Amount
|
self.invoices_list.filter(t, [0, 1, 2, 3]) # Date, Requestor, Description, Amount
|
||||||
elif i == 2:
|
elif i == 2:
|
||||||
|
|
|
@ -40,7 +40,6 @@ class NetworkProxy(util.DaemonThread):
|
||||||
self.subscriptions = {}
|
self.subscriptions = {}
|
||||||
self.debug = False
|
self.debug = False
|
||||||
self.lock = threading.Lock()
|
self.lock = threading.Lock()
|
||||||
self.pending_transactions_for_notifications = []
|
|
||||||
self.callbacks = {}
|
self.callbacks = {}
|
||||||
|
|
||||||
if socket:
|
if socket:
|
||||||
|
@ -100,7 +99,10 @@ class NetworkProxy(util.DaemonThread):
|
||||||
self.servers = value
|
self.servers = value
|
||||||
elif key == 'interfaces':
|
elif key == 'interfaces':
|
||||||
self.interfaces = value
|
self.interfaces = value
|
||||||
self.trigger_callback(key)
|
if key in ['status', 'updated']:
|
||||||
|
self.trigger_callback(key)
|
||||||
|
else:
|
||||||
|
self.trigger_callback(key, (value,))
|
||||||
return
|
return
|
||||||
|
|
||||||
msg_id = response.get('id')
|
msg_id = response.get('id')
|
||||||
|
@ -227,8 +229,8 @@ class NetworkProxy(util.DaemonThread):
|
||||||
self.callbacks[event] = []
|
self.callbacks[event] = []
|
||||||
self.callbacks[event].append(callback)
|
self.callbacks[event].append(callback)
|
||||||
|
|
||||||
def trigger_callback(self, event):
|
def trigger_callback(self, event, params=()):
|
||||||
with self.lock:
|
with self.lock:
|
||||||
callbacks = self.callbacks.get(event,[])[:]
|
callbacks = self.callbacks.get(event,[])[:]
|
||||||
if callbacks:
|
if callbacks:
|
||||||
[callback() for callback in callbacks]
|
[callback(*params) for callback in callbacks]
|
||||||
|
|
|
@ -126,16 +126,14 @@ class WalletSynchronizer():
|
||||||
except Exception:
|
except Exception:
|
||||||
self.print_msg("cannot deserialize transaction, skipping", tx_hash)
|
self.print_msg("cannot deserialize transaction, skipping", tx_hash)
|
||||||
return
|
return
|
||||||
|
|
||||||
self.wallet.receive_tx_callback(tx_hash, tx, tx_height)
|
self.wallet.receive_tx_callback(tx_hash, tx, tx_height)
|
||||||
self.requested_tx.remove((tx_hash, tx_height))
|
self.requested_tx.remove((tx_hash, tx_height))
|
||||||
self.print_error("received tx:", tx_hash, len(tx.raw))
|
self.print_error("received tx:", tx_hash, len(tx.raw))
|
||||||
|
# callbacks
|
||||||
|
self.network.trigger_callback('new_transaction', (tx,))
|
||||||
if not self.requested_tx:
|
if not self.requested_tx:
|
||||||
self.network.trigger_callback('updated')
|
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):
|
def request_missing_txs(self, hist):
|
||||||
# "hist" is a list of [tx_hash, tx_height] lists
|
# "hist" is a list of [tx_hash, tx_height] lists
|
||||||
|
|
|
@ -424,7 +424,9 @@ class Abstract_Wallet(object):
|
||||||
with self.lock:
|
with self.lock:
|
||||||
self.verified_tx[tx_hash] = info # (tx_height, timestamp, pos)
|
self.verified_tx[tx_hash] = info # (tx_height, timestamp, pos)
|
||||||
self.storage.put('verified_tx3', self.verified_tx, True)
|
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):
|
def get_unverified_txs(self):
|
||||||
'''Returns a list of tuples (tx_hash, height) that are unverified and not beyond local height'''
|
'''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):
|
def receive_tx_callback(self, tx_hash, tx, tx_height):
|
||||||
self.add_transaction(tx_hash, tx)
|
self.add_transaction(tx_hash, tx)
|
||||||
#self.network.pending_transactions_for_notifications.append(tx)
|
|
||||||
self.add_unverified_tx(tx_hash, tx_height)
|
self.add_unverified_tx(tx_hash, tx_height)
|
||||||
|
|
||||||
|
|
||||||
def receive_history_callback(self, addr, hist):
|
def receive_history_callback(self, addr, hist):
|
||||||
|
|
||||||
with self.lock:
|
with self.lock:
|
||||||
old_hist = self.history.get(addr, [])
|
old_hist = self.history.get(addr, [])
|
||||||
for tx_hash, height in old_hist:
|
for tx_hash, height in old_hist:
|
||||||
|
|
Loading…
Reference in New Issue