unlock icon
[electrum-nvc.git] / gui / gui_classic.py
index fa7abea..bfba42a 100644 (file)
@@ -41,6 +41,7 @@ except:
 from electrum.wallet import format_satoshis
 from electrum.bitcoin import Transaction, is_valid
 from electrum import mnemonic
+from electrum import util, bitcoin, commands
 
 import bmp, pyqrnative
 import exchange_rate
@@ -60,8 +61,6 @@ elif platform.system() == 'Darwin':
 else:
     MONOSPACE_FONT = 'monospace'
 
-ALIAS_REGEXP = '^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$'    
-
 from electrum import ELECTRUM_VERSION
 import re
 
@@ -225,7 +224,6 @@ class StatusBarButton(QPushButton):
 
 
 
-
 def waiting_dialog(f):
 
     s = Timer()
@@ -247,18 +245,35 @@ def waiting_dialog(f):
     w.destroy()
 
 
-def ok_cancel_buttons(dialog):
+def ok_cancel_buttons(dialog, ok_label=_("OK") ):
     hbox = QHBoxLayout()
     hbox.addStretch(1)
-    b = QPushButton("OK")
-    hbox.addWidget(b)
-    b.clicked.connect(dialog.accept)
-    b = QPushButton("Cancel")
+    b = QPushButton(_("Cancel"))
     hbox.addWidget(b)
     b.clicked.connect(dialog.reject)
+    b = QPushButton(ok_label)
+    hbox.addWidget(b)
+    b.clicked.connect(dialog.accept)
+    b.setDefault(True)
     return hbox
 
 
+def text_dialog(parent, title, label, ok_label):
+    dialog = QDialog(parent)
+    dialog.setMinimumWidth(500)
+    dialog.setWindowTitle(title)
+    dialog.setModal(1)
+    l = QVBoxLayout()
+    dialog.setLayout(l)
+    l.addWidget(QLabel(label))
+    txt = QTextEdit()
+    l.addWidget(txt)
+    l.addLayout(ok_cancel_buttons(dialog, ok_label))
+    if dialog.exec_():
+        return unicode(txt.toPlainText())
+
+
+
 default_column_widths = { "history":[40,140,350,140], "contacts":[350,330], 
        "receive":[[370],[370,200,130]] }
 
@@ -271,13 +286,14 @@ class ElectrumWindow(QMainWindow):
         self.config = config
         self.init_plugins()
 
-        self.wallet.interface.register_callback('updated', self.update_callback)
-        self.wallet.interface.register_callback('banner', lambda: self.emit(QtCore.SIGNAL('banner_signal')) )
-        self.wallet.interface.register_callback('disconnected', self.update_callback)
-        self.wallet.interface.register_callback('disconnecting', self.update_callback)
+        self.create_status_bar()
+
+        self.wallet.interface.register_callback('updated', lambda: self.emit(QtCore.SIGNAL('update_wallet')))
+        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.merchant_name = config.get('merchant_name', 'Invoice')
 
         set_language(config.get('language'))
 
@@ -294,7 +310,6 @@ class ElectrumWindow(QMainWindow):
         tabs.setMinimumSize(600, 400)
         tabs.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
         self.setCentralWidget(tabs)
-        self.create_status_bar()
 
         g = self.config.get("winpos-qt",[100, 100, 840, 400])
         self.setGeometry(g[0], g[1], g[2], g[3])
@@ -307,7 +322,8 @@ class ElectrumWindow(QMainWindow):
         QShortcut(QKeySequence("Ctrl+PgUp"), self, lambda: tabs.setCurrentIndex( (tabs.currentIndex() - 1 )%tabs.count() ))
         QShortcut(QKeySequence("Ctrl+PgDown"), self, lambda: tabs.setCurrentIndex( (tabs.currentIndex() + 1 )%tabs.count() ))
         
-        self.connect(self, QtCore.SIGNAL('updatesignal'), self.update_wallet)
+        self.connect(self, QtCore.SIGNAL('update_wallet'), self.update_wallet)
+        self.connect(self, QtCore.SIGNAL('update_status'), self.update_status)
         self.connect(self, QtCore.SIGNAL('banner_signal'), lambda: self.console.showMessage(self.wallet.banner) )
         self.history_list.setFocus(True)
         
@@ -323,74 +339,90 @@ class ElectrumWindow(QMainWindow):
         # set initial message
         self.console.showMessage(self.wallet.banner)
 
+        # plugins that need to change the GUI do it here
+        self.run_hook('init_gui')
+
 
     # plugins
     def init_plugins(self):
-        import imp, pkgutil
-        if os.path.exists("plugins"):
+        import imp, pkgutil, __builtin__
+        if __builtin__.use_local_modules:
             fp, pathname, description = imp.find_module('plugins')
+            plugin_names = [name for a, name, b in pkgutil.iter_modules([pathname])]
+            plugin_names = filter( lambda name: os.path.exists(os.path.join(pathname,name+'.py')), plugin_names)
             imp.load_module('electrum_plugins', fp, pathname, description)
-            plugin_names = [name for a, name, b in pkgutil.iter_modules(['plugins'])]
-            self.plugins = map(lambda name: imp.load_source('electrum_plugins.'+name, os.path.join(pathname,name+'.py')), plugin_names)
+            plugins = map(lambda name: imp.load_source('electrum_plugins.'+name, os.path.join(pathname,name+'.py')), plugin_names)
         else:
             import electrum_plugins
             plugin_names = [name for a, name, b in pkgutil.iter_modules(electrum_plugins.__path__)]
-            self.plugins = [ __import__('electrum_plugins.'+name, fromlist=['electrum_plugins']) for name in plugin_names]
+            plugins = [ __import__('electrum_plugins.'+name, fromlist=['electrum_plugins']) for name in plugin_names]
 
-        self.plugin_hooks = {}
-        for p in self.plugins:
+        self.plugins = []
+        for p in plugins:
             try:
-                p.init(self)
+                self.plugins.append( p.Plugin(self) )
             except:
                 print_msg("Error:cannot initialize plugin",p)
                 traceback.print_exc(file=sys.stdout)
 
-    def set_hook(self, name, callback):
-        h = self.plugin_hooks.get(name, [])
-        h.append(callback)
-        self.plugin_hooks[name] = h
 
-    def unset_hook(self, name, callback):
-        h = self.plugin_hooks.get(name,[])
-        if callback in h: h.remove(callback)
-        self.plugin_hooks[name] = h
+    def run_hook(self, name, *args):
+        for p in self.plugins:
+            if not p.is_enabled():
+                continue
+            try:
+                f = eval('p.'+name)
+            except:
+                continue
+            apply(f, args)
+        return
+
+        
+    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
+                changed = True
+        else:
+            if old_text:
+                self.wallet.labels.pop(name)
+                changed = True
+        self.run_hook('set_label', name, text, changed)
+        return changed
+
+
+    # custom wrappers for getOpenFileName and getSaveFileName, that remember the path selected by the user
+    def getOpenFileName(self, title, filter = None):
+        directory = self.config.get('io_dir', 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 = None):
+        directory = self.config.get('io_dir', 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):
+            self.config.set_key('io_dir', os.path.dirname(fileName), True)
+        return fileName
 
