Initial novacoin support
[electrum-nvc.git] / gui / qt / lite_window.py
index 1e2d666..4d7997a 100644 (file)
@@ -13,43 +13,37 @@ except ImportError:
     sys.exit(0)
 
 from decimal import Decimal as D
-from electrum.util import get_resource_path as rsrc
-from electrum.bitcoin import is_valid
-from electrum.i18n import _
+from electrum_nvc.util import get_resource_path as rsrc
+from electrum_nvc.bitcoin import is_valid
+from electrum_nvc.i18n import _
 import decimal
 import json
 import os.path
 import random
 import re
 import time
-from electrum.wallet import Wallet, WalletStorage
+from electrum_nvc.wallet import Wallet, WalletStorage
 import webbrowser
 import history_widget
 import receiving_widget
-from electrum import util
-import csv 
+from electrum_nvc import util
 import datetime
 
-from electrum.version import ELECTRUM_VERSION as electrum_version
-from electrum.util import format_satoshis, age
+from electrum_nvc.version import ELECTRUM_VERSION as electrum_version
+from electrum_nvc.util import format_satoshis, age
 
 from main_window import ElectrumWindow
 import shutil
 
 from util import *
 
-bitcoin = lambda v: v * 100000000
+bitcoin = lambda v: v * 1000000
 
 def IconButton(filename, parent=None):
     pixmap = QPixmap(filename)
     icon = QIcon(pixmap)
     return QPushButton(icon, "", parent)
 
-class Timer(QThread):
-    def run(self):
-        while True:
-            self.emit(SIGNAL('timersignal'))
-            time.sleep(0.5)
 
 def resize_line_edit_width(line_edit, text_input):
     metrics = QFontMetrics(qApp.font())
@@ -88,50 +82,6 @@ def load_theme_paths():
     return theme_paths
 
 
-def csv_transaction(wallet):
-    try:
-        select_export = _('Select file to export your wallet transactions to')
-        fileName = QFileDialog.getSaveFileName(QWidget(), select_export, os.path.expanduser('~/electrum-history.csv'), "*.csv")
-        if fileName:
-            with open(fileName, "w+") as csvfile:
-                transaction = csv.writer(csvfile)
-                transaction.writerow(["transaction_hash","label", "confirmations", "value", "fee", "balance", "timestamp"])
-                for item in wallet.get_tx_history():
-                    tx_hash, confirmations, is_mine, value, fee, balance, timestamp = item
-                    if confirmations:
-                        if timestamp is not None:
-                            try:
-                                time_string = datetime.datetime.fromtimestamp(timestamp).isoformat(' ')[:-3]
-                            except [RuntimeError, TypeError, NameError] as reason:
-                                time_string = "unknown"
-                                pass
-                        else:
-                          time_string = "unknown"
-                    else:
-                        time_string = "pending"
-
-                    if value is not None:
-                        value_string = format_satoshis(value, True, wallet.num_zeros)
-                    else:
-                        value_string = '--'
-
-                    if fee is not None:
-                        fee_string = format_satoshis(fee, True, wallet.num_zeros)
-                    else:
-                        fee_string = '0'
-
-                    if tx_hash:
-                        label, is_default_label = wallet.get_label(tx_hash)
-                    else:
-                      label = ""
-
-                    balance_string = format_satoshis(balance, False, wallet.num_zeros)
-                    transaction.writerow([tx_hash, label, confirmations, value_string, fee_string, balance_string, time_string])
-                QMessageBox.information(None,"CSV Export created", "Your CSV export has been successfully created.")
-    except (IOError, os.error), reason:
-        export_error_label = _("Electrum was unable to produce a transaction export.")
-        QMessageBox.critical(None,_("Unable to create csv"), export_error_label + "\n" + str(reason))
-
 
 
 class TransactionWindow(QDialog):
@@ -173,14 +123,15 @@ class MiniWindow(QDialog):
 
     def __init__(self, actuator, expand_callback, config):
         super(MiniWindow, self).__init__()
-        tx = "e08115d0f7819aee65b9d24f81ef9d46eb62bb67ddef5318156cbc3ceb7b703e"
 
         self.actuator = actuator
         self.config = config
         self.btc_balance = None
+        self.use_exchanges = ["Blockchain", "CoinDesk"]
         self.quote_currencies = ["BRL", "CNY", "EUR", "GBP", "RUB", "USD"]
         self.actuator.set_configured_currency(self.set_quote_currency)
-        #self.exchanger = exchange_rate.Exchanger(self)
+        self.actuator.set_configured_exchange(self.set_exchange)
+
         # Needed because price discovery is done in a different thread
         # which needs to be sent back to this main one to update the GUI
         self.connect(self, SIGNAL("refresh_balance()"), self.refresh_balance)
