don't set column width in update, but only in create
[electrum-nvc.git] / gui / qt / main_window.py
index 486dca5..174fbdf 100644 (file)
@@ -41,10 +41,12 @@ from electrum import mnemonic
 from electrum import util, bitcoin, commands, Interface, Wallet
 from electrum import SimpleConfig, Wallet, WalletStorage
 
+from electrum.paymentrequest import PR_UNPAID, PR_PAID
+
 
 from electrum import bmp, pyqrnative
 
-from amountedit import AmountEdit
+from amountedit import AmountEdit, BTCAmountEdit, MyLineEdit
 from network_dialog import NetworkDialog
 from qrcodewidget import QRCodeWidget
 
@@ -69,8 +71,11 @@ import re
 from util import *
 
 
-
-
+def format_status(x):
+    if x == PR_UNPAID:
+        return _('Unpaid')
+    elif x == PR_PAID:
+        return _('Paid')
 
 
 class StatusBarButton(QPushButton):
@@ -117,6 +122,7 @@ class ElectrumWindow(QMainWindow):
 
         self.decimal_point = config.get('decimal_point', 5)
         self.num_zeros     = int(config.get('num_zeros',0))
+        self.invoices      = {}
 
         set_language(config.get('language'))
 
@@ -129,6 +135,7 @@ class ElectrumWindow(QMainWindow):
         tabs.addTab(self.create_send_tab(), _('Send') )
         tabs.addTab(self.create_receive_tab(), _('Receive') )
         tabs.addTab(self.create_contacts_tab(), _('Contacts') )
+        tabs.addTab(self.create_invoices_tab(), _('Invoices') )
         tabs.addTab(self.create_console_tab(), _('Console') )
         tabs.setMinimumSize(600, 400)
         tabs.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
@@ -191,6 +198,7 @@ class ElectrumWindow(QMainWindow):
         self.wallet = wallet
         self.update_wallet_format()
 
+        self.invoices = self.wallet.storage.get('invoices', {})
         self.accounts_expanded = self.wallet.storage.get('accounts_expanded',{})
         self.current_account = self.wallet.storage.get("current_account", None)
         title = 'Electrum ' + self.wallet.electrum_version + '  -  ' + self.wallet.storage.path
@@ -322,7 +330,7 @@ class ElectrumWindow(QMainWindow):
         tools_menu.addAction(_("&Plugins"), self.plugins_dialog)
         tools_menu.addSeparator()
         tools_menu.addAction(_("&Sign/verify message"), self.sign_verify_message)
-        #tools_menu.addAction(_("&Encrypt/decrypt message"), self.encrypt_message)
+        tools_menu.addAction(_("&Encrypt/decrypt message"), self.encrypt_message)
         tools_menu.addSeparator()
 
         csv_transaction_menu = tools_menu.addMenu(_("&Create transaction"))
@@ -333,6 +341,7 @@ class ElectrumWindow(QMainWindow):
         raw_transaction_menu.addAction(_("&From file"), self.do_process_from_file)
         raw_transaction_menu.addAction(_("&From text"), self.do_process_from_text)
         raw_transaction_menu.addAction(_("&From the blockchain"), self.do_process_from_txid)
+        self.raw_transaction_menu = raw_transaction_menu
 
         help_menu = menubar.addMenu(_("&Help"))
         help_menu.addAction(_("&About"), self.show_about)
@@ -468,6 +477,7 @@ class ElectrumWindow(QMainWindow):
             self.update_receive_tab()
             self.update_contacts_tab()
             self.update_completions()
+            self.update_invoices_tab()
 
 
     def create_history_tab(self):
@@ -637,14 +647,14 @@ class ElectrumWindow(QMainWindow):
     def create_send_tab(self):
         w = QWidget()
 
-        grid = QGridLayout(w)
+        self.send_grid = grid = QGridLayout(w)
         grid.setSpacing(8)
         grid.setColumnMinimumWidth(3,300)
         grid.setColumnStretch(5,1)
         grid.setRowStretch(8, 1)
 
         from paytoedit import PayToEdit
