add switch-gui button for qt
[electrum-nvc.git] / lib / gui_lite.py
index 6552751..dc7b434 100644 (file)
@@ -4,22 +4,17 @@ import sys
 try:
     from PyQt4.QtCore import *
     from PyQt4.QtGui import *
+    import PyQt4.QtCore as QtCore
+
 except ImportError:
     print "You need to have PyQT installed to run Electrum in graphical mode."
     print "If you have pip installed try 'sudo pip install pyqt' if you are on Debian/Ubuntu try 'sudo apt-get install python-qt4'."
     sys.exit(0)
 
 
-qtVersion = qVersion()
-if not(int(qtVersion[0]) >= 4 and int(qtVersion[2]) >= 7):
-    app = QApplication(sys.argv)
-    QMessageBox.warning(None,"Could not start Lite GUI.", "Electrum was unable to load the 'Lite GUI' because it needs Qt version >= 4.7.\nPlease use the 'Qt' GUI")
-    sys.exit(0)
-
 
 
 from decimal import Decimal as D
-from interface import DEFAULT_SERVERS
 from util import get_resource_path as rsrc
 from i18n import _
 import decimal
@@ -31,8 +26,13 @@ import time
 import wallet
 import webbrowser
 import history_widget
+import receiving_widget
 import util
+import csv 
+import datetime
 
+from version import ELECTRUM_VERSION as electrum_version
+from wallet import format_satoshis
 import gui_qt
 import shutil
 
@@ -55,19 +55,62 @@ def resize_line_edit_width(line_edit, text_input):
     text_input += "A"
     line_edit.setMinimumWidth(metrics.width(text_input))
 
+def load_theme_name(theme_path):
+    try:
+        with open(os.path.join(theme_path, "name.cfg")) as name_cfg_file:
+            return name_cfg_file.read().rstrip("\n").strip()
+    except IOError:
+        return None
+
+
+def theme_dirs_from_prefix(prefix):
+    if not os.path.exists(prefix):
+        return []
+    theme_paths = {}
+    for potential_theme in os.listdir(prefix):
+        theme_full_path = os.path.join(prefix, potential_theme)
+        theme_css = os.path.join(theme_full_path, "style.css")
+        if not os.path.exists(theme_css):
+            continue
+        theme_name = load_theme_name(theme_full_path)
+        if theme_name is None:
+            continue
+        theme_paths[theme_name] = prefix, potential_theme
+    return theme_paths
+
+def load_theme_paths():
+    theme_paths = {}
+    prefixes = (util.local_data_dir(), util.appdata_dir())
+    for prefix in prefixes:
+        theme_paths.update(theme_dirs_from_prefix(prefix))
+    return theme_paths
+
+
 class ElectrumGui(QObject):
 
-    def __init__(self, wallet, config):
+    def __init__(self, wallet, config, expert=None):
         super(QObject, self).__init__()
 
         self.wallet = wallet
         self.config = config
-        self.app = QApplication(sys.argv)
+        self.check_qt_version()
+        self.expert = expert
+        if self.expert != None:
+            self.app = self.expert.app
+        else:
+            self.app = QApplication(sys.argv)
+
+    def check_qt_version(self):
+        qtVersion = qVersion()
+        if not(int(qtVersion[0]) >= 4 and int(qtVersion[2]) >= 7):
+            app = QApplication(sys.argv)
+            QMessageBox.warning(None,"Could not start Lite GUI.", "Electrum was unable to load the 'Lite GUI' because it needs Qt version >= 4.7.\nChanging your config to use the 'Classic' GUI")
+            self.config.set_key('gui','classic',True)
+            sys.exit(0)
+
 
     def main(self, url):
         actuator = MiniActuator(self.wallet)
-        self.connect(self, SIGNAL("updateservers()"),
-                     actuator.update_servers_list)
         # Should probably not modify the current path but instead
         # change the behaviour of rsrc(...)
         old_path = QDir.currentPath()
@@ -82,17 +125,15 @@ class ElectrumGui(QObject):
 
         if url:
             self.set_url(url)
