LCOV - code coverage report
Current view: top level - src/qt - optionsdialog.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 0 217 0.0 %
Date: 2020-09-26 01:30:44 Functions: 0 24 0.0 %

          Line data    Source code
       1             : // Copyright (c) 2011-2019 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/optionsdialog.h>
      10             : #include <qt/forms/ui_optionsdialog.h>
      11             : 
      12             : #include <qt/bitcoinunits.h>
      13             : #include <qt/guiconstants.h>
      14             : #include <qt/guiutil.h>
      15             : #include <qt/optionsmodel.h>
      16             : 
      17             : #include <interfaces/node.h>
      18             : #include <validation.h> // for DEFAULT_SCRIPTCHECK_THREADS and MAX_SCRIPTCHECK_THREADS
      19             : #include <netbase.h>
      20             : #include <txdb.h> // for -dbcache defaults
      21             : 
      22             : #include <QDataWidgetMapper>
      23             : #include <QDir>
      24             : #include <QIntValidator>
      25             : #include <QLocale>
      26             : #include <QMessageBox>
      27             : #include <QSystemTrayIcon>
      28             : #include <QTimer>
      29             : 
      30           0 : OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
      31           0 :     QDialog(parent),
      32           0 :     ui(new Ui::OptionsDialog),
      33           0 :     model(nullptr),
      34           0 :     mapper(nullptr)
      35           0 : {
      36           0 :     ui->setupUi(this);
      37             : 
      38             :     /* Main elements init */
      39           0 :     ui->databaseCache->setMinimum(nMinDbCache);
      40           0 :     ui->databaseCache->setMaximum(nMaxDbCache);
      41           0 :     ui->threadsScriptVerif->setMinimum(-GetNumCores());
      42           0 :     ui->threadsScriptVerif->setMaximum(MAX_SCRIPTCHECK_THREADS);
      43           0 :     ui->pruneWarning->setVisible(false);
      44           0 :     ui->pruneWarning->setStyleSheet("QLabel { color: red; }");
      45             : 
      46           0 :     ui->pruneSize->setEnabled(false);
      47           0 :     connect(ui->prune, &QPushButton::toggled, ui->pruneSize, &QWidget::setEnabled);
      48             : 
      49             :     /* Network elements init */
      50             : #ifndef USE_UPNP
      51             :     ui->mapPortUpnp->setEnabled(false);
      52             : #endif
      53             : 
      54           0 :     ui->proxyIp->setEnabled(false);
      55           0 :     ui->proxyPort->setEnabled(false);
      56           0 :     ui->proxyPort->setValidator(new QIntValidator(1, 65535, this));
      57             : 
      58           0 :     ui->proxyIpTor->setEnabled(false);
      59           0 :     ui->proxyPortTor->setEnabled(false);
      60           0 :     ui->proxyPortTor->setValidator(new QIntValidator(1, 65535, this));
      61             : 
      62           0 :     connect(ui->connectSocks, &QPushButton::toggled, ui->proxyIp, &QWidget::setEnabled);
      63           0 :     connect(ui->connectSocks, &QPushButton::toggled, ui->proxyPort, &QWidget::setEnabled);
      64           0 :     connect(ui->connectSocks, &QPushButton::toggled, this, &OptionsDialog::updateProxyValidationState);
      65             : 
      66           0 :     connect(ui->connectSocksTor, &QPushButton::toggled, ui->proxyIpTor, &QWidget::setEnabled);
      67           0 :     connect(ui->connectSocksTor, &QPushButton::toggled, ui->proxyPortTor, &QWidget::setEnabled);
      68           0 :     connect(ui->connectSocksTor, &QPushButton::toggled, this, &OptionsDialog::updateProxyValidationState);
      69             : 
      70             :     /* Window elements init */
      71             : #ifdef Q_OS_MAC
      72             :     /* remove Window tab on Mac */
      73           0 :     ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tabWindow));
      74             :     /* hide launch at startup option on macOS */
      75           0 :     ui->bitcoinAtStartup->setVisible(false);
      76           0 :     ui->verticalLayout_Main->removeWidget(ui->bitcoinAtStartup);
      77           0 :     ui->verticalLayout_Main->removeItem(ui->horizontalSpacer_0_Main);
      78             : #endif
      79             : 
      80             :     /* remove Wallet tab and 3rd party-URL textbox in case of -disablewallet */
      81           0 :     if (!enableWallet) {
      82           0 :         ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tabWallet));
      83           0 :         ui->thirdPartyTxUrlsLabel->setVisible(false);
      84           0 :         ui->thirdPartyTxUrls->setVisible(false);
      85             :     }
      86             : 
      87             :     /* Display elements init */
      88           0 :     QDir translations(":translations");
      89             : 
      90           0 :     ui->bitcoinAtStartup->setToolTip(ui->bitcoinAtStartup->toolTip().arg(PACKAGE_NAME));
      91           0 :     ui->bitcoinAtStartup->setText(ui->bitcoinAtStartup->text().arg(PACKAGE_NAME));
      92             : 
      93           0 :     ui->openBitcoinConfButton->setToolTip(ui->openBitcoinConfButton->toolTip().arg(PACKAGE_NAME));
      94             : 
      95           0 :     ui->lang->setToolTip(ui->lang->toolTip().arg(PACKAGE_NAME));
      96           0 :     ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant(""));
      97           0 :     for (const QString &langStr : translations.entryList())
      98             :     {
      99           0 :         QLocale locale(langStr);
     100             : 
     101             :         /** check if the locale name consists of 2 parts (language_country) */
     102           0 :         if(langStr.contains("_"))
     103             :         {
     104             :             /** display language strings as "native language - native country (locale name)", e.g. "Deutsch - Deutschland (de)" */
     105           0 :             ui->lang->addItem(locale.nativeLanguageName() + QString(" - ") + locale.nativeCountryName() + QString(" (") + langStr + QString(")"), QVariant(langStr));
     106           0 :         }
     107             :         else
     108             :         {
     109             :             /** display language strings as "native language (locale name)", e.g. "Deutsch (de)" */
     110           0 :             ui->lang->addItem(locale.nativeLanguageName() + QString(" (") + langStr + QString(")"), QVariant(langStr));
     111             :         }
     112           0 :     }
     113           0 :     ui->unit->setModel(new BitcoinUnits(this));
     114             : 
     115             :     /* Widget-to-option mapper */
     116           0 :     mapper = new QDataWidgetMapper(this);
     117           0 :     mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
     118           0 :     mapper->setOrientation(Qt::Vertical);
     119             : 
     120           0 :     GUIUtil::ItemDelegate* delegate = new GUIUtil::ItemDelegate(mapper);
     121           0 :     connect(delegate, &GUIUtil::ItemDelegate::keyEscapePressed, this, &OptionsDialog::reject);
     122           0 :     mapper->setItemDelegate(delegate);
     123             : 
     124             :     /* setup/change UI elements when proxy IPs are invalid/valid */
     125           0 :     ui->proxyIp->setCheckValidator(new ProxyAddressValidator(parent));
     126           0 :     ui->proxyIpTor->setCheckValidator(new ProxyAddressValidator(parent));
     127           0 :     connect(ui->proxyIp, &QValidatedLineEdit::validationDidChange, this, &OptionsDialog::updateProxyValidationState);
     128           0 :     connect(ui->proxyIpTor, &QValidatedLineEdit::validationDidChange, this, &OptionsDialog::updateProxyValidationState);
     129           0 :     connect(ui->proxyPort, &QLineEdit::textChanged, this, &OptionsDialog::updateProxyValidationState);
     130           0 :     connect(ui->proxyPortTor, &QLineEdit::textChanged, this, &OptionsDialog::updateProxyValidationState);
     131             : 
     132           0 :     if (!QSystemTrayIcon::isSystemTrayAvailable()) {
     133           0 :         ui->hideTrayIcon->setChecked(true);
     134           0 :         ui->hideTrayIcon->setEnabled(false);
     135           0 :         ui->minimizeToTray->setChecked(false);
     136           0 :         ui->minimizeToTray->setEnabled(false);
     137             :     }
     138             : 
     139           0 :     GUIUtil::handleCloseWindowShortcut(this);
     140           0 : }
     141             : 
     142           0 : OptionsDialog::~OptionsDialog()
     143           0 : {
     144           0 :     delete ui;
     145           0 : }
     146             : 
     147           0 : void OptionsDialog::setModel(OptionsModel *_model)
     148             : {
     149           0 :     this->model = _model;
     150             : 
     151           0 :     if(_model)
     152             :     {
     153             :         /* check if client restart is needed and show persistent message */
     154           0 :         if (_model->isRestartRequired())
     155           0 :             showRestartWarning(true);
     156             : 
     157             :         // Prune values are in GB to be consistent with intro.cpp
     158             :         static constexpr uint64_t nMinDiskSpace = (MIN_DISK_SPACE_FOR_BLOCK_FILES / GB_BYTES) + (MIN_DISK_SPACE_FOR_BLOCK_FILES % GB_BYTES) ? 1 : 0;
     159           0 :         ui->pruneSize->setRange(nMinDiskSpace, std::numeric_limits<int>::max());
     160             : 
     161           0 :         QString strLabel = _model->getOverriddenByCommandLine();
     162           0 :         if (strLabel.isEmpty())
     163           0 :             strLabel = tr("none");
     164           0 :         ui->overriddenByCommandLineLabel->setText(strLabel);
     165             : 
     166           0 :         mapper->setModel(_model);
     167           0 :         setMapper();
     168           0 :         mapper->toFirst();
     169             : 
     170           0 :         updateDefaultProxyNets();
     171           0 :     }
     172             : 
     173             :     /* warn when one of the following settings changes by user action (placed here so init via mapper doesn't trigger them) */
     174             : 
     175             :     /* Main */
     176           0 :     connect(ui->prune, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning);
     177           0 :     connect(ui->prune, &QCheckBox::clicked, this, &OptionsDialog::togglePruneWarning);
     178           0 :     connect(ui->pruneSize, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &OptionsDialog::showRestartWarning);
     179           0 :     connect(ui->databaseCache, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &OptionsDialog::showRestartWarning);
     180           0 :     connect(ui->threadsScriptVerif, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &OptionsDialog::showRestartWarning);
     181             :     /* Wallet */
     182           0 :     connect(ui->spendZeroConfChange, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning);
     183             :     /* Network */
     184           0 :     connect(ui->allowIncoming, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning);
     185           0 :     connect(ui->connectSocks, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning);
     186           0 :     connect(ui->connectSocksTor, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning);
     187             :     /* Display */
     188           0 :     connect(ui->lang, static_cast<void (QValueComboBox::*)()>(&QValueComboBox::valueChanged), [this]{ showRestartWarning(); });
     189           0 :     connect(ui->thirdPartyTxUrls, &QLineEdit::textChanged, [this]{ showRestartWarning(); });
     190           0 : }
     191             : 
     192           0 : void OptionsDialog::setCurrentTab(OptionsDialog::Tab tab)
     193             : {
     194             :     QWidget *tab_widget = nullptr;
     195           0 :     if (tab == OptionsDialog::Tab::TAB_NETWORK) tab_widget = ui->tabNetwork;
     196           0 :     if (tab == OptionsDialog::Tab::TAB_MAIN) tab_widget = ui->tabMain;
     197           0 :     if (tab_widget && ui->tabWidget->currentWidget() != tab_widget) {
     198           0 :         ui->tabWidget->setCurrentWidget(tab_widget);
     199           0 :     }
     200           0 : }
     201             : 
     202           0 : void OptionsDialog::setMapper()
     203             : {
     204             :     /* Main */
     205           0 :     mapper->addMapping(ui->bitcoinAtStartup, OptionsModel::StartAtStartup);
     206           0 :     mapper->addMapping(ui->threadsScriptVerif, OptionsModel::ThreadsScriptVerif);
     207           0 :     mapper->addMapping(ui->databaseCache, OptionsModel::DatabaseCache);
     208           0 :     mapper->addMapping(ui->prune, OptionsModel::Prune);
     209           0 :     mapper->addMapping(ui->pruneSize, OptionsModel::PruneSize);
     210             : 
     211             :     /* Wallet */
     212           0 :     mapper->addMapping(ui->spendZeroConfChange, OptionsModel::SpendZeroConfChange);
     213           0 :     mapper->addMapping(ui->coinControlFeatures, OptionsModel::CoinControlFeatures);
     214             : 
     215             :     /* Network */
     216           0 :     mapper->addMapping(ui->mapPortUpnp, OptionsModel::MapPortUPnP);
     217           0 :     mapper->addMapping(ui->allowIncoming, OptionsModel::Listen);
     218             : 
     219           0 :     mapper->addMapping(ui->connectSocks, OptionsModel::ProxyUse);
     220           0 :     mapper->addMapping(ui->proxyIp, OptionsModel::ProxyIP);
     221           0 :     mapper->addMapping(ui->proxyPort, OptionsModel::ProxyPort);
     222             : 
     223           0 :     mapper->addMapping(ui->connectSocksTor, OptionsModel::ProxyUseTor);
     224           0 :     mapper->addMapping(ui->proxyIpTor, OptionsModel::ProxyIPTor);
     225           0 :     mapper->addMapping(ui->proxyPortTor, OptionsModel::ProxyPortTor);
     226             : 
     227             :     /* Window */
     228             : #ifndef Q_OS_MAC
     229             :     if (QSystemTrayIcon::isSystemTrayAvailable()) {
     230             :         mapper->addMapping(ui->hideTrayIcon, OptionsModel::HideTrayIcon);
     231             :         mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray);
     232             :     }
     233             :     mapper->addMapping(ui->minimizeOnClose, OptionsModel::MinimizeOnClose);
     234             : #endif
     235             : 
     236             :     /* Display */
     237           0 :     mapper->addMapping(ui->lang, OptionsModel::Language);
     238           0 :     mapper->addMapping(ui->unit, OptionsModel::DisplayUnit);
     239           0 :     mapper->addMapping(ui->thirdPartyTxUrls, OptionsModel::ThirdPartyTxUrls);
     240           0 : }
     241             : 
     242           0 : void OptionsDialog::setOkButtonState(bool fState)
     243             : {
     244           0 :     ui->okButton->setEnabled(fState);
     245           0 : }
     246             : 
     247           0 : void OptionsDialog::on_resetButton_clicked()
     248             : {
     249           0 :     if(model)
     250             :     {
     251             :         // confirmation dialog
     252           0 :         QMessageBox::StandardButton btnRetVal = QMessageBox::question(this, tr("Confirm options reset"),
     253           0 :             tr("Client restart required to activate changes.") + "<br><br>" + tr("Client will be shut down. Do you want to proceed?"),
     254           0 :             QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);
     255             : 
     256           0 :         if(btnRetVal == QMessageBox::Cancel)
     257           0 :             return;
     258             : 
     259             :         /* reset all options and close GUI */
     260           0 :         model->Reset();
     261           0 :         QApplication::quit();
     262           0 :     }
     263           0 : }
     264             : 
     265           0 : void OptionsDialog::on_openBitcoinConfButton_clicked()
     266             : {
     267             :     /* explain the purpose of the config file */
     268           0 :     QMessageBox::information(this, tr("Configuration options"),
     269           0 :         tr("The configuration file is used to specify advanced user options which override GUI settings. "
     270             :            "Additionally, any command-line options will override this configuration file."));
     271             : 
     272             :     /* show an error if there was some problem opening the file */
     273           0 :     if (!GUIUtil::openBitcoinConf())
     274           0 :         QMessageBox::critical(this, tr("Error"), tr("The configuration file could not be opened."));
     275           0 : }
     276             : 
     277           0 : void OptionsDialog::on_okButton_clicked()
     278             : {
     279           0 :     mapper->submit();
     280           0 :     accept();
     281           0 :     updateDefaultProxyNets();
     282           0 : }
     283             : 
     284           0 : void OptionsDialog::on_cancelButton_clicked()
     285             : {
     286           0 :     reject();
     287           0 : }
     288             : 
     289           0 : void OptionsDialog::on_hideTrayIcon_stateChanged(int fState)
     290             : {
     291           0 :     if(fState)
     292             :     {
     293           0 :         ui->minimizeToTray->setChecked(false);
     294           0 :         ui->minimizeToTray->setEnabled(false);
     295           0 :     }
     296             :     else
     297             :     {
     298           0 :         ui->minimizeToTray->setEnabled(true);
     299             :     }
     300           0 : }
     301             : 
     302           0 : void OptionsDialog::togglePruneWarning(bool enabled)
     303             : {
     304           0 :     ui->pruneWarning->setVisible(!ui->pruneWarning->isVisible());
     305           0 : }
     306             : 
     307           0 : void OptionsDialog::showRestartWarning(bool fPersistent)
     308             : {
     309           0 :     ui->statusLabel->setStyleSheet("QLabel { color: red; }");
     310             : 
     311           0 :     if(fPersistent)
     312             :     {
     313           0 :         ui->statusLabel->setText(tr("Client restart required to activate changes."));
     314           0 :     }
     315             :     else
     316             :     {
     317           0 :         ui->statusLabel->setText(tr("This change would require a client restart."));
     318             :         // clear non-persistent status label after 10 seconds
     319             :         // Todo: should perhaps be a class attribute, if we extend the use of statusLabel
     320           0 :         QTimer::singleShot(10000, this, &OptionsDialog::clearStatusLabel);
     321             :     }
     322           0 : }
     323             : 
     324           0 : void OptionsDialog::clearStatusLabel()
     325             : {
     326           0 :     ui->statusLabel->clear();
     327           0 :     if (model && model->isRestartRequired()) {
     328           0 :         showRestartWarning(true);
     329           0 :     }
     330           0 : }
     331             : 
     332           0 : void OptionsDialog::updateProxyValidationState()
     333             : {
     334           0 :     QValidatedLineEdit *pUiProxyIp = ui->proxyIp;
     335           0 :     QValidatedLineEdit *otherProxyWidget = (pUiProxyIp == ui->proxyIpTor) ? ui->proxyIp : ui->proxyIpTor;
     336           0 :     if (pUiProxyIp->isValid() && (!ui->proxyPort->isEnabled() || ui->proxyPort->text().toInt() > 0) && (!ui->proxyPortTor->isEnabled() || ui->proxyPortTor->text().toInt() > 0))
     337             :     {
     338           0 :         setOkButtonState(otherProxyWidget->isValid()); //only enable ok button if both proxys are valid
     339           0 :         clearStatusLabel();
     340           0 :     }
     341             :     else
     342             :     {
     343           0 :         setOkButtonState(false);
     344           0 :         ui->statusLabel->setStyleSheet("QLabel { color: red; }");
     345           0 :         ui->statusLabel->setText(tr("The supplied proxy address is invalid."));
     346             :     }
     347           0 : }
     348             : 
     349           0 : void OptionsDialog::updateDefaultProxyNets()
     350             : {
     351           0 :     proxyType proxy;
     352           0 :     std::string strProxy;
     353           0 :     QString strDefaultProxyGUI;
     354             : 
     355           0 :     model->node().getProxy(NET_IPV4, proxy);
     356           0 :     strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
     357           0 :     strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
     358           0 :     (strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachIPv4->setChecked(true) : ui->proxyReachIPv4->setChecked(false);
     359             : 
     360           0 :     model->node().getProxy(NET_IPV6, proxy);
     361           0 :     strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
     362           0 :     strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
     363           0 :     (strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachIPv6->setChecked(true) : ui->proxyReachIPv6->setChecked(false);
     364             : 
     365           0 :     model->node().getProxy(NET_ONION, proxy);
     366           0 :     strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
     367           0 :     strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
     368           0 :     (strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachTor->setChecked(true) : ui->proxyReachTor->setChecked(false);
     369           0 : }
     370             : 
     371           0 : ProxyAddressValidator::ProxyAddressValidator(QObject *parent) :
     372           0 : QValidator(parent)
     373           0 : {
     374           0 : }
     375             : 
     376           0 : QValidator::State ProxyAddressValidator::validate(QString &input, int &pos) const
     377             : {
     378             :     Q_UNUSED(pos);
     379             :     // Validate the proxy
     380           0 :     CService serv(LookupNumeric(input.toStdString(), DEFAULT_GUI_PROXY_PORT));
     381           0 :     proxyType addrProxy = proxyType(serv, true);
     382           0 :     if (addrProxy.IsValid())
     383           0 :         return QValidator::Acceptable;
     384             : 
     385           0 :     return QValidator::Invalid;
     386           0 : }

Generated by: LCOV version 1.15