You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

839 lines
30 KiB

13 years ago
#!/usr/bin/env python
#
# Electrum - lightweight Bitcoin client
# Copyright (C) 2011 thomasv@gitorious
#
# 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 datetime
import thread, time, ast
import pygtk
pygtk.require('2.0')
import gtk, gobject
gtk.gdk.threads_init()
APP_NAME = "Electrum"
def format_satoshis(x):
xx = ("%f"%(x*1e-8)).rstrip('0')
if xx[-1] =='.': xx+="00"
if xx[-2] =='.': xx+="0"
return xx
def numbify(entry, is_int = False):
text = entry.get_text().strip()
s = ''.join([i for i in text if i in '0123456789.'])
entry.set_text(s)
def init_wallet(wallet):
if not wallet.read():
# ask if the user wants to create a new wallet, or recover from a seed.
# if he wants to recover, and nothing is found, do not create wallet
dialog = gtk.Dialog("electrum", parent=None,
flags=gtk.DIALOG_MODAL|gtk.DIALOG_NO_SEPARATOR,
buttons= ("create", 0, "restore",1, "cancel",2) )
label = gtk.Label("Wallet file not found.\nDo you want to create a new wallet,\n or to restore an existing one?" )
label.show()
dialog.vbox.pack_start(label)
dialog.show()
r = dialog.run()
dialog.destroy()
if r==2:
exit(1)
is_recovery = (r==1)
if not is_recovery:
wallet.new_seed(None)
# ask for the server.
run_settings_dialog(wallet, is_create=True, is_recovery=False)
# generate first key
wallet.create_new_address(False, None)
# run a dialog indicating the seed, ask the user to remember it
13 years ago
dialog = gtk.MessageDialog(
parent = None,
flags = gtk.DIALOG_MODAL,
buttons = gtk.BUTTONS_OK,
message_format = "Your secret seed is:\n"+ wallet.seed+ "\n\nPlease keep it in a safe place; if you lose it, you will not be able to restore your wallet." )
dialog.show()
r = dialog.run()
dialog.destroy()
13 years ago
#ask for password
change_password_dialog(wallet, None)
else:
# ask for the server, seed and gap.
run_settings_dialog(wallet, is_create=True, is_recovery=True)
dialog = gtk.MessageDialog(
parent = None,
flags = gtk.DIALOG_MODAL,
buttons = gtk.BUTTONS_CANCEL,
message_format = "Please wait..." )
13 years ago
dialog.show()
def recover_thread( wallet, dialog, password ):
wallet.is_found = wallet.recover( password )
if wallet.is_found:
wallet.save()
gobject.idle_add( dialog.destroy )
thread.start_new_thread( recover_thread, ( wallet, dialog, None ) ) # no password
13 years ago
r = dialog.run()
dialog.destroy()
13 years ago
if r==gtk.RESPONSE_CANCEL: exit(1)
if not wallet.is_found:
show_message("No transactions found for this seed")
13 years ago
def settings_dialog(wallet, is_create, is_recovery):
13 years ago
if is_create:
13 years ago
dialog = gtk.MessageDialog(
parent = None,
flags = gtk.DIALOG_MODAL,
buttons = gtk.BUTTONS_OK_CANCEL,
message_format = "Please indicate the server and port number" if not is_recovery else 'Please enter the seed, the server and gap')
else:
dialog = gtk.Dialog("settings", parent=None,
flags=gtk.DIALOG_MODAL|gtk.DIALOG_NO_SEPARATOR,
buttons= ("cancel", 0, "ok", 1) )
13 years ago
vbox = dialog.vbox
13 years ago
dialog.set_default_response(gtk.RESPONSE_OK)
13 years ago
if is_recovery:
# ask seed, server and gap in the same dialog
seed_box = gtk.HBox()
seed_label = gtk.Label('Seed:')
seed_label.show()
seed_box.pack_start(seed_label)
seed_entry = gtk.Entry()
seed_entry.show()
seed_box.pack_start(seed_entry)
seed_box.show()
vbox.pack_start(seed_box, False, False, 5)
if is_recovery or (not is_create):
gap = gtk.HBox()
gap_label = gtk.Label('Max. gap:')
gap_label.set_size_request(100,10)
gap_label.show()
gap.pack_start(gap_label,False, False, 10)
gap_entry = gtk.Entry()
gap_entry.set_text("%d"%wallet.gap_limit)
gap_entry.connect('changed', numbify, True)
gap_entry.show()
gap.pack_start(gap_entry,False,False, 10)
add_help_button(gap, 'The maximum gap that is allowed between unused addresses in your wallet. During wallet recovery, this parameter is used to decide when to stop the recovery process. If you increase this value, you will need to remember it in order to be able to recover your wallet from seed.')
gap.show()
vbox.pack_start(gap, False,False, 5)
13 years ago
host = gtk.HBox()
host_label = gtk.Label('Server:')
host_label.set_size_request(100,10)
host_label.show()
host.pack_start(host_label,False, False, 10)
host_entry = gtk.Entry()
host_entry.set_text(wallet.host+":%d"%wallet.port)
host_entry.show()
host.pack_start(host_entry,False,False, 10)
add_help_button(host, 'The name and port number of your Bitcoin server, separated by a colon. Example: ecdsa.org:50000')
host.show()
vbox.pack_start(host, False,False, 5)
13 years ago
if not is_create:
fee = gtk.HBox()
fee_entry = gtk.Entry()
13 years ago
fee_label = gtk.Label('Tx. fee:')
fee_label.set_size_request(100,10)
fee_label.show()
fee.pack_start(fee_label,False, False, 10)
fee_entry.set_text("%f"%(wallet.fee))
fee_entry.connect('changed', numbify, False)
fee_entry.show()
fee.pack_start(fee_entry,False,False, 10)
add_help_button(fee, 'Transaction fee. Recommended value:0.005')
fee.show()
vbox.pack_start(fee, False,False, 5)
if not is_create:
return dialog, fee_entry, gap_entry, host_entry
elif is_recovery:
return dialog, seed_entry, gap_entry, host_entry
else:
return dialog, host_entry
13 years ago
def run_settings_dialog( wallet, is_create, is_recovery):
if not is_create:
dialog, fee_entry, gap_entry, host_entry = settings_dialog(wallet, is_create, is_recovery)
elif is_recovery:
dialog, seed_entry, gap_entry, host_entry = settings_dialog(wallet, is_create, is_recovery)
else:
dialog, host_entry, = settings_dialog(wallet, is_create, is_recovery)
13 years ago
dialog.show()
r = dialog.run()
hh = host_entry.get_text()
if is_recovery:
gap = gap_entry.get_text()
seed = seed_entry.get_text()
13 years ago
dialog.destroy()
if r==-6:
exit(1)
13 years ago
try:
a, b = hh.split(':')
wallet.host = a
wallet.port = int(b)
if is_recovery:
wallet.seed = seed
wallet.gap_limit = int(gap)
13 years ago
except:
pass
def show_message(message):
dialog = gtk.MessageDialog(
parent = None,
flags = gtk.DIALOG_MODAL,
buttons = gtk.BUTTONS_CLOSE,
message_format = message )
dialog.show()
dialog.run()
dialog.destroy()
def password_line(label):
password = gtk.HBox()
password_label = gtk.Label(label)
password_label.set_size_request(120,10)
password_label.show()
password.pack_start(password_label,False, False, 10)
password_entry = gtk.Entry()
password_entry.set_visibility(False)
password_entry.show()
password.pack_start(password_entry,False,False, 10)
password.show()
return password, password_entry
def password_dialog():
dialog = gtk.MessageDialog( None, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK_CANCEL, "Your wallet is encrypted.")
dialog.get_image().set_visible(False)
current_pw, current_pw_entry = password_line('Password:')
current_pw_entry.connect("activate", lambda entry, dialog, response: dialog.response(response), dialog, gtk.RESPONSE_OK)
dialog.vbox.pack_start(current_pw, False, True, 0)
dialog.show()
result = dialog.run()
pw = current_pw_entry.get_text()
dialog.destroy()
if result: return pw
def change_password_dialog(wallet, icon):
if icon:
msg = 'Your wallet is encrypted' if wallet.use_encryption else 'Your wallet is not encrypted'
else:
msg = "Please choose a password to encrypt your wallet keys"
dialog = gtk.MessageDialog( None, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK_CANCEL, msg)
13 years ago
if wallet.use_encryption:
13 years ago
current_pw, current_pw_entry = password_line('Current password:')
13 years ago
dialog.vbox.pack_start(current_pw, False, True, 0)
password, password_entry = password_line('New password:')
dialog.vbox.pack_start(password, False, True, 5)
password2, password2_entry = password_line('Confirm password:')
dialog.vbox.pack_start(password2, False, True, 5)
dialog.show()
result = dialog.run()
password = current_pw_entry.get_text() if wallet.use_encryption else None
new_password = password_entry.get_text()
new_password2 = password2_entry.get_text()
dialog.destroy()
13 years ago
if result == gtk.RESPONSE_CANCEL:
13 years ago
return
try:
seed = wallet.pw_decode( wallet.seed, password)
13 years ago
private_keys = ast.literal_eval( wallet.pw_decode( wallet.private_keys, password) )
except:
13 years ago
show_message("Incorrect password")
13 years ago
return
if new_password != new_password2:
show_message("passwords do not match")
return
wallet.use_encryption = (new_password != '')
wallet.seed = wallet.pw_encode( seed, new_password)
13 years ago
wallet.private_keys = wallet.pw_encode( repr( private_keys ), new_password)
wallet.save()
13 years ago
if icon:
if wallet.use_encryption:
icon.set_tooltip_text('wallet is encrypted')
else:
icon.set_tooltip_text('wallet is unencrypted')
13 years ago
def add_help_button(hbox, message):
button = gtk.Button('?')
button.connect("clicked", lambda x: show_message(message))
button.show()
hbox.pack_start(button,False, False)
class MyWindow(gtk.Window): __gsignals__ = dict( mykeypress = (gobject.SIGNAL_RUN_LAST | gobject.SIGNAL_ACTION, None, (str,)) )
gobject.type_register(MyWindow)
gtk.binding_entry_add_signal(MyWindow, gtk.keysyms.W, gtk.gdk.CONTROL_MASK, 'mykeypress', str, 'ctrl+W')
gtk.binding_entry_add_signal(MyWindow, gtk.keysyms.Q, gtk.gdk.CONTROL_MASK, 'mykeypress', str, 'ctrl+Q')
class BitcoinGUI:
def __init__(self, wallet):
self.error = ''
self.wallet = wallet
self.update_time = 0
self.window = MyWindow(gtk.WINDOW_TOPLEVEL)
self.window.set_title(APP_NAME)
self.window.connect("destroy", gtk.main_quit)
self.window.set_border_width(0)
self.window.connect('mykeypress', gtk.main_quit)
self.window.set_default_size(650, 350)
vbox = gtk.VBox()
self.notebook = gtk.Notebook()
self.create_history_tab()
self.create_send_tab()
self.create_recv_tab()
self.create_book_tab()
#self.add_tab( make_settings_box( self.wallet, False), 'Preferences')
self.create_about_tab()
self.notebook.show()
vbox.pack_start(self.notebook, True, True, 2)
# status bar for balance, connection, blocks
self.status_bar = gtk.Statusbar()
vbox.pack_start(self.status_bar, False, False, 0)
self.status_image = gtk.Image()
self.status_image.set_from_stock(gtk.STOCK_YES, gtk.ICON_SIZE_MENU)
self.status_image.set_alignment(True, 0.5 )
self.status_image.show()
13 years ago
self.status_bar.pack_end(self.status_image, False, False)
13 years ago
settings_icon = gtk.Image()
settings_icon.set_from_stock(gtk.STOCK_PREFERENCES, gtk.ICON_SIZE_MENU)
13 years ago
settings_icon.set_alignment(0.5, 0.5)
settings_icon.set_size_request(16,16 )
13 years ago
settings_icon.show()
prefs_button = gtk.Button()
prefs_button.connect("clicked", lambda x: run_settings_dialog(self.wallet, False, False) )
13 years ago
prefs_button.add(settings_icon)
prefs_button.set_tooltip_text("Settings")
13 years ago
prefs_button.set_relief(gtk.RELIEF_NONE)
13 years ago
prefs_button.show()
self.status_bar.pack_end(prefs_button,False,False)
13 years ago
pw_icon = gtk.Image()
pw_icon.set_from_stock(gtk.STOCK_DIALOG_AUTHENTICATION, gtk.ICON_SIZE_MENU)
pw_icon.set_alignment(0.5, 0.5)
pw_icon.set_size_request(16,16 )
pw_icon.show()
password_button = gtk.Button()
password_button.connect("clicked", lambda x: change_password_dialog(self.wallet, pw_icon))
13 years ago
password_button.add(pw_icon)
password_button.set_relief(gtk.RELIEF_NONE)
password_button.show()
self.status_bar.pack_end(password_button,False,False)
13 years ago
self.window.add(vbox)
self.window.show_all()
self.context_id = self.status_bar.get_context_id("statusbar")
self.update_status_bar()
def update_status_bar_thread():
while True:
gobject.idle_add( self.update_status_bar )
time.sleep(0.5)
def update_wallet_thread():
import socket, traceback, sys
while True:
try:
self.wallet.new_session()
except:
self.error = "Not connected"
time.sleep(5)
continue
self.info.set_text( self.wallet.message)
while True:
try:
u = self.wallet.update()
except:
self.error = "Not connected"
print "error"
traceback.print_exc(file=sys.stdout)
break
self.update_time = time.time()
self.error = ''
if u:
self.wallet.save()
gobject.idle_add( self.update_history_tab )
time.sleep(5)
thread.start_new_thread(update_wallet_thread, ())
thread.start_new_thread(update_status_bar_thread, ())
self.notebook.set_current_page(0)
def add_tab(self, page, name):
tab_label = gtk.Label(name)
tab_label.show()
self.notebook.append_page(page, tab_label)
def create_send_tab(self):
page = vbox = gtk.VBox()
page.show()
payto = gtk.HBox()
payto_label = gtk.Label('Pay to:')
payto_label.set_size_request(100,10)
payto_label.show()
payto.pack_start(payto_label, False)
payto_entry = gtk.Entry()
payto_entry.set_size_request(350, 26)
payto_entry.show()
payto.pack_start(payto_entry, False)
vbox.pack_start(payto, False, False, 5)
label = gtk.HBox()
label_label = gtk.Label('Label:')
label_label.set_size_request(100,10)
label_label.show()
label.pack_start(label_label, False)
label_entry = gtk.Entry()
label_entry.set_size_request(350, 26)
label_entry.show()
label.pack_start(label_entry, False)
vbox.pack_start(label, False, False, 5)
amount = gtk.HBox()
amount_label = gtk.Label('Amount:')
amount_label.set_size_request(100,10)
amount_label.show()
amount.pack_start(amount_label, False)
amount_entry = gtk.Entry()
amount_entry.set_size_request(100, 26)
amount_entry.connect('changed', numbify)
amount_entry.show()
amount.pack_start(amount_entry, False)
vbox.pack_start(amount, False, False, 5)
button = gtk.Button("Send")
button.connect("clicked", self.do_send, (payto_entry, label_entry, amount_entry))
button.show()
amount.pack_start(button, False, False, 5)
self.payto_entry = payto_entry
self.payto_amount_entry = amount_entry
self.payto_label_entry = label_entry
self.add_tab(page, 'Send')
def create_about_tab(self):
page = gtk.VBox()
page.show()
self.info = gtk.Label('')
self.info.set_selectable(True)
page.pack_start(self.info)
#tv = gtk.TextView()
#tv.set_editable(False)
#tv.set_cursor_visible(False)
#page.pack_start(tv)
#self.info = tv.get_buffer()
self.add_tab(page, 'Board')
def do_send(self, w, data):
payto_entry, label_entry, amount_entry = data
label = label_entry.get_text()
to_address = payto_entry.get_text()
if not self.wallet.is_valid(to_address):
show_message( "invalid bitcoin address" )
return
try:
amount = float(amount_entry.get_text())
except:
show_message( "invalid amount" )
return
password = password_dialog() if self.wallet.use_encryption else None
status, msg = self.wallet.send( to_address, amount, label, password )
if status:
show_message( "payment sent.\n" + msg )
payto_entry.set_text("")
label_entry.set_text("")
amount_entry.set_text("")
self.update_sending_tab()
13 years ago
else:
show_message( msg )
def treeview_key_press(self, treeview, event):
c = treeview.get_cursor()[0]
if event.keyval == gtk.keysyms.Up:
if c and c[0] == 0:
treeview.parent.grab_focus()
treeview.set_cursor((0,))
elif event.keyval == gtk.keysyms.Return and treeview == self.history_treeview:
tx_hash = self.history_list.get_value( self.history_list.get_iter(c), 0)
tx = self.wallet.tx_history.get(tx_hash)
# print "tx details:\n"+repr(tx)
inputs = '\n-'.join(tx['inputs'])
outputs = '\n-'.join(tx['outputs'])
msg = tx_hash + "\n\ninputs:\n-"+ inputs + "\noutputs:\n-"+ outputs + "\n"
show_message(msg)
return False
def create_history_tab(self):
self.history_list = gtk.ListStore(str, str, str, str, 'gboolean', str, str,str)
treeview = gtk.TreeView(model=self.history_list)
self.history_treeview = treeview
treeview.set_tooltip_column(7)
treeview.show()
treeview.connect('key-press-event', self.treeview_key_press)
tvcolumn = gtk.TreeViewColumn('tx_id')
treeview.append_column(tvcolumn)
cell = gtk.CellRendererText()
tvcolumn.pack_start(cell, False)
tvcolumn.add_attribute(cell, 'text', 0)
tvcolumn.set_visible(False)
tvcolumn = gtk.TreeViewColumn('')
treeview.append_column(tvcolumn)
cell = gtk.CellRendererPixbuf()
tvcolumn.pack_start(cell, False)
tvcolumn.set_attributes(cell, stock_id=1)
tvcolumn = gtk.TreeViewColumn('Date')
treeview.append_column(tvcolumn)
cell = gtk.CellRendererText()
tvcolumn.pack_start(cell, False)
tvcolumn.add_attribute(cell, 'text', 2)
tvcolumn = gtk.TreeViewColumn('Label')
treeview.append_column(tvcolumn)
cell = gtk.CellRendererText()
cell.set_property('foreground', 'grey')
cell.set_property('family', 'monospace')
cell.set_property('editable', True)
def edited_cb(cell, path, new_text, h_list):
tx = h_list.get_value( h_list.get_iter(path), 0)
self.wallet.labels[tx] = new_text
self.wallet.save()
self.update_history_tab()
cell.connect('edited', edited_cb, self.history_list)
def editing_started(cell, entry, path, h_list):
tx = h_list.get_value( h_list.get_iter(path), 0)
if not self.wallet.labels.get(tx): entry.set_text('')
cell.connect('editing-started', editing_started, self.history_list)
tvcolumn.set_expand(True)
tvcolumn.pack_start(cell, True)
tvcolumn.set_attributes(cell, text=3, foreground_set = 4)
tvcolumn = gtk.TreeViewColumn('Amount')
treeview.append_column(tvcolumn)
cell = gtk.CellRendererText()
cell.set_alignment(1, 0.5)
tvcolumn.pack_start(cell, False)
tvcolumn.add_attribute(cell, 'text', 5)
tvcolumn = gtk.TreeViewColumn('Balance')
treeview.append_column(tvcolumn)
cell = gtk.CellRendererText()
cell.set_alignment(1, 0.5)
tvcolumn.pack_start(cell, False)
tvcolumn.add_attribute(cell, 'text', 6)
tvcolumn = gtk.TreeViewColumn('Tooltip')
treeview.append_column(tvcolumn)
cell = gtk.CellRendererText()
tvcolumn.pack_start(cell, False)
tvcolumn.add_attribute(cell, 'text', 7)
tvcolumn.set_visible(False)
scroll = gtk.ScrolledWindow()
scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
scroll.add(treeview)
self.add_tab(scroll, 'History')
self.update_history_tab()
def create_recv_tab(self):
self.recv_list = gtk.ListStore(str, str, str)
self.add_tab( self.make_address_list(True), 'Receive')
self.update_receiving_tab()
def create_book_tab(self):
self.addressbook_list = gtk.ListStore(str, str, str)
self.add_tab( self.make_address_list(False), 'Contacts')
self.update_sending_tab()
def make_address_list(self, is_recv):
liststore = self.recv_list if is_recv else self.addressbook_list
treeview = gtk.TreeView(model= liststore)
treeview.connect('key-press-event', self.treeview_key_press)
treeview.show()
tvcolumn = gtk.TreeViewColumn('Address')
treeview.append_column(tvcolumn)
cell = gtk.CellRendererText()
cell.set_property('family', 'monospace')
tvcolumn.pack_start(cell, True)
tvcolumn.add_attribute(cell, 'text', 0)
tvcolumn = gtk.TreeViewColumn('Label')
tvcolumn.set_expand(True)
treeview.append_column(tvcolumn)
cell = gtk.CellRendererText()
cell.set_property('editable', True)
def edited_cb2(cell, path, new_text, liststore):
address = liststore.get_value( liststore.get_iter(path), 0)
self.wallet.labels[address] = new_text
self.wallet.save()
self.wallet.update_tx_labels()
self.update_receiving_tab()
self.update_sending_tab()
self.update_history_tab()
cell.connect('edited', edited_cb2, liststore)
tvcolumn.pack_start(cell, True)
tvcolumn.add_attribute(cell, 'text', 1)
tvcolumn = gtk.TreeViewColumn('Tx')
treeview.append_column(tvcolumn)
cell = gtk.CellRendererText()
tvcolumn.pack_start(cell, True)
tvcolumn.add_attribute(cell, 'text', 2)
scroll = gtk.ScrolledWindow()
scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
scroll.add(treeview)
hbox = gtk.HBox()
button = gtk.Button("New address")
button.connect("clicked", self.newaddress_dialog, is_recv)
button.show()
hbox.pack_start(button,False)
button = gtk.Button("Copy to clipboard")
def copy2clipboard(w, treeview, liststore):
path, col = treeview.get_cursor()
if path:
address = liststore.get_value( liststore.get_iter(path), 0)
c = gtk.clipboard_get()
c.set_text( address )
button.connect("clicked", copy2clipboard, treeview, liststore)
button.show()
hbox.pack_start(button,False)
if not is_recv:
button = gtk.Button("Pay to")
def payto(w, treeview, liststore):
path, col = treeview.get_cursor()
if path:
address = liststore.get_value( liststore.get_iter(path), 0)
self.payto_entry.set_text( address )
self.notebook.set_current_page(1)
self.payto_amount_entry.grab_focus()
button.connect("clicked", payto, treeview, liststore)
button.show()
hbox.pack_start(button,False)
vbox = gtk.VBox()
vbox.pack_start(scroll,True)
vbox.pack_start(hbox, False)
return vbox
def update_status_bar(self):
c, u = self.wallet.get_balance()
dt = time.time() - self.update_time
if dt < 15:
self.status_image.set_from_stock(gtk.STOCK_YES, gtk.ICON_SIZE_MENU)
self.status_image.set_tooltip_text("Connected to %s.\n%d blocks"%(self.wallet.host, self.wallet.blocks))
else:
self.status_image.set_from_stock(gtk.STOCK_NO, gtk.ICON_SIZE_MENU)
self.status_image.set_tooltip_text("Trying to contact %s.\n%d blocks"%(self.wallet.host, self.wallet.blocks))
text = "Balance: %s "%( format_satoshis(c) )
if u: text += "[+ %s unconfirmed]"%( format_satoshis(u) )
if self.error: text = self.error
self.status_bar.pop(self.context_id)
self.status_bar.push(self.context_id, text)
def update_receiving_tab(self):
self.recv_list.clear()
for address in self.wallet.addresses:
13 years ago
if self.wallet.is_change(address):continue
13 years ago
label = self.wallet.labels.get(address)
n = 0
h = self.wallet.history.get(address)
if h:
for item in h:
if not item['is_in'] : n=n+1
tx = "None" if n==0 else "%d"%n
self.recv_list.prepend((address, label, tx ))
def update_sending_tab(self):
# detect addresses that are not mine in history, add them here...
self.addressbook_list.clear()
for address in self.wallet.addressbook:
label = self.wallet.labels.get(address)
n = 0
for item in self.wallet.tx_history.values():
if address in item['outputs'] : n=n+1
tx = "None" if n==0 else "%d"%n
self.addressbook_list.append((address, label, tx))
def update_history_tab(self):
cursor = self.history_treeview.get_cursor()[0]
self.history_list.clear()
balance = 0
for tx in self.wallet.get_tx_history():
tx_hash = tx['tx_hash']
if tx['height']:
conf = self.wallet.blocks - tx['height'] + 1
time_str = datetime.datetime.fromtimestamp( tx['nTime']).isoformat(' ')[:-3]
conf_icon = gtk.STOCK_APPLY
else:
conf = 0
time_str = 'pending'
conf_icon = gtk.STOCK_EXECUTE
v = tx['value']
balance += v
label = self.wallet.labels.get(tx_hash)
is_default_label = (label == '') or (label is None)
if is_default_label: label = tx['default_label']
tooltip = tx_hash + "\n%d confirmations"%conf
self.history_list.prepend( [tx_hash, conf_icon, time_str, label, is_default_label,
('+' if v>0 else '') + format_satoshis(v), format_satoshis(balance), tooltip] )
if cursor: self.history_treeview.set_cursor( cursor )
def newaddress_dialog(self, w, is_recv):
if not is_recv:
title = "New sending address"
dialog = gtk.Dialog(title, parent=self.window,
flags=gtk.DIALOG_MODAL|gtk.DIALOG_NO_SEPARATOR,
buttons= ("cancel", 0, "ok",1) )
dialog.show()
label = gtk.HBox()
label_label = gtk.Label('Label:')
label_label.set_size_request(120,10)
label_label.show()
label.pack_start(label_label)
label_entry = gtk.Entry()
label_entry.show()
label.pack_start(label_entry)
label.show()
dialog.vbox.pack_start(label, False, True, 5)
address = gtk.HBox()
address_label = gtk.Label('Address:')
address_label.set_size_request(120,10)
address_label.show()
address.pack_start(address_label)
address_entry = gtk.Entry()
address_entry.show()
address.pack_start(address_entry)
address.show()
dialog.vbox.pack_start(address, False, True, 5)
result = dialog.run()
address = address_entry.get_text()
label = label_entry.get_text()
dialog.destroy()
if result == 1:
if self.wallet.is_valid(address):
self.wallet.addressbook.append(address)
if label: self.wallet.labels[address] = label
self.wallet.save()
self.update_sending_tab()
else:
errorDialog = gtk.MessageDialog(
parent=self.window,
flags=gtk.DIALOG_MODAL,
buttons= gtk.BUTTONS_CLOSE,
message_format = "Invalid address")
errorDialog.show()
errorDialog.run()
errorDialog.destroy()
else:
password = password_dialog() if self.wallet.use_encryption else None
success, ret = self.wallet.get_new_address(password)
if success:
address = ret
#if label: self.wallet.labels[address] = label
self.wallet.save()
self.update_receiving_tab()
else:
msg = ret
errorDialog = gtk.MessageDialog(
parent=self.window,
flags=gtk.DIALOG_MODAL,
buttons= gtk.BUTTONS_CLOSE,
message_format = msg)
errorDialog.show()
errorDialog.run()
errorDialog.destroy()
def main(self):
gtk.main()