-        self.amount_e = AmountEdit(self.get_decimal_point)
+        self.amount_e = BTCAmountEdit(self.get_decimal_point)
         self.payto_e = PayToEdit(self.amount_e)
         self.payto_help = 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)'))
         grid.addWidget(QLabel(_('Pay to')), 1, 0)
@@ -656,7 +666,7 @@ class ElectrumWindow(QMainWindow):
         self.payto_e.setCompleter(completer)
         completer.setModel(self.completions)
 
-        self.message_e = QLineEdit()
+        self.message_e = MyLineEdit()
         self.message_help = HelpButton(_('Description of the transaction (not mandatory).') + '\n\n' + _('The description is not sent to the recipient of the funds. It is stored in your wallet file, and displayed in the \'History\' tab.'))
         grid.addWidget(QLabel(_('Description')), 2, 0)
         grid.addWidget(self.message_e, 2, 1, 1, 3)
@@ -664,12 +674,14 @@ class ElectrumWindow(QMainWindow):
 
         self.from_label = QLabel(_('From'))
         grid.addWidget(self.from_label, 3, 0)
-        self.from_list = QTreeWidget(self)
+        self.from_list = MyTreeWidget(self)
         self.from_list.setColumnCount(2)
         self.from_list.setColumnWidth(0, 350)
         self.from_list.setColumnWidth(1, 50)
-        self.from_list.setHeaderHidden (True)
+        self.from_list.setHeaderHidden(True)
         self.from_list.setMaximumHeight(80)
+        self.from_list.setContextMenuPolicy(Qt.CustomContextMenu)
+        self.from_list.customContextMenuRequested.connect(self.from_list_menu)
         grid.addWidget(self.from_list, 3, 1, 1, 3)
         self.set_pay_from([])
 
@@ -680,7 +692,7 @@ class ElectrumWindow(QMainWindow):
         grid.addWidget(self.amount_e, 4, 1, 1, 2)
         grid.addWidget(self.amount_help, 4, 3)
 
-        self.fee_e = AmountEdit(self.get_decimal_point)
+        self.fee_e = BTCAmountEdit(self.get_decimal_point)
         grid.addWidget(QLabel(_('Fee')), 5, 0)
         grid.addWidget(self.fee_e, 5, 1, 1, 2)
         grid.addWidget(HelpButton(
@@ -688,8 +700,6 @@ class ElectrumWindow(QMainWindow):
                     + _('The amount of fee can be decided freely by the sender. However, transactions with low fees take more time to be processed.') + '\n\n'\
                     + _('A suggested fee is automatically added to this field. You may override it. The suggested fee increases with the size of the transaction.')), 5, 3)
 
-        run_hook('exchange_rate_button', grid)
-
         self.send_button = EnterButton(_("Send"), self.do_send)
         grid.addWidget(self.send_button, 6, 1)
 
@@ -699,8 +709,8 @@ class ElectrumWindow(QMainWindow):
         self.payto_sig = QLabel('')
         grid.addWidget(self.payto_sig, 7, 0, 1, 4)
 
-        QShortcut(QKeySequence("Up"), w, w.focusPreviousChild)
-        QShortcut(QKeySequence("Down"), w, w.focusNextChild)
+        #QShortcut(QKeySequence("Up"), w, w.focusPreviousChild)
+        #QShortcut(QKeySequence("Down"), w, w.focusNextChild)
         w.setLayout(grid)
 
         def entry_changed( is_fee ):
@@ -710,11 +720,11 @@ class ElectrumWindow(QMainWindow):
                 self.amount_e.is_shortcut = False
                 sendable = self.get_sendable_balance()
                 # there is only one output because we are completely spending inputs
