from electrum.wallet import format_satoshis
from electrum.bitcoin import Transaction, is_valid
from electrum import mnemonic
-from electrum import util, bitcoin, commands
+from electrum import util, bitcoin, commands, Interface, Wallet, WalletVerifier, WalletSynchronizer
+from electrum import SimpleConfig, Wallet, WalletSynchronizer, WalletStorage
+
import bmp, pyqrnative
import exchange_rate
-class Timer(QtCore.QThread):
- def run(self):
- while True:
- self.emit(QtCore.SIGNAL('timersignal'))
- time.sleep(0.5)
-
-class HelpButton(QPushButton):
- def __init__(self, text):
- QPushButton.__init__(self, '?')
- self.setFocusPolicy(Qt.NoFocus)
- self.setFixedWidth(20)
- self.clicked.connect(lambda: QMessageBox.information(self, 'Help', text, 'OK') )
-
-
-class EnterButton(QPushButton):
- def __init__(self, text, func):
- QPushButton.__init__(self, text)
- self.func = func
- self.clicked.connect(func)
-
- def keyPressEvent(self, e):
- if e.key() == QtCore.Qt.Key_Return:
- apply(self.func,())
class MyTreeWidget(QTreeWidget):
def __init__(self, parent):
-def waiting_dialog(f):
-
- s = Timer()
- s.start()
- w = QDialog()
- w.resize(200, 70)
- w.setWindowTitle('Electrum')
- l = QLabel('')
- vbox = QVBoxLayout()
- vbox.addWidget(l)
- w.setLayout(vbox)
- w.show()
- def ff():
- s = f()
- if s: l.setText(s)
- else: w.close()
- w.connect(s, QtCore.SIGNAL('timersignal'), ff)
- w.exec_()
- w.destroy()
-
default_column_widths = { "history":[40,140,350,140], "contacts":[350,330], "receive":[[370], [370,200,130]] }
class ElectrumWindow(QMainWindow):
+ def changeEvent(self, event):
+ flags = self.windowFlags();
+ if event and event.type() == QtCore.QEvent.WindowStateChange:
+ if self.windowState() & QtCore.Qt.WindowMinimized:
+ self.build_menu(True)
+ # The only way to toggle the icon in the window managers taskbar is to use the Qt.Tooltip flag
+ # The problem is that it somehow creates an (in)visible window that will stay active and prevent
+ # Electrum from closing.
+ # As for now I have no clue how to implement a proper 'hide to tray' functionality.
+ # self.setWindowFlags(flags & ~Qt.ToolTip)
+ elif event.oldState() & QtCore.Qt.WindowMinimized:
+ self.build_menu(False)
+ #self.setWindowFlags(flags | Qt.ToolTip)
+
+ def build_menu(self, is_hidden = False):
+ m = QMenu()
+ if self.isMinimized():
+ m.addAction(_("Show"), self.showNormal)
+ else:
+ m.addAction(_("Hide"), self.showMinimized)
- def __init__(self, wallet, config):
+ m.addSeparator()
+ m.addAction(_("Exit Electrum"), self.close)
+ self.tray.setContextMenu(m)
+
+ def tray_activated(self, reason):
+ if reason == QSystemTrayIcon.DoubleClick:
+ self.showNormal()
+
+
+ def __init__(self, config):
QMainWindow.__init__(self)
- self.lite = None
- self.wallet = wallet
+
self.config = config
+ self.init_plugins()
+
+ self._close_electrum = False
+ self.lite = None
self.current_account = self.config.get("current_account", None)
- self.init_plugins()
+ self.icon = QIcon(os.getcwd() + '/icons/electrum.png')
+ self.tray = QSystemTrayIcon(self.icon, self)
+ self.tray.setToolTip('Electrum')
+ self.tray.activated.connect(self.tray_activated)
+
+ self.build_menu()
+ self.tray.show()
self.create_status_bar()
self.need_update = threading.Event()
- self.wallet.interface.register_callback('updated', lambda: self.need_update.set())
- self.wallet.interface.register_callback('banner', lambda: self.emit(QtCore.SIGNAL('banner_signal')))
- self.wallet.interface.register_callback('disconnected', lambda: self.emit(QtCore.SIGNAL('update_status')))
- self.wallet.interface.register_callback('disconnecting', lambda: self.emit(QtCore.SIGNAL('update_status')))
- self.expert_mode = config.get('classic_expert_mode', False)
+ self.expert_mode = config.get('classic_expert_mode', False)
self.decimal_point = config.get('decimal_point', 8)
+ self.num_zeros = int(config.get('num_zeros',0))
+ self.fee = int(config.get('fee_per_kb',20000))
set_language(config.get('language'))
g = self.config.get("winpos-qt",[100, 100, 840, 400])
self.setGeometry(g[0], g[1], g[2], g[3])
- title = 'Electrum ' + self.wallet.electrum_version + ' - ' + self.config.path
- if not self.wallet.seed: title += ' [%s]' % (_('seedless'))
- self.setWindowTitle( title )
self.init_menubar()
self.connect(self, QtCore.SIGNAL('update_status'), self.update_status)
self.connect(self, QtCore.SIGNAL('banner_signal'), lambda: self.console.showMessage(self.wallet.interface.banner) )
+ self.connect(self, QtCore.SIGNAL('transaction_signal'), lambda: self.notify_transactions() )
self.history_list.setFocus(True)
self.exchanger = exchange_rate.Exchanger(self)
tabs.setCurrentIndex (n)
tabs.setCurrentIndex (0)
- # fix fee
- if self.wallet.fee < 50000:
- self.wallet.set_fee(50000)
- self.show_message("Note: Your default fee was raised to 0.0005 BTC/kilobyte")
+ # plugins that need to change the GUI do it here
+ self.run_hook('init')
+
+
+
+ def load_wallet(self, wallet):
+ import electrum
+ self.wallet = wallet
+
+ self.wallet.interface.register_callback('updated', lambda: self.need_update.set())
+ self.wallet.interface.register_callback('banner', lambda: self.emit(QtCore.SIGNAL('banner_signal')))
+ self.wallet.interface.register_callback('disconnected', lambda: self.emit(QtCore.SIGNAL('update_status')))
+ self.wallet.interface.register_callback('disconnecting', lambda: self.emit(QtCore.SIGNAL('update_status')))
+ self.wallet.interface.register_callback('new_transaction', lambda: self.emit(QtCore.SIGNAL('transaction_signal')))
+ title = 'Electrum ' + self.wallet.electrum_version + ' - ' #+ self.config.path
+ if not self.wallet.seed: title += ' [%s]' % (_('seedless'))
+ self.setWindowTitle( title )
+ self.update_wallet()
# set initial message
self.console.showMessage(self.wallet.interface.banner)
+ # Once GUI has been initialized check if we want to announce something since the callback has been called before the GUI was initialized
+ self.notify_transactions()
- # plugins that need to change the GUI do it here
- self.run_hook('init_gui')
+ # account selector
+ accounts = self.wallet.get_accounts()
+ self.account_selector.clear()
+ if len(accounts) > 1:
+ self.account_selector.addItems([_("All accounts")] + accounts.values())
+ self.account_selector.setCurrentIndex(0)
+ self.account_selector.show()
+ else:
+ self.account_selector.hide()
+
+ self.update_lock_icon()
+ self.update_buttons_on_seed()
+ self.update_console()
def select_wallet_file(self):
- wallet_folder = self.wallet.config.path
+ wallet_folder = self.wallet.storage.path
re.sub("(\/\w*.dat)$", "", wallet_folder)
- file_name = QFileDialog.getOpenFileName(self, "Select your wallet file", wallet_folder, "*.dat")
- if not file_name:
+ file_name = unicode( QFileDialog.getOpenFileName(self, "Select your wallet file", wallet_folder, "*.dat") )
+ return file_name
+
+
+ def open_wallet(self):
+
+ filename = self.select_wallet_file()
+ if not filename:
return
- else:
- self.load_wallet(file_name)
+
+ storage = WalletStorage({'wallet_path': filename})
+ if not storage.file_exists:
+ self.show_message("file not found "+ filename)
+ return
+
+ interface = self.wallet.interface
+ verifier = self.wallet.verifier
+ self.wallet.synchronizer.stop()
+
+ # create wallet
+ wallet = Wallet(storage)
+ wallet.interface = interface
+ wallet.verifier = verifier
+ synchronizer = WalletSynchronizer(wallet)
+ synchronizer.start()
+
+ self.load_wallet(wallet)
+
+
+ def new_wallet(self):
+ import installwizard
+
+ wallet_folder = self.wallet.storage.path
+ re.sub("(\/\w*.dat)$", "", wallet_folder)
+ filename = self.getSaveFileName("Select your wallet file", wallet_folder, "*.dat")
+
+ storage = WalletStorage({'wallet_path': filename})
+ assert not storage.file_exists
+
+ wizard = installwizard.InstallWizard(self.config, self.wallet.interface, storage)
+ wallet = wizard.run()
+ if wallet:
+ self.load_wallet(wallet)
+
def init_menubar(self):
menubar = QMenuBar()
- electrum_menu = menubar.addMenu(_("&File"))
- open_wallet_action = electrum_menu.addAction(_("Open wallet"))
- open_wallet_action.triggered.connect(self.select_wallet_file)
+ file_menu = menubar.addMenu(_("&File"))
+ open_wallet_action = file_menu.addAction(_("&Open"))
+ open_wallet_action.triggered.connect(self.open_wallet)
- preferences_name = _("Preferences")
- if sys.platform == 'darwin':
- preferences_name = _("Electrum preferences") # Settings / Preferences are all reserved keywords in OSX using this as work around
+ new_wallet_action = file_menu.addAction(_("&Create/Restore"))
+ new_wallet_action.triggered.connect(self.new_wallet)
- preferences_menu = electrum_menu.addAction(preferences_name)
+ wallet_backup = file_menu.addAction(_("&Copy"))
+ wallet_backup.triggered.connect(lambda: backup_wallet(self.config.path))
+
+ quit_item = file_menu.addAction(_("&Close"))
+ quit_item.triggered.connect(self.close)
+
+ wallet_menu = menubar.addMenu(_("&Wallet"))
+
+ # Settings / Preferences are all reserved keywords in OSX using this as work around
+ preferences_name = _("Electrum preferences") if sys.platform == 'darwin' else _("Preferences")
+ preferences_menu = wallet_menu.addAction(preferences_name)
preferences_menu.triggered.connect(self.settings_dialog)
- electrum_menu.addSeparator()
- raw_transaction_menu = electrum_menu.addMenu(_("&Load raw transaction"))
+ wallet_menu.addSeparator()
+
+ raw_transaction_menu = wallet_menu.addMenu(_("&Load raw transaction"))
raw_transaction_file = raw_transaction_menu.addAction(_("&From file"))
raw_transaction_file.triggered.connect(self.do_process_from_file)
raw_transaction_text = raw_transaction_menu.addAction(_("&From text"))
raw_transaction_text.triggered.connect(self.do_process_from_text)
- electrum_menu.addSeparator()
- quit_item = electrum_menu.addAction(_("&Close"))
- quit_item.triggered.connect(self.close)
-
- wallet_menu = menubar.addMenu(_("&Wallet"))
- wallet_backup = wallet_menu.addAction(_("&Create backup"))
- wallet_backup.triggered.connect(backup_wallet)
+ wallet_menu.addSeparator()
show_menu = wallet_menu.addMenu(_("Show"))
- if self.wallet.seed:
- show_seed = show_menu.addAction(_("&Seed"))
- show_seed.triggered.connect(self.show_seed_dialog)
+ #if self.wallet.seed:
+ show_seed = show_menu.addAction(_("&Seed"))
+ show_seed.triggered.connect(self.show_seed_dialog)
show_mpk = show_menu.addAction(_("&Master Public Key"))
show_mpk.triggered.connect(self.show_master_public_key)
new_contact = wallet_menu.addAction(_("&New contact"))
new_contact.triggered.connect(self.new_contact_dialog)
+ new_account = wallet_menu.addAction(_("&New account"))
+ new_account.triggered.connect(self.new_account_dialog)
+
import_menu = menubar.addMenu(_("&Import"))
in_labels = import_menu.addAction(_("&Labels"))
in_labels.triggered.connect(self.do_import_labels)
- def load_wallet(self, filename):
- import electrum
-
- config = electrum.SimpleConfig({'wallet_path': filename})
- if not config.wallet_file_exists:
- self.show_message("file not found "+ filename)
- return
-
- #self.wallet.verifier.stop()
- interface = self.wallet.interface
- verifier = self.wallet.verifier
- self.wallet.synchronizer.stop()
-
- self.config = config
- self.wallet = electrum.Wallet(self.config)
- self.wallet.interface = interface
- self.wallet.verifier = verifier
+ def notify_transactions(self):
+ print_error("Notifying GUI")
+ if len(self.wallet.interface.pending_transactions_for_notifications) > 0:
+ # Combine the transactions if there are more then three
+ tx_amount = len(self.wallet.interface.pending_transactions_for_notifications)
+ if(tx_amount >= 3):
+ total_amount = 0
+ for tx in self.wallet.interface.pending_transactions_for_notifications:
+ is_relevant, is_mine, v, fee = self.wallet.get_tx_value(tx)
+ if(v > 0):
+ total_amount += v
- synchronizer = electrum.WalletSynchronizer(self.wallet, self.config)
- synchronizer.start()
+ self.notify("%s new transactions received. Total amount received in the new transactions %s %s" \
+ % (tx_amount, self.format_amount(total_amount), self.base_unit()))
- self.update_wallet()
+ self.wallet.interface.pending_transactions_for_notifications = []
+ else:
+ for tx in self.wallet.interface.pending_transactions_for_notifications:
+ if tx:
+ self.wallet.interface.pending_transactions_for_notifications.remove(tx)
+ is_relevant, is_mine, v, fee = self.wallet.get_tx_value(tx)
+ if(v > 0):
+ self.notify("New transaction received. %s %s" % (self.format_amount(v), self.base_unit()))
-
+ def notify(self, message):
+ self.tray.showMessage("Electrum", message, QSystemTrayIcon.Information, 20000)
# plugins
def init_plugins(self):
plugins = [ __import__('electrum_plugins.'+name, fromlist=['electrum_plugins']) for name in plugin_names]
self.plugins = []
- for p in plugins:
+ for name, p in zip(plugin_names, plugins):
try:
- self.plugins.append( p.Plugin(self) )
+ self.plugins.append( p.Plugin(self, name) )
except:
print_msg("Error:cannot initialize plugin",p)
traceback.print_exc(file=sys.stdout)
return
+
+ def set_fee(self, fee):
+ if self.fee != fee:
+ self.fee = fee
+ self.config.set_key('fee_per_kb', self.fee, True)
+
def set_label(self, name, text = None):
changed = False
old_text = self.wallet.labels.get(name)
if text:
if old_text != text:
self.wallet.labels[name] = text
- self.wallet.config.set_key('labels', self.wallet.labels)
+ self.wallet.storage.set_key('labels', self.wallet.labels)
changed = True
else:
if old_text:
self.need_update.clear()
self.run_hook('timer_actions')
- def format_amount(self, x, is_diff=False):
- return format_satoshis(x, is_diff, self.wallet.num_zeros, self.decimal_point)
+ def format_amount(self, x, is_diff=False, whitespaces=False):
+ return format_satoshis(x, is_diff, self.num_zeros, self.decimal_point, whitespaces)
def read_amount(self, x):
if x in['.', '']: return None
text = _( "Balance" ) + ": %s "%( self.format_amount(c) ) + self.base_unit()
if u: text += " [%s unconfirmed]"%( self.format_amount(u,True).strip() )
text += self.create_quote_text(Decimal(c+u)/100000000)
+ self.tray.setToolTip(text)
icon = QIcon(":icons/status_connected.png")
else:
text = _("Not connected")
icon = QIcon(":icons/confirmed.png")
if value is not None:
- v_str = self.format_amount(value, True)
+ v_str = self.format_amount(value, True, whitespaces=True)
else:
v_str = '--'
- balance_str = self.format_amount(balance)
+ balance_str = self.format_amount(balance, whitespaces=True)
if tx_hash:
label, is_default_label = self.wallet.get_label(tx_hash)
_('Bitcoin transactions are in general not free. A transaction fee is paid by the sender of the funds.') + '\n\n'\
+ _('The amount of fee can be decided freely by the sender. However, transactions with low fees take more time to be processed.') + '\n\n'\
+ _('A suggested fee is automatically added to this field. You may override it. The suggested fee increases with the size of the transaction.')), 4, 3)
- b = ''
- if self.wallet.seed:
- b = EnterButton(_("Send"), self.do_send)
- else:
- b = EnterButton(_("Create unsigned transaction"), self.do_send)
- grid.addWidget(b, 6, 1)
+
+
+ self.send_button = EnterButton(_("Send"), self.do_send)
+ grid.addWidget(self.send_button, 6, 1)
b = EnterButton(_("Clear"),self.do_clear)
grid.addWidget(b, 6, 2)
return lambda s, *args: s.do_protect(func, args)
- @protected
- def do_send(self, password):
+ def do_send(self):
label = unicode( self.message_e.text() )
r = unicode( self.payto_e.text() )
QMessageBox.warning(self, _('Error'), _('Invalid Fee'), _('OK'))
return
+ confirm_amount = self.config.get('confirm_amount', 100000000)
+ if amount >= confirm_amount:
+ if not self.question("send %s to %s?"%(self.format_amount(amount) + ' '+ self.base_unit(), to_address)):
+ return
+
+ self.send_tx(to_address, amount, fee, label)
+
+
+ @protected
+ def send_tx(self, to_address, amount, fee, label, password):
+
try:
tx = self.wallet.mktx( [(to_address, amount)], password, fee, account=self.current_account)
except BaseException, e:
+ traceback.print_exc(file=sys.stdout)
self.show_message(str(e))
return
account_items = []
for k, account in account_items:
- name = account.get('name',str(k))
+ name = self.wallet.labels.get(k, 'unnamed account')
c,u = self.wallet.get_account_balance(k)
account_item = QTreeWidgetItem( [ name, '', self.format_amount(c+u), ''] )
l.addTopLevelItem(account_item)
is_red = False
gap = 0
- for address in account[is_change]:
+ for address in account.get_addresses(is_change):
h = self.wallet.history.get(address,[])
if h == []:
def create_console_tab(self):
from qt_console import Console
self.console = console = Console()
- self.console.history = self.config.get("console-history",[])
- self.console.history_index = len(self.console.history)
+ return console
+
+
+ def update_console(self):
+ console = self.console
+ console.history = self.config.get("console-history",[])
+ console.history_index = len(console.history)
console.updateNamespace({'wallet' : self.wallet, 'interface' : self.wallet.interface, 'gui':self})
console.updateNamespace({'util' : util, 'bitcoin':bitcoin})
methods[m] = mkfunc(c._run, m)
console.updateNamespace(methods)
- return console
+
def change_account(self,s):
if s == _("All accounts"):
if(update_notification.new_version):
sb.addPermanentWidget(update_notification)
- accounts = self.wallet.get_accounts()
- if len(accounts) > 1:
- from_combo = QComboBox()
- from_combo.addItems([_("All accounts")] + accounts.values())
- from_combo.setCurrentIndex(0)
- self.connect(from_combo,SIGNAL("activated(QString)"),self.change_account)
- sb.addPermanentWidget(from_combo)
+ self.account_selector = QComboBox()
+ self.connect(self.account_selector,SIGNAL("activated(QString)"),self.change_account)
+ sb.addPermanentWidget(self.account_selector)
if (int(qtVersion[0]) >= 4 and int(qtVersion[2]) >= 7):
sb.addPermanentWidget( StatusBarButton( QIcon(":icons/switchgui.png"), _("Switch to Lite Mode"), self.go_lite ) )
- if self.wallet.seed:
- self.lock_icon = QIcon(":icons/lock.png") if self.wallet.use_encryption else QIcon(":icons/unlock.png")
- self.password_button = StatusBarButton( self.lock_icon, _("Password"), lambda: self.change_password_dialog(self.wallet, self) )
- sb.addPermanentWidget( self.password_button )
+
+ self.lock_icon = QIcon()
+ self.password_button = StatusBarButton( self.lock_icon, _("Password"), self.change_password_dialog )
+ sb.addPermanentWidget( self.password_button )
+
sb.addPermanentWidget( StatusBarButton( QIcon(":icons/preferences.png"), _("Preferences"), self.settings_dialog ) )
- if self.wallet.seed:
- sb.addPermanentWidget( StatusBarButton( QIcon(":icons/seed.png"), _("Seed"), self.show_seed_dialog ) )
+ self.seed_button = StatusBarButton( QIcon(":icons/seed.png"), _("Seed"), self.show_seed_dialog )
+ sb.addPermanentWidget( self.seed_button )
self.status_button = StatusBarButton( QIcon(":icons/status_disconnected.png"), _("Network"), self.run_network_dialog )
sb.addPermanentWidget( self.status_button )
self.run_hook('create_status_bar', (sb,))
self.setStatusBar(sb)
+
+
+ def update_lock_icon(self):
+ icon = QIcon(":icons/lock.png") if self.wallet.use_encryption else QIcon(":icons/unlock.png")
+ self.password_button.setIcon( icon )
+
+
+ def update_buttons_on_seed(self):
+ if self.wallet.seed:
+ self.seed_button.show()
+ self.password_button.show()
+ self.send_button.setText(_("Send"))
+ else:
+ self.password_button.hide()
+ self.seed_button.hide()
+ self.send_button.setText(_("Create unsigned transaction"))
+
+
+ def change_password_dialog(self):
+ from password_dialog import PasswordDialog
+ d = PasswordDialog(self.wallet, self)
+ d.run()
+ self.update_lock_icon()
+
def go_lite(self):
import gui_lite
self.lite = gui_lite.ElectrumGui(self.wallet, self.config, self)
self.lite.main(None)
+
def new_contact_dialog(self):
text, ok = QInputDialog.getText(self, _('New Contact'), _('Address') + ':')
address = unicode(text)
else:
QMessageBox.warning(self, _('Error'), _('Invalid Address'), _('OK'))
+
+ def new_account_dialog(self):
+
+ dialog = QDialog(self)
+ dialog.setModal(1)
+ dialog.setWindowTitle(_("New Account"))
+
+ addr = self.wallet.new_account_address()
+ vbox = QVBoxLayout()
+ vbox.addWidget(QLabel(_("To create a new account, please send coins to the first address of that account:")))
+ e = QLineEdit(addr)
+ e.setReadOnly(True)
+ vbox.addWidget(e)
+
+ ok_button = QPushButton(_("OK"))
+ ok_button.setDefault(True)
+ ok_button.clicked.connect(dialog.accept)
+
+ hbox = QHBoxLayout()
+ hbox.addStretch(1)
+ hbox.addWidget(ok_button)
+ vbox.addLayout(hbox)
+
+ dialog.setLayout(vbox)
+ dialog.exec_()
+
+
+
def show_master_public_key(self):
dialog = QDialog(self)
dialog.setModal(1)
except:
QMessageBox.warning(self, _('Error'), _('Incorrect Password'), _('OK'))
return
- self.show_seed(seed, self.wallet.imported_keys, self)
-
-
- @classmethod
- def show_seed(self, seed, imported_keys, parent=None):
- dialog = QDialog(parent)
- dialog.setModal(1)
- dialog.setWindowTitle('Electrum' + ' - ' + _('Seed'))
-
- brainwallet = ' '.join(mnemonic.mn_encode(seed))
-
- label1 = QLabel(_("Your wallet generation seed is")+ ":")
-
- seed_text = QTextEdit(brainwallet)
- seed_text.setReadOnly(True)
- seed_text.setMaximumHeight(130)
-
- msg2 = _("Please write down or memorize these 12 words (order is important).") + " " \
- + _("This seed will allow you to recover your wallet in case of computer failure.") + " " \
- + _("Your seed is also displayed as QR code, in case you want to transfer it to a mobile phone.") + "<p>" \
- + "<b>"+_("WARNING")+":</b> " + _("Never disclose your seed. Never type it on a website.") + "</b><p>"
- if imported_keys:
- msg2 += "<b>"+_("WARNING")+":</b> " + _("Your wallet contains imported keys. These keys cannot be recovered from seed.") + "</b><p>"
- label2 = QLabel(msg2)
- label2.setWordWrap(True)
- logo = QLabel()
- logo.setPixmap(QPixmap(":icons/seed.png").scaledToWidth(56))
- logo.setMaximumWidth(60)
+ from seed_dialog import SeedDialog
+ d = SeedDialog(self)
+ d.show_seed(seed, self.wallet.imported_keys)
- qrw = QRCodeWidget(seed)
- ok_button = QPushButton(_("OK"))
- ok_button.setDefault(True)
- ok_button.clicked.connect(dialog.accept)
-
- grid = QGridLayout()
- #main_layout.addWidget(logo, 0, 0)
-
- grid.addWidget(logo, 0, 0)
- grid.addWidget(label1, 0, 1)
-
- grid.addWidget(seed_text, 1, 0, 1, 2)
-
- grid.addWidget(qrw, 0, 2, 2, 1)
-
- vbox = QVBoxLayout()
- vbox.addLayout(grid)
- vbox.addWidget(label2)
-
- hbox = QHBoxLayout()
- hbox.addStretch(1)
- hbox.addWidget(ok_button)
- vbox.addLayout(hbox)
-
- dialog.setLayout(vbox)
- dialog.exec_()
def show_qrcode(self, data, title = "QR code"):
if not data: return
- @staticmethod
- def change_password_dialog( wallet, parent=None ):
-
- if not wallet.seed:
- QMessageBox.information(parent, _('Error'), _('No seed'), _('OK'))
- return
-
- d = QDialog(parent)
- d.setModal(1)
-
- pw = QLineEdit()
- pw.setEchoMode(2)
- new_pw = QLineEdit()
- new_pw.setEchoMode(2)
- conf_pw = QLineEdit()
- conf_pw.setEchoMode(2)
-
- vbox = QVBoxLayout()
- if parent:
- msg = (_('Your wallet is encrypted. Use this dialog to change your password.')+'\n'\
- +_('To disable wallet encryption, enter an empty new password.')) \
- if wallet.use_encryption else _('Your wallet keys are not encrypted')
- else:
- msg = _("Please choose a password to encrypt your wallet keys.")+'\n'\
- +_("Leave these fields empty if you want to disable encryption.")
- vbox.addWidget(QLabel(msg))
-
- grid = QGridLayout()
- grid.setSpacing(8)
-
- if wallet.use_encryption:
- grid.addWidget(QLabel(_('Password')), 1, 0)
- grid.addWidget(pw, 1, 1)
-
- grid.addWidget(QLabel(_('New Password')), 2, 0)
- grid.addWidget(new_pw, 2, 1)
-
- grid.addWidget(QLabel(_('Confirm Password')), 3, 0)
- grid.addWidget(conf_pw, 3, 1)
- vbox.addLayout(grid)
-
- vbox.addLayout(ok_cancel_buttons(d))
- d.setLayout(vbox)
-
- if not d.exec_(): return
-
- password = unicode(pw.text()) if wallet.use_encryption else None
- new_password = unicode(new_pw.text())
- new_password2 = unicode(conf_pw.text())
-
- try:
- seed = wallet.decode_seed(password)
- except:
- QMessageBox.warning(parent, _('Error'), _('Incorrect Password'), _('OK'))
- return
-
- if new_password != new_password2:
- QMessageBox.warning(parent, _('Error'), _('Passwords do not match'), _('OK'))
- return ElectrumWindow.change_password_dialog(wallet, parent) # Retry
-
- try:
- wallet.update_password(seed, password, new_password)
- except:
- QMessageBox.warning(parent, _('Error'), _('Failed to update password'), _('OK'))
- return
-
- QMessageBox.information(parent, _('Success'), _('Password was updated successfully'), _('OK'))
-
- if parent:
- icon = QIcon(":icons/lock.png") if wallet.use_encryption else QIcon(":icons/unlock.png")
- parent.password_button.setIcon( icon )
-
-
def generate_transaction_information_widget(self, tx):
tabs = QTabWidget(self)
nz_label = QLabel(_('Display zeros'))
grid_ui.addWidget(nz_label, 0, 0)
nz_e = AmountEdit(None,True)
- nz_e.setText("%d"% self.wallet.num_zeros)
+ nz_e.setText("%d"% self.num_zeros)
grid_ui.addWidget(nz_e, 0, 1)
msg = _('Number of zeros displayed after the decimal point. For example, if this is set to 2, "1." will be displayed as "1.00"')
grid_ui.addWidget(HelpButton(msg), 0, 2)
fee_label = QLabel(_('Transaction fee'))
grid_wallet.addWidget(fee_label, 0, 0)
fee_e = AmountEdit(self.base_unit)
- fee_e.setText(self.format_amount(self.wallet.fee).strip())
+ fee_e.setText(self.format_amount(self.fee).strip())
grid_wallet.addWidget(fee_e, 0, 2)
msg = _('Fee per kilobyte of transaction.') + ' ' \
+ _('Recommended value') + ': ' + self.format_amount(50000)
return lambda: cb.setChecked(p.toggle())
for i, p in enumerate(self.plugins):
try:
- name, description = p.get_info()
- cb = QCheckBox(name)
+ cb = QCheckBox(p.fullname())
cb.setDisabled(not p.is_available())
cb.setChecked(p.is_enabled())
cb.clicked.connect(mk_toggle(cb,p))
grid_plugins.addWidget(cb, i, 0)
if p.requires_settings():
grid_plugins.addWidget(EnterButton(_('Settings'), p.settings_dialog), i, 1)
- grid_plugins.addWidget(HelpButton(description), i, 2)
+ grid_plugins.addWidget(HelpButton(p.description()), i, 2)
except:
print_msg("Error: cannot display plugin", p)
traceback.print_exc(file=sys.stdout)
QMessageBox.warning(self, _('Error'), _('Invalid value') +': %s'%fee, _('OK'))
return
- self.wallet.set_fee(fee)
+ self.set_fee(fee)
nz = unicode(nz_e.text())
try:
QMessageBox.warning(self, _('Error'), _('Invalid value')+':%s'%nz, _('OK'))
return
- if self.wallet.num_zeros != nz:
- self.wallet.num_zeros = nz
+ if self.num_zeros != nz:
+ self.num_zeros = nz
self.config.set_key('num_zeros', nz, True)
self.update_history_tab()
self.update_receive_tab()
g = self.geometry()
self.config.set_key("winpos-qt", [g.left(),g.top(),g.width(),g.height()], True)
self.save_column_widths()
- self.config.set_key("console-history",self.console.history[-50:])
+ self.config.set_key("console-history", self.console.history[-50:], True)
event.accept()
+class OpenFileEventFilter(QObject):
+ def __init__(self, windows):
+ self.windows = windows
+ super(OpenFileEventFilter, self).__init__()
+
+ def eventFilter(self, obj, event):
+ if event.type() == QtCore.QEvent.FileOpen:
+ if len(self.windows) >= 1:
+ self.windows[0].set_url(event.url().toString())
+ return True
+ return False
class ElectrumGui:
- def __init__(self, wallet, config, app=None):
- self.wallet = wallet
+ def __init__(self, config, interface, app=None):
+ self.interface = interface
self.config = config
+ self.windows = []
+ self.efilter = OpenFileEventFilter(self.windows)
if app is None:
self.app = QApplication(sys.argv)
+ self.app.installEventFilter(self.efilter)
- def restore_or_create(self):
- msg = _("Wallet file not found.")+"\n"+_("Do you want to create a new wallet, or to restore an existing one?")
- r = QMessageBox.question(None, _('Message'), msg, _('Create'), _('Restore'), _('Cancel'), 0, 2)
- if r==2: return None
- return 'restore' if r==1 else 'create'
-
-
- def verify_seed(self):
- r = self.seed_dialog(False)
- if r != self.wallet.seed:
- QMessageBox.warning(None, _('Error'), 'incorrect seed', 'OK')
- return False
- else:
- return True
-
-
-
- def seed_dialog(self, is_restore=True):
- d = QDialog()
- d.setModal(1)
-
- vbox = QVBoxLayout()
- if is_restore:
- msg = _("Please enter your wallet seed (or your master public key if you want to create a watching-only wallet)." + ' ')
- else:
- msg = _("Your seed is important! To make sure that you have properly saved your seed, please type it here." + ' ')
-
- msg += _("Your seed can be entered as a sequence of words, or as a hexadecimal string."+ '\n')
-
- label=QLabel(msg)
- label.setWordWrap(True)
- vbox.addWidget(label)
-
- seed_e = QTextEdit()
- seed_e.setMaximumHeight(100)
- vbox.addWidget(seed_e)
-
- if is_restore:
- grid = QGridLayout()
- grid.setSpacing(8)
- gap_e = AmountEdit(None, True)
- gap_e.setText("5")
- grid.addWidget(QLabel(_('Gap limit')), 2, 0)
- grid.addWidget(gap_e, 2, 1)
- grid.addWidget(HelpButton(_('Keep the default value unless you modified this parameter in your wallet.')), 2, 3)
- vbox.addLayout(grid)
-
- vbox.addLayout(ok_cancel_buttons(d))
- d.setLayout(vbox)
-
- if not d.exec_(): return
-
- try:
- seed = str(seed_e.toPlainText())
- seed.decode('hex')
- except:
- try:
- seed = mnemonic.mn_decode( seed.split() )
- except:
- QMessageBox.warning(None, _('Error'), _('I cannot decode this'), _('OK'))
- return
-
- if not seed:
- QMessageBox.warning(None, _('Error'), _('No seed'), _('OK'))
- return
+ def main(self, url):
- if not is_restore:
- return seed
+ storage = WalletStorage(self.config)
+ if not storage.file_exists:
+ import installwizard
+ wizard = installwizard.InstallWizard(self.config, self.interface, storage)
+ wallet = wizard.run()
+ if not wallet:
+ exit()
else:
- try:
- gap = int(unicode(gap_e.text()))
- except:
- QMessageBox.warning(None, _('Error'), 'error', 'OK')
- return
- return seed, gap
-
-
- def network_dialog(self):
- return NetworkDialog(self.wallet.interface, self.config, None).do_exec()
-
-
- def show_seed(self):
- ElectrumWindow.show_seed(self.wallet.seed, self.wallet.imported_keys)
-
- def password_dialog(self):
- if self.wallet.seed:
- ElectrumWindow.change_password_dialog(self.wallet)
-
-
- def restore_wallet(self):
- wallet = self.wallet
- # wait until we are connected, because the user might have selected another server
- if not wallet.interface.is_connected:
- waiting = lambda: False if wallet.interface.is_connected else "%s \n" % (_("Connecting..."))
- waiting_dialog(waiting)
-
- waiting = lambda: False if wallet.is_up_to_date() else "%s\n%s %d\n%s %.1f"\
- %(_("Please wait..."),_("Addresses generated:"),len(wallet.addresses(True)),_("Kilobytes received:"), wallet.interface.bytes_received/1024.)
+ wallet = Wallet(storage)
- wallet.set_up_to_date(False)
- wallet.interface.poke('synchronizer')
- waiting_dialog(waiting)
- if wallet.is_found():
- print_error( "Recovery successful" )
- else:
- QMessageBox.information(None, _('Error'), _("No transactions found for this seed"), _('OK'))
+ wallet.interface = self.interface
- return True
+ verifier = WalletVerifier(self.interface, storage)
+ verifier.start()
+ wallet.set_verifier(verifier)
+ synchronizer = WalletSynchronizer(wallet)
+ synchronizer.start()
- def main(self,url):
s = Timer()
s.start()
- w = ElectrumWindow(self.wallet, self.config)
+ w = ElectrumWindow(self.config)
+ w.load_wallet(wallet)
+
+ self.windows.append(w)
if url: w.set_url(url)
w.app = self.app
w.connect_slots(s)
self.app.exec_()
+ verifier.stop()
+ synchronizer.stop()
+