fix payment ack
[electrum-nvc.git] / gui / qt / main_window.py
index 2a33d87..3aca682 100644 (file)
@@ -99,49 +99,23 @@ class StatusBarButton(QPushButton):
 default_column_widths = { "history":[40,140,350,140], "contacts":[350,330], "receive": [370,200,130] }
 
 class ElectrumWindow(QMainWindow):
-    def build_menu(self):
-        m = QMenu()
-        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:
-            if self.isMinimized() or self.isHidden():
-                self.show()
-            else:
-                self.hide()
 
-    def __init__(self, config, network):
+
+
+    def __init__(self, config, network, gui_object):
         QMainWindow.__init__(self)
 
         self.config = config
         self.network = network
-
-        self._close_electrum = False
+        self.gui_object = gui_object
+        self.tray = gui_object.tray
+        self.go_lite = gui_object.go_lite
         self.lite = None
 
-        if sys.platform == 'darwin':
-          self.icon = QIcon(":icons/electrum_dark_icon.png")
-          #self.icon = QIcon(":icons/lock.png")
-        else:
-          self.icon = QIcon(':icons/electrum_light_icon.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.decimal_point = config.get('decimal_point', 8)
+        self.decimal_point = config.get('decimal_point', 5)
         self.num_zeros     = int(config.get('num_zeros',0))
 
         set_language(config.get('language'))
@@ -162,6 +136,8 @@ class ElectrumWindow(QMainWindow):
 
         g = self.config.get("winpos-qt",[100, 100, 840, 400])
         self.setGeometry(g[0], g[1], g[2], g[3])
+        if self.config.get("is_maximized"):
+            self.showMaximized()
 
         self.setWindowIcon(QIcon(":icons/electrum.png"))
         self.init_menubar()
@@ -178,6 +154,10 @@ class ElectrumWindow(QMainWindow):
         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)
 
@@ -193,49 +173,6 @@ class ElectrumWindow(QMainWindow):
             self.console.showMessage(self.network.banner)
 
         self.wallet = None
-        self.init_lite()
-
-
-    def go_full(self):
-        self.config.set_key('lite_mode', False, True)
-        self.mini.hide()
-        self.show()
-
-    def go_lite(self):
-        self.config.set_key('lite_mode', True, True)
-        self.hide()
-        self.mini.show()
-
-
-    def init_lite(self):
-        import lite_window
-        if not self.check_qt_version():
-            if self.config.get('lite_mode') is True:
-                msg = "Electrum was unable to load the 'Lite GUI' because it needs Qt version >= 4.7.\nChanging your config to use the 'Classic' GUI"
-                QMessageBox.warning(None, "Could not start Lite GUI.", msg)
-                self.config.set_key('lite_mode', False, True)
-                sys.exit(0)
-            self.mini = None
-            self.show()
-            return
-
-        actuator = lite_window.MiniActuator(self)
-
-        actuator.load_theme()
-
-        self.mini = lite_window.MiniWindow(actuator, self.go_full, self.config)
-
-        driver = lite_window.MiniDriver(self, self.mini)
-
-        if self.config.get('lite_mode') is True:
-            self.go_lite()
-        else:
-            self.go_full()
-
-
-    def check_qt_version(self):
-        qtVersion = qVersion()
-        return int(qtVersion[0]) >= 4 and int(qtVersion[2]) >= 7
 
 
     def update_account_selector(self):
@@ -263,7 +200,14 @@ class ElectrumWindow(QMainWindow):
         # 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()
         self.update_account_selector()
-        self.new_account.setEnabled(self.wallet.seed_version>4)
+        # update menus
+        self.new_account_menu.setEnabled(self.wallet.can_create_accounts())
+        self.private_keys_menu.setEnabled(not self.wallet.is_watching_only())
+        self.password_menu.setEnabled(not self.wallet.is_watching_only())
+        self.seed_menu.setEnabled(self.wallet.has_seed())
+        self.mpk_menu.setEnabled(self.wallet.is_deterministic())
+        self.import_menu.setEnabled(self.wallet.can_import())
+
         self.update_lock_icon()
         self.update_buttons_on_seed()
         self.update_console()
@@ -324,7 +268,7 @@ class ElectrumWindow(QMainWindow):
             return
 
         wizard = installwizard.InstallWizard(self.config, self.network, storage)
-        wallet = wizard.run()
+        wallet = wizard.run('new')
         if wallet:
             self.load_wallet(wallet)
 
@@ -341,24 +285,24 @@ class ElectrumWindow(QMainWindow):
 
         wallet_menu = menubar.addMenu(_("&Wallet"))
         wallet_menu.addAction(_("&New contact"), self.new_contact_dialog)
-        self.new_account = wallet_menu.addAction(_("&New account"), self.new_account_dialog)
+        self.new_account_menu = wallet_menu.addAction(_("&New account"), self.new_account_dialog)
 
         wallet_menu.addSeparator()
 
