2011-11-04 10:00:37 -07:00
#!/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/>.
2013-09-28 04:51:25 -07:00
2011-11-04 10:00:37 -07:00
import datetime
2012-02-03 06:45:41 -08:00
import thread , time , ast , sys , re
2011-11-10 13:21:40 -08:00
import socket , traceback
2014-02-01 17:19:43 -08:00
import gi
gi . require_version ( ' Gtk ' , ' 3.0 ' )
from gi . repository import Gtk , Gdk , GObject , cairo
2011-12-06 12:05:46 -08:00
from decimal import Decimal
2014-12-03 13:35:05 -08:00
from electrum . util import print_error , InvalidPassword
2015-05-31 19:26:22 -07:00
from electrum . bitcoin import is_valid , COIN
2015-05-31 02:31:41 -07:00
from electrum . wallet import NotEnoughFunds
2014-08-29 03:27:10 -07:00
from electrum import WalletStorage , Wallet
2012-05-30 07:46:04 -07:00
2014-02-01 17:19:43 -08:00
Gdk . threads_init ( )
2011-11-04 10:00:37 -07:00
APP_NAME = " Electrum "
2012-03-31 07:46:32 -07:00
import platform
MONOSPACE_FONT = ' Lucida Console ' if platform . system ( ) == ' Windows ' else ' monospace '
2011-11-04 10:00:37 -07:00
2014-06-13 07:02:30 -07:00
from electrum . util import format_satoshis , parse_URI
2013-03-24 03:25:17 -07:00
from electrum . bitcoin import MIN_RELAY_TX_FEE
2011-11-04 10:00:37 -07:00
def numbify ( entry , is_int = False ) :
text = entry . get_text ( ) . strip ( )
2011-12-07 13:38:31 -08:00
chars = ' 0123456789 '
if not is_int : chars + = ' . '
s = ' ' . join ( [ i for i in text if i in chars ] )
2011-12-07 09:54:32 -08:00
if not is_int :
2011-12-07 13:38:31 -08:00
if ' . ' in s :
p = s . find ( ' . ' )
s = s . replace ( ' . ' , ' ' )
s = s [ : p ] + ' . ' + s [ p : p + 8 ]
2011-12-07 09:54:32 -08:00
try :
2015-05-31 19:26:22 -07:00
amount = int ( Decimal ( s ) * COIN )
2013-11-10 12:30:57 -08:00
except Exception :
2011-12-07 13:11:35 -08:00
amount = None
2011-12-07 13:38:31 -08:00
else :
try :
amount = int ( s )
2013-11-10 12:30:57 -08:00
except Exception :
2011-12-07 13:38:31 -08:00
amount = None
2011-12-07 10:24:04 -08:00
entry . set_text ( s )
2011-12-07 09:54:32 -08:00
return amount
2011-11-08 04:56:35 -08:00
2014-04-30 00:31:20 -07:00
def show_seed_dialog ( seed , parent ) :
if not seed :
2012-05-12 15:43:22 -07:00
show_message ( " No seed " )
return
2014-04-30 00:31:20 -07:00
2014-02-01 17:19:43 -08:00
dialog = Gtk . MessageDialog (
2011-12-06 03:39:42 -08:00
parent = parent ,
2014-02-01 17:19:43 -08:00
flags = Gtk . DialogFlags . MODAL ,
buttons = Gtk . ButtonsType . OK ,
2014-04-30 00:31:20 -07:00
message_format = " Your wallet generation seed is: \n \n " + ' " ' + seed + ' " ' \
2013-12-13 08:30:34 -08:00
+ " \n \n Please keep it in a safe place; if you lose it, you will not be able to restore your wallet. \n \n " )
2011-12-06 03:39:42 -08:00
dialog . set_title ( " Seed " )
2011-11-08 04:56:35 -08:00
dialog . show ( )
dialog . run ( )
dialog . destroy ( )
2013-09-28 04:45:49 -07:00
def restore_create_dialog ( ) :
2011-11-04 10:00:37 -07:00
2012-02-11 04:14:12 -08:00
# 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
2014-02-01 17:19:43 -08:00
dialog = Gtk . Dialog ( " electrum " , parent = None ,
2014-04-30 00:31:20 -07:00
flags = Gtk . DialogFlags . MODAL ,
2012-02-11 04:14:12 -08:00
buttons = ( " create " , 0 , " restore " , 1 , " cancel " , 2 ) )
2014-02-01 17:19:43 -08:00
label = Gtk . Label ( " Wallet file not found. \n Do you want to create a new wallet, \n or to restore an existing one? " )
2012-02-11 04:14:12 -08:00
label . show ( )
2014-02-01 17:19:43 -08:00
dialog . vbox . pack_start ( label , True , True , 0 )
2012-02-11 04:14:12 -08:00
dialog . show ( )
r = dialog . run ( )
dialog . destroy ( )
2012-02-14 00:52:03 -08:00
if r == 2 : return False
2012-11-20 06:30:46 -08:00
return ' restore ' if r == 1 else ' create '
2011-11-06 02:13:58 -08:00
2012-02-14 00:52:03 -08:00
2011-11-04 10:00:37 -07:00
2013-09-28 04:45:49 -07:00
def run_recovery_dialog ( ) :
2012-01-12 05:48:41 -08:00
message = " Please enter your wallet seed or the corresponding mnemonic list of words, and the gap limit of your wallet. "
2014-02-01 17:19:43 -08:00
dialog = Gtk . MessageDialog (
2012-01-12 05:48:41 -08:00
parent = None ,
2014-02-01 17:19:43 -08:00
flags = Gtk . DialogFlags . MODAL ,
buttons = Gtk . ButtonsType . OK_CANCEL ,
2012-01-12 05:48:41 -08:00
message_format = message )
vbox = dialog . vbox
2014-02-01 17:19:43 -08:00
dialog . set_default_response ( Gtk . ResponseType . OK )
2012-01-12 05:48:41 -08:00
# ask seed, server and gap in the same dialog
2014-02-01 17:19:43 -08:00
seed_box = Gtk . HBox ( )
seed_label = Gtk . Label ( label = ' Seed or mnemonic: ' )
2012-01-12 05:48:41 -08:00
seed_label . set_size_request ( 150 , - 1 )
seed_box . pack_start ( seed_label , False , False , 10 )
seed_label . show ( )
2014-02-01 17:19:43 -08:00
seed_entry = Gtk . Entry ( )
2012-01-12 05:48:41 -08:00
seed_entry . show ( )
seed_entry . set_size_request ( 450 , - 1 )
seed_box . pack_start ( seed_entry , False , False , 10 )
add_help_button ( seed_box , ' . ' )
seed_box . show ( )
vbox . pack_start ( seed_box , False , False , 5 )
dialog . show ( )
r = dialog . run ( )
2012-01-14 16:39:16 -08:00
seed = seed_entry . get_text ( )
2012-01-12 05:48:41 -08:00
dialog . destroy ( )
2014-02-01 17:19:43 -08:00
if r == Gtk . ResponseType . CANCEL :
2012-11-20 06:30:46 -08:00
return False
2014-04-30 00:31:20 -07:00
if Wallet . is_seed ( seed ) :
return seed
show_message ( " no seed " )
return False
2012-01-12 05:48:41 -08:00
2013-10-07 01:05:15 -07:00
def run_settings_dialog ( self ) :
2012-01-12 05:48:41 -08:00
2012-02-14 00:52:03 -08:00
message = " Here are the settings of your wallet. For more explanations, click on the question mark buttons next to each input field. "
2011-12-06 03:39:42 -08:00
2014-02-01 17:19:43 -08:00
dialog = Gtk . MessageDialog (
2013-10-07 01:05:15 -07:00
parent = self . window ,
2014-02-01 17:19:43 -08:00
flags = Gtk . DialogFlags . MODAL ,
buttons = Gtk . ButtonsType . OK_CANCEL ,
2011-12-06 03:39:42 -08:00
message_format = message )
2011-11-04 10:00:37 -07:00
2014-02-01 17:19:43 -08:00
image = Gtk . Image ( )
image . set_from_stock ( Gtk . STOCK_PREFERENCES , Gtk . IconSize . DIALOG )
2011-12-03 05:08:21 -08:00
image . show ( )
dialog . set_image ( image )
2011-12-06 03:39:42 -08:00
dialog . set_title ( " Settings " )
2011-12-03 05:08:21 -08:00
2011-11-06 02:13:58 -08:00
vbox = dialog . vbox
2014-02-01 17:19:43 -08:00
dialog . set_default_response ( Gtk . ResponseType . OK )
2011-11-04 10:00:37 -07:00
2014-02-01 17:19:43 -08:00
fee = Gtk . HBox ( )
fee_entry = Gtk . Entry ( )
fee_label = Gtk . Label ( label = ' Transaction fee: ' )
2012-01-12 05:48:41 -08:00
fee_label . set_size_request ( 150 , 10 )
fee_label . show ( )
fee . pack_start ( fee_label , False , False , 10 )
2015-05-31 19:26:22 -07:00
fee_entry . set_text ( str ( Decimal ( self . wallet . fee_per_kb ) / COIN ) )
2012-01-12 05:48:41 -08:00
fee_entry . connect ( ' changed ' , numbify , False )
fee_entry . show ( )
fee . pack_start ( fee_entry , False , False , 10 )
2013-03-23 01:23:57 -07:00
add_help_button ( fee , ' Fee per kilobyte of transaction. Recommended value:0.0001 ' )
2012-01-12 05:48:41 -08:00
fee . show ( )
vbox . pack_start ( fee , False , False , 5 )
2011-11-06 02:13:58 -08:00
2014-02-01 17:19:43 -08:00
nz = Gtk . HBox ( )
nz_entry = Gtk . Entry ( )
nz_label = Gtk . Label ( label = ' Display zeros: ' )
2012-05-02 08:40:39 -07:00
nz_label . set_size_request ( 150 , 10 )
nz_label . show ( )
nz . pack_start ( nz_label , False , False , 10 )
2013-10-07 01:05:15 -07:00
nz_entry . set_text ( str ( self . num_zeros ) )
2012-05-02 08:40:39 -07:00
nz_entry . connect ( ' changed ' , numbify , True )
nz_entry . show ( )
nz . pack_start ( nz_entry , False , False , 10 )
add_help_button ( nz , " Number of zeros displayed after the decimal point. \n For example, if this number is 2, then ' 5. ' is displayed as ' 5.00 ' " )
nz . show ( )
vbox . pack_start ( nz , False , False , 5 )
2011-11-04 10:00:37 -07:00
dialog . show ( )
r = dialog . run ( )
2012-01-12 05:48:41 -08:00
fee = fee_entry . get_text ( )
2012-05-02 08:40:39 -07:00
nz = nz_entry . get_text ( )
2011-12-06 03:39:42 -08:00
2011-11-04 10:00:37 -07:00
dialog . destroy ( )
2014-02-01 17:19:43 -08:00
if r == Gtk . ResponseType . CANCEL :
2012-01-12 05:48:41 -08:00
return
2011-11-08 04:56:35 -08:00
2011-12-02 07:40:48 -08:00
try :
2015-05-31 19:26:22 -07:00
fee = int ( COIN * Decimal ( fee ) )
2013-11-10 12:30:57 -08:00
except Exception :
2011-12-02 07:40:48 -08:00
show_message ( " error " )
return
2013-10-07 01:05:15 -07:00
self . wallet . set_fee ( fee )
2011-12-02 07:40:48 -08:00
2012-05-02 08:40:39 -07:00
try :
nz = int ( nz )
if nz > 8 : nz = 8
2013-11-10 12:30:57 -08:00
except Exception :
2012-05-02 08:40:39 -07:00
show_message ( " error " )
return
2011-12-02 07:40:48 -08:00
2013-10-07 01:05:15 -07:00
if self . num_zeros != nz :
self . num_zeros = nz
self . config . set_key ( ' num_zeros ' , nz , True )
self . update_history_tab ( )
2012-10-12 08:04:16 -07:00
2011-12-02 07:40:48 -08:00
2011-11-04 10:00:37 -07:00
2012-03-31 05:20:25 -07:00
2013-09-28 04:45:49 -07:00
def run_network_dialog ( network , parent ) :
2014-02-01 17:19:43 -08:00
image = Gtk . Image ( )
image . set_from_stock ( Gtk . STOCK_NETWORK , Gtk . IconSize . DIALOG )
2014-07-28 00:28:02 -07:00
host , port , protocol , proxy_config , auto_connect = network . get_parameters ( )
2014-08-27 04:48:10 -07:00
server = " %s : %s : %s " % ( host , port , protocol )
2012-01-12 06:42:13 -08:00
if parent :
2013-10-07 01:05:15 -07:00
if network . is_connected ( ) :
2014-08-27 04:48:10 -07:00
status = " Connected to %s \n %d blocks " % ( host , network . get_local_height ( ) )
2012-01-12 06:42:13 -08:00
else :
status = " Not connected "
2012-01-12 05:48:41 -08:00
else :
2012-01-13 02:52:14 -08:00
import random
2012-11-20 06:30:46 -08:00
status = " Please choose a server. \n Select cancel if you are offline. "
2012-10-16 00:29:08 -07:00
2013-09-28 04:45:49 -07:00
servers = network . get_servers ( )
2012-03-31 05:46:00 -07:00
2014-02-01 17:19:43 -08:00
dialog = Gtk . MessageDialog ( parent , Gtk . DialogFlags . MODAL | Gtk . DialogFlags . DESTROY_WITH_PARENT ,
Gtk . MessageType . QUESTION , Gtk . ButtonsType . OK_CANCEL , status )
2012-01-12 05:48:41 -08:00
dialog . set_title ( " Server " )
dialog . set_image ( image )
image . show ( )
vbox = dialog . vbox
2014-02-01 17:19:43 -08:00
host_box = Gtk . HBox ( )
host_label = Gtk . Label ( label = ' Connect to: ' )
2012-01-12 05:48:41 -08:00
host_label . set_size_request ( 100 , - 1 )
host_label . show ( )
2012-01-13 02:52:14 -08:00
host_box . pack_start ( host_label , False , False , 10 )
2014-02-01 17:19:43 -08:00
host_entry = Gtk . Entry ( )
2012-01-12 05:48:41 -08:00
host_entry . set_size_request ( 200 , - 1 )
2013-11-07 18:36:53 -08:00
if network . is_connected ( ) :
host_entry . set_text ( server )
else :
host_entry . set_text ( " Not Connected " )
2012-01-12 05:48:41 -08:00
host_entry . show ( )
2012-01-13 02:52:14 -08:00
host_box . pack_start ( host_entry , False , False , 10 )
2013-10-07 01:05:15 -07:00
add_help_button ( host_box , ' The name, port number and protocol of your Electrum server, separated by a colon. Example: " ecdsa.org:50002:s " . Some servers allow you to connect through http (port 80) or https (port 443) ' )
2012-01-13 02:52:14 -08:00
host_box . show ( )
2012-03-31 05:46:00 -07:00
2014-02-01 17:19:43 -08:00
p_box = Gtk . HBox ( False , 10 )
2012-03-31 05:46:00 -07:00
p_box . show ( )
2014-02-01 17:19:43 -08:00
p_label = Gtk . Label ( label = ' Protocol: ' )
2012-03-31 05:46:00 -07:00
p_label . set_size_request ( 100 , - 1 )
p_label . show ( )
p_box . pack_start ( p_label , False , False , 10 )
2014-02-01 17:19:43 -08:00
combobox = Gtk . ComboBoxText ( )
2013-10-07 01:05:15 -07:00
combobox . show ( )
combobox . append_text ( " TCP " )
combobox . append_text ( " SSL " )
combobox . append_text ( " HTTP " )
combobox . append_text ( " HTTPS " )
p_box . pack_start ( combobox , True , True , 0 )
2012-03-31 05:46:00 -07:00
def current_line ( ) :
return unicode ( host_entry . get_text ( ) ) . split ( ' : ' )
2013-11-07 18:36:53 -08:00
2013-10-07 01:05:15 -07:00
def set_combobox ( protocol ) :
combobox . set_active ( ' tshg ' . index ( protocol ) )
2012-03-31 05:46:00 -07:00
def set_protocol ( protocol ) :
host = current_line ( ) [ 0 ]
2013-04-28 04:47:19 -07:00
pp = servers [ host ]
2012-03-31 05:46:00 -07:00
if protocol not in pp . keys ( ) :
protocol = pp . keys ( ) [ 0 ]
2013-10-07 01:05:15 -07:00
set_combobox ( protocol )
2012-03-31 05:46:00 -07:00
port = pp [ protocol ]
host_entry . set_text ( host + ' : ' + port + ' : ' + protocol )
2013-10-07 01:05:15 -07:00
combobox . connect ( " changed " , lambda x : set_protocol ( ' tshg ' [ combobox . get_active ( ) ] ) )
2013-11-07 18:36:53 -08:00
if network . is_connected ( ) :
set_combobox ( protocol )
2012-01-12 05:48:41 -08:00
2014-02-01 17:19:43 -08:00
server_list = Gtk . ListStore ( str )
2013-04-28 04:47:19 -07:00
for host in servers . keys ( ) :
2012-03-31 05:46:00 -07:00
server_list . append ( [ host ] )
2012-01-12 05:48:41 -08:00
2014-02-01 17:19:43 -08:00
treeview = Gtk . TreeView ( model = server_list )
2012-01-12 05:48:41 -08:00
treeview . show ( )
2014-07-28 00:28:02 -07:00
label = ' Active Servers ' if network . is_connected ( ) else ' Default Servers '
2014-02-01 17:19:43 -08:00
tvcolumn = Gtk . TreeViewColumn ( label )
2012-01-12 05:48:41 -08:00
treeview . append_column ( tvcolumn )
2014-02-01 17:19:43 -08:00
cell = Gtk . CellRendererText ( )
2012-01-12 05:48:41 -08:00
tvcolumn . pack_start ( cell , False )
tvcolumn . add_attribute ( cell , ' text ' , 0 )
2012-01-13 02:52:14 -08:00
vbox . pack_start ( host_box , False , False , 5 )
2012-03-31 05:46:00 -07:00
vbox . pack_start ( p_box , True , True , 0 )
2013-10-07 01:05:15 -07:00
2014-02-01 17:19:43 -08:00
#scroll = Gtk.ScrolledWindow()
#scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.ALWAYS)
2013-10-07 01:05:15 -07:00
#scroll.add_with_viewport(treeview)
#scroll.show()
#vbox.pack_start(scroll, True)
2014-02-01 17:19:43 -08:00
vbox . pack_start ( treeview , True , True , 0 )
2012-01-12 05:48:41 -08:00
def my_treeview_cb ( treeview ) :
path , view_column = treeview . get_cursor ( )
2012-03-31 05:46:00 -07:00
host = server_list . get_value ( server_list . get_iter ( path ) , 0 )
2013-04-28 04:47:19 -07:00
pp = servers [ host ]
2012-03-31 05:46:00 -07:00
if ' t ' in pp . keys ( ) :
protocol = ' t '
else :
protocol = pp . keys ( ) [ 0 ]
port = pp [ protocol ]
host_entry . set_text ( host + ' : ' + port + ' : ' + protocol )
2013-10-07 01:05:15 -07:00
set_combobox ( protocol )
2012-03-31 05:46:00 -07:00
2012-01-12 05:48:41 -08:00
treeview . connect ( ' cursor-changed ' , my_treeview_cb )
2013-10-07 01:05:15 -07:00
dialog . show_all ( )
2012-01-12 05:48:41 -08:00
r = dialog . run ( )
2012-03-30 14:44:54 -07:00
server = host_entry . get_text ( )
2012-01-12 05:48:41 -08:00
dialog . destroy ( )
2012-01-12 06:42:13 -08:00
2014-02-01 17:19:43 -08:00
if r == Gtk . ResponseType . CANCEL :
2012-02-14 06:42:13 -08:00
return False
2012-01-12 06:42:13 -08:00
2012-01-12 05:48:41 -08:00
try :
2013-10-07 01:05:15 -07:00
host , port , protocol = server . split ( ' : ' )
2013-11-10 12:30:57 -08:00
except Exception :
2012-03-30 14:44:54 -07:00
show_message ( " error: " + server )
2012-02-14 06:42:13 -08:00
return False
2012-01-12 05:48:41 -08:00
2014-08-27 04:48:10 -07:00
network . set_parameters ( host , port , protocol , proxy_config , auto_connect )
2013-10-07 01:05:15 -07:00
2012-01-12 05:48:41 -08:00
2011-11-04 10:00:37 -07:00
2011-12-07 09:54:32 -08:00
def show_message ( message , parent = None ) :
2014-02-01 17:19:43 -08:00
dialog = Gtk . MessageDialog (
2011-12-07 09:54:32 -08:00
parent = parent ,
2014-02-01 17:19:43 -08:00
flags = Gtk . DialogFlags . MODAL ,
buttons = Gtk . ButtonsType . CLOSE ,
2011-11-04 10:00:37 -07:00
message_format = message )
dialog . show ( )
dialog . run ( )
dialog . destroy ( )
def password_line ( label ) :
2014-02-01 17:19:43 -08:00
password = Gtk . HBox ( )
password_label = Gtk . Label ( label = label )
2011-11-04 10:00:37 -07:00
password_label . set_size_request ( 120 , 10 )
password_label . show ( )
password . pack_start ( password_label , False , False , 10 )
2014-02-01 17:19:43 -08:00
password_entry = Gtk . Entry ( )
2011-11-11 02:12:40 -08:00
password_entry . set_size_request ( 300 , - 1 )
2011-11-04 10:00:37 -07:00
password_entry . set_visibility ( False )
password_entry . show ( )
password . pack_start ( password_entry , False , False , 10 )
password . show ( )
return password , password_entry
2012-02-06 09:01:35 -08:00
def password_dialog ( parent ) :
2014-02-01 17:19:43 -08:00
dialog = Gtk . MessageDialog ( parent , Gtk . DialogFlags . MODAL | Gtk . DialogFlags . DESTROY_WITH_PARENT ,
Gtk . MessageType . QUESTION , Gtk . ButtonsType . OK_CANCEL , " Please enter your password. " )
2011-11-04 10:00:37 -07:00
dialog . get_image ( ) . set_visible ( False )
current_pw , current_pw_entry = password_line ( ' Password: ' )
2014-02-01 17:19:43 -08:00
current_pw_entry . connect ( " activate " , lambda entry , dialog , response : dialog . response ( response ) , dialog , Gtk . ResponseType . OK )
2011-11-04 10:00:37 -07:00
dialog . vbox . pack_start ( current_pw , False , True , 0 )
dialog . show ( )
result = dialog . run ( )
pw = current_pw_entry . get_text ( )
dialog . destroy ( )
2014-02-01 17:19:43 -08:00
if result != Gtk . ResponseType . CANCEL : return pw
2011-11-04 10:00:37 -07:00
2013-12-13 08:30:34 -08:00
def change_password_dialog ( is_encrypted , parent ) :
2012-05-12 15:43:22 -07:00
2011-12-06 03:39:42 -08:00
if parent :
2013-12-13 08:30:34 -08:00
msg = ' Your wallet is encrypted. Use this dialog to change the password. To disable wallet encryption, enter an empty new password. ' if is_encrypted else ' Your wallet keys are not encrypted '
2011-11-06 02:13:58 -08:00
else :
msg = " Please choose a password to encrypt your wallet keys "
2014-02-01 17:19:43 -08:00
dialog = Gtk . MessageDialog ( parent , Gtk . DialogFlags . MODAL | Gtk . DialogFlags . DESTROY_WITH_PARENT , Gtk . MessageType . QUESTION , Gtk . ButtonsType . OK_CANCEL , msg )
2011-12-03 02:31:00 -08:00
dialog . set_title ( " Change password " )
2014-02-01 17:19:43 -08:00
image = Gtk . Image ( )
image . set_from_stock ( Gtk . STOCK_DIALOG_AUTHENTICATION , Gtk . IconSize . DIALOG )
2011-12-03 05:08:21 -08:00
image . show ( )
dialog . set_image ( image )
2011-11-08 04:56:35 -08:00
2013-12-13 08:30:34 -08:00
if is_encrypted :
2011-11-04 16:15:02 -07:00
current_pw , current_pw_entry = password_line ( ' Current password: ' )
2011-11-04 10:00:37 -07:00
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 ( )
2013-12-13 08:30:34 -08:00
password = current_pw_entry . get_text ( ) if is_encrypted else None
2011-11-04 10:00:37 -07:00
new_password = password_entry . get_text ( )
new_password2 = password2_entry . get_text ( )
dialog . destroy ( )
2014-02-01 17:19:43 -08:00
if result == Gtk . ResponseType . CANCEL :
2011-11-04 10:00:37 -07:00
return
if new_password != new_password2 :
show_message ( " passwords do not match " )
2013-12-13 08:30:34 -08:00
return change_password_dialog ( is_encrypted , parent )
2011-11-04 10:00:37 -07:00
2013-12-13 08:30:34 -08:00
if not new_password :
new_password = None
return True , password , new_password
2011-11-04 16:15:02 -07:00
2011-11-04 10:00:37 -07:00
def add_help_button ( hbox , message ) :
2014-02-01 17:19:43 -08:00
button = Gtk . Button ( ' ? ' )
2011-11-04 10:00:37 -07:00
button . connect ( " clicked " , lambda x : show_message ( message ) )
button . show ( )
2014-02-01 17:19:43 -08:00
hbox . pack_start ( button , False , False , 0 )
2011-11-04 10:00:37 -07:00
2012-02-14 00:52:03 -08:00
class ElectrumWindow :
2011-11-04 10:00:37 -07:00
2011-12-07 09:54:32 -08:00
def show_message ( self , msg ) :
show_message ( msg , self . window )
2014-07-28 00:28:02 -07:00
def on_key ( self , w , event ) :
if Gdk . ModifierType . CONTROL_MASK & event . state and event . keyval in [ 113 , 119 ] :
Gtk . main_quit ( )
return True
2013-09-28 04:45:49 -07:00
def __init__ ( self , wallet , config , network ) :
2012-10-11 11:10:12 -07:00
self . config = config
2011-11-04 10:00:37 -07:00
self . wallet = wallet
2013-09-28 04:45:49 -07:00
self . network = network
2012-02-08 04:37:14 -08:00
self . funds_error = False # True if not enough funds
2013-10-07 01:05:15 -07:00
self . num_zeros = int ( self . config . get ( ' num_zeros ' , 0 ) )
2014-07-28 00:28:02 -07:00
self . window = Gtk . Window ( Gtk . WindowType . TOPLEVEL )
self . window . connect ( ' key-press-event ' , self . on_key )
2012-10-11 11:10:12 -07:00
title = ' Electrum ' + self . wallet . electrum_version + ' - ' + self . config . path
2012-05-13 01:54:03 -07:00
if not self . wallet . seed : title + = ' [seedless] '
self . window . set_title ( title )
2014-02-01 17:19:43 -08:00
self . window . connect ( " destroy " , Gtk . main_quit )
2011-11-04 10:00:37 -07:00
self . window . set_border_width ( 0 )
2014-07-28 00:28:02 -07:00
#self.window.connect('mykeypress', Gtk.main_quit)
2011-12-07 09:54:32 -08:00
self . window . set_default_size ( 720 , 350 )
2012-11-20 06:30:46 -08:00
self . wallet_updated = False
2011-11-04 10:00:37 -07:00
2015-04-23 03:46:52 -07:00
from electrum . util import StoreDict
self . contacts = StoreDict ( self . config , ' contacts ' )
2014-02-01 17:19:43 -08:00
vbox = Gtk . VBox ( )
2011-11-04 10:00:37 -07:00
2014-02-01 17:19:43 -08:00
self . notebook = Gtk . Notebook ( )
2011-11-04 10:00:37 -07:00
self . create_history_tab ( )
2012-05-13 02:05:26 -07:00
if self . wallet . seed :
self . create_send_tab ( )
2011-11-04 10:00:37 -07:00
self . create_recv_tab ( )
self . create_book_tab ( )
self . create_about_tab ( )
self . notebook . show ( )
vbox . pack_start ( self . notebook , True , True , 2 )
2014-02-01 17:19:43 -08:00
self . status_bar = Gtk . Statusbar ( )
2011-11-04 10:00:37 -07:00
vbox . pack_start ( self . status_bar , False , False , 0 )
2014-02-01 17:19:43 -08:00
self . status_image = Gtk . Image ( )
self . status_image . set_from_stock ( Gtk . STOCK_NO , Gtk . IconSize . MENU )
2011-11-04 10:00:37 -07:00
self . status_image . set_alignment ( True , 0.5 )
self . status_image . show ( )
2011-12-02 07:40:48 -08:00
2014-02-01 17:19:43 -08:00
self . network_button = Gtk . Button ( )
2013-09-28 04:45:49 -07:00
self . network_button . connect ( " clicked " , lambda x : run_network_dialog ( self . network , self . window ) )
2011-12-02 08:22:49 -08:00
self . network_button . add ( self . status_image )
2014-02-01 17:19:43 -08:00
self . network_button . set_relief ( Gtk . ReliefStyle . NONE )
2011-12-02 08:22:49 -08:00
self . network_button . show ( )
2014-02-01 17:19:43 -08:00
self . status_bar . pack_end ( self . network_button , False , False , 0 )
2011-11-08 04:56:35 -08:00
2012-05-13 01:54:03 -07:00
if self . wallet . seed :
def seedb ( w , wallet ) :
if wallet . use_encryption :
password = password_dialog ( self . window )
if not password : return
else : password = None
2014-04-30 00:31:20 -07:00
seed = wallet . get_mnemonic ( password )
show_seed_dialog ( seed , self . window )
2014-02-01 17:19:43 -08:00
button = Gtk . Button ( ' S ' )
button . connect ( " clicked " , seedb , self . wallet )
button . set_relief ( Gtk . ReliefStyle . NONE )
2012-05-13 01:54:03 -07:00
button . show ( )
2014-02-01 17:19:43 -08:00
self . status_bar . pack_end ( button , False , False , 0 )
2011-11-08 04:56:35 -08:00
2014-02-01 17:19:43 -08:00
settings_icon = Gtk . Image ( )
settings_icon . set_from_stock ( Gtk . STOCK_PREFERENCES , Gtk . IconSize . MENU )
2011-11-04 16:15:02 -07:00
settings_icon . set_alignment ( 0.5 , 0.5 )
settings_icon . set_size_request ( 16 , 16 )
2011-11-04 10:00:37 -07:00
settings_icon . show ( )
2014-02-01 17:19:43 -08:00
prefs_button = Gtk . Button ( )
2013-10-07 01:05:15 -07:00
prefs_button . connect ( " clicked " , lambda x : run_settings_dialog ( self ) )
2011-11-04 10:00:37 -07:00
prefs_button . add ( settings_icon )
prefs_button . set_tooltip_text ( " Settings " )
2014-02-01 17:19:43 -08:00
prefs_button . set_relief ( Gtk . ReliefStyle . NONE )
2011-11-04 10:00:37 -07:00
prefs_button . show ( )
2014-02-01 17:19:43 -08:00
self . status_bar . pack_end ( prefs_button , False , False , 0 )
2011-11-04 10:00:37 -07:00
2014-02-01 17:19:43 -08:00
self . pw_icon = Gtk . Image ( )
self . pw_icon . set_from_stock ( Gtk . STOCK_DIALOG_AUTHENTICATION , Gtk . IconSize . MENU )
2013-12-13 08:30:34 -08:00
self . pw_icon . set_alignment ( 0.5 , 0.5 )
self . pw_icon . set_size_request ( 16 , 16 )
self . pw_icon . show ( )
2011-11-04 16:15:02 -07:00
2012-05-13 01:54:03 -07:00
if self . wallet . seed :
2014-02-01 17:19:43 -08:00
if self . wallet . use_encryption :
self . pw_icon . set_tooltip_text ( ' Wallet is encrypted ' )
else :
self . pw_icon . set_tooltip_text ( ' Wallet is unencrypted ' )
password_button = Gtk . Button ( )
password_button . connect ( " clicked " , self . do_update_password , self . wallet )
2013-12-13 08:30:34 -08:00
password_button . add ( self . pw_icon )
2014-02-01 17:19:43 -08:00
password_button . set_relief ( Gtk . ReliefStyle . NONE )
2012-05-13 01:54:03 -07:00
password_button . show ( )
2014-02-01 17:19:43 -08:00
self . status_bar . pack_end ( password_button , False , False , 0 )
2011-11-04 16:15:02 -07:00
2011-11-04 10:00:37 -07:00
self . window . add ( vbox )
self . window . show_all ( )
2012-02-03 02:48:09 -08:00
#self.fee_box.hide()
2011-11-04 10:00:37 -07:00
self . context_id = self . status_bar . get_context_id ( " statusbar " )
self . update_status_bar ( )
2013-09-28 04:45:49 -07:00
self . network . register_callback ( ' updated ' , self . update_callback )
2012-10-27 10:20:50 -07:00
2011-11-04 10:00:37 -07:00
def update_status_bar_thread ( ) :
while True :
2014-02-01 17:19:43 -08:00
GObject . idle_add ( self . update_status_bar )
2011-11-04 10:00:37 -07:00
time . sleep ( 0.5 )
2012-02-03 06:45:41 -08:00
def check_recipient_thread ( ) :
old_r = ' '
while True :
time . sleep ( 0.5 )
2012-02-03 06:57:45 -08:00
if self . payto_entry . is_focus ( ) :
continue
2012-02-03 06:45:41 -08:00
r = self . payto_entry . get_text ( )
if r != old_r :
old_r = r
2012-02-03 07:08:28 -08:00
r = r . strip ( )
2012-02-03 06:45:41 -08:00
if re . match ( ' ^(|([ \ w \ - \ .]+)@)(( \ w[ \ w \ -]+ \ .)+[ \ w \ -]+)$ ' , r ) :
2012-02-03 07:39:27 -08:00
try :
2012-02-14 00:52:03 -08:00
to_address = self . wallet . get_alias ( r , interactive = False )
2013-11-10 12:30:57 -08:00
except Exception :
2012-02-03 07:39:27 -08:00
continue
2012-02-03 06:45:41 -08:00
if to_address :
2012-02-03 07:08:28 -08:00
s = r + ' < ' + to_address + ' > '
2014-02-01 17:19:43 -08:00
GObject . idle_add ( lambda : self . payto_entry . set_text ( s ) )
2012-02-03 06:45:41 -08:00
2011-11-04 10:00:37 -07:00
thread . start_new_thread ( update_status_bar_thread , ( ) )
2012-05-13 02:05:26 -07:00
if self . wallet . seed :
thread . start_new_thread ( check_recipient_thread , ( ) )
2011-11-04 10:00:37 -07:00
self . notebook . set_current_page ( 0 )
2012-10-27 10:20:50 -07:00
def update_callback ( self ) :
self . wallet_updated = True
2014-02-01 17:19:43 -08:00
def do_update_password ( self , button , wallet ) :
2013-12-13 08:30:34 -08:00
if not wallet . seed :
show_message ( " No seed " )
return
2014-02-01 17:19:43 -08:00
res = change_password_dialog ( wallet . use_encryption , self . window )
2013-12-13 08:30:34 -08:00
if res :
_ , password , new_password = res
try :
wallet . get_seed ( password )
2014-12-03 13:35:05 -08:00
except InvalidPassword :
2013-12-13 08:30:34 -08:00
show_message ( " Incorrect password " )
return
wallet . update_password ( password , new_password )
if wallet . use_encryption :
2014-02-01 17:19:43 -08:00
self . pw_icon . set_tooltip_text ( ' Wallet is encrypted ' )
2013-12-13 08:30:34 -08:00
else :
2014-02-01 17:19:43 -08:00
self . pw_icon . set_tooltip_text ( ' Wallet is unencrypted ' )
2013-12-13 08:30:34 -08:00
2011-11-04 10:00:37 -07:00
def add_tab ( self , page , name ) :
2014-02-01 17:19:43 -08:00
tab_label = Gtk . Label ( label = name )
2011-11-04 10:00:37 -07:00
tab_label . show ( )
self . notebook . append_page ( page , tab_label )
def create_send_tab ( self ) :
2012-02-03 02:48:09 -08:00
2014-02-01 17:19:43 -08:00
page = vbox = Gtk . VBox ( )
2011-11-04 10:00:37 -07:00
page . show ( )
2014-02-01 17:19:43 -08:00
payto = Gtk . HBox ( )
payto_label = Gtk . Label ( label = ' Pay to: ' )
2012-02-03 02:48:09 -08:00
payto_label . set_size_request ( 100 , - 1 )
2014-02-01 17:19:43 -08:00
payto . pack_start ( payto_label , False , False , 0 )
payto_entry = Gtk . Entry ( )
2012-02-03 06:45:41 -08:00
payto_entry . set_size_request ( 450 , 26 )
2014-02-01 17:19:43 -08:00
payto . pack_start ( payto_entry , False , False , 0 )
2011-11-04 10:00:37 -07:00
vbox . pack_start ( payto , False , False , 5 )
2012-02-03 02:48:09 -08:00
2014-02-01 17:19:43 -08:00
message = Gtk . HBox ( )
message_label = Gtk . Label ( label = ' Description: ' )
2012-02-03 13:25:50 -08:00
message_label . set_size_request ( 100 , - 1 )
2014-02-01 17:19:43 -08:00
message . pack_start ( message_label , False , False , 0 )
message_entry = Gtk . Entry ( )
2012-02-03 13:25:50 -08:00
message_entry . set_size_request ( 450 , 26 )
2014-02-01 17:19:43 -08:00
message . pack_start ( message_entry , False , False , 0 )
2012-02-03 13:25:50 -08:00
vbox . pack_start ( message , False , False , 5 )
2011-11-04 10:00:37 -07:00
2014-02-01 17:19:43 -08:00
amount_box = Gtk . HBox ( )
amount_label = Gtk . Label ( label = ' Amount: ' )
2011-12-07 09:54:32 -08:00
amount_label . set_size_request ( 100 , - 1 )
2014-02-01 17:19:43 -08:00
amount_box . pack_start ( amount_label , False , False , 0 )
amount_entry = Gtk . Entry ( )
2011-12-07 09:54:32 -08:00
amount_entry . set_size_request ( 120 , - 1 )
2014-02-01 17:19:43 -08:00
amount_box . pack_start ( amount_entry , False , False , 0 )
2011-12-07 09:54:32 -08:00
vbox . pack_start ( amount_box , False , False , 5 )
2011-11-04 10:00:37 -07:00
2014-02-01 17:19:43 -08:00
self . fee_box = fee_box = Gtk . HBox ( )
fee_label = Gtk . Label ( label = ' Fee: ' )
2012-02-03 02:48:09 -08:00
fee_label . set_size_request ( 100 , - 1 )
2014-02-01 17:19:43 -08:00
fee_box . pack_start ( fee_label , False , False , 0 )
fee_entry = Gtk . Entry ( )
2012-02-02 09:56:57 -08:00
fee_entry . set_size_request ( 60 , 26 )
2014-02-01 17:19:43 -08:00
fee_box . pack_start ( fee_entry , False , False , 0 )
2012-02-03 13:25:50 -08:00
vbox . pack_start ( fee_box , False , False , 5 )
2012-02-02 09:44:50 -08:00
2014-02-01 17:19:43 -08:00
end_box = Gtk . HBox ( )
empty_label = Gtk . Label ( label = ' ' )
2012-02-03 02:48:09 -08:00
empty_label . set_size_request ( 100 , - 1 )
2014-02-01 17:19:43 -08:00
end_box . pack_start ( empty_label , False , False , 0 )
send_button = Gtk . Button ( " Send " )
2012-02-02 09:44:50 -08:00
send_button . show ( )
2012-02-03 13:25:50 -08:00
end_box . pack_start ( send_button , False , False , 0 )
2014-02-01 17:19:43 -08:00
clear_button = Gtk . Button ( " Clear " )
2012-02-02 09:44:50 -08:00
clear_button . show ( )
2012-02-03 13:25:50 -08:00
end_box . pack_start ( clear_button , False , False , 15 )
send_button . connect ( " clicked " , self . do_send , ( payto_entry , message_entry , amount_entry , fee_entry ) )
clear_button . connect ( " clicked " , self . do_clear , ( payto_entry , message_entry , amount_entry , fee_entry ) )
2012-02-03 02:48:09 -08:00
2012-02-02 09:44:50 -08:00
vbox . pack_start ( end_box , False , False , 5 )
2011-12-07 09:54:32 -08:00
2012-02-03 02:48:09 -08:00
# display this line only if there is a signature
2014-02-01 17:19:43 -08:00
payto_sig = Gtk . HBox ( )
payto_sig_id = Gtk . Label ( label = ' ' )
payto_sig . pack_start ( payto_sig_id , False , False , 0 )
2012-02-03 02:48:09 -08:00
vbox . pack_start ( payto_sig , True , True , 5 )
2011-12-07 09:54:32 -08:00
self . user_fee = False
def entry_changed ( entry , is_fee ) :
amount = numbify ( amount_entry )
fee = numbify ( fee_entry )
if not is_fee : fee = None
2012-02-08 04:37:14 -08:00
if amount is None :
2012-02-03 02:48:09 -08:00
return
2015-05-31 02:31:41 -07:00
coins = self . wallet . get_spendable_coins ( )
2014-11-20 10:10:43 -08:00
try :
2015-08-03 22:15:54 -07:00
tx = self . wallet . make_unsigned_transaction ( coins , [ ( ' op_return ' , ' dummy_tx ' , amount ) ] , self . config , fee )
2014-11-20 10:10:43 -08:00
self . funds_error = False
except NotEnoughFunds :
self . funds_error = True
if not self . funds_error :
if not is_fee :
2014-09-07 09:45:06 -07:00
fee = tx . get_fee ( )
2015-05-31 19:26:22 -07:00
fee_entry . set_text ( str ( Decimal ( fee ) / COIN ) )
2014-09-07 09:45:06 -07:00
self . fee_box . show ( )
2014-02-01 17:19:43 -08:00
amount_entry . modify_text ( Gtk . StateType . NORMAL , Gdk . color_parse ( " #000000 " ) )
fee_entry . modify_text ( Gtk . StateType . NORMAL , Gdk . color_parse ( " #000000 " ) )
2011-12-07 09:54:32 -08:00
send_button . set_sensitive ( True )
else :
send_button . set_sensitive ( False )
2014-02-01 17:19:43 -08:00
amount_entry . modify_text ( Gtk . StateType . NORMAL , Gdk . color_parse ( " #cc0000 " ) )
fee_entry . modify_text ( Gtk . StateType . NORMAL , Gdk . color_parse ( " #cc0000 " ) )
2011-12-07 09:54:32 -08:00
amount_entry . connect ( ' changed ' , entry_changed , False )
2012-02-03 06:45:41 -08:00
fee_entry . connect ( ' changed ' , entry_changed , True )
2011-11-04 10:00:37 -07:00
self . payto_entry = payto_entry
2012-02-02 09:44:50 -08:00
self . payto_fee_entry = fee_entry
2012-02-03 02:48:09 -08:00
self . payto_sig_id = payto_sig_id
self . payto_sig = payto_sig
2012-02-03 13:25:50 -08:00
self . amount_entry = amount_entry
self . message_entry = message_entry
2011-11-04 10:00:37 -07:00
self . add_tab ( page , ' Send ' )
2012-02-03 02:48:09 -08:00
def set_frozen ( self , entry , frozen ) :
if frozen :
entry . set_editable ( False )
entry . set_has_frame ( False )
2014-02-01 17:19:43 -08:00
entry . modify_base ( Gtk . StateType . NORMAL , Gdk . color_parse ( " #eeeeee " ) )
2012-02-03 02:48:09 -08:00
else :
entry . set_editable ( True )
entry . set_has_frame ( True )
2014-02-01 17:19:43 -08:00
entry . modify_base ( Gtk . StateType . NORMAL , Gdk . color_parse ( " #ffffff " ) )
2012-02-03 02:48:09 -08:00
2012-02-14 03:45:39 -08:00
def set_url ( self , url ) :
2015-07-18 09:42:56 -07:00
out = parse_URI ( url )
address = out . get ( ' address ' )
message = out . get ( ' message ' )
amount = out . get ( ' amount ' )
2012-02-07 02:14:48 -08:00
self . notebook . set_current_page ( 1 )
2015-07-18 09:42:56 -07:00
self . payto_entry . set_text ( address )
2012-02-03 13:25:50 -08:00
self . message_entry . set_text ( message )
self . amount_entry . set_text ( amount )
2014-05-07 08:35:38 -07:00
self . payto_sig . set_visible ( False )
2012-01-15 09:45:30 -08:00
2011-11-04 10:00:37 -07:00
def create_about_tab ( self ) :
2014-02-01 17:19:43 -08:00
from gi . repository import Pango
page = Gtk . VBox ( )
2011-11-04 10:00:37 -07:00
page . show ( )
2014-02-01 17:19:43 -08:00
tv = Gtk . TextView ( )
2011-12-06 03:39:42 -08:00
tv . set_editable ( False )
tv . set_cursor_visible ( False )
2014-02-01 17:19:43 -08:00
tv . modify_font ( Pango . FontDescription ( MONOSPACE_FONT ) )
scroll = Gtk . ScrolledWindow ( )
2012-11-16 10:18:14 -08:00
scroll . add ( tv )
2014-02-01 17:19:43 -08:00
page . pack_start ( scroll , True , True , 0 )
2011-12-06 03:39:42 -08:00
self . info = tv . get_buffer ( )
2011-11-13 15:25:00 -08:00
self . add_tab ( page , ' Wall ' )
2011-11-04 10:00:37 -07:00
2012-02-02 09:44:50 -08:00
def do_clear ( self , w , data ) :
2012-02-03 02:48:09 -08:00
self . payto_sig . set_visible ( False )
2012-02-07 02:14:48 -08:00
self . payto_fee_entry . set_text ( ' ' )
2012-02-03 13:25:50 -08:00
for entry in [ self . payto_entry , self . amount_entry , self . message_entry ] :
2012-02-03 02:48:09 -08:00
self . set_frozen ( entry , False )
entry . set_text ( ' ' )
2012-02-03 06:45:41 -08:00
2012-02-06 08:59:31 -08:00
def question ( self , msg ) :
2014-02-01 17:19:43 -08:00
dialog = Gtk . MessageDialog ( self . window , Gtk . DialogFlags . MODAL | Gtk . DialogFlags . DESTROY_WITH_PARENT , Gtk . MessageType . QUESTION , Gtk . ButtonsType . OK_CANCEL , msg )
2012-02-06 08:59:31 -08:00
dialog . show ( )
result = dialog . run ( )
dialog . destroy ( )
2014-02-01 17:19:43 -08:00
return result == Gtk . ResponseType . OK
2012-02-06 08:59:31 -08:00
2011-11-04 10:00:37 -07:00
def do_send ( self , w , data ) :
2011-12-07 09:54:32 -08:00
payto_entry , label_entry , amount_entry , fee_entry = data
2011-11-04 10:00:37 -07:00
label = label_entry . get_text ( )
2012-02-03 06:45:41 -08:00
r = payto_entry . get_text ( )
2012-02-03 07:39:27 -08:00
r = r . strip ( )
2012-02-03 08:17:33 -08:00
m1 = re . match ( ' ^(|([ \ w \ - \ .]+)@)(( \ w[ \ w \ -]+ \ .)+[ \ w \ -]+)$ ' , r )
m2 = re . match ( ' (|([ \ w \ - \ .]+)@)(( \ w[ \ w \ -]+ \ .)+[ \ w \ -]+) \ <([1-9A-HJ-NP-Za-km-z] { 26,}) \ > ' , r )
if m1 :
2012-02-14 00:52:03 -08:00
to_address = self . wallet . get_alias ( r , True , self . show_message , self . question )
2012-02-03 08:17:33 -08:00
if not to_address :
return
2012-02-14 00:52:03 -08:00
else :
self . update_sending_tab ( )
2012-02-03 08:17:33 -08:00
elif m2 :
to_address = m2 . group ( 5 )
2012-02-03 06:45:41 -08:00
else :
to_address = r
2012-02-03 08:17:33 -08:00
2013-03-01 05:27:56 -08:00
if not is_valid ( to_address ) :
2012-02-03 06:45:41 -08:00
self . show_message ( " invalid bitcoin address: \n " + to_address )
2011-11-04 10:00:37 -07:00
return
try :
2015-05-31 19:26:22 -07:00
amount = int ( Decimal ( amount_entry . get_text ( ) ) * COIN )
2013-11-10 12:30:57 -08:00
except Exception :
2011-12-07 09:54:32 -08:00
self . show_message ( " invalid amount " )
return
try :
2015-05-31 19:26:22 -07:00
fee = int ( Decimal ( fee_entry . get_text ( ) ) * COIN )
2013-11-10 12:30:57 -08:00
except Exception :
2011-12-07 09:54:32 -08:00
self . show_message ( " invalid fee " )
2011-11-04 10:00:37 -07:00
return
2012-01-17 02:15:17 -08:00
if self . wallet . use_encryption :
2012-02-06 09:01:35 -08:00
password = password_dialog ( self . window )
2012-01-17 02:15:17 -08:00
if not password :
return
else :
password = None
2011-11-04 10:00:37 -07:00
2011-12-16 06:40:05 -08:00
try :
2015-08-03 22:15:54 -07:00
tx = self . wallet . mktx ( [ ( to_address , amount ) ] , password , self . config , fee )
2013-11-09 20:21:02 -08:00
except Exception as e :
2012-05-16 10:20:21 -07:00
self . show_message ( str ( e ) )
2011-11-16 06:16:36 -08:00
return
2013-03-23 01:23:57 -07:00
2015-05-06 16:52:34 -07:00
if tx . requires_fee ( self . wallet ) and fee < MIN_RELAY_TX_FEE :
2013-03-24 03:25:17 -07:00
self . show_message ( " This transaction requires a higher fee, or it will not be propagated by the network. " )
2013-03-23 01:23:57 -07:00
return
2011-12-16 06:40:05 -08:00
2013-02-27 03:51:49 -08:00
if label :
self . wallet . labels [ tx . hash ( ) ] = label
2011-11-16 06:16:36 -08:00
status , msg = self . wallet . sendtx ( tx )
2011-11-04 10:00:37 -07:00
if status :
2011-12-07 09:54:32 -08:00
self . show_message ( " payment sent. \n " + msg )
2011-11-04 10:00:37 -07:00
payto_entry . set_text ( " " )
label_entry . set_text ( " " )
amount_entry . set_text ( " " )
2011-12-07 09:54:32 -08:00
fee_entry . set_text ( " " )
2012-02-03 02:48:09 -08:00
#self.fee_box.hide()
2011-11-05 00:32:58 -07:00
self . update_sending_tab ( )
2011-11-04 10:00:37 -07:00
else :
2011-12-07 09:54:32 -08:00
self . show_message ( msg )
2011-11-04 10:00:37 -07:00
2011-12-12 22:33:23 -08:00
def treeview_button_press ( self , treeview , event ) :
2014-02-01 17:19:43 -08:00
if event . type == Gdk . EventType . DOUBLE_BUTTON_PRESS :
2011-12-12 22:33:23 -08:00
c = treeview . get_cursor ( ) [ 0 ]
2012-02-07 06:00:12 -08:00
if treeview == self . history_treeview :
tx_details = self . history_list . get_value ( self . history_list . get_iter ( c ) , 8 )
self . show_message ( tx_details )
elif treeview == self . contacts_treeview :
m = self . addressbook_list . get_value ( self . addressbook_list . get_iter ( c ) , 0 )
2013-03-14 08:32:05 -07:00
#a = self.wallet.aliases.get(m)
#if a:
# if a[0] in self.wallet.authorities.keys():
# s = self.wallet.authorities.get(a[0])
# else:
# s = "self-signed"
# msg = 'Alias: '+ m + '\nTarget address: '+ a[1] + '\n\nSigned by: ' + s + '\nSigning address:' + a[0]
# self.show_message(msg)
2012-02-07 06:00:12 -08:00
2011-12-12 22:33:23 -08:00
2011-11-04 10:00:37 -07:00
def treeview_key_press ( self , treeview , event ) :
c = treeview . get_cursor ( ) [ 0 ]
2014-02-01 17:19:43 -08:00
if event . keyval == Gdk . KEY_Up :
2011-11-04 10:00:37 -07:00
if c and c [ 0 ] == 0 :
treeview . parent . grab_focus ( )
treeview . set_cursor ( ( 0 , ) )
2014-02-01 17:19:43 -08:00
elif event . keyval == Gdk . KEY_Return :
2012-02-07 06:00:12 -08:00
if treeview == self . history_treeview :
tx_details = self . history_list . get_value ( self . history_list . get_iter ( c ) , 8 )
self . show_message ( tx_details )
elif treeview == self . contacts_treeview :
m = self . addressbook_list . get_value ( self . addressbook_list . get_iter ( c ) , 0 )
2013-03-14 08:32:05 -07:00
#a = self.wallet.aliases.get(m)
#if a:
# if a[0] in self.wallet.authorities.keys():
# s = self.wallet.authorities.get(a[0])
# else:
# s = "self"
# msg = 'Alias:'+ m + '\n\nTarget: '+ a[1] + '\nSigned by: ' + s + '\nSigning address:' + a[0]
# self.show_message(msg)
2012-02-07 06:00:12 -08:00
2011-11-04 10:00:37 -07:00
return False
def create_history_tab ( self ) :
2014-02-01 17:19:43 -08:00
self . history_list = Gtk . ListStore ( str , str , str , str , ' gboolean ' , str , str , str , str )
treeview = Gtk . TreeView ( model = self . history_list )
2011-11-04 10:00:37 -07:00
self . history_treeview = treeview
treeview . set_tooltip_column ( 7 )
treeview . show ( )
treeview . connect ( ' key-press-event ' , self . treeview_key_press )
2011-12-12 22:33:23 -08:00
treeview . connect ( ' button-press-event ' , self . treeview_button_press )
2011-11-04 10:00:37 -07:00
2014-02-01 17:19:43 -08:00
tvcolumn = Gtk . TreeViewColumn ( ' ' )
2011-11-04 10:00:37 -07:00
treeview . append_column ( tvcolumn )
2014-02-01 17:19:43 -08:00
cell = Gtk . CellRendererPixbuf ( )
2011-11-04 10:00:37 -07:00
tvcolumn . pack_start ( cell , False )
tvcolumn . set_attributes ( cell , stock_id = 1 )
2014-02-01 17:19:43 -08:00
tvcolumn = Gtk . TreeViewColumn ( ' Date ' )
2011-11-04 10:00:37 -07:00
treeview . append_column ( tvcolumn )
2014-02-01 17:19:43 -08:00
cell = Gtk . CellRendererText ( )
2011-11-04 10:00:37 -07:00
tvcolumn . pack_start ( cell , False )
tvcolumn . add_attribute ( cell , ' text ' , 2 )
2014-02-01 17:19:43 -08:00
tvcolumn = Gtk . TreeViewColumn ( ' Description ' )
2011-11-04 10:00:37 -07:00
treeview . append_column ( tvcolumn )
2014-02-01 17:19:43 -08:00
cell = Gtk . CellRendererText ( )
2011-11-04 10:00:37 -07:00
cell . set_property ( ' foreground ' , ' grey ' )
2012-03-30 14:44:54 -07:00
cell . set_property ( ' family ' , MONOSPACE_FONT )
2011-11-04 10:00:37 -07:00
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 )
2013-11-07 16:18:12 -08:00
self . wallet . set_label ( tx , new_text )
2011-11-04 10:00:37 -07:00
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 )
2014-02-01 17:19:43 -08:00
tvcolumn = Gtk . TreeViewColumn ( ' Amount ' )
2011-11-04 10:00:37 -07:00
treeview . append_column ( tvcolumn )
2014-02-01 17:19:43 -08:00
cell = Gtk . CellRendererText ( )
2011-11-04 10:00:37 -07:00
cell . set_alignment ( 1 , 0.5 )
2012-03-30 14:44:54 -07:00
cell . set_property ( ' family ' , MONOSPACE_FONT )
2011-11-04 10:00:37 -07:00
tvcolumn . pack_start ( cell , False )
tvcolumn . add_attribute ( cell , ' text ' , 5 )
2014-02-01 17:19:43 -08:00
tvcolumn = Gtk . TreeViewColumn ( ' Balance ' )
2011-11-04 10:00:37 -07:00
treeview . append_column ( tvcolumn )
2014-02-01 17:19:43 -08:00
cell = Gtk . CellRendererText ( )
2011-11-04 10:00:37 -07:00
cell . set_alignment ( 1 , 0.5 )
2012-03-30 14:44:54 -07:00
cell . set_property ( ' family ' , MONOSPACE_FONT )
2011-11-04 10:00:37 -07:00
tvcolumn . pack_start ( cell , False )
tvcolumn . add_attribute ( cell , ' text ' , 6 )
2014-02-01 17:19:43 -08:00
tvcolumn = Gtk . TreeViewColumn ( ' Tooltip ' )
2011-11-04 10:00:37 -07:00
treeview . append_column ( tvcolumn )
2014-02-01 17:19:43 -08:00
cell = Gtk . CellRendererText ( )
2011-11-04 10:00:37 -07:00
tvcolumn . pack_start ( cell , False )
tvcolumn . add_attribute ( cell , ' text ' , 7 )
tvcolumn . set_visible ( False )
2014-02-01 17:19:43 -08:00
scroll = Gtk . ScrolledWindow ( )
scroll . set_policy ( Gtk . PolicyType . NEVER , Gtk . PolicyType . AUTOMATIC )
2011-11-04 10:00:37 -07:00
scroll . add ( treeview )
self . add_tab ( scroll , ' History ' )
self . update_history_tab ( )
def create_recv_tab ( self ) :
2014-02-01 17:19:43 -08:00
self . recv_list = Gtk . ListStore ( str , str , str , str , str )
2011-11-04 10:00:37 -07:00
self . add_tab ( self . make_address_list ( True ) , ' Receive ' )
self . update_receiving_tab ( )
def create_book_tab ( self ) :
2014-02-01 17:19:43 -08:00
self . addressbook_list = Gtk . ListStore ( str , str , str )
2011-11-04 10:00:37 -07:00
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
2014-02-01 17:19:43 -08:00
treeview = Gtk . TreeView ( model = liststore )
2011-11-04 10:00:37 -07:00
treeview . connect ( ' key-press-event ' , self . treeview_key_press )
2012-02-07 06:00:12 -08:00
treeview . connect ( ' button-press-event ' , self . treeview_button_press )
2011-11-04 10:00:37 -07:00
treeview . show ( )
2012-02-07 06:00:12 -08:00
if not is_recv :
self . contacts_treeview = treeview
2011-11-04 10:00:37 -07:00
2014-02-01 17:19:43 -08:00
tvcolumn = Gtk . TreeViewColumn ( ' Address ' )
2011-11-04 10:00:37 -07:00
treeview . append_column ( tvcolumn )
2014-02-01 17:19:43 -08:00
cell = Gtk . CellRendererText ( )
2012-03-30 14:44:54 -07:00
cell . set_property ( ' family ' , MONOSPACE_FONT )
2011-11-04 10:00:37 -07:00
tvcolumn . pack_start ( cell , True )
tvcolumn . add_attribute ( cell , ' text ' , 0 )
2014-02-01 17:19:43 -08:00
tvcolumn = Gtk . TreeViewColumn ( ' Label ' )
2011-11-04 10:00:37 -07:00
tvcolumn . set_expand ( True )
treeview . append_column ( tvcolumn )
2014-02-01 17:19:43 -08:00
cell = Gtk . CellRendererText ( )
2011-11-04 10:00:37 -07:00
cell . set_property ( ' editable ' , True )
def edited_cb2 ( cell , path , new_text , liststore ) :
address = liststore . get_value ( liststore . get_iter ( path ) , 0 )
2013-11-07 16:18:12 -08:00
self . wallet . set_label ( address , new_text )
2011-11-04 10:00:37 -07:00
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 )
2014-02-01 17:19:43 -08:00
tvcolumn = Gtk . TreeViewColumn ( ' Tx ' )
2011-11-04 10:00:37 -07:00
treeview . append_column ( tvcolumn )
2014-02-01 17:19:43 -08:00
cell = Gtk . CellRendererText ( )
2011-11-04 10:00:37 -07:00
tvcolumn . pack_start ( cell , True )
tvcolumn . add_attribute ( cell , ' text ' , 2 )
2013-11-07 18:24:13 -08:00
if is_recv :
2014-02-01 17:19:43 -08:00
tvcolumn = Gtk . TreeViewColumn ( ' Balance ' )
2013-11-07 18:24:13 -08:00
treeview . append_column ( tvcolumn )
2014-02-01 17:19:43 -08:00
cell = Gtk . CellRendererText ( )
2013-11-07 18:24:13 -08:00
tvcolumn . pack_start ( cell , True )
tvcolumn . add_attribute ( cell , ' text ' , 3 )
2014-02-01 17:19:43 -08:00
tvcolumn = Gtk . TreeViewColumn ( ' Type ' )
2013-11-10 13:54:32 -08:00
treeview . append_column ( tvcolumn )
2014-02-01 17:19:43 -08:00
cell = Gtk . CellRendererText ( )
2013-11-10 13:54:32 -08:00
tvcolumn . pack_start ( cell , True )
tvcolumn . add_attribute ( cell , ' text ' , 4 )
2013-11-07 18:24:13 -08:00
2014-02-01 17:19:43 -08:00
scroll = Gtk . ScrolledWindow ( )
scroll . set_policy ( Gtk . PolicyType . AUTOMATIC , Gtk . PolicyType . AUTOMATIC )
2011-11-04 10:00:37 -07:00
scroll . add ( treeview )
2014-02-01 17:19:43 -08:00
hbox = Gtk . HBox ( )
2011-12-16 03:22:04 -08:00
if not is_recv :
2014-02-01 17:19:43 -08:00
button = Gtk . Button ( " New " )
2011-12-19 03:35:39 -08:00
button . connect ( " clicked " , self . newaddress_dialog )
2011-12-16 03:22:04 -08:00
button . show ( )
2014-02-01 17:19:43 -08:00
hbox . pack_start ( button , False , False , 0 )
2011-11-04 10:00:37 -07:00
2011-11-22 05:41:41 -08:00
def showqrcode ( w , treeview , liststore ) :
2014-07-13 16:24:29 -07:00
import qrcode
2011-11-22 05:41:41 -08:00
path , col = treeview . get_cursor ( )
if not path : return
address = liststore . get_value ( liststore . get_iter ( path ) , 0 )
2014-07-13 16:24:29 -07:00
qr = qrcode . QRCode ( )
qr . add_data ( address )
2011-11-22 05:41:41 -08:00
boxsize = 7
2014-07-13 16:24:29 -07:00
matrix = qr . get_matrix ( )
boxcount_row = len ( matrix )
2014-02-01 17:19:43 -08:00
size = ( boxcount_row + 4 ) * boxsize
def area_expose_cb ( area , cr ) :
2011-11-22 05:41:41 -08:00
style = area . get_style ( )
2014-02-01 17:19:43 -08:00
Gdk . cairo_set_source_color ( cr , style . white )
cr . rectangle ( 0 , 0 , size , size )
cr . fill ( )
Gdk . cairo_set_source_color ( cr , style . black )
for r in range ( boxcount_row ) :
for c in range ( boxcount_row ) :
2014-07-13 16:24:29 -07:00
if matrix [ r ] [ c ] :
2014-02-01 17:19:43 -08:00
cr . rectangle ( ( c + 2 ) * boxsize , ( r + 2 ) * boxsize , boxsize , boxsize )
cr . fill ( )
area = Gtk . DrawingArea ( )
2011-11-22 05:41:41 -08:00
area . set_size_request ( size , size )
2014-02-01 17:19:43 -08:00
area . connect ( " draw " , area_expose_cb )
2011-11-22 05:41:41 -08:00
area . show ( )
2014-02-01 17:19:43 -08:00
dialog = Gtk . Dialog ( address , parent = self . window , flags = Gtk . DialogFlags . MODAL , buttons = ( " ok " , 1 ) )
2011-11-22 05:41:41 -08:00
dialog . vbox . add ( area )
dialog . run ( )
dialog . destroy ( )
2014-02-01 17:19:43 -08:00
button = Gtk . Button ( " QR " )
2011-11-22 05:41:41 -08:00
button . connect ( " clicked " , showqrcode , treeview , liststore )
button . show ( )
2014-02-01 17:19:43 -08:00
hbox . pack_start ( button , False , False , 0 )
2011-11-22 05:41:41 -08:00
2014-02-01 17:19:43 -08:00
button = Gtk . Button ( " Copy to clipboard " )
2011-11-04 10:00:37 -07:00
def copy2clipboard ( w , treeview , liststore ) :
2011-11-13 15:20:49 -08:00
import platform
2011-11-04 10:00:37 -07:00
path , col = treeview . get_cursor ( )
if path :
address = liststore . get_value ( liststore . get_iter ( path ) , 0 )
2011-11-13 15:20:49 -08:00
if platform . system ( ) == ' Windows ' :
from Tkinter import Tk
r = Tk ( )
r . withdraw ( )
r . clipboard_clear ( )
r . clipboard_append ( address )
r . destroy ( )
else :
2014-02-01 17:19:43 -08:00
atom = Gdk . atom_intern ( ' CLIPBOARD ' , True )
c = Gtk . Clipboard . get ( atom )
c . set_text ( address , len ( address ) )
2011-11-04 10:00:37 -07:00
button . connect ( " clicked " , copy2clipboard , treeview , liststore )
button . show ( )
2014-02-01 17:19:43 -08:00
hbox . pack_start ( button , False , False , 0 )
2011-11-04 10:00:37 -07:00
2013-11-10 13:36:52 -08:00
if is_recv :
2014-02-01 17:19:43 -08:00
button = Gtk . Button ( " Freeze " )
2013-11-10 13:36:52 -08:00
def freeze_address ( w , treeview , liststore , wallet ) :
path , col = treeview . get_cursor ( )
if path :
address = liststore . get_value ( liststore . get_iter ( path ) , 0 )
2015-05-30 18:37:43 -07:00
wallet . set_frozen_state ( [ address ] , not wallet . is_frozen ( address ) )
2013-11-10 13:36:52 -08:00
self . update_receiving_tab ( )
button . connect ( " clicked " , freeze_address , treeview , liststore , self . wallet )
button . show ( )
2014-02-01 17:19:43 -08:00
hbox . pack_start ( button , False , False , 0 )
2013-11-10 13:36:52 -08:00
2011-11-04 10:00:37 -07:00
if not is_recv :
2014-02-01 17:19:43 -08:00
button = Gtk . Button ( " Pay to " )
2011-11-04 10:00:37 -07:00
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 )
2012-02-03 13:25:50 -08:00
self . amount_entry . grab_focus ( )
2011-11-04 10:00:37 -07:00
button . connect ( " clicked " , payto , treeview , liststore )
button . show ( )
2014-02-01 17:19:43 -08:00
hbox . pack_start ( button , False , False , 0 )
2011-11-04 10:00:37 -07:00
2014-02-01 17:19:43 -08:00
vbox = Gtk . VBox ( )
vbox . pack_start ( scroll , True , True , 0 )
vbox . pack_start ( hbox , False , False , 0 )
2011-11-04 10:00:37 -07:00
return vbox
def update_status_bar ( self ) :
2014-07-28 00:28:02 -07:00
2012-02-08 04:37:14 -08:00
if self . funds_error :
text = " Not enough funds "
2014-07-28 00:28:02 -07:00
elif self . network . is_connected ( ) :
2014-08-01 08:23:24 -07:00
host , port , _ , _ , _ = self . network . get_parameters ( )
port = int ( port )
2014-07-28 00:28:02 -07:00
height = self . network . get_local_height ( )
self . network_button . set_tooltip_text ( " Connected to %s : %d . \n %d blocks " % ( host , port , height ) )
2012-10-25 15:40:19 -07:00
if not self . wallet . up_to_date :
2014-02-01 17:19:43 -08:00
self . status_image . set_from_stock ( Gtk . STOCK_REFRESH , Gtk . IconSize . MENU )
2012-02-08 05:13:11 -08:00
text = " Synchronizing... "
else :
2014-02-01 17:19:43 -08:00
self . status_image . set_from_stock ( Gtk . STOCK_YES , Gtk . IconSize . MENU )
2015-05-05 11:52:14 -07:00
c , u , x = self . wallet . get_balance ( )
text = " Balance: %s " % ( format_satoshis ( c , False , self . num_zeros ) )
if u :
text + = " [ %s unconfirmed] " % ( format_satoshis ( u , True , self . num_zeros ) . strip ( ) )
if x :
text + = " [ %s unmatured] " % ( format_satoshis ( x , True , self . num_zeros ) . strip ( ) )
2011-11-04 10:00:37 -07:00
else :
2014-02-01 17:19:43 -08:00
self . status_image . set_from_stock ( Gtk . STOCK_NO , Gtk . IconSize . MENU )
2012-10-25 15:40:19 -07:00
self . network_button . set_tooltip_text ( " Not connected. " )
2012-02-08 04:37:14 -08:00
text = " Not connected "
2011-11-04 10:00:37 -07:00
self . status_bar . pop ( self . context_id )
2012-02-08 04:37:14 -08:00
self . status_bar . push ( self . context_id , text )
2012-10-27 10:20:50 -07:00
if self . wallet . up_to_date and self . wallet_updated :
2012-02-08 04:37:14 -08:00
self . update_history_tab ( )
self . update_receiving_tab ( )
# addressbook too...
2013-09-28 04:45:49 -07:00
self . info . set_text ( self . network . banner )
2012-10-27 10:20:50 -07:00
self . wallet_updated = False
2011-11-04 10:00:37 -07:00
def update_receiving_tab ( self ) :
self . recv_list . clear ( )
2013-03-02 02:40:17 -08:00
for address in self . wallet . addresses ( True ) :
2013-11-07 18:24:13 -08:00
Type = " R "
2013-11-10 13:54:32 -08:00
c = u = 0
2013-11-07 18:24:13 -08:00
if self . wallet . is_change ( address ) : Type = " C "
2013-11-10 13:54:32 -08:00
if address in self . wallet . imported_keys . keys ( ) :
Type = " I "
2015-05-05 11:52:14 -07:00
c , u , x = self . wallet . get_addr_balance ( address )
2015-05-30 18:37:43 -07:00
if self . wallet . is_frozen ( address ) : Type = Type + " F "
2011-11-04 10:00:37 -07:00
label = self . wallet . labels . get ( address )
2011-12-21 09:10:21 -08:00
h = self . wallet . history . get ( address , [ ] )
2012-11-04 02:57:12 -08:00
n = len ( h )
2013-11-07 18:24:13 -08:00
tx = " 0 " if n == 0 else " %d " % n
2015-05-05 11:52:14 -07:00
self . recv_list . append ( ( address , label , tx , format_satoshis ( c + u + x , False , self . num_zeros ) , Type ) )
2011-11-04 10:00:37 -07:00
def update_sending_tab ( self ) :
self . addressbook_list . clear ( )
2015-04-23 03:46:52 -07:00
for k , v in self . contacts . items ( ) :
t , v = v
self . addressbook_list . append ( ( k , v , t ) )
2011-11-04 10:00:37 -07:00
def update_history_tab ( self ) :
cursor = self . history_treeview . get_cursor ( ) [ 0 ]
self . history_list . clear ( )
2012-11-16 05:39:31 -08:00
2015-03-20 14:37:06 -07:00
for item in self . wallet . get_history ( ) :
2015-03-30 11:17:24 -07:00
tx_hash , conf , value , timestamp , balance = item
2013-04-27 08:48:27 -07:00
if conf > 0 :
2012-11-16 05:39:31 -08:00
try :
time_str = datetime . datetime . fromtimestamp ( timestamp ) . isoformat ( ' ' ) [ : - 3 ]
2013-11-10 12:30:57 -08:00
except Exception :
2012-11-16 05:39:31 -08:00
time_str = " ------ "
2014-02-01 17:19:43 -08:00
conf_icon = Gtk . STOCK_APPLY
2013-04-27 08:48:27 -07:00
elif conf == - 1 :
time_str = ' unverified '
conf_icon = None
2011-11-04 10:00:37 -07:00
else :
time_str = ' pending '
2014-02-01 17:19:43 -08:00
conf_icon = Gtk . STOCK_EXECUTE
2012-11-16 05:39:31 -08:00
2012-11-05 02:08:16 -08:00
label , is_default_label = self . wallet . get_label ( tx_hash )
2012-11-16 05:39:31 -08:00
tooltip = tx_hash + " \n %d confirmations " % conf if tx_hash else ' '
2013-03-14 08:32:05 -07:00
details = self . get_tx_details ( tx_hash )
2011-11-22 09:54:10 -08:00
self . history_list . prepend ( [ tx_hash , conf_icon , time_str , label , is_default_label ,
2013-09-11 03:05:28 -07:00
format_satoshis ( value , True , self . num_zeros , whitespaces = True ) ,
format_satoshis ( balance , False , self . num_zeros , whitespaces = True ) , tooltip , details ] )
2011-11-04 10:00:37 -07:00
if cursor : self . history_treeview . set_cursor ( cursor )
2013-03-14 08:32:05 -07:00
def get_tx_details ( self , tx_hash ) :
import datetime
if not tx_hash : return ' '
tx = self . wallet . transactions . get ( tx_hash )
2015-03-30 11:17:24 -07:00
tx . deserialize ( )
2015-03-20 14:37:06 -07:00
is_relevant , is_mine , v , fee = self . wallet . get_wallet_delta ( tx )
2015-05-06 16:52:34 -07:00
conf , timestamp = self . wallet . get_confirmations ( tx_hash )
2013-03-14 08:32:05 -07:00
if timestamp :
time_str = datetime . datetime . fromtimestamp ( timestamp ) . isoformat ( ' ' ) [ : - 3 ]
else :
time_str = ' pending '
inputs = map ( lambda x : x . get ( ' address ' ) , tx . inputs )
2014-07-13 16:24:29 -07:00
outputs = map ( lambda x : x [ 0 ] , tx . get_outputs ( ) )
2013-03-14 08:32:05 -07:00
tx_details = " Transaction Details " + " \n \n " \
+ " Transaction ID: \n " + tx_hash + " \n \n " \
+ " Status: %d confirmations \n " % conf
if is_mine :
if fee :
tx_details + = " Amount sent: %s \n " % format_satoshis ( v - fee , False ) \
+ " Transaction fee: %s \n " % format_satoshis ( fee , False )
else :
tx_details + = " Amount sent: %s \n " % format_satoshis ( v , False ) \
+ " Transaction fee: unknown \n "
else :
tx_details + = " Amount received: %s \n " % format_satoshis ( v , False ) \
tx_details + = " Date: %s \n \n " % time_str \
+ " Inputs: \n - " + ' \n - ' . join ( inputs ) + " \n \n " \
+ " Outputs: \n - " + ' \n - ' . join ( outputs )
return tx_details
2011-11-04 10:00:37 -07:00
2011-12-19 03:35:39 -08:00
def newaddress_dialog ( self , w ) :
2011-11-04 10:00:37 -07:00
2012-02-12 15:00:33 -08:00
title = " New Contact "
2014-02-01 17:19:43 -08:00
dialog = Gtk . Dialog ( title , parent = self . window ,
flags = Gtk . DialogFlags . MODAL ,
2011-12-19 03:35:39 -08:00
buttons = ( " cancel " , 0 , " ok " , 1 ) )
dialog . show ( )
2011-11-04 10:00:37 -07:00
2014-02-01 17:19:43 -08:00
label = Gtk . HBox ( )
label_label = Gtk . Label ( label = ' Label: ' )
2011-12-19 03:35:39 -08:00
label_label . set_size_request ( 120 , 10 )
label_label . show ( )
2014-02-01 17:19:43 -08:00
label . pack_start ( label_label , True , True , 0 )
label_entry = Gtk . Entry ( )
2011-12-19 03:35:39 -08:00
label_entry . show ( )
2014-02-01 17:19:43 -08:00
label . pack_start ( label_entry , True , True , 0 )
2011-12-19 03:35:39 -08:00
label . show ( )
dialog . vbox . pack_start ( label , False , True , 5 )
2014-02-01 17:19:43 -08:00
address = Gtk . HBox ( )
address_label = Gtk . Label ( label = ' Address: ' )
2011-12-19 03:35:39 -08:00
address_label . set_size_request ( 120 , 10 )
address_label . show ( )
2014-02-01 17:19:43 -08:00
address . pack_start ( address_label , True , True , 0 )
address_entry = Gtk . Entry ( )
2011-12-19 03:35:39 -08:00
address_entry . show ( )
2014-02-01 17:19:43 -08:00
address . pack_start ( address_entry , True , True , 0 )
2011-12-19 03:35:39 -08:00
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 ( )
2011-11-04 10:00:37 -07:00
2011-12-19 03:35:39 -08:00
if result == 1 :
2013-03-01 05:27:56 -08:00
if is_valid ( address ) :
2015-04-23 03:46:52 -07:00
self . contacts [ label ] = address
2011-12-19 03:35:39 -08:00
self . update_sending_tab ( )
else :
2014-02-01 17:19:43 -08:00
errorDialog = Gtk . MessageDialog (
2011-12-19 03:35:39 -08:00
parent = self . window ,
2014-02-01 17:19:43 -08:00
flags = Gtk . DialogFlags . MODAL ,
buttons = Gtk . ButtonsType . CLOSE ,
2011-12-19 03:35:39 -08:00
message_format = " Invalid address " )
errorDialog . show ( )
errorDialog . run ( )
errorDialog . destroy ( )
2011-12-08 12:43:52 -08:00
2011-11-04 10:00:37 -07:00
2012-02-14 00:52:03 -08:00
class ElectrumGui ( ) :
2013-09-11 03:05:28 -07:00
def __init__ ( self , config , network ) :
self . network = network
2012-10-11 11:10:12 -07:00
self . config = config
2013-09-11 03:05:28 -07:00
2012-02-14 00:52:03 -08:00
2012-02-14 03:45:39 -08:00
def main ( self , url = None ) :
2013-09-28 04:45:49 -07:00
2015-05-08 01:58:54 -07:00
storage = WalletStorage ( self . config . get_wallet_path ( ) )
2013-09-28 04:45:49 -07:00
if not storage . file_exists :
action = self . restore_or_create ( )
if not action :
exit ( )
self . wallet = wallet = Wallet ( storage )
gap = self . config . get ( ' gap_limit ' , 5 )
if gap != 5 :
wallet . gap_limit = gap
wallet . storage . put ( ' gap_limit ' , gap , True )
if action == ' create ' :
2014-04-30 00:31:20 -07:00
seed = wallet . make_seed ( )
show_seed_dialog ( seed , None )
2013-12-13 08:30:34 -08:00
r = change_password_dialog ( False , None )
password = r [ 2 ] if r else None
2014-04-30 00:31:20 -07:00
wallet . add_seed ( seed , password )
2014-08-29 05:11:59 -07:00
wallet . create_master_keys ( password )
wallet . create_main_account ( password )
2013-09-28 04:45:49 -07:00
wallet . synchronize ( ) # generate first addresses offline
2013-12-13 08:30:34 -08:00
2013-09-28 04:45:49 -07:00
elif action == ' restore ' :
seed = self . seed_dialog ( )
2014-04-30 00:31:20 -07:00
if not seed :
exit ( )
2013-12-13 08:30:34 -08:00
r = change_password_dialog ( False , None )
password = r [ 2 ] if r else None
2014-04-30 00:31:20 -07:00
wallet . add_seed ( seed , password )
2014-08-29 05:11:59 -07:00
wallet . create_master_keys ( password )
wallet . create_main_account ( password )
2013-09-28 04:45:49 -07:00
else :
exit ( )
else :
self . wallet = Wallet ( storage )
2013-12-13 08:30:34 -08:00
action = None
self . wallet . start_threads ( self . network )
if action == ' restore ' :
self . restore_wallet ( wallet )
2013-09-28 04:45:49 -07:00
w = ElectrumWindow ( self . wallet , self . config , self . network )
if url : w . set_url ( url )
2014-02-01 17:19:43 -08:00
Gtk . main ( )
2011-11-04 10:00:37 -07:00
2012-02-14 00:52:03 -08:00
def restore_or_create ( self ) :
2013-09-28 04:45:49 -07:00
return restore_create_dialog ( )
2012-10-11 04:18:04 -07:00
2012-11-20 06:30:46 -08:00
def seed_dialog ( self ) :
2013-09-28 04:45:49 -07:00
return run_recovery_dialog ( )
2012-11-20 06:30:46 -08:00
def network_dialog ( self ) :
2013-09-28 04:45:49 -07:00
return run_network_dialog ( self . network , parent = None )
2012-11-20 06:30:46 -08:00
2013-09-28 04:45:49 -07:00
def restore_wallet ( self , wallet ) :
2012-11-20 06:30:46 -08:00
2014-02-01 17:19:43 -08:00
dialog = Gtk . MessageDialog (
2012-11-20 06:30:46 -08:00
parent = None ,
2014-02-01 17:19:43 -08:00
flags = Gtk . DialogFlags . MODAL ,
buttons = Gtk . ButtonsType . CANCEL ,
2012-11-20 06:30:46 -08:00
message_format = " Please wait... " )
dialog . show ( )
def recover_thread ( wallet , dialog ) :
2013-09-28 04:45:49 -07:00
wallet . restore ( lambda x : x )
2014-02-01 17:19:43 -08:00
GObject . idle_add ( dialog . destroy )
2012-11-20 06:30:46 -08:00
thread . start_new_thread ( recover_thread , ( wallet , dialog ) )
r = dialog . run ( )
dialog . destroy ( )
2014-02-01 17:19:43 -08:00
if r == Gtk . ResponseType . CANCEL : return False
2012-11-20 12:36:06 -08:00
if not wallet . is_found ( ) :
2012-11-20 06:30:46 -08:00
show_message ( " No transactions found for this seed " )
return True