-    def run_hook(self, name, args):
-        for cb in self.plugin_hooks.get(name,[]):
-            apply(cb, args)
 
 
     def close(self):
         QMainWindow.close(self)
-        self.run_hook('close_main_window', (self,))
+        self.run_hook('close_main_window')
 
     def connect_slots(self, sender):
         self.connect(sender, QtCore.SIGNAL('timersignal'), self.timer_actions)
         self.previous_payto_e=''
 
     def timer_actions(self):
-        self.run_hook('timer_actions', (self,))
+        self.run_hook('timer_actions')
             
-        if self.payto_e.hasFocus():
-            return
-        r = unicode( self.payto_e.text() )
-        if r != self.previous_payto_e:
-            self.previous_payto_e = r
-            r = r.strip()
-            if re.match('^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$', r):
-                try:
-                    to_address = self.wallet.get_alias(r, True, self.show_message, self.question)
-                except:
-                    return
-                if to_address:
-                    s = r + '  <' + to_address + '>'
-                    self.payto_e.setText(s)
-
-
-    def update_callback(self):
-        self.emit(QtCore.SIGNAL('updatesignal'))
-
-    def update_wallet(self):
+    def update_status(self):
         if self.wallet.interface and self.wallet.interface.is_connected:
             if not self.wallet.up_to_date:
                 text = _("Synchronizing...")
@@ -409,6 +441,8 @@ class ElectrumWindow(QMainWindow):
         self.statusBar().showMessage(text)
         self.status_button.setIcon( icon )
 
+    def update_wallet(self):
+        self.update_status()
         if self.wallet.up_to_date or not self.wallet.interface.is_connected:
             self.update_history_tab()
             self.update_receive_tab()
@@ -453,7 +487,7 @@ class ElectrumWindow(QMainWindow):
 
 
     def show_tx_details(self, tx):
-        dialog = QDialog(None)
+        dialog = QDialog(self)
         dialog.setModal(1)
         dialog.setWindowTitle(_("Transaction Details"))
         vbox = QVBoxLayout()
@@ -479,7 +513,7 @@ class ElectrumWindow(QMainWindow):
         vbox.addWidget(QLabel("Date: %s"%time_str))
         vbox.addWidget(QLabel("Status: %d confirmations"%conf))
         if is_mine:
-            if fee: 
+            if fee is not None: 
                 vbox.addWidget(QLabel("Amount sent: %s"% format_satoshis(v-fee, False)))
                 vbox.addWidget(QLabel("Transaction fee: %s"% format_satoshis(fee, False)))
             else:
@@ -514,13 +548,11 @@ class ElectrumWindow(QMainWindow):
         self.is_edit=True
         tx_hash = str(item.data(0, Qt.UserRole).toString())
         tx = self.wallet.transactions.get(tx_hash)
-        s = self.wallet.labels.get(tx_hash)
         text = unicode( item.text(2) )
+        self.set_label(tx_hash, text) 
         if text: 
-            self.wallet.labels[tx_hash] = text
             item.setForeground(2, QBrush(QColor('black')))
         else:
-            if s: self.wallet.labels.pop(tx_hash)
             text = self.wallet.get_default_label(tx_hash)
             item.setText(2, text)
             item.setForeground(2, QBrush(QColor('gray')))
@@ -538,49 +570,36 @@ class ElectrumWindow(QMainWindow):
 
     def address_label_clicked(self, item, column, l, column_addr, column_label):
         if column == column_label and item.isSelected():
+            is_editable = item.data(0, 32).toBool()
+            if not is_editable:
+                return
             addr = unicode( item.text(column_addr) )
             label = unicode( item.text(column_label) )
-            if label in self.wallet.aliases.keys():
-                return
             item.setFlags(Qt.ItemIsEditable|Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled)
             l.editItem( item, column )
             item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled)
 
 
     def address_label_changed(self, item, column, l, column_addr, column_label):
-
         if column == column_label:
             addr = unicode( item.text(column_addr) )
             text = unicode( item.text(column_label) )
-            changed = False
-
-            if text:
-                if text not in self.wallet.aliases.keys():
-                    old_addr = self.wallet.labels.get(text)
-                    if old_addr != addr:
-                        self.wallet.labels[addr] = text
-                        changed = True
-                else:
-                    print_error("Error: This is one of your aliases")
-                    label = self.wallet.labels.get(addr,'')
-                    item.setText(column_label, QString(label))
-            else:
-                s = self.wallet.labels.get(addr)
-                if s: 
-                    self.wallet.labels.pop(addr)
-                    changed = True
+            is_editable = item.data(0, 32).toBool()
+            if not is_editable:
+                return
 
+            changed = self.set_label(addr, text)
             if changed:
                 self.update_history_tab()
                 self.update_completions()
                 
             self.current_item_changed(item)
 
-        self.run_hook('item_changed',(self, item, column))
+        self.run_hook('item_changed', item, column)
 
 
     def current_item_changed(self, a):
-        self.run_hook('current_item_changed',(self, a))
+        self.run_hook('current_item_changed', a)
 
 
 
@@ -726,7 +745,7 @@ class ElectrumWindow(QMainWindow):
         self.amount_e.textChanged.connect(lambda: entry_changed(False) )
         self.fee_e.textChanged.connect(lambda: entry_changed(True) )
 
-        self.run_hook('create_send_tab',(self,grid))
+        self.run_hook('create_send_tab', grid)
         return w2
 
 
@@ -735,31 +754,25 @@ class ElectrumWindow(QMainWindow):
         for addr,label in self.wallet.labels.items():
             if addr in self.wallet.addressbook:
                 l.append( label + '  <' + addr + '>')
-        l = l + self.wallet.aliases.keys()
 
+        self.run_hook('update_completions', l)
         self.completions.setStringList(l)
 
 
+    def protected(func):
+        return lambda s, *args: s.do_protect(func, args)
 
-    def do_send(self):
+
+    @protected
+    def do_send(self, password):
 
         label = unicode( self.message_e.text() )
         r = unicode( self.payto_e.text() )
         r = r.strip()
 
-        # alias
-        m1 = re.match(ALIAS_REGEXP, r)
         # label or alias, with address in brackets
-        m2 = re.match('(.*?)\s*\<([1-9A-HJ-NP-Za-km-z]{26,})\>', r)
-        
-        if m1:
-            to_address = self.wallet.get_alias(r, True, self.show_message, self.question)
-            if not to_address:
-                return
-        elif m2:
-            to_address = m2.group(2)
-        else:
-            to_address = r
+        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'))
@@ -776,23 +789,16 @@ class ElectrumWindow(QMainWindow):
             QMessageBox.warning(self, _('Error'), _('Invalid Fee'), _('OK'))
             return
 