-        wallet_menu.addAction(_("&Password"), self.change_password_dialog)
-        wallet_menu.addAction(_("&Seed"), self.show_seed_dialog)
-        wallet_menu.addAction(_("&Master Public Key"), self.show_master_public_key)
+        self.password_menu = wallet_menu.addAction(_("&Password"), self.change_password_dialog)
+        self.seed_menu = wallet_menu.addAction(_("&Seed"), self.show_seed_dialog)
+        self.mpk_menu = wallet_menu.addAction(_("&Master Public Keys"), self.show_master_public_keys)
 
         wallet_menu.addSeparator()
         labels_menu = wallet_menu.addMenu(_("&Labels"))
         labels_menu.addAction(_("&Import"), self.do_import_labels)
         labels_menu.addAction(_("&Export"), self.do_export_labels)
 
-        keys_menu = wallet_menu.addMenu(_("&Private keys"))
-        keys_menu.addAction(_("&Import"), self.do_import_privkey)
-        keys_menu.addAction(_("&Export"), self.do_export_privkeys)
-
-        wallet_menu.addAction(_("&Export History"), self.do_export_history)
+        self.private_keys_menu = wallet_menu.addMenu(_("&Private keys"))
+        self.private_keys_menu.addAction(_("&Sweep"), self.sweep_key_dialog)
+        self.import_menu = self.private_keys_menu.addAction(_("&Import"), self.do_import_privkey)
+        self.private_keys_menu.addAction(_("&Export"), self.export_privkeys_dialog)
+        wallet_menu.addAction(_("&Export History"), self.export_history_dialog)
 
         tools_menu = menubar.addMenu(_("&Tools"))
 
@@ -403,12 +347,12 @@ class ElectrumWindow(QMainWindow):
             return
 
         print_error("Notifying GUI")
-        if len(self.network.interface.pending_transactions_for_notifications) > 0:
+        if len(self.network.pending_transactions_for_notifications) > 0:
             # Combine the transactions if there are more then three
-            tx_amount = len(self.network.interface.pending_transactions_for_notifications)
+            tx_amount = len(self.network.pending_transactions_for_notifications)
             if(tx_amount >= 3):
                 total_amount = 0
-                for tx in self.network.interface.pending_transactions_for_notifications:
+                for tx in self.network.pending_transactions_for_notifications:
                     is_relevant, is_mine, v, fee = self.wallet.get_tx_value(tx)
                     if(v > 0):
                         total_amount += v
@@ -416,11 +360,11 @@ class ElectrumWindow(QMainWindow):
                 self.notify(_("%(txs)s new transactions received. Total amount received in the new transactions %(amount)s %(unit)s") \
                                 % { 'txs' : tx_amount, 'amount' : self.format_amount(total_amount), 'unit' : self.base_unit()})
 
-                self.network.interface.pending_transactions_for_notifications = []
+                self.network.pending_transactions_for_notifications = []
             else:
-              for tx in self.network.interface.pending_transactions_for_notifications:
+              for tx in self.network.pending_transactions_for_notifications:
                   if tx:
-                      self.network.interface.pending_transactions_for_notifications.remove(tx)
+                      self.network.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. %(amount)s %(unit)s") % { 'amount' : self.format_amount(v), 'unit' : self.base_unit()})
@@ -432,14 +376,14 @@ class ElectrumWindow(QMainWindow):
 
     # custom wrappers for getOpenFileName and getSaveFileName, that remember the path selected by the user
     def getOpenFileName(self, title, filter = ""):
-        directory = self.config.get('io_dir', os.path.expanduser('~'))
+        directory = self.config.get('io_dir', unicode(os.path.expanduser('~')))
         fileName = unicode( QFileDialog.getOpenFileName(self, title, directory, filter) )
         if fileName and directory != os.path.dirname(fileName):
             self.config.set_key('io_dir', os.path.dirname(fileName), True)
         return fileName
 
     def getSaveFileName(self, title, filename, filter = ""):
-        directory = self.config.get('io_dir', os.path.expanduser('~'))
+        directory = self.config.get('io_dir', unicode(os.path.expanduser('~')))
         path = os.path.join( directory, filename )
         fileName = unicode( QFileDialog.getSaveFileName(self, title, path, filter) )
         if fileName and directory != os.path.dirname(fileName):
@@ -532,6 +476,13 @@ class ElectrumWindow(QMainWindow):
     def create_history_menu(self, position):
         self.history_list.selectedIndexes()
         item = self.history_list.currentItem()
+        be = self.config.get('block_explorer', 'Blockchain.info')
+        if be == 'Blockchain.info':
+            block_explorer = 'https://blockchain.info/tx/'
+        elif be == 'Blockr.io':
+            block_explorer = 'https://blockr.io/tx/info/'
+        elif be == 'Insight.is':
+            block_explorer = 'http://live.insight.is/tx/'
         if not item: return
         tx_hash = str(item.data(0, Qt.UserRole).toString())
         if not tx_hash: return
@@ -539,7 +490,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.addAction(_("View on block explorer"), lambda: webbrowser.open(block_explorer + tx_hash))
         menu.exec_(self.contacts_list.viewport().mapToGlobal(position))
 
 
@@ -819,24 +770,31 @@ class ElectrumWindow(QMainWindow):
 
 
     def do_send(self):
-
         label = unicode( self.message_e.text() )
-        r = unicode( self.payto_e.text() )
-        r = r.strip()
 