@@ -191,14 +142,14 @@ class MiniWindow(QDialog):
 
         # Bitcoin address code
         self.address_input = QLineEdit()
-        self.address_input.setPlaceholderText(_("Enter a Bitcoin address or contact"))
+        self.address_input.setPlaceholderText(_("Enter a Novacoin address or contact"))
         self.address_input.setObjectName("address_input")
 
         self.address_input.setFocusPolicy(Qt.ClickFocus)
 
         self.address_input.textChanged.connect(self.address_field_changed)
         resize_line_edit_width(self.address_input,
-                               "1BtaFUr3qVvAmwrsuDuu5zk6e4s2rxd2Gy")
+                               "4LJgtjeXMjLA6nVzYMJh1LEkwxMFsRtnP4")
 
         self.address_completions = QStringListModel()
         address_completer = QCompleter(self.address_input)
@@ -210,7 +161,7 @@ class MiniWindow(QDialog):
         address_layout.addWidget(self.address_input)
 
         self.amount_input = QLineEdit()
-        self.amount_input.setPlaceholderText(_("... and amount"))
+        self.amount_input.setPlaceholderText(_("... and amount") + " (%s)"%self.actuator.g.base_unit())
         self.amount_input.setObjectName("amount_input")
 
         self.amount_input.setFocusPolicy(Qt.ClickFocus)
@@ -225,10 +176,10 @@ class MiniWindow(QDialog):
         self.amount_input.setAttribute(Qt.WA_MacShowFocusRect, 0)
         self.amount_input.textChanged.connect(self.amount_input_changed)
 
-        if self.actuator.wallet.seed:
-            self.send_button = QPushButton(_("&Send"))
-        else:
-            self.send_button = QPushButton(_("&Create"))
+        #if self.actuator.g.wallet.seed:
+        self.send_button = QPushButton(_("&Send"))
+        #else:
+        #    self.send_button = QPushButton(_("&Create"))
 
         self.send_button.setObjectName("send_button")
         self.send_button.setDisabled(True);
@@ -303,12 +254,11 @@ class MiniWindow(QDialog):
         self.toggle_receiving_layout(show_hist)
         
         self.setWindowIcon(QIcon(":icons/electrum.png"))
-        self.setWindowTitle("Electrum")
+        self.setWindowTitle("Electrum-NVC")
         self.setWindowFlags(Qt.Window|Qt.MSWindowsFixedSizeDialogHint)
         self.layout().setSizeConstraint(QLayout.SetFixedSize)
         self.setObjectName("main_window")
 
-        self.show()
 
     def context_menu(self):
         view_menu = QMenu()
@@ -347,24 +297,25 @@ class MiniWindow(QDialog):
 
 
     def toggle_theme(self, theme_name):
-        old_path = QDir.currentPath()
         self.actuator.change_theme(theme_name)
         # Recompute style globally
         qApp.style().unpolish(self)
         qApp.style().polish(self)
-        QDir.setCurrent(old_path)
 
     def closeEvent(self, event):
         g = self.geometry()
         self.config.set_key("winpos-lite", [g.left(),g.top(),g.width(),g.height()],True)
-        
-        super(MiniWindow, self).closeEvent(event)
+        self.actuator.g.closeEvent(event)
         qApp.quit()
 
-    def set_payment_fields(self, dest_address, amount):
+    def pay_from_URI(self, URI):
+        try:
+            dest_address, amount, label, message, request_url = util.parse_URI(URI)
+        except:
+            return
         self.address_input.setText(dest_address)
         self.address_field_changed(dest_address)
-        self.amount_input.setText(amount)
+        self.amount_input.setText(str(amount))
 
     def activate(self):
         pass
@@ -372,6 +323,13 @@ class MiniWindow(QDialog):
     def deactivate(self):
         pass
 
+    def set_exchange(self, use_exchange):
+        if use_exchange not in self.use_exchanges:
+            return
+        self.use_exchanges.remove(use_exchange)
+        self.use_exchanges.insert(0, use_exchange)
+        self.refresh_balance()
+
     def set_quote_currency(self, currency):
         """Set and display the fiat currency country."""
         if currency not in self.quote_currencies:
@@ -404,20 +362,23 @@ class MiniWindow(QDialog):
         quote_text = self.create_quote_text(btc_balance)
         if quote_text:
             quote_text = "(%s)" % quote_text
