electrum

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

commit 93250b10417299e8b8c6681df8cb5b4120d0f582
parent b8a72180c7a5d3198b2f8d299d9247b8eabda952
Author: ThomasV <thomasv@gitorious>
Date:   Sat,  4 Apr 2015 20:59:57 +0200

gui simplification

Diffstat:
Agui/qt/history_widget.py | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mgui/qt/main_window.py | 97+++++++++----------------------------------------------------------------------
Mgui/qt/util.py | 52+++++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 159 insertions(+), 90 deletions(-)

diff --git a/gui/qt/history_widget.py b/gui/qt/history_widget.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python +# +# Electrum - lightweight Bitcoin client +# Copyright (C) 2015 Thomas Voegtlin +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +import webbrowser + +from util import * +from electrum.i18n import _ +from electrum.util import format_satoshis, format_time +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')], [40, 140, None, 140, 140]) + self.config = self.parent.config + + def update(self, h): + self.wallet = self.parent.wallet + item = self.currentItem() + current_tx = item.data(0, Qt.UserRole).toString() if item else None + 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") + 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.setFont(3, QFont(MONOSPACE_FONT)) + item.setFont(4, QFont(MONOSPACE_FONT)) + if value < 0: + item.setForeground(3, 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) + self.insertTopLevelItem(0, item) + if current_tx == tx_hash: + self.setCurrentItem(item) + + run_hook('history_tab_update') + + + def create_menu(self, position): + self.selectedIndexes() + item = self.currentItem() + be = self.config.get('block_explorer', 'Blockchain.info') + if be == 'Blockchain.info': + block_explorer = 'https://blockchain.info/tx/' + elif be == 'Blockr.io': + block_explorer = 'https://blockr.io/tx/info/' + elif be == 'Insight.is': + block_explorer = 'http://live.insight.is/tx/' + elif be == "Blocktrail.com": + block_explorer = 'https://www.blocktrail.com/BTC/tx/' + if not item: + return + tx_hash = str(item.data(0, Qt.UserRole).toString()) + if not tx_hash: + return + menu = QMenu() + menu.addAction(_("Copy ID to Clipboard"), lambda: self.parent.app.clipboard().setText(tx_hash)) + menu.addAction(_("Details"), lambda: self.parent.show_transaction(self.wallet.transactions.get(tx_hash))) + menu.addAction(_("Edit description"), lambda: self.edit_label(item, 2)) + menu.addAction(_("View on block explorer"), lambda: webbrowser.open(block_explorer + tx_hash)) + menu.exec_(self.viewport().mapToGlobal(position)) + diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py @@ -556,41 +556,6 @@ class ElectrumWindow(QMainWindow): d = transaction_dialog.TxDialog(tx, self) d.exec_() - def edit_label(self, is_recv): - l = self.address_list if is_recv else self.contacts_list - item = l.currentItem() - item.setFlags(Qt.ItemIsEditable|Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled) - l.editItem( item, 1 ) - item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled) - - def address_label_clicked(self, item, column, l, column_addr, column_label): - if column == column_label and item.isSelected(): - is_editable = item.data(0, 32).toBool() - if not is_editable: - return - addr = unicode( item.text(column_addr) ) - label = unicode( item.text(column_label) ) - item.setFlags(Qt.ItemIsEditable|Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled) - l.editItem( item, column ) - item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled) - - def address_label_changed(self, item, column, l, column_addr, column_label): - if column == column_label: - addr = unicode( item.text(column_addr) ) - text = unicode( item.text(column_label) ) - is_editable = item.data(0, 32).toBool() - if not is_editable: - return - changed = self.wallet.set_label(addr, text) - if changed: - self.update_history_tab() - self.update_completions() - self.current_item_changed(item) - run_hook('item_changed', item, column) - - def current_item_changed(self, a): - run_hook('current_item_changed', a) - def update_history_tab(self): domain = self.wallet.get_account_addresses(self.current_account) h = self.wallet.get_history(domain) @@ -645,11 +610,9 @@ class ElectrumWindow(QMainWindow): grid.setRowStretch(6, 1) self.receive_requests_label = QLabel(_('Saved Requests')) - self.receive_list = MyTreeWidget(self) - self.receive_list.customContextMenuRequested.connect(self.receive_list_menu) + self.receive_list = MyTreeWidget(self, self.receive_list_menu, [_('Date'), _('Account'), _('Address'), _('Message'), _('Amount')], []) self.receive_list.currentItemChanged.connect(self.receive_item_changed) self.receive_list.itemClicked.connect(self.receive_item_changed) - self.receive_list.setHeaderLabels( [_('Date'), _('Account'), _('Address'), _('Message'), _('Amount')] ) self.receive_list.setSortingEnabled(True) self.receive_list.setColumnWidth(0, 180) self.receive_list.hideColumn(1) # the update will show it if necessary @@ -843,14 +806,9 @@ class ElectrumWindow(QMainWindow): self.from_label = QLabel(_('From')) grid.addWidget(self.from_label, 3, 0) - self.from_list = MyTreeWidget(self) - self.from_list.setColumnCount(2) - self.from_list.setColumnWidth(0, 350) - self.from_list.setColumnWidth(1, 50) + self.from_list = MyTreeWidget(self, self.from_list_menu, ['',''], [350, 50]) self.from_list.setHeaderHidden(True) self.from_list.setMaximumHeight(80) - self.from_list.setContextMenuPolicy(Qt.CustomContextMenu) - self.from_list.customContextMenuRequested.connect(self.from_list_menu) grid.addWidget(self.from_list, 3, 1, 1, 3) self.set_pay_from([]) @@ -1242,13 +1200,7 @@ class ElectrumWindow(QMainWindow): self.wallet.freeze(addr) self.update_address_tab() - - - def create_list_tab(self, headers): - "generic tab creation method" - l = MyTreeWidget(self) - l.setColumnCount( len(headers) ) - l.setHeaderLabels( headers ) + def create_list_tab(self, l): w = QWidget() vbox = QVBoxLayout() w.setLayout(vbox) @@ -1257,52 +1209,23 @@ class ElectrumWindow(QMainWindow): vbox.addWidget(l) buttons = QWidget() vbox.addWidget(buttons) - return l, w + return w def create_addresses_tab(self): - column_width = [370, 200, 130] - l, w = self.create_list_tab([ _('Address'), _('Label'), _('Balance'), _('Tx')]) - l.header().setResizeMode(1, QHeaderView.Stretch); - l.header().setStretchLastSection(False) - for i,width in enumerate(column_width): - l.setColumnWidth(i, width) - l.setContextMenuPolicy(Qt.CustomContextMenu) - l.customContextMenuRequested.connect(self.create_receive_menu) + l = MyTreeWidget(self, self.create_receive_menu, [ _('Address'), _('Label'), _('Balance'), _('Tx')], [370, None, 130]) l.setSelectionMode(QAbstractItemView.ExtendedSelection) - l.itemDoubleClicked.connect(lambda a, b: self.address_label_clicked(a,b,l,0,1)) - l.itemChanged.connect(lambda a,b: self.address_label_changed(a,b,l,0,1)) - l.currentItemChanged.connect(lambda a,b: self.current_item_changed(a)) self.address_list = l - return w + return self.create_list_tab(l) def create_contacts_tab(self): - column_width = [350,330] - l, w = self.create_list_tab([_('Address'), _('Label'), _('Tx')]) - l.header().setResizeMode(1, QHeaderView.Stretch); - l.header().setStretchLastSection(False) - l.setContextMenuPolicy(Qt.CustomContextMenu) - l.customContextMenuRequested.connect(self.create_contact_menu) - for i,width in enumerate(column_width): - l.setColumnWidth(i, width) - l.itemDoubleClicked.connect(lambda a, b: self.address_label_clicked(a,b,l,0,1)) - l.itemChanged.connect(lambda a,b: self.address_label_changed(a,b,l,0,1)) + l = MyTreeWidget(self, self.create_contact_menu, [_('Address'), _('Label'), _('Tx')], [350, None]) self.contacts_list = l - return w - + return self.create_list_tab(l) def create_invoices_tab(self): - l, w = self.create_list_tab([_('Date'), _('Requestor'), _('Memo'), _('Amount'), _('Status')]) - l.setColumnWidth(0, 150) - l.setColumnWidth(1, 150) - l.setColumnWidth(3, 150) - l.setColumnWidth(4, 40) - h = l.header() - h.setStretchLastSection(False) - h.setResizeMode(2, QHeaderView.Stretch) - l.setContextMenuPolicy(Qt.CustomContextMenu) - l.customContextMenuRequested.connect(self.create_invoice_menu) + l = MyTreeWidget(self, self.create_invoice_menu, [_('Date'), _('Requestor'), _('Memo'), _('Amount'), _('Status')], [150, 150, None, 150, 40]) self.invoices_list = l - return w + return self.create_list_tab(l) def update_invoices_tab(self): invoices = self.wallet.storage.get('invoices', {}) diff --git a/gui/qt/util.py b/gui/qt/util.py @@ -253,16 +253,34 @@ def filename_field(parent, config, defaultname, select_msg): class MyTreeWidget(QTreeWidget): - def __init__(self, parent): + def __init__(self, parent, create_menu, headers, column_width): QTreeWidget.__init__(self, parent) + self.parent = parent + self.setColumnCount(len(headers)) + self.setHeaderLabels(headers) + self.header().setStretchLastSection(False) self.setContextMenuPolicy(Qt.CustomContextMenu) self.itemActivated.connect(self.on_activated) + self.customContextMenuRequested.connect(create_menu) # extend the syntax for consistency self.addChild = self.addTopLevelItem self.insertChild = self.insertTopLevelItem + # editable column + self.is_edit = False + self.edit_column = None + self.itemDoubleClicked.connect(self.edit_label) + self.itemChanged.connect(self.label_changed) + # set column width + for i, width in enumerate(column_width): + if width is None: + self.header().setResizeMode(i, QHeaderView.Stretch) + self.edit_column = i + else: + self.setColumnWidth(i, width) def on_activated(self, item): - if not item: return + if not item: + return for i in range(0,self.viewport().height()/5): if self.itemAt(QPoint(0,i*5)) == item: break @@ -273,7 +291,35 @@ class MyTreeWidget(QTreeWidget): break self.emit(SIGNAL('customContextMenuRequested(const QPoint&)'), QPoint(50, i*5 + j - 1)) - + def edit_label(self, item, column): + if column==self.edit_column and item.isSelected(): + text = unicode(item.text(column)) + tx_hash = str(item.data(0, Qt.UserRole).toString()) + self.is_edit = True + if text == self.parent.wallet.get_default_label(tx_hash): + item.setText(column, '') + item.setFlags(Qt.ItemIsEditable|Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled) + self.editItem(item, column) + item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled) + self.is_edit = False + + def label_changed(self, item, column): + if self.is_edit: + return + self.is_edit = True + key = str(item.data(0, Qt.UserRole).toString()) + text = unicode(item.text(self.edit_column)) + changed = self.parent.wallet.set_label(key, text) + if text: + item.setForeground(self.edit_column, QBrush(QColor('black'))) + else: + text = self.wallet.get_default_label(key) + item.setText(self.edit_column, text) + item.setForeground(self.edit_column, QBrush(QColor('gray'))) + self.is_edit = False + if changed: + self.parent.update_history_tab() + self.parent.update_completions() if __name__ == "__main__":