-        if self.wallet.use_encryption:
-            password = self.password_dialog()
-            if not password:
-                return
-        else:
-            password = None
-
         try:
             tx = self.wallet.mktx( [(to_address, amount)], password, fee)
         except BaseException, e:
             self.show_message(str(e))
             return
 
-        self.run_hook('send_tx', (wallet, self, tx))
+        self.run_hook('send_tx', tx)
 
         if label: 
-            self.wallet.labels[tx.hash()] = label
+            self.set_label(tx.hash(), label)
 
         if tx.is_complete:
             h = self.wallet.send_tx(tx)
@@ -805,9 +811,9 @@ class ElectrumWindow(QMainWindow):
             else:
                 QMessageBox.warning(self, _('Error'), msg, _('OK'))
         else:
-            filename = 'unsigned_tx_%s' % (time.mktime(time.gmtime()))
+            filename = label + '.txn' if label else 'unsigned_%s.txn' % (time.mktime(time.gmtime()))
             try:
-                fileName = QFileDialog.getSaveFileName(QWidget(), _("Select a transaction filename"), os.path.expanduser('~/%s' % (filename)))
+                fileName = self.getSaveFileName(_("Select a transaction filename"), filename, "*.txn")
                 with open(fileName,'w') as f:
                     f.write(json.dumps(tx.as_dict(),indent=4) + '\n')
                 QMessageBox.information(self, _('Unsigned transaction created'), _("Unsigned transaction was saved to file:") + " " +fileName, _('OK'))
@@ -818,10 +824,19 @@ class ElectrumWindow(QMainWindow):
 
 
     def set_url(self, url):
-        payto, amount, label, message, signature, identity, url = self.wallet.parse_url(url, self.show_message, self.question)
+        address, amount, label, message, signature, identity, url = util.parse_url(url)
+
+        if label and self.wallet.labels.get(address) != label:
+            if self.question('Give label "%s" to address %s ?'%(label,address)):
+                if address not in self.wallet.addressbook and not self.wallet.is_mine(address):
+                    self.wallet.addressbook.append(address)
+                self.set_label(address, label)
+
+        self.run_hook('set_url', url, self.show_message, self.question)
+
         self.tabs.setCurrentIndex(1)
-        label = self.wallet.labels.get(payto)
-        m_addr = label + '  <'+ payto+'>' if label else payto
+        label = self.wallet.labels.get(address)
+        m_addr = label + '  <'+ address +'>' if label else address
         self.payto_e.setText(m_addr)
 
         self.message_e.setText(message)
@@ -972,9 +987,9 @@ class ElectrumWindow(QMainWindow):
             return 
         menu = QMenu()
         menu.addAction(_("Copy to clipboard"), lambda: self.app.clipboard().setText(addr))
-        menu.addAction(_("QR code"), lambda: ElectrumWindow.show_qrcode("bitcoin:" + addr, _("Address")) )
+        menu.addAction(_("QR code"), lambda: self.show_qrcode("bitcoin:" + addr, _("Address")) )
         menu.addAction(_("Edit label"), lambda: self.edit_label(True))
-        menu.addAction(_("Private key"), lambda: self.view_private_key(addr))
+        menu.addAction(_("Private key"), lambda: self.show_private_key(addr))
         menu.addAction(_("Sign message"), lambda: self.sign_message(addr))
         if addr in self.wallet.imported_keys:
             menu.addAction(_("Remove from wallet"), lambda: self.delete_imported_key(addr))
@@ -985,55 +1000,45 @@ class ElectrumWindow(QMainWindow):
             t = _("Unprioritize") if addr in self.wallet.prioritized_addresses else _("Prioritize")
             menu.addAction(t, lambda: self.toggle_priority(addr))
             
-        self.run_hook('receive_menu', (self, menu,))
+        self.run_hook('receive_menu', menu)
         menu.exec_(self.receive_list.viewport().mapToGlobal(position))
 
 
-    def payto(self, x, is_alias):
-        if not x: return
-        if is_alias:
-            label = x
-            m_addr = label
-        else:
-            addr = x
-            label = self.wallet.labels.get(addr)
-            m_addr = label + '  <' + addr + '>' if label else addr
+    def payto(self, addr):
+        if not addr: return
+        label = self.wallet.labels.get(addr)
+        m_addr = label + '  <' + addr + '>' if label else addr
         self.tabs.setCurrentIndex(1)
         self.payto_e.setText(m_addr)
         self.amount_e.setFocus()
 
-    def delete_contact(self, x, is_alias):
+
+    def delete_contact(self, x):
         if self.question(_("Do you want to remove")+" %s "%x +_("from your list of contacts?")):
-            if not is_alias and x in self.wallet.addressbook:
+            if x in self.wallet.addressbook:
                 self.wallet.addressbook.remove(x)
-                if x in self.wallet.labels.keys():
-                    self.wallet.labels.pop(x)
-            elif is_alias and x in self.wallet.aliases:
-                self.wallet.aliases.pop(x)
-            self.update_history_tab()
-            self.update_contacts_tab()
-            self.update_completions()
+                self.set_label(x, None)
+                self.update_history_tab()
+                self.update_contacts_tab()
+                self.update_completions()
 
-    def create_contact_menu(self, position):
-        # fixme: this function apparently has a side effect.
-        # if it is not called the menu pops up several times
-        #self.contacts_list.selectedIndexes() 
 
+    def create_contact_menu(self, position):
         item = self.contacts_list.itemAt(position)
         if not item: return
         addr = unicode(item.text(0))
         label = unicode(item.text(1))
-        is_alias = label in self.wallet.aliases.keys()
-        x = label if is_alias else addr
+        is_editable = item.data(0,32).toBool()
+        payto_addr = item.data(0,33).toString()
         menu = QMenu()
         menu.addAction(_("Copy to Clipboard"), lambda: self.app.clipboard().setText(addr))
-        menu.addAction(_("Pay to"), lambda: self.payto(x, is_alias))
+        menu.addAction(_("Pay to"), lambda: self.payto(payto_addr))
         menu.addAction(_("QR code"), lambda: self.show_qrcode("bitcoin:" + addr, _("Address")))
-        if not is_alias:
+        if is_editable:
             menu.addAction(_("Edit label"), lambda: self.edit_label(False))
-        else:
-            menu.addAction(_("View alias details"), lambda: self.show_contact_details(label))
-        menu.addAction(_("Delete"), lambda: self.delete_contact(x,is_alias))
+            menu.addAction(_("Delete"), lambda: self.delete_contact(addr))
+
+        self.run_hook('create_contact_menu', menu, item)
         menu.exec_(self.contacts_list.viewport().mapToGlobal(position))
 
 
@@ -1043,7 +1048,7 @@ class ElectrumWindow(QMainWindow):
         label = self.wallet.labels.get(address,'')
         item.setData(1,0,label)
 
-        self.run_hook('update_receive_item', (self, address, item))
+        self.run_hook('update_receive_item', address, item)
                 
         c, u = self.wallet.get_addr_balance(address)
         balance = format_satoshis( c + u, False, self.wallet.num_zeros )
