tMerge pull request #2911 from SomberNight/pyqt5 - electrum - Electrum Bitcoin wallet
 (HTM) git clone https://git.parazyd.org/electrum
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
       ---
 (DIR) commit 99bc43d8db3879b1118ca8b3db44dbb9152c8da8
 (DIR) parent c43b48f4f59d3214bbb3fa851d6e039f086adb45
 (HTM) Author: ThomasV <thomasv@electrum.org>
       Date:   Sun, 24 Sep 2017 09:42:32 +0200
       
       Merge pull request #2911 from SomberNight/pyqt5
       
       migration to PyQt5
       Diffstat:
         M README.rst                          |       6 +++---
         M gui/qt/__init__.py                  |      30 ++++++++++++++++++++----------
         M gui/qt/address_dialog.py            |       6 +++---
         M gui/qt/amountedit.py                |       7 ++++---
         M gui/qt/console.py                   |      13 +++++++------
         M gui/qt/contact_list.py              |       8 +++++---
         M gui/qt/fee_slider.py                |       9 +++++----
         M gui/qt/installwizard.py             |      23 +++++++++++++----------
         M gui/qt/invoice_list.py              |       4 ++--
         M gui/qt/main_window.py               |      70 ++++++++++++++++++-------------
         M gui/qt/network_dialog.py            |      38 ++++++++++++++++---------------
         M gui/qt/password_dialog.py           |       4 ++--
         M gui/qt/paytoedit.py                 |       5 +++--
         M gui/qt/qrcodewidget.py              |      13 ++++++++-----
         M gui/qt/qrtextedit.py                |       7 ++++---
         M gui/qt/qrwindow.py                  |       9 +++++----
         M gui/qt/request_list.py              |       7 ++++---
         M gui/qt/seed_dialog.py               |       4 ++--
         M gui/qt/transaction_dialog.py        |       8 ++++----
         M gui/qt/util.py                      |      23 ++++++++++++-----------
         M lib/plot.py                         |       4 ++--
         M plugins/audio_modem/qt.py           |       5 +++--
         M plugins/cosigner_pool/qt.py         |      17 +++++++++++------
         M plugins/digitalbitbox/qt.py         |       2 +-
         M plugins/email_requests/qt.py        |      19 ++++++++++++-------
         M plugins/greenaddress_instant/qt.py  |       2 +-
         M plugins/hw_wallet/qt.py             |       2 +-
         M plugins/labels/qt.py                |      15 ++++++++++-----
         M plugins/ledger/auth2fa.py           |       5 +++--
         M plugins/ledger/qt.py                |       6 +++---
         M plugins/trezor/qt_generic.py        |       8 ++++----
         M plugins/trustedcoin/qt.py           |      16 ++++++++++++----
         M plugins/virtualkeyboard/qt.py       |       3 ++-
         M setup-release.py                    |       2 +-
       
       34 files changed, 232 insertions(+), 168 deletions(-)
       ---
 (DIR) diff --git a/README.rst b/README.rst
       t@@ -23,7 +23,7 @@ Getting started
        Electrum is a pure python application. If you want to use the
        Qt interface, install the Qt dependencies::
        
       -    sudo apt-get install python3-pyqt4
       +    sudo apt-get install python3-pyqt5
        
        If you downloaded the official package (tar.gz), you can run
        Electrum from its root directory, without installing it on your
       t@@ -60,8 +60,8 @@ Run install (this should install dependencies)::
        
        Compile the icons file for Qt::
        
       -    sudo apt-get install pyqt4-dev-tools
       -    pyrcc4 icons.qrc -o gui/qt/icons_rc.py -py3
       +    sudo apt-get install pyqt5-dev-tools
       +    pyrcc5 icons.qrc -o gui/qt/icons_rc.py
        
        Compile the protobuf description file::
        
 (DIR) diff --git a/gui/qt/__init__.py b/gui/qt/__init__.py
       t@@ -28,13 +28,14 @@ import os
        import signal
        
        try:
       -    import PyQt4
       +    import PyQt5
        except Exception:
       -    sys.exit("Error: Could not import PyQt4 on Linux systems, you may try 'sudo apt-get install python3-pyqt4'")
       +    sys.exit("Error: Could not import PyQt5 on Linux systems, you may try 'sudo apt-get install python3-pyqt5'")
        
       -from PyQt4.QtGui import *
       -from PyQt4.QtCore import *
       -import PyQt4.QtCore as QtCore
       +from PyQt5.QtGui import *
       +from PyQt5.QtWidgets import *
       +from PyQt5.QtCore import *
       +import PyQt5.QtCore as QtCore
        
        from electrum.i18n import _, set_language
        from electrum.plugins import run_hook
       t@@ -52,7 +53,7 @@ try:
        except Exception as e:
            print(e)
            print("Error: Could not find icons file.")
       -    print("Please run 'pyrcc4 icons.qrc -o gui/qt/icons_rc.py -py3', and reinstall Electrum")
       +    print("Please run 'pyrcc5 icons.qrc -o gui/qt/icons_rc.py', and reinstall Electrum")
            sys.exit(1)
        
        from .util import *   # * needed for plugins
       t@@ -73,6 +74,13 @@ class OpenFileEventFilter(QObject):
                return False
        
        
       +class QElectrumApplication(QApplication):
       +    new_window_signal = pyqtSignal(str, object)
       +
       +
       +class QNetworkUpdatedSignalObject(QObject):
       +    network_updated_signal = pyqtSignal(str, object)
       +
        
        class ElectrumGui:
        
       t@@ -88,10 +96,11 @@ class ElectrumGui:
                self.plugins = plugins
                self.windows = []
                self.efilter = OpenFileEventFilter(self.windows)
       -        self.app = QApplication(sys.argv)
       +        self.app = QElectrumApplication(sys.argv)
                self.app.installEventFilter(self.efilter)
                self.timer = Timer()
                self.nd = None
       +        self.network_updated_signal_obj = QNetworkUpdatedSignalObject()
                # init tray
                self.dark_icon = self.config.get("dark_icon", False)
                self.tray = QSystemTrayIcon(self.tray_icon(), None)
       t@@ -99,7 +108,7 @@ class ElectrumGui:
                self.tray.activated.connect(self.tray_activated)
                self.build_tray_menu()
                self.tray.show()
       -        self.app.connect(self.app, QtCore.SIGNAL('new_window'), self.start_new_window)
       +        self.app.new_window_signal.connect(self.start_new_window)
                run_hook('init_qt', self)
        
            def build_tray_menu(self):
       t@@ -141,7 +150,7 @@ class ElectrumGui:
        
            def new_window(self, path, uri=None):
                # Use a signal as can be called from daemon thread
       -        self.app.emit(SIGNAL('new_window'), path, uri)
       +        self.app.new_window_signal.emit(path, uri)
        
            def show_network_dialog(self, parent):
                if not self.daemon.network:
       t@@ -152,7 +161,8 @@ class ElectrumGui:
                    self.nd.show()
                    self.nd.raise_()
                    return
       -        self.nd = NetworkDialog(self.daemon.network, self.config)
       +        self.nd = NetworkDialog(self.daemon.network, self.config,
       +                                self.network_updated_signal_obj)
                self.nd.show()
        
            def create_window_for_wallet(self, wallet):
 (DIR) diff --git a/gui/qt/address_dialog.py b/gui/qt/address_dialog.py
       t@@ -30,9 +30,9 @@ from __future__ import unicode_literals
        import six
        from electrum.i18n import _
        
       -import PyQt4
       -from PyQt4.QtGui import *
       -from PyQt4.QtCore import *
       +import PyQt5
       +from PyQt5.QtGui import *
       +from PyQt5.QtCore import *
        
        from .util import *
        from .history_list import HistoryList
 (DIR) diff --git a/gui/qt/amountedit.py b/gui/qt/amountedit.py
       t@@ -5,8 +5,9 @@ from __future__ import print_function
        from __future__ import unicode_literals
        
        import six
       -from PyQt4.QtCore import *
       -from PyQt4.QtGui import *
       +from PyQt5.QtCore import *
       +from PyQt5.QtGui import *
       +from PyQt5.QtWidgets import (QLineEdit, QStyle, QStyleOptionFrame)
        
        from decimal import Decimal
        from electrum.util import format_satoshis_plain
       t@@ -59,7 +60,7 @@ class AmountEdit(MyLineEdit):
            def paintEvent(self, event):
                QLineEdit.paintEvent(self, event)
                if self.base_unit:
       -            panel = QStyleOptionFrameV2()
       +            panel = QStyleOptionFrame()
                    self.initStyleOption(panel)
                    textRect = self.style().subElementRect(QStyle.SE_LineEditContents, panel, self)
                    textRect.adjust(2, 0, -10, 0)
 (DIR) diff --git a/gui/qt/console.py b/gui/qt/console.py
       t@@ -8,8 +8,9 @@ import six
        
        import sys, os, re
        import traceback, platform
       -from PyQt4 import QtCore
       -from PyQt4 import QtGui
       +from PyQt5 import QtCore
       +from PyQt5 import QtGui
       +from PyQt5 import QtWidgets
        from electrum import util
        
        
       t@@ -21,9 +22,9 @@ else:
            MONOSPACE_FONT = 'monospace'
        
        
       -class Console(QtGui.QPlainTextEdit):
       +class Console(QtWidgets.QPlainTextEdit):
            def __init__(self, prompt='>> ', startup_message='', parent=None):
       -        QtGui.QPlainTextEdit.__init__(self, parent)
       +        QtWidgets.QPlainTextEdit.__init__(self, parent)
        
                self.prompt = prompt
                self.history = []
       t@@ -315,8 +316,8 @@ welcome_message = '''
        '''
        
        if __name__ == '__main__':
       -    app = QtGui.QApplication(sys.argv)
       +    app = QtWidgets.QApplication(sys.argv)
            console = Console(startup_message=welcome_message)
            console.updateNamespace({'myVar1' : app, 'myVar2' : 1234})
       -    console.show();
       +    console.show()
            sys.exit(app.exec_())
 (DIR) diff --git a/gui/qt/contact_list.py b/gui/qt/contact_list.py
       t@@ -35,8 +35,10 @@ from electrum.bitcoin import is_address
        from electrum.util import block_explorer_URL, format_satoshis, format_time, age
        from electrum.plugins import run_hook
        from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED
       -from PyQt4.QtGui import *
       -from PyQt4.QtCore import *
       +from PyQt5.QtGui import *
       +from PyQt5.QtCore import *
       +from PyQt5.QtWidgets import (
       +    QAbstractItemView, QFileDialog, QMenu, QTreeWidgetItem)
        from .util import MyTreeWidget, pr_tooltips, pr_icons
        
        
       t@@ -59,7 +61,7 @@ class ContactList(MyTreeWidget):
        
            def import_contacts(self):
                wallet_folder = self.parent.get_wallet_folder()
       -        filename = QFileDialog.getOpenFileName(self.parent, "Select your wallet file", wallet_folder)
       +        filename, __ = QFileDialog.getOpenFileName(self.parent, "Select your wallet file", wallet_folder)
                if not filename:
                    return
                self.parent.contacts.import_file(filename)
 (DIR) diff --git a/gui/qt/fee_slider.py b/gui/qt/fee_slider.py
       t@@ -6,10 +6,11 @@ from __future__ import unicode_literals
        import six
        from electrum.i18n import _
        
       -import PyQt4
       -from PyQt4.QtGui import *
       -from PyQt4.QtCore import *
       -import PyQt4.QtCore as QtCore
       +import PyQt5
       +from PyQt5.QtGui import *
       +from PyQt5.QtCore import *
       +import PyQt5.QtCore as QtCore
       +from PyQt5.QtWidgets import QSlider, QToolTip
        
        import threading
        
 (DIR) diff --git a/gui/qt/installwizard.py b/gui/qt/installwizard.py
       t@@ -7,9 +7,9 @@ import six
        import sys
        import os
        
       -from PyQt4.QtGui import *
       -from PyQt4.QtCore import *
       -import PyQt4.QtCore as QtCore
       +from PyQt5.QtGui import *
       +from PyQt5.QtCore import *
       +import PyQt5.QtCore as QtCore
        
        import electrum
        from electrum import Wallet, WalletStorage
       t@@ -101,6 +101,9 @@ def wizard_dialog(func):
        # WindowModalDialog must come first as it overrides show_error
        class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
        
       +    accept_signal = pyqtSignal()
       +    synchronized_signal = pyqtSignal(str)
       +
            def __init__(self, config, app, plugins, storage):
                BaseWizard.__init__(self, config, storage)
                QDialog.__init__(self, None)
       t@@ -111,7 +114,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
                self.plugins = plugins
                self.language_for_seed = config.get('language')
                self.setMinimumSize(600, 400)
       -        self.connect(self, QtCore.SIGNAL('accept'), self.accept)
       +        self.accept_signal.connect(self.accept)
                self.title = QLabel()
                self.main_widget = QWidget()
                self.back_button = QPushButton(_("Back"), self)
       t@@ -176,7 +179,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
                wallet_folder = os.path.dirname(self.storage.path)
        
                def on_choose():
       -            path = QFileDialog.getOpenFileName(self, "Select your wallet file", wallet_folder)
       +            path, __ = QFileDialog.getOpenFileName(self, "Select your wallet file", wallet_folder)
                    if path:
                        self.name_e.setText(path)
        
       t@@ -227,11 +230,11 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
                            self.storage.decrypt(password)
                            break
                        except InvalidPassword as e:
       -                    QMessageBox.information(None, _('Error'), str(e), _('OK'))
       +                    QMessageBox.information(None, _('Error'), str(e))
                            continue
                        except BaseException as e:
                            traceback.print_exc(file=sys.stdout)
       -                    QMessageBox.information(None, _('Error'), str(e), _('OK'))
       +                    QMessageBox.information(None, _('Error'), str(e))
                            return
        
                path = self.storage.path
       t@@ -408,8 +411,8 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
                            msg = _("Recovery successful")
                        else:
                            msg = _("No transactions found for this seed")
       -                self.emit(QtCore.SIGNAL('synchronized'), msg)
       -            self.connect(self, QtCore.SIGNAL('synchronized'), self.show_message)
       +                self.synchronized_signal.emit(msg)
       +            self.synchronized_signal.connect(self.show_message)
                    t = threading.Thread(target = task)
                    t.daemon = True
                    t.start()
       t@@ -436,7 +439,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
                self.run(action)
        
            def terminate(self):
       -        self.emit(QtCore.SIGNAL('accept'))
       +        self.accept_signal.emit()
        
            def waiting_dialog(self, task, msg):
                self.please_wait.setText(MSG_GENERATING_WAIT)
 (DIR) diff --git a/gui/qt/invoice_list.py b/gui/qt/invoice_list.py
       t@@ -40,7 +40,7 @@ class InvoiceList(MyTreeWidget):
            def __init__(self, parent):
                MyTreeWidget.__init__(self, parent, self.create_menu, [_('Expires'), _('Requestor'), _('Description'), _('Amount'), _('Status')], 2)
                self.setSortingEnabled(True)
       -        self.header().setResizeMode(1, QHeaderView.Interactive)
       +        self.header().setSectionResizeMode(1, QHeaderView.Interactive)
                self.setColumnWidth(1, 200)
        
            def on_update(self):
       t@@ -64,7 +64,7 @@ class InvoiceList(MyTreeWidget):
        
            def import_invoices(self):
                wallet_folder = self.parent.get_wallet_folder()
       -        filename = QFileDialog.getOpenFileName(self.parent, "Select your wallet file", wallet_folder)
       +        filename, __ = QFileDialog.getOpenFileName(self.parent, "Select your wallet file", wallet_folder)
                if not filename:
                    return
                self.parent.invoices.import_file(filename)
 (DIR) diff --git a/gui/qt/main_window.py b/gui/qt/main_window.py
       t@@ -33,10 +33,10 @@ from decimal import Decimal
        import base64
        from functools import partial
        
       -import PyQt4
       -from PyQt4.QtGui import *
       -from PyQt4.QtCore import *
       -import PyQt4.QtCore as QtCore
       +import PyQt5
       +from PyQt5.QtGui import *
       +from PyQt5.QtCore import *
       +import PyQt5.QtCore as QtCore
        
        from electrum.util import bh2u, bfh
        from . import icons_rc
       t@@ -81,7 +81,7 @@ class StatusBarButton(QPushButton):
                self.setIconSize(QSize(25,25))
        
            def onPress(self, checked=False):
       -        '''Drops the unwanted PyQt4 "checked" argument'''
       +        '''Drops the unwanted PyQt5 "checked" argument'''
                self.func()
        
            def keyPressEvent(self, e):
       t@@ -94,6 +94,15 @@ from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED
        
        class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
        
       +    payment_request_ok_signal = pyqtSignal()
       +    payment_request_error_signal = pyqtSignal()
       +    new_fx_quotes_signal = pyqtSignal()
       +    new_fx_history_signal = pyqtSignal()
       +    network_signal = pyqtSignal(str, object)
       +    alias_received_signal = pyqtSignal()
       +    computing_privkeys_signal = pyqtSignal()
       +    show_privkeys_signal = pyqtSignal()
       +
            def __init__(self, gui_object, wallet):
                QMainWindow.__init__(self)
        
       t@@ -167,13 +176,13 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
                for i in range(wrtabs.count()):
                    QShortcut(QKeySequence("Alt+" + str(i + 1)), self, lambda i=i: wrtabs.setCurrentIndex(i))
        
       -        self.connect(self, QtCore.SIGNAL('payment_request_ok'), self.payment_request_ok)
       -        self.connect(self, QtCore.SIGNAL('payment_request_error'), self.payment_request_error)
       +        self.payment_request_ok_signal.connect(self.payment_request_ok)
       +        self.payment_request_error_signal.connect(self.payment_request_error)
                self.history_list.setFocus(True)
        
                # network callbacks
                if self.network:
       -            self.connect(self, QtCore.SIGNAL('network'), self.on_network_qt)
       +            self.network_signal.connect(self.on_network_qt)
                    interests = ['updated', 'new_transaction', 'status',
                                 'banner', 'verified', 'fee']
                    # To avoid leaking references to "self" that prevent the
       t@@ -185,8 +194,8 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
                    self.console.showMessage(self.network.banner)
                    self.network.register_callback(self.on_quotes, ['on_quotes'])
                    self.network.register_callback(self.on_history, ['on_history'])
       -            self.connect(self, SIGNAL('new_fx_quotes'), self.on_fx_quotes)
       -            self.connect(self, SIGNAL('new_fx_history'), self.on_fx_history)
       +            self.new_fx_quotes_signal.connect(self.on_fx_quotes)
       +            self.new_fx_history_signal.connect(self.on_fx_history)
        
                # update fee slider in case we missed the callback
                self.fee_slider.update()
       t@@ -195,7 +204,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
                self.fetch_alias()
        
            def on_history(self, b):
       -        self.emit(SIGNAL('new_fx_history'))
       +        self.new_fx_history_signal.emit()
        
            def on_fx_history(self):
                self.history_list.refresh_headers()
       t@@ -203,7 +212,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
                self.address_list.update()
        
            def on_quotes(self, b):
       -        self.emit(SIGNAL('new_fx_quotes'))
       +        self.new_fx_quotes_signal.emit()
        
            def on_fx_quotes(self):
                self.update_status()
       t@@ -275,17 +284,18 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
            def on_network(self, event, *args):
                if event == 'updated':
                    self.need_update.set()
       -            self.emit(QtCore.SIGNAL('updated'), event, *args)
       +            self.gui_object.network_updated_signal_obj.network_updated_signal \
       +                .emit(event, args)
        
                elif event == 'new_transaction':
                    self.tx_notifications.append(args[0])
                elif event in ['status', 'banner', 'verified', 'fee']:
                    # Handle in GUI thread
       -            self.emit(QtCore.SIGNAL('network'), event, *args)
       +            self.network_signal.emit(event, args)
                else:
                    self.print_error("unexpected network message:", event, args)
        
       -    def on_network_qt(self, event, *args):
       +    def on_network_qt(self, event, args=None):
                # Handle a network message in the GUI thread
                if event == 'status':
                    self.update_status()
       t@@ -307,7 +317,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
                    alias = str(alias)
                    def f():
                        self.alias_info = self.contacts.resolve_openalias(alias)
       -                self.emit(SIGNAL('alias_received'))
       +                self.alias_received_signal.emit()
                    t = threading.Thread(target=f)
                    t.setDaemon(True)
                    t.start()
       t@@ -380,7 +390,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
        
            def open_wallet(self):
                wallet_folder = self.get_wallet_folder()
       -        filename = QFileDialog.getOpenFileName(self, "Select your wallet file", wallet_folder)
       +        filename, __ = QFileDialog.getOpenFileName(self, "Select your wallet file", wallet_folder)
                if not filename:
                    return
                self.gui_object.new_window(filename)
       t@@ -389,7 +399,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
            def backup_wallet(self):
                path = self.wallet.storage.path
                wallet_folder = os.path.dirname(path)
       -        filename = QFileDialog.getSaveFileName(self, _('Enter a filename for the copy of your wallet'), wallet_folder)
       +        filename, __ = QFileDialog.getSaveFileName(self, _('Enter a filename for the copy of your wallet'), wallet_folder)
                if not filename:
                    return
        
       t@@ -574,7 +584,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
            # custom wrappers for getOpenFileName and getSaveFileName, that remember the path selected by the user
            def getOpenFileName(self, title, filter = ""):
                directory = self.config.get('io_dir', os.path.expanduser('~'))
       -        fileName = QFileDialog.getOpenFileName(self, title, directory, filter)
       +        fileName, __ = QFileDialog.getOpenFileName(self, title, directory, filter)
                if fileName and directory != os.path.dirname(fileName):
                    self.config.set_key('io_dir', os.path.dirname(fileName), True)
                return fileName
       t@@ -582,13 +592,13 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
            def getSaveFileName(self, title, filename, filter = ""):
                directory = self.config.get('io_dir', os.path.expanduser('~'))
                path = os.path.join( directory, filename )
       -        fileName = QFileDialog.getSaveFileName(self, title, path, filter)
       +        fileName, __ = QFileDialog.getSaveFileName(self, title, path, filter)
                if fileName and directory != os.path.dirname(fileName):
                    self.config.set_key('io_dir', os.path.dirname(fileName), True)
                return fileName
        
            def connect_slots(self, sender):
       -        self.connect(sender, QtCore.SIGNAL('timersignal'), self.timer_actions)
       +        sender.timer_signal.connect(self.timer_actions)
        
            def timer_actions(self):
                # Note this runs in the GUI thread
       t@@ -1499,9 +1509,9 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
            def on_pr(self, request):
                self.payment_request = request
                if self.payment_request.verify(self.contacts):
       -            self.emit(SIGNAL('payment_request_ok'))
       +            self.payment_request_ok_signal.emit()
                else:
       -            self.emit(SIGNAL('payment_request_error'))
       +            self.payment_request_error_signal.emit()
        
            def pay_to_URI(self, URI):
                if not URI:
       t@@ -1558,7 +1568,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
                w.searchable_list = l
                vbox = QVBoxLayout()
                w.setLayout(vbox)
       -        vbox.setMargin(0)
       +        vbox.setContentsMargins(0, 0, 0, 0)
                vbox.setSpacing(0)
                vbox.addWidget(l)
                buttons = QWidget()
       t@@ -2121,16 +2131,16 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
                        if done:
                            break
                        private_keys[addr] = "\n".join(self.wallet.get_private_key(addr, password))
       -                d.emit(SIGNAL('computing_privkeys'))
       -            d.emit(SIGNAL('show_privkeys'))
       +                self.computing_privkeys_signal.emit()
       +            self.show_privkeys_signal.emit()
        
                def show_privkeys():
                    s = "\n".join( map( lambda x: x[0] + "\t"+ x[1], private_keys.items()))
                    e.setText(s)
                    b.setEnabled(True)
        
       -        d.connect(d, QtCore.SIGNAL('computing_privkeys'), lambda: e.setText("Please wait... %d/%d"%(len(private_keys),len(addresses))))
       -        d.connect(d, QtCore.SIGNAL('show_privkeys'), show_privkeys)
       +        self.computing_privkeys_signal.connect(lambda: e.setText("Please wait... %d/%d"%(len(private_keys),len(addresses))))
       +        self.show_privkeys_signal.connect(show_privkeys)
                threading.Thread(target=privkeys_thread).start()
        
                if not d.exec_():
       t@@ -2470,7 +2480,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
                    if alias:
                        self.fetch_alias()
                set_alias_color()
       -        self.connect(self, SIGNAL('alias_received'), set_alias_color)
       +        self.alias_received_signal.connect(set_alias_color)
                alias_e.editingFinished.connect(on_alias_edit)
                id_widgets.append((alias_label, alias_e))
        
       t@@ -2730,7 +2740,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
                if self.fx:
                    self.fx.timeout = 0
        
       -        self.disconnect(self, SIGNAL('alias_received'), set_alias_color)
       +        self.alias_received_signal.disconnect(set_alias_color)
        
                run_hook('close_settings_dialog')
                if self.need_restart:
 (DIR) diff --git a/gui/qt/network_dialog.py b/gui/qt/network_dialog.py
       t@@ -31,9 +31,9 @@ from __future__ import unicode_literals
        
        import socket
        import six
       -from PyQt4.QtGui import *
       -from PyQt4.QtCore import *
       -import PyQt4.QtCore as QtCore
       +from PyQt5.QtGui import *
       +from PyQt5.QtCore import *
       +import PyQt5.QtCore as QtCore
        
        from electrum.i18n import _
        from electrum.network import DEFAULT_PORTS
       t@@ -45,19 +45,21 @@ protocol_names = ['TCP', 'SSL']
        protocol_letters = 'ts'
        
        class NetworkDialog(QDialog):
       -    def __init__(self, network, config):
       +    def __init__(self, network, config, network_updated_signal_obj):
                QDialog.__init__(self)
                self.setWindowTitle(_('Network'))
                self.setMinimumSize(500, 20)
                self.nlayout = NetworkChoiceLayout(network, config)
       +        self.network_updated_signal_obj = network_updated_signal_obj
                vbox = QVBoxLayout(self)
                vbox.addLayout(self.nlayout.layout())
                vbox.addLayout(Buttons(CloseButton(self)))
       -        self.connect(self, QtCore.SIGNAL('updated'), self.on_update)
       +        self.network_updated_signal_obj.network_updated_signal.connect(
       +            self.on_update)
                network.register_callback(self.on_network, ['updated', 'interfaces'])
        
            def on_network(self, event, *args):
       -        self.emit(QtCore.SIGNAL('updated'), event, *args)
       +        self.network_updated_signal_obj.network_updated_signal.emit(event, args)
        
            def on_update(self):
                self.nlayout.update()
       t@@ -97,7 +99,7 @@ class NodesListWidget(QTreeWidget):
                # on 'enter' we show the menu
                pt = self.visualItemRect(item).bottomLeft()
                pt.setX(50)
       -        self.emit(SIGNAL('customContextMenuRequested(const QPoint&)'), pt)
       +        self.customContextMenuRequested.emit(pt)
        
            def update(self, network):
                self.clear()
       t@@ -125,8 +127,8 @@ class NodesListWidget(QTreeWidget):
        
                h = self.header()
                h.setStretchLastSection(False)
       -        h.setResizeMode(0, QHeaderView.Stretch)
       -        h.setResizeMode(1, QHeaderView.ResizeToContents)
       +        h.setSectionResizeMode(0, QHeaderView.Stretch)
       +        h.setSectionResizeMode(1, QHeaderView.ResizeToContents)
        
        
        class ServerListWidget(QTreeWidget):
       t@@ -163,7 +165,7 @@ class ServerListWidget(QTreeWidget):
                # on 'enter' we show the menu
                pt = self.visualItemRect(item).bottomLeft()
                pt.setX(50)
       -        self.emit(SIGNAL('customContextMenuRequested(const QPoint&)'), pt)
       +        self.customContextMenuRequested.emit(pt)
        
            def update(self, servers, protocol, use_tor):
                self.clear()
       t@@ -179,8 +181,8 @@ class ServerListWidget(QTreeWidget):
        
                h = self.header()
                h.setStretchLastSection(False)
       -        h.setResizeMode(0, QHeaderView.Stretch)
       -        h.setResizeMode(1, QHeaderView.ResizeToContents)
       +        h.setSectionResizeMode(0, QHeaderView.Stretch)
       +        h.setSectionResizeMode(1, QHeaderView.ResizeToContents)
        
        
        class NetworkChoiceLayout(object):
       t@@ -251,13 +253,13 @@ class NetworkChoiceLayout(object):
                self.proxy_password.editingFinished.connect(self.set_proxy)
        
                self.check_disable_proxy()
       -        self.proxy_mode.connect(self.proxy_mode, SIGNAL('currentIndexChanged(int)'), self.check_disable_proxy)
       +        self.proxy_mode.currentIndexChanged.connect(self.check_disable_proxy)
        
       -        self.proxy_mode.connect(self.proxy_mode, SIGNAL('currentIndexChanged(int)'), self.proxy_settings_changed)
       -        self.proxy_host.connect(self.proxy_host, SIGNAL('textEdited(QString)'), self.proxy_settings_changed)
       -        self.proxy_port.connect(self.proxy_port, SIGNAL('textEdited(QString)'), self.proxy_settings_changed)
       -        self.proxy_user.connect(self.proxy_user, SIGNAL('textEdited(QString)'), self.proxy_settings_changed)
       -        self.proxy_password.connect(self.proxy_password, SIGNAL('textEdited(QString)'), self.proxy_settings_changed)
       +        self.proxy_mode.currentIndexChanged.connect(self.proxy_settings_changed)
       +        self.proxy_host.textEdited.connect(self.proxy_settings_changed)
       +        self.proxy_port.textEdited.connect(self.proxy_settings_changed)
       +        self.proxy_user.textEdited.connect(self.proxy_settings_changed)
       +        self.proxy_password.textEdited.connect(self.proxy_settings_changed)
        
                self.tor_cb = QCheckBox(_("Use Tor Proxy"))
                self.tor_cb.setIcon(QIcon(":icons/tor_logo.png"))
 (DIR) diff --git a/gui/qt/password_dialog.py b/gui/qt/password_dialog.py
       t@@ -28,8 +28,8 @@ from __future__ import print_function
        from __future__ import unicode_literals
        
        import six
       -from PyQt4.QtGui import *
       -from PyQt4.QtCore import *
       +from PyQt5.QtGui import *
       +from PyQt5.QtCore import *
        from electrum.i18n import _
        from .util import *
        import re
 (DIR) diff --git a/gui/qt/paytoedit.py b/gui/qt/paytoedit.py
       t@@ -28,8 +28,9 @@ from __future__ import print_function
        from __future__ import unicode_literals
        
        import six
       -from PyQt4.QtCore import *
       -from PyQt4.QtGui import *
       +from PyQt5.QtCore import *
       +from PyQt5.QtGui import *
       +from PyQt5.QtWidgets import QCompleter, QPlainTextEdit
        from .qrtextedit import ScanQRTextEdit
        
        import re
 (DIR) diff --git a/gui/qt/qrcodewidget.py b/gui/qt/qrcodewidget.py
       t@@ -4,9 +4,11 @@ from __future__ import print_function
        from __future__ import unicode_literals
        
        import six
       -from PyQt4.QtGui import *
       -from PyQt4.QtCore import *
       -import PyQt4.QtGui as QtGui
       +from PyQt5.QtGui import *
       +from PyQt5.QtCore import *
       +import PyQt5.QtGui as QtGui
       +from PyQt5.QtWidgets import (
       +    QApplication, QVBoxLayout, QTextEdit, QHBoxLayout, QPushButton, QWidget)
        
        import os
        import qrcode
       t@@ -95,6 +97,7 @@ class QRDialog(WindowModalDialog):
        
                vbox = QVBoxLayout()
                qrw = QRCodeWidget(data)
       +        qscreen = QApplication.primaryScreen()
                vbox.addWidget(qrw, 1)
                if show_text:
                    text = QTextEdit()
       t@@ -109,12 +112,12 @@ class QRDialog(WindowModalDialog):
                    filename = os.path.join(config.path, "qrcode.png")
        
                    def print_qr():
       -                p = QPixmap.grabWindow(qrw.winId())
       +                p = qscreen.grabWindow(qrw.winId())
                        p.save(filename, 'png')
                        self.show_message(_("QR code saved to file") + " " + filename)
        
                    def copy_to_clipboard():
       -                p = QPixmap.grabWindow(qrw.winId())
       +                p = qscreen.grabWindow(qrw.winId())
                        p.save(filename, 'png')
                        QApplication.clipboard().setImage(QImage(filename))
                        self.show_message(_("QR code copied to clipboard"))
 (DIR) diff --git a/gui/qt/qrtextedit.py b/gui/qt/qrtextedit.py
       t@@ -6,8 +6,9 @@ from __future__ import unicode_literals
        import six
        from electrum.i18n import _
        from electrum.plugins import run_hook
       -from PyQt4.QtGui import *
       -from PyQt4.QtCore import *
       +from PyQt5.QtGui import *
       +from PyQt5.QtCore import *
       +from PyQt5.QtWidgets import QFileDialog
        
        from .util import ButtonsTextEdit, MessageBoxMixin
        
       t@@ -45,7 +46,7 @@ class ScanQRTextEdit(ButtonsTextEdit, MessageBoxMixin):
                run_hook('scan_text_edit', self)
        
            def file_input(self):
       -        fileName = QFileDialog.getOpenFileName(self, 'select file')
       +        fileName, __ = QFileDialog.getOpenFileName(self, 'select file')
                if not fileName:
                    return
                with open(fileName, "r") as f:
 (DIR) diff --git a/gui/qt/qrwindow.py b/gui/qt/qrwindow.py
       t@@ -32,10 +32,11 @@ import re
        import platform
        from decimal import Decimal
        
       -from PyQt4.QtGui import *
       -from PyQt4.QtCore import *
       -import PyQt4.QtCore as QtCore
       -import PyQt4.QtGui as QtGui
       +from PyQt5.QtGui import *
       +from PyQt5.QtCore import *
       +import PyQt5.QtCore as QtCore
       +import PyQt5.QtGui as QtGui
       +from PyQt5.QtWidgets import (QHBoxLayout, QVBoxLayout, QLabel, QWidget)
        
        from electrum_gui.qt.qrcodewidget import QRCodeWidget
        from electrum.i18n import _
 (DIR) diff --git a/gui/qt/request_list.py b/gui/qt/request_list.py
       t@@ -33,8 +33,9 @@ from electrum.i18n import _
        from electrum.util import block_explorer_URL, format_satoshis, format_time, age
        from electrum.plugins import run_hook
        from electrum.paymentrequest import PR_UNPAID, PR_PAID, PR_UNKNOWN, PR_EXPIRED
       -from PyQt4.QtGui import *
       -from PyQt4.QtCore import *
       +from PyQt5.QtGui import *
       +from PyQt5.QtCore import *
       +from PyQt5.QtWidgets import QTreeWidgetItem, QMenu
        from .util import MyTreeWidget, pr_tooltips, pr_icons
        
        
       t@@ -53,7 +54,7 @@ class RequestList(MyTreeWidget):
            def item_changed(self, item):
                if item is None:
                    return
       -        if not self.isItemSelected(item):
       +        if not item.isSelected():
                    return
                addr = str(item.text(1))
                req = self.wallet.receive_requests[addr]
 (DIR) diff --git a/gui/qt/seed_dialog.py b/gui/qt/seed_dialog.py
       t@@ -28,8 +28,8 @@ from __future__ import print_function
        from __future__ import unicode_literals
        
        import six
       -from PyQt4.QtGui import *
       -from PyQt4.QtCore import *
       +from PyQt5.QtGui import *
       +from PyQt5.QtCore import *
        from electrum.i18n import _
        
        from .util import *
 (DIR) diff --git a/gui/qt/transaction_dialog.py b/gui/qt/transaction_dialog.py
       t@@ -32,10 +32,10 @@ import copy
        import datetime
        import json
        
       -import PyQt4
       -from PyQt4.QtGui import *
       -from PyQt4.QtCore import *
       -import PyQt4.QtCore as QtCore
       +import PyQt5
       +from PyQt5.QtGui import *
       +from PyQt5.QtCore import *
       +import PyQt5.QtCore as QtCore
        
        from electrum import transaction
        from electrum.bitcoin import base_encode
 (DIR) diff --git a/gui/qt/util.py b/gui/qt/util.py
       t@@ -15,8 +15,9 @@ from collections import namedtuple
        from functools import partial
        
        from electrum.i18n import _
       -from PyQt4.QtGui import *
       -from PyQt4.QtCore import *
       +from PyQt5.QtGui import *
       +from PyQt5.QtCore import *
       +from PyQt5.QtWidgets import *
        
        if platform.system() == 'Windows':
            MONOSPACE_FONT = 'Lucida Console'
       t@@ -57,10 +58,11 @@ expiration_values = [
        
        class Timer(QThread):
            stopped = False
       +    timer_signal = pyqtSignal()
        
            def run(self):
                while not self.stopped:
       -            self.emit(SIGNAL('timersignal'))
       +            self.timer_signal.emit()
                    time.sleep(0.5)
        
            def stop(self):
       t@@ -111,7 +113,7 @@ class HelpLabel(QLabel):
                self.font = QFont()
        
            def mouseReleaseEvent(self, x):
       -        QMessageBox.information(self, 'Help', self.help_text, 'OK')
       +        QMessageBox.information(self, 'Help', self.help_text)
        
            def enterEvent(self, event):
                self.font.setUnderline(True)
       t@@ -135,7 +137,7 @@ class HelpButton(QPushButton):
                self.clicked.connect(self.onclick)
        
            def onclick(self):
       -        QMessageBox.information(self, 'Help', self.help_text, 'OK')
       +        QMessageBox.information(self, 'Help', self.help_text)
        
        class Buttons(QHBoxLayout):
            def __init__(self, *buttons):
       t@@ -349,7 +351,7 @@ def filename_field(parent, config, defaultname, select_msg):
            def func():
                text = filename_e.text()
                _filter = "*.csv" if text.endswith(".csv") else "*.json" if text.endswith(".json") else None
       -        p = QFileDialog.getSaveFileName(None, select_msg, text, _filter)
       +        p, __ = QFileDialog.getSaveFileName(None, select_msg, text, _filter)
                if p:
                    filename_e.setText(p)
        
       t@@ -405,7 +407,7 @@ class MyTreeWidget(QTreeWidget):
                self.header().setStretchLastSection(False)
                for col in range(len(headers)):
                    sm = QHeaderView.Stretch if col == self.stretch_column else QHeaderView.ResizeToContents
       -            self.header().setResizeMode(col, sm)
       +            self.header().setSectionResizeMode(col, sm)
        
            def editItem(self, item, column):
                if column in self.editable_columns:
       t@@ -436,13 +438,12 @@ class MyTreeWidget(QTreeWidget):
                # on 'enter' we show the menu
                pt = self.visualItemRect(item).bottomLeft()
                pt.setX(50)
       -        self.emit(SIGNAL('customContextMenuRequested(const QPoint&)'), pt)
       +        self.customContextMenuRequested.emit(pt)
        
            def createEditor(self, parent, option, index):
                self.editor = QStyledItemDelegate.createEditor(self.itemDelegate(),
                                                               parent, option, index)
       -        self.editor.connect(self.editor, SIGNAL("editingFinished()"),
       -                            self.editing_finished)
       +        self.editor.editingFinished.connect(self.editing_finished)
                return self.editor
        
            def editing_finished(self):
       t@@ -603,6 +604,6 @@ class TaskThread(QThread):
        
        if __name__ == "__main__":
            app = QApplication([])
       -    t = WaitingDialog(None, 'testing ...', lambda: [time.sleep(1)], lambda x: QMessageBox.information(None, 'done', "done", _('OK')))
       +    t = WaitingDialog(None, 'testing ...', lambda: [time.sleep(1)], lambda x: QMessageBox.information(None, 'done', "done"))
            t.start()
            app.exec_()
 (DIR) diff --git a/lib/plot.py b/lib/plot.py
       t@@ -1,4 +1,4 @@
       -from PyQt4.QtGui import *
       +from PyQt5.QtGui import *
        from electrum.i18n import _
        
        
       t@@ -9,7 +9,7 @@ from electrum.util import format_satoshis
        from electrum.bitcoin import COIN
        
        import matplotlib
       -matplotlib.use('Qt4Agg')
       +matplotlib.use('Qt5Agg')
        import matplotlib.pyplot as plt
        import matplotlib.dates as md
        from matplotlib.patches import Ellipse
 (DIR) diff --git a/plugins/audio_modem/qt.py b/plugins/audio_modem/qt.py
       t@@ -10,8 +10,9 @@ from electrum_gui.qt.util import WaitingDialog, EnterButton, WindowModalDialog
        from electrum.util import print_msg, print_error
        from electrum.i18n import _
        
       -from PyQt4.QtGui import *
       -from PyQt4.QtCore import *
       +from PyQt5.QtGui import *
       +from PyQt5.QtCore import *
       +from PyQt5.QtWidgets import (QComboBox, QGridLayout, QLabel, QPushButton)
        
        try:
            import amodem.audio
 (DIR) diff --git a/plugins/cosigner_pool/qt.py b/plugins/cosigner_pool/qt.py
       t@@ -28,8 +28,9 @@ import threading
        import time
        from xmlrpc.client import ServerProxy
        
       -from PyQt4.QtGui import *
       -from PyQt4.QtCore import *
       +from PyQt5.QtGui import *
       +from PyQt5.QtCore import *
       +from PyQt5.QtWidgets import QPushButton
        
        from electrum import bitcoin, util
        from electrum import transaction
       t@@ -82,19 +83,23 @@ class Listener(util.DaemonThread):
                        if message:
                            self.received.add(keyhash)
                            self.print_error("received message for", keyhash)
       -                    self.parent.obj.emit(SIGNAL("cosigner:receive"), keyhash,
       -                                         message)
       +                    self.parent.obj.cosigner_receive_signal.emit(
       +                        keyhash, message)
                    # poll every 30 seconds
                    time.sleep(30)
        
        
       +class QReceiveSignalObject(QObject):
       +    cosigner_receive_signal = pyqtSignal(object, object)
       +
       +
        class Plugin(BasePlugin):
        
            def __init__(self, parent, config, name):
                BasePlugin.__init__(self, parent, config, name)
                self.listener = None
       -        self.obj = QObject()
       -        self.obj.connect(self.obj, SIGNAL('cosigner:receive'), self.on_receive)
       +        self.obj = QReceiveSignalObject()
       +        self.obj.cosigner_receive_signal.connect(self.on_receive)
                self.keys = []
                self.cosigner_list = []
        
 (DIR) diff --git a/plugins/digitalbitbox/qt.py b/plugins/digitalbitbox/qt.py
       t@@ -1,4 +1,4 @@
       -from PyQt4.Qt import (QInputDialog, QLineEdit)
       +from PyQt5.QtWidgets import (QInputDialog, QLineEdit)
        from ..hw_wallet.qt import QtHandlerBase, QtPluginBase
        from .digitalbitbox import DigitalBitboxPlugin
        
 (DIR) diff --git a/plugins/email_requests/qt.py b/plugins/email_requests/qt.py
       t@@ -35,10 +35,11 @@ from email.mime.multipart import MIMEMultipart
        from email.mime.base import MIMEBase
        from email.encoders import encode_base64
        
       -from PyQt4.QtGui import *
       -from PyQt4.QtCore import *
       -import PyQt4.QtCore as QtCore
       -import PyQt4.QtGui as QtGui
       +from PyQt5.QtGui import *
       +from PyQt5.QtCore import *
       +import PyQt5.QtCore as QtCore
       +import PyQt5.QtGui as QtGui
       +from PyQt5.QtWidgets import (QVBoxLayout, QLabel, QGridLayout, QLineEdit)
        
        from electrum.plugins import BasePlugin, hook
        from electrum.paymentrequest import PaymentRequest
       t@@ -102,6 +103,10 @@ class Processor(threading.Thread):
                s.quit()
        
        
       +class QEmailSignalObject(QObject):
       +    email_new_invoice_signal = pyqtSignal()
       +
       +
        class Plugin(BasePlugin):
        
            def fullname(self):
       t@@ -121,13 +126,13 @@ class Plugin(BasePlugin):
                if self.imap_server and self.username and self.password:
                    self.processor = Processor(self.imap_server, self.username, self.password, self.on_receive)
                    self.processor.start()
       -        self.obj = QObject()
       -        self.obj.connect(self.obj, SIGNAL('email:new_invoice'), self.new_invoice)
       +        self.obj = QEmailSignalObject()
       +        self.obj.email_new_invoice_signal.connect(self.new_invoice)
        
            def on_receive(self, pr_str):
                self.print_error('received payment request')
                self.pr = PaymentRequest(pr_str)
       -        self.obj.emit(SIGNAL('email:new_invoice'))
       +        self.obj.email_new_invoice_signal.emit()
        
            def new_invoice(self):
                self.parent.invoices.add(self.pr)
 (DIR) diff --git a/plugins/greenaddress_instant/qt.py b/plugins/greenaddress_instant/qt.py
       t@@ -28,7 +28,7 @@ import urllib
        import sys
        import requests
        
       -from PyQt4.QtGui import QApplication, QPushButton
       +from PyQt5.QtWidgets import QApplication, QPushButton
        
        from electrum.plugins import BasePlugin, hook
        from electrum.i18n import _
 (DIR) diff --git a/plugins/hw_wallet/qt.py b/plugins/hw_wallet/qt.py
       t@@ -26,7 +26,7 @@
        
        import threading
        
       -from PyQt4.Qt import QVBoxLayout, QLabel, SIGNAL
       +from PyQt5.Qt import QVBoxLayout, QLabel
        from electrum_gui.qt.password_dialog import PasswordDialog, PW_PASSPHRASE
        from electrum_gui.qt.util import *
        
 (DIR) diff --git a/plugins/labels/qt.py b/plugins/labels/qt.py
       t@@ -1,7 +1,8 @@
        from functools import partial
        
       -from PyQt4.QtGui import *
       -from PyQt4.QtCore import *
       +from PyQt5.QtGui import *
       +from PyQt5.QtCore import *
       +from PyQt5.QtWidgets import (QHBoxLayout, QLabel, QVBoxLayout)
        
        from electrum.plugins import hook
        from electrum.i18n import _
       t@@ -12,11 +13,15 @@ from electrum_gui.qt.util import WindowModalDialog, OkButton
        from .labels import LabelsPlugin
        
        
       +class QLabelsSignalObject(QObject):
       +    labels_changed_signal = pyqtSignal(object)
       +
       +
        class Plugin(LabelsPlugin):
        
            def __init__(self, *args):
                LabelsPlugin.__init__(self, *args)
       -        self.obj = QObject()
       +        self.obj = QLabelsSignalObject()
        
            def requires_settings(self):
                return True
       t@@ -47,14 +52,14 @@ class Plugin(LabelsPlugin):
                return bool(d.exec_())
        
            def on_pulled(self, wallet):
       -        self.obj.emit(SIGNAL('labels_changed'), wallet)
       +        self.obj.labels_changed_signal.emit(wallet)
        
            def done_processing(self, dialog, result):
                dialog.show_message(_("Your labels have been synchronised."))
        
            @hook
            def on_new_window(self, window):
       -        window.connect(window.app, SIGNAL('labels_changed'), window.update_tabs)
       +        self.obj.labels_changed_signal.connect(window.update_tabs)
                self.start_wallet(window.wallet)
        
            @hook
 (DIR) diff --git a/plugins/ledger/auth2fa.py b/plugins/ledger/auth2fa.py
       t@@ -1,8 +1,9 @@
        from binascii import hexlify, unhexlify
        import threading
        
       -from PyQt4.Qt import (QDialog, QInputDialog, QLineEdit, QTextEdit, QVBoxLayout, QLabel, SIGNAL)
       -import PyQt4.QtCore as QtCore
       +from PyQt5.Qt import (QDialog, QInputDialog, QLineEdit, QTextEdit, QVBoxLayout, QLabel)
       +import PyQt5.QtCore as QtCore
       +from PyQt5.QtWidgets import *
        
        from electrum.i18n import _
        from electrum_gui.qt.util import *
 (DIR) diff --git a/plugins/ledger/qt.py b/plugins/ledger/qt.py
       t@@ -1,8 +1,8 @@
        import threading
        
       -from PyQt4.Qt import (QDialog, QInputDialog, QLineEdit,
       -                      QVBoxLayout, QLabel, SIGNAL)
       -import PyQt4.QtCore as QtCore
       +from PyQt5.Qt import (QDialog, QInputDialog, QLineEdit,
       +                      QVBoxLayout, QLabel)
       +import PyQt5.QtCore as QtCore
        
        from electrum.i18n import _
        from .ledger import LedgerPlugin
 (DIR) diff --git a/plugins/trezor/qt_generic.py b/plugins/trezor/qt_generic.py
       t@@ -1,9 +1,9 @@
        from functools import partial
        import threading
        
       -from PyQt4.Qt import Qt
       -from PyQt4.Qt import QGridLayout, QInputDialog, QPushButton
       -from PyQt4.Qt import QVBoxLayout, QLabel, SIGNAL
       +from PyQt5.Qt import Qt
       +from PyQt5.Qt import QGridLayout, QInputDialog, QPushButton
       +from PyQt5.Qt import QVBoxLayout, QLabel
        from electrum_gui.qt.util import *
        from .plugin import TIM_NEW, TIM_RECOVER, TIM_MNEMONIC
        from ..hw_wallet.qt import QtHandlerBase, QtPluginBase
       t@@ -377,7 +377,7 @@ class SettingsDialog(WindowModalDialog):
                def change_homescreen():
                    from PIL import Image  # FIXME
                    dialog = QFileDialog(self, _("Choose Homescreen"))
       -            filename = dialog.getOpenFileName()
       +            filename, __ = dialog.getOpenFileName()
                    if filename:
                        im = Image.open(str(filename))
                        if im.size != (hs_cols, hs_rows):
 (DIR) diff --git a/plugins/trustedcoin/qt.py b/plugins/trustedcoin/qt.py
       t@@ -28,8 +28,8 @@ from threading import Thread
        import re
        from decimal import Decimal
        
       -from PyQt4.QtGui import *
       -from PyQt4.QtCore import *
       +from PyQt5.QtGui import *
       +from PyQt5.QtCore import *
        
        from electrum_gui.qt.util import *
        from electrum_gui.qt.qrcodewidget import QRCodeWidget
       t@@ -40,8 +40,16 @@ from electrum.plugins import hook
        from .trustedcoin import TrustedCoinPlugin, server
        
        
       +class QTOSSignalObject(QObject):
       +    two_factor_tos_signal = pyqtSignal()
       +
       +
        class Plugin(TrustedCoinPlugin):
        
       +    def __init__(self, parent, config, name):
       +        super().__init__(parent, config, name)
       +        self.tos_signal_obj = QTOSSignalObject()
       +
            @hook
            def on_new_window(self, window):
                wallet = window.wallet
       t@@ -196,7 +204,7 @@ class Plugin(TrustedCoinPlugin):
                def request_TOS():
                    tos = server.get_terms_of_service()
                    self.TOS = tos
       -            window.emit(SIGNAL('twofactor:TOS'))
       +            self.tos_signal_obj.two_factor_tos_signal.emit()
        
                def on_result():
                    tos_e.setText(self.TOS)
       t@@ -204,7 +212,7 @@ class Plugin(TrustedCoinPlugin):
                def set_enabled():
                    next_button.setEnabled(re.match(regexp,email_e.text()) is not None)
        
       -        window.connect(window, SIGNAL('twofactor:TOS'), on_result)
       +        self.tos_signal_obj.two_factor_tos_signal.connect(on_result)
                t = Thread(target=request_TOS)
                t.setDaemon(True)
                t.start()
 (DIR) diff --git a/plugins/virtualkeyboard/qt.py b/plugins/virtualkeyboard/qt.py
       t@@ -1,4 +1,5 @@
       -from PyQt4.QtGui import *
       +from PyQt5.QtGui import *
       +from PyQt5.QtWidgets import (QVBoxLayout, QGridLayout, QPushButton)
        from electrum.plugins import BasePlugin, hook
        from electrum.i18n import _
        import random
 (DIR) diff --git a/setup-release.py b/setup-release.py
       t@@ -34,7 +34,7 @@ if sys.platform == 'darwin':
                setup_requires=['py2app'],
                app=[mainscript],
                options=dict(py2app=dict(argv_emulation=False,
       -                                 includes=['PyQt4.QtCore', 'PyQt4.QtGui', 'PyQt4.QtWebKit', 'PyQt4.QtNetwork', 'sip'],
       +                                 includes=['PyQt5.QtCore', 'PyQt5.QtGui', 'PyQt5.QtWebKit', 'PyQt5.QtNetwork', 'sip'],
                                         packages=['lib', 'gui', 'plugins'],
                                         iconfile='electrum.icns',
                                         plist=plist,