self.config = config
self.network = network
+ self.gui_object = gui_object
self.tray = gui_object.tray
self.go_lite = gui_object.go_lite
self.lite = None
set_language(config.get('language'))
self.funds_error = False
- self.payment_request = None
self.completions = QStringListModel()
self.tabs = tabs = QTabWidget(self)
self.connect(self, QtCore.SIGNAL('update_status'), self.update_status)
self.connect(self, QtCore.SIGNAL('banner_signal'), lambda: self.console.showMessage(self.network.banner) )
self.connect(self, QtCore.SIGNAL('transaction_signal'), lambda: self.notify_transactions() )
- self.connect(self, QtCore.SIGNAL('send_tx2'), self.send_tx2)
- self.connect(self, QtCore.SIGNAL('send_tx3'), self.send_tx3)
self.connect(self, QtCore.SIGNAL('payment_request_ok'), self.payment_request_ok)
+ self.connect(self, QtCore.SIGNAL('payment_request_error'), self.payment_request_error)
self.history_list.setFocus(True)
def load_wallet(self, wallet):
import electrum
+
self.wallet = wallet
+ self.update_wallet_format()
+
self.accounts_expanded = self.wallet.storage.get('accounts_expanded',{})
self.current_account = self.wallet.storage.get("current_account", None)
-
title = 'Electrum ' + self.wallet.electrum_version + ' - ' + self.wallet.storage.path
if self.wallet.is_watching_only(): title += ' [%s]' % (_('watching only'))
self.setWindowTitle( title )
run_hook('load_wallet', wallet)
+ def update_wallet_format(self):
+ # convert old-format imported keys
+ if self.wallet.imported_keys:
+ password = self.password_dialog(_("Please enter your password in order to update imported keys"))
+ try:
+ self.wallet.convert_imported_keys(password)
+ except:
+ self.show_message("error")
+
+
def open_wallet(self):
wallet_folder = self.wallet.storage.path
filename = unicode( QFileDialog.getOpenFileName(self, "Select your wallet file", wallet_folder) )
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
- p = pow(10, self.decimal_point)
- return int( p * Decimal(x) )
+
+ def get_decimal_point(self):
+ return self.decimal_point
+
def base_unit(self):
assert self.decimal_point in [5,8]
def create_send_tab(self):
w = QWidget()
- grid = QGridLayout()
+ grid = QGridLayout(w)
grid.setSpacing(8)
grid.setColumnMinimumWidth(3,300)
grid.setColumnStretch(5,1)
+ grid.setRowStretch(8, 1)
-
- self.payto_e = QLineEdit()
+ from paytoedit import PayToEdit
+ self.amount_e = AmountEdit(self.get_decimal_point)
+ self.payto_e = PayToEdit(self.amount_e)
+ self.payto_help = HelpButton(_('Recipient of the funds.') + '\n\n' + _('You may enter a Bitcoin address, a label from your list of contacts (a list of completions will be proposed), or an alias (email-like address that forwards to a Bitcoin address)'))
grid.addWidget(QLabel(_('Pay to')), 1, 0)
grid.addWidget(self.payto_e, 1, 1, 1, 3)
-
- grid.addWidget(HelpButton(_('Recipient of the funds.') + '\n\n' + _('You may enter a Bitcoin address, a label from your list of contacts (a list of completions will be proposed), or an alias (email-like address that forwards to a Bitcoin address)')), 1, 4)
+ grid.addWidget(self.payto_help, 1, 4)
completer = QCompleter()
completer.setCaseSensitivity(False)
completer.setModel(self.completions)
self.message_e = QLineEdit()
+ self.message_help = HelpButton(_('Description of the transaction (not mandatory).') + '\n\n' + _('The description is not sent to the recipient of the funds. It is stored in your wallet file, and displayed in the \'History\' tab.'))
grid.addWidget(QLabel(_('Description')), 2, 0)
grid.addWidget(self.message_e, 2, 1, 1, 3)
- grid.addWidget(HelpButton(_('Description of the transaction (not mandatory).') + '\n\n' + _('The description is not sent to the recipient of the funds. It is stored in your wallet file, and displayed in the \'History\' tab.')), 2, 4)
+ grid.addWidget(self.message_help, 2, 4)
self.from_label = QLabel(_('From'))
grid.addWidget(self.from_label, 3, 0)
grid.addWidget(self.from_list, 3, 1, 1, 3)
self.set_pay_from([])
- self.amount_e = AmountEdit(self.base_unit)
+ self.amount_help = HelpButton(_('Amount to be sent.') + '\n\n' \
+ + _('The amount will be displayed in red if you do not have enough funds in your wallet. Note that if you have frozen some of your addresses, the available funds will be lower than your total balance.') \
+ + '\n\n' + _('Keyboard shortcut: type "!" to send all your coins.'))
grid.addWidget(QLabel(_('Amount')), 4, 0)
grid.addWidget(self.amount_e, 4, 1, 1, 2)
- grid.addWidget(HelpButton(
- _('Amount to be sent.') + '\n\n' \
- + _('The amount will be displayed in red if you do not have enough funds in your wallet. Note that if you have frozen some of your addresses, the available funds will be lower than your total balance.') \
- + '\n\n' + _('Keyboard shortcut: type "!" to send all your coins.')), 4, 3)
+ grid.addWidget(self.amount_help, 4, 3)
- self.fee_e = AmountEdit(self.base_unit)
+ self.fee_e = AmountEdit(self.get_decimal_point)
grid.addWidget(QLabel(_('Fee')), 5, 0)
grid.addWidget(self.fee_e, 5, 1, 1, 2)
grid.addWidget(HelpButton(
self.send_button = EnterButton(_("Send"), self.do_send)
grid.addWidget(self.send_button, 6, 1)
- b = EnterButton(_("Clear"),self.do_clear)
+ b = EnterButton(_("Clear"), self.do_clear)
grid.addWidget(b, 6, 2)
self.payto_sig = QLabel('')
QShortcut(QKeySequence("Down"), w, w.focusNextChild)
w.setLayout(grid)
- w2 = QWidget()
- vbox = QVBoxLayout()
- vbox.addWidget(w)
- vbox.addStretch(1)
- w2.setLayout(vbox)
-
def entry_changed( is_fee ):
self.funds_error = False
self.fee_e.setText( self.format_amount( fee ) )
return
- amount = self.read_amount(str(self.amount_e.text()))
- fee = self.read_amount(str(self.fee_e.text()))
+ amount = self.amount_e.get_amount()
+ fee = self.fee_e.get_amount()
if not is_fee: fee = None
if amount is None:
self.fee_e.textChanged.connect(lambda: entry_changed(True) )
run_hook('create_send_tab', grid)
- return w2
+ return w
def set_pay_from(self, l):
def do_send(self):
label = unicode( self.message_e.text() )
- if self.payment_request:
- outputs = self.payment_request.outputs
- amount = self.payment_request.get_amount()
+ if self.gui_object.payment_request:
+ outputs = self.gui_object.payment_request.outputs
+ amount = self.gui_object.payment_request.get_amount()
else:
r = unicode( self.payto_e.text() )
if not is_valid(to_address):
QMessageBox.warning(self, _('Error'), _('Invalid Bitcoin Address') + ':\n' + to_address, _('OK'))
return
-
+
try:
- amount = self.read_amount(unicode( self.amount_e.text()))
+ amount = self.amount_e.get_amount()
except Exception:
QMessageBox.warning(self, _('Error'), _('Invalid Amount'), _('OK'))
return
outputs = [(to_address, amount)]
try:
- fee = self.read_amount(unicode( self.fee_e.text()))
+ fee = self.fee_e.get_amount()
except Exception:
QMessageBox.warning(self, _('Error'), _('Invalid Fee'), _('OK'))
return
self.send_tx(outputs, fee, label)
- def waiting_dialog(self, message):
- d = QDialog(self)
- d.setWindowTitle('Please wait')
- l = QLabel(message)
- vbox = QVBoxLayout(d)
- vbox.addWidget(l)
- d.show()
- return d
-
@protected
def send_tx(self, outputs, fee, label, password):
+ self.send_button.setDisabled(True)
# first, create an unsigned tx
domain = self.get_payment_sources()
except Exception as e:
traceback.print_exc(file=sys.stdout)
self.show_message(str(e))
+ self.send_button.setDisabled(False)
return
# call hook to see if plugin needs gui interaction
keypairs = {}
self.wallet.add_keypairs_from_wallet(tx, keypairs, password)
self.wallet.sign_transaction(tx, keypairs, password)
- self.signed_tx_data = (tx, fee, label)
- self.emit(SIGNAL('send_tx2'))
- self.tx_wait_dialog = self.waiting_dialog('Signing..')
- threading.Thread(target=sign_thread).start()
+ return tx, fee, label
+ def sign_done(tx, fee, label):
+ if tx.error:
+ self.show_message(tx.error)
+ self.send_button.setDisabled(False)
+ return
+ if tx.requires_fee(self.wallet.verifier) and fee < MIN_RELAY_TX_FEE:
+ QMessageBox.warning(self, _('Error'), _("This transaction requires a higher fee, or it will not be propagated by the network."), _('OK'))
+ self.send_button.setDisabled(False)
+ return
+ if label:
+ self.wallet.set_label(tx.hash(), label)
+ if not self.gui_object.payment_request:
+ if not tx.is_complete() or self.config.get('show_before_broadcast'):
+ self.show_transaction(tx)
+ self.do_clear()
+ self.send_button.setDisabled(False)
+ return
- def send_tx2(self):
- tx, fee, label = self.signed_tx_data
- self.tx_wait_dialog.accept()
-
- if tx.error:
- self.show_message(tx.error)
- return
+ self.broadcast_transaction(tx)
- if tx.requires_fee(self.wallet.verifier) and fee < MIN_RELAY_TX_FEE:
- QMessageBox.warning(self, _('Error'), _("This transaction requires a higher fee, or it will not be propagated by the network."), _('OK'))
- return
+ self.waiting_dialog = WaitingDialog(self, 'Signing..', sign_thread, sign_done)
+ self.waiting_dialog.start()
- if label:
- self.wallet.set_label(tx.hash(), label)
- if not tx.is_complete() or self.config.get('show_before_broadcast'):
- self.show_transaction(tx)
- return
+
+ def broadcast_transaction(self, tx):
def broadcast_thread():
- if self.payment_request:
+ if self.gui_object.payment_request:
refund_address = self.wallet.addresses()[0]
- self.payment_request.send_ack(str(tx), refund_address)
- self.payment_request = None
- # note: BIP 70 recommends not broadcasting the tx to the network and letting the merchant do that
- self.tx_broadcast_result = self.wallet.sendtx(tx)
- self.emit(SIGNAL('send_tx3'))
-
- self.tx_broadcast_dialog = self.waiting_dialog('Broadcasting..')
- threading.Thread(target=broadcast_thread).start()
+ status, msg = self.gui_object.payment_request.send_ack(str(tx), refund_address)
+ self.gui_object.payment_request = None
+ else:
+ status, msg = self.wallet.sendtx(tx)
+ return status, msg
+ def broadcast_done(status, msg):
+ if status:
+ QMessageBox.information(self, '', _('Payment sent.') + '\n' + msg, _('OK'))
+ self.do_clear()
+ else:
+ QMessageBox.warning(self, _('Error'), msg, _('OK'))
+ self.send_button.setDisabled(False)
+ self.waiting_dialog = WaitingDialog(self, 'Broadcasting..', broadcast_thread, broadcast_done)
+ self.waiting_dialog.start()
- def send_tx3(self):
- self.tx_broadcast_dialog.accept()
- status, msg = self.tx_broadcast_result
- if status:
- QMessageBox.information(self, '', _('Payment sent.') + '\n' + msg, _('OK'))
- self.do_clear()
- else:
- QMessageBox.warning(self, _('Error'), msg, _('OK'))
+ def prepare_for_payment_request(self):
+ style = "QWidget { background-color:none;border:none;}"
+ self.tabs.setCurrentIndex(1)
+ for e in [self.payto_e, self.amount_e, self.message_e]:
+ e.setReadOnly(True)
+ e.setStyleSheet(style)
+ for h in [self.payto_help, self.amount_help, self.message_help]:
+ h.hide()
+ self.payto_e.setText(_("please wait..."))
+ return True
def payment_request_ok(self):
- style = "QWidget { background-color:none;border:none;}"
- self.payto_e.setText(self.payment_request.domain)
- self.payto_e.setReadOnly(True)
- self.payto_e.setStyleSheet(style)
- self.amount_e.setText(self.format_amount(self.payment_request.get_amount()))
- self.amount_e.setReadOnly(True)
- self.amount_e.setStyleSheet(style)
+ self.payto_e.setText(self.gui_object.payment_request.domain)
+ self.amount_e.setText(self.format_amount(self.gui_object.payment_request.get_amount()))
+ self.message_e.setText(self.gui_object.payment_request.memo)
+
+ def payment_request_error(self):
+ self.do_clear()
+ self.show_message(self.gui_object.payment_request.error)
def set_send(self, address, amount, label, message):
e.setText('')
self.set_frozen(e,False)
e.setStyleSheet("")
+ for h in [self.payto_help, self.amount_help, self.message_help]:
+ h.show()
self.set_pay_from([])
self.update_status()
l = self.receive_list
# extend the syntax for consistency
l.addChild = l.addTopLevelItem
+ l.insertChild = l.insertTopLevelItem
l.clear()
for i,width in enumerate(self.column_widths['receive']):
gap = 0
for address in account.get_addresses(is_change):
- h = self.wallet.history.get(address,[])
- if h == []:
+ num, is_used = self.wallet.is_used(address)
+ if num == 0:
gap += 1
if gap > self.wallet.gap_limit:
is_red = True
else:
gap = 0
- c, u = self.wallet.get_addr_balance(address)
- num_tx = '*' if h == ['*'] else "%d"%len(h)
-
- item = QTreeWidgetItem( [ address, '', '', num_tx] )
+ item = QTreeWidgetItem( [ address, '', '', "%d"%num] )
self.update_receive_item(item)
if is_red:
item.setBackgroundColor(1, QColor('red'))
- if len(h) > 0 and c == -u:
+
+ if is_used:
if not used_flag:
seq_item.insertChild(0,used_item)
used_flag = True
QMessageBox.warning(self, _('Error'), _('Incorrect Password'), _('OK'))
return
from seed_dialog import SeedDialog
- d = SeedDialog(self, mnemonic, self.wallet.imported_keys)
+ d = SeedDialog(self, mnemonic, self.wallet.has_imported_keys())
d.exec_()
def show_message(self, msg):
QMessageBox.information(self, _('Message'), msg, _('OK'))
- def password_dialog(self ):
+ def password_dialog(self, msg=None):
d = QDialog(self)
d.setModal(1)
d.setWindowTitle(_("Enter Password"))
pw.setEchoMode(2)
vbox = QVBoxLayout()
- msg = _('Please enter your password')
+ if not msg:
+ msg = _('Please enter your password')
vbox.addWidget(QLabel(msg))
grid = QGridLayout()
try:
tx_dict = json.loads(str(txt))
assert "hex" in tx_dict.keys()
- assert "complete" in tx_dict.keys()
- tx = Transaction(tx_dict["hex"], tx_dict["complete"])
- if not tx_dict["complete"]:
- assert "input_info" in tx_dict.keys()
+ tx = Transaction(tx_dict["hex"])
+ if tx_dict.has_key("input_info"):
input_info = json.loads(tx_dict['input_info'])
tx.add_input_info(input_info)
return tx
except Exception:
+ traceback.print_exc(file=sys.stdout)
pass
QMessageBox.critical(None, _("Unable to parse transaction"), _("Electrum was unable to parse your transaction"))
@protected
def do_import_privkey(self, password):
- if not self.wallet.imported_keys:
+ if not self.wallet.has_imported_keys():
r = QMessageBox.question(None, _('Warning'), '<b>'+_('Warning') +':\n</b><br/>'+ _('Imported keys are not recoverable from seed.') + ' ' \
+ _('If you ever need to restore your wallet from its seed, these keys will be lost.') + '<p>' \
+ _('Are you sure you understand what you are doing?'), 3, 4)
fee_label = QLabel(_('Transaction fee') + ':')
grid.addWidget(fee_label, 2, 0)
- fee_e = AmountEdit(self.base_unit)
+ fee_e = AmountEdit(self.get_decimal_point)
fee_e.setText(self.format_amount(self.wallet.fee).strip())
grid.addWidget(fee_e, 2, 1)
msg = _('Fee per kilobyte of transaction.') + ' ' \
# run the dialog
if not d.exec_(): return
- fee = unicode(fee_e.text())
try:
- fee = self.read_amount(fee)
+ fee = self.fee_e.get_amount()
except Exception:
QMessageBox.warning(self, _('Error'), _('Invalid value') +': %s'%fee, _('OK'))
return