@@ -1089,13 +1094,12 @@ class ElectrumWindow(QMainWindow):
                 for address in account[is_change]:
                     h = self.wallet.history.get(address,[])
             
-                    if not is_change:
-                        if h == []:
-                            gap += 1
-                            if gap > self.wallet.gap_limit:
-                                is_red = True
-                        else:
-                            gap = 0
+                    if h == []:
+                        gap += 1
+                        if gap > self.wallet.gap_limit:
+                            is_red = True
+                    else:
+                        gap = 0
 
                     num_tx = '*' if h == ['*'] else "%d"%len(h)
                     item = QTreeWidgetItem( [ address, '', '', num_tx] )
@@ -1118,46 +1122,30 @@ class ElectrumWindow(QMainWindow):
         # we use column 1 because column 0 may be hidden
         l.setCurrentItem(l.topLevelItem(0),1)
 
-    def show_contact_details(self, m):
-        a = self.wallet.aliases.get(m)
-        if a:
-            if a[0] in self.wallet.authorities.keys():
-                s = self.wallet.authorities.get(a[0])
-            else:
-                s = "self-signed"
-            msg = _('Alias:')+' '+ m + '\n'+_('Target address:')+' '+ a[1] + '\n\n'+_('Signed by:')+' ' + s + '\n'+_('Signing address:')+' ' + a[0]
-            QMessageBox.information(self, 'Alias', msg, 'OK')
 
     def update_contacts_tab(self):
 
         l = self.contacts_list
         l.clear()
 
-        alias_targets = []
-        for alias, v in self.wallet.aliases.items():
-            s, target = v
-            alias_targets.append(target)
-            item = QTreeWidgetItem( [ target, alias, '-'] )
-            item.setBackgroundColor(0, QColor('lightgray'))
-            l.addTopLevelItem(item)
-            
         for address in self.wallet.addressbook:
-            if address in alias_targets: continue
             label = self.wallet.labels.get(address,'')
-            n = 0 
-            for tx in self.wallet.transactions.values():
-                if address in map(lambda x: x[0], tx.outputs): n += 1
-            
+            n = self.wallet.get_num_tx(address)
             item = QTreeWidgetItem( [ address, label, "%d"%n] )
             item.setFont(0, QFont(MONOSPACE_FONT))
+            # 32 = label can be edited (bool)
+            item.setData(0,32, True)
+            # 33 = payto string
+            item.setData(0,33, address)
             l.addTopLevelItem(item)
 
+        self.run_hook('update_contacts_tab', l)
         l.setCurrentItem(l.topLevelItem(0))
 
 
+
     def create_console_tab(self):
         from qt_console import Console
-        from electrum import util, bitcoin, commands
         self.console = console = Console()
         self.console.history = self.config.get("console-history",[])
         self.console.history_index = len(self.console.history)
@@ -1190,13 +1178,17 @@ class ElectrumWindow(QMainWindow):
         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:
-            sb.addPermanentWidget( StatusBarButton( QIcon(":icons/lock.png"), _("Password"), lambda: self.change_password_dialog(self.wallet, self) ) )
+            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 )
         sb.addPermanentWidget( StatusBarButton( QIcon(":icons/preferences.png"), _("Preferences"), self.settings_dialog ) )
         if self.wallet.seed:
-            sb.addPermanentWidget( StatusBarButton( QIcon(":icons/seed.png"), _("Seed"), lambda: self.show_seed_dialog(self.wallet, self) ) )
+            sb.addPermanentWidget( StatusBarButton( QIcon(":icons/seed.png"), _("Seed"), self.show_seed_dialog ) )
         self.status_button = StatusBarButton( QIcon(":icons/status_disconnected.png"), _("Network"), lambda: self.network_dialog(self.wallet, self) ) 
         sb.addPermanentWidget( self.status_button )
 
+        self.run_hook('create_status_bar', (sb,))
+
         self.setStatusBar(sb)
         
     def go_lite(self):
@@ -1223,7 +1215,7 @@ class ElectrumWindow(QMainWindow):
                 QMessageBox.warning(self, _('Error'), _('Invalid Address'), _('OK'))
 
     def show_master_public_key(self):
-        dialog = QDialog(None)
+        dialog = QDialog(self)
         dialog.setModal(1)
         dialog.setWindowTitle(_("Master Public Key"))
 
@@ -1231,7 +1223,7 @@ class ElectrumWindow(QMainWindow):
         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(), 6)
+        qrw = QRCodeWidget(self.wallet.get_master_public_key())
 
         ok_button = QPushButton(_("OK"))
         ok_button.setDefault(True)
@@ -1254,30 +1246,22 @@ class ElectrumWindow(QMainWindow):
         dialog.exec_()
         
 
-    @classmethod
-    def show_seed_dialog(self, wallet, parent=None):
-        if not wallet.seed:
+    @protected
+    def show_seed_dialog(self, password):
+        if not self.wallet.seed:
             QMessageBox.information(parent, _('Message'), _('No seed'), _('OK'))
             return
-
-        if wallet.use_encryption:
-            password = parent.password_dialog()
-            if not password:
-                return
-        else:
-            password = None
-            
         try:
-            seed = wallet.decode_seed(password)
+            seed = self.wallet.decode_seed(password)
         except:
-            QMessageBox.warning(parent, _('Error'), _('Incorrect Password'), _('OK'))
+            QMessageBox.warning(self, _('Error'), _('Incorrect Password'), _('OK'))
             return
+        self.show_seed(seed, self)
 
-        self.show_seed(seed)
 
     @classmethod
-    def show_seed(self, seed):
-        dialog = QDialog(None)
+    def show_seed(self, seed, parent=None):
+        dialog = QDialog(parent)
         dialog.setModal(1)
         dialog.setWindowTitle('Electrum' + ' - ' + _('Seed'))
 
@@ -1300,7 +1284,7 @@ class ElectrumWindow(QMainWindow):
         logo.setPixmap(QPixmap(":icons/seed.png").scaledToWidth(56))
         logo.setMaximumWidth(60)
 
-        qrw = QRCodeWidget(seed, 4)
+        qrw = QRCodeWidget(seed)
 
         ok_button = QPushButton(_("OK"))
         ok_button.setDefault(True)
@@ -1328,10 +1312,9 @@ class ElectrumWindow(QMainWindow):
         dialog.setLayout(vbox)
         dialog.exec_()
 
-    @staticmethod
-    def show_qrcode(data, title = "QR code"):
+    def show_qrcode(self, data, title = "QR code"):
         if not data: return
-        d = QDialog(None)
+        d = QDialog(self)
         d.setModal(1)
         d.setWindowTitle(title)
         d.setMinimumSize(270, 300)
@@ -1360,25 +1343,42 @@ class ElectrumWindow(QMainWindow):
         d.setLayout(vbox)
         d.exec_()
 
-    def view_private_key(self,address):
-        if not address: return
+
+    def do_protect(self, func, args):
         if self.wallet.use_encryption:
             password = self.password_dialog()
             if not password:
                 return
         else:
             password = None
