use named callbacks with the interface
[electrum-nvc.git] / lib / gui_qt.py
index d61e5a8..31542bd 100644 (file)
@@ -23,9 +23,7 @@ from util import print_error
 try:
     import PyQt4
 except:
-    print_error("Error: Could not import PyQt4")
-    print_error("on Linux systems, you may try 'sudo apt-get install python-qt4'")
-    sys.exit(1)
+    sys.exit("Error: Could not import PyQt4 on Linux systems, you may try 'sudo apt-get install python-qt4'")
 
 from PyQt4.QtGui import *
 from PyQt4.QtCore import *
@@ -36,12 +34,10 @@ from interface import DEFAULT_SERVERS
 try:
     import icons_rc
 except:
-    print_error("Error: Could not import icons_rc.py")
-    print_error("Please generate it with: 'pyrcc4 icons.qrc -o lib/icons_rc.py'")
-    sys.exit(1)
+    sys.exit("Error: Could not import icons_rc.py, please generate it with: 'pyrcc4 icons.qrc -o lib/icons_rc.py'")
 
 from wallet import format_satoshis
-import bmp, mnemonic, pyqrnative
+import bmp, mnemonic, pyqrnative, qrscanner
 
 from decimal import Decimal
 
@@ -58,6 +54,7 @@ ALIAS_REGEXP = '^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$'
 
 def numbify(entry, is_int = False):
     text = unicode(entry.text()).strip()
+    pos = entry.cursorPosition()
     chars = '0123456789'
     if not is_int: chars +='.'
     s = ''.join([i for i in text if i in chars])
@@ -76,6 +73,7 @@ def numbify(entry, is_int = False):
         except:
             amount = None
     entry.setText(s)
+    entry.setCursorPosition(pos)
     return amount
 
 
@@ -170,6 +168,26 @@ class QRCodeWidget(QWidget):
         qp.end()
         
 
+def waiting_dialog(f):
+
+    s = Timer()
+    s.start()
+    w = QDialog()
+    w.resize(200, 70)
+    w.setWindowTitle('Electrum')
+    l = QLabel('')
+    vbox = QVBoxLayout()
+    vbox.addWidget(l)
+    w.setLayout(vbox)
+    w.show()
+    def ff():
+        s = f()
+        if s: l.setText(s)
+        else: w.close()
+    w.connect(s, QtCore.SIGNAL('timersignal'), ff)
+    w.exec_()
+    w.destroy()
+
 
 def ok_cancel_buttons(dialog):
     hbox = QHBoxLayout()
@@ -185,10 +203,13 @@ def ok_cancel_buttons(dialog):
 
 class ElectrumWindow(QMainWindow):
 
-    def __init__(self, wallet):
+    def __init__(self, wallet, config):
         QMainWindow.__init__(self)
         self.wallet = wallet
-        self.wallet.register_callback(self.update_callback)
+        self.config = config
+        self.wallet.interface.register_callback('updated', self.update_callback)
+
+        self.detailed_view = config.get('qt_detailed_view', False)
 
         self.funds_error = False
         self.completions = QStringListModel()
@@ -204,8 +225,10 @@ class ElectrumWindow(QMainWindow):
         tabs.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
         self.setCentralWidget(tabs)
         self.create_status_bar()
-        self.setGeometry(100,100,840,400)
-        title = 'Electrum ' + self.wallet.electrum_version + '  -  ' + self.wallet.path
+
+        g = self.config.get("winpos-qt",[100, 100, 840, 400])
+        self.setGeometry(g[0], g[1], g[2], g[3])
+        title = 'Electrum ' + self.wallet.electrum_version + '  -  ' + self.config.path
         if not self.wallet.seed: title += ' [seedless]'
         self.setWindowTitle( title )
 
@@ -291,7 +314,7 @@ class ElectrumWindow(QMainWindow):
         l.setColumnWidth(2, 350) 
         l.setColumnWidth(3, 140) 
         l.setColumnWidth(4, 140) 
