Browse Source

Merge pull request #899 from Tafelpoot/qrcode_fix2

QR code fixes
283
ThomasV 10 years ago
parent
commit
bfbd6f0e9d
  1. 2
      gui/qt/installwizard.py
  2. 64
      gui/qt/main_window.py
  3. 15
      gui/qt/paytoedit.py
  4. 2
      gui/qt/qrcodewidget.py
  5. 48
      gui/qt/qrtextedit.py
  6. 11
      gui/qt/seed_dialog.py
  7. 4
      gui/qt/util.py
  8. 15
      lib/qrscanner.py

2
gui/qt/installwizard.py

@ -128,7 +128,7 @@ class InstallWizard(QDialog):
def enter_seed_dialog(self, msg, sid, func=None):
if func is None:
func = self.is_any
vbox, seed_e = seed_dialog.enter_seed_box(msg, sid)
vbox, seed_e = seed_dialog.enter_seed_box(msg, self, sid)
vbox.addStretch(1)
hbox, button = ok_cancel_buttons2(self, _('Next'))
vbox.addLayout(hbox)

64
gui/qt/main_window.py

@ -45,7 +45,7 @@ from electrum import Imported_Wallet
from amountedit import AmountEdit, BTCAmountEdit, MyLineEdit
from network_dialog import NetworkDialog
from qrcodewidget import QRCodeWidget, QRDialog
from qrtextedit import QRTextEdit
from qrtextedit import ScanQRTextEdit, ShowQRTextEdit
from decimal import Decimal
@ -1828,15 +1828,36 @@ class ElectrumWindow(QMainWindow):
main_layout = QGridLayout()
mpk_dict = self.wallet.get_master_public_keys()
i = 0
for key, value in mpk_dict.items():
main_layout.addWidget(QLabel(key), i, 0)
mpk_text = QRTextEdit()
mpk_text.setReadOnly(True)
# filter out the empty keys (PendingAccount)
mpk_dict = {acc:mpk for acc,mpk in mpk_dict.items() if mpk}
# only show the combobox in case multiple accounts are available
if len(mpk_dict) > 1:
main_layout.addWidget(QLabel(_("Select Account")), 0, 0)
combobox = QComboBox()
for name in mpk_dict:
combobox.addItem(name)
combobox.setCurrentIndex(0)
main_layout.addWidget(combobox, 1, 0)
account = unicode(combobox.currentText())
mpk_text = ShowQRTextEdit(text=mpk_dict[account])
mpk_text.setMaximumHeight(170)
mpk_text.selectAll() # for easy copying
main_layout.addWidget(mpk_text, 2, 0)
def show_mpk(account):
mpk = mpk_dict.get(unicode(account), "")
mpk_text.setText(mpk)
combobox.currentIndexChanged[str].connect(lambda acc: show_mpk(acc))
elif len(mpk_dict) == 1:
mpk = mpk_dict.values()[0]
mpk_text = ShowQRTextEdit(text=mpk)
mpk_text.setMaximumHeight(170)
mpk_text.setText(value)
main_layout.addWidget(mpk_text, i + 1, 0)
i += 2
mpk_text.selectAll() # for easy copying
main_layout.addWidget(mpk_text, 2, 0)
vbox = QVBoxLayout()
vbox.addLayout(main_layout)
@ -1845,7 +1866,6 @@ class ElectrumWindow(QMainWindow):
dialog.setLayout(vbox)
dialog.exec_()
@protected
def show_seed_dialog(self, password):
if not self.wallet.has_seed():
@ -1900,9 +1920,7 @@ class ElectrumWindow(QMainWindow):
vbox = QVBoxLayout()
vbox.addWidget( QLabel(_("Address") + ': ' + address))
vbox.addWidget( QLabel(_("Public key") + ':'))
keys = QRTextEdit()
keys.setReadOnly(True)
keys.setText('\n'.join(pubkey_list))
keys = ShowQRTextEdit(text='\n'.join(pubkey_list))
vbox.addWidget(keys)
vbox.addLayout(close_button(d))
d.setLayout(vbox)
@ -1924,9 +1942,7 @@ class ElectrumWindow(QMainWindow):
vbox = QVBoxLayout()
vbox.addWidget( QLabel(_("Address") + ': ' + address))
vbox.addWidget( QLabel(_("Private key") + ':'))
keys = QRTextEdit()
keys.setReadOnly(True)
keys.setText('\n'.join(pk_list))
keys = ShowQRTextEdit(text='\n'.join(pk_list))
vbox.addWidget(keys)
vbox.addLayout(close_button(d))
d.setLayout(vbox)
@ -2128,6 +2144,12 @@ class ElectrumWindow(QMainWindow):
def read_tx_from_qrcode(self):
from electrum import qrscanner
if qrscanner.proc is None:
try:
qrscanner.init(self.config)
except Exception, e:
QMessageBox.warning(self, _('Error'), _(e), _('OK'))
return
try:
data = qrscanner.scan_qr(self.config)
except BaseException, e:
@ -2135,12 +2157,14 @@ class ElectrumWindow(QMainWindow):
return
if not data:
return
# if the user scanned a bitcoin URI
if data.startswith("bitcoin:"):
self.pay_from_URI(data)
return
# else if the user scanned an offline signed tx
# transactions are binary, but qrcode seems to return utf8...
z = data.decode('utf8')
s = ''
for b in z:
s += chr(ord(b))
data = s.encode('hex')
data = ''.join(chr(ord(b)) for b in z).encode('hex')
tx = self.tx_from_text(data)
if not tx:
return