-        btc_balance = "%.4f" % (btc_balance / bitcoin(1))
-        self.balance_label.set_balance_text(btc_balance, quote_text)
-        self.setWindowTitle("Electrum %s - %s BTC" % (electrum_version, btc_balance))
+
+        amount = self.actuator.g.format_amount(btc_balance)
+        unit = self.actuator.g.base_unit()
+
+        self.balance_label.set_balance_text(amount, unit, quote_text)
+        self.setWindowTitle("Electrum %s - %s %s" % (electrum_version, amount, unit))
 
     def amount_input_changed(self, amount_text):
         """Update the number of bitcoins displayed."""
         self.check_button_status()
 
         try:
-            amount = D(str(amount_text))
+            amount = D(str(amount_text)) * (10**self.actuator.g.decimal_point)
         except decimal.InvalidOperation:
             self.balance_label.show_balance()
         else:
-            quote_text = self.create_quote_text(amount * bitcoin(1))
+            quote_text = self.create_quote_text(amount)
             if quote_text:
                 self.balance_label.set_amount_text(quote_text)
                 self.balance_label.show_amount()
@@ -427,14 +388,10 @@ class MiniWindow(QDialog):
     def create_quote_text(self, btc_balance):
         """Return a string copy of the amount fiat currency the 
         user has in bitcoins."""