-        l.setHeaderLabels( [ '', _( 'Date' ), _( 'Description' ) , _('Amount'), _('Balance')] )
+        l.setHeaderLabels( [ '', _( 'Date' ), _( 'To / From' ) , _('Amount'), _('Balance')] )
         self.connect(l, SIGNAL('itemDoubleClicked(QTreeWidgetItem*, int)'), self.tx_label_clicked)
         self.connect(l, SIGNAL('itemChanged(QTreeWidgetItem*, int)'), self.tx_label_changed)
         l.setContextMenuPolicy(Qt.CustomContextMenu)
@@ -385,19 +408,29 @@ class ElectrumWindow(QMainWindow):
     def address_label_changed(self, item, column, l, column_addr, 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():
-                self.wallet.labels[addr] = text
+                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)
+            if s: 
+                self.wallet.labels.pop(addr)
+                changed = True
+
+        if changed:
+            self.wallet.update_tx_labels()
+            self.update_history_tab()
+            self.update_completions()
 
-        self.update_history_tab()
-        self.update_completions()
 
     def update_history_tab(self):
         self.history_list.clear()
@@ -407,7 +440,10 @@ class ElectrumWindow(QMainWindow):
             if tx['height']:
                 conf = self.wallet.blocks - tx['height'] + 1
                 time_str = datetime.datetime.fromtimestamp( tx['timestamp']).isoformat(' ')[:-3]
-                icon = QIcon(":icons/confirmed.png")
+                if conf < 6:
+                    icon = QIcon(":icons/clock%d.png"%conf)
+                else:
+                    icon = QIcon(":icons/confirmed.png")
             else:
                 conf = 0
                 time_str = 'pending'
@@ -443,6 +479,24 @@ class ElectrumWindow(QMainWindow):
         self.payto_e = QLineEdit()
         grid.addWidget(QLabel(_('Pay to')), 1, 0)
         grid.addWidget(self.payto_e, 1, 1, 1, 3)
+        
+        def fill_from_qr():
+            qrcode = qrscanner.scan_qr()
+            if 'address' in qrcode:
+                self.payto_e.setText(qrcode['address'])
+            if 'amount' in qrcode:
+                self.amount_e.setText(str(qrcode['amount']))
+            if 'label' in qrcode:
+                self.message_e.setText(qrcode['label'])
+            if 'message' in qrcode:
+                self.message_e.setText("%s (%s)" % (self.message_e.text(), qrcode['message']))
+                
+
+        if qrscanner.is_available():
+            b = QPushButton(_("Scan QR code"))
+            b.clicked.connect(fill_from_qr)
+            grid.addWidget(b, 1, 5)
+    
         grid.addWidget(HelpButton(_('Recipient of the funds.') + '\n\n' + _('You may enter a Bitcoin address, a label from your list of contacts (a list of completions will be proposed), or an alias (email-like address that forwards to a Bitcoin address)')), 1, 4)
 
         completer = QCompleter()
@@ -574,7 +628,10 @@ class ElectrumWindow(QMainWindow):
             self.show_message(str(e))
             return
             
-        status, msg = self.wallet.sendtx( tx )
+        h = self.wallet.send_tx(tx)
+        waiting_dialog(lambda: False if self.wallet.tx_event.isSet() else _("Please wait..."))
+        status, msg = self.wallet.receive_tx( h )
+
         if status:
             QMessageBox.information(self, '', _('Payment sent.')+'\n'+msg, _('OK'))
             self.do_clear()
@@ -670,8 +727,23 @@ class ElectrumWindow(QMainWindow):
         self.connect(l, SIGNAL('itemChanged(QTreeWidgetItem*, int)'), lambda a,b: self.address_label_changed(a,b,l,1,2))
         self.receive_list = l
         self.receive_buttons_hbox = hbox
+        self.details_button = EnterButton(self.details_button_text(), self.toggle_detailed_view)
+        hbox.addWidget(self.details_button)
+        hbox.addStretch(1)
         return w
 
+    def details_button_text(self):
+        return _('Hide details') if self.detailed_view else _('Show details')
+
+    def toggle_detailed_view(self):
+        self.detailed_view = not self.detailed_view
+        self.config.set_key('qt_detailed_view', self.detailed_view, True)
+
+        self.details_button.setText(self.details_button_text())
+        self.wallet.save()
+        self.update_receive_tab()
+        self.update_contacts_tab()
+
 
     def create_contacts_tab(self):
         l,w,hbox = self.create_list_tab([_('Address'), _('Label'), _('Tx')])