-        # label or alias, with address in brackets
-        m = re.match('(.*?)\s*\<([1-9A-HJ-NP-Za-km-z]{26,})\>', r)
-        to_address = m.group(2) if m else r
+        if self.gui_object.payment_request:
+            outputs = self.gui_object.payment_request.outputs
+            amount = self.gui_object.payment_request.get_amount()
 
-        if not is_valid(to_address):
-            QMessageBox.warning(self, _('Error'), _('Invalid Bitcoin Address') + ':\n' + to_address, _('OK'))
-            return
+        else:
+            r = unicode( self.payto_e.text() )
+            r = r.strip()
+
+            # label or alias, with address in brackets
+            m = re.match('(.*?)\s*\<([1-9A-HJ-NP-Za-km-z]{26,})\>', r)
+            to_address = m.group(2) if m else r
+            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()))
+            except Exception:
+                QMessageBox.warning(self, _('Error'), _('Invalid Amount'), _('OK'))
+                return
+
+            outputs = [(to_address, amount)]
 
-        try:
-            amount = self.read_amount(unicode( self.amount_e.text()))
-        except Exception:
-            QMessageBox.warning(self, _('Error'), _('Invalid Amount'), _('OK'))
-            return
         try:
             fee = self.read_amount(unicode( self.fee_e.text()))
         except Exception:
@@ -853,7 +811,7 @@ class ElectrumWindow(QMainWindow):
             if not self.question(_("The fee for this transaction seems unusually high.\nAre you really sure you want to pay %(fee)s in fees?")%{ 'fee' : self.format_amount(fee) + ' '+ self.base_unit()}):
                 return
 
-        self.send_tx(to_address, amount, fee, label)
+        self.send_tx(outputs, fee, label)
 
 
     def waiting_dialog(self, message):
@@ -867,11 +825,10 @@ class ElectrumWindow(QMainWindow):
 
 
     @protected
-    def send_tx(self, to_address, amount, fee, label, password):
+    def send_tx(self, outputs, fee, label, password):
 
         # first, create an unsigned tx 
         domain = self.get_payment_sources()
-        outputs = [(to_address, amount)]
         try:
             tx = self.wallet.make_unsigned_transaction(outputs, fee, None, domain)
             tx.error = None
@@ -883,26 +840,22 @@ class ElectrumWindow(QMainWindow):
         # call hook to see if plugin needs gui interaction
         run_hook('send_tx', tx)
 
+        # sign the tx
         def sign_thread():
             time.sleep(0.1)
             keypairs = {}
             self.wallet.add_keypairs_from_wallet(tx, keypairs, password)
             self.wallet.sign_transaction(tx, keypairs, password)
-            self.signed_tx = tx
+            self.signed_tx_data = (tx, fee, label)
             self.emit(SIGNAL('send_tx2'))
-
-        # sign the tx
-        dialog = self.waiting_dialog('Signing..')
-        self.connect(self, QtCore.SIGNAL('send_tx2'), lambda: self.send_tx2(self.signed_tx, fee, label, dialog, password))
+        self.tx_wait_dialog = self.waiting_dialog('Signing..')
         threading.Thread(target=sign_thread).start()
 
-        # add recipient to addressbook
-        if to_address not in self.wallet.addressbook and not self.wallet.is_mine(to_address):
-            self.wallet.addressbook.append(to_address)
 
 
-    def send_tx2(self, tx, fee, label, dialog, password):
-        dialog.accept()
+    def send_tx2(self):
+        tx, fee, label = self.signed_tx_data
+        self.tx_wait_dialog.accept()
         
         if tx.error:
             self.show_message(tx.error)
@@ -915,39 +868,55 @@ class ElectrumWindow(QMainWindow):
         if label:
             self.wallet.set_label(tx.hash(), label)
 
-        if tx.is_complete:
+        if not tx.is_complete() or self.config.get('show_before_broadcast'):
+            self.show_transaction(tx)
+            return
+
+        def broadcast_thread():
+            if self.gui_object.payment_request:
+                print "sending ack"
+                refund_address = self.wallet.addresses()[0]
+                self.gui_object.payment_request.send_ack(str(tx), refund_address)
+                self.gui_object.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'))
 
-            d = self.waiting_dialog('Broadcasting...')
-            h = self.wallet.send_tx(tx)
-            self.wallet.tx_event.wait()
-            d.accept()
-            
-            status, msg = self.wallet.receive_tx( h, tx )
-            if status:
-                QMessageBox.information(self, '', _('Payment sent.')+'\n'+msg, _('OK'))
-                self.do_clear()
-                self.update_contacts_tab()
-            else:
-                QMessageBox.warning(self, _('Error'), msg, _('OK'))
+        self.tx_broadcast_dialog = self.waiting_dialog('Broadcasting..')
+        threading.Thread(target=broadcast_thread).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'))
 
-            self.show_transaction(tx)
 
 
+    def prepare_for_payment_request(self):
+        style = "QWidget { background-color:none;border:none;}"
+        self.tabs.setCurrentIndex(1)
+        self.payto_e.setReadOnly(True)
+        self.payto_e.setStyleSheet(style)
+        self.amount_e.setReadOnly(True)
+        self.payto_e.setText(_("please wait..."))
+        self.amount_e.setStyleSheet(style)
+        return True
 