-
-        timer = Timer()
-        timer.start()
-        self.expert = gui_qt.ElectrumWindow(self.wallet, self.config)
-        self.expert.app = self.app
-        self.expert.connect_slots(timer)
-        self.expert.update_wallet()
-        self.app.exec_()
-
-    def server_list_changed(self):
-        self.emit(SIGNAL("updateservers()"))
+            
+        if self.expert == None:
+            timer = Timer()
+            timer.start()
+            self.expert = gui_qt.ElectrumWindow(self.wallet, self.config)
+            self.expert.app = self.app
+            self.expert.connect_slots(timer)
+            self.expert.update_wallet()
+            self.app.exec_()
 
     def expand(self):
         """Hide the lite mode window and show pro-mode."""
@@ -117,16 +158,50 @@ class ElectrumGui(QObject):
         qt_gui_object = gui_qt.ElectrumGui(self.wallet, self.app)
         return qt_gui_object.restore_or_create()
 
+class TransactionWindow(QDialog):
+
+    def set_label(self):
+        label = unicode(self.label_edit.text())
+        self.parent.wallet.labels[self.tx_id] = label
+
+        super(TransactionWindow, self).accept() 
+
+    def __init__(self, transaction_id, parent):
+        super(TransactionWindow, self).__init__()
+
+        self.tx_id = str(transaction_id)
+        self.parent = parent
+
+        self.setModal(True)
+        self.resize(200,100)
+        self.setWindowTitle("Transaction successfully sent")
+
+        self.layout = QGridLayout(self)
+        self.layout.addWidget(QLabel("Your transaction has been sent.\nPlease enter a label for this transaction for future reference."))
+
+        self.label_edit = QLineEdit()
+        self.label_edit.setPlaceholderText(_("Transaction label"))
+        self.label_edit.setObjectName("label_input")
+        self.label_edit.setAttribute(Qt.WA_MacShowFocusRect, 0)
+        self.label_edit.setFocusPolicy(Qt.ClickFocus)
+        self.layout.addWidget(self.label_edit)
+
+        self.save_button = QPushButton(_("Save"))
+        self.layout.addWidget(self.save_button)
+        self.save_button.clicked.connect(self.set_label)
+
+        self.exec_()
+
 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.quote_currencies = ["EUR", "USD", "GBP"]
+        self.quote_currencies = ["BRL", "CNY", "EUR", "GBP", "RUB", "USD"]
         self.actuator.set_configured_currency(self.set_quote_currency)
         self.exchanger = exchange_rate.Exchanger(self)
         # Needed because price discovery is done in a different thread
@@ -136,18 +211,15 @@ class MiniWindow(QDialog):
         self.balance_label = BalanceLabel(self.change_quote_currency)
         self.balance_label.setObjectName("balance_label")
 
-        self.receive_button = QPushButton(_("&Receive"))
-        self.receive_button.setObjectName("receive_button")
-        self.receive_button.setDefault(True)
-        self.receive_button.clicked.connect(self.copy_address)
 
         # Bitcoin address code
         self.address_input = QLineEdit()
-        self.address_input.setPlaceholderText(_("Enter a Bitcoin address..."))
+        self.address_input.setPlaceholderText(_("Enter a Bitcoin address or contact"))
         self.address_input.setObjectName("address_input")
 
+        self.address_input.setFocusPolicy(Qt.ClickFocus)
 
-        self.address_input.textEdited.connect(self.address_field_changed)
+        self.address_input.textChanged.connect(self.address_field_changed)
         resize_line_edit_width(self.address_input,
                                "1BtaFUr3qVvAmwrsuDuu5zk6e4s2rxd2Gy")
 
@@ -163,6 +235,8 @@ class MiniWindow(QDialog):
         self.amount_input = QLineEdit()
         self.amount_input.setPlaceholderText(_("... and amount"))
         self.amount_input.setObjectName("amount_input")