@@ -698,11 +770,11 @@ class ElectrumWindow(QMainWindow):
         menu.addAction(_("Copy to Clipboard"), lambda: self.app.clipboard().setText(addr))
         menu.addAction(_("View QR code"),lambda: self.show_address_qrcode(addr))
         menu.addAction(_("Edit label"), lambda: self.edit_label(True))
-        if self.wallet.expert_mode:
-            t = _("Unfreeze") if addr in self.wallet.frozen_addresses else _("Freeze")
-            menu.addAction(t, lambda: self.toggle_freeze(addr))
-            t = _("Unprioritize") if addr in self.wallet.prioritized_addresses else _("Prioritize")
-            menu.addAction(t, lambda: self.toggle_priority(addr))
+
+        t = _("Unfreeze") if addr in self.wallet.frozen_addresses else _("Freeze")
+        menu.addAction(t, lambda: self.toggle_freeze(addr))
+        t = _("Unprioritize") if addr in self.wallet.prioritized_addresses else _("Prioritize")
+        menu.addAction(t, lambda: self.toggle_priority(addr))
         menu.exec_(self.receive_list.viewport().mapToGlobal(position))
 
 
@@ -757,9 +829,9 @@ class ElectrumWindow(QMainWindow):
     def update_receive_tab(self):
         l = self.receive_list
         l.clear()
-        l.setColumnHidden(0,not self.wallet.expert_mode)
-        l.setColumnHidden(3,not self.wallet.expert_mode)
-        l.setColumnHidden(4,not self.wallet.expert_mode)
+        l.setColumnHidden(0,not self.detailed_view)
+        l.setColumnHidden(3,not self.detailed_view)
+        l.setColumnHidden(4,not self.detailed_view)
         l.setColumnWidth(0, 50) 
         l.setColumnWidth(1, 310) 
         l.setColumnWidth(2, 250)
@@ -770,7 +842,7 @@ class ElectrumWindow(QMainWindow):
         is_red = False
         for address in self.wallet.all_addresses():
 
-            if self.wallet.is_change(address) and not self.wallet.expert_mode:
+            if self.wallet.is_change(address) and not self.detailed_view:
                 continue
 
             label = self.wallet.labels.get(address,'')
@@ -822,7 +894,7 @@ class ElectrumWindow(QMainWindow):
 
         l = self.contacts_list
         l.clear()
-        l.setColumnHidden(2, not self.wallet.expert_mode)
+        l.setColumnHidden(2, not self.detailed_view)
         l.setColumnWidth(0, 350) 
         l.setColumnWidth(1, 330)
         l.setColumnWidth(2, 100) 
@@ -881,66 +953,68 @@ class ElectrumWindow(QMainWindow):
 
     @staticmethod
     def show_seed_dialog(wallet, parent=None):
-
         if not wallet.seed:
-            QMessageBox.information(parent, _('Message'), _('No seed'), _('OK'))
+            QMessageBox.information(parent, _('Message'),
+                                    _('No seed'), _('OK'))
             return
 
         if wallet.use_encryption:
             password = parent.password_dialog()
-            if not password: return
+            if not password:
+                return
         else:
             password = None
             
         try:
-            seed = wallet.pw_decode( wallet.seed, password)
+            seed = wallet.pw_decode(wallet.seed, password)
         except:
-            QMessageBox.warning(parent, _('Error'), _('Incorrect Password'), _('OK'))
+            QMessageBox.warning(parent, _('Error'),
+                                _('Incorrect Password'), _('OK'))
             return
 
-        msg = _("Your wallet generation seed is") + ":\n\n" + seed + "\n\n"\
-              + _("Please keep it in a safe place; if you lose it, you will not be able to restore your wallet.") + "\n\n" \
-              + _("Equivalently, your wallet seed can be stored and recovered with the following mnemonic code") + ":\n\n\"" \
-              + ' '.join(mnemonic.mn_encode(seed)) + "\"\n\n\n"
+        dialog = QDialog(None)
+        dialog.setModal(1)
+        dialog.setWindowTitle(_("Seed"))
 