+    def payment_request_ok(self):
+        self.payto_e.setText(self.gui_object.payment_request.domain)
+        self.amount_e.setText(self.format_amount(self.gui_object.payment_request.get_amount()))
 
-    def set_url(self, url):
-        address, amount, label, message, signature, identity, url = util.parse_url(url)
+    def payment_request_error(self):
+        self.payto_e.setText(self.gui_object.payment_request.error)
 
-        try:
-            if amount and self.base_unit() == 'mBTC': amount = str( 1000* Decimal(amount))
-            elif amount: amount = str(Decimal(amount))
-        except Exception:
-            amount = "0.0"
-            QMessageBox.warning(self, _('Error'), _('Invalid Amount'), _('OK'))
 
-        if self.mini:
-            self.mini.set_payment_fields(address, amount)
+    def set_send(self, address, amount, label, message):
 
         if label and self.wallet.labels.get(address) != label:
             if self.question('Give label "%s" to address %s ?'%(label,address)):
@@ -955,8 +924,6 @@ class ElectrumWindow(QMainWindow):
                     self.wallet.addressbook.append(address)
                 self.wallet.set_label(address, label)
 
-        run_hook('set_url', url, self.show_message, self.question)
-
         self.tabs.setCurrentIndex(1)
         label = self.wallet.labels.get(address)
         m_addr = label + '  <'+ address +'>' if label else address
@@ -966,19 +933,13 @@ class ElectrumWindow(QMainWindow):
         if amount:
             self.amount_e.setText(amount)
 
-        if identity:
-            self.set_frozen(self.payto_e,True)
-            self.set_frozen(self.amount_e,True)
-            self.set_frozen(self.message_e,True)
-            self.payto_sig.setText( '      '+_('The bitcoin URI was signed by')+' ' + identity )
-        else:
-            self.payto_sig.setVisible(False)
 
     def do_clear(self):
         self.payto_sig.setVisible(False)
         for e in [self.payto_e, self.message_e, self.amount_e, self.fee_e]:
             e.setText('')
             self.set_frozen(e,False)
+            e.setStyleSheet("")
 
         self.set_pay_from([])
         self.update_status()
@@ -1140,11 +1101,12 @@ class ElectrumWindow(QMainWindow):
             menu.addAction(_("Copy to clipboard"), lambda: self.app.clipboard().setText(addr))
             menu.addAction(_("QR code"), lambda: self.show_qrcode("bitcoin:" + addr, _("Address")) )
             menu.addAction(_("Edit label"), lambda: self.edit_label(True))
-            if self.wallet.seed:
+            menu.addAction(_("Public keys"), lambda: self.show_public_keys(addr))
+            if not self.wallet.is_watching_only():
                 menu.addAction(_("Private key"), lambda: self.show_private_key(addr))
                 menu.addAction(_("Sign/verify message"), lambda: self.sign_verify_message(addr))
                 #menu.addAction(_("Encrypt/decrypt message"), lambda: self.encrypt_message(addr))
-            if addr in self.wallet.imported_keys:
+            if self.wallet.is_imported(addr):
                 menu.addAction(_("Remove from wallet"), lambda: self.delete_imported_key(addr))
 
         if any(addr not in self.wallet.frozen_addresses for addr in addrs):
@@ -1235,39 +1197,45 @@ class ElectrumWindow(QMainWindow):
 
     def update_receive_tab(self):
         l = self.receive_list
+        # extend the syntax for consistency
+        l.addChild = l.addTopLevelItem
 
         l.clear()
-        l.setColumnHidden(2, False)
-        l.setColumnHidden(3, False)
         for i,width in enumerate(self.column_widths['receive']):
             l.setColumnWidth(i, width)
 
+        accounts = self.wallet.get_accounts()
         if self.current_account is None:
-            account_items = self.wallet.accounts.items()
-        elif self.current_account != -1:
-            account_items = [(self.current_account, self.wallet.accounts.get(self.current_account))]
+            account_items = sorted(accounts.items())
         else:
-            account_items = []
+            account_items = [(self.current_account, accounts.get(self.current_account))]
+
 
         for k, account in account_items:
-            name = self.wallet.get_account_name(k)
-            c,u = self.wallet.get_account_balance(k)
-            account_item = QTreeWidgetItem( [ name, '', self.format_amount(c+u), ''] )
-            l.addTopLevelItem(account_item)
-            account_item.setExpanded(self.accounts_expanded.get(k, True))
-            account_item.setData(0, 32, k)
-
-            if not self.wallet.is_seeded(k):
-                icon = QIcon(":icons/key.png")
-                account_item.setIcon(0, icon)
-
-            for is_change in ([0,1]):
-                name = _("Receiving") if not is_change else _("Change")
-                seq_item = QTreeWidgetItem( [ name, '', '', '', ''] )
-                account_item.addChild(seq_item)
+
+            if len(accounts) > 1:
+                name = self.wallet.get_account_name(k)
+                c,u = self.wallet.get_account_balance(k)
+                account_item = QTreeWidgetItem( [ name, '', self.format_amount(c+u), ''] )
+                l.addTopLevelItem(account_item)
+                account_item.setExpanded(self.accounts_expanded.get(k, True))
+                account_item.setData(0, 32, k)
+            else:
+                account_item = l
+
+            sequences = [0,1] if account.has_change() else [0]
+            for is_change in sequences:
+                if len(sequences) > 1:
+                    name = _("Receiving") if not is_change else _("Change")
+                    seq_item = QTreeWidgetItem( [ name, '', '', '', ''] )
+                    account_item.addChild(seq_item)
+                    if not is_change: 
+                        seq_item.setExpanded(True)
+                else:
+                    seq_item = account_item
+                    
                 used_item = QTreeWidgetItem( [ _("Used"), '', '', '', ''] )
                 used_flag = False