-                inputs, total, fee = self.wallet.choose_tx_inputs( sendable, 0, 1, self.get_payment_sources())
+                inputs, total, fee = self.wallet.choose_tx_inputs( sendable, 0, 1, coins = self.get_coins())
                 fee = self.wallet.estimated_fee(inputs, 1)
                 amount = total - fee
-                self.amount_e.setText( self.format_amount(amount) )
-                self.fee_e.setText( self.format_amount( fee ) )
+                self.amount_e.setAmount(amount)
+                self.fee_e.setAmount(fee)
                 return
 
             amount = self.amount_e.get_amount()
@@ -724,9 +734,9 @@ class ElectrumWindow(QMainWindow):
             if amount is None:
                 return
             # assume that there will be 2 outputs (one for change)
-            inputs, total, fee = self.wallet.choose_tx_inputs(amount, fee, 2, self.get_payment_sources())
+            inputs, total, fee = self.wallet.choose_tx_inputs(amount, fee, 2, coins = self.get_coins())
             if not is_fee:
-                self.fee_e.setText( self.format_amount( fee ) )
+                self.fee_e.setAmount(fee)
             if inputs:
                 palette = QPalette()
                 palette.setColor(self.amount_e.foregroundRole(), QColor('black'))
@@ -749,17 +759,32 @@ class ElectrumWindow(QMainWindow):
         run_hook('create_send_tab', grid)
         return w
 
+    def from_list_delete(self, item):
+        i = self.from_list.indexOfTopLevelItem(item)
+        self.pay_from.pop(i)
+        self.redraw_from_list()
 
-    def set_pay_from(self, l):
-        self.pay_from = l
+    def from_list_menu(self, position):
+        item = self.from_list.itemAt(position)
+        menu = QMenu()
+        menu.addAction(_("Remove"), lambda: self.from_list_delete(item))
+        menu.exec_(self.from_list.viewport().mapToGlobal(position))
+
+    def set_pay_from(self, domain = None):
+        self.pay_from = [] if domain == [] else self.wallet.get_unspent_coins(domain)
+        self.redraw_from_list()
+
+    def redraw_from_list(self):
         self.from_list.clear()
         self.from_label.setHidden(len(self.pay_from) == 0)
         self.from_list.setHidden(len(self.pay_from) == 0)
-        for addr in self.pay_from:
-            c, u = self.wallet.get_addr_balance(addr)
-            balance = self.format_amount(c + u)
-            self.from_list.addTopLevelItem(QTreeWidgetItem( [addr, balance] ))
 
+        def format(x):
+            h = x.get('prevout_hash')
+            return h[0:8] + '...' + h[-8:] + ":%d"%x.get('prevout_n') + u'\t' + "%s"%x.get('address')
+
+        for item in self.pay_from:
+            self.from_list.addTopLevelItem(QTreeWidgetItem( [format(item), self.format_amount(item['value']) ]))
 
     def update_completions(self):
         l = []
@@ -775,41 +800,37 @@ class ElectrumWindow(QMainWindow):
         return lambda s, *args: s.do_protect(func, args)
 
 
-    def do_send(self):
+    def read_send_tab(self):
         label = unicode( self.message_e.text() )
 
         if self.gui_object.payment_request:
-            outputs = self.gui_object.payment_request.outputs
-            amount = self.gui_object.payment_request.get_amount()
-
+            outputs = self.gui_object.payment_request.get_outputs()
         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'))
+            outputs = self.payto_e.get_outputs()
+
+        if not outputs:
+            QMessageBox.warning(self, _('Error'), _('No outputs'), _('OK'))
+            return
+
+        for addr, x in outputs:
+            if addr is None or not bitcoin.is_address(addr):
+                QMessageBox.warning(self, _('Error'), _('Invalid Bitcoin Address'), _('OK'))
                 return
-            
-            try:
-                amount = self.amount_e.get_amount()
-            except Exception:
+            if x is None:
                 QMessageBox.warning(self, _('Error'), _('Invalid Amount'), _('OK'))
                 return
 
