Bitcoin ABC 0.32.4
P2P Digital Currency
optionsdialog.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-2016 The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#if defined(HAVE_CONFIG_H)
6#include <config/bitcoin-config.h>
7#endif
8
9#include <qt/forms/ui_optionsdialog.h>
10#include <qt/optionsdialog.h>
11
12#include <interfaces/node.h>
13#include <netbase.h>
14#include <node/caches.h>
15#include <qt/bitcoinunits.h>
16#include <qt/guiconstants.h>
17#include <qt/guiutil.h>
18#include <qt/optionsmodel.h>
19#include <validation.h> // for DEFAULT_SCRIPTCHECK_THREADS and MAX_SCRIPTCHECK_THREADS
20
21#include <QDataWidgetMapper>
22#include <QDir>
23#include <QIntValidator>
24#include <QLocale>
25#include <QMessageBox>
26#include <QSettings>
27#include <QSystemTrayIcon>
28#include <QTimer>
29
30OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet)
31 : QDialog(parent), ui(new Ui::OptionsDialog), model(nullptr),
32 mapper(nullptr) {
33 ui->setupUi(this);
34
35 /* Main elements init */
36 ui->databaseCache->setRange(MIN_DB_CACHE >> 20,
37 std::numeric_limits<int>::max());
38 ui->threadsScriptVerif->setMinimum(-GetNumCores());
39 ui->threadsScriptVerif->setMaximum(MAX_SCRIPTCHECK_THREADS);
40 ui->pruneWarning->setVisible(false);
41 ui->pruneWarning->setStyleSheet("QLabel { color: red; }");
42
43 ui->pruneSize->setEnabled(false);
44 connect(ui->prune, &QPushButton::toggled, ui->pruneSize,
45 &QWidget::setEnabled);
46
47/* Network elements init */
48#ifndef USE_UPNP
49 ui->mapPortUpnp->setEnabled(false);
50#endif
51#ifndef USE_NATPMP
52 ui->mapPortNatpmp->setEnabled(false);
53#endif
54 connect(this, &QDialog::accepted, [this]() {
55 QSettings settings;
56 model->node().mapPort(settings.value("fUseUPnP").toBool(),
57 settings.value("fUseNatpmp").toBool());
58 });
59
60 ui->proxyIp->setEnabled(false);
61 ui->proxyPort->setEnabled(false);
62 ui->proxyPort->setValidator(new QIntValidator(1, 65535, this));
63
64 ui->proxyIpTor->setEnabled(false);
65 ui->proxyPortTor->setEnabled(false);
66 ui->proxyPortTor->setValidator(new QIntValidator(1, 65535, this));
67
68 connect(ui->connectSocks, &QPushButton::toggled, ui->proxyIp,
69 &QWidget::setEnabled);
70 connect(ui->connectSocks, &QPushButton::toggled, ui->proxyPort,
71 &QWidget::setEnabled);
72 connect(ui->connectSocks, &QPushButton::toggled, this,
74
75 connect(ui->connectSocksTor, &QPushButton::toggled, ui->proxyIpTor,
76 &QWidget::setEnabled);
77 connect(ui->connectSocksTor, &QPushButton::toggled, ui->proxyPortTor,
78 &QWidget::setEnabled);
79 connect(ui->connectSocksTor, &QPushButton::toggled, this,
81
82 /* Window elements init */
83#ifdef Q_OS_MAC
84 /* remove Window tab on Mac */
85 ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tabWindow));
86 /* hide launch at startup option on macOS */
87 ui->bitcoinAtStartup->setVisible(false);
88 ui->verticalLayout_Main->removeWidget(ui->bitcoinAtStartup);
89 ui->verticalLayout_Main->removeItem(ui->horizontalSpacer_0_Main);
90#endif
91
92 /* remove Wallet tab and 3rd party-URL textbox in case of -disablewallet */
93 if (!enableWallet) {
94 ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tabWallet));
95 ui->thirdPartyTxUrlsLabel->setVisible(false);
96 ui->thirdPartyTxUrls->setVisible(false);
97 }
98
99 /* Display elements init */
100 QDir translations(":translations");
101
102 ui->bitcoinAtStartup->setToolTip(
103 ui->bitcoinAtStartup->toolTip().arg(PACKAGE_NAME));
104 ui->bitcoinAtStartup->setText(
105 ui->bitcoinAtStartup->text().arg(PACKAGE_NAME));
106
107 ui->openBitcoinConfButton->setToolTip(
108 ui->openBitcoinConfButton->toolTip().arg(PACKAGE_NAME));
109
110 ui->lang->setToolTip(ui->lang->toolTip().arg(PACKAGE_NAME));
111 ui->lang->addItem(QString("(") + tr("default") + QString(")"),
112 QVariant(""));
113 for (const QString &langStr : translations.entryList()) {
114 QLocale locale(langStr);
115
117 if (langStr.contains("_")) {
123 ui->lang->addItem(locale.nativeLanguageName() + QString(" - ") +
124#if (QT_VERSION >= QT_VERSION_CHECK(6, 2, 0))
125 locale.nativeTerritoryName() +
126#else
127 locale.nativeCountryName() +
128#endif
129 QString(" (") + langStr + QString(")"),
130 QVariant(langStr));
131 } else {
134 ui->lang->addItem(locale.nativeLanguageName() + QString(" (") +
135 langStr + QString(")"),
136 QVariant(langStr));
137 }
138 }
139 ui->unit->setModel(new BitcoinUnits(this));
140
141 /* Widget-to-option mapper */
142 mapper = new QDataWidgetMapper(this);
143 mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
144 mapper->setOrientation(Qt::Vertical);
145
147 connect(delegate, &GUIUtil::ItemDelegate::keyEscapePressed, this,
148 &OptionsDialog::reject);
149 mapper->setItemDelegate(delegate);
150
151 /* setup/change UI elements when proxy IPs are invalid/valid */
152 ui->proxyIp->setCheckValidator(new ProxyAddressValidator(parent));
153 ui->proxyIpTor->setCheckValidator(new ProxyAddressValidator(parent));
154 connect(ui->proxyIp, &QValidatedLineEdit::validationDidChange, this,
156 connect(ui->proxyIpTor, &QValidatedLineEdit::validationDidChange, this,
158 connect(ui->proxyPort, &QLineEdit::textChanged, this,
160 connect(ui->proxyPortTor, &QLineEdit::textChanged, this,
162
163 /* setup/change UI elements when third party tx URLs are invalid/valid */
164 ui->thirdPartyTxUrls->setCheckValidator(
165 new ThirdPartyTxUrlsValidator(parent));
166 connect(ui->thirdPartyTxUrls, &QValidatedLineEdit::validationDidChange,
168
169 if (!QSystemTrayIcon::isSystemTrayAvailable()) {
170 ui->hideTrayIcon->setChecked(true);
171 ui->hideTrayIcon->setEnabled(false);
172 ui->minimizeToTray->setChecked(false);
173 ui->minimizeToTray->setEnabled(false);
174 }
175
177}
178
180 delete ui;
181}
182
184 this->model = _model;
185
186 if (_model) {
187 /* check if client restart is needed and show persistent message */
188 if (_model->isRestartRequired()) {
189 showRestartWarning(true);
190 }
191
192 // Prune values are in GB to be consistent with intro.cpp
193 static constexpr uint64_t nMinDiskSpace =
196 ? 1
197 : 0;
198 ui->pruneSize->setRange(nMinDiskSpace, std::numeric_limits<int>::max());
199
200 QString strLabel = _model->getOverriddenByCommandLine();
201 if (strLabel.isEmpty()) {
202 strLabel = tr("none");
203 }
204 ui->overriddenByCommandLineLabel->setText(strLabel);
205
206 mapper->setModel(_model);
207 setMapper();
208 mapper->toFirst();
209
211 }
212
213 /* warn when one of the following settings changes by user action (placed
214 * here so init via mapper doesn't trigger them) */
215
216 /* Main */
217 connect(ui->prune, &QCheckBox::clicked, this,
219 connect(ui->prune, &QCheckBox::clicked, this,
221 connect(ui->pruneSize,
222 static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
224 connect(ui->databaseCache,
225 static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
227 connect(ui->threadsScriptVerif,
228 static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
230 /* Wallet */
231 connect(ui->spendZeroConfChange, &QCheckBox::clicked, this,
233 /* Network */
234 connect(ui->allowIncoming, &QCheckBox::clicked, this,
236 connect(ui->connectSocks, &QCheckBox::clicked, this,
238 connect(ui->connectSocksTor, &QCheckBox::clicked, this,
240 /* Display */
241 connect(
242 ui->lang,
243 static_cast<void (QValueComboBox::*)()>(&QValueComboBox::valueChanged),
244 [this] { showRestartWarning(); });
245 connect(ui->thirdPartyTxUrls, &QLineEdit::textChanged,
246 [this] { showRestartWarning(); });
247}
248
250 QWidget *tab_widget = nullptr;
251 if (tab == OptionsDialog::Tab::TAB_NETWORK) {
252 tab_widget = ui->tabNetwork;
253 }
254 if (tab == OptionsDialog::Tab::TAB_MAIN) {
255 tab_widget = ui->tabMain;
256 }
257 if (tab_widget && ui->tabWidget->currentWidget() != tab_widget) {
258 ui->tabWidget->setCurrentWidget(tab_widget);
259 }
260}
261
263 /* Main */
264 mapper->addMapping(ui->bitcoinAtStartup, OptionsModel::StartAtStartup);
265 mapper->addMapping(ui->threadsScriptVerif,
267 mapper->addMapping(ui->databaseCache, OptionsModel::DatabaseCache);
268 mapper->addMapping(ui->prune, OptionsModel::Prune);
269 mapper->addMapping(ui->pruneSize, OptionsModel::PruneSize);
270
271 /* Wallet */
272 mapper->addMapping(ui->spendZeroConfChange,
274 mapper->addMapping(ui->coinControlFeatures,
276
277 /* Network */
278 mapper->addMapping(ui->mapPortUpnp, OptionsModel::MapPortUPnP);
279 mapper->addMapping(ui->mapPortNatpmp, OptionsModel::MapPortNatpmp);
280 mapper->addMapping(ui->allowIncoming, OptionsModel::Listen);
281
282 mapper->addMapping(ui->connectSocks, OptionsModel::ProxyUse);
283 mapper->addMapping(ui->proxyIp, OptionsModel::ProxyIP);
284 mapper->addMapping(ui->proxyPort, OptionsModel::ProxyPort);
285
286 mapper->addMapping(ui->connectSocksTor, OptionsModel::ProxyUseTor);
287 mapper->addMapping(ui->proxyIpTor, OptionsModel::ProxyIPTor);
288 mapper->addMapping(ui->proxyPortTor, OptionsModel::ProxyPortTor);
289
290/* Window */
291#ifndef Q_OS_MAC
292 if (QSystemTrayIcon::isSystemTrayAvailable()) {
293 mapper->addMapping(ui->hideTrayIcon, OptionsModel::HideTrayIcon);
294 mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray);
295 }
296 mapper->addMapping(ui->minimizeOnClose, OptionsModel::MinimizeOnClose);
297#endif
298
299 /* Display */
300 mapper->addMapping(ui->lang, OptionsModel::Language);
301 mapper->addMapping(ui->unit, OptionsModel::DisplayUnit);
302 mapper->addMapping(ui->thirdPartyTxUrls, OptionsModel::ThirdPartyTxUrls);
303}
304
306 ui->okButton->setEnabled(fState);
307}
308
310 if (model) {
311 // confirmation dialog
312 QMessageBox::StandardButton btnRetVal = QMessageBox::question(
313 this, tr("Confirm options reset"),
314 tr("Client restart required to activate changes.") + "<br><br>" +
315 tr("Client will be shut down. Do you want to proceed?"),
316 QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);
317
318 if (btnRetVal == QMessageBox::Cancel) {
319 return;
320 }
321
322 /* reset all options and close GUI */
323 model->Reset();
324 close();
325 Q_EMIT quitOnReset();
326 }
327}
328
330 /* explain the purpose of the config file */
331 QMessageBox::information(
332 this, tr("Configuration options"),
333 tr("The configuration file is used to specify advanced user options "
334 "which override GUI settings. Additionally, any command-line "
335 "options will override this configuration file."));
336
337 /* show an error if there was some problem opening the file */
339 QMessageBox::critical(
340 this, tr("Error"),
341 tr("The configuration file could not be opened."));
342 }
343}
344
346 mapper->submit();
347 accept();
349}
350
352 reject();
353}
354
356 if (fState) {
357 ui->minimizeToTray->setChecked(false);
358 ui->minimizeToTray->setEnabled(false);
359 } else {
360 ui->minimizeToTray->setEnabled(true);
361 }
362}
363
365 ui->pruneWarning->setVisible(!ui->pruneWarning->isVisible());
366}
367
368void OptionsDialog::showRestartWarning(bool fPersistent) {
369 ui->statusLabel->setStyleSheet("QLabel { color: red; }");
370
371 if (fPersistent) {
372 ui->statusLabel->setText(
373 tr("Client restart required to activate changes."));
374 } else {
375 ui->statusLabel->setText(
376 tr("This change would require a client restart."));
377 // clear non-persistent status label after 10 seconds
378 // TODO: should perhaps be a class attribute, if we extend the use of
379 // statusLabel
380 QTimer::singleShot(10000, this, &OptionsDialog::clearStatusLabel);
381 }
382}
383
385 ui->statusLabel->clear();
386 if (model && model->isRestartRequired()) {
387 showRestartWarning(true);
388 }
389}
390
392 QValidatedLineEdit *pUiProxyIp = ui->proxyIp;
393 QValidatedLineEdit *otherProxyWidget =
394 (pUiProxyIp == ui->proxyIpTor) ? ui->proxyIp : ui->proxyIpTor;
395 if (pUiProxyIp->isValid() &&
396 (!ui->proxyPort->isEnabled() || ui->proxyPort->text().toInt() > 0) &&
397 (!ui->proxyPortTor->isEnabled() ||
398 ui->proxyPortTor->text().toInt() > 0)) {
399 // Only enable ok button if both proxys are valid
400 setOkButtonState(otherProxyWidget->isValid());
402 } else {
403 setOkButtonState(false);
404 ui->statusLabel->setStyleSheet("QLabel { color: red; }");
405 ui->statusLabel->setText(tr("The supplied proxy address is invalid."));
406 }
407}
408
410 proxyType proxy;
411 std::string strProxy;
412 QString strDefaultProxyGUI;
413
414 model->node().getProxy(NET_IPV4, proxy);
415 strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
416 strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
417 (strProxy == strDefaultProxyGUI.toStdString())
418 ? ui->proxyReachIPv4->setChecked(true)
419 : ui->proxyReachIPv4->setChecked(false);
420
421 model->node().getProxy(NET_IPV6, proxy);
422 strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
423 strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
424 (strProxy == strDefaultProxyGUI.toStdString())
425 ? ui->proxyReachIPv6->setChecked(true)
426 : ui->proxyReachIPv6->setChecked(false);
427
428 model->node().getProxy(NET_ONION, proxy);
429 strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
430 strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
431 (strProxy == strDefaultProxyGUI.toStdString())
432 ? ui->proxyReachTor->setChecked(true)
433 : ui->proxyReachTor->setChecked(false);
434}
435
437 : QValidator(parent) {}
438
439QValidator::State ProxyAddressValidator::validate(QString &input,
440 int &pos) const {
441 Q_UNUSED(pos);
442 // Validate the proxy
443 CService serv(LookupNumeric(input.toStdString(), DEFAULT_GUI_PROXY_PORT));
444 proxyType addrProxy = proxyType(serv, true);
445 if (addrProxy.IsValid()) {
446 return QValidator::Acceptable;
447 }
448
449 return QValidator::Invalid;
450}
451
453 QValidatedLineEdit *thirdPartyTxUrls = ui->thirdPartyTxUrls;
454 if (thirdPartyTxUrls->isValid()) {
455 // Only enable OK button if the third party tx URLS pattern is valid
456 setOkButtonState(true);
458 } else {
459 setOkButtonState(false);
460 ui->statusLabel->setStyleSheet("QLabel { color: red; }");
461 ui->statusLabel->setText(
462 tr("The third party transaction URLs should start with https://."));
463 }
464}
465
467 : QValidator(parent) {}
468
469QValidator::State ThirdPartyTxUrlsValidator::validate(QString &input,
470 int &pos) const {
471 Q_UNUSED(pos);
472 // Check the URL starts with https. All other schemes are rejected for
473 // security reasons.
474 if (input.isEmpty() || input.startsWith("https://")) {
475 return QValidator::Acceptable;
476 }
477
478 return QValidator::Invalid;
479}
Bitcoin unit definitions.
Definition: bitcoinunits.h:32
std::string ToStringIP() const
Definition: netaddress.cpp:623
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:545
std::string ToStringPort() const
Preferences dialog.
Definition: optionsdialog.h:43
void setModel(OptionsModel *model)
OptionsModel * model
Definition: optionsdialog.h:83
void setCurrentTab(OptionsDialog::Tab tab)
void on_okButton_clicked()
void on_openBitcoinConfButton_clicked()
void updateDefaultProxyNets()
void updateProxyValidationState()
void togglePruneWarning(bool enabled)
void on_hideTrayIcon_stateChanged(int fState)
void showRestartWarning(bool fPersistent=false)
void updateThirdPartyTxUrlsState()
void on_resetButton_clicked()
Ui::OptionsDialog * ui
Definition: optionsdialog.h:82
void quitOnReset()
OptionsDialog(QWidget *parent, bool enableWallet)
QDataWidgetMapper * mapper
Definition: optionsdialog.h:84
void clearStatusLabel()
void on_cancelButton_clicked()
void setOkButtonState(bool fState)
Interface from Qt to configuration data structure for Bitcoin client.
Definition: optionsmodel.h:48
bool isRestartRequired() const
interfaces::Node & node() const
Definition: optionsmodel.h:113
const QString & getOverriddenByCommandLine()
Definition: optionsmodel.h:101
Proxy address widget validator, checks for a valid proxy address.
Definition: optionsdialog.h:23
ProxyAddressValidator(QObject *parent)
State validate(QString &input, int &pos) const override
Line edit that can be marked as "invalid" to show input validation feedback.
void validationDidChange(QValidatedLineEdit *validatedLineEdit)
void valueChanged()
Third party tx URL validator, checks for an https link.
Definition: optionsdialog.h:33
ThirdPartyTxUrlsValidator(QObject *parent)
State validate(QString &input, int &pos) const override
virtual bool getProxy(Network net, proxyType &proxy_info)=0
Get proxy.
bool IsValid() const
Definition: netbase.h:58
CService proxy
Definition: netbase.h:60
static constexpr uint64_t GB_BYTES
Definition: guiconstants.h:53
bool openBitcoinConf()
Definition: guiutil.cpp:425
void handleCloseWindowShortcut(QWidget *w)
Definition: guiutil.cpp:410
@ NET_ONION
TOR (v2 or v3)
Definition: netaddress.h:56
@ NET_IPV6
IPv6.
Definition: netaddress.h:53
@ NET_IPV4
IPv4.
Definition: netaddress.h:50
CService LookupNumeric(const std::string &name, uint16_t portDefault, DNSLookupFn dns_lookup_function)
Resolve a service string with a numeric IP to its first corresponding service.
Definition: netbase.cpp:259
static constexpr size_t MIN_DB_CACHE
min. -dbcache (bytes)
Definition: caches.h:16
static constexpr uint16_t DEFAULT_GUI_PROXY_PORT
Definition: optionsmodel.h:24
int GetNumCores()
Return the number of cores available on the current system.
Definition: system.cpp:112
static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES
Require that user allocate at least 550 MiB for block & undo files (blk???.dat and rev?...
Definition: validation.h:116
static const int MAX_SCRIPTCHECK_THREADS
Maximum number of dedicated script-checking threads allowed.
Definition: validation.h:90