-                if not is_change: seq_item.setExpanded(True)
 
                 is_red = False
                 gap = 0
@@ -1284,6 +1252,7 @@ class ElectrumWindow(QMainWindow):
 
                     c, u = self.wallet.get_addr_balance(address)
                     num_tx = '*' if h == ['*'] else "%d"%len(h)
+
                     item = QTreeWidgetItem( [ address, '', '', num_tx] )
                     self.update_receive_item(item)
                     if is_red:
@@ -1296,30 +1265,6 @@ class ElectrumWindow(QMainWindow):
                     else:
                         seq_item.addChild(item)
 
-
-        for k, addr in self.wallet.get_pending_accounts():
-            name = self.wallet.labels.get(k,'')
-            account_item = QTreeWidgetItem( [ name + "  [ "+_('pending account')+" ]", '', '', ''] )
-            self.update_receive_item(item)
-            l.addTopLevelItem(account_item)
-            account_item.setExpanded(True)
-            account_item.setData(0, 32, k)
-            item = QTreeWidgetItem( [ addr, '', '', '', ''] )
-            account_item.addChild(item)
-            self.update_receive_item(item)
-
-
-        if self.wallet.imported_keys and (self.current_account is None or self.current_account == -1):
-            c,u = self.wallet.get_imported_balance()
-            account_item = QTreeWidgetItem( [ _('Imported'), '', self.format_amount(c+u), ''] )
-            l.addTopLevelItem(account_item)
-            account_item.setExpanded(True)
-            for address in self.wallet.imported_keys.keys():
-                item = QTreeWidgetItem( [ address, '', '', ''] )
-                self.update_receive_item(item)
-                account_item.addChild(item)
-
-
         # we use column 1 because column 0 may be hidden
         l.setCurrentItem(l.topLevelItem(0),1)
 
@@ -1422,13 +1367,16 @@ class ElectrumWindow(QMainWindow):
 
 
     def update_buttons_on_seed(self):
-        if not self.wallet.is_watching_only():
+        if self.wallet.has_seed():
            self.seed_button.show()
+        else:
+           self.seed_button.hide()
+
+        if not self.wallet.is_watching_only():
            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"))
 
 
@@ -1502,76 +1450,30 @@ class ElectrumWindow(QMainWindow):
         name = str(e.text())
         if not name: return
 
-        self.wallet.create_pending_account('1of1', name, password)
+        self.wallet.create_pending_account(name, password)
         self.update_receive_tab()
         self.tabs.setCurrentIndex(2)
 
 
 
-    def show_master_public_key_old(self):
-        dialog = QDialog(self)
-        dialog.setModal(1)
-        dialog.setWindowTitle(_("Master Public Key"))
-
-        main_text = QTextEdit()
-        main_text.setText(self.wallet.get_master_public_key())
-        main_text.setReadOnly(True)
-        main_text.setMaximumHeight(170)
-        qrw = QRCodeWidget(self.wallet.get_master_public_key())
-
-        ok_button = QPushButton(_("OK"))
-        ok_button.setDefault(True)
-        ok_button.clicked.connect(dialog.accept)
 
-        main_layout = QGridLayout()
-        main_layout.addWidget(QLabel(_('Your Master Public Key is:')), 0, 0, 1, 2)
-
-        main_layout.addWidget(main_text, 1, 0)
-        main_layout.addWidget(qrw, 1, 1 )
-
-        vbox = QVBoxLayout()
-        vbox.addLayout(main_layout)
-        vbox.addLayout(close_button(dialog))
-        dialog.setLayout(vbox)
-        dialog.exec_()
-
-
-    def show_master_public_key(self):
-
-        if self.wallet.seed_version == 4:
-            self.show_master_public_key_old()
-            return
+    def show_master_public_keys(self):
 
         dialog = QDialog(self)
         dialog.setModal(1)
         dialog.setWindowTitle(_("Master Public Keys"))
 
-        mpk_text = QTextEdit()
-        mpk_text.setReadOnly(True)
-        mpk_text.setMaximumHeight(170)
-        mpk_qrw = QRCodeWidget()
-
         main_layout = QGridLayout()