+            
+        if args != (False,):
+            args = (self,) + args + (password,)
+        else:
+            args = (self,password)
+        apply( func, args)
 
+
+    @protected
+    def show_private_key(self, address, password):
+        if not address: return
         try:
             pk = self.wallet.get_private_key(address, password)
         except BaseException, e:
             self.show_message(str(e))
             return
-
         QMessageBox.information(self, _('Private key'), 'Address'+ ': ' + address + '\n\n' + _('Private key') + ': ' + pk, _('OK'))
 
 
-    def sign_message(self,address):
+    @protected
+    def do_sign(self, address, message, signature, password):
+        try:
+            sig = self.wallet.sign_message(str(address.text()), str(message.toPlainText()), password)
+            signature.setText(sig)
+        except BaseException, e:
+            self.show_message(str(e))
+
+    def sign_message(self, address):
         if not address: return
         d = QDialog(self)
         d.setModal(1)
@@ -1405,25 +1405,11 @@ class ElectrumWindow(QMainWindow):
         layout.addWidget(sign_signature, 3, 1)
         layout.setRowStretch(3,1)
 
-        def do_sign():
-            if self.wallet.use_encryption:
-                password = self.password_dialog()
-                if not password:
-                    return
-            else:
-                password = None
-
-            try:
-                signature = self.wallet.sign_message(str(sign_address.text()), str(sign_message.toPlainText()), password)
-                sign_signature.setText(signature)
-            except BaseException, e:
-                self.show_message(str(e))
-                return
 
         hbox = QHBoxLayout()
         b = QPushButton(_("Sign"))
         hbox.addWidget(b)
-        b.clicked.connect(do_sign)
+        b.clicked.connect(lambda: self.do_sign(sign_address, sign_message, sign_signature))
         b = QPushButton(_("Close"))
         b.clicked.connect(d.accept)
         hbox.addWidget(b)
@@ -1498,8 +1484,9 @@ class ElectrumWindow(QMainWindow):
         vbox.addLayout(grid)
 
         vbox.addLayout(ok_cancel_buttons(d))
-        d.setLayout(vbox) 
+        d.setLayout(vbox)
 
+        self.run_hook('password_dialog', pw, grid, 1)
         if not d.exec_(): return
         return unicode(pw.text())
 
@@ -1568,6 +1555,10 @@ class ElectrumWindow(QMainWindow):
             return ElectrumWindow.change_password_dialog(wallet, parent) # Retry
 
         wallet.update_password(seed, password, new_password)
+        if parent: 
+            icon = QIcon(":icons/lock.png") if wallet.use_encryption else QIcon(":icons/unlock.png")
+            parent.password_button.setIcon( icon )
+
 
     @staticmethod
     def seed_dialog(wallet, parent=None):
@@ -1575,20 +1566,22 @@ class ElectrumWindow(QMainWindow):
         d.setModal(1)
 
         vbox = QVBoxLayout()
-        msg = _("Please enter your wallet seed or the corresponding mnemonic list of words, and the gap limit of your wallet.")
+        msg = _("Please enter your wallet seed (or your master public key if you want to create a watching-only wallet)." + '\n')
         vbox.addWidget(QLabel(msg))
 
         grid = QGridLayout()
         grid.setSpacing(8)
 
         seed_e = QLineEdit()
-        grid.addWidget(QLabel(_('Seed or mnemonic')), 1, 0)
+        grid.addWidget(QLabel(_('Seed or master public key')), 1, 0)
         grid.addWidget(seed_e, 1, 1)
+        grid.addWidget(HelpButton(_("Your seed can be entered as a mnemonic (sequence of words), or as a hexadecimal string.")), 1, 3)
 
         gap_e = QLineEdit()
         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)
         gap_e.textChanged.connect(lambda: numbify(gap_e,True))
         vbox.addLayout(grid)
 
@@ -1634,8 +1627,8 @@ class ElectrumWindow(QMainWindow):
         tree_widget.setColumnWidth(0, 300)
         tree_widget.setColumnWidth(1, 50)
 
-        for output in tx.d["outputs"]:
-            item = QTreeWidgetItem( ["%s" %(output["address"]), "%s" % ( format_satoshis(output["value"]))] )
+        for address, value in tx.outputs:
+            item = QTreeWidgetItem( [address, "%s" % ( format_satoshis(value))] )
             tree_widget.addTopLevelItem(item)
 
         tree_widget.setMaximumHeight(100)
@@ -1669,13 +1662,13 @@ class ElectrumWindow(QMainWindow):
             if not tx_dict["complete"]:
                 assert "input_info" in tx_dict.keys()
         except:
-            QMessageBox.critical(None, "Unable to parse transaction", _("Electrum was unable to parse your transaction:"))
+            QMessageBox.critical(None, "Unable to parse transaction", _("Electrum was unable to parse your transaction"))
             return None
         return tx_dict
 
 
     def read_tx_from_file(self):
-        fileName = QFileDialog.getOpenFileName(QWidget(), _("Select your transaction file"), os.path.expanduser('~'))
+        fileName = self.getOpenFileName(_("Select your transaction file"), "*.txn")
         if not fileName:
             return
         try:
@@ -1687,122 +1680,88 @@ class ElectrumWindow(QMainWindow):
         return self.tx_dict_from_text(file_content)
 
 
-    def sign_raw_transaction(self, tx, input_info):
-        if self.wallet.use_encryption:
-            password = self.password_dialog()
-            if not password:
-                return
-        else:
-            password = None
-
+    @protected
+    def sign_raw_transaction(self, tx, input_info, dialog ="", password = ""):
         try:
             self.wallet.signrawtransaction(tx, input_info, [], password)
             
-            fileName = QFileDialog.getSaveFileName(QWidget(), _("Select where to save your signed transaction"), os.path.expanduser('~/signed_tx_%s' % (tx.hash()[0:8])))
+            fileName = self.getSaveFileName(_("Select where to save your signed transaction"), 'signed_%s.txn' % (tx.hash()[0:8]), "*.txn")
             if fileName:
                 with open(fileName, "w+") as f:
                     f.write(json.dumps(tx.as_dict(),indent=4) + '\n')
-                self.show_message(_("Transaction saved succesfully"))
+                self.show_message(_("Transaction saved successfully"))
+                if dialog:
+                    dialog.done(0)
         except BaseException, e:
             self.show_message(str(e))
