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