-            outputs = [(to_address, amount)]
+        amount = sum(map(lambda x:x[1], outputs))
 
-        try:
-            fee = self.fee_e.get_amount()
-        except Exception:
+        fee = self.fee_e.get_amount()
+        if fee is None:
             QMessageBox.warning(self, _('Error'), _('Invalid Fee'), _('OK'))
             return
 
         confirm_amount = self.config.get('confirm_amount', 100000000)
         if amount >= confirm_amount:
-            if not self.question(_("send %(amount)s to %(address)s?")%{ 'amount' : self.format_amount(amount) + ' '+ self.base_unit(), 'address' : to_address}):
+            o = '\n'.join(map(lambda x:x[0], outputs))
+            if not self.question(_("send %(amount)s to %(address)s?")%{ 'amount' : self.format_amount(amount) + ' '+ self.base_unit(), 'address' : o}):
                 return
             
         confirm_fee = self.config.get('confirm_fee', 100000)
@@ -817,18 +838,25 @@ 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(outputs, fee, label)
+        coins = self.get_coins()
+        return outputs, fee, label, coins
 
 
+    def do_send(self):
+        r = self.read_send_tab()
+        if not r:
+            return
+        outputs, fee, label, coins = r
+        self.send_tx(outputs, fee, label, coins)
+
 
     @protected
-    def send_tx(self, outputs, fee, label, password):
+    def send_tx(self, outputs, fee, label, coins, password):
         self.send_button.setDisabled(True)
 
         # first, create an unsigned tx 
-        domain = self.get_payment_sources()
         try:
-            tx = self.wallet.make_unsigned_transaction(outputs, fee, None, domain)
+            tx = self.wallet.make_unsigned_transaction(outputs, fee, None, coins = coins)
             tx.error = None
         except Exception as e:
             traceback.print_exc(file=sys.stdout)
@@ -859,12 +887,11 @@ class ElectrumWindow(QMainWindow):
             if label:
                 self.wallet.set_label(tx.hash(), label)
 
-            if not self.gui_object.payment_request:
-                if not tx.is_complete() or self.config.get('show_before_broadcast'):
-                    self.show_transaction(tx)
-                    self.do_clear()
-                    self.send_button.setDisabled(False)
-                    return
+            if not tx.is_complete() or self.config.get('show_before_broadcast'):
+                self.show_transaction(tx)
+                self.do_clear()
+                self.send_button.setDisabled(False)
+                return
 
             self.broadcast_transaction(tx)
 
@@ -876,12 +903,27 @@ class ElectrumWindow(QMainWindow):
     def broadcast_transaction(self, tx):
 
         def broadcast_thread():
-            if self.gui_object.payment_request:
-                refund_address = self.wallet.addresses()[0]
-                status, msg = self.gui_object.payment_request.send_ack(str(tx), refund_address)
+            pr = self.gui_object.payment_request
+            if pr is None:
+                return self.wallet.sendtx(tx)
+
+            if pr.has_expired():
                 self.gui_object.payment_request = None
-            else:
-                status, msg =  self.wallet.sendtx(tx)
+                return False, _("Payment request has expired")
+
+            status, msg =  self.wallet.sendtx(tx)
+            if not status:
+                return False, msg
+
+            self.invoices[pr.get_id()] = (pr.get_domain(), pr.get_memo(), pr.get_amount(), PR_PAID, tx.hash())
+            self.wallet.storage.put('invoices', self.invoices)
+            self.update_invoices_tab()
+            self.gui_object.payment_request = None
+            refund_address = self.wallet.addresses()[0]
+            ack_status, ack_msg = pr.send_ack(str(tx), refund_address)
+            if ack_status:
+                msg = ack_msg
+
             return status, msg
 
         def broadcast_done(status, msg):
@@ -898,25 +940,44 @@ class ElectrumWindow(QMainWindow):
 
 
     def prepare_for_payment_request(self):