+
+        self.amount_input.setFocusPolicy(Qt.ClickFocus)
         # This is changed according to the user's displayed balance
         self.amount_validator = QDoubleValidator(self.amount_input)
         self.amount_validator.setNotation(QDoubleValidator.StandardNotation)
@@ -179,12 +253,17 @@ class MiniWindow(QDialog):
         self.send_button.setDisabled(True);
         self.send_button.clicked.connect(self.send)
 
+        # Creating the receive button
+        self.receive_button = QPushButton(_("&Receive"))
+        self.receive_button.setObjectName("receive_button")
+        self.receive_button.setDefault(True)
+
         main_layout = QGridLayout(self)
 
         main_layout.addWidget(self.balance_label, 0, 0)
         main_layout.addWidget(self.receive_button, 0, 1)
 
-        main_layout.addWidget(self.address_input, 1, 0, 1, -1)
+        main_layout.addWidget(self.address_input, 1, 0)
 
         main_layout.addWidget(self.amount_input, 2, 0)
         main_layout.addWidget(self.send_button, 2, 1)
@@ -193,19 +272,46 @@ class MiniWindow(QDialog):
         self.history_list.setObjectName("history")
         self.history_list.hide()
         self.history_list.setAlternatingRowColors(True)
-        main_layout.addWidget(self.history_list, 3, 0, 1, -1)
 
+        main_layout.addWidget(self.history_list, 3, 0, 1, 2)
+        
+
+        self.receiving = receiving_widget.ReceivingWidget(self)
+        self.receiving.setObjectName("receiving")
+
+        # Add to the right side 
+        self.receiving_box = QGroupBox(_("Select a receiving address"))
+        extra_layout = QGridLayout()
+
+        # Checkbox to filter used addresses
+        hide_used = QCheckBox(_('Hide used addresses'))
+        hide_used.setChecked(True)
+        hide_used.stateChanged.connect(self.receiving.toggle_used)
+
+        # Events for receiving addresses
+        self.receiving.clicked.connect(self.receiving.copy_address)
+        self.receiving.itemDoubleClicked.connect(self.receiving.edit_label)
+        self.receiving.itemChanged.connect(self.receiving.update_label)
+
+        # Label
+        extra_layout.addWidget( QLabel(_('Selecting an address will copy it to the clipboard.\nDouble clicking the label will allow you to edit it.') ),0,0)
+
+        extra_layout.addWidget(self.receiving, 1,0)
+        extra_layout.addWidget(hide_used, 2,0)
+        extra_layout.setColumnMinimumWidth(0,200)
+
+        self.receiving_box.setLayout(extra_layout)
+        main_layout.addWidget(self.receiving_box,0,3,-1,3)
+        self.receiving_box.hide()
+
+        self.receive_button.clicked.connect(self.toggle_receiving_layout)
+
+        # Creating the menu bar
         menubar = QMenuBar()
         electrum_menu = menubar.addMenu(_("&Bitcoin"))
 
-        servers_menu = electrum_menu.addMenu(_("&Servers"))
-        servers_group = QActionGroup(self)
-        self.actuator.set_servers_gui_stuff(servers_menu, servers_group)
-        self.actuator.populate_servers_menu()
         electrum_menu.addSeparator()
 
-        brain_seed = electrum_menu.addAction(_("&BrainWallet Info"))
-        brain_seed.triggered.connect(self.actuator.show_seed_dialog)
         quit_option = electrum_menu.addAction(_("&Quit"))
         quit_option.triggered.connect(self.close)
 
@@ -215,7 +321,13 @@ class MiniWindow(QDialog):
         backup_wallet = extra_menu.addAction( _("&Create wallet backup"))
         backup_wallet.triggered.connect(self.backup_wallet)
 
-        expert_gui = view_menu.addAction(_("&Pro Mode"))
+        export_csv = extra_menu.addAction( _("&Export transactions to CSV") )
+        export_csv.triggered.connect(self.actuator.csv_transaction)
+        
+        master_key = extra_menu.addAction( _("Copy master public key to clipboard") ) 
+        master_key.triggered.connect(self.actuator.copy_master_public_key)
+
+        expert_gui = view_menu.addAction(_("&Classic GUI"))
         expert_gui.triggered.connect(expand_callback)
         themes_menu = view_menu.addMenu(_("&Themes"))
         selected_theme = self.actuator.selected_theme()