-
-
-    def create_sign_transaction_window(self, tx_dict):
-        tx = Transaction(tx_dict["hex"])
-
-        dialog = QDialog(self)
-        dialog.setMinimumWidth(500)
-        dialog.setWindowTitle(_('Sign unsigned transaction'))
-        dialog.setModal(1)
-
-        vbox = QVBoxLayout()
-        dialog.setLayout(vbox)
-        vbox.addWidget( self.generate_transaction_information_widget(tx) )
-
-        if tx_dict["complete"] == True:
-            vbox.addWidget(QLabel(_("This transaction is already signed.")))
-        else:
-            vbox.addWidget(QLabel(_("Create a signed transaction.")))
-            vbox.addLayout(ok_cancel_buttons(dialog))
-            input_info = json.loads(tx_dict["input_info"])
-
-        if dialog.exec_():
-            self.sign_raw_transaction(tx, input_info)
-
-
-
-    def do_sign_from_text(self):
-        txt, ok = QInputDialog.getText(QTextEdit(), _('Sign raw transaction'), _('Transaction data in JSON') + ':')
-        if not ok:
-            return
-        tx_dict = self.tx_dict_from_text(unicode(txt))
-        if tx_dict:
-            self.create_sign_transaction_window(tx_dict)
-
-
-    def do_sign_from_file(self):
-        tx_dict = self.read_tx_from_file()
-        if tx_dict:
-            self.create_sign_transaction_window(tx_dict)
     
 
-    def send_raw_transaction(self, raw_tx):
+    def send_raw_transaction(self, raw_tx, dialog = ""):
         result, result_message = self.wallet.sendtx( raw_tx )
         if result:
-            self.show_message("Transaction succesfully sent: %s" % (result_message))
+            self.show_message("Transaction successfully sent: %s" % (result_message))
+            if dialog:
+                dialog.done(0)
         else:
             self.show_message("There was a problem sending your transaction:\n %s" % (result_message))
 
+    def do_process_from_text(self):
+        text = text_dialog(self, _('Input raw transaction'), _("Transaction:"), _("Load transaction"))
+        if not text:
+            return
+        tx_dict = self.tx_dict_from_text(text)
+        if tx_dict:
+            self.create_process_transaction_window(tx_dict)
 
-    def create_send_transaction_window(self, tx_dict):
-        tx = Transaction(tx_dict["hex"])
+    def do_process_from_file(self):
+        tx_dict = self.read_tx_from_file()
+        if tx_dict: 
+            self.create_process_transaction_window(tx_dict)
 
+    def create_process_transaction_window(self, tx_dict):
+        tx = Transaction(tx_dict["hex"])
+            
         dialog = QDialog(self)
         dialog.setMinimumWidth(500)
-        dialog.setWindowTitle(_('Send raw transaction'))
+        dialog.setWindowTitle(_('Process raw transaction'))
         dialog.setModal(1)
 
-        vbox = QVBoxLayout()
-        dialog.setLayout(vbox)
-        vbox.addWidget( self.generate_transaction_information_widget(tx))
+        l = QGridLayout()
+        dialog.setLayout(l)
+
+        l.addWidget(QLabel(_("Transaction status:")), 3,0)
+        l.addWidget(QLabel(_("Actions")), 4,0)
 
         if tx_dict["complete"] == False:
-            vbox.addWidget(QLabel(_("This transaction is not signed yet.")))
+            l.addWidget(QLabel(_("Unsigned")), 3,1)
+            if self.wallet.seed :
+                b = QPushButton("Sign transaction")
+                input_info = json.loads(tx_dict["input_info"])
+                b.clicked.connect(lambda: self.sign_raw_transaction(tx, input_info, dialog))
+                l.addWidget(b, 4, 1)
+            else:
+                l.addWidget(QLabel(_("Wallet is de-seeded, can't sign.")), 4,1)
         else:
-            vbox.addWidget(QLabel(_("Broadcast this transaction")))
-            vbox.addLayout(ok_cancel_buttons(dialog))
-
-        if dialog.exec_():
-            self.send_raw_transaction(tx_dict["hex"])
+            l.addWidget(QLabel(_("Signed")), 3,1)
+            b = QPushButton("Broadcast transaction")
+            b.clicked.connect(lambda: self.send_raw_transaction(tx, dialog))
+            l.addWidget(b,4,1)
 
+        l.addWidget( self.generate_transaction_information_widget(tx), 0,0,2,3)
+        cancelButton = QPushButton(_("Cancel"))
+        cancelButton.clicked.connect(lambda: dialog.done(0))
+        l.addWidget(cancelButton, 4,2)
 
-    def do_send_from_file(self):
-        tx_dict = self.read_tx_from_file()
-        if tx_dict: 
-            self.create_send_transaction_window(tx_dict)
-        
-
-    def do_send_from_text(self):
-        txt, ok = QInputDialog.getText(QTextEdit(), _('Send raw transaction'), _('Transaction data in JSON') + ':')
-        if not ok:
-            return
-        tx_dict = self.tx_dict_from_text(unicode(txt))
-        if tx_dict:
-            self.create_send_transaction_window(tx_dict)
+        dialog.exec_()
 
 
-    def do_export_privkeys(self):
+    @protected
+    def do_export_privkeys(self, password):
         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.")))
 
-        if self.wallet.use_encryption:
-            password = self.password_dialog()
-            if not password:
-                return
-        else:
-            password = None
         try:
             select_export = _('Select file to export your private keys to')
-            fileName = QFileDialog.getSaveFileName(QWidget(), select_export, os.path.expanduser('~/electrum-private-keys.csv'), "*.csv")
+            fileName = self.getSaveFileName(select_export, 'electrum-private-keys.csv', "*.csv")
             if fileName:
                 with open(fileName, "w+") as csvfile:
                     transaction = csv.writer(csvfile)
@@ -1824,7 +1783,7 @@ class ElectrumWindow(QMainWindow):
 
 
     def do_import_labels(self):
-        labelsFile = QFileDialog.getOpenFileName(QWidget(), _("Open text file"), util.user_dir(), self.tr("Text Files (labels.dat)"))
+        labelsFile = self.getOpenFileName(_("Open labels file"), "*.dat")
         if not labelsFile: return
         try:
             f = open(labelsFile, 'r')
@@ -1833,53 +1792,60 @@ class ElectrumWindow(QMainWindow):
             for key, value in json.loads(data).items():
                 self.wallet.labels[key] = value
             self.wallet.save()
-            QMessageBox.information(None, _("Labels imported"), _("Your labels where imported from")+" '%s'" % str(labelsFile))
+            QMessageBox.information(None, _("Labels imported"), _("Your labels were imported from")+" '%s'" % str(labelsFile))
         except (IOError, os.error), reason:
             QMessageBox.critical(None, _("Unable to import labels"), _("Electrum was unable to import your labels.")+"\n" + str(reason))
-        
-
+            
 
     def do_export_labels(self):
         labels = self.wallet.labels
         try:
-            labelsFile = util.user_dir() + '/labels.dat'
-            f = open(labelsFile, 'w+')
-            json.dump(labels, f)
-            f.close()
-            QMessageBox.information(None, "Labels exported", _("Your labels where exported to")+" '%s'" % str(labelsFile))
+            fileName = self.getSaveFileName(_("Select file to save your labels"), 'electrum_labels.dat', "*.dat")
+            if fileName:
+                with open(fileName, 'w+') as f:
+                    json.dump(labels, f)
+                QMessageBox.information(None, "Labels exported", _("Your labels where exported to")+" '%s'" % str(fileName))
         except (IOError, os.error), reason:
             QMessageBox.critical(None, "Unable to export labels", _("Electrum was unable to export your labels.")+"\n" + str(reason))
 