-        quote_currency = self.quote_currencies[0]
-        quote_balance = None #self.exchanger.exchange(btc_balance, quote_currency)
-        if quote_balance is None:
-            quote_text = ""
-        else:
-            quote_text = "%.2f %s" % ((quote_balance / bitcoin(1)),
-                                      quote_currency)
-        return quote_text
+        from electrum_nvc.plugins import run_hook
+        r = {}
+        run_hook('get_fiat_balance_text', btc_balance, r)
+        return r.get(0,'')
 
     def send(self):
         if self.actuator.send(self.address_input.text(),
@@ -446,7 +403,7 @@ class MiniWindow(QDialog):
         """Check that the bitcoin address is valid and that something
         is entered in the amount before making the send button clickable."""
         try:
-            value = D(str(self.amount_input.text())) * 10**8
+            value = D(str(self.amount_input.text())) * (10**self.actuator.g.decimal_point)
         except decimal.InvalidOperation:
             value = None
         # self.address_input.property(...) returns a qVariant, not a bool.
@@ -496,13 +453,10 @@ class MiniWindow(QDialog):
 
         for item in tx_history[-10:]:
             tx_hash, conf, is_mine, value, fee, balance, timestamp = item
-            label = self.actuator.wallet.get_label(tx_hash)[0]
-            #amount = D(value) / 10**8
-            v_str = format_satoshis(value, True)
+            label = self.actuator.g.wallet.get_label(tx_hash)[0]
+            v_str = self.actuator.g.format_amount(value, True)
             self.history_list.append(label, v_str, age(timestamp))
 
-    def acceptbit(self):
-        self.actuator.acceptbit(self.quote_currencies[0])
 
     def the_website(self):
         webbrowser.open("http://electrum.org")
@@ -549,11 +503,15 @@ class BalanceLabel(QLabel):
                 menu.exec_(position)
                 
 
-    def set_balance_text(self, btc_balance, quote_text):
+    def set_balance_text(self, amount, unit, quote_text):
         """Set the amount of bitcoins in the gui."""
         if self.state == self.SHOW_CONNECTING:
             self.state = self.SHOW_BALANCE
-        self.balance_text = "<span style='font-size: 18pt'>%s</span> <span style='font-size: 10pt'>BTC</span> <span style='font-size: 10pt'>%s</span>" % (btc_balance, quote_text)
+
+        self.balance_text = "<span style='font-size: 18pt'>%s</span>"%amount\
+            + " <span style='font-size: 10pt'>%s</span>" % unit \
+            + " <span style='font-size: 10pt'>%s</span>" % quote_text
+
         if self.state == self.SHOW_BALANCE:
             self.setText(self.balance_text)
 
@@ -617,7 +575,7 @@ class ReceivePopup(QDialog):
         self.close()
 
     def setup(self, address):
-        label = QLabel(_("Copied your Bitcoin address to the clipboard!"))
+        label = QLabel(_("Copied your Novacoin address to the clipboard!"))
         address_display = QLineEdit(address)
         address_display.setReadOnly(True)
         resize_line_edit_width(address_display, address)
@@ -627,7 +585,7 @@ class ReceivePopup(QDialog):
         main_layout.addWidget(address_display)
 
         self.setMouseTracking(True)
-        self.setWindowTitle("Electrum - " + _("Receive Bitcoin payment"))
+        self.setWindowTitle("Electrum - " + _("Receive Novacoin payment"))
         self.setWindowFlags(Qt.Window|Qt.FramelessWindowHint|
                             Qt.MSWindowsFixedSizeDialogHint)
         self.layout().setSizeConstraint(QLayout.SetFixedSize)
@@ -647,12 +605,12 @@ class MiniActuator:
     sending/receiving bitcoins."""
     
     
-    def __init__(self, config, wallet):
+    def __init__(self, main_window):
         """Retrieve the gui theme used in previous session."""
-        self.config = config
-        self.wallet = wallet
-        self.theme_name = self.config.get('litegui_theme','Cleanlook')
+        self.g = main_window
+        self.theme_name = self.g.config.get('litegui_theme','Cleanlook')
         self.themes = load_theme_paths()
+        self.load_theme()
 
     def load_theme(self):
         """Load theme retrieved from wallet file."""
@@ -661,8 +619,8 @@ class MiniActuator:
         except KeyError:
             util.print_error("Theme not found!", self.theme_name)
             return
-        QDir.setCurrent(os.path.join(theme_prefix, theme_path))
-        with open(rsrc("style.css")) as style_file:
+        full_theme_path = "%s/%s/style.css" % (theme_prefix, theme_path)
+        with open(full_theme_path) as style_file:
             qApp.setStyleSheet(style_file.read())
 
     def theme_names(self):
@@ -676,28 +634,38 @@ class MiniActuator:
     def change_theme(self, theme_name):
         """Change theme."""
         self.theme_name = theme_name
-        self.config.set_key('litegui_theme',theme_name)
+        self.g.config.set_key('litegui_theme',theme_name)
         self.load_theme()
+   
+    def set_configured_exchange(self, set_exchange):
+        use_exchange = self.g.config.get('use_exchange')
+        if use_exchange is not None:
+            set_exchange(use_exchange)
     
     def set_configured_currency(self, set_quote_currency):
         """Set the inital fiat currency conversion country (USD/EUR/GBP) in 
         the GUI to what it was set to in the wallet."""
-        currency = self.config.get('currency')
+        currency = self.g.config.get('currency')
         # currency can be none when Electrum is used for the first
         # time and no setting has been created yet.
         if currency is not None:
             set_quote_currency(currency)
 
+    def set_config_exchange(self, conversion_exchange):
+        self.g.config.set_key('exchange',conversion_exchange,True)
+        self.g.update_status()
+
     def set_config_currency(self, conversion_currency):
         """Change the wallet fiat currency country."""
-        self.config.set_key('conversion_currency',conversion_currency,True)
+        self.g.config.set_key('currency',conversion_currency,True)
+        self.g.update_status()
 
     def copy_address(self, receive_popup):
         """Copy the wallet addresses into the client."""
-        addrs = [addr for addr in self.wallet.addresses(True)
-                 if not self.wallet.is_change(addr)]
+        addrs = [addr for addr in self.g.wallet.addresses(True)
+                 if not self.g.wallet.is_change(addr)]
         # Select most recent addresses from gap limit
-        addrs = addrs[-self.wallet.gap_limit:]
+        addrs = addrs[-self.g.wallet.gap_limit:]
         copied_address = random.choice(addrs)
         qApp.clipboard().setText(copied_address)
         receive_popup.setup(copied_address)
@@ -729,14 +697,14 @@ class MiniActuator:
 
         if dest_address is None or not is_valid(dest_address):
             QMessageBox.warning(parent_window, _('Error'), 
-                _('Invalid Bitcoin Address') + ':\n' + address, _('OK'))
+                _('Invalid Novacoin Address') + ':\n' + address, _('OK'))
             return False
 
-        convert_amount = lambda amount: \
-            int(D(unicode(amount)) * bitcoin(1))
-        amount = convert_amount(amount)
+        amount = D(unicode(amount)) * (10*self.g.decimal_point)
+        print "amount", amount
+        return
 
-        if self.wallet.use_encryption:
+        if self.g.wallet.use_encryption:
             password_dialog = PasswordDialog(parent_window)
             password = password_dialog.run()
             if not password:
@@ -745,23 +713,23 @@ class MiniActuator:
             password = None
 
         fee = 0
-        # 0.1 BTC = 10000000
+        # 0.1 NVC = 100000
         if amount < bitcoin(1) / 10:
-            # 0.001 BTC
+            # 0.001 NVC
             fee = bitcoin(1) / 1000
 
         try:
-            tx = self.wallet.mktx([(dest_address, amount)], password, fee)
-        except BaseException as error:
+            tx = self.g.wallet.mktx([(dest_address, amount)], password, fee)
+        except Exception as error:
             QMessageBox.warning(parent_window, _('Error'), str(error), _('OK'))
             return False
 
-        if tx.is_complete:
-            h = self.wallet.send_tx(tx)
+        if tx.is_complete():
+            h = self.g.wallet.send_tx(tx)
 
-            self.waiting_dialog(lambda: False if self.wallet.tx_event.isSet() else _("Sending transaction, please wait..."))
+            self.waiting_dialog(lambda: False if self.g.wallet.tx_event.isSet() else _("Sending transaction, please wait..."))
               
-            status, message = self.wallet.receive_tx(h)
+            status, message = self.g.wallet.receive_tx(h, tx)
 
             if not status:
                 import tempfile
@@ -780,7 +748,7 @@ class MiniActuator:
                 with open(fileName,'w') as f:
                     f.write(json.dumps(tx.as_dict(),indent=4) + '\n')
                 QMessageBox.information(QWidget(), _('Unsigned transaction created'), _("Unsigned transaction was saved to file:") + " " +fileName, _('OK'))
-            except BaseException as e:
+            except Exception as e:
                 QMessageBox.warning(QWidget(), _('Error'), _('Could not write transaction to file: %s' % e), _('OK'))
         return True
 
@@ -797,7 +765,7 @@ class MiniActuator:
         
         if match1:
             dest_address = \
-                self.wallet.get_alias(recipient, True, 
+                self.g.wallet.get_alias(recipient, True, 
                                       self.show_message, self.question)
             return dest_address
         elif match2:
@@ -806,19 +774,8 @@ class MiniActuator:
             return recipient
 
 
-    def copy_master_public_key(self):
-        master_pubkey = self.wallet.get_master_public_key()
-        qApp.clipboard().setText(master_pubkey)
-        QMessageBox.information(None, _("Copy successful"), _("Your master public key has been copied to your clipboard."))
         
 
-    def acceptbit(self, currency):
-        master_pubkey = self.wallet.master_public_key
-        url = "http://acceptbit.com/mpk/%s/%s" % (master_pubkey, currency)
-        webbrowser.open(url)
-
-    def show_seed_dialog(self):
-        ElectrumWindow.show_seed_dialog(self.wallet)
 
 class MiniDriver(QObject):
 
@@ -827,16 +784,17 @@ class MiniDriver(QObject):
     SYNCHRONIZING = 2
     READY = 3
 
-    def __init__(self, wallet, window):
+    def __init__(self, main_window, mini_window):
         super(QObject, self).__init__()
 
-        self.wallet = wallet
-        self.network = wallet.network
-        self.window = window
+        self.g = main_window
+        self.network = main_window.network
+        self.window = mini_window
 
-        self.wallet.network.register_callback('updated',self.update_callback)
-        self.wallet.network.register_callback('connected', self.update_callback)
-        self.wallet.network.register_callback('disconnected', self.update_callback)
+        if self.network:
+            self.network.register_callback('updated',self.update_callback)
+            self.network.register_callback('connected', self.update_callback)
+            self.network.register_callback('disconnected', self.update_callback)
 
         self.state = None
 
@@ -851,19 +809,24 @@ class MiniDriver(QObject):
         self.emit(SIGNAL("updatesignal()"))
 
     def update(self):
-        if not self.network.interface:
+        if not self.network:
+            self.initializing()
+        elif not self.network.interface:
             self.initializing()
         elif not self.network.interface.is_connected:
             self.connecting()
-        elif not self.wallet.up_to_date:
+
+        if self.g.wallet is None:
+            self.ready()
+        elif not self.g.wallet.up_to_date:
             self.synchronizing()
         else:
             self.ready()
-
-        if self.wallet.up_to_date:
             self.update_balance()
             self.update_completions()
             self.update_history()
+            self.window.receiving.update_list()
+
 
     def initializing(self):
         if self.state == self.INITIALIZING:
@@ -890,19 +853,19 @@ class MiniDriver(QObject):
         self.window.activate()
 
     def update_balance(self):
-        conf_balance, unconf_balance = self.wallet.get_balance()
+        conf_balance, unconf_balance = self.g.wallet.get_balance()
         balance = D(conf_balance + unconf_balance)
         self.window.set_balances(balance)
 
     def update_completions(self):
         completions = []
-        for addr, label in self.wallet.labels.items():
-            if addr in self.wallet.addressbook:
+        for addr, label in self.g.wallet.labels.items():
+            if addr in self.g.wallet.addressbook:
                 completions.append("%s <%s>" % (label, addr))
         self.window.update_completions(completions)
 
     def update_history(self):
-        tx_history = self.wallet.get_tx_history()
+        tx_history = self.g.wallet.get_tx_history()
         self.window.update_history(tx_history)