@@ -249,6 +361,7 @@ class MiniWindow(QDialog):
         show_about = help_menu.addAction(_("&About"))
         show_about.triggered.connect(self.show_about)
         main_layout.setMenuBar(menubar)
+        self.main_layout = main_layout
 
         quit_shortcut = QShortcut(QKeySequence("Ctrl+Q"), self)
         quit_shortcut.activated.connect(self.close)
@@ -269,6 +382,20 @@ class MiniWindow(QDialog):
         self.setObjectName("main_window")
         self.show()
 
+    def toggle_receiving_layout(self):
+        if self.receiving_box.isVisible():
+            self.receiving_box.hide()
+            self.receive_button.setProperty("isActive", False)
+
+            qApp.style().unpolish(self.receive_button)
+            qApp.style().polish(self.receive_button)
+        else:
+            self.receiving_box.show()
+            self.receive_button.setProperty("isActive", 'true')
+
+            qApp.style().unpolish(self.receive_button)
+            qApp.style().polish(self.receive_button)
+
     def toggle_theme(self, theme_name):
         old_path = QDir.currentPath()
         self.actuator.change_theme(theme_name)
@@ -325,7 +452,7 @@ class MiniWindow(QDialog):
             quote_text = "(%s)" % quote_text
         btc_balance = "%.2f" % (btc_balance / bitcoin(1))
         self.balance_label.set_balance_text(btc_balance, quote_text)
-        self.setWindowTitle("Electrum - %s BTC" % btc_balance)
+        self.setWindowTitle("Electrum %s - %s BTC" % (electrum_version, btc_balance))
 
     def amount_input_changed(self, amount_text):
         """Update the number of bitcoins displayed."""
@@ -377,6 +504,13 @@ class MiniWindow(QDialog):
             self.send_button.setDisabled(True)
 
     def address_field_changed(self, address):
+        # label or alias, with address in brackets
+        match2 = re.match("(.*?)\s*\<([1-9A-HJ-NP-Za-km-z]{26,})\>",
+                          address)
+        if match2:
+          address = match2.group(2)
+          self.address_input.setText(address)
+
         if self.actuator.is_valid(address):
             self.check_button_status()
             self.address_input.setProperty("isValid", True)
@@ -400,12 +534,19 @@ class MiniWindow(QDialog):
 
     def update_completions(self, completions):
         self.address_completions.setStringList(completions)
 
     def update_history(self, tx_history):
-        for tx in tx_history[-10:]:
-            address = tx["default_label"]
-            amount = D(tx["value"]) / 10**8
-            self.history_list.append(address, amount)
+        from util import format_satoshis, age
+
+        self.history_list.empty()
+
+        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)
+            self.history_list.append(label, v_str, age(timestamp))
 
     def acceptbit(self):
         self.actuator.acceptbit(self.quote_currencies[0])
@@ -415,16 +556,18 @@ class MiniWindow(QDialog):
 
     def show_about(self):
         QMessageBox.about(self, "Electrum",
-            _("Electrum's focus is speed, with low resource usage and simplifying Bitcoin. You do not need to perform regular backups, because your wallet can be recovered from a secret phrase that you can memorize or write on paper. Startup times are instant because it operates in conjuction with high-performance servers that handle the most complicated parts of the Bitcoin system.\n\nSend donations to 1JwTMv4GWaPdf931N6LNPJeZBfZgZJ3zX1"))
+            _("Electrum's focus is speed, with low resource usage and simplifying Bitcoin. You do not need to perform regular backups, because your wallet can be recovered from a secret phrase that you can memorize or write on paper. Startup times are instant because it operates in conjuction with high-performance servers that handle the most complicated parts of the Bitcoin system."))
 
     def show_report_bug(self):
         QMessageBox.information(self, "Electrum - " + _("Reporting Bugs"),
-            _("Email bug reports to %s") % "genjix" + "@" + "riseup.net")
+            _("Please report any bugs as issues on github: <a href=\"https://github.com/spesmilo/electrum/issues\">https://github.com/spesmilo/electrum/issues</a>"))
 
     def show_history(self, toggle_state):
         if toggle_state:
+            self.main_layout.setRowMinimumHeight(3,200)
             self.history_list.show()
         else:
+            self.main_layout.setRowMinimumHeight(3,0)
             self.history_list.hide()
 
     def backup_wallet(self):
@@ -560,7 +703,7 @@ class MiniActuator:
         """Retrieve the gui theme used in previous session."""
         self.wallet = wallet
         self.theme_name = self.wallet.config.get('litegui_theme','Cleanlook')
-        self.themes = util.load_theme_paths()
+        self.themes = load_theme_paths()
 
     def load_theme(self):
         """Load theme retrieved from wallet file."""
@@ -600,66 +743,6 @@ class MiniActuator:
         """Change the wallet fiat currency country."""
         self.wallet.config.set_key('conversion_currency',conversion_currency,True)
 
-    def set_servers_gui_stuff(self, servers_menu, servers_group):
-        self.servers_menu = servers_menu
-        self.servers_group = servers_group
-
-    def populate_servers_menu(self):
-        interface = self.wallet.interface
-        if not interface.servers:
-            print "No servers loaded yet."
-            self.servers_list = []
-            for server_string in DEFAULT_SERVERS:
-                host, port, protocol = server_string.split(':')
-                transports = [(protocol,port)]
-                self.servers_list.append((host, transports))
-        else:
-            print "Servers loaded."
-            self.servers_list = interface.servers
-        server_names = [details[0] for details in self.servers_list]
-        current_server = interface.server.split(":")[0]
-        for server_name in server_names:
-            server_action = self.servers_menu.addAction(server_name)
-            server_action.setCheckable(True)
-            if server_name == current_server:
-                server_action.setChecked(True)
-            class SelectServerFunctor:
-                def __init__(self, server_name, server_selected):
-                    self.server_name = server_name
-                    self.server_selected = server_selected
-                def __call__(self, checked):
-                    if checked:
-                        # call server_selected
-                        self.server_selected(self.server_name)
-            delegate = SelectServerFunctor(server_name, self.server_selected)
-            server_action.toggled.connect(delegate)
-            self.servers_group.addAction(server_action)
-
-    def update_servers_list(self):
-        # Clear servers_group
-        for action in self.servers_group.actions():
-            self.servers_group.removeAction(action)
-        self.populate_servers_menu()
-
-    def server_selected(self, server_name):
-        match = [transports for (host, transports) in self.servers_list
-                 if host == server_name]
-        assert len(match) == 1
-        match = match[0]
-        # Default to TCP if available else use anything
-        # TODO: protocol should be selectable.
-        tcp_port = [port for (protocol, port) in match if protocol == "t"]
-        if len(tcp_port) == 0:
-            protocol = match[0][0]
-            port = match[0][1]
-        else:
-            protocol = "t"
-            port = tcp_port[0]
-        server_line = "%s:%s:%s" % (server_name, port, protocol)
-
-        # Should this have exception handling?
-        self.wallet.interface.set_server(server_line, self.wallet.config.get("proxy"))
-
     def copy_address(self, receive_popup):
         """Copy the wallet addresses into the client."""
         addrs = [addr for addr in self.wallet.all_addresses()
@@ -671,6 +754,67 @@ class MiniActuator:
         receive_popup.setup(copied_address)
         receive_popup.popup()
 
+    def waiting_dialog(self, f):
+        s = Timer()
+        s.start()
+        w = QDialog()
+        w.resize(200, 70)
+        w.setWindowTitle('Electrum')
+        l = QLabel('Sending transaction, please wait.')
+        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 csv_transaction(self):
+        try:
+          fileName = QFileDialog.getSaveFileName(QWidget(), 'Select file to export your wallet transactions to', os.path.expanduser('~/'), "*.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 self.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, self.wallet.num_zeros)
+                    else:
+                        value_string = '--'
+
+                    if fee is not None:
+                        fee_string = format_satoshis(fee, True, self.wallet.num_zeros)
+                    else:
+                        fee_string = '0'
+
+                    if tx_hash:
+                        label, is_default_label = self.wallet.get_label(tx_hash)
+                    else:
+                      label = ""
+
+                    balance_string = format_satoshis(balance, False, self.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 succesfully created.")
+        except (IOError, os.error), reason:
+          QMessageBox.critical(None,"Unable to create csv", "Electrum was unable to produce a transaction export.\n" + str(reason))
+
     def send(self, address, amount, parent_window):
         """Send bitcoins to the target address."""
         dest_address = self.fetch_destination(address)
@@ -699,12 +843,17 @@ class MiniActuator:
             fee = bitcoin(1) / 1000
 
         try:
-            tx = self.wallet.mktx(dest_address, amount, "", password, fee)
+            tx = self.wallet.mktx([(dest_address, amount)], "", password, fee)
         except BaseException as error:
             QMessageBox.warning(parent_window, _('Error'), str(error), _('OK'))
             return False
-            
-        status, message = self.wallet.sendtx(tx)
+
+        h = self.wallet.send_tx(tx)
+
+        self.waiting_dialog(lambda: False if self.wallet.tx_event.isSet() else _("Sending transaction, please wait..."))
+          
+        status, message = self.wallet.receive_tx(h)
+
         if not status:
             import tempfile
             dumpf = tempfile.NamedTemporaryFile(delete=False)
@@ -713,9 +862,10 @@ class MiniActuator:
             print "Dumped error tx to", dumpf.name
             QMessageBox.warning(parent_window, _('Error'), message, _('OK'))
             return False
-
-        QMessageBox.information(parent_window, '',
-            _('Payment sent.') + '\n' + message, _('OK'))
+      
+        TransactionWindow(message, self)
+#        QMessageBox.information(parent_window, '',
+#            _('Your transaction has been sent.') + '\n' + message, _('OK'))
         return True
 
     def fetch_destination(self, address):
@@ -741,10 +891,17 @@ class MiniActuator:
 
     def is_valid(self, address):
         """Check if bitcoin address is valid."""
+
         return self.wallet.is_valid(address)
 
+    def copy_master_public_key(self):
+        master_pubkey = self.wallet.master_public_key
+        qApp.clipboard().setText(master_pubkey)
+        QMessageBox.information(None,"Copy succesful", "Your public master key has been copied to your clipboard.")
+        
+
     def acceptbit(self, currency):
-        master_pubkey = self.wallet.master_public_key.encode("hex")
+        master_pubkey = self.wallet.master_public_key
         url = "http://acceptbit.com/mpk/%s/%s" % (master_pubkey, currency)
         webbrowser.open(url)
 
@@ -764,7 +921,9 @@ class MiniDriver(QObject):
         self.wallet = wallet
         self.window = window
 
-        self.wallet.register_callback(self.update_callback)
+        self.wallet.interface.register_callback('updated',self.update_callback)
+        self.wallet.interface.register_callback('connected', self.update_callback)
+        self.wallet.interface.register_callback('disconnected', self.update_callback)
 
         self.state = None
 
@@ -783,9 +942,7 @@ class MiniDriver(QObject):
             self.initializing()
         elif not self.wallet.interface.is_connected:
             self.connecting()
-        elif not self.wallet.blocks == -1:
-            self.connecting()
-        elif not self.wallet.is_up_to_date:
+        elif not self.wallet.up_to_date:
             self.synchronizing()
         else:
             self.ready()
@@ -836,6 +993,7 @@ class MiniDriver(QObject):
         tx_history = self.wallet.get_tx_history()
         self.window.update_history(tx_history)
 
+
 if __name__ == "__main__":
     app = QApplication(sys.argv)
     with open(rsrc("style.css")) as style_file: