change remove tabs for verify/sign
[electrum-nvc.git] / gui / qt / main_window.py
index 20b7caa..bba7e8f 100644 (file)
@@ -20,6 +20,7 @@ import sys, time, datetime, re, threading
 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
 
@@ -98,37 +99,22 @@ class StatusBarButton(QPushButton):
 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)
@@ -423,6 +409,9 @@ class ElectrumWindow(QMainWindow):
         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"))
@@ -441,6 +430,9 @@ class ElectrumWindow(QMainWindow):
         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"))
@@ -606,6 +598,7 @@ class ElectrumWindow(QMainWindow):
         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))
 
 
@@ -681,9 +674,6 @@ class ElectrumWindow(QMainWindow):
     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):
@@ -766,7 +756,6 @@ class ElectrumWindow(QMainWindow):
         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)
@@ -776,7 +765,7 @@ class ElectrumWindow(QMainWindow):
         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)
@@ -859,7 +848,8 @@ class ElectrumWindow(QMainWindow):
         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)
@@ -941,7 +931,7 @@ class ElectrumWindow(QMainWindow):
         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()
@@ -1003,9 +993,7 @@ class ElectrumWindow(QMainWindow):
             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):
@@ -1166,7 +1154,7 @@ class ElectrumWindow(QMainWindow):
             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))
 
@@ -1175,7 +1163,8 @@ class ElectrumWindow(QMainWindow):
         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))
@@ -1193,7 +1182,7 @@ class ElectrumWindow(QMainWindow):
 
 
     def send_from_addresses(self, addrs):
-        self.pay_from = addrs[:]
+        self.set_pay_from( addrs )
         self.tabs.setCurrentIndex(1)
 
 
@@ -1312,7 +1301,7 @@ class ElectrumWindow(QMainWindow):
                         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:
@@ -1716,6 +1705,7 @@ class ElectrumWindow(QMainWindow):
         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_()
@@ -1731,16 +1721,26 @@ class ElectrumWindow(QMainWindow):
         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()
 
@@ -1758,61 +1758,23 @@ class ElectrumWindow(QMainWindow):
         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
 
@@ -1906,17 +1868,39 @@ class ElectrumWindow(QMainWindow):
         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)
@@ -2099,7 +2083,7 @@ class ElectrumWindow(QMainWindow):
         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)
@@ -2179,6 +2163,8 @@ class ElectrumWindow(QMainWindow):
         event.accept()
 
 
+    def verify_message(self):
+        self.sign_message(False, "")
 
     def plugins_dialog(self):
         from electrum.plugins import plugins