-        style = "QWidget { background-color:none;border:none;}"
         self.tabs.setCurrentIndex(1)
+        self.payto_e.is_pr = True
         for e in [self.payto_e, self.amount_e, self.message_e]:
-            e.setReadOnly(True)
-            e.setStyleSheet(style)
+            e.setFrozen(True)
         for h in [self.payto_help, self.amount_help, self.message_help]:
             h.hide()
         self.payto_e.setText(_("please wait..."))
         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()))
-        self.message_e.setText(self.gui_object.payment_request.memo)
+        pr = self.gui_object.payment_request
+        pr_id = pr.get_id()
+        if pr_id not in self.invoices:
+            self.invoices[pr_id] = (pr.get_domain(), pr.get_memo(), pr.get_amount(), PR_UNPAID, None)
+            self.wallet.storage.put('invoices', self.invoices)
+            self.update_invoices_tab()
+        else:
+            print_error('invoice already in list')
+
+        status = self.invoices[pr_id][3]
+        if status == PR_PAID:
+            self.do_clear()
+            self.show_message("invoice already paid")
+            self.gui_object.payment_request = None
+            return
+
+        self.payto_help.show()
+        self.payto_help.set_alt(lambda: self.show_pr_details(pr))
+
+        self.payto_e.setGreen()
+        self.payto_e.setText(pr.domain)
+        self.amount_e.setText(self.format_amount(pr.get_amount()))
+        self.message_e.setText(pr.get_memo())
 
     def payment_request_error(self):
         self.do_clear()
         self.show_message(self.gui_object.payment_request.error)
-
+        self.gui_object.payment_request = None
 
     def set_send(self, address, amount, label, message):
 
@@ -937,30 +998,19 @@ class ElectrumWindow(QMainWindow):
 
 
     def do_clear(self):
+        self.payto_e.is_pr = False
         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("")
+            e.setFrozen(False)
+
         for h in [self.payto_help, self.amount_help, self.message_help]:
             h.show()
 
+        self.payto_help.set_alt(None)
         self.set_pay_from([])
         self.update_status()
 
-    def set_frozen(self,entry,frozen):
-        if frozen:
-            entry.setReadOnly(True)
-            entry.setFrame(False)
-            palette = QPalette()
-            palette.setColor(entry.backgroundRole(), QColor('lightgray'))
-            entry.setPalette(palette)
-        else:
-            entry.setReadOnly(False)
-            entry.setFrame(True)
-            palette = QPalette()
-            palette.setColor(entry.backgroundRole(), QColor('white'))
-            entry.setPalette(palette)
 
 
     def set_addrs_frozen(self,addrs,freeze):
@@ -990,16 +1040,13 @@ class ElectrumWindow(QMainWindow):
         buttons = QWidget()
         vbox.addWidget(buttons)
 
-        hbox = QHBoxLayout()
-        hbox.setMargin(0)
-        hbox.setSpacing(0)
-        buttons.setLayout(hbox)
-
-        return l,w,hbox
+        return l, w
 
 
     def create_receive_tab(self):
-        l,w,hbox = self.create_list_tab([ _('Address'), _('Label'), _('Balance'), _('Tx')])
+        l, w = self.create_list_tab([ _('Address'), _('Label'), _('Balance'), _('Tx')])
+        for i,width in enumerate(self.column_widths['receive']):
+            l.setColumnWidth(i, width)
         l.setContextMenuPolicy(Qt.CustomContextMenu)
         l.customContextMenuRequested.connect(self.create_receive_menu)
         l.setSelectionMode(QAbstractItemView.ExtendedSelection)
@@ -1007,8 +1054,6 @@ class ElectrumWindow(QMainWindow):
         self.connect(l, SIGNAL('itemChanged(QTreeWidgetItem*, int)'), lambda a,b: self.address_label_changed(a,b,l,0,1))
         self.connect(l, SIGNAL('currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)'), lambda a,b: self.current_item_changed(a))
         self.receive_list = l