-
-        main_layout.addWidget(QLabel(_('Key')), 1, 0)
-        main_layout.addWidget(mpk_text, 1, 1)
-        main_layout.addWidget(mpk_qrw, 1, 2)
-
-        def update(key):
-            xpub = self.wallet.master_public_keys[str(key)]
-            mpk_text.setText(xpub)
-            mpk_qrw.set_addr(xpub)
-            mpk_qrw.update_qr()
-
-        key_selector = QComboBox()
-        keys = sorted(self.wallet.master_public_keys.keys())
-        key_selector.addItems(keys)
-
-        main_layout.addWidget(QLabel(_('Derivation:')), 0, 0)
-        main_layout.addWidget(key_selector, 0, 1)
-        dialog.connect(key_selector,SIGNAL("activated(QString)"),update)
-
-        update(keys[0])
+        mpk_dict = self.wallet.get_master_public_keys()
+        i = 0
+        for key, value in mpk_dict.items():
+            main_layout.addWidget(QLabel(key), i, 0)
+            mpk_text = QTextEdit()
+            mpk_text.setReadOnly(True)
+            mpk_text.setMaximumHeight(170)
+            mpk_text.setText(value)
+            main_layout.addWidget(mpk_text, i + 1, 0)
+            i += 2
 
         vbox = QVBoxLayout()
         vbox.addLayout(main_layout)
@@ -1583,29 +1485,18 @@ class ElectrumWindow(QMainWindow):
 
     @protected
     def show_seed_dialog(self, password):
-        if self.wallet.is_watching_only():
-            QMessageBox.information(self, _('Message'), _('This is a watching-only wallet'), _('OK'))
+        if not self.wallet.has_seed():
+            QMessageBox.information(self, _('Message'), _('This wallet has no seed'), _('OK'))
             return
 
-        if self.wallet.seed:
-            try:
-                mnemonic = self.wallet.get_mnemonic(password)
-            except Exception:
-                QMessageBox.warning(self, _('Error'), _('Incorrect Password'), _('OK'))
-                return
-            from seed_dialog import SeedDialog
-            d = SeedDialog(self, mnemonic, self.wallet.imported_keys)
-            d.exec_()
-        else:
-            l = {}
-            for k in self.wallet.master_private_keys.keys():
-                pk = self.wallet.get_master_private_key(k, password)
-                l[k] = pk
-            from seed_dialog import PrivateKeysDialog
-            d = PrivateKeysDialog(self,l)
-            d.exec_()
-
-
+        try:
+            mnemonic = self.wallet.get_mnemonic(password)
+        except Exception:
+            QMessageBox.warning(self, _('Error'), _('Incorrect Password'), _('OK'))
+            return
+        from seed_dialog import SeedDialog
+        d = SeedDialog(self, mnemonic, self.wallet.imported_keys)
+        d.exec_()
 
 
 
@@ -1666,6 +1557,30 @@ class ElectrumWindow(QMainWindow):
         apply( func, args)
 
 
+    def show_public_keys(self, address):
+        if not address: return
+        try:
+            pubkey_list = self.wallet.get_public_keys(address)
+        except Exception as e:
+            traceback.print_exc(file=sys.stdout)
+            self.show_message(str(e))
+            return
+
+        d = QDialog(self)
+        d.setMinimumSize(600, 200)
+        d.setModal(1)
+        vbox = QVBoxLayout()
+        vbox.addWidget( QLabel(_("Address") + ': ' + address))
+        vbox.addWidget( QLabel(_("Public key") + ':'))
+        keys = QTextEdit()
+        keys.setReadOnly(True)
+        keys.setText('\n'.join(pubkey_list))
+        vbox.addWidget(keys)
+        #vbox.addWidget( QRCodeWidget('\n'.join(pk_list)) )
+        vbox.addLayout(close_button(d))
+        d.setLayout(vbox)
+        d.exec_()
+
     @protected
     def show_private_key(self, address, password):
         if not address: return
@@ -1973,36 +1888,86 @@ class ElectrumWindow(QMainWindow):
 
 
     @protected
-    def do_export_privkeys(self, password):
-        if not self.wallet.seed:
-            self.show_message(_("This wallet has no seed"))
+    def export_privkeys_dialog(self, password):
+        if self.wallet.is_watching_only():
+            self.show_message(_("This is a watching-only wallet"))
             return
 
-        self.show_message("%s\n%s\n%s" % (_("WARNING: ALL your private keys are secret."),  _("Exposing a single private key can compromise your entire wallet!"), _("In particular, DO NOT use 'redeem private key' services proposed by third parties.")))
+        d = QDialog(self)
+        d.setWindowTitle(_('Private keys'))
+        d.setMinimumSize(850, 300)
+        vbox = QVBoxLayout(d)
+
+        msg = "%s\n%s\n%s" % (_("WARNING: ALL your private keys are secret."), 
+                              _("Exposing a single private key can compromise your entire wallet!"), 
+                              _("In particular, DO NOT use 'redeem private key' services proposed by third parties."))
+        vbox.addWidget(QLabel(msg))
 
-        try:
-            select_export = _('Select file to export your private keys to')
-            fileName = self.getSaveFileName(select_export, 'electrum-private-keys.csv', "*.csv")
-            if fileName:
-                with open(fileName, "w+") as csvfile:
-                    transaction = csv.writer(csvfile)
-                    transaction.writerow(["address", "private_key"])
+        e = QTextEdit()
+        e.setReadOnly(True)
+        vbox.addWidget(e)
 