15
gui/qt/paytoedit.py

@ -18,7 +18,7 @@
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from qrtextedit import QRTextEdit
from qrtextedit import ScanQRTextEdit
import re
from decimal import Decimal
@ -30,11 +30,9 @@ RE_ALIAS = '(.*?)\s*\<([1-9A-HJ-NP-Za-km-z]{26,})\>'
frozen_style = "QWidget { background-color:none; border:none;}"
normal_style = "QPlainTextEdit { }"
class PayToEdit(QRTextEdit):
class PayToEdit(ScanQRTextEdit):
def __init__(self, win):
QRTextEdit.__init__(self)
self.win = win
super(PayToEdit,self).__init__(win=win)
self.amount_edit = win.amount_e
self.document().contentsChanged.connect(self.update_size)
self.heightMin = 0
@ -235,3 +233,10 @@ class PayToEdit(QRTextEdit):
cr = self.cursorRect()
cr.setWidth(self.c.popup().sizeHintForColumn(0) + self.c.popup().verticalScrollBar().sizeHint().width())
self.c.complete(cr)
def qr_input(self):
data = super(PayToEdit,self).qr_input()
if data.startswith("bitcoin:"):
self.scan_f(data)
# TODO: update fee

2
gui/qt/qrcodewidget.py

@ -114,7 +114,7 @@ class QRDialog(QDialog):
def copy_to_clipboard():
bmp.save_qrcode(qrw.qr, filename)
self.parent().app.clipboard().setImage(QImage(filename))
QApplication.clipboard().setImage(QImage(filename))
QMessageBox.information(None, _('Message'), _("QR code saved to clipboard"), _('OK'))
b = QPushButton(_("Copy"))

48
gui/qt/qrtextedit.py

@ -3,14 +3,13 @@ from PyQt4.QtGui import *
from PyQt4.QtCore import *
class QRTextEdit(QPlainTextEdit):
"""Abstract class for QR-code related TextEdits. Do not use directly."""
def __init__(self, text=None):
QPlainTextEdit.__init__(self, text)
super(QRTextEdit, self).__init__(text)
self.button = QToolButton(self)
self.button.setIcon(QIcon(":icons/qrcode.png"))
self.button.setStyleSheet("QToolButton { border: none; padding: 0px; }")
self.button.setVisible(True)
self.button.clicked.connect(lambda: self.qr_show() if self.isReadOnly() else self.qr_input())
self.setText = self.setPlainText
def resizeEvent(self, e):
@ -21,13 +20,11 @@ class QRTextEdit(QPlainTextEdit):
(self.rect().bottom() - frameWidth - sz.height()))
return o
def contextMenuEvent(self, e):
m = self.createStandardContextMenu()
if self.isReadOnly():
m.addAction(_("Show as QR code"), self.qr_show)
else:
m.addAction(_("Read QR code"), self.qr_input)
m.exec_(e.globalPos())
class ShowQRTextEdit(QRTextEdit):
def __init__(self, text=None):
super(ShowQRTextEdit, self).__init__(text)
self.setReadOnly(1)
self.button.clicked.connect(self.qr_show)
def qr_show(self):
from qrcodewidget import QRDialog
@ -37,13 +34,42 @@ class QRTextEdit(QPlainTextEdit):
s = unicode(self.toPlainText())
QRDialog(s).exec_()
def contextMenuEvent(self, e):
m = self.createStandardContextMenu()
m.addAction(_("Show as QR code"), self.qr_show)
m.exec_(e.globalPos())
class ScanQRTextEdit(QRTextEdit):
def __init__(self, win, text=""):
super(ScanQRTextEdit,self).__init__(text)
self.setReadOnly(0)
self.win = win
assert win, "You must pass a window with access to the config to ScanQRTextEdit constructor."
if win:
assert hasattr(win,"config"), "You must pass a window with access to the config to ScanQRTextEdit constructor."
self.button.clicked.connect(self.qr_input)
def qr_input(self):
from electrum import qrscanner
if qrscanner.proc is None:
try:
qrscanner.init(self.win.config)
except Exception, e:
QMessageBox.warning(self, _('Error'), _(e), _('OK'))
return
try:
data = qrscanner.scan_qr(self.win.config)
except BaseException, e:
QMessageBox.warning(self.win, _('Error'), _(e), _('OK'))
QMessageBox.warning(self, _('Error'), _(e), _('OK'))
return
if type(data) != str:
return
self.setText(data)
return data
def contextMenuEvent(self, e):
m = self.createStandardContextMenu()
m.addAction(_("Read QR code"), self.qr_input)
m.exec_(e.globalPos())