-        self.receive_buttons_hbox = hbox
-        hbox.addStretch(1)
         return w
 
 
@@ -1031,20 +1076,44 @@ class ElectrumWindow(QMainWindow):
 
 
     def create_contacts_tab(self):
-        l,w,hbox = self.create_list_tab([_('Address'), _('Label'), _('Tx')])
+        l, w = self.create_list_tab([_('Address'), _('Label'), _('Tx')])
         l.setContextMenuPolicy(Qt.CustomContextMenu)
         l.customContextMenuRequested.connect(self.create_contact_menu)
         for i,width in enumerate(self.column_widths['contacts']):
             l.setColumnWidth(i, width)
-
         self.connect(l, SIGNAL('itemDoubleClicked(QTreeWidgetItem*, int)'), lambda a, b: self.address_label_clicked(a,b,l,0,1))
         self.connect(l, SIGNAL('itemChanged(QTreeWidgetItem*, int)'), lambda a,b: self.address_label_changed(a,b,l,0,1))
         self.contacts_list = l
-        self.contacts_buttons_hbox = hbox
-        hbox.addStretch(1)
         return w
 
 
+    def create_invoices_tab(self):
+        l, w = self.create_list_tab([_('Requestor'), _('Memo'),_('Amount'), _('Status')])
+        h = l.header()
+        h.setStretchLastSection(False)
+        h.setResizeMode(1, QHeaderView.Stretch)
+        l.setContextMenuPolicy(Qt.CustomContextMenu)
+        l.customContextMenuRequested.connect(self.create_invoice_menu)
+        self.invoices_list = l
+        return w
+
+    def update_invoices_tab(self):
+        invoices = self.wallet.storage.get('invoices', {})
+        l = self.invoices_list
+        l.clear()
+        for key, value in invoices.items():
+            try:
+                domain, memo, amount, status, tx_hash = value
+            except:
+                invoices.pop(key)
+                continue
+            item = QTreeWidgetItem( [ domain, memo, self.format_amount(amount), format_status(status)] )
+            l.addTopLevelItem(item)
+
+        l.setCurrentItem(l.topLevelItem(0))
+
+
+
     def delete_imported_key(self, addr):
         if self.question(_("Do you want to remove")+" %s "%addr +_("from your wallet?")):
             self.wallet.delete_imported_key(addr)
@@ -1109,7 +1178,7 @@ class ElectrumWindow(QMainWindow):
             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))
+                menu.addAction(_("Encrypt/decrypt message"), lambda: self.encrypt_message(addr))
             if self.wallet.is_imported(addr):
                 menu.addAction(_("Remove from wallet"), lambda: self.delete_imported_key(addr))
 
@@ -1126,14 +1195,17 @@ class ElectrumWindow(QMainWindow):
 
 
     def get_sendable_balance(self):
-        return sum(sum(self.wallet.get_addr_balance(a)) for a in self.get_payment_sources())
+        return sum(map(lambda x:x['value'], self.get_coins()))
 
 
-    def get_payment_sources(self):
+    def get_coins(self):
         if self.pay_from:
             return self.pay_from
         else:
-            return self.wallet.get_account_addresses(self.current_account)
+            domain = self.wallet.get_account_addresses(self.current_account)
+            for i in self.wallet.frozen_addresses:
+                if i in domain: domain.remove(i)
+            return self.wallet.get_unspent_coins(domain)
 
 
     def send_from_addresses(self, addrs):
@@ -1179,6 +1251,56 @@ class ElectrumWindow(QMainWindow):
         run_hook('create_contact_menu', menu, item)
         menu.exec_(self.contacts_list.viewport().mapToGlobal(position))
 