-                    addresses = self.wallet.addresses(True)
+        defaultname = 'electrum-private-keys.csv'
+        select_msg = _('Select file to export your private keys to')
+        hbox, filename_e, csv_button = filename_field(self, self.config, defaultname, select_msg)
+        vbox.addLayout(hbox)
+
+        h, b = ok_cancel_buttons2(d, _('Export'))
+        b.setEnabled(False)
+        vbox.addLayout(h)
+
+        private_keys = {}
+        addresses = self.wallet.addresses(True)
+        done = False
+        def privkeys_thread():
+            for addr in addresses:
+                time.sleep(0.1)
+                if done: 
+                    break
+                private_keys[addr] = "\n".join(self.wallet.get_private_key(addr, password))
+                d.emit(SIGNAL('computing_privkeys'))
+            d.emit(SIGNAL('show_privkeys'))
+
+        def show_privkeys():
+            s = "\n".join( map( lambda x: x[0] + "\t"+ x[1], private_keys.items()))
+            e.setText(s)
+            b.setEnabled(True)
+
+        d.connect(d, QtCore.SIGNAL('computing_privkeys'), lambda: e.setText("Please wait... %d/%d"%(len(private_keys),len(addresses))))
+        d.connect(d, QtCore.SIGNAL('show_privkeys'), show_privkeys)
+        threading.Thread(target=privkeys_thread).start()
 
-                    for addr in addresses:
-                        pk = "".join(self.wallet.get_private_key(addr, password))
-                        transaction.writerow(["%34s"%addr,pk])
+        if not d.exec_():
+            done = True
+            return
 
-                    self.show_message(_("Private keys exported."))
+        filename = filename_e.text()
+        if not filename:
+            return
 
+        try:
+            self.do_export_privkeys(filename, private_keys, csv_button.isChecked())
         except (IOError, os.error), reason:
             export_error_label = _("Electrum was unable to produce a private key-export.")
             QMessageBox.critical(None, _("Unable to create csv"), export_error_label + "\n" + str(reason))
 
         except Exception as e:
-          self.show_message(str(e))
-          return
+            self.show_message(str(e))
+            return
+
+        self.show_message(_("Private keys exported."))
+
+
+    def do_export_privkeys(self, fileName, pklist, is_csv):
+        with open(fileName, "w+") as f:
+            if is_csv:
+                transaction = csv.writer(f)
+                transaction.writerow(["address", "private_key"])
+                for addr, pk in pklist.items():
+                    transaction.writerow(["%34s"%addr,pk])
+            else:
+                import json
+                f.write(json.dumps(pklist, indent = 4))
 
 
     def do_import_labels(self):
@@ -2031,9 +1996,129 @@ class ElectrumWindow(QMainWindow):
             QMessageBox.critical(None, _("Unable to export labels"), _("Electrum was unable to export your labels.")+"\n" + str(reason))
 
 
-    def do_export_history(self):
-        from lite_window import csv_transaction
-        csv_transaction(self.wallet)
+    def export_history_dialog(self):
+
+        d = QDialog(self)
+        d.setWindowTitle(_('Export History'))
+        d.setMinimumSize(400, 200)
+        vbox = QVBoxLayout(d)
+
+        defaultname = os.path.expanduser('~/electrum-history.csv')
+        select_msg = _('Select file to export your wallet transactions to')
+
+        hbox, filename_e, csv_button = filename_field(self, self.config, defaultname, select_msg)
+        vbox.addLayout(hbox)
+
+        vbox.addStretch(1)
+
+        h, b = ok_cancel_buttons2(d, _('Export'))
+        vbox.addLayout(h)
+        if not d.exec_():
+            return
+
+        filename = filename_e.text()
+        if not filename:
+            return
+
+        try:
+            self.do_export_history(self.wallet, filename, csv_button.isChecked())
+        except (IOError, os.error), reason:
+            export_error_label = _("Electrum was unable to produce a transaction export.")
+            QMessageBox.critical(self, _("Unable to export history"), export_error_label + "\n" + str(reason))
+            return
+
+        QMessageBox.information(self,_("History exported"), _("Your wallet history has been successfully exported."))
+
+
+    def do_export_history(self, wallet, fileName, is_csv):
+        history = wallet.get_tx_history()
+        lines = []
+        for item in history:
+            tx_hash, confirmations, is_mine, value, fee, balance, timestamp = item
+            if confirmations:
+                if timestamp is not None:
+                    try:
+                        time_string = datetime.datetime.fromtimestamp(timestamp).isoformat(' ')[:-3]
+                    except [RuntimeError, TypeError, NameError] as reason:
+                        time_string = "unknown"
+                        pass
+                else:
+                    time_string = "unknown"
+            else:
+                time_string = "pending"
+
+            if value is not None:
+                value_string = format_satoshis(value, True)
+            else:
+                value_string = '--'
+
+            if fee is not None:
+                fee_string = format_satoshis(fee, True)
+            else:
+                fee_string = '0'
+
+            if tx_hash:
+                label, is_default_label = wallet.get_label(tx_hash)
+                label = label.encode('utf-8')
+            else:
+                label = ""
+
+            balance_string = format_satoshis(balance, False)
+            if is_csv:
+                lines.append([tx_hash, label, confirmations, value_string, fee_string, balance_string, time_string])
+            else:
+                lines.append({'txid':tx_hash, 'date':"%16s"%time_string, 'label':label, 'value':value_string})
+
+        with open(fileName, "w+") as f:
+            if is_csv:
+                transaction = csv.writer(f)
+                transaction.writerow(["transaction_hash","label", "confirmations", "value", "fee", "balance", "timestamp"])
+                for line in lines:
+                    transaction.writerow(line)
+            else:
+                import json
+                f.write(json.dumps(lines, indent = 4))
+
+
+    def sweep_key_dialog(self):
+        d = QDialog(self)
+        d.setWindowTitle(_('Sweep private keys'))
+        d.setMinimumSize(600, 300)
+
+        vbox = QVBoxLayout(d)
+        vbox.addWidget(QLabel(_("Enter private keys")))
+
+        keys_e = QTextEdit()
+        keys_e.setTabChangesFocus(True)
+        vbox.addWidget(keys_e)
+
+        h, address_e = address_field(self.wallet.addresses())
+        vbox.addLayout(h)
+
+        vbox.addStretch(1)
+        hbox, button = ok_cancel_buttons2(d, _('Sweep'))
+        vbox.addLayout(hbox)
+        button.setEnabled(False)
+
+        def get_address():
+            addr = str(address_e.text())
+            if bitcoin.is_address(addr):
+                return addr
+
+        def get_pk():
+            pk = str(keys_e.toPlainText()).strip()
+            if Wallet.is_private_key(pk):
+                return pk.split()
+
+        f = lambda: button.setEnabled(get_address() is not None and get_pk() is not None)
+        keys_e.textChanged.connect(f)
+        address_e.textChanged.connect(f)
+        if not d.exec_():
+            return
+
+        fee = self.wallet.fee
+        tx = Transaction.sweep(get_pk(), self.network, get_address(), fee)
+        self.show_transaction(tx)
 
 
     @protected