+
     def do_export_history(self):
         from gui_lite import csv_transaction
         csv_transaction(self.wallet)
 
-    def do_import_privkey(self):
+
+    @protected
+    def do_import_privkey(self, password):
         if not self.wallet.imported_keys:
-            r = QMessageBox.question(None, _('Warning'), _('Warning: Imported keys are not recoverable from seed.') + ' ' \
-                                         + _('If you ever need to restore your wallet from its seed, these keys will be lost.') + '\n\n' \
+            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>' \
+                                         + _('In addition, when you send bitcoins from one of your imported addresses, the "change" will be sent to an address derived from your seed, unless you disabled this option.') + '<p>' \
                                          + _('Are you sure you understand what you are doing?'), 3, 4)
             if r == 4: return
 
-        text, ok = QInputDialog.getText(self, _('Import private key'), _('Private Key') + ':')
-        if not ok: return
-        sec = str(text).strip()
-        if self.wallet.use_encryption:
-            password = self.password_dialog()
-            if not password:
-                return
-        else:
-            password = None
-        try:
-            addr = self.wallet.import_key(sec, password)
-            if not addr:
-                QMessageBox.critical(None, _("Unable to import key"), "error")
+        text = text_dialog(self, _('Import private keys'), _("Enter private keys")+':', _("Import"))
+        if not text: return
+
+        text = str(text).split()
+        badkeys = []
+        addrlist = []
+        for key in text:
+            try:
+                addr = self.wallet.import_key(key, password)
+            except BaseException as e:
+                badkeys.append(key)
+                continue
+            if not addr: 
+                badkeys.append(key)
             else:
-                QMessageBox.information(None, _("Key imported"), addr)
-                self.update_receive_tab()
-                self.update_history_tab()
-        except BaseException as e:
-            QMessageBox.critical(None, _("Unable to import key"), str(e))
+                addrlist.append(addr)
+        if addrlist:
+            QMessageBox.information(self, _('Information'), _("The following addresses were added") + ':\n' + '\n'.join(addrlist))
+        if badkeys:
+            QMessageBox.critical(self, _('Error'), _("The following inputs could not be imported") + ':\n'+ '\n'.join(badkeys))
+        self.update_receive_tab()
+        self.update_history_tab()
+
 
     def settings_dialog(self):
         d = QDialog(self)
@@ -1888,6 +1854,7 @@ class ElectrumWindow(QMainWindow):
         vbox = QVBoxLayout()
 
         tabs = QTabWidget(self)
+        self.settings_tab = tabs
         vbox.addWidget(tabs)
 
         tab1 = QWidget()
@@ -1896,18 +1863,18 @@ class ElectrumWindow(QMainWindow):
         tabs.addTab(tab1, _('Display') )
 
         nz_label = QLabel(_('Display zeros'))
-        grid_ui.addWidget(nz_label, 3, 0)
+        grid_ui.addWidget(nz_label, 0, 0)
         nz_e = QLineEdit()
         nz_e.setText("%d"% self.wallet.num_zeros)
-        grid_ui.addWidget(nz_e, 3, 1)
+        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), 3, 2)
+        grid_ui.addWidget(HelpButton(msg), 0, 2)
         nz_e.textChanged.connect(lambda: numbify(nz_e,True))
         if not self.config.is_modifiable('num_zeros'):
             for w in [nz_e, nz_label]: w.setEnabled(False)
         
         lang_label=QLabel(_('Language') + ':')
-        grid_ui.addWidget(lang_label , 8, 0)
+        grid_ui.addWidget(lang_label, 1, 0)
         lang_combo = QComboBox()
         from i18n import languages
         lang_combo.addItems(languages.values())
@@ -1916,8 +1883,8 @@ class ElectrumWindow(QMainWindow):
         except:
             index = 0
         lang_combo.setCurrentIndex(index)
-        grid_ui.addWidget(lang_combo, 8, 1)
-        grid_ui.addWidget(HelpButton(_('Select which language is used in the GUI (after restart).')+' '), 8, 2)
+        grid_ui.addWidget(lang_combo, 1, 1)
+        grid_ui.addWidget(HelpButton(_('Select which language is used in the GUI (after restart).')+' '), 1, 2)
         if not self.config.is_modifiable('language'):
             for w in [lang_combo, lang_label]: w.setEnabled(False)
 
@@ -1925,7 +1892,7 @@ class ElectrumWindow(QMainWindow):
         currencies.insert(0, "None")
 
         cur_label=QLabel(_('Currency') + ':')
-        grid_ui.addWidget(cur_label , 9, 0)
+        grid_ui.addWidget(cur_label , 2, 0)
         cur_combo = QComboBox()
         cur_combo.addItems(currencies)
         try:
@@ -1933,20 +1900,21 @@ class ElectrumWindow(QMainWindow):
         except:
             index = 0
         cur_combo.setCurrentIndex(index)
-        grid_ui.addWidget(cur_combo, 9, 1)
-        grid_ui.addWidget(HelpButton(_('Select which currency is used for quotes.')+' '), 9, 2)
+        grid_ui.addWidget(cur_combo, 2, 1)
+        grid_ui.addWidget(HelpButton(_('Select which currency is used for quotes.')+' '), 2, 2)
         
         view_label=QLabel(_('Receive Tab') + ':')
-        grid_ui.addWidget(view_label , 10, 0)
+        grid_ui.addWidget(view_label , 3, 0)
         view_combo = QComboBox()
         view_combo.addItems([_('Simple'), _('Advanced')])
         view_combo.setCurrentIndex(self.expert_mode)
-        grid_ui.addWidget(view_combo, 10, 1)
+        grid_ui.addWidget(view_combo, 3, 1)
         hh = _('This selects the interaction mode of the "Receive" tab.')+' ' + '\n\n' \
              + _('Simple') +   ': ' + _('Show only addresses and labels.') + '\n\n' \
              + _('Advanced') + ': ' + _('Show address balances and add extra menu items to freeze/prioritize addresses.') + '\n\n' 
         
-        grid_ui.addWidget(HelpButton(hh), 10, 2)
+        grid_ui.addWidget(HelpButton(hh), 3, 2)
+        grid_ui.setRowStretch(4,1)
 
         # wallet tab
         tab2 = QWidget()
@@ -1958,10 +1926,10 @@ class ElectrumWindow(QMainWindow):
         grid_wallet.addWidget(fee_label, 0, 0)
         fee_e = QLineEdit()
         fee_e.setText("%s"% str( Decimal( self.wallet.fee)/100000000 ) )
-        grid_wallet.addWidget(fee_e, 0, 1)
+        grid_wallet.addWidget(fee_e, 0, 2)
         msg = _('Fee per transaction input. Transactions involving multiple inputs tend to require a higher fee.') + ' ' \
             + _('Recommended value') + ': 0.001'
