You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

optionsdialog.cpp 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. // Copyright (c) 2011-2016 The Starwels developers
  2. // Distributed under the MIT software license, see the accompanying
  3. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  4. #if defined(HAVE_CONFIG_H)
  5. #include "config/starwels-config.h"
  6. #endif
  7. #include "optionsdialog.h"
  8. #include "ui_optionsdialog.h"
  9. #include "starwelsunits.h"
  10. #include "guiutil.h"
  11. #include "optionsmodel.h"
  12. #include "validation.h" // for DEFAULT_SCRIPTCHECK_THREADS and MAX_SCRIPTCHECK_THREADS
  13. #include "netbase.h"
  14. #include "txdb.h" // for -dbcache defaults
  15. #ifdef ENABLE_WALLET
  16. #include "wallet/wallet.h" // for CWallet::GetRequiredFee()
  17. #endif
  18. #include <QDataWidgetMapper>
  19. #include <QDir>
  20. #include <QIntValidator>
  21. #include <QLocale>
  22. #include <QMessageBox>
  23. #include <QTimer>
  24. OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
  25. QDialog(parent),
  26. ui(new Ui::OptionsDialog),
  27. model(0),
  28. mapper(0)
  29. {
  30. ui->setupUi(this);
  31. /* Main elements init */
  32. ui->databaseCache->setMinimum(nMinDbCache);
  33. ui->databaseCache->setMaximum(nMaxDbCache);
  34. ui->threadsScriptVerif->setMinimum(-GetNumCores());
  35. ui->threadsScriptVerif->setMaximum(MAX_SCRIPTCHECK_THREADS);
  36. /* Network elements init */
  37. #ifndef USE_UPNP
  38. ui->mapPortUpnp->setEnabled(false);
  39. #endif
  40. ui->proxyIp->setEnabled(false);
  41. ui->proxyPort->setEnabled(false);
  42. ui->proxyPort->setValidator(new QIntValidator(1, 65535, this));
  43. ui->proxyIpTor->setEnabled(false);
  44. ui->proxyPortTor->setEnabled(false);
  45. ui->proxyPortTor->setValidator(new QIntValidator(1, 65535, this));
  46. connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyIp, SLOT(setEnabled(bool)));
  47. connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyPort, SLOT(setEnabled(bool)));
  48. connect(ui->connectSocks, SIGNAL(toggled(bool)), this, SLOT(updateProxyValidationState()));
  49. connect(ui->connectSocksTor, SIGNAL(toggled(bool)), ui->proxyIpTor, SLOT(setEnabled(bool)));
  50. connect(ui->connectSocksTor, SIGNAL(toggled(bool)), ui->proxyPortTor, SLOT(setEnabled(bool)));
  51. connect(ui->connectSocksTor, SIGNAL(toggled(bool)), this, SLOT(updateProxyValidationState()));
  52. /* Window elements init */
  53. #ifdef Q_OS_MAC
  54. /* remove Window tab on Mac */
  55. ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tabWindow));
  56. #endif
  57. /* remove Wallet tab in case of -disablewallet */
  58. if (!enableWallet) {
  59. ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tabWallet));
  60. }
  61. /* Display elements init */
  62. QDir translations(":translations");
  63. ui->starwelsAtStartup->setToolTip(ui->starwelsAtStartup->toolTip().arg(tr(PACKAGE_NAME)));
  64. ui->starwelsAtStartup->setText(ui->starwelsAtStartup->text().arg(tr(PACKAGE_NAME)));
  65. ui->openStarwelsConfButton->setToolTip(ui->openStarwelsConfButton->toolTip().arg(tr(PACKAGE_NAME)));
  66. ui->lang->setToolTip(ui->lang->toolTip().arg(tr(PACKAGE_NAME)));
  67. ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant(""));
  68. for (const QString &langStr : translations.entryList())
  69. {
  70. QLocale locale(langStr);
  71. /** check if the locale name consists of 2 parts (language_country) */
  72. if(langStr.contains("_"))
  73. {
  74. #if QT_VERSION >= 0x040800
  75. /** display language strings as "native language - native country (locale name)", e.g. "Deutsch - Deutschland (de)" */
  76. ui->lang->addItem(locale.nativeLanguageName() + QString(" - ") + locale.nativeCountryName() + QString(" (") + langStr + QString(")"), QVariant(langStr));
  77. #else
  78. /** display language strings as "language - country (locale name)", e.g. "German - Germany (de)" */
  79. ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" - ") + QLocale::countryToString(locale.country()) + QString(" (") + langStr + QString(")"), QVariant(langStr));
  80. #endif
  81. }
  82. else
  83. {
  84. #if QT_VERSION >= 0x040800
  85. /** display language strings as "native language (locale name)", e.g. "Deutsch (de)" */
  86. ui->lang->addItem(locale.nativeLanguageName() + QString(" (") + langStr + QString(")"), QVariant(langStr));
  87. #else
  88. /** display language strings as "language (locale name)", e.g. "German (de)" */
  89. ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" (") + langStr + QString(")"), QVariant(langStr));
  90. #endif
  91. }
  92. }
  93. #if QT_VERSION >= 0x040700
  94. ui->thirdPartyTxUrls->setPlaceholderText("https://example.com/tx/%s");
  95. #endif
  96. ui->unit->setModel(new StarwelsUnits(this));
  97. /* Widget-to-option mapper */
  98. mapper = new QDataWidgetMapper(this);
  99. mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
  100. mapper->setOrientation(Qt::Vertical);
  101. /* setup/change UI elements when proxy IPs are invalid/valid */
  102. ui->proxyIp->setCheckValidator(new ProxyAddressValidator(parent));
  103. ui->proxyIpTor->setCheckValidator(new ProxyAddressValidator(parent));
  104. connect(ui->proxyIp, SIGNAL(validationDidChange(QValidatedLineEdit *)), this, SLOT(updateProxyValidationState()));
  105. connect(ui->proxyIpTor, SIGNAL(validationDidChange(QValidatedLineEdit *)), this, SLOT(updateProxyValidationState()));
  106. connect(ui->proxyPort, SIGNAL(textChanged(const QString&)), this, SLOT(updateProxyValidationState()));
  107. connect(ui->proxyPortTor, SIGNAL(textChanged(const QString&)), this, SLOT(updateProxyValidationState()));
  108. }
  109. OptionsDialog::~OptionsDialog()
  110. {
  111. delete ui;
  112. }
  113. void OptionsDialog::setModel(OptionsModel *_model)
  114. {
  115. this->model = _model;
  116. if(_model)
  117. {
  118. /* check if client restart is needed and show persistent message */
  119. if (_model->isRestartRequired())
  120. showRestartWarning(true);
  121. QString strLabel = _model->getOverriddenByCommandLine();
  122. if (strLabel.isEmpty())
  123. strLabel = tr("none");
  124. ui->overriddenByCommandLineLabel->setText(strLabel);
  125. mapper->setModel(_model);
  126. setMapper();
  127. mapper->toFirst();
  128. updateDefaultProxyNets();
  129. }
  130. /* warn when one of the following settings changes by user action (placed here so init via mapper doesn't trigger them) */
  131. /* Main */
  132. connect(ui->databaseCache, SIGNAL(valueChanged(int)), this, SLOT(showRestartWarning()));
  133. connect(ui->threadsScriptVerif, SIGNAL(valueChanged(int)), this, SLOT(showRestartWarning()));
  134. /* Wallet */
  135. connect(ui->spendZeroConfChange, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning()));
  136. /* Network */
  137. connect(ui->allowIncoming, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning()));
  138. connect(ui->connectSocks, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning()));
  139. connect(ui->connectSocksTor, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning()));
  140. /* Display */
  141. connect(ui->lang, SIGNAL(valueChanged()), this, SLOT(showRestartWarning()));
  142. connect(ui->thirdPartyTxUrls, SIGNAL(textChanged(const QString &)), this, SLOT(showRestartWarning()));
  143. }
  144. void OptionsDialog::setMapper()
  145. {
  146. /* Main */
  147. mapper->addMapping(ui->starwelsAtStartup, OptionsModel::StartAtStartup);
  148. mapper->addMapping(ui->threadsScriptVerif, OptionsModel::ThreadsScriptVerif);
  149. mapper->addMapping(ui->databaseCache, OptionsModel::DatabaseCache);
  150. /* Wallet */
  151. mapper->addMapping(ui->spendZeroConfChange, OptionsModel::SpendZeroConfChange);
  152. mapper->addMapping(ui->coinControlFeatures, OptionsModel::CoinControlFeatures);
  153. /* Network */
  154. mapper->addMapping(ui->mapPortUpnp, OptionsModel::MapPortUPnP);
  155. mapper->addMapping(ui->allowIncoming, OptionsModel::Listen);
  156. mapper->addMapping(ui->connectSocks, OptionsModel::ProxyUse);
  157. mapper->addMapping(ui->proxyIp, OptionsModel::ProxyIP);
  158. mapper->addMapping(ui->proxyPort, OptionsModel::ProxyPort);
  159. mapper->addMapping(ui->connectSocksTor, OptionsModel::ProxyUseTor);
  160. mapper->addMapping(ui->proxyIpTor, OptionsModel::ProxyIPTor);
  161. mapper->addMapping(ui->proxyPortTor, OptionsModel::ProxyPortTor);
  162. /* Window */
  163. #ifndef Q_OS_MAC
  164. mapper->addMapping(ui->hideTrayIcon, OptionsModel::HideTrayIcon);
  165. mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray);
  166. mapper->addMapping(ui->minimizeOnClose, OptionsModel::MinimizeOnClose);
  167. #endif
  168. /* Display */
  169. mapper->addMapping(ui->lang, OptionsModel::Language);
  170. mapper->addMapping(ui->unit, OptionsModel::DisplayUnit);
  171. mapper->addMapping(ui->thirdPartyTxUrls, OptionsModel::ThirdPartyTxUrls);
  172. }
  173. void OptionsDialog::setOkButtonState(bool fState)
  174. {
  175. ui->okButton->setEnabled(fState);
  176. }
  177. void OptionsDialog::on_resetButton_clicked()
  178. {
  179. if(model)
  180. {
  181. // confirmation dialog
  182. QMessageBox::StandardButton btnRetVal = QMessageBox::question(this, tr("Confirm options reset"),
  183. tr("Client restart required to activate changes.") + "<br><br>" + tr("Client will be shut down. Do you want to proceed?"),
  184. QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);
  185. if(btnRetVal == QMessageBox::Cancel)
  186. return;
  187. /* reset all options and close GUI */
  188. model->Reset();
  189. QApplication::quit();
  190. }
  191. }
  192. void OptionsDialog::on_openStarwelsConfButton_clicked()
  193. {
  194. /* explain the purpose of the config file */
  195. QMessageBox::information(this, tr("Configuration options"),
  196. tr("The configuration file is used to specify advanced user options which override GUI settings. "
  197. "Additionally, any command-line options will override this configuration file."));
  198. /* show an error if there was some problem opening the file */
  199. if (!GUIUtil::openStarwelsConf())
  200. QMessageBox::critical(this, tr("Error"), tr("The configuration file could not be opened."));
  201. }
  202. void OptionsDialog::on_okButton_clicked()
  203. {
  204. mapper->submit();
  205. accept();
  206. updateDefaultProxyNets();
  207. }
  208. void OptionsDialog::on_cancelButton_clicked()
  209. {
  210. reject();
  211. }
  212. void OptionsDialog::on_hideTrayIcon_stateChanged(int fState)
  213. {
  214. if(fState)
  215. {
  216. ui->minimizeToTray->setChecked(false);
  217. ui->minimizeToTray->setEnabled(false);
  218. }
  219. else
  220. {
  221. ui->minimizeToTray->setEnabled(true);
  222. }
  223. }
  224. void OptionsDialog::showRestartWarning(bool fPersistent)
  225. {
  226. ui->statusLabel->setStyleSheet("QLabel { color: red; }");
  227. if(fPersistent)
  228. {
  229. ui->statusLabel->setText(tr("Client restart required to activate changes."));
  230. }
  231. else
  232. {
  233. ui->statusLabel->setText(tr("This change would require a client restart."));
  234. // clear non-persistent status label after 10 seconds
  235. // Todo: should perhaps be a class attribute, if we extend the use of statusLabel
  236. QTimer::singleShot(10000, this, SLOT(clearStatusLabel()));
  237. }
  238. }
  239. void OptionsDialog::clearStatusLabel()
  240. {
  241. ui->statusLabel->clear();
  242. if (model && model->isRestartRequired()) {
  243. showRestartWarning(true);
  244. }
  245. }
  246. void OptionsDialog::updateProxyValidationState()
  247. {
  248. QValidatedLineEdit *pUiProxyIp = ui->proxyIp;
  249. QValidatedLineEdit *otherProxyWidget = (pUiProxyIp == ui->proxyIpTor) ? ui->proxyIp : ui->proxyIpTor;
  250. if (pUiProxyIp->isValid() && (!ui->proxyPort->isEnabled() || ui->proxyPort->text().toInt() > 0) && (!ui->proxyPortTor->isEnabled() || ui->proxyPortTor->text().toInt() > 0))
  251. {
  252. setOkButtonState(otherProxyWidget->isValid()); //only enable ok button if both proxys are valid
  253. clearStatusLabel();
  254. }
  255. else
  256. {
  257. setOkButtonState(false);
  258. ui->statusLabel->setStyleSheet("QLabel { color: red; }");
  259. ui->statusLabel->setText(tr("The supplied proxy address is invalid."));
  260. }
  261. }
  262. void OptionsDialog::updateDefaultProxyNets()
  263. {
  264. proxyType proxy;
  265. std::string strProxy;
  266. QString strDefaultProxyGUI;
  267. GetProxy(NET_IPV4, proxy);
  268. strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
  269. strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
  270. (strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachIPv4->setChecked(true) : ui->proxyReachIPv4->setChecked(false);
  271. GetProxy(NET_IPV6, proxy);
  272. strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
  273. strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
  274. (strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachIPv6->setChecked(true) : ui->proxyReachIPv6->setChecked(false);
  275. GetProxy(NET_TOR, proxy);
  276. strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
  277. strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
  278. (strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachTor->setChecked(true) : ui->proxyReachTor->setChecked(false);
  279. }
  280. ProxyAddressValidator::ProxyAddressValidator(QObject *parent) :
  281. QValidator(parent)
  282. {
  283. }
  284. QValidator::State ProxyAddressValidator::validate(QString &input, int &pos) const
  285. {
  286. Q_UNUSED(pos);
  287. // Validate the proxy
  288. CService serv(LookupNumeric(input.toStdString().c_str(), 9050));
  289. proxyType addrProxy = proxyType(serv, true);
  290. if (addrProxy.IsValid())
  291. return QValidator::Acceptable;
  292. return QValidator::Invalid;
  293. }