@@ -2130,9 +2215,23 @@ class ElectrumWindow(QMainWindow):
         grid.addWidget(HelpButton(_('Using change addresses makes it more difficult for other people to track your transactions.')+' '), 4, 2)
         if not self.config.is_modifiable('use_change'): usechange_cb.setEnabled(False)
 
-        grid.setRowStretch(5,1)
+        block_explorers = ['Blockchain.info', 'Blockr.io', 'Insight.is']
+        block_ex_label = QLabel(_('Online Block Explorer') + ':')
+        grid.addWidget(block_ex_label, 5, 0)
+        block_ex_combo = QComboBox()
+        block_ex_combo.addItems(block_explorers)
+        block_ex_combo.setCurrentIndex(block_explorers.index(self.config.get('block_explorer', 'Blockchain.info')))
+        grid.addWidget(block_ex_combo, 5, 1)
+        grid.addWidget(HelpButton(_('Choose which online block explorer to use for functions that open a web browser')+' '), 5, 2)
+
+        show_tx = self.config.get('show_before_broadcast', False)
+        showtx_cb = QCheckBox(_('Show before broadcast'))
+        showtx_cb.setChecked(show_tx)
+        grid.addWidget(showtx_cb, 6, 0)
+        grid.addWidget(HelpButton(_('Display the details of your transactions before broadcasting it.')), 6, 2)
 
         vbox.addLayout(grid)
+        vbox.addStretch(1)
         vbox.addLayout(ok_cancel_buttons(d))
         d.setLayout(vbox)
 
@@ -2167,6 +2266,9 @@ class ElectrumWindow(QMainWindow):
             self.wallet.use_change = usechange_result
             self.wallet.storage.put('use_change', self.wallet.use_change)
 
+        if showtx_cb.isChecked() != show_tx:
+            self.config.set_key('show_before_broadcast', not show_tx)
+
         unit_result = units[unit_combo.currentIndex()]
         if self.base_unit() != unit_result:
             self.decimal_point = 8 if unit_result == 'BTC' else 5
@@ -2181,6 +2283,9 @@ class ElectrumWindow(QMainWindow):
             self.config.set_key("language", lang_request, True)
             need_restart = True
 
+        be_result = block_explorers[block_ex_combo.currentIndex()]
+        self.config.set_key('block_explorer', be_result, True)
+
         run_hook('close_settings_dialog')
 
         if need_restart:
@@ -2194,8 +2299,10 @@ class ElectrumWindow(QMainWindow):
 
     def closeEvent(self, event):
         self.tray.hide()
-        g = self.geometry()
-        self.config.set_key("winpos-qt", [g.left(),g.top(),g.width(),g.height()], True)
+        self.config.set_key("is_maximized", self.isMaximized())
+        if not self.isMaximized():
+            g = self.geometry()
+            self.config.set_key("winpos-qt", [g.left(),g.top(),g.width(),g.height()])
         self.save_column_widths()
         self.config.set_key("console-history", self.console.history[-50:], True)
         self.wallet.storage.put('accounts_expanded', self.accounts_expanded)