gui simplification
This commit is contained in:
parent
b8a72180c7
commit
93250b1041
|
@ -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))
|
||||
|
|
@ -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', {})
|
||||
|
|
|
@ -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__":
|
||||
|
|
Loading…
Reference in New Issue