mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-31 09:21:39 +00:00
Qt: move settings dialog to a separate module
This commit is contained in:
parent
9d595f1fe1
commit
96d3c36e4a
2 changed files with 505 additions and 436 deletions
|
@ -2893,448 +2893,17 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger):
|
|||
self.update_status()
|
||||
|
||||
def settings_dialog(self):
|
||||
self.need_restart = False
|
||||
d = WindowModalDialog(self, _('Preferences'))
|
||||
vbox = QVBoxLayout()
|
||||
tabs = QTabWidget()
|
||||
gui_widgets = []
|
||||
fee_widgets = []
|
||||
tx_widgets = []
|
||||
oa_widgets = []
|
||||
server_widgets = []
|
||||
|
||||
# language
|
||||
lang_help = _('Select which language is used in the GUI (after restart).')
|
||||
lang_label = HelpLabel(_('Language') + ':', lang_help)
|
||||
lang_combo = QComboBox()
|
||||
from electrum.i18n import languages
|
||||
lang_combo.addItems(list(languages.values()))
|
||||
lang_keys = list(languages.keys())
|
||||
lang_cur_setting = self.config.get("language", '')
|
||||
try:
|
||||
index = lang_keys.index(lang_cur_setting)
|
||||
except ValueError: # not in list
|
||||
index = 0
|
||||
lang_combo.setCurrentIndex(index)
|
||||
if not self.config.is_modifiable('language'):
|
||||
for w in [lang_combo, lang_label]: w.setEnabled(False)
|
||||
def on_lang(x):
|
||||
lang_request = list(languages.keys())[lang_combo.currentIndex()]
|
||||
if lang_request != self.config.get('language'):
|
||||
self.config.set_key("language", lang_request, True)
|
||||
self.need_restart = True
|
||||
lang_combo.currentIndexChanged.connect(on_lang)
|
||||
gui_widgets.append((lang_label, lang_combo))
|
||||
|
||||
nz_help = _('Number of zeros displayed after the decimal point. For example, if this is set to 2, "1." will be displayed as "1.00"')
|
||||
nz_label = HelpLabel(_('Zeros after decimal point') + ':', nz_help)
|
||||
nz = QSpinBox()
|
||||
nz.setMinimum(0)
|
||||
nz.setMaximum(self.decimal_point)
|
||||
nz.setValue(self.num_zeros)
|
||||
if not self.config.is_modifiable('num_zeros'):
|
||||
for w in [nz, nz_label]: w.setEnabled(False)
|
||||
def on_nz():
|
||||
value = nz.value()
|
||||
if self.num_zeros != value:
|
||||
self.num_zeros = value
|
||||
self.config.set_key('num_zeros', value, True)
|
||||
self.history_list.update()
|
||||
self.address_list.update()
|
||||
nz.valueChanged.connect(on_nz)
|
||||
gui_widgets.append((nz_label, nz))
|
||||
|
||||
msg = '\n'.join([
|
||||
_('Time based: fee rate is based on average confirmation time estimates'),
|
||||
_('Mempool based: fee rate is targeting a depth in the memory pool')
|
||||
]
|
||||
)
|
||||
fee_type_label = HelpLabel(_('Fee estimation') + ':', msg)
|
||||
fee_type_combo = QComboBox()
|
||||
fee_type_combo.addItems([_('Static'), _('ETA'), _('Mempool')])
|
||||
fee_type_combo.setCurrentIndex((2 if self.config.use_mempool_fees() else 1) if self.config.is_dynfee() else 0)
|
||||
def on_fee_type(x):
|
||||
self.config.set_key('mempool_fees', x==2)
|
||||
self.config.set_key('dynamic_fees', x>0)
|
||||
self.fee_slider.update()
|
||||
fee_type_combo.currentIndexChanged.connect(on_fee_type)
|
||||
fee_widgets.append((fee_type_label, fee_type_combo))
|
||||
|
||||
feebox_cb = QCheckBox(_('Edit fees manually'))
|
||||
feebox_cb.setChecked(bool(self.config.get('show_fee', False)))
|
||||
feebox_cb.setToolTip(_("Show fee edit box in send tab."))
|
||||
def on_feebox(x):
|
||||
self.config.set_key('show_fee', x == Qt.Checked)
|
||||
self.fee_adv_controls.setVisible(bool(x))
|
||||
feebox_cb.stateChanged.connect(on_feebox)
|
||||
fee_widgets.append((feebox_cb, None))
|
||||
|
||||
use_rbf = bool(self.config.get('use_rbf', True))
|
||||
use_rbf_cb = QCheckBox(_('Use Replace-By-Fee'))
|
||||
use_rbf_cb.setChecked(use_rbf)
|
||||
use_rbf_cb.setToolTip(
|
||||
_('If you check this box, your transactions will be marked as non-final,') + '\n' + \
|
||||
_('and you will have the possibility, while they are unconfirmed, to replace them with transactions that pay higher fees.') + '\n' + \
|
||||
_('Note that some merchants do not accept non-final transactions until they are confirmed.'))
|
||||
def on_use_rbf(x):
|
||||
self.config.set_key('use_rbf', bool(x))
|
||||
batch_rbf_cb.setEnabled(bool(x))
|
||||
use_rbf_cb.stateChanged.connect(on_use_rbf)
|
||||
fee_widgets.append((use_rbf_cb, None))
|
||||
|
||||
batch_rbf_cb = QCheckBox(_('Batch RBF transactions'))
|
||||
batch_rbf_cb.setChecked(bool(self.config.get('batch_rbf', False)))
|
||||
batch_rbf_cb.setEnabled(use_rbf)
|
||||
batch_rbf_cb.setToolTip(
|
||||
_('If you check this box, your unconfirmed transactions will be consolidated into a single transaction.') + '\n' + \
|
||||
_('This will save fees.'))
|
||||
def on_batch_rbf(x):
|
||||
self.config.set_key('batch_rbf', bool(x))
|
||||
batch_rbf_cb.stateChanged.connect(on_batch_rbf)
|
||||
fee_widgets.append((batch_rbf_cb, None))
|
||||
|
||||
msg = _('OpenAlias record, used to receive coins and to sign payment requests.') + '\n\n'\
|
||||
+ _('The following alias providers are available:') + '\n'\
|
||||
+ '\n'.join(['https://cryptoname.co/', 'http://xmr.link']) + '\n\n'\
|
||||
+ 'For more information, see https://openalias.org'
|
||||
alias_label = HelpLabel(_('OpenAlias') + ':', msg)
|
||||
alias = self.config.get('alias','')
|
||||
alias_e = QLineEdit(alias)
|
||||
def set_alias_color():
|
||||
if not self.config.get('alias'):
|
||||
alias_e.setStyleSheet("")
|
||||
return
|
||||
if self.alias_info:
|
||||
alias_addr, alias_name, validated = self.alias_info
|
||||
alias_e.setStyleSheet((ColorScheme.GREEN if validated else ColorScheme.RED).as_stylesheet(True))
|
||||
else:
|
||||
alias_e.setStyleSheet(ColorScheme.RED.as_stylesheet(True))
|
||||
def on_alias_edit():
|
||||
alias_e.setStyleSheet("")
|
||||
alias = str(alias_e.text())
|
||||
self.config.set_key('alias', alias, True)
|
||||
if alias:
|
||||
self.fetch_alias()
|
||||
set_alias_color()
|
||||
self.alias_received_signal.connect(set_alias_color)
|
||||
alias_e.editingFinished.connect(on_alias_edit)
|
||||
oa_widgets.append((alias_label, alias_e))
|
||||
|
||||
# SSL certificate
|
||||
msg = ' '.join([
|
||||
_('SSL certificate used to sign payment requests.'),
|
||||
_('Use setconfig to set ssl_chain and ssl_privkey.'),
|
||||
])
|
||||
if self.config.get('ssl_keyfile') and self.config.get('ssl_certfile'):
|
||||
try:
|
||||
SSL_identity = paymentrequest.check_ssl_config(self.config)
|
||||
SSL_error = None
|
||||
except BaseException as e:
|
||||
SSL_identity = "error"
|
||||
SSL_error = repr(e)
|
||||
else:
|
||||
SSL_identity = ""
|
||||
SSL_error = None
|
||||
SSL_id_label = HelpLabel(_('SSL certificate') + ':', msg)
|
||||
SSL_id_e = QLineEdit(SSL_identity)
|
||||
SSL_id_e.setStyleSheet((ColorScheme.RED if SSL_error else ColorScheme.GREEN).as_stylesheet(True) if SSL_identity else '')
|
||||
if SSL_error:
|
||||
SSL_id_e.setToolTip(SSL_error)
|
||||
SSL_id_e.setReadOnly(True)
|
||||
server_widgets.append((SSL_id_label, SSL_id_e))
|
||||
|
||||
units = base_units_list
|
||||
msg = (_('Base unit of your wallet.')
|
||||
+ '\n1 BTC = 1000 mBTC. 1 mBTC = 1000 bits. 1 bit = 100 sat.\n'
|
||||
+ _('This setting affects the Send tab, and all balance related fields.'))
|
||||
unit_label = HelpLabel(_('Base unit') + ':', msg)
|
||||
unit_combo = QComboBox()
|
||||
unit_combo.addItems(units)
|
||||
unit_combo.setCurrentIndex(units.index(self.base_unit()))
|
||||
def on_unit(x, nz):
|
||||
unit_result = units[unit_combo.currentIndex()]
|
||||
if self.base_unit() == unit_result:
|
||||
return
|
||||
edits = self.amount_e, self.fee_e, self.receive_amount_e
|
||||
amounts = [edit.get_amount() for edit in edits]
|
||||
self.decimal_point = base_unit_name_to_decimal_point(unit_result)
|
||||
self.config.set_key('decimal_point', self.decimal_point, True)
|
||||
nz.setMaximum(self.decimal_point)
|
||||
self.history_list.update()
|
||||
self.request_list.update()
|
||||
self.address_list.update()
|
||||
for edit, amount in zip(edits, amounts):
|
||||
edit.setAmount(amount)
|
||||
self.update_status()
|
||||
unit_combo.currentIndexChanged.connect(lambda x: on_unit(x, nz))
|
||||
gui_widgets.append((unit_label, unit_combo))
|
||||
|
||||
block_explorers = sorted(util.block_explorer_info().keys())
|
||||
msg = _('Choose which online block explorer to use for functions that open a web browser')
|
||||
block_ex_label = HelpLabel(_('Online Block Explorer') + ':', msg)
|
||||
block_ex_combo = QComboBox()
|
||||
block_ex_combo.addItems(block_explorers)
|
||||
block_ex_combo.setCurrentIndex(block_ex_combo.findText(util.block_explorer(self.config)))
|
||||
def on_be(x):
|
||||
be_result = block_explorers[block_ex_combo.currentIndex()]
|
||||
self.config.set_key('block_explorer', be_result, True)
|
||||
block_ex_combo.currentIndexChanged.connect(on_be)
|
||||
gui_widgets.append((block_ex_label, block_ex_combo))
|
||||
|
||||
from electrum import qrscanner
|
||||
system_cameras = qrscanner._find_system_cameras()
|
||||
qr_combo = QComboBox()
|
||||
qr_combo.addItem("Default","default")
|
||||
for camera, device in system_cameras.items():
|
||||
qr_combo.addItem(camera, device)
|
||||
#combo.addItem("Manually specify a device", config.get("video_device"))
|
||||
index = qr_combo.findData(self.config.get("video_device"))
|
||||
qr_combo.setCurrentIndex(index)
|
||||
msg = _("Install the zbar package to enable this.")
|
||||
qr_label = HelpLabel(_('Video Device') + ':', msg)
|
||||
qr_combo.setEnabled(qrscanner.libzbar is not None)
|
||||
on_video_device = lambda x: self.config.set_key("video_device", qr_combo.itemData(x), True)
|
||||
qr_combo.currentIndexChanged.connect(on_video_device)
|
||||
gui_widgets.append((qr_label, qr_combo))
|
||||
|
||||
colortheme_combo = QComboBox()
|
||||
colortheme_combo.addItem(_('Light'), 'default')
|
||||
colortheme_combo.addItem(_('Dark'), 'dark')
|
||||
index = colortheme_combo.findData(self.config.get('qt_gui_color_theme', 'default'))
|
||||
colortheme_combo.setCurrentIndex(index)
|
||||
colortheme_label = QLabel(_('Color theme') + ':')
|
||||
def on_colortheme(x):
|
||||
self.config.set_key('qt_gui_color_theme', colortheme_combo.itemData(x), True)
|
||||
self.need_restart = True
|
||||
colortheme_combo.currentIndexChanged.connect(on_colortheme)
|
||||
gui_widgets.append((colortheme_label, colortheme_combo))
|
||||
|
||||
updatecheck_cb = QCheckBox(_("Automatically check for software updates"))
|
||||
updatecheck_cb.setChecked(bool(self.config.get('check_updates', False)))
|
||||
def on_set_updatecheck(v):
|
||||
self.config.set_key('check_updates', v == Qt.Checked, save=True)
|
||||
updatecheck_cb.stateChanged.connect(on_set_updatecheck)
|
||||
gui_widgets.append((updatecheck_cb, None))
|
||||
|
||||
filelogging_cb = QCheckBox(_("Write logs to file"))
|
||||
filelogging_cb.setChecked(bool(self.config.get('log_to_file', False)))
|
||||
def on_set_filelogging(v):
|
||||
self.config.set_key('log_to_file', v == Qt.Checked, save=True)
|
||||
self.need_restart = True
|
||||
filelogging_cb.stateChanged.connect(on_set_filelogging)
|
||||
filelogging_cb.setToolTip(_('Debug logs can be persisted to disk. These are useful for troubleshooting.'))
|
||||
gui_widgets.append((filelogging_cb, None))
|
||||
|
||||
usechange_cb = QCheckBox(_('Use change addresses'))
|
||||
usechange_cb.setChecked(self.wallet.use_change)
|
||||
if not self.config.is_modifiable('use_change'): usechange_cb.setEnabled(False)
|
||||
def on_usechange(x):
|
||||
usechange_result = x == Qt.Checked
|
||||
if self.wallet.use_change != usechange_result:
|
||||
self.wallet.use_change = usechange_result
|
||||
self.wallet.storage.put('use_change', self.wallet.use_change)
|
||||
multiple_cb.setEnabled(self.wallet.use_change)
|
||||
usechange_cb.stateChanged.connect(on_usechange)
|
||||
usechange_cb.setToolTip(_('Using change addresses makes it more difficult for other people to track your transactions.'))
|
||||
tx_widgets.append((usechange_cb, None))
|
||||
|
||||
def on_multiple(x):
|
||||
multiple = x == Qt.Checked
|
||||
if self.wallet.multiple_change != multiple:
|
||||
self.wallet.multiple_change = multiple
|
||||
self.wallet.storage.put('multiple_change', multiple)
|
||||
multiple_change = self.wallet.multiple_change
|
||||
multiple_cb = QCheckBox(_('Use multiple change addresses'))
|
||||
multiple_cb.setEnabled(self.wallet.use_change)
|
||||
multiple_cb.setToolTip('\n'.join([
|
||||
_('In some cases, use up to 3 change addresses in order to break '
|
||||
'up large coin amounts and obfuscate the recipient address.'),
|
||||
_('This may result in higher transactions fees.')
|
||||
]))
|
||||
multiple_cb.setChecked(multiple_change)
|
||||
multiple_cb.stateChanged.connect(on_multiple)
|
||||
tx_widgets.append((multiple_cb, None))
|
||||
|
||||
def fmt_docs(key, klass):
|
||||
lines = [ln.lstrip(" ") for ln in klass.__doc__.split("\n")]
|
||||
return '\n'.join([key, "", " ".join(lines)])
|
||||
|
||||
choosers = sorted(coinchooser.COIN_CHOOSERS.keys())
|
||||
if len(choosers) > 1:
|
||||
chooser_name = coinchooser.get_name(self.config)
|
||||
msg = _('Choose coin (UTXO) selection method. The following are available:\n\n')
|
||||
msg += '\n\n'.join(fmt_docs(*item) for item in coinchooser.COIN_CHOOSERS.items())
|
||||
chooser_label = HelpLabel(_('Coin selection') + ':', msg)
|
||||
chooser_combo = QComboBox()
|
||||
chooser_combo.addItems(choosers)
|
||||
i = choosers.index(chooser_name) if chooser_name in choosers else 0
|
||||
chooser_combo.setCurrentIndex(i)
|
||||
def on_chooser(x):
|
||||
chooser_name = choosers[chooser_combo.currentIndex()]
|
||||
self.config.set_key('coin_chooser', chooser_name)
|
||||
chooser_combo.currentIndexChanged.connect(on_chooser)
|
||||
tx_widgets.append((chooser_label, chooser_combo))
|
||||
|
||||
def on_unconf(x):
|
||||
self.config.set_key('confirmed_only', bool(x))
|
||||
conf_only = bool(self.config.get('confirmed_only', False))
|
||||
unconf_cb = QCheckBox(_('Spend only confirmed coins'))
|
||||
unconf_cb.setToolTip(_('Spend only confirmed inputs.'))
|
||||
unconf_cb.setChecked(conf_only)
|
||||
unconf_cb.stateChanged.connect(on_unconf)
|
||||
tx_widgets.append((unconf_cb, None))
|
||||
|
||||
def on_outrounding(x):
|
||||
self.config.set_key('coin_chooser_output_rounding', bool(x))
|
||||
enable_outrounding = bool(self.config.get('coin_chooser_output_rounding', False))
|
||||
outrounding_cb = QCheckBox(_('Enable output value rounding'))
|
||||
outrounding_cb.setToolTip(
|
||||
_('Set the value of the change output so that it has similar precision to the other outputs.') + '\n' +
|
||||
_('This might improve your privacy somewhat.') + '\n' +
|
||||
_('If enabled, at most 100 satoshis might be lost due to this, per transaction.'))
|
||||
outrounding_cb.setChecked(enable_outrounding)
|
||||
outrounding_cb.stateChanged.connect(on_outrounding)
|
||||
tx_widgets.append((outrounding_cb, None))
|
||||
|
||||
# Fiat Currency
|
||||
hist_checkbox = QCheckBox()
|
||||
hist_capgains_checkbox = QCheckBox()
|
||||
fiat_address_checkbox = QCheckBox()
|
||||
ccy_combo = QComboBox()
|
||||
ex_combo = QComboBox()
|
||||
|
||||
def update_currencies():
|
||||
if not self.fx: return
|
||||
currencies = sorted(self.fx.get_currencies(self.fx.get_history_config()))
|
||||
ccy_combo.clear()
|
||||
ccy_combo.addItems([_('None')] + currencies)
|
||||
if self.fx.is_enabled():
|
||||
ccy_combo.setCurrentIndex(ccy_combo.findText(self.fx.get_currency()))
|
||||
|
||||
def update_history_cb():
|
||||
if not self.fx: return
|
||||
hist_checkbox.setChecked(self.fx.get_history_config())
|
||||
hist_checkbox.setEnabled(self.fx.is_enabled())
|
||||
|
||||
def update_fiat_address_cb():
|
||||
if not self.fx: return
|
||||
fiat_address_checkbox.setChecked(self.fx.get_fiat_address_config())
|
||||
|
||||
def update_history_capgains_cb():
|
||||
if not self.fx: return
|
||||
hist_capgains_checkbox.setChecked(self.fx.get_history_capital_gains_config())
|
||||
hist_capgains_checkbox.setEnabled(hist_checkbox.isChecked())
|
||||
|
||||
def update_exchanges():
|
||||
if not self.fx: return
|
||||
b = self.fx.is_enabled()
|
||||
ex_combo.setEnabled(b)
|
||||
if b:
|
||||
h = self.fx.get_history_config()
|
||||
c = self.fx.get_currency()
|
||||
exchanges = self.fx.get_exchanges_by_ccy(c, h)
|
||||
else:
|
||||
exchanges = self.fx.get_exchanges_by_ccy('USD', False)
|
||||
ex_combo.blockSignals(True)
|
||||
ex_combo.clear()
|
||||
ex_combo.addItems(sorted(exchanges))
|
||||
ex_combo.setCurrentIndex(ex_combo.findText(self.fx.config_exchange()))
|
||||
ex_combo.blockSignals(False)
|
||||
|
||||
def on_currency(hh):
|
||||
if not self.fx: return
|
||||
b = bool(ccy_combo.currentIndex())
|
||||
ccy = str(ccy_combo.currentText()) if b else None
|
||||
self.fx.set_enabled(b)
|
||||
if b and ccy != self.fx.ccy:
|
||||
self.fx.set_currency(ccy)
|
||||
update_history_cb()
|
||||
update_exchanges()
|
||||
self.update_fiat()
|
||||
|
||||
def on_exchange(idx):
|
||||
exchange = str(ex_combo.currentText())
|
||||
if self.fx and self.fx.is_enabled() and exchange and exchange != self.fx.exchange.name():
|
||||
self.fx.set_exchange(exchange)
|
||||
|
||||
def on_history(checked):
|
||||
if not self.fx: return
|
||||
self.fx.set_history_config(checked)
|
||||
update_exchanges()
|
||||
self.history_model.refresh('on_history')
|
||||
if self.fx.is_enabled() and checked:
|
||||
self.fx.trigger_update()
|
||||
update_history_capgains_cb()
|
||||
|
||||
def on_history_capgains(checked):
|
||||
if not self.fx: return
|
||||
self.fx.set_history_capital_gains_config(checked)
|
||||
self.history_model.refresh('on_history_capgains')
|
||||
|
||||
def on_fiat_address(checked):
|
||||
if not self.fx: return
|
||||
self.fx.set_fiat_address_config(checked)
|
||||
self.address_list.refresh_headers()
|
||||
self.address_list.update()
|
||||
|
||||
update_currencies()
|
||||
update_history_cb()
|
||||
update_history_capgains_cb()
|
||||
update_fiat_address_cb()
|
||||
update_exchanges()
|
||||
ccy_combo.currentIndexChanged.connect(on_currency)
|
||||
hist_checkbox.stateChanged.connect(on_history)
|
||||
hist_capgains_checkbox.stateChanged.connect(on_history_capgains)
|
||||
fiat_address_checkbox.stateChanged.connect(on_fiat_address)
|
||||
ex_combo.currentIndexChanged.connect(on_exchange)
|
||||
|
||||
fiat_widgets = []
|
||||
fiat_widgets.append((QLabel(_('Fiat currency')), ccy_combo))
|
||||
fiat_widgets.append((QLabel(_('Show history rates')), hist_checkbox))
|
||||
fiat_widgets.append((QLabel(_('Show capital gains in history')), hist_capgains_checkbox))
|
||||
fiat_widgets.append((QLabel(_('Show Fiat balance for addresses')), fiat_address_checkbox))
|
||||
fiat_widgets.append((QLabel(_('Source')), ex_combo))
|
||||
|
||||
tabs_info = [
|
||||
(fee_widgets, _('Fees')),
|
||||
(tx_widgets, _('Transactions')),
|
||||
(gui_widgets, _('General')),
|
||||
(fiat_widgets, _('Fiat')),
|
||||
(server_widgets, _('PayServer')),
|
||||
(oa_widgets, _('OpenAlias')),
|
||||
]
|
||||
for widgets, name in tabs_info:
|
||||
tab = QWidget()
|
||||
grid = QGridLayout(tab)
|
||||
grid.setColumnStretch(0,1)
|
||||
for a,b in widgets:
|
||||
i = grid.rowCount()
|
||||
if b:
|
||||
if a:
|
||||
grid.addWidget(a, i, 0)
|
||||
grid.addWidget(b, i, 1)
|
||||
else:
|
||||
grid.addWidget(a, i, 0, 1, 2)
|
||||
tabs.addTab(tab, name)
|
||||
|
||||
vbox.addWidget(tabs)
|
||||
vbox.addStretch(1)
|
||||
vbox.addLayout(Buttons(CloseButton(d)))
|
||||
d.setLayout(vbox)
|
||||
|
||||
# run the dialog
|
||||
from .settings_dialog import SettingsDialog
|
||||
d = SettingsDialog(self, self.config)
|
||||
self.alias_received_signal.connect(d.set_alias_color)
|
||||
d.exec_()
|
||||
|
||||
self.alias_received_signal.disconnect(d.set_alias_color)
|
||||
if self.fx:
|
||||
self.fx.trigger_update()
|
||||
|
||||
self.alias_received_signal.disconnect(set_alias_color)
|
||||
|
||||
run_hook('close_settings_dialog')
|
||||
if self.need_restart:
|
||||
if d.need_restart:
|
||||
self.show_warning(_('Please restart Electrum to activate the new GUI settings'), title=_('Success'))
|
||||
|
||||
|
||||
def closeEvent(self, event):
|
||||
# It seems in some rare cases this closeEvent() is called twice
|
||||
if not self.cleaned_up:
|
||||
|
|
500
electrum/gui/qt/settings_dialog.py
Normal file
500
electrum/gui/qt/settings_dialog.py
Normal file
|
@ -0,0 +1,500 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# Electrum - lightweight Bitcoin client
|
||||
# Copyright (C) 2012 thomasv@gitorious
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person
|
||||
# obtaining a copy of this software and associated documentation files
|
||||
# (the "Software"), to deal in the Software without restriction,
|
||||
# including without limitation the rights to use, copy, modify, merge,
|
||||
# publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
# and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
import sys
|
||||
import time
|
||||
import threading
|
||||
import os
|
||||
import traceback
|
||||
import json
|
||||
from decimal import Decimal
|
||||
|
||||
from PyQt5.QtGui import QPixmap, QKeySequence, QIcon, QCursor
|
||||
from PyQt5.QtCore import Qt, QRect, QStringListModel, QSize, pyqtSignal
|
||||
from PyQt5.QtWidgets import (QMessageBox, QComboBox, QSystemTrayIcon, QTabWidget,
|
||||
QSpinBox, QMenuBar, QFileDialog, QCheckBox, QLabel,
|
||||
QVBoxLayout, QGridLayout, QLineEdit, QTreeWidgetItem,
|
||||
QHBoxLayout, QPushButton, QScrollArea, QTextEdit,
|
||||
QShortcut, QMainWindow, QCompleter, QInputDialog,
|
||||
QWidget, QMenu, QSizePolicy, QStatusBar)
|
||||
|
||||
import electrum
|
||||
from electrum.i18n import _
|
||||
from electrum import util, coinchooser, paymentrequest
|
||||
from electrum.util import (format_time, format_satoshis, format_fee_satoshis,
|
||||
format_satoshis_plain, NotEnoughFunds,
|
||||
UserCancelled, NoDynamicFeeEstimates, profiler,
|
||||
export_meta, import_meta, bh2u, bfh, InvalidPassword,
|
||||
base_units, base_units_list, base_unit_name_to_decimal_point,
|
||||
decimal_point_to_base_unit_name, quantize_feerate,
|
||||
UnknownBaseUnit, DECIMAL_POINT_DEFAULT, UserFacingException,
|
||||
get_new_wallet_name, send_exception_to_crash_reporter,
|
||||
InvalidBitcoinURI, InvoiceError)
|
||||
|
||||
from .amountedit import AmountEdit, BTCAmountEdit, MyLineEdit, FeerateEdit
|
||||
from .util import (read_QIcon, ColorScheme, text_dialog, icon_path, WaitingDialog,
|
||||
WindowModalDialog, ChoicesLayout, HelpLabel, FromList, Buttons,
|
||||
OkButton, InfoButton, WWLabel, TaskThread, CancelButton,
|
||||
CloseButton, HelpButton, MessageBoxMixin, EnterButton,
|
||||
ButtonsLineEdit, CopyCloseButton, import_meta_gui, export_meta_gui,
|
||||
filename_field, address_field, char_width_in_lineedit, webopen)
|
||||
|
||||
from electrum.i18n import languages
|
||||
from electrum import qrscanner
|
||||
|
||||
class SettingsDialog(WindowModalDialog):
|
||||
|
||||
def __init__(self, parent, config):
|
||||
WindowModalDialog.__init__(self, parent, _('Preferences'))
|
||||
self.config = config
|
||||
self.window = parent
|
||||
self.need_restart = False
|
||||
self.fx = self.window.fx
|
||||
self.wallet = self.window.wallet
|
||||
|
||||
vbox = QVBoxLayout()
|
||||
tabs = QTabWidget()
|
||||
gui_widgets = []
|
||||
fee_widgets = []
|
||||
tx_widgets = []
|
||||
oa_widgets = []
|
||||
server_widgets = []
|
||||
|
||||
# language
|
||||
lang_help = _('Select which language is used in the GUI (after restart).')
|
||||
lang_label = HelpLabel(_('Language') + ':', lang_help)
|
||||
lang_combo = QComboBox()
|
||||
lang_combo.addItems(list(languages.values()))
|
||||
lang_keys = list(languages.keys())
|
||||
lang_cur_setting = self.config.get("language", '')
|
||||
try:
|
||||
index = lang_keys.index(lang_cur_setting)
|
||||
except ValueError: # not in list
|
||||
index = 0
|
||||
lang_combo.setCurrentIndex(index)
|
||||
if not self.config.is_modifiable('language'):
|
||||
for w in [lang_combo, lang_label]: w.setEnabled(False)
|
||||
def on_lang(x):
|
||||
lang_request = list(languages.keys())[lang_combo.currentIndex()]
|
||||
if lang_request != self.config.get('language'):
|
||||
self.config.set_key("language", lang_request, True)
|
||||
self.need_restart = True
|
||||
lang_combo.currentIndexChanged.connect(on_lang)
|
||||
gui_widgets.append((lang_label, lang_combo))
|
||||
|
||||
nz_help = _('Number of zeros displayed after the decimal point. For example, if this is set to 2, "1." will be displayed as "1.00"')
|
||||
nz_label = HelpLabel(_('Zeros after decimal point') + ':', nz_help)
|
||||
nz = QSpinBox()
|
||||
nz.setMinimum(0)
|
||||
nz.setMaximum(self.window.decimal_point)
|
||||
nz.setValue(self.window.num_zeros)
|
||||
if not self.config.is_modifiable('num_zeros'):
|
||||
for w in [nz, nz_label]: w.setEnabled(False)
|
||||
def on_nz():
|
||||
value = nz.value()
|
||||
if self.window.num_zeros != value:
|
||||
self.window.num_zeros = value
|
||||
self.config.set_key('num_zeros', value, True)
|
||||
self.window.history_list.update()
|
||||
self.window.address_list.update()
|
||||
nz.valueChanged.connect(on_nz)
|
||||
gui_widgets.append((nz_label, nz))
|
||||
|
||||
msg = '\n'.join([
|
||||
_('Time based: fee rate is based on average confirmation time estimates'),
|
||||
_('Mempool based: fee rate is targeting a depth in the memory pool')
|
||||
]
|
||||
)
|
||||
fee_type_label = HelpLabel(_('Fee estimation') + ':', msg)
|
||||
fee_type_combo = QComboBox()
|
||||
fee_type_combo.addItems([_('Static'), _('ETA'), _('Mempool')])
|
||||
fee_type_combo.setCurrentIndex((2 if self.config.use_mempool_fees() else 1) if self.config.is_dynfee() else 0)
|
||||
def on_fee_type(x):
|
||||
self.config.set_key('mempool_fees', x==2)
|
||||
self.config.set_key('dynamic_fees', x>0)
|
||||
self.window.fee_slider.update()
|
||||
fee_type_combo.currentIndexChanged.connect(on_fee_type)
|
||||
fee_widgets.append((fee_type_label, fee_type_combo))
|
||||
|
||||
feebox_cb = QCheckBox(_('Edit fees manually'))
|
||||
feebox_cb.setChecked(bool(self.config.get('show_fee', False)))
|
||||
feebox_cb.setToolTip(_("Show fee edit box in send tab."))
|
||||
def on_feebox(x):
|
||||
self.config.set_key('show_fee', x == Qt.Checked)
|
||||
self.window.fee_adv_controls.setVisible(bool(x))
|
||||
feebox_cb.stateChanged.connect(on_feebox)
|
||||
fee_widgets.append((feebox_cb, None))
|
||||
|
||||
use_rbf = bool(self.config.get('use_rbf', True))
|
||||
use_rbf_cb = QCheckBox(_('Use Replace-By-Fee'))
|
||||
use_rbf_cb.setChecked(use_rbf)
|
||||
use_rbf_cb.setToolTip(
|
||||
_('If you check this box, your transactions will be marked as non-final,') + '\n' + \
|
||||
_('and you will have the possibility, while they are unconfirmed, to replace them with transactions that pay higher fees.') + '\n' + \
|
||||
_('Note that some merchants do not accept non-final transactions until they are confirmed.'))
|
||||
def on_use_rbf(x):
|
||||
self.config.set_key('use_rbf', bool(x))
|
||||
batch_rbf_cb.setEnabled(bool(x))
|
||||
use_rbf_cb.stateChanged.connect(on_use_rbf)
|
||||
fee_widgets.append((use_rbf_cb, None))
|
||||
|
||||
batch_rbf_cb = QCheckBox(_('Batch RBF transactions'))
|
||||
batch_rbf_cb.setChecked(bool(self.config.get('batch_rbf', False)))
|
||||
batch_rbf_cb.setEnabled(use_rbf)
|
||||
batch_rbf_cb.setToolTip(
|
||||
_('If you check this box, your unconfirmed transactions will be consolidated into a single transaction.') + '\n' + \
|
||||
_('This will save fees.'))
|
||||
def on_batch_rbf(x):
|
||||
self.config.set_key('batch_rbf', bool(x))
|
||||
batch_rbf_cb.stateChanged.connect(on_batch_rbf)
|
||||
fee_widgets.append((batch_rbf_cb, None))
|
||||
|
||||
msg = _('OpenAlias record, used to receive coins and to sign payment requests.') + '\n\n'\
|
||||
+ _('The following alias providers are available:') + '\n'\
|
||||
+ '\n'.join(['https://cryptoname.co/', 'http://xmr.link']) + '\n\n'\
|
||||
+ 'For more information, see https://openalias.org'
|
||||
alias_label = HelpLabel(_('OpenAlias') + ':', msg)
|
||||
alias = self.config.get('alias','')
|
||||
self.alias_e = QLineEdit(alias)
|
||||
self.set_alias_color()
|
||||
self.alias_e.editingFinished.connect(self.on_alias_edit)
|
||||
oa_widgets.append((alias_label, self.alias_e))
|
||||
|
||||
# SSL certificate
|
||||
msg = ' '.join([
|
||||
_('SSL certificate used to sign payment requests.'),
|
||||
_('Use setconfig to set ssl_chain and ssl_privkey.'),
|
||||
])
|
||||
if self.config.get('ssl_keyfile') and self.config.get('ssl_certfile'):
|
||||
try:
|
||||
SSL_identity = paymentrequest.check_ssl_config(self.config)
|
||||
SSL_error = None
|
||||
except BaseException as e:
|
||||
SSL_identity = "error"
|
||||
SSL_error = repr(e)
|
||||
else:
|
||||
SSL_identity = ""
|
||||
SSL_error = None
|
||||
SSL_id_label = HelpLabel(_('SSL certificate') + ':', msg)
|
||||
SSL_id_e = QLineEdit(SSL_identity)
|
||||
SSL_id_e.setStyleSheet((ColorScheme.RED if SSL_error else ColorScheme.GREEN).as_stylesheet(True) if SSL_identity else '')
|
||||
if SSL_error:
|
||||
SSL_id_e.setToolTip(SSL_error)
|
||||
SSL_id_e.setReadOnly(True)
|
||||
server_widgets.append((SSL_id_label, SSL_id_e))
|
||||
|
||||
units = base_units_list
|
||||
msg = (_('Base unit of your wallet.')
|
||||
+ '\n1 BTC = 1000 mBTC. 1 mBTC = 1000 bits. 1 bit = 100 sat.\n'
|
||||
+ _('This setting affects the Send tab, and all balance related fields.'))
|
||||
unit_label = HelpLabel(_('Base unit') + ':', msg)
|
||||
unit_combo = QComboBox()
|
||||
unit_combo.addItems(units)
|
||||
unit_combo.setCurrentIndex(units.index(self.window.base_unit()))
|
||||
def on_unit(x, nz):
|
||||
unit_result = units[unit_combo.currentIndex()]
|
||||
if self.window.base_unit() == unit_result:
|
||||
return
|
||||
edits = self.window.amount_e, self.window.fee_e, self.window.receive_amount_e
|
||||
amounts = [edit.get_amount() for edit in edits]
|
||||
self.window.decimal_point = base_unit_name_to_decimal_point(unit_result)
|
||||
self.config.set_key('decimal_point', self.window.decimal_point, True)
|
||||
nz.setMaximum(self.window.decimal_point)
|
||||
self.window.history_list.update()
|
||||
self.window.request_list.update()
|
||||
self.window.address_list.update()
|
||||
for edit, amount in zip(edits, amounts):
|
||||
edit.setAmount(amount)
|
||||
self.window.update_status()
|
||||
unit_combo.currentIndexChanged.connect(lambda x: on_unit(x, nz))
|
||||
gui_widgets.append((unit_label, unit_combo))
|
||||
|
||||
block_explorers = sorted(util.block_explorer_info().keys())
|
||||
msg = _('Choose which online block explorer to use for functions that open a web browser')
|
||||
block_ex_label = HelpLabel(_('Online Block Explorer') + ':', msg)
|
||||
block_ex_combo = QComboBox()
|
||||
block_ex_combo.addItems(block_explorers)
|
||||
block_ex_combo.setCurrentIndex(block_ex_combo.findText(util.block_explorer(self.config)))
|
||||
def on_be(x):
|
||||
be_result = block_explorers[block_ex_combo.currentIndex()]
|
||||
self.config.set_key('block_explorer', be_result, True)
|
||||
block_ex_combo.currentIndexChanged.connect(on_be)
|
||||
gui_widgets.append((block_ex_label, block_ex_combo))
|
||||
|
||||
system_cameras = qrscanner._find_system_cameras()
|
||||
qr_combo = QComboBox()
|
||||
qr_combo.addItem("Default","default")
|
||||
for camera, device in system_cameras.items():
|
||||
qr_combo.addItem(camera, device)
|
||||
#combo.addItem("Manually specify a device", config.get("video_device"))
|
||||
index = qr_combo.findData(self.config.get("video_device"))
|
||||
qr_combo.setCurrentIndex(index)
|
||||
msg = _("Install the zbar package to enable this.")
|
||||
qr_label = HelpLabel(_('Video Device') + ':', msg)
|
||||
qr_combo.setEnabled(qrscanner.libzbar is not None)
|
||||
on_video_device = lambda x: self.config.set_key("video_device", qr_combo.itemData(x), True)
|
||||
qr_combo.currentIndexChanged.connect(on_video_device)
|
||||
gui_widgets.append((qr_label, qr_combo))
|
||||
|
||||
colortheme_combo = QComboBox()
|
||||
colortheme_combo.addItem(_('Light'), 'default')
|
||||
colortheme_combo.addItem(_('Dark'), 'dark')
|
||||
index = colortheme_combo.findData(self.config.get('qt_gui_color_theme', 'default'))
|
||||
colortheme_combo.setCurrentIndex(index)
|
||||
colortheme_label = QLabel(_('Color theme') + ':')
|
||||
def on_colortheme(x):
|
||||
self.config.set_key('qt_gui_color_theme', colortheme_combo.itemData(x), True)
|
||||
self.need_restart = True
|
||||
colortheme_combo.currentIndexChanged.connect(on_colortheme)
|
||||
gui_widgets.append((colortheme_label, colortheme_combo))
|
||||
|
||||
updatecheck_cb = QCheckBox(_("Automatically check for software updates"))
|
||||
updatecheck_cb.setChecked(bool(self.config.get('check_updates', False)))
|
||||
def on_set_updatecheck(v):
|
||||
self.config.set_key('check_updates', v == Qt.Checked, save=True)
|
||||
updatecheck_cb.stateChanged.connect(on_set_updatecheck)
|
||||
gui_widgets.append((updatecheck_cb, None))
|
||||
|
||||
filelogging_cb = QCheckBox(_("Write logs to file"))
|
||||
filelogging_cb.setChecked(bool(self.config.get('log_to_file', False)))
|
||||
def on_set_filelogging(v):
|
||||
self.config.set_key('log_to_file', v == Qt.Checked, save=True)
|
||||
self.need_restart = True
|
||||
filelogging_cb.stateChanged.connect(on_set_filelogging)
|
||||
filelogging_cb.setToolTip(_('Debug logs can be persisted to disk. These are useful for troubleshooting.'))
|
||||
gui_widgets.append((filelogging_cb, None))
|
||||
|
||||
usechange_cb = QCheckBox(_('Use change addresses'))
|
||||
usechange_cb.setChecked(self.window.wallet.use_change)
|
||||
if not self.config.is_modifiable('use_change'): usechange_cb.setEnabled(False)
|
||||
def on_usechange(x):
|
||||
usechange_result = x == Qt.Checked
|
||||
if self.window.wallet.use_change != usechange_result:
|
||||
self.window.wallet.use_change = usechange_result
|
||||
self.window.wallet.storage.put('use_change', self.window.wallet.use_change)
|
||||
multiple_cb.setEnabled(self.window.wallet.use_change)
|
||||
usechange_cb.stateChanged.connect(on_usechange)
|
||||
usechange_cb.setToolTip(_('Using change addresses makes it more difficult for other people to track your transactions.'))
|
||||
tx_widgets.append((usechange_cb, None))
|
||||
|
||||
def on_multiple(x):
|
||||
multiple = x == Qt.Checked
|
||||
if self.wallet.multiple_change != multiple:
|
||||
self.wallet.multiple_change = multiple
|
||||
self.wallet.storage.put('multiple_change', multiple)
|
||||
multiple_change = self.wallet.multiple_change
|
||||
multiple_cb = QCheckBox(_('Use multiple change addresses'))
|
||||
multiple_cb.setEnabled(self.wallet.use_change)
|
||||
multiple_cb.setToolTip('\n'.join([
|
||||
_('In some cases, use up to 3 change addresses in order to break '
|
||||
'up large coin amounts and obfuscate the recipient address.'),
|
||||
_('This may result in higher transactions fees.')
|
||||
]))
|
||||
multiple_cb.setChecked(multiple_change)
|
||||
multiple_cb.stateChanged.connect(on_multiple)
|
||||
tx_widgets.append((multiple_cb, None))
|
||||
|
||||
def fmt_docs(key, klass):
|
||||
lines = [ln.lstrip(" ") for ln in klass.__doc__.split("\n")]
|
||||
return '\n'.join([key, "", " ".join(lines)])
|
||||
|
||||
choosers = sorted(coinchooser.COIN_CHOOSERS.keys())
|
||||
if len(choosers) > 1:
|
||||
chooser_name = coinchooser.get_name(self.config)
|
||||
msg = _('Choose coin (UTXO) selection method. The following are available:\n\n')
|
||||
msg += '\n\n'.join(fmt_docs(*item) for item in coinchooser.COIN_CHOOSERS.items())
|
||||
chooser_label = HelpLabel(_('Coin selection') + ':', msg)
|
||||
chooser_combo = QComboBox()
|
||||
chooser_combo.addItems(choosers)
|
||||
i = choosers.index(chooser_name) if chooser_name in choosers else 0
|
||||
chooser_combo.setCurrentIndex(i)
|
||||
def on_chooser(x):
|
||||
chooser_name = choosers[chooser_combo.currentIndex()]
|
||||
self.config.set_key('coin_chooser', chooser_name)
|
||||
chooser_combo.currentIndexChanged.connect(on_chooser)
|
||||
tx_widgets.append((chooser_label, chooser_combo))
|
||||
|
||||
def on_unconf(x):
|
||||
self.config.set_key('confirmed_only', bool(x))
|
||||
conf_only = bool(self.config.get('confirmed_only', False))
|
||||
unconf_cb = QCheckBox(_('Spend only confirmed coins'))
|
||||
unconf_cb.setToolTip(_('Spend only confirmed inputs.'))
|
||||
unconf_cb.setChecked(conf_only)
|
||||
unconf_cb.stateChanged.connect(on_unconf)
|
||||
tx_widgets.append((unconf_cb, None))
|
||||
|
||||
def on_outrounding(x):
|
||||
self.config.set_key('coin_chooser_output_rounding', bool(x))
|
||||
enable_outrounding = bool(self.config.get('coin_chooser_output_rounding', False))
|
||||
outrounding_cb = QCheckBox(_('Enable output value rounding'))
|
||||
outrounding_cb.setToolTip(
|
||||
_('Set the value of the change output so that it has similar precision to the other outputs.') + '\n' +
|
||||
_('This might improve your privacy somewhat.') + '\n' +
|
||||
_('If enabled, at most 100 satoshis might be lost due to this, per transaction.'))
|
||||
outrounding_cb.setChecked(enable_outrounding)
|
||||
outrounding_cb.stateChanged.connect(on_outrounding)
|
||||
tx_widgets.append((outrounding_cb, None))
|
||||
|
||||
# Fiat Currency
|
||||
hist_checkbox = QCheckBox()
|
||||
hist_capgains_checkbox = QCheckBox()
|
||||
fiat_address_checkbox = QCheckBox()
|
||||
ccy_combo = QComboBox()
|
||||
ex_combo = QComboBox()
|
||||
|
||||
def update_currencies():
|
||||
if not self.window.fx: return
|
||||
currencies = sorted(self.fx.get_currencies(self.fx.get_history_config()))
|
||||
ccy_combo.clear()
|
||||
ccy_combo.addItems([_('None')] + currencies)
|
||||
if self.fx.is_enabled():
|
||||
ccy_combo.setCurrentIndex(ccy_combo.findText(self.fx.get_currency()))
|
||||
|
||||
def update_history_cb():
|
||||
if not self.fx: return
|
||||
hist_checkbox.setChecked(self.fx.get_history_config())
|
||||
hist_checkbox.setEnabled(self.fx.is_enabled())
|
||||
|
||||
def update_fiat_address_cb():
|
||||
if not self.fx: return
|
||||
fiat_address_checkbox.setChecked(self.fx.get_fiat_address_config())
|
||||
|
||||
def update_history_capgains_cb():
|
||||
if not self.fx: return
|
||||
hist_capgains_checkbox.setChecked(self.fx.get_history_capital_gains_config())
|
||||
hist_capgains_checkbox.setEnabled(hist_checkbox.isChecked())
|
||||
|
||||
def update_exchanges():
|
||||
if not self.fx: return
|
||||
b = self.fx.is_enabled()
|
||||
ex_combo.setEnabled(b)
|
||||
if b:
|
||||
h = self.fx.get_history_config()
|
||||
c = self.fx.get_currency()
|
||||
exchanges = self.fx.get_exchanges_by_ccy(c, h)
|
||||
else:
|
||||
exchanges = self.fx.get_exchanges_by_ccy('USD', False)
|
||||
ex_combo.blockSignals(True)
|
||||
ex_combo.clear()
|
||||
ex_combo.addItems(sorted(exchanges))
|
||||
ex_combo.setCurrentIndex(ex_combo.findText(self.fx.config_exchange()))
|
||||
ex_combo.blockSignals(False)
|
||||
|
||||
def on_currency(hh):
|
||||
if not self.fx: return
|
||||
b = bool(ccy_combo.currentIndex())
|
||||
ccy = str(ccy_combo.currentText()) if b else None
|
||||
self.fx.set_enabled(b)
|
||||
if b and ccy != self.fx.ccy:
|
||||
self.fx.set_currency(ccy)
|
||||
update_history_cb()
|
||||
update_exchanges()
|
||||
self.window.update_fiat()
|
||||
|
||||
def on_exchange(idx):
|
||||
exchange = str(ex_combo.currentText())
|
||||
if self.fx and self.fx.is_enabled() and exchange and exchange != self.fx.exchange.name():
|
||||
self.fx.set_exchange(exchange)
|
||||
|
||||
def on_history(checked):
|
||||
if not self.fx: return
|
||||
self.fx.set_history_config(checked)
|
||||
update_exchanges()
|
||||
self.window.history_model.refresh('on_history')
|
||||
if self.fx.is_enabled() and checked:
|
||||
self.fx.trigger_update()
|
||||
update_history_capgains_cb()
|
||||
|
||||
def on_history_capgains(checked):
|
||||
if not self.fx: return
|
||||
self.fx.set_history_capital_gains_config(checked)
|
||||
self.window.history_model.refresh('on_history_capgains')
|
||||
|
||||
def on_fiat_address(checked):
|
||||
if not self.fx: return
|
||||
self.fx.set_fiat_address_config(checked)
|
||||
self.window.address_list.refresh_headers()
|
||||
self.window.address_list.update()
|
||||
|
||||
update_currencies()
|
||||
update_history_cb()
|
||||
update_history_capgains_cb()
|
||||
update_fiat_address_cb()
|
||||
update_exchanges()
|
||||
ccy_combo.currentIndexChanged.connect(on_currency)
|
||||
hist_checkbox.stateChanged.connect(on_history)
|
||||
hist_capgains_checkbox.stateChanged.connect(on_history_capgains)
|
||||
fiat_address_checkbox.stateChanged.connect(on_fiat_address)
|
||||
ex_combo.currentIndexChanged.connect(on_exchange)
|
||||
|
||||
fiat_widgets = []
|
||||
fiat_widgets.append((QLabel(_('Fiat currency')), ccy_combo))
|
||||
fiat_widgets.append((QLabel(_('Show history rates')), hist_checkbox))
|
||||
fiat_widgets.append((QLabel(_('Show capital gains in history')), hist_capgains_checkbox))
|
||||
fiat_widgets.append((QLabel(_('Show Fiat balance for addresses')), fiat_address_checkbox))
|
||||
fiat_widgets.append((QLabel(_('Source')), ex_combo))
|
||||
|
||||
tabs_info = [
|
||||
(fee_widgets, _('Fees')),
|
||||
(tx_widgets, _('Transactions')),
|
||||
(gui_widgets, _('General')),
|
||||
(fiat_widgets, _('Fiat')),
|
||||
(server_widgets, _('PayServer')),
|
||||
(oa_widgets, _('OpenAlias')),
|
||||
]
|
||||
for widgets, name in tabs_info:
|
||||
tab = QWidget()
|
||||
grid = QGridLayout(tab)
|
||||
grid.setColumnStretch(0,1)
|
||||
for a,b in widgets:
|
||||
i = grid.rowCount()
|
||||
if b:
|
||||
if a:
|
||||
grid.addWidget(a, i, 0)
|
||||
grid.addWidget(b, i, 1)
|
||||
else:
|
||||
grid.addWidget(a, i, 0, 1, 2)
|
||||
tabs.addTab(tab, name)
|
||||
|
||||
vbox.addWidget(tabs)
|
||||
vbox.addStretch(1)
|
||||
vbox.addLayout(Buttons(CloseButton(self)))
|
||||
self.setLayout(vbox)
|
||||
|
||||
def set_alias_color(self):
|
||||
if not self.config.get('alias'):
|
||||
self.alias_e.setStyleSheet("")
|
||||
return
|
||||
if self.window.alias_info:
|
||||
alias_addr, alias_name, validated = self.window.alias_info
|
||||
self.alias_e.setStyleSheet((ColorScheme.GREEN if validated else ColorScheme.RED).as_stylesheet(True))
|
||||
else:
|
||||
self.alias_e.setStyleSheet(ColorScheme.RED.as_stylesheet(True))
|
||||
|
||||
def on_alias_edit(self):
|
||||
self.alias_e.setStyleSheet("")
|
||||
alias = str(self.alias_e.text())
|
||||
self.config.set_key('alias', alias, True)
|
||||
if alias:
|
||||
self.window.fetch_alias()
|
Loading…
Add table
Reference in a new issue