Browse Source

Merge #248: Convert JoinmarketQt to PySide2, qt5reactor

8e5826d Convert JoinmarketQt to PySide2 (AdamISZ)
master
AdamISZ 7 years ago
parent
commit
5907cc253a
No known key found for this signature in database
GPG Key ID: 141001A1AF77F20B
  1. 4
      jmclient/setup.py
  2. 112
      scripts/joinmarket-qt.py
  3. 108
      scripts/qtsupport.py

4
jmclient/setup.py

@ -9,5 +9,7 @@ setup(name='joinmarketclient',
author_email='', author_email='',
license='GPL', license='GPL',
packages=['jmclient'], packages=['jmclient'],
install_requires=['future', 'configparser;python_version<"3.2"', 'joinmarketbase==0.4.2', 'mnemonic', 'qt4reactor', 'argon2_cffi', 'bencoder.pyx', 'pyaes'], install_requires=['future', 'configparser;python_version<"3.2"',
'joinmarketbase==0.4.2', 'mnemonic', 'argon2_cffi',
'bencoder.pyx', 'pyaes'],
zip_safe=False) zip_safe=False)

112
scripts/joinmarket-qt.py

@ -24,13 +24,15 @@ Some widgets copied and modified from https://github.com/spesmilo/electrum
''' '''
import sys, datetime, os, logging import sys, datetime, os, logging
import platform, csv, threading, time import platform, json, threading, time
from decimal import Decimal from decimal import Decimal
from PySide2 import QtCore
from PyQt4 import QtCore from PySide2.QtGui import *
from PyQt4.QtGui import *
from PySide2.QtWidgets import *
if platform.system() == 'Windows': if platform.system() == 'Windows':
MONOSPACE_FONT = 'Lucida Console' MONOSPACE_FONT = 'Lucida Console'
@ -41,11 +43,19 @@ else:
import jmbitcoin as btc import jmbitcoin as btc
# This is required to change the decimal separator
# to '.' regardless of the locale; TODO don't require
# this, but will require other edits for parsing amounts.
curL = QtCore.QLocale("en_US")
QtCore.QLocale.setDefault(curL)
app = QApplication(sys.argv) app = QApplication(sys.argv)
if 'twisted.internet.reactor' in sys.modules: if 'twisted.internet.reactor' in sys.modules:
del sys.modules['twisted.internet.reactor'] del sys.modules['twisted.internet.reactor']
from qtreactor import pyqt4reactor
pyqt4reactor.install() import qt5reactor
qt5reactor.install()
#General Joinmarket donation address; TODO #General Joinmarket donation address; TODO
donation_address = "1AZgQZWYRteh6UyF87hwuvyWj73NvWKpL" donation_address = "1AZgQZWYRteh6UyF87hwuvyWj73NvWKpL"
@ -133,7 +143,8 @@ def getSettingsWidgets():
if x[2] == int: if x[2] == int:
qle.setValidator(QIntValidator(*x[4])) qle.setValidator(QIntValidator(*x[4]))
if x[2] == float: if x[2] == float:
qle.setValidator(QDoubleValidator(*x[4])) qdv = QDoubleValidator(*x[4])
qle.setValidator(qdv)
results.append((ql, qle)) results.append((ql, qle))
return results return results
@ -152,7 +163,7 @@ class HelpLabel(QLabel):
self.setStyleSheet(BLUE_FG) self.setStyleSheet(BLUE_FG)
def mouseReleaseEvent(self, x): def mouseReleaseEvent(self, x):
QMessageBox.information(w, self.wtitle, self.help_text, 'OK') QMessageBox.information(w, self.wtitle, self.help_text)
def enterEvent(self, event): def enterEvent(self, event):
self.font.setUnderline(True) self.font.setUnderline(True)
@ -343,14 +354,14 @@ class SpendTab(QWidget):
'Choose Schedule File', 'Choose Schedule File',
directory=current_path) directory=current_path)
#TODO validate the schedule #TODO validate the schedule
log.debug('Looking for schedule in: ' + firstarg) log.debug('Looking for schedule in: ' + str(firstarg))
if not firstarg: if not firstarg:
return return
#extract raw text before processing #extract raw text before processing
with open(firstarg, 'rb') as f: with open(firstarg[0], 'rb') as f:
rawsched = f.read() rawsched = f.read()
res, schedule = get_schedule(firstarg) res, schedule = get_schedule(firstarg[0])
if not res: if not res:
JMQtMessageBox(self, "Not a valid JM schedule file", mbtype='crit', JMQtMessageBox(self, "Not a valid JM schedule file", mbtype='crit',
title='Error') title='Error')
@ -370,7 +381,7 @@ class SpendTab(QWidget):
def updateSchedView(self): def updateSchedView(self):
self.sch_label2.setText(self.spendstate.schedule_name) self.sch_label2.setText(self.spendstate.schedule_name)
self.sched_view.setText(schedule_to_text(self.spendstate.loaded_schedule)) self.sched_view.setText(schedule_to_text(self.spendstate.loaded_schedule).decode('utf-8'))
def getDonateLayout(self): def getDonateLayout(self):
donateLayout = QHBoxLayout() donateLayout = QHBoxLayout()
@ -601,7 +612,7 @@ class SpendTab(QWidget):
return return
destaddr = str(self.widgets[0][1].text()) destaddr = str(self.widgets[0][1].text())
#convert from bitcoins (enforced by QDoubleValidator) to satoshis #convert from bitcoins (enforced by QDoubleValidator) to satoshis
btc_amount_str = str(self.widgets[3][1].text()) btc_amount_str = self.widgets[3][1].text()
amount = int(Decimal(btc_amount_str) * Decimal('1e8')) amount = int(Decimal(btc_amount_str) * Decimal('1e8'))
makercount = int(self.widgets[1][1].text()) makercount = int(self.widgets[1][1].text())
mixdepth = int(self.widgets[2][1].text()) mixdepth = int(self.widgets[2][1].text())
@ -825,10 +836,10 @@ class SpendTab(QWidget):
def persistTxToHistory(self, addr, amt, txid): def persistTxToHistory(self, addr, amt, txid):
#persist the transaction to history #persist the transaction to history
with open(jm_single().config.get("GUI", "history_file"), 'ab') as f: with open(jm_single().config.get("GUI", "history_file"), 'ab') as f:
f.write(','.join([addr, satoshis_to_amt_str(amt), txid, f.write((','.join([addr, satoshis_to_amt_str(amt), txid,
datetime.datetime.now( datetime.datetime.now(
).strftime("%Y/%m/%d %H:%M:%S")])) ).strftime("%Y/%m/%d %H:%M:%S")])).encode('utf-8'))
f.write('\n') #TODO: Windows f.write(b'\n') #TODO: Windows
#update the TxHistory tab #update the TxHistory tab
txhist = w.centralWidget().widget(3) txhist = w.centralWidget().widget(3)
txhist.updateTxInfo() txhist.updateTxInfo()
@ -897,7 +908,7 @@ class SpendTab(QWidget):
"Mixdepth must be chosen.", "Mixdepth must be chosen.",
"Amount, in bitcoins, must be provided."] "Amount, in bitcoins, must be provided."]
for i in range(1, 4): for i in range(1, 4):
if self.widgets[i][1].text().size() == 0: if len(self.widgets[i][1].text()) == 0:
JMQtMessageBox(self, errs[i - 1], mbtype='warn', title="Error") JMQtMessageBox(self, errs[i - 1], mbtype='warn', title="Error")
return False return False
if not w.wallet: if not w.wallet:
@ -917,12 +928,12 @@ class TxHistoryTab(QWidget):
def initUI(self): def initUI(self):
self.tHTW = MyTreeWidget(self, self.create_menu, self.getHeaders()) self.tHTW = MyTreeWidget(self, self.create_menu, self.getHeaders())
self.tHTW.setSelectionMode(QAbstractItemView.ExtendedSelection) self.tHTW.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.tHTW.header().setResizeMode(QHeaderView.Interactive) self.tHTW.header().setSectionResizeMode(QHeaderView.Interactive)
self.tHTW.header().setStretchLastSection(False) self.tHTW.header().setStretchLastSection(False)
self.tHTW.on_update = self.updateTxInfo self.tHTW.on_update = self.updateTxInfo
vbox = QVBoxLayout() vbox = QVBoxLayout()
self.setLayout(vbox) self.setLayout(vbox)
vbox.setMargin(0) vbox.setContentsMargins(0,0,0,0)
vbox.setSpacing(0) vbox.setSpacing(0)
vbox.addWidget(self.tHTW) vbox.addWidget(self.tHTW)
self.updateTxInfo() self.updateTxInfo()
@ -952,7 +963,7 @@ class TxHistoryTab(QWidget):
with open(hf, 'rb') as f: with open(hf, 'rb') as f:
txlines = f.readlines() txlines = f.readlines()
for tl in txlines: for tl in txlines:
txhist.append(tl.strip().split(',')) txhist.append(tl.decode('utf-8').strip().split(','))
if not len(txhist[-1]) == 4: if not len(txhist[-1]) == 4:
JMQtMessageBox(self, JMQtMessageBox(self,
"Incorrectedly formatted file " + hf, "Incorrectedly formatted file " + hf,
@ -1005,15 +1016,13 @@ class JMWalletTab(QWidget):
self.history = v self.history = v
vbox = QVBoxLayout() vbox = QVBoxLayout()
self.setLayout(vbox) self.setLayout(vbox)
vbox.setMargin(0) vbox.setContentsMargins(0,0,0,0)
vbox.setSpacing(0) vbox.setSpacing(0)
vbox.addWidget(self.label1) vbox.addWidget(self.label1)
vbox.addWidget(v) vbox.addWidget(v)
buttons = QWidget() buttons = QWidget()
vbox.addWidget(buttons) vbox.addWidget(buttons)
self.updateWalletInfo() self.updateWalletInfo()
#vBoxLayout.addWidget(self.label2)
#vBoxLayout.addWidget(self.table)
self.show() self.show()
def getHeaders(self): def getHeaders(self):
@ -1090,6 +1099,9 @@ class JMWalletTab(QWidget):
class JMMainWindow(QMainWindow): class JMMainWindow(QMainWindow):
computing_privkeys_signal = QtCore.Signal()
show_privkeys_signal = QtCore.Signal()
def __init__(self, reactor): def __init__(self, reactor):
super(JMMainWindow, self).__init__() super(JMMainWindow, self).__init__()
self.wallet = None self.wallet = None
@ -1127,9 +1139,9 @@ class JMMainWindow(QMainWindow):
aboutAction = QAction('About Joinmarket', self) aboutAction = QAction('About Joinmarket', self)
aboutAction.triggered.connect(self.showAboutDialog) aboutAction.triggered.connect(self.showAboutDialog)
exportPrivAction = QAction('&Export keys', self) exportPrivAction = QAction('&Export keys', self)
exportPrivAction.setStatusTip('Export all private keys to a csv file') exportPrivAction.setStatusTip('Export all private keys to a file')
exportPrivAction.triggered.connect(self.exportPrivkeysCsv) exportPrivAction.triggered.connect(self.exportPrivkeysJson)
menubar = QMenuBar() menubar = self.menuBar()
walletMenu = menubar.addMenu('&Wallet') walletMenu = menubar.addMenu('&Wallet')
walletMenu.addAction(loadAction) walletMenu.addAction(loadAction)
@ -1140,7 +1152,6 @@ class JMMainWindow(QMainWindow):
aboutMenu = menubar.addMenu('&About') aboutMenu = menubar.addMenu('&About')
aboutMenu.addAction(aboutAction) aboutMenu.addAction(aboutAction)
self.setMenuBar(menubar)
self.show() self.show()
def showAboutDialog(self): def showAboutDialog(self):
@ -1171,7 +1182,7 @@ class JMMainWindow(QMainWindow):
lyt.addWidget(btnbox) lyt.addWidget(btnbox)
msgbox.exec_() msgbox.exec_()
def exportPrivkeysCsv(self): def exportPrivkeysJson(self):
if not self.wallet: if not self.wallet:
JMQtMessageBox(self, JMQtMessageBox(self,
"No wallet loaded.", "No wallet loaded.",
@ -1220,8 +1231,8 @@ class JMMainWindow(QMainWindow):
private_keys[addr] = btc.wif_compressed_privkey( private_keys[addr] = btc.wif_compressed_privkey(
priv, priv,
vbyte=get_p2pk_vbyte()) vbyte=get_p2pk_vbyte())
d.emit(QtCore.SIGNAL('computing_privkeys')) self.computing_privkeys_signal.emit()
d.emit(QtCore.SIGNAL('show_privkeys')) self.show_privkeys_signal.emit()
def show_privkeys(): def show_privkeys():
s = "\n".join(map(lambda x: x[0] + "\t" + x[1], private_keys.items( s = "\n".join(map(lambda x: x[0] + "\t" + x[1], private_keys.items(
@ -1229,10 +1240,9 @@ class JMMainWindow(QMainWindow):
e.setText(s) e.setText(s)
b.setEnabled(True) b.setEnabled(True)
d.connect( self.computing_privkeys_signal.connect(lambda: e.setText(
d, QtCore.SIGNAL('computing_privkeys'), "Please wait... %d/%d" % (len(private_keys), len(addresses))))
lambda: e.setText("Please wait... %d/%d" % (len(private_keys), len(addresses)))) self.show_privkeys_signal.connect(show_privkeys)
d.connect(d, QtCore.SIGNAL('show_privkeys'), show_privkeys)
threading.Thread(target=privkeys_thread).start() threading.Thread(target=privkeys_thread).start()
if not d.exec_(): if not d.exec_():
@ -1241,13 +1251,13 @@ class JMMainWindow(QMainWindow):
privkeys_fn_base = 'joinmarket-private-keys' privkeys_fn_base = 'joinmarket-private-keys'
i = 0 i = 0
privkeys_fn = privkeys_fn_base privkeys_fn = privkeys_fn_base
while os.path.isfile(privkeys_fn + '.csv'): # Updated to use json format, simply because L1354 writer
# has some extremely weird behaviour cross Py2/Py3
while os.path.isfile(privkeys_fn + '.json'):
i += 1 i += 1
privkeys_fn = privkeys_fn_base + str(i) privkeys_fn = privkeys_fn_base + str(i)
try: try:
with open(privkeys_fn + '.csv', "w") as f: with open(privkeys_fn + '.json', "wb") as f:
transaction = csv.writer(f)
transaction.writerow(["address", "private_key"])
for addr, pk in private_keys.items(): for addr, pk in private_keys.items():
#sanity check #sanity check
if not addr == btc.pubkey_to_p2sh_p2wpkh_address( if not addr == btc.pubkey_to_p2sh_p2wpkh_address(
@ -1258,20 +1268,20 @@ class JMMainWindow(QMainWindow):
" critical error in key parsing.", " critical error in key parsing.",
mbtype='crit') mbtype='crit')
return return
transaction.writerow(["%34s" % addr, pk]) f.write(json.dumps(private_keys, indent=4).encode('utf-8'))
except (IOError, os.error) as reason: except (IOError, os.error) as reason:
export_error_label = "JoinmarketQt was unable to produce a private key-export." export_error_label = "JoinmarketQt was unable to produce a private key-export."
JMQtMessageBox(None, JMQtMessageBox(None,
export_error_label + "\n" + str(reason), export_error_label + "\n" + str(reason),
mbtype='crit', mbtype='crit',
title="Unable to create csv") title="Unable to create json file")
except Exception as e: except Exception as er:
JMQtMessageBox(self, str(e), mbtype='crit', title="Error") JMQtMessageBox(self, str(er), mbtype='crit', title="Error")
return return
JMQtMessageBox(self, JMQtMessageBox(self,
"Private keys exported to: " + privkeys_fn + '.csv', "Private keys exported to: " + privkeys_fn + '.json',
title="Success") title="Success")
def seedEntry(self): def seedEntry(self):
@ -1287,7 +1297,7 @@ class JMMainWindow(QMainWindow):
pp_field = QLineEdit() pp_field = QLineEdit()
pp_field.setEnabled(False) pp_field.setEnabled(False)
use_pp = QCheckBox('Input Mnemonic Extension', self) use_pp = QCheckBox('Input Mnemonic Extension', self)
use_pp.setCheckState(False) use_pp.setCheckState(QtCore.Qt.CheckState(False))
use_pp.stateChanged.connect(lambda state: pp_field.setEnabled(state use_pp.stateChanged.connect(lambda state: pp_field.setEnabled(state
== QtCore.Qt.Checked)) == QtCore.Qt.Checked))
pp_hbox.addWidget(use_pp) pp_hbox.addWidget(use_pp)
@ -1307,8 +1317,8 @@ class JMMainWindow(QMainWindow):
return None, None return None, None
mn_extension = None mn_extension = None
if use_pp.checkState() == QtCore.Qt.Checked: if use_pp.checkState() == QtCore.Qt.Checked:
mn_extension = str(pp_field.text()) mn_extension = pp_field.text()
return str(message_e.toPlainText()), mn_extension return message_e.toPlainText(), mn_extension
def restartForScan(self, msg): def restartForScan(self, msg):
JMQtMessageBox(self, msg, mbtype='info', JMQtMessageBox(self, msg, mbtype='info',
@ -1341,7 +1351,7 @@ class JMMainWindow(QMainWindow):
directory=current_path, directory=current_path,
options=QFileDialog.DontUseNativeDialog) options=QFileDialog.DontUseNativeDialog)
#TODO validate the file looks vaguely like a wallet file #TODO validate the file looks vaguely like a wallet file
log.debug('Looking for wallet in: ' + firstarg) log.debug('Looking for wallet in: ' + str(firstarg))
if not firstarg: if not firstarg:
return return
decrypted = False decrypted = False
@ -1353,13 +1363,13 @@ class JMMainWindow(QMainWindow):
if not ok: if not ok:
return return
pwd = str(text).strip() pwd = str(text).strip()
decrypted = self.loadWalletFromBlockchain(firstarg, pwd, restart_cb) decrypted = self.loadWalletFromBlockchain(firstarg[0], pwd, restart_cb)
else: else:
if not testnet_seed: if not testnet_seed:
testnet_seed, ok = QInputDialog.getText(self, testnet_seed, ok = QInputDialog.getText(self,
'Load Testnet wallet', 'Load Testnet wallet',
'Enter a testnet seed:', 'Enter a testnet seed:',
mode=QLineEdit.Normal) QLineEdit.Normal)
if not ok: if not ok:
return return
firstarg = str(testnet_seed) firstarg = str(testnet_seed)
@ -1372,7 +1382,7 @@ class JMMainWindow(QMainWindow):
wallet_path = get_wallet_path(str(firstarg), None) wallet_path = get_wallet_path(str(firstarg), None)
try: try:
self.wallet = open_test_wallet_maybe(wallet_path, str(firstarg), self.wallet = open_test_wallet_maybe(wallet_path, str(firstarg),
None, ask_for_password=False, password=pwd, None, ask_for_password=False, password=pwd.encode('utf-8'),
gap_limit=jm_single().config.getint("GUI", "gaplimit")) gap_limit=jm_single().config.getint("GUI", "gaplimit"))
except Exception as e: except Exception as e:
JMQtMessageBox(self, JMQtMessageBox(self,
@ -1438,7 +1448,7 @@ class JMMainWindow(QMainWindow):
seed = self.getTestnetSeed() seed = self.getTestnetSeed()
self.selectWallet(testnet_seed=seed) self.selectWallet(testnet_seed=seed)
else: else:
self.initWallet() self.initWallet(restart_cb=self.restartForScan)
def getTestnetSeed(self): def getTestnetSeed(self):
text, ok = QInputDialog.getText( text, ok = QInputDialog.getText(
@ -1463,7 +1473,7 @@ class JMMainWindow(QMainWindow):
continue continue
break break
self.textpassword = str(pd.new_pw.text()) self.textpassword = str(pd.new_pw.text())
return self.textpassword return self.textpassword.encode('utf-8')
def getWalletFileName(self): def getWalletFileName(self):
walletname, ok = QInputDialog.getText(self, 'Choose wallet name', walletname, ok = QInputDialog.getText(self, 'Choose wallet name',

108
scripts/qtsupport.py

@ -20,11 +20,11 @@ Qt files for the wizard for initiating a tumbler run.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
''' '''
import sys, math, re, logging, Queue import math, re, logging
from collections import namedtuple from PySide2 import QtCore
from PySide2.QtGui import *
from PySide2.QtWidgets import *
from PyQt4 import QtCore
from PyQt4.QtGui import *
from jmclient import (jm_single, validate_address, get_tumble_schedule) from jmclient import (jm_single, validate_address, get_tumble_schedule)
@ -193,45 +193,6 @@ def JMQtMessageBox(obj, msg, mbtype='info', title='', detailed_text= None):
else: else:
mbtypes[mbtype](obj, title, msg) mbtypes[mbtype](obj, title, msg)
class TaskThread(QtCore.QThread):
'''Thread that runs background tasks. Callbacks are guaranteed
to happen in the context of its parent.'''
Task = namedtuple("Task", "task cb_success cb_done cb_error")
doneSig = QtCore.pyqtSignal(object, object, object)
def __init__(self, parent, on_error=None):
super(TaskThread, self).__init__(parent)
self.on_error = on_error
self.tasks = Queue.Queue()
self.doneSig.connect(self.on_done)
self.start()
def add(self, task, on_success=None, on_done=None, on_error=None):
on_error = on_error or self.on_error
self.tasks.put(TaskThread.Task(task, on_success, on_done, on_error))
def run(self):
while True:
task = self.tasks.get()
if not task:
break
try:
result = task.task()
self.doneSig.emit(result, task.cb_done, task.cb_success)
except BaseException:
self.doneSig.emit(sys.exc_info(), task.cb_done, task.cb_error)
def on_done(self, result, cb_done, cb):
# This runs in the parent's thread.
if cb_done:
cb_done()
if cb:
cb(result)
def stop(self):
self.tasks.put(None)
class QtHandler(logging.Handler): class QtHandler(logging.Handler):
def __init__(self): def __init__(self):
@ -245,7 +206,7 @@ class QtHandler(logging.Handler):
class XStream(QtCore.QObject): class XStream(QtCore.QObject):
_stdout = None _stdout = None
_stderr = None _stderr = None
messageWritten = QtCore.pyqtSignal(str) messageWritten = QtCore.Signal(str)
def flush(self): def flush(self):
pass pass
@ -255,20 +216,22 @@ class XStream(QtCore.QObject):
def write(self, msg): def write(self, msg):
if (not self.signalsBlocked()): if (not self.signalsBlocked()):
self.messageWritten.emit(unicode(msg)) self.messageWritten.emit(msg)
@staticmethod @staticmethod
def stdout(): def stdout():
if (not XStream._stdout): if (not XStream._stdout):
XStream._stdout = XStream() XStream._stdout = XStream()
sys.stdout = XStream._stdout # temporarily removed, seems not needed
#sys.stdout = XStream._stdout
return XStream._stdout return XStream._stdout
@staticmethod @staticmethod
def stderr(): def stderr():
if (not XStream._stderr): if (not XStream._stderr):
XStream._stderr = XStream() XStream._stderr = XStream()
sys.stderr = XStream._stderr # temporarily removed, seems not needed
#sys.stderr = XStream._stderr
return XStream._stderr return XStream._stderr
@ -326,7 +289,6 @@ def check_password_strength(password):
:param password: password entered by user in New Password :param password: password entered by user in New Password
:return: password strength Weak or Medium or Strong :return: password strength Weak or Medium or Strong
''' '''
password = unicode(password)
n = math.log(len(set(password))) n = math.log(len(set(password)))
num = re.search("[0-9]", password) is not None and re.match( num = re.search("[0-9]", password) is not None and re.match(
"^[0-9]*$", password) is None "^[0-9]*$", password) is None
@ -361,9 +323,9 @@ def update_password_strength(pw_strength_label, password):
def make_password_dialog(self, msg, new_pass=True): def make_password_dialog(self, msg, new_pass=True):
self.new_pw = QLineEdit() self.new_pw = QLineEdit()
self.new_pw.setEchoMode(2) self.new_pw.setEchoMode(QLineEdit.EchoMode(2))
self.conf_pw = QLineEdit() self.conf_pw = QLineEdit()
self.conf_pw.setEchoMode(2) self.conf_pw.setEchoMode(QLineEdit.EchoMode(2))
vbox = QVBoxLayout() vbox = QVBoxLayout()
label = QLabel(msg) label = QLabel(msg)
@ -450,7 +412,7 @@ class MyTreeWidget(QTreeWidget):
self.header().setStretchLastSection(False) self.header().setStretchLastSection(False)
for col in range(len(headers)): for col in range(len(headers)):
#note, a single stretch column is currently not used. #note, a single stretch column is currently not used.
self.header().setResizeMode(col, QHeaderView.Interactive) self.header().setSectionResizeMode(col, QHeaderView.Interactive)
def editItem(self, item, column): def editItem(self, item, column):
if column in self.editable_columns: if column in self.editable_columns:
@ -514,7 +476,7 @@ class MyTreeWidget(QTreeWidget):
def on_edited(self, item, column, prior): def on_edited(self, item, column, prior):
'''Called only when the text actually changes''' '''Called only when the text actually changes'''
key = str(item.data(0, Qt.UserRole).toString()) key = str(item.data(0, Qt.UserRole))
text = unicode(item.text(column)) text = unicode(item.text(column))
self.parent.wallet.set_label(key, text) self.parent.wallet.set_label(key, text)
if text: if text:
@ -625,7 +587,7 @@ class SchDynamicPage2(QWizardPage):
def initializePage(self): def initializePage(self):
addrLEs = [] addrLEs = []
requested_mixdepths = int(self.field("mixdepthcount").toString()) requested_mixdepths = int(self.field("mixdepthcount"))
#for testing #for testing
if jm_single().config.get("BLOCKCHAIN", "blockchain_source") == "regtest": if jm_single().config.get("BLOCKCHAIN", "blockchain_source") == "regtest":
testaddrs = ["mteaYsGsLCL9a4cftZFTpGEWXNwZyDt5KS", testaddrs = ["mteaYsGsLCL9a4cftZFTpGEWXNwZyDt5KS",
@ -753,7 +715,7 @@ class ScheduleWizard(QWizard):
def get_name(self): def get_name(self):
#TODO de-hardcode generated name #TODO de-hardcode generated name
return "TUMBLE.schedule" return "TUMBLE.schedule"
#return self.field("schedfilename").toString()
def get_destaddrs(self): def get_destaddrs(self):
return self.destaddrs return self.destaddrs
@ -761,7 +723,7 @@ class ScheduleWizard(QWizard):
def get_schedule(self): def get_schedule(self):
self.destaddrs = [] self.destaddrs = []
for i in range(self.page(2).required_addresses): for i in range(self.page(2).required_addresses):
daddrstring = str(self.field("destaddr"+str(i)).toString()) daddrstring = str(self.field("destaddr"+str(i)))
if validate_address(daddrstring)[0]: if validate_address(daddrstring)[0]:
self.destaddrs.append(daddrstring) self.destaddrs.append(daddrstring)
elif daddrstring != "": elif daddrstring != "":
@ -769,22 +731,22 @@ class ScheduleWizard(QWizard):
title='Error') title='Error')
return None return None
self.opts = {} self.opts = {}
self.opts['mixdepthsrc'] = int(self.field("mixdepthsrc").toString()) self.opts['mixdepthsrc'] = int(self.field("mixdepthsrc"))
self.opts['mixdepthcount'] = int(self.field("mixdepthcount").toString()) self.opts['mixdepthcount'] = int(self.field("mixdepthcount"))
self.opts['txfee'] = -1 self.opts['txfee'] = -1
self.opts['addrcount'] = len(self.destaddrs) self.opts['addrcount'] = len(self.destaddrs)
self.opts['makercountrange'] = (int(self.field("makercount").toString()), self.opts['makercountrange'] = (int(self.field("makercount")),
float(self.field("makercountsdev").toString())) float(self.field("makercountsdev")))
self.opts['minmakercount'] = int(self.field("minmakercount").toString()) self.opts['minmakercount'] = int(self.field("minmakercount"))
self.opts['txcountparams'] = (int(self.field("txcountparams").toString()), self.opts['txcountparams'] = (int(self.field("txcountparams")),
float(self.field("txcountsdev").toString())) float(self.field("txcountsdev")))
self.opts['mintxcount'] = int(self.field("mintxcount").toString()) self.opts['mintxcount'] = int(self.field("mintxcount"))
self.opts['amountpower'] = float(self.field("amountpower").toString()) self.opts['amountpower'] = float(self.field("amountpower"))
self.opts['timelambda'] = float(self.field("timelambda").toString()) self.opts['timelambda'] = float(self.field("timelambda"))
self.opts['waittime'] = float(self.field("waittime").toString()) self.opts['waittime'] = float(self.field("waittime"))
self.opts['mincjamount'] = int(self.field("mincjamount").toString()) self.opts['mincjamount'] = int(self.field("mincjamount"))
relfeeval = float(self.field("maxrelfee").toString()) relfeeval = float(self.field("maxrelfee"))
absfeeval = int(self.field("maxabsfee").toString()) absfeeval = int(self.field("maxabsfee"))
self.opts['maxcjfee'] = (relfeeval, absfeeval) self.opts['maxcjfee'] = (relfeeval, absfeeval)
#needed for Taker to check: #needed for Taker to check:
jm_single().mincjamount = self.opts['mincjamount'] jm_single().mincjamount = self.opts['mincjamount']
@ -798,10 +760,10 @@ class TumbleRestartWizard(QWizard):
def getOptions(self): def getOptions(self):
self.opts = {} self.opts = {}
self.opts['amountpower'] = float(self.field("amountpower").toString()) self.opts['amountpower'] = float(self.field("amountpower"))
self.opts['mincjamount'] = int(self.field("mincjamount").toString()) self.opts['mincjamount'] = int(self.field("mincjamount"))
relfeeval = float(self.field("maxrelfee").toString()) relfeeval = float(self.field("maxrelfee"))
absfeeval = int(self.field("maxabsfee").toString()) absfeeval = int(self.field("maxabsfee"))
self.opts['maxcjfee'] = (relfeeval, absfeeval) self.opts['maxcjfee'] = (relfeeval, absfeeval)
#needed for Taker to check: #needed for Taker to check:
jm_single().mincjamount = self.opts['mincjamount'] jm_single().mincjamount = self.opts['mincjamount']

Loading…
Cancel
Save