from electrum.i18n import _, set_language
from electrum.util import print_error, print_msg
import os.path, json, ast, traceback
+import webbrowser
import shutil
import StringIO
default_column_widths = { "history":[40,140,350,140], "contacts":[350,330], "receive": [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):
+ def build_menu(self):
m = QMenu()
- if self.isMinimized():
- m.addAction(_("Show"), self.showNormal)
- else:
- m.addAction(_("Hide"), self.showMinimized)
-
+ m.addAction(_("Show/Hide"), self.show_or_hide)
m.addSeparator()
m.addAction(_("Exit Electrum"), self.close)
self.tray.setContextMenu(m)
+ def show_or_hide(self):
+ self.tray_activated(QSystemTrayIcon.DoubleClick)
+
def tray_activated(self, reason):
if reason == QSystemTrayIcon.DoubleClick:
- self.showNormal()
-
- def showNormal(self):
- self.setWindowState(self.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive)
+ if self.isMinimized() or self.isHidden():
+ self.show()
+ else:
+ self.hide()
def __init__(self, config, network):
QMainWindow.__init__(self)
plugins_labels = tools_menu.addAction(_("&Plugins"))
plugins_labels.triggered.connect(self.plugins_dialog)
+ verifymessage = tools_menu.addAction(_("&Verify message"))
+ verifymessage.triggered.connect(self.verify_message)
+
tools_menu.addSeparator()
csv_transaction_menu = tools_menu.addMenu(_("&Create transaction"))
raw_transaction_text = raw_transaction_menu.addAction(_("&From text"))
raw_transaction_text.triggered.connect(self.do_process_from_text)
+ raw_transaction_text = raw_transaction_menu.addAction(_("&From the blockchain"))
+ raw_transaction_text.triggered.connect(self.do_process_from_txid)
+
help_menu = menubar.addMenu(_("&Help"))
show_about = help_menu.addAction(_("&About"))
menu.addAction(_("Copy ID to Clipboard"), lambda: self.app.clipboard().setText(tx_hash))
menu.addAction(_("Details"), lambda: self.show_transaction(self.wallet.transactions.get(tx_hash)))
menu.addAction(_("Edit description"), lambda: self.tx_label_clicked(item,2))
+ menu.addAction(_("View on Blockchain.info"), lambda: webbrowser.open("https://blockchain.info/tx/" + tx_hash))
menu.exec_(self.contacts_list.viewport().mapToGlobal(position))
def current_item_changed(self, a):
run_hook('current_item_changed', a)
- self.pay_from = []
- self.tabs.emit(SIGNAL('currentChanged(int)'), 1)
-
def update_history_tab(self):
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)
- self.pay_from = []
self.from_label = QLabel(_('From'))
grid.addWidget(self.from_label, 3, 0)
self.from_list = QTreeWidget(self)
self.from_list.setHeaderHidden (True)
self.from_list.setMaximumHeight(80)
grid.addWidget(self.from_list, 3, 1, 1, 3)
- self.connect(self.tabs, SIGNAL('currentChanged(int)'), lambda: self.update_pay_from_list(grid))
+ self.set_pay_from([])
self.amount_e = AmountEdit(self.base_unit)
grid.addWidget(QLabel(_('Amount')), 4, 0)
return w2
- def update_pay_from_list(self, grid):
+ def set_pay_from(self, l):
+ self.pay_from = l
self.from_list.clear()
self.from_label.setHidden(len(self.pay_from) == 0)
self.from_list.setHidden(len(self.pay_from) == 0)
if tx.is_complete:
h = self.wallet.send_tx(tx)
waiting_dialog(lambda: False if self.wallet.tx_event.isSet() else _("Please wait..."))
- status, msg = self.wallet.receive_tx( h )
+ status, msg = self.wallet.receive_tx( h, tx )
if status:
QMessageBox.information(self, '', _('Payment sent.')+'\n'+msg, _('OK'))
self.do_clear()
e.setText('')
self.set_frozen(e,False)
- self.pay_from = []
- self.tabs.emit(SIGNAL('currentChanged(int)'), 1)
-
+ self.set_pay_from([])
self.update_status()
def set_frozen(self,entry,frozen):
menu.addAction(_("Edit label"), lambda: self.edit_label(True))
if self.wallet.seed:
menu.addAction(_("Private key"), lambda: self.show_private_key(addr))
- menu.addAction(_("Sign message"), lambda: self.sign_message(addr))
+ menu.addAction(_("Sign message"), lambda: self.sign_message(True,addr))
if addr in self.wallet.imported_keys:
menu.addAction(_("Remove from wallet"), lambda: self.delete_imported_key(addr))
if any(addr in self.wallet.frozen_addresses for addr in addrs):
menu.addAction(_("Unfreeze"), lambda: self.set_addrs_frozen(addrs, False))
- menu.addAction(_("Send From"), lambda: self.send_from_addresses(addrs))
+ if any(addr not in self.wallet.frozen_addresses for addr in addrs):
+ menu.addAction(_("Send From"), lambda: self.send_from_addresses(addrs))
run_hook('receive_menu', menu, addrs)
menu.exec_(self.receive_list.viewport().mapToGlobal(position))
def send_from_addresses(self, addrs):
- self.pay_from = addrs[:]
+ self.set_pay_from( addrs )
self.tabs.setCurrentIndex(1)
item.setBackgroundColor(1, QColor('red'))
if len(h) > 0 and c == -u:
if not used_flag:
- seq_item.addChild(used_item)
+ seq_item.insertChild(0,used_item)
used_flag = True
used_item.addChild(item)
else:
keys.setReadOnly(True)
keys.setText('\n'.join(pk_list))
vbox.addWidget(keys)
+ vbox.addWidget( QRCodeWidget('\n'.join(pk_list)) )
vbox.addLayout(close_button(d))
d.setLayout(vbox)
d.exec_()
except Exception as e:
self.show_message(str(e))
- def sign_message(self, address):
- if not address: return
+ def do_verify(self, address, message, signature):
+ message = unicode(message.toPlainText())
+ message = message.encode('utf-8')
+ if bitcoin.verify_message(address.text(), str(signature.toPlainText()), message):
+ self.show_message(_("Signature verified"))
+ else:
+ self.show_message(_("Error: wrong signature"))
+
+
+ def sign_message(self, sign, address):
+ if sign and not address: return
d = QDialog(self)
d.setModal(1)
- d.setWindowTitle(_('Sign Message'))
+ if sign:
+ d.setWindowTitle(_('Sign Message'))
+ elif not sign:
+ d.setWindowTitle(_('Verify Message'))
d.setMinimumSize(410, 290)
- tab_widget = QTabWidget()
- tab = QWidget()
- layout = QGridLayout(tab)
+ layout = QGridLayout(d)
sign_address = QLineEdit()
layout.addWidget(sign_signature, 3, 1)
layout.setRowStretch(3,1)
-
hbox = QHBoxLayout()
- b = QPushButton(_("Sign"))
+ if sign:
+ b = QPushButton(_("Sign"))
+ elif not sign:
+ b = QPushButton(_("Verify"))
hbox.addWidget(b)
- b.clicked.connect(lambda: self.do_sign(sign_address, sign_message, sign_signature))
+ if sign:
+ b.clicked.connect(lambda: self.do_sign(sign_address, sign_message, sign_signature))
+ elif not sign:
+ b.clicked.connect(lambda: self.do_verify(sign_address, sign_message, sign_signature))
b = QPushButton(_("Close"))
b.clicked.connect(d.accept)
hbox.addWidget(b)
layout.addLayout(hbox, 4, 1)
- tab_widget.addTab(tab, _("Sign"))
-
-
- tab = QWidget()
- layout = QGridLayout(tab)
-
- verify_address = QLineEdit()
- layout.addWidget(QLabel(_('Address')), 1, 0)
- layout.addWidget(verify_address, 1, 1)
-
- verify_message = QTextEdit()
- layout.addWidget(QLabel(_('Message')), 2, 0)
- layout.addWidget(verify_message, 2, 1)
- layout.setRowStretch(2,3)
-
- verify_signature = QTextEdit()
- layout.addWidget(QLabel(_('Signature')), 3, 0)
- layout.addWidget(verify_signature, 3, 1)
- layout.setRowStretch(3,1)
-
- def do_verify():
- message = unicode(verify_message.toPlainText())
- message = message.encode('utf-8')
- if bitcoin.verify_message(verify_address.text(), str(verify_signature.toPlainText()), message):
- self.show_message(_("Signature verified"))
- else:
- self.show_message(_("Error: wrong signature"))
-
- hbox = QHBoxLayout()
- b = QPushButton(_("Verify"))
- b.clicked.connect(do_verify)
- hbox.addWidget(b)
- b = QPushButton(_("Close"))
- b.clicked.connect(d.accept)
- hbox.addWidget(b)
- layout.addLayout(hbox, 4, 1)
- tab_widget.addTab(tab, _("Verify"))
-
- vbox = QVBoxLayout()
- vbox.addWidget(tab_widget)
- d.setLayout(vbox)
d.exec_()
-
-
def question(self, msg):
return QMessageBox.question(self, _('Message'), msg, QMessageBox.Yes | QMessageBox.No, QMessageBox.No) == QMessageBox.Yes
if tx:
self.show_transaction(tx)
+ def do_process_from_txid(self):
+ from electrum import transaction
+ txid, ok = QInputDialog.getText(self, _('Lookup transaction'), _('Transaction ID') + ':')
+ if ok and txid:
+ r = self.network.synchronous_get([ ('blockchain.transaction.get',[str(txid)]) ])[0]
+ if r:
+ tx = transaction.Transaction(r)
+ if tx:
+ self.show_transaction(tx)
+ else:
+ self.show_message("unknown transaction")
+
def do_process_from_csvReader(self, csvReader):
outputs = []
+ errors = []
+ errtext = ""
try:
- for row in csvReader:
+ for position, row in enumerate(csvReader):
address = row[0]
+ if not is_valid(address):
+ errors.append((position, address))
+ continue
amount = Decimal(row[1])
amount = int(100000000*amount)
outputs.append((address, amount))
except (ValueError, IOError, os.error), reason:
QMessageBox.critical(None, _("Unable to read file or no transaction found"), _("Electrum was unable to open your transaction file") + "\n" + str(reason))
return
+ if errors != []:
+ for x in errors:
+ errtext += "CSV Row " + str(x[0]+1) + ": " + x[1] + "\n"
+ QMessageBox.critical(None, _("Invalid Addresses"), _("ABORTING! Invalid Addresses found:") + "\n\n" + errtext)
+ return
try:
tx = self.wallet.make_unsigned_transaction(outputs, None, None)
grid.addWidget(unit_combo, 3, 1)
grid.addWidget(HelpButton(_('Base unit of your wallet.')\
+ '\n1BTC=1000mBTC.\n' \
- + _(' This settings affects the fields in the Send tab')+' '), 3, 2)
+ + _(' These settings affects the fields in the Send tab')+' '), 3, 2)
usechange_cb = QCheckBox(_('Use change addresses'))
usechange_cb.setChecked(self.wallet.use_change)
event.accept()
+ def verify_message(self):
+ self.sign_message(False, "")
def plugins_dialog(self):
from electrum.plugins import plugins