-        d = QDialog(None)
-        d.setModal(1)
-        d.setWindowTitle(_("Seed"))
-        d.setMinimumSize(400, 270)
+        brainwallet = ' '.join(mnemonic.mn_encode(seed))
 
-        vbox = QVBoxLayout()
-        hbox = QHBoxLayout()
-        vbox2 = QVBoxLayout()
-        l = QLabel()
-        l.setPixmap(QPixmap(":icons/seed.png").scaledToWidth(56))
-        vbox2.addWidget(l)
-        vbox2.addStretch(1)
-        hbox.addLayout(vbox2)
-        hbox.addWidget(QLabel(msg))
-        vbox.addLayout(hbox)
+        msg =   _("Your wallet generation seed is") +":<p>\"" + brainwallet + "\"<p>" \
+              + _("Please write down or memorize these 12 words (order is important).") + " " \
+              + _("This seed will allow you to recover your wallet in case of computer failure.") + "<p>" \
+              + _("WARNING: Never disclose your seed. Never type it on a website.") + "<p>"
 
-        hbox = QHBoxLayout()
-        hbox.addStretch(1)
+        main_text = QLabel(msg)
+        main_text.setWordWrap(True)
 
+        logo = QLabel()
+        logo.setPixmap(QPixmap(":icons/seed.png").scaledToWidth(56))
 
         if parent:
             app = parent.app
         else:
             app = QApplication
 
-        b = QPushButton(_("Copy to Clipboard"))
-        b.clicked.connect(lambda: app.clipboard().setText(seed + ' "' + ' '.join(mnemonic.mn_encode(seed))+'"'))
-        hbox.addWidget(b)
-        b = QPushButton(_("View as QR Code"))
-        b.clicked.connect(lambda: ElectrumWindow.show_seed_qrcode(seed))
-        hbox.addWidget(b)
+        copy_function = lambda: app.clipboard().setText(brainwallet)
+        copy_button = QPushButton(_("Copy to Clipboard"))
+        copy_button.clicked.connect(copy_function)
 
-        b = QPushButton(_("OK"))
-        b.clicked.connect(d.accept)
-        hbox.addWidget(b)
-        vbox.addLayout(hbox)
-        d.setLayout(vbox)
-        d.exec_()
+        show_qr_function = lambda: ElectrumWindow.show_seed_qrcode(seed)
+        qr_button = QPushButton(_("View as QR Code"))
+        qr_button.clicked.connect(show_qr_function)
+
+        ok_button = QPushButton(_("OK"))
+        ok_button.setDefault(True)
+        ok_button.clicked.connect(dialog.accept)
+
+        main_layout = QGridLayout()
+        main_layout.addWidget(logo, 0, 0)
+        main_layout.addWidget(main_text, 0, 1, 1, -1)
+        main_layout.addWidget(copy_button, 1, 1)
+        main_layout.addWidget(qr_button, 1, 2)
+        main_layout.addWidget(ok_button, 1, 3)
+        dialog.setLayout(main_layout)
+
+        dialog.exec_()
 
     @staticmethod
     def show_seed_qrcode(seed):
@@ -1158,14 +1232,6 @@ class ElectrumWindow(QMainWindow):
         return True
 
 
-    def set_expert_mode(self, b):
-        self.wallet.expert_mode = b
-        self.wallet.save()
-        self.update_receive_tab()
-        self.update_contacts_tab()
-        # if self.wallet.seed:
-        # self.nochange_cb.setHidden(not self.wallet.expert_mode)
-        
 
     def settings_dialog(self):
         d = QDialog(self)
@@ -1184,49 +1250,62 @@ class ElectrumWindow(QMainWindow):
         grid.setSpacing(8)
         vbox.addLayout(grid)
 
+        fee_label = QLabel(_('Transaction fee'))
+        grid.addWidget(fee_label, 2, 0)
         fee_e = QLineEdit()
         fee_e.setText("%s"% str( Decimal( self.wallet.fee)/100000000 ) )
-        grid.addWidget(QLabel(_('Transaction fee')), 2, 0)
         grid.addWidget(fee_e, 2, 1)
         msg = _('Fee per transaction input. Transactions involving multiple inputs tend to require a higher fee.') + ' ' \
             + _('Recommended value') + ': 0.001'
         grid.addWidget(HelpButton(msg), 2, 2)
         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)
 
