Bitcoin ABC 0.33.10
P2P Digital Currency
optionsmodel.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/optionsmodel.h>
10
11#include <clientversion.h>
12#include <common/args.h>
13#include <interfaces/node.h>
14#include <mapport.h>
15#include <net.h>
16#include <netbase.h>
17#include <node/caches.h>
19#include <qt/bitcoinunits.h>
20#include <qt/guiconstants.h>
21#include <qt/guiutil.h>
22#include <util/string.h>
23#include <validation.h> // For DEFAULT_SCRIPTCHECK_THREADS
24
25#include <QDebug> // needed by qInfo()
26#ifdef ENABLE_BIP70
27#include <QNetworkProxy>
28#endif
29#include <QSettings>
30#include <QStringList>
31
32using util::ToString;
33
34const char *DEFAULT_GUI_PROXY_HOST = "127.0.0.1";
35
36static QString GetDefaultProxyAddress();
37
38OptionsModel::OptionsModel(QObject *parent, bool resetSettings)
39 : QAbstractListModel(parent) {
40 Init(resetSettings);
41}
42
43void OptionsModel::addOverriddenOption(const std::string &option) {
45 QString::fromStdString(option) + "=" +
46 QString::fromStdString(gArgs.GetArg(option, "")) + " ";
47}
48
49// Writes all missing QSettings with their default values
50void OptionsModel::Init(bool resetSettings) {
51 if (resetSettings) {
52 Reset();
53 }
54
56
57 QSettings settings;
58
59 // Ensure restart flag is unset on client startup
60 setRestartRequired(false);
61
62 // These are Qt-only settings:
63
64 // Window
65 if (!settings.contains("fHideTrayIcon")) {
66 settings.setValue("fHideTrayIcon", false);
67 }
68 fHideTrayIcon = settings.value("fHideTrayIcon").toBool();
70
71 if (!settings.contains("fMinimizeToTray")) {
72 settings.setValue("fMinimizeToTray", false);
73 }
75 settings.value("fMinimizeToTray").toBool() && !fHideTrayIcon;
76
77 if (!settings.contains("fMinimizeOnClose")) {
78 settings.setValue("fMinimizeOnClose", false);
79 }
80 fMinimizeOnClose = settings.value("fMinimizeOnClose").toBool();
81
82 // Display
83 if (!settings.contains("nDisplayUnit")) {
84 settings.setValue("nDisplayUnit", BitcoinUnits::base);
85 }
86 nDisplayUnit = settings.value("nDisplayUnit").toInt();
87
88 if (!settings.contains("strThirdPartyTxUrls")) {
89 settings.setValue("strThirdPartyTxUrls", "");
90 }
91 strThirdPartyTxUrls = settings.value("strThirdPartyTxUrls", "").toString();
92
93 if (!settings.contains("fCoinControlFeatures")) {
94 settings.setValue("fCoinControlFeatures", false);
95 }
97 settings.value("fCoinControlFeatures", false).toBool();
98
99 // These are shared with the core or have a command-line parameter
100 // and we want command-line parameters to overwrite the GUI settings.
101 //
102 // If setting doesn't exist create it with defaults.
103 //
104 // If gArgs.SoftSetArg() or gArgs.SoftSetBoolArg() return false we were
105 // overridden
106 // by command-line and show this in the UI.
107
108 // Main
109 if (!settings.contains("bPrune")) {
110 settings.setValue("bPrune", false);
111 }
112 if (!settings.contains("nPruneSize")) {
113 settings.setValue("nPruneSize", DEFAULT_PRUNE_TARGET_GB);
114 }
115 SetPruneEnabled(settings.value("bPrune").toBool());
116
117 if (!settings.contains("nDatabaseCache")) {
118 settings.setValue("nDatabaseCache", (qint64)DEFAULT_DB_CACHE >> 20);
119 }
120 if (!gArgs.SoftSetArg(
121 "-dbcache",
122 settings.value("nDatabaseCache").toString().toStdString())) {
123 addOverriddenOption("-dbcache");
124 }
125
126 if (!settings.contains("nThreadsScriptVerif")) {
127 settings.setValue("nThreadsScriptVerif", DEFAULT_SCRIPTCHECK_THREADS);
128 }
129 if (!gArgs.SoftSetArg(
130 "-par",
131 settings.value("nThreadsScriptVerif").toString().toStdString())) {
132 addOverriddenOption("-par");
133 }
134
135 if (!settings.contains("strDataDir")) {
136 settings.setValue("strDataDir", GUIUtil::getDefaultDataDirectory());
137 }
138
139// Wallet
140#ifdef ENABLE_WALLET
141 if (!settings.contains("bSpendZeroConfChange")) {
142 settings.setValue("bSpendZeroConfChange", true);
143 }
145 "-spendzeroconfchange",
146 settings.value("bSpendZeroConfChange").toBool())) {
147 addOverriddenOption("-spendzeroconfchange");
148 }
149#endif
150
151 // Network
152 if (!settings.contains("fUseNatpmp")) {
153 settings.setValue("fUseNatpmp", DEFAULT_NATPMP);
154 }
155 if (!gArgs.SoftSetBoolArg("-natpmp",
156 settings.value("fUseNatpmp").toBool())) {
157 addOverriddenOption("-natpmp");
158 }
159
160 if (!settings.contains("fListen")) {
161 settings.setValue("fListen", DEFAULT_LISTEN);
162 }
163 if (!gArgs.SoftSetBoolArg("-listen", settings.value("fListen").toBool())) {
164 addOverriddenOption("-listen");
165 }
166
167 if (!settings.contains("fUseProxy")) {
168 settings.setValue("fUseProxy", false);
169 }
170 if (!settings.contains("addrProxy")) {
171 settings.setValue("addrProxy", GetDefaultProxyAddress());
172 }
173 // Only try to set -proxy, if user has enabled fUseProxy
174 if (settings.value("fUseProxy").toBool() &&
176 "-proxy", settings.value("addrProxy").toString().toStdString())) {
177 addOverriddenOption("-proxy");
178 } else if (!settings.value("fUseProxy").toBool() &&
179 !gArgs.GetArg("-proxy", "").empty()) {
180 addOverriddenOption("-proxy");
181 }
182
183 if (!settings.contains("fUseSeparateProxyTor")) {
184 settings.setValue("fUseSeparateProxyTor", false);
185 }
186 if (!settings.contains("addrSeparateProxyTor")) {
187 settings.setValue("addrSeparateProxyTor", GetDefaultProxyAddress());
188 }
189 // Only try to set -onion, if user has enabled fUseSeparateProxyTor
190 if (settings.value("fUseSeparateProxyTor").toBool() &&
192 "-onion",
193 settings.value("addrSeparateProxyTor").toString().toStdString())) {
194 addOverriddenOption("-onion");
195 } else if (!settings.value("fUseSeparateProxyTor").toBool() &&
196 !gArgs.GetArg("-onion", "").empty()) {
197 addOverriddenOption("-onion");
198 }
199
200 // Display
201 if (!settings.contains("language")) {
202 settings.setValue("language", "");
203 }
204 if (!gArgs.SoftSetArg(
205 "-lang", settings.value("language").toString().toStdString())) {
206 addOverriddenOption("-lang");
207 }
208
209 language = settings.value("language").toString();
210}
211
216static void CopySettings(QSettings &dst, const QSettings &src) {
217 for (const QString &key : src.allKeys()) {
218 dst.setValue(key, src.value(key));
219 }
220}
221
223static void BackupSettings(const fs::path &filename, const QSettings &src) {
224 qInfo() << "Backing up GUI settings to"
225 << GUIUtil::boostPathToQString(filename);
226 QSettings dst(GUIUtil::boostPathToQString(filename), QSettings::IniFormat);
227 dst.clear();
228 CopySettings(dst, src);
229}
230
232 QSettings settings;
233
234 // Backup old settings to chain-specific datadir for troubleshooting
235 BackupSettings(gArgs.GetDataDirNet() / "guisettings.ini.bak", settings);
236
237 // Save the strDataDir setting
238 QString dataDir = GUIUtil::getDefaultDataDirectory();
239 dataDir = settings.value("strDataDir", dataDir).toString();
240
241 // Remove all entries from our QSettings object
242 settings.clear();
243
244 // Set strDataDir
245 settings.setValue("strDataDir", dataDir);
246
247 // Set that this was reset
248 settings.setValue("fReset", true);
249
250 // default setting for OptionsModel::StartAtStartup - disabled
253 }
254}
255
256int OptionsModel::rowCount(const QModelIndex &parent) const {
257 return OptionIDRowCount;
258}
259
261 bool is_set;
262 QString ip;
263 QString port;
264};
265
266static ProxySetting GetProxySetting(QSettings &settings, const QString &name) {
267 static const ProxySetting default_val = {
269 QString("%1").arg(DEFAULT_GUI_PROXY_PORT)};
270 // Handle the case that the setting is not set at all
271 if (!settings.contains(name)) {
272 return default_val;
273 }
274 // contains IP at index 0 and port at index 1
275 QStringList ip_port =
276 GUIUtil::splitSkipEmptyParts(settings.value(name).toString(), ":");
277 if (ip_port.size() == 2) {
278 return {true, ip_port.at(0), ip_port.at(1)};
279 } else { // Invalid: return default
280 return default_val;
281 }
282}
283
284static void SetProxySetting(QSettings &settings, const QString &name,
285 const ProxySetting &ip_port) {
286 settings.setValue(name, ip_port.ip + ":" + ip_port.port);
287}
288
289static QString GetDefaultProxyAddress() {
290 return QString("%1:%2")
293}
294
295void OptionsModel::SetPruneEnabled(bool prune, bool force) {
296 QSettings settings;
297 settings.setValue("bPrune", prune);
298 const int64_t prune_target_mib =
299 PruneGBtoMiB(settings.value("nPruneSize").toInt());
300 std::string prune_val = prune ? ToString(prune_target_mib) : "0";
301 if (force) {
302 gArgs.ForceSetArg("-prune", prune_val);
303 return;
304 }
305 if (!gArgs.SoftSetArg("-prune", prune_val)) {
306 addOverriddenOption("-prune");
307 }
308}
309
310void OptionsModel::SetPruneTargetGB(int prune_target_gb, bool force) {
311 const bool prune = prune_target_gb > 0;
312 if (prune) {
313 QSettings settings;
314 settings.setValue("nPruneSize", prune_target_gb);
315 }
316 SetPruneEnabled(prune, force);
317}
318
319// read QSettings values and return them
320QVariant OptionsModel::data(const QModelIndex &index, int role) const {
321 if (role == Qt::EditRole) {
322 QSettings settings;
323 switch (index.row()) {
324 case StartAtStartup:
326 case HideTrayIcon:
327 return fHideTrayIcon;
328 case MinimizeToTray:
329 return fMinimizeToTray;
330 case MapPortNatpmp:
331 return settings.value("fUseNatpmp");
332 case MinimizeOnClose:
333 return fMinimizeOnClose;
334
335 // default proxy
336 case ProxyUse:
337 return settings.value("fUseProxy", false);
338 case ProxyIP:
339 return GetProxySetting(settings, "addrProxy").ip;
340 case ProxyPort:
341 return GetProxySetting(settings, "addrProxy").port;
342
343 // separate Tor proxy
344 case ProxyUseTor:
345 return settings.value("fUseSeparateProxyTor", false);
346 case ProxyIPTor:
347 return GetProxySetting(settings, "addrSeparateProxyTor").ip;
348 case ProxyPortTor:
349 return GetProxySetting(settings, "addrSeparateProxyTor").port;
350
351#ifdef ENABLE_WALLET
353 return settings.value("bSpendZeroConfChange");
354#endif
355 case DisplayUnit:
356 return nDisplayUnit;
357 case ThirdPartyTxUrls:
358 return strThirdPartyTxUrls;
359 case Language:
360 return settings.value("language");
363 case Prune:
364 return settings.value("bPrune");
365 case PruneSize:
366 return settings.value("nPruneSize");
367 case DatabaseCache:
368 return settings.value("nDatabaseCache");
370 return settings.value("nThreadsScriptVerif");
371 case Listen:
372 return settings.value("fListen");
373 default:
374 return QVariant();
375 }
376 }
377 return QVariant();
378}
379
380// write QSettings values
381bool OptionsModel::setData(const QModelIndex &index, const QVariant &value,
382 int role) {
383 bool successful = true; /* set to false on parse error */
384 if (role == Qt::EditRole) {
385 QSettings settings;
386 switch (index.row()) {
387 case StartAtStartup:
388 successful = GUIUtil::SetStartOnSystemStartup(value.toBool());
389 break;
390 case HideTrayIcon:
391 fHideTrayIcon = value.toBool();
392 settings.setValue("fHideTrayIcon", fHideTrayIcon);
394 break;
395 case MinimizeToTray:
396 fMinimizeToTray = value.toBool();
397 settings.setValue("fMinimizeToTray", fMinimizeToTray);
398 break;
399 case MapPortNatpmp: // core option - can be changed on-the-fly
400 settings.setValue("fUseNatpmp", value.toBool());
401 break;
402 case MinimizeOnClose:
403 fMinimizeOnClose = value.toBool();
404 settings.setValue("fMinimizeOnClose", fMinimizeOnClose);
405 break;
406
407 // default proxy
408 case ProxyUse:
409 if (settings.value("fUseProxy") != value) {
410 settings.setValue("fUseProxy", value.toBool());
411 setRestartRequired(true);
412 }
413 break;
414 case ProxyIP: {
415 auto ip_port = GetProxySetting(settings, "addrProxy");
416 if (!ip_port.is_set || ip_port.ip != value.toString()) {
417 ip_port.ip = value.toString();
418 SetProxySetting(settings, "addrProxy", ip_port);
419 setRestartRequired(true);
420 }
421 } break;
422 case ProxyPort: {
423 auto ip_port = GetProxySetting(settings, "addrProxy");
424 if (!ip_port.is_set || ip_port.port != value.toString()) {
425 ip_port.port = value.toString();
426 SetProxySetting(settings, "addrProxy", ip_port);
427 setRestartRequired(true);
428 }
429 } break;
430
431 // separate Tor proxy
432 case ProxyUseTor:
433 if (settings.value("fUseSeparateProxyTor") != value) {
434 settings.setValue("fUseSeparateProxyTor", value.toBool());
435 setRestartRequired(true);
436 }
437 break;
438 case ProxyIPTor: {
439 auto ip_port =
440 GetProxySetting(settings, "addrSeparateProxyTor");
441 if (!ip_port.is_set || ip_port.ip != value.toString()) {
442 ip_port.ip = value.toString();
443 SetProxySetting(settings, "addrSeparateProxyTor", ip_port);
444 setRestartRequired(true);
445 }
446 } break;
447 case ProxyPortTor: {
448 auto ip_port =
449 GetProxySetting(settings, "addrSeparateProxyTor");
450 if (!ip_port.is_set || ip_port.port != value.toString()) {
451 ip_port.port = value.toString();
452 SetProxySetting(settings, "addrSeparateProxyTor", ip_port);
453 setRestartRequired(true);
454 }
455 } break;
456
457#ifdef ENABLE_WALLET
459 if (settings.value("bSpendZeroConfChange") != value) {
460 settings.setValue("bSpendZeroConfChange", value);
461 setRestartRequired(true);
462 }
463 break;
464#endif
465 case DisplayUnit:
466 setDisplayUnit(value);
467 break;
468 case ThirdPartyTxUrls:
469 if (strThirdPartyTxUrls != value.toString()) {
470 strThirdPartyTxUrls = value.toString();
471 settings.setValue("strThirdPartyTxUrls",
473 setRestartRequired(true);
474 }
475 break;
476 case Language:
477 if (settings.value("language") != value) {
478 settings.setValue("language", value);
479 setRestartRequired(true);
480 }
481 break;
483 fCoinControlFeatures = value.toBool();
484 settings.setValue("fCoinControlFeatures", fCoinControlFeatures);
486 break;
487 case Prune:
488 if (settings.value("bPrune") != value) {
489 settings.setValue("bPrune", value);
490 setRestartRequired(true);
491 }
492 break;
493 case PruneSize:
494 if (settings.value("nPruneSize") != value) {
495 settings.setValue("nPruneSize", value);
496 setRestartRequired(true);
497 }
498 break;
499 case DatabaseCache:
500 if (settings.value("nDatabaseCache") != value) {
501 settings.setValue("nDatabaseCache", value);
502 setRestartRequired(true);
503 }
504 break;
506 if (settings.value("nThreadsScriptVerif") != value) {
507 settings.setValue("nThreadsScriptVerif", value);
508 setRestartRequired(true);
509 }
510 break;
511 case Listen:
512 if (settings.value("fListen") != value) {
513 settings.setValue("fListen", value);
514 setRestartRequired(true);
515 }
516 break;
517 default:
518 break;
519 }
520 }
521
522 Q_EMIT dataChanged(index, index);
523
524 return successful;
525}
526
529void OptionsModel::setDisplayUnit(const QVariant &value) {
530 if (!value.isNull()) {
531 QSettings settings;
532 nDisplayUnit = value.toInt();
533 settings.setValue("nDisplayUnit", nDisplayUnit);
535 }
536}
537
538#ifdef ENABLE_BIP70
539bool OptionsModel::getProxySettings(QNetworkProxy &proxy) const {
540 // Directly query current base proxy, because
541 // GUI settings can be overridden with -proxy.
542 Proxy curProxy;
543 if (node().getProxy(NET_IPV4, curProxy)) {
544 proxy.setType(QNetworkProxy::Socks5Proxy);
545 proxy.setHostName(
546 QString::fromStdString(curProxy.proxy.ToStringAddr()));
547 proxy.setPort(curProxy.proxy.GetPort());
548
549 return true;
550 } else {
551 proxy.setType(QNetworkProxy::NoProxy);
552 }
553
554 return false;
555}
556#endif
557
559 QSettings settings;
560 return settings.setValue("fRestartRequired", fRequired);
561}
562
564 QSettings settings;
565 return settings.value("fRestartRequired", false).toBool();
566}
567
569 // Migration of default values
570 // Check if the QSettings container was already loaded with this client
571 // version
572 QSettings settings;
573 static const char strSettingsVersionKey[] = "nSettingsVersion";
574 int settingsVersion = settings.contains(strSettingsVersionKey)
575 ? settings.value(strSettingsVersionKey).toInt()
576 : 0;
577 if (settingsVersion < CLIENT_VERSION) {
578 // -dbcache was bumped from 100 to 300 in 0.13
579 // see https://github.com/bitcoin/bitcoin/pull/8273
580 // force people to upgrade to the new value if they are using 100MB
581 if (settingsVersion < 130000 && settings.contains("nDatabaseCache") &&
582 settings.value("nDatabaseCache").toLongLong() == 100) {
583 settings.setValue("nDatabaseCache", (qint64)DEFAULT_DB_CACHE >> 20);
584 }
585
586 settings.setValue(strSettingsVersionKey, CLIENT_VERSION);
587 }
588
589 // Overwrite the 'addrProxy' setting in case it has been set to an illegal
590 // default value (see issue #12623; PR #12650).
591 if (settings.contains("addrProxy") &&
592 settings.value("addrProxy").toString().endsWith("%2")) {
593 settings.setValue("addrProxy", GetDefaultProxyAddress());
594 }
595
596 // Overwrite the 'addrSeparateProxyTor' setting in case it has been set to
597 // an illegal default value (see issue #12623; PR #12650).
598 if (settings.contains("addrSeparateProxyTor") &&
599 settings.value("addrSeparateProxyTor").toString().endsWith("%2")) {
600 settings.setValue("addrSeparateProxyTor", GetDefaultProxyAddress());
601 }
602}
ArgsManager gArgs
Definition: args.cpp:39
static constexpr int DEFAULT_SCRIPTCHECK_THREADS
-par default (number of script-checking threads, 0 = auto)
void ForceSetArg(const std::string &strArg, const std::string &strValue)
Definition: args.cpp:565
fs::path GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: args.h:239
bool SoftSetArg(const std::string &strArg, const std::string &strValue)
Set an argument if it doesn't already have a value.
Definition: args.cpp:547
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: args.cpp:462
bool SoftSetBoolArg(const std::string &strArg, bool fValue)
Set a boolean argument if it doesn't already have a value.
Definition: args.cpp:557
std::string ToStringAddr() const
Definition: netaddress.cpp:630
uint16_t GetPort() const
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
QString strOverriddenByCommandLine
Definition: optionsmodel.h:132
bool getProxySettings(QNetworkProxy &proxy) const
bool isRestartRequired() const
void Init(bool resetSettings=false)
bool fCoinControlFeatures
Definition: optionsmodel.h:130
interfaces::Node & node() const
Definition: optionsmodel.h:112
void setDisplayUnit(const QVariant &value)
Updates current unit in memory, settings and emits displayUnitChanged(newUnit) signal.
void coinControlFeaturesChanged(bool)
QString strThirdPartyTxUrls
Definition: optionsmodel.h:129
OptionsModel(QObject *parent=nullptr, bool resetSettings=false)
int rowCount(const QModelIndex &parent=QModelIndex()) const override
void SetPruneTargetGB(int prune_target_gb, bool force=false)
void SetPruneEnabled(bool prune, bool force=false)
void displayUnitChanged(int unit)
bool fHideTrayIcon
Definition: optionsmodel.h:124
bool fMinimizeToTray
Definition: optionsmodel.h:125
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
void checkAndMigrate()
QString language
Definition: optionsmodel.h:127
void addOverriddenOption(const std::string &option)
bool fMinimizeOnClose
Definition: optionsmodel.h:126
void setRestartRequired(bool fRequired)
void hideTrayIconChanged(bool)
Definition: netbase.h:67
CService proxy
Definition: netbase.h:77
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:30
static constexpr int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:38
static constexpr int DEFAULT_PRUNE_TARGET_GB
Definition: guiconstants.h:56
static constexpr bool DEFAULT_NATPMP
Definition: mapport.h:8
QString getDefaultDataDirectory()
Determine default data directory for operating system.
Definition: guiutil.cpp:300
QString boostPathToQString(const fs::path &path)
Convert OS specific boost path to QString through UTF-8.
Definition: guiutil.cpp:796
bool SetStartOnSystemStartup(bool fAutoStart)
Definition: guiutil.cpp:781
bool GetStartOnSystemStartup()
Definition: guiutil.cpp:778
QStringList splitSkipEmptyParts(const QString &s, const QString &separator)
Definition: guiutil.cpp:456
std::string ToString(const T &t)
Locale-independent version of std::to_string.
Definition: string.h:150
static const bool DEFAULT_LISTEN
-listen default
Definition: net.h:89
@ NET_IPV4
IPv4.
Definition: netaddress.h:43
static constexpr size_t DEFAULT_DB_CACHE
-dbcache default (bytes)
Definition: caches.h:18
static void CopySettings(QSettings &dst, const QSettings &src)
Helper function to copy contents from one QSettings to another.
static QString GetDefaultProxyAddress()
static ProxySetting GetProxySetting(QSettings &settings, const QString &name)
static void SetProxySetting(QSettings &settings, const QString &name, const ProxySetting &ip_port)
static void BackupSettings(const fs::path &filename, const QSettings &src)
Back up a QSettings to an ini-formatted file.
const char * DEFAULT_GUI_PROXY_HOST
static int64_t PruneGBtoMiB(int gb)
Convert displayed prune target GB to configured MiB.
Definition: optionsmodel.h:38
static constexpr uint16_t DEFAULT_GUI_PROXY_PORT
Definition: optionsmodel.h:24
const char * name
Definition: rest.cpp:47
static std::string ToString(const CService &ip)
Definition: db.h:36