11
gui/qt/seed_dialog.py

@ -23,7 +23,7 @@ from electrum.i18n import _
from electrum import mnemonic
from qrcodewidget import QRCodeWidget, QRDialog
from util import close_button
from qrtextedit import QRTextEdit
from qrtextedit import ShowQRTextEdit, ScanQRTextEdit
class SeedDialog(QDialog):
def __init__(self, parent, seed, imported_keys):
@ -72,15 +72,13 @@ def show_seed_box(seed, sid=None):
+ _("If you ever need to recover your wallet from seed, you will need both this seed and your cold seed.") + " " \
label1 = QLabel(msg+ ":")
seed_text = QRTextEdit(seed)
seed_text.setReadOnly(True)
seed_text = ShowQRTextEdit(text=seed)
seed_text.setMaximumHeight(130)
label2 = QLabel(msg2)
label2.setWordWrap(True)
logo = QLabel()
logo.setPixmap(QPixmap(icon_filename(sid)).scaledToWidth(56))
logo.setMaximumWidth(60)
@ -96,8 +94,7 @@ def show_seed_box(seed, sid=None):
return vbox
def enter_seed_box(msg, sid=None):
def enter_seed_box(msg, window, sid=None):
vbox = QVBoxLayout()
logo = QLabel()
logo.setPixmap(QPixmap(icon_filename(sid)).scaledToWidth(56))
@ -106,7 +103,7 @@ def enter_seed_box(msg, sid=None):
label = QLabel(msg)
label.setWordWrap(True)
seed_e = QRTextEdit()
seed_e = ScanQRTextEdit(win=window)
seed_e.setMaximumHeight(100)
seed_e.setTabChangesFocus(True)

4
gui/qt/util.py

@ -137,7 +137,7 @@ def line_dialog(parent, title, label, ok_label, default=None):
return unicode(txt.text())
def text_dialog(parent, title, label, ok_label, default=None):
from qrtextedit import QRTextEdit
from qrtextedit import ScanQRTextEdit
dialog = QDialog(parent)
dialog.setMinimumWidth(500)
dialog.setWindowTitle(title)
@ -145,7 +145,7 @@ def text_dialog(parent, title, label, ok_label, default=None):
l = QVBoxLayout()
dialog.setLayout(l)
l.addWidget(QLabel(label))
txt = QRTextEdit()
txt = ScanQRTextEdit(parent)
if default:
txt.setText(default)
l.addWidget(txt)

15
lib/qrscanner.py

@ -6,28 +6,37 @@ try:
except ImportError:
zbar = None
proc = None
def scan_qr(config):
def init(config):
if not zbar:
raise BaseException("\n".join([_("Cannot start QR scanner."),_("The zbar package is not available."),_("On Linux, try 'sudo apt-get install python-zbar'")]))
device = config.get("video_device", "default")
if device == 'default':
device = ''
global proc
proc = zbar.Processor()
proc.init(video_device=device)
def scan_qr(self):
if not zbar:
raise BaseException("\n".join([_("Cannot start QR scanner."),_("The zbar package is not available."),_("On Linux, try 'sudo apt-get install python-zbar'")]))
if proc is None:
raise BaseException("Start proc first")
proc.visible = True
while True:
try:
proc.process_one()
except Exception:
# User closed the preview window
return {}
return ""
for r in proc.results:
if str(r.type) != 'QRCODE':
continue
# hiding the preview window stops the camera
proc.visible = False
return r.data
def _find_system_cameras():
device_root = "/sys/class/video4linux"
devices = {} # Name -> device

Loading…
Cancel
Save