+        nz_label = QLabel(_('Display zeros'))
+        grid.addWidget(nz_label, 3, 0)
         nz_e = QLineEdit()
         nz_e.setText("%d"% self.wallet.num_zeros)
-        grid.addWidget(QLabel(_('Display zeros')), 3, 0)
+        grid.addWidget(nz_e, 3, 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.addWidget(HelpButton(msg), 3, 2)
-        grid.addWidget(nz_e, 3, 1)
         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)
 
-        cb = QCheckBox(_('Expert mode'))
-        grid.addWidget(cb, 4, 0)
-        cb.setChecked(self.wallet.expert_mode)
-
-        if self.wallet.expert_mode:
-
-            usechange_cb = QCheckBox(_('Use change addresses'))
-            grid.addWidget(usechange_cb, 5, 0)
-            usechange_cb.setChecked(self.wallet.use_change)
-            grid.addWidget(HelpButton(_('Using a change addresses makes it more difficult for other people to track your transactions. ')), 5, 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' \
-                  + _('Given the current status of your address sequence, the minimum gap limit you can use is: ') + '%d'%self.wallet.min_acceptable_gap() + '\n\n' \
-                  + _('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' 
-            gap_e = QLineEdit()
-            gap_e.setText("%d"% self.wallet.gap_limit)
-            grid.addWidget(QLabel(_('Gap limit')), 6, 0)
-            grid.addWidget(gap_e, 6, 1)
-            grid.addWidget(HelpButton(msg), 6, 2)
-            gap_e.textChanged.connect(lambda: numbify(nz_e,True))
+        usechange_cb = QCheckBox(_('Use change addresses'))
+        grid.addWidget(usechange_cb, 5, 0)
+        usechange_cb.setChecked(self.wallet.use_change)
+        grid.addWidget(HelpButton(_('Using change addresses makes it more difficult for other people to track your transactions. ')), 5, 2)
+        if not self.config.is_modifiable('use_change'): usechange_cb.setEnabled(False)
 
+        gap_label = QLabel(_('Gap limit'))
+        grid.addWidget(gap_label, 6, 0)
+        gap_e = QLineEdit()
+        gap_e.setText("%d"% self.wallet.gap_limit)
+        grid.addWidget(gap_e, 6, 1)
+        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' \
+              + _('Given the current status of your address sequence, the minimum gap limit you can use is: ') + '%d'%self.wallet.min_acceptable_gap() + '\n\n' \
+              + _('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.addWidget(HelpButton(msg), 6, 2)
+        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)
         
+        gui_label=QLabel(_('Default GUI') + ':')
+        grid.addWidget(gui_label , 7, 0)
+        gui_combo = QComboBox()
+        gui_combo.addItems(['Lite', 'Classic', 'Gtk', 'Text'])
+        gui_combo.setCurrentIndex(gui_combo.findText(self.config.get("gui","classic").capitalize()))
+        grid.addWidget(gui_combo, 7, 1)
+        grid.addWidget(HelpButton(_('Select which GUI mode to use at start up. ')), 7, 2)
+        if not self.config.is_modifiable('gui'):
+            for w in [gui_combo, gui_label]: w.setEnabled(False)
+
         vbox.addLayout(ok_cancel_buttons(d))
         d.setLayout(vbox) 
 
@@ -1254,27 +1333,30 @@ class ElectrumWindow(QMainWindow):
 
         if self.wallet.num_zeros != nz:
             self.wallet.num_zeros = nz
+            self.config.set_key('num_zeros', nz, True)
             self.update_history_tab()
             self.update_receive_tab()
-            self.wallet.save()
-
-        if self.wallet.expert_mode:
 
+        if self.wallet.use_change != usechange_cb.isChecked():
             self.wallet.use_change = usechange_cb.isChecked()
+            self.config.set_key('use_change', self.wallet.use_change, True)
+        
+        try:
+            n = int(gap_e.text())
+        except:
+            QMessageBox.warning(self, _('Error'), _('Invalid value'), _('OK'))
+            return
 
-            try:
-                n = int(gap_e.text())
-            except:
+        if self.wallet.gap_limit != n:
+            r = self.wallet.change_gap_limit(n)
+            if r:
+                self.update_receive_tab()
+                self.config.set_key('gap_limit', self.wallet.gap_limit, True)
+            else:
                 QMessageBox.warning(self, _('Error'), _('Invalid value'), _('OK'))
-                return
-            if self.wallet.gap_limit != n:
-                r = self.wallet.change_gap_limit(n)
-                if r:
-                    self.update_receive_tab()
-                else:
-                    QMessageBox.warning(self, _('Error'), _('Invalid value'), _('OK'))
+                    
+        self.config.set_key("gui", str(gui_combo.currentText()).lower(), True)
 
-        self.set_expert_mode(cb.isChecked())
 
 
     @staticmethod 
@@ -1282,14 +1364,14 @@ class ElectrumWindow(QMainWindow):
         interface = wallet.interface
         if parent:
             if interface.is_connected:
-                status = _("Connected to")+" %s:%d\n%d blocks"%(interface.host, interface.port, wallet.blocks)
+                status = _("Connected to")+" %s\n%d blocks"%(interface.host, wallet.blocks)
             else:
                 status = _("Not connected")
-            server = wallet.server
         else:
             import random
             status = _("Please choose a server.")
-            server = random.choice( DEFAULT_SERVERS )
+
+        server = interface.server
 
         if not wallet.interface.servers:
             servers_list = []
@@ -1301,12 +1383,12 @@ class ElectrumWindow(QMainWindow):
             
         plist = {}
         for item in servers_list:
-            host, pp = item
+            _host, pp = item
             z = {}
             for item2 in pp:
-                protocol, port = item2
-                z[protocol] = port
-            plist[host] = z
+                _protocol, _port = item2
+                z[_protocol] = _port
+            plist[_host] = z
 
         d = QDialog(parent)
         d.setModal(1)
@@ -1314,132 +1396,166 @@ class ElectrumWindow(QMainWindow):
         d.setMinimumSize(375, 20)
 
         vbox = QVBoxLayout()
-        vbox.setSpacing(20)
+        vbox.setSpacing(30)
 
         hbox = QHBoxLayout()
         l = QLabel()
         l.setPixmap(QPixmap(":icons/network.png"))
+        hbox.addStretch(10)
         hbox.addWidget(l)        
         hbox.addWidget(QLabel(status))
-
+        hbox.addStretch(50)
         vbox.addLayout(hbox)
 
-        hbox = QHBoxLayout()
-        host_line = QLineEdit()
-        host_line.setText(server)
-        hbox.addWidget(QLabel(_('Connect to') + ':'))
-        hbox.addWidget(host_line)
-        vbox.addLayout(hbox)
 
-        hbox = QHBoxLayout()
+        # grid layout
+        grid = QGridLayout()
+        grid.setSpacing(8)
+        vbox.addLayout(grid)
 
-        buttonGroup = QGroupBox(_("Protocol"))
-        radio1 = QRadioButton("tcp", buttonGroup)
-        radio2 = QRadioButton("http", buttonGroup)
+        # server
+        server_protocol = QComboBox()
+        server_host = QLineEdit()
+        server_host.setFixedWidth(200)
+        server_port = QLineEdit()
+        server_port.setFixedWidth(60)
 
-        def current_line():
-            return unicode(host_line.text()).split(':')
-            
-        def set_button(protocol):
-            if protocol == 't':
-                radio1.setChecked(1)
-            elif protocol == 'h':
-                radio2.setChecked(1)
-
-        def set_protocol(protocol):
-            host = current_line()[0]
+        protocol_names = ['TCP', 'HTTP', 'TCP/SSL', 'HTTPS']
+        protocol_letters = 'thsg'
+        server_protocol.addItems(protocol_names)
+
+        grid.addWidget(QLabel(_('Server') + ':'), 0, 0)
+        grid.addWidget(server_protocol, 0, 1)
+        grid.addWidget(server_host, 0, 2)
+        grid.addWidget(server_port, 0, 3)
+
+        host, port, protocol = server.split(':')
+
+        def change_protocol(p):
+            protocol = protocol_letters[p]
+            host = unicode(server_host.text())
             pp = plist[host]
             if protocol not in pp.keys():
                 protocol = pp.keys()[0]
-                set_button(protocol)
             port = pp[protocol]
-            host_line.setText( host + ':' + port + ':' + protocol)
-
-        radio1.clicked.connect(lambda x: set_protocol('t') )
-        radio2.clicked.connect(lambda x: set_protocol('h') )
-
-        set_button(current_line()[2])
+            server_host.setText( host )
+            server_port.setText( port )
 
-        hbox.addWidget(QLabel(_('Protocol')+':'))
-        hbox.addWidget(radio1)
-        hbox.addWidget(radio2)
-
-        vbox.addLayout(hbox)
-
-        if wallet.interface.servers:
-            label = _('Active Servers')
-        else:
-            label = _('Default Servers')
+        server_protocol.connect(server_protocol, SIGNAL('currentIndexChanged(int)'), change_protocol)
         
+        label = _('Active Servers') if wallet.interface.servers else _('Default Servers')
         servers_list_widget = QTreeWidget(parent)
         servers_list_widget.setHeaderLabels( [ label ] )
         servers_list_widget.setMaximumHeight(150)
-        for host in plist.keys():
-            servers_list_widget.addTopLevelItem(QTreeWidgetItem( [ host ] ))
+        for _host in plist.keys():
+            servers_list_widget.addTopLevelItem(QTreeWidgetItem( [ _host ] ))
+
+
+        def change_server(host, protocol=None):
+            pp = plist.get(host,{})
+            if protocol:
+                port = pp.get(protocol)
+                if not port: protocol = None
+                    
+            if not protocol:
+                if not pp:
+                    protocol = 't'
+                    port = '50001'
+                elif 't' in pp.keys():
+                    protocol = 't'
+                    port = pp.get(protocol)
+                else:
+                    protocol = pp.keys()[0]
+                    port = pp.get(protocol)
 
-        def do_set_line(x):
-            host = unicode(x.text(0))
-            pp = plist[host]
-            if 't' in pp.keys():
-                protocol = 't'
+            
+            server_host.setText( host )
+            server_port.setText( port )
+            server_protocol.setCurrentIndex(protocol_letters.index(protocol))
+
+            for p in protocol_letters:
+                i = protocol_letters.index(p)
+                j = server_protocol.model().index(i,0)
+                if p not in pp.keys():
+                    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)
+
+        change_server(host,protocol)
+
+
+        servers_list_widget.connect(servers_list_widget, SIGNAL('itemClicked(QTreeWidgetItem*, int)'), lambda x: change_server(unicode(x.text(0))))
+        grid.addWidget(servers_list_widget, 1, 1, 1, 3)
+
+        if not wallet.config.is_modifiable('server'):
+            for w in [server_host, server_port, server_protocol, servers_list_widget]: w.setEnabled(False)
+
+        # proxy setting
+        proxy_mode = QComboBox()
+        proxy_host = QLineEdit()
+        proxy_host.setFixedWidth(200)
+        proxy_port = QLineEdit()
+        proxy_port.setFixedWidth(60)
+        proxy_mode.addItems(['NONE', 'SOCKS4', 'SOCKS5', 'HTTP'])
+
+        def check_for_disable(index = False):
+            if proxy_mode.currentText() != 'NONE':
+                proxy_host.setEnabled(True)
+                proxy_port.setEnabled(True)
             else:
-                protocol = pp.keys()[0]
-            port = pp[protocol]
-            host_line.setText( host + ':' + port + ':' + protocol)
-            set_button(protocol)
+                proxy_host.setEnabled(False)
+                proxy_port.setEnabled(False)
+
+        check_for_disable()
+        proxy_mode.connect(proxy_mode, SIGNAL('currentIndexChanged(int)'), check_for_disable)
+
+        if not wallet.config.is_modifiable('proxy'):
+            for w in [proxy_host, proxy_port, proxy_mode]: w.setEnabled(False)
 
-        servers_list_widget.connect(servers_list_widget, SIGNAL('itemClicked(QTreeWidgetItem*, int)'), do_set_line)
-        vbox.addWidget(servers_list_widget)
+        proxy_config = interface.proxy if interface.proxy else { "mode":"none", "host":"localhost", "port":"8080"}
+        proxy_mode.setCurrentIndex(proxy_mode.findText(str(proxy_config.get("mode").upper())))
+        proxy_host.setText(proxy_config.get("host"))
+        proxy_port.setText(proxy_config.get("port"))
 
+        grid.addWidget(QLabel(_('Proxy') + ':'), 2, 0)
+        grid.addWidget(proxy_mode, 2, 1)
+        grid.addWidget(proxy_host, 2, 2)
+        grid.addWidget(proxy_port, 2, 3)
+
+        # buttons
         vbox.addLayout(ok_cancel_buttons(d))
         d.setLayout(vbox) 
 
         if not d.exec_(): return
-        server = unicode( host_line.text() )
 
-        try:
-            wallet.set_server(server)
-        except:
-            QMessageBox.information(None, _('Error'), 'error', _('OK'))
-            if parent == None:
-                sys.exit(1)
-            else:
-                return
+        server = unicode( server_host.text() ) + ':' + unicode( server_port.text() ) + ':' + (protocol_letters[server_protocol.currentIndex()])
+        if proxy_mode.currentText() != 'NONE':
+            proxy = { u'mode':unicode(proxy_mode.currentText()).lower(), u'host':unicode(proxy_host.text()), u'port':unicode(proxy_port.text()) }
+        else:
+            proxy = None
 
+        wallet.config.set_key("proxy", proxy, True)
+        wallet.config.set_key("server", server, True)
+        interface.set_server(server, proxy)
+                
         return True
 
+    def closeEvent(self, event):
+        g = self.geometry()
+        self.config.set_key("winpos-qt", [g.left(),g.top(),g.width(),g.height()], True)
+        event.accept()
 
 
 class ElectrumGui:
 
-    def __init__(self, wallet, app=None):
+    def __init__(self, wallet, config, app=None):
         self.wallet = wallet
+        self.config = config
         if app is None:
             self.app = QApplication(sys.argv)
 
-    def waiting_dialog(self):
-
-        s = Timer()
-        s.start()
-        w = QDialog()
-        w.resize(200, 70)
-        w.setWindowTitle('Electrum')
-        l = QLabel('')
-        vbox = QVBoxLayout()
-        vbox.addWidget(l)
-        w.setLayout(vbox)
-        w.show()
-        def f():
-            if self.wallet.up_to_date: 
-                w.close()
-            else:
-                l.setText("Please wait...\nAddresses generated: %d\nKilobytes received: %.1f"\
-                              %(len(self.wallet.all_addresses()), self.wallet.interface.bytes_received/1024.))
-
-        w.connect(s, QtCore.SIGNAL('timersignal'), f)
-        self.wallet.interface.poke()
-        w.exec_()
-        w.destroy()
+    def server_list_changed(self):
+        pass
 
 
     def restore_or_create(self):
@@ -1453,12 +1569,16 @@ class ElectrumGui:
         # ask for the server.
         if not ElectrumWindow.network_dialog( wallet, parent=None ): return False
 
+        waiting = lambda: False if wallet.up_to_date else "Please wait...\nAddresses generated: %d\nKilobytes received: %.1f"\
+            %(len(wallet.all_addresses()), wallet.interface.bytes_received/1024.)
+
         if not is_recovery:
             wallet.new_seed(None)
             wallet.init_mpk( wallet.seed )
             wallet.up_to_date_event.clear()
             wallet.up_to_date = False
-            self.waiting_dialog()
+            wallet.interface.poke('synchronizer')
+            waiting_dialog(waiting)
             # run a dialog indicating the seed, ask the user to remember it
             ElectrumWindow.show_seed_dialog(wallet)
             #ask for password
@@ -1469,7 +1589,8 @@ class ElectrumGui:
             wallet.init_mpk( wallet.seed )
             wallet.up_to_date_event.clear()
             wallet.up_to_date = False
-            self.waiting_dialog()
+            wallet.interface.poke('synchronizer')
+            waiting_dialog(waiting)
             if wallet.is_found():
                 # history and addressbook
                 wallet.update_tx_history()
@@ -1485,7 +1606,7 @@ class ElectrumGui:
     def main(self,url):
         s = Timer()
         s.start()
-        w = ElectrumWindow(self.wallet)
+        w = ElectrumWindow(self.wallet, self.config)
         if url: w.set_url(url)
         w.app = self.app
         w.connect_slots(s)