+    def delete_invoice(self, key):
+        self.invoices.pop(key)
+        self.wallet.storage.put('invoices', self.invoices)
+        self.update_invoices_tab()
+
+    def show_invoice(self, key):
+        from electrum.paymentrequest import PaymentRequest
+        domain, memo, value, status, tx_hash = self.invoices[key]
+        pr = PaymentRequest(self.config)
+        pr.read_file(key)
+        pr.domain = domain
+        pr.verify()
+        self.show_pr_details(pr)
+
+    def show_pr_details(self, pr):
+        msg = 'Domain: ' + pr.domain
+        msg += '\nStatus: ' + pr.get_status()
+        msg += '\nMemo: ' + pr.get_memo()
+        msg += '\nPayment URL: ' + pr.payment_url
+        msg += '\n\nOutputs:\n' + '\n'.join(map(lambda x: x[0] + ' ' + self.format_amount(x[1])+ self.base_unit(), pr.get_outputs()))
+        QMessageBox.information(self, 'Invoice', msg , 'OK')
+
+    def do_pay_invoice(self, key):
+        from electrum.paymentrequest import PaymentRequest
+        domain, memo, value, status, tx_hash = self.invoices[key]
+        pr = PaymentRequest(self.config)
+        pr.read_file(key)
+        pr.domain = domain
+        self.gui_object.payment_request = pr
+        self.prepare_for_payment_request()
+        if pr.verify():
+            self.payment_request_ok()
+        else:
+            self.payment_request_error()
+            
+
+    def create_invoice_menu(self, position):
+        item = self.invoices_list.itemAt(position)
+        if not item:
+            return
+        k = self.invoices_list.indexOfTopLevelItem(item)
+        key = self.invoices.keys()[k]
+        domain, memo, value, status, tx_hash = self.invoices[key]
+        menu = QMenu()
+        menu.addAction(_("Details"), lambda: self.show_invoice(key))
+        if status == PR_UNPAID:
+            menu.addAction(_("Pay Now"), lambda: self.do_pay_invoice(key))
+        menu.addAction(_("Delete"), lambda: self.delete_invoice(key))
+        menu.exec_(self.invoices_list.viewport().mapToGlobal(position))
+
 
     def update_receive_item(self, item):
         item.setFont(0, QFont(MONOSPACE_FONT))
@@ -1206,8 +1328,6 @@ class ElectrumWindow(QMainWindow):
         l.insertChild = l.insertTopLevelItem
 
         l.clear()
-        for i,width in enumerate(self.column_widths['receive']):
-            l.setColumnWidth(i, width)
 
         accounts = self.wallet.get_accounts()
         if self.current_account is None:
@@ -2192,11 +2312,11 @@ class ElectrumWindow(QMainWindow):
 
         fee_label = QLabel(_('Transaction fee') + ':')
         grid.addWidget(fee_label, 2, 0)
-        fee_e = AmountEdit(self.get_decimal_point)
-        fee_e.setText(self.format_amount(self.wallet.fee).strip())
+        fee_e = BTCAmountEdit(self.get_decimal_point)
+        fee_e.setAmount(self.wallet.fee)
         grid.addWidget(fee_e, 2, 1)
-        msg = _('Fee per kilobyte of transaction.') + ' ' \
-            + _('Recommended value') + ': ' + self.format_amount(20000)
+        msg = _('Fee per kilobyte of transaction.') + '\n' \
+            + _('Recommended value') + ': ' + self.format_amount(10000) + ' ' + self.base_unit()
         grid.addWidget(HelpButton(msg), 2, 2)
         if not self.config.is_modifiable('fee_per_kb'):
             for w in [fee_e, fee_label]: w.setEnabled(False)
@@ -2241,9 +2361,8 @@ class ElectrumWindow(QMainWindow):
         # run the dialog
         if not d.exec_(): return
 
-        try:
-            fee = self.fee_e.get_amount()
-        except Exception:
+        fee = fee_e.get_amount()
+        if fee is None:
             QMessageBox.warning(self, _('Error'), _('Invalid value') +': %s'%fee, _('OK'))
             return