-        grid_wallet.addWidget(HelpButton(msg), 0, 2)
+        grid_wallet.addWidget(HelpButton(msg), 0, 3)
         fee_e.textChanged.connect(lambda: numbify(fee_e,False))
         if not self.config.is_modifiable('fee'):
             for w in [fee_e, fee_label]: w.setEnabled(False)
@@ -1971,15 +1939,15 @@ class ElectrumWindow(QMainWindow):
         usechange_combo = QComboBox()
         usechange_combo.addItems([_('Yes'), _('No')])
         usechange_combo.setCurrentIndex(not self.wallet.use_change)
-        grid_wallet.addWidget(usechange_combo, 1, 1)
-        grid_wallet.addWidget(HelpButton(_('Using change addresses makes it more difficult for other people to track your transactions.')+' '), 1, 2)
+        grid_wallet.addWidget(usechange_combo, 1, 2)
+        grid_wallet.addWidget(HelpButton(_('Using change addresses makes it more difficult for other people to track your transactions.')+' '), 1, 3)
         if not self.config.is_modifiable('use_change'): usechange_combo.setEnabled(False)
 
         gap_label = QLabel(_('Gap limit'))
         grid_wallet.addWidget(gap_label, 2, 0)
         gap_e = QLineEdit()
         gap_e.setText("%d"% self.wallet.gap_limit)
-        grid_wallet.addWidget(gap_e, 2, 1)
+        grid_wallet.addWidget(gap_e, 2, 2)
         msg =  _('The gap limit is the maximal number of contiguous unused addresses in your sequence of receiving addresses.') + '\n' \
               + _('You may increase it if you need more receiving addresses.') + '\n\n' \
               + _('Your current gap limit is') + ': %d'%self.wallet.gap_limit + '\n' \
@@ -1987,7 +1955,7 @@ class ElectrumWindow(QMainWindow):
               + _('Warning') + ': ' \
               + _('The gap limit parameter must be provided in order to recover your wallet from seed.') + ' ' \
               + _('Do not modify it if you do not understand what you are doing, or if you expect to recover your wallet without knowing it!') + '\n\n' 
-        grid_wallet.addWidget(HelpButton(msg), 2, 2)
+        grid_wallet.addWidget(HelpButton(msg), 2, 3)
         gap_e.textChanged.connect(lambda: numbify(nz_e,True))
         if not self.config.is_modifiable('gap_limit'):
             for w in [gap_e, gap_label]: w.setEnabled(False)
@@ -2022,46 +1990,39 @@ class ElectrumWindow(QMainWindow):
                               + _('If you give it to someone, they will be able to see your transactions, but not to spend your money.') + ' ' \
                               + _('If you restore your wallet from it, a watching-only (deseeded) wallet will be created.')), 4, 3)
 
-        grid_io.setRowStretch(4,1)
 
-        tab4 = QWidget()
-        grid_raw = QGridLayout(tab4)
-        grid_raw.setColumnStretch(0,1)
-        tabs.addTab(tab4, _('Raw tx') )  # move this to wallet tab
+        grid_io.addWidget(QLabel(_("Load transaction")), 5, 0)
+        grid_io.addWidget(EnterButton(_("From file"), self.do_process_from_file), 5, 1)
+        grid_io.addWidget(EnterButton(_("From text"), self.do_process_from_text), 5, 2)
+        grid_io.addWidget(HelpButton(_("This will give you the option to sign or broadcast a transaction based on it's status.")), 5, 3)
 
-        if self.wallet.seed:
-            grid_raw.addWidget(QLabel(_("Sign transaction")), 1, 0)
-            grid_raw.addWidget(EnterButton(_("From file"), self.do_sign_from_file),1,1)
-            grid_raw.addWidget(EnterButton(_("From text"), self.do_sign_from_text),1,2)
-            grid_raw.addWidget(HelpButton(_("Sign an unsigned transaction generated by a watching-only wallet")),1,3)
+        grid_io.setRowStretch(5,1)
 
-        grid_raw.addWidget(QLabel(_("Send signed transaction")), 2, 0)
-        grid_raw.addWidget(EnterButton(_("From file"), self.do_send_from_file),2,1)
-        grid_raw.addWidget(EnterButton(_("From text"), self.do_send_from_text),2,2)
-        grid_raw.addWidget(HelpButton(_("This will broadcast a transaction to the network.")),2,3)
-        grid_raw.setRowStretch(3,1)
 
         # plugins
         if self.plugins:
-            tab5 = QWidget()
+            tab5 = QScrollArea()
             grid_plugins = QGridLayout(tab5)
             grid_plugins.setColumnStretch(0,1)
             tabs.addTab(tab5, _('Plugins') )
             def mk_toggle(cb, p):
-                return lambda: cb.setChecked(p.toggle(self))
+                return lambda: cb.setChecked(p.toggle())
             for i, p in enumerate(self.plugins):
                 try:
                     name, description = p.get_info()
                     cb = QCheckBox(name)
+                    cb.setDisabled(not p.is_available())
                     cb.setChecked(p.is_enabled())
-                    cb.stateChanged.connect(mk_toggle(cb,p))
+                    cb.clicked.connect(mk_toggle(cb,p))
                     grid_plugins.addWidget(cb, i, 0)
-                    grid_plugins.addWidget(HelpButton(description), i, 2)
+                    grid_plugins.addWidget(HelpButton(description), i, 1)
                 except:
                     print_msg("Error: cannot display plugin", p)
                     traceback.print_exc(file=sys.stdout)
             grid_plugins.setRowStretch(i+1,1)
 
+        self.run_hook('create_settings_tab', tabs)
+
         vbox.addLayout(ok_cancel_buttons(d))
         d.setLayout(vbox) 
 
@@ -2124,6 +2085,8 @@ class ElectrumWindow(QMainWindow):
             self.config.set_key('currency', cur_request, True)
             self.update_wallet()
 
+        self.run_hook('close_settings_dialog')
+
         if need_restart:
             QMessageBox.warning(self, _('Success'), _('Please restart Electrum to activate the new GUI settings'), _('OK'))
 
@@ -2229,7 +2192,7 @@ class ElectrumWindow(QMainWindow):
             for p in protocol_letters:
                 i = protocol_letters.index(p)
                 j = server_protocol.model().index(i,0)
-                if p not in pp.keys():
+                if p not in pp.keys() and interface.is_connected:
                     server_protocol.model().setData(j, QtCore.QVariant(0), QtCore.Qt.UserRole-1)
                 else:
                     server_protocol.model().setData(j, QtCore.QVariant(0,False), QtCore.Qt.UserRole-1)
@@ -2333,11 +2296,12 @@ class ElectrumGui:
         
 
     def show_seed(self):
-        ElectrumWindow.show_seed_dialog(self.wallet)
+        ElectrumWindow.show_seed(self.wallet.seed)
 
 
     def password_dialog(self):
-        ElectrumWindow.change_password_dialog(self.wallet)
+        if self.wallet.seed:
+            ElectrumWindow.change_password_dialog(self.wallet)
 
 
     def restore_wallet(self):