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.

optionsmodel.cpp 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  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 "optionsmodel.h"
  8. #include "starwelsunits.h"
  9. #include "guiutil.h"
  10. #include "amount.h"
  11. #include "init.h"
  12. #include "validation.h" // For DEFAULT_SCRIPTCHECK_THREADS
  13. #include "net.h"
  14. #include "netbase.h"
  15. #include "txdb.h" // for -dbcache defaults
  16. #include "intro.h"
  17. #ifdef ENABLE_WALLET
  18. #include "wallet/wallet.h"
  19. #include "wallet/walletdb.h"
  20. #endif
  21. #include <QNetworkProxy>
  22. #include <QSettings>
  23. #include <QStringList>
  24. OptionsModel::OptionsModel(QObject *parent, bool resetSettings) :
  25. QAbstractListModel(parent)
  26. {
  27. Init(resetSettings);
  28. }
  29. void OptionsModel::addOverriddenOption(const std::string &option)
  30. {
  31. strOverriddenByCommandLine += QString::fromStdString(option) + "=" + QString::fromStdString(gArgs.GetArg(option, "")) + " ";
  32. }
  33. // Writes all missing QSettings with their default values
  34. void OptionsModel::Init(bool resetSettings)
  35. {
  36. if (resetSettings)
  37. Reset();
  38. checkAndMigrate();
  39. QSettings settings;
  40. // Ensure restart flag is unset on client startup
  41. setRestartRequired(false);
  42. // These are Qt-only settings:
  43. // Window
  44. if (!settings.contains("fHideTrayIcon"))
  45. settings.setValue("fHideTrayIcon", false);
  46. fHideTrayIcon = settings.value("fHideTrayIcon").toBool();
  47. Q_EMIT hideTrayIconChanged(fHideTrayIcon);
  48. if (!settings.contains("fMinimizeToTray"))
  49. settings.setValue("fMinimizeToTray", false);
  50. fMinimizeToTray = settings.value("fMinimizeToTray").toBool() && !fHideTrayIcon;
  51. if (!settings.contains("fMinimizeOnClose"))
  52. settings.setValue("fMinimizeOnClose", false);
  53. fMinimizeOnClose = settings.value("fMinimizeOnClose").toBool();
  54. // Display
  55. if (!settings.contains("nDisplayUnit"))
  56. settings.setValue("nDisplayUnit", StarwelsUnits::MAI);
  57. nDisplayUnit = settings.value("nDisplayUnit").toInt();
  58. if (!settings.contains("strThirdPartyTxUrls"))
  59. settings.setValue("strThirdPartyTxUrls", "");
  60. strThirdPartyTxUrls = settings.value("strThirdPartyTxUrls", "").toString();
  61. if (!settings.contains("fCoinControlFeatures"))
  62. settings.setValue("fCoinControlFeatures", false);
  63. fCoinControlFeatures = settings.value("fCoinControlFeatures", false).toBool();
  64. // These are shared with the core or have a command-line parameter
  65. // and we want command-line parameters to overwrite the GUI settings.
  66. //
  67. // If setting doesn't exist create it with defaults.
  68. //
  69. // If gArgs.SoftSetArg() or gArgs.SoftSetBoolArg() return false we were overridden
  70. // by command-line and show this in the UI.
  71. // Main
  72. if (!settings.contains("nDatabaseCache"))
  73. settings.setValue("nDatabaseCache", (qint64)nDefaultDbCache);
  74. if (!gArgs.SoftSetArg("-dbcache", settings.value("nDatabaseCache").toString().toStdString()))
  75. addOverriddenOption("-dbcache");
  76. if (!settings.contains("nThreadsScriptVerif"))
  77. settings.setValue("nThreadsScriptVerif", DEFAULT_SCRIPTCHECK_THREADS);
  78. if (!gArgs.SoftSetArg("-par", settings.value("nThreadsScriptVerif").toString().toStdString()))
  79. addOverriddenOption("-par");
  80. if (!settings.contains("strDataDir"))
  81. settings.setValue("strDataDir", Intro::getDefaultDataDirectory());
  82. // Wallet
  83. #ifdef ENABLE_WALLET
  84. if (!settings.contains("bSpendZeroConfChange"))
  85. settings.setValue("bSpendZeroConfChange", true);
  86. if (!gArgs.SoftSetBoolArg("-spendzeroconfchange", settings.value("bSpendZeroConfChange").toBool()))
  87. addOverriddenOption("-spendzeroconfchange");
  88. #endif
  89. // Network
  90. if (!settings.contains("fUseUPnP"))
  91. settings.setValue("fUseUPnP", DEFAULT_UPNP);
  92. if (!gArgs.SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool()))
  93. addOverriddenOption("-upnp");
  94. if (!settings.contains("fListen"))
  95. settings.setValue("fListen", DEFAULT_LISTEN);
  96. if (!gArgs.SoftSetBoolArg("-listen", settings.value("fListen").toBool()))
  97. addOverriddenOption("-listen");
  98. if (!settings.contains("fUseProxy"))
  99. settings.setValue("fUseProxy", false);
  100. if (!settings.contains("addrProxy"))
  101. settings.setValue("addrProxy", "127.0.0.1:9050");
  102. // Only try to set -proxy, if user has enabled fUseProxy
  103. if (settings.value("fUseProxy").toBool() && !gArgs.SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString()))
  104. addOverriddenOption("-proxy");
  105. else if(!settings.value("fUseProxy").toBool() && !gArgs.GetArg("-proxy", "").empty())
  106. addOverriddenOption("-proxy");
  107. if (!settings.contains("fUseSeparateProxyTor"))
  108. settings.setValue("fUseSeparateProxyTor", false);
  109. if (!settings.contains("addrSeparateProxyTor"))
  110. settings.setValue("addrSeparateProxyTor", "127.0.0.1:9050");
  111. // Only try to set -onion, if user has enabled fUseSeparateProxyTor
  112. if (settings.value("fUseSeparateProxyTor").toBool() && !gArgs.SoftSetArg("-onion", settings.value("addrSeparateProxyTor").toString().toStdString()))
  113. addOverriddenOption("-onion");
  114. else if(!settings.value("fUseSeparateProxyTor").toBool() && !gArgs.GetArg("-onion", "").empty())
  115. addOverriddenOption("-onion");
  116. // Display
  117. if (!settings.contains("language"))
  118. settings.setValue("language", "");
  119. if (!gArgs.SoftSetArg("-lang", settings.value("language").toString().toStdString()))
  120. addOverriddenOption("-lang");
  121. language = settings.value("language").toString();
  122. }
  123. /** Helper function to copy contents from one QSettings to another.
  124. * By using allKeys this also covers nested settings in a hierarchy.
  125. */
  126. static void CopySettings(QSettings& dst, const QSettings& src)
  127. {
  128. for (const QString& key : src.allKeys()) {
  129. dst.setValue(key, src.value(key));
  130. }
  131. }
  132. /** Back up a QSettings to an ini-formatted file. */
  133. static void BackupSettings(const fs::path& filename, const QSettings& src)
  134. {
  135. qWarning() << "Backing up GUI settings to" << GUIUtil::boostPathToQString(filename);
  136. QSettings dst(GUIUtil::boostPathToQString(filename), QSettings::IniFormat);
  137. dst.clear();
  138. CopySettings(dst, src);
  139. }
  140. void OptionsModel::Reset()
  141. {
  142. QSettings settings;
  143. // Backup old settings to chain-specific datadir for troubleshooting
  144. BackupSettings(GetDataDir(true) / "guisettings.ini.bak", settings);
  145. // Save the strDataDir setting
  146. QString dataDir = Intro::getDefaultDataDirectory();
  147. dataDir = settings.value("strDataDir", dataDir).toString();
  148. // Remove all entries from our QSettings object
  149. settings.clear();
  150. // Set strDataDir
  151. settings.setValue("strDataDir", dataDir);
  152. // Set that this was reset
  153. settings.setValue("fReset", true);
  154. // default setting for OptionsModel::StartAtStartup - disabled
  155. if (GUIUtil::GetStartOnSystemStartup())
  156. GUIUtil::SetStartOnSystemStartup(false);
  157. }
  158. int OptionsModel::rowCount(const QModelIndex & parent) const
  159. {
  160. return OptionIDRowCount;
  161. }
  162. // read QSettings values and return them
  163. QVariant OptionsModel::data(const QModelIndex & index, int role) const
  164. {
  165. if(role == Qt::EditRole)
  166. {
  167. QSettings settings;
  168. switch(index.row())
  169. {
  170. case StartAtStartup:
  171. return GUIUtil::GetStartOnSystemStartup();
  172. case HideTrayIcon:
  173. return fHideTrayIcon;
  174. case MinimizeToTray:
  175. return fMinimizeToTray;
  176. case MapPortUPnP:
  177. #ifdef USE_UPNP
  178. return settings.value("fUseUPnP");
  179. #else
  180. return false;
  181. #endif
  182. case MinimizeOnClose:
  183. return fMinimizeOnClose;
  184. // default proxy
  185. case ProxyUse:
  186. return settings.value("fUseProxy", false);
  187. case ProxyIP: {
  188. // contains IP at index 0 and port at index 1
  189. QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts);
  190. return strlIpPort.at(0);
  191. }
  192. case ProxyPort: {
  193. // contains IP at index 0 and port at index 1
  194. QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts);
  195. return strlIpPort.at(1);
  196. }
  197. // separate Tor proxy
  198. case ProxyUseTor:
  199. return settings.value("fUseSeparateProxyTor", false);
  200. case ProxyIPTor: {
  201. // contains IP at index 0 and port at index 1
  202. QStringList strlIpPort = settings.value("addrSeparateProxyTor").toString().split(":", QString::SkipEmptyParts);
  203. return strlIpPort.at(0);
  204. }
  205. case ProxyPortTor: {
  206. // contains IP at index 0 and port at index 1
  207. QStringList strlIpPort = settings.value("addrSeparateProxyTor").toString().split(":", QString::SkipEmptyParts);
  208. return strlIpPort.at(1);
  209. }
  210. #ifdef ENABLE_WALLET
  211. case SpendZeroConfChange:
  212. return settings.value("bSpendZeroConfChange");
  213. #endif
  214. case DisplayUnit:
  215. return nDisplayUnit;
  216. case ThirdPartyTxUrls:
  217. return strThirdPartyTxUrls;
  218. case Language:
  219. return settings.value("language");
  220. case CoinControlFeatures:
  221. return fCoinControlFeatures;
  222. case DatabaseCache:
  223. return settings.value("nDatabaseCache");
  224. case ThreadsScriptVerif:
  225. return settings.value("nThreadsScriptVerif");
  226. case Listen:
  227. return settings.value("fListen");
  228. default:
  229. return QVariant();
  230. }
  231. }
  232. return QVariant();
  233. }
  234. // write QSettings values
  235. bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, int role)
  236. {
  237. bool successful = true; /* set to false on parse error */
  238. if(role == Qt::EditRole)
  239. {
  240. QSettings settings;
  241. switch(index.row())
  242. {
  243. case StartAtStartup:
  244. successful = GUIUtil::SetStartOnSystemStartup(value.toBool());
  245. break;
  246. case HideTrayIcon:
  247. fHideTrayIcon = value.toBool();
  248. settings.setValue("fHideTrayIcon", fHideTrayIcon);
  249. Q_EMIT hideTrayIconChanged(fHideTrayIcon);
  250. break;
  251. case MinimizeToTray:
  252. fMinimizeToTray = value.toBool();
  253. settings.setValue("fMinimizeToTray", fMinimizeToTray);
  254. break;
  255. case MapPortUPnP: // core option - can be changed on-the-fly
  256. settings.setValue("fUseUPnP", value.toBool());
  257. MapPort(value.toBool());
  258. break;
  259. case MinimizeOnClose:
  260. fMinimizeOnClose = value.toBool();
  261. settings.setValue("fMinimizeOnClose", fMinimizeOnClose);
  262. break;
  263. // default proxy
  264. case ProxyUse:
  265. if (settings.value("fUseProxy") != value) {
  266. settings.setValue("fUseProxy", value.toBool());
  267. setRestartRequired(true);
  268. }
  269. break;
  270. case ProxyIP: {
  271. // contains current IP at index 0 and current port at index 1
  272. QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts);
  273. // if that key doesn't exist or has a changed IP
  274. if (!settings.contains("addrProxy") || strlIpPort.at(0) != value.toString()) {
  275. // construct new value from new IP and current port
  276. QString strNewValue = value.toString() + ":" + strlIpPort.at(1);
  277. settings.setValue("addrProxy", strNewValue);
  278. setRestartRequired(true);
  279. }
  280. }
  281. break;
  282. case ProxyPort: {
  283. // contains current IP at index 0 and current port at index 1
  284. QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts);
  285. // if that key doesn't exist or has a changed port
  286. if (!settings.contains("addrProxy") || strlIpPort.at(1) != value.toString()) {
  287. // construct new value from current IP and new port
  288. QString strNewValue = strlIpPort.at(0) + ":" + value.toString();
  289. settings.setValue("addrProxy", strNewValue);
  290. setRestartRequired(true);
  291. }
  292. }
  293. break;
  294. // separate Tor proxy
  295. case ProxyUseTor:
  296. if (settings.value("fUseSeparateProxyTor") != value) {
  297. settings.setValue("fUseSeparateProxyTor", value.toBool());
  298. setRestartRequired(true);
  299. }
  300. break;
  301. case ProxyIPTor: {
  302. // contains current IP at index 0 and current port at index 1
  303. QStringList strlIpPort = settings.value("addrSeparateProxyTor").toString().split(":", QString::SkipEmptyParts);
  304. // if that key doesn't exist or has a changed IP
  305. if (!settings.contains("addrSeparateProxyTor") || strlIpPort.at(0) != value.toString()) {
  306. // construct new value from new IP and current port
  307. QString strNewValue = value.toString() + ":" + strlIpPort.at(1);
  308. settings.setValue("addrSeparateProxyTor", strNewValue);
  309. setRestartRequired(true);
  310. }
  311. }
  312. break;
  313. case ProxyPortTor: {
  314. // contains current IP at index 0 and current port at index 1
  315. QStringList strlIpPort = settings.value("addrSeparateProxyTor").toString().split(":", QString::SkipEmptyParts);
  316. // if that key doesn't exist or has a changed port
  317. if (!settings.contains("addrSeparateProxyTor") || strlIpPort.at(1) != value.toString()) {
  318. // construct new value from current IP and new port
  319. QString strNewValue = strlIpPort.at(0) + ":" + value.toString();
  320. settings.setValue("addrSeparateProxyTor", strNewValue);
  321. setRestartRequired(true);
  322. }
  323. }
  324. break;
  325. #ifdef ENABLE_WALLET
  326. case SpendZeroConfChange:
  327. if (settings.value("bSpendZeroConfChange") != value) {
  328. settings.setValue("bSpendZeroConfChange", value);
  329. setRestartRequired(true);
  330. }
  331. break;
  332. #endif
  333. case DisplayUnit:
  334. setDisplayUnit(value);
  335. break;
  336. case ThirdPartyTxUrls:
  337. if (strThirdPartyTxUrls != value.toString()) {
  338. strThirdPartyTxUrls = value.toString();
  339. settings.setValue("strThirdPartyTxUrls", strThirdPartyTxUrls);
  340. setRestartRequired(true);
  341. }
  342. break;
  343. case Language:
  344. if (settings.value("language") != value) {
  345. settings.setValue("language", value);
  346. setRestartRequired(true);
  347. }
  348. break;
  349. case CoinControlFeatures:
  350. fCoinControlFeatures = value.toBool();
  351. settings.setValue("fCoinControlFeatures", fCoinControlFeatures);
  352. Q_EMIT coinControlFeaturesChanged(fCoinControlFeatures);
  353. break;
  354. case DatabaseCache:
  355. if (settings.value("nDatabaseCache") != value) {
  356. settings.setValue("nDatabaseCache", value);
  357. setRestartRequired(true);
  358. }
  359. break;
  360. case ThreadsScriptVerif:
  361. if (settings.value("nThreadsScriptVerif") != value) {
  362. settings.setValue("nThreadsScriptVerif", value);
  363. setRestartRequired(true);
  364. }
  365. break;
  366. case Listen:
  367. if (settings.value("fListen") != value) {
  368. settings.setValue("fListen", value);
  369. setRestartRequired(true);
  370. }
  371. break;
  372. default:
  373. break;
  374. }
  375. }
  376. Q_EMIT dataChanged(index, index);
  377. return successful;
  378. }
  379. /** Updates current unit in memory, settings and emits displayUnitChanged(newUnit) signal */
  380. void OptionsModel::setDisplayUnit(const QVariant &value)
  381. {
  382. if (!value.isNull())
  383. {
  384. QSettings settings;
  385. nDisplayUnit = value.toInt();
  386. settings.setValue("nDisplayUnit", nDisplayUnit);
  387. Q_EMIT displayUnitChanged(nDisplayUnit);
  388. }
  389. }
  390. bool OptionsModel::getProxySettings(QNetworkProxy& proxy) const
  391. {
  392. // Directly query current base proxy, because
  393. // GUI settings can be overridden with -proxy.
  394. proxyType curProxy;
  395. if (GetProxy(NET_IPV4, curProxy)) {
  396. proxy.setType(QNetworkProxy::Socks5Proxy);
  397. proxy.setHostName(QString::fromStdString(curProxy.proxy.ToStringIP()));
  398. proxy.setPort(curProxy.proxy.GetPort());
  399. return true;
  400. }
  401. else
  402. proxy.setType(QNetworkProxy::NoProxy);
  403. return false;
  404. }
  405. void OptionsModel::setRestartRequired(bool fRequired)
  406. {
  407. QSettings settings;
  408. return settings.setValue("fRestartRequired", fRequired);
  409. }
  410. bool OptionsModel::isRestartRequired()
  411. {
  412. QSettings settings;
  413. return settings.value("fRestartRequired", false).toBool();
  414. }
  415. void OptionsModel::checkAndMigrate()
  416. {
  417. // Migration of default values
  418. // Check if the QSettings container was already loaded with this client version
  419. QSettings settings;
  420. static const char strSettingsVersionKey[] = "nSettingsVersion";
  421. int settingsVersion = settings.contains(strSettingsVersionKey) ? settings.value(strSettingsVersionKey).toInt() : 0;
  422. if (settingsVersion < CLIENT_VERSION)
  423. {
  424. // -dbcache was bumped from 100 to 300 in 0.13
  425. // see https://github.com/bitcoin/bitcoin/pull/8273
  426. // force people to upgrade to the new value if they are using 100MB
  427. if (settingsVersion < 130000 && settings.contains("nDatabaseCache") && settings.value("nDatabaseCache").toLongLong() == 100)
  428. settings.setValue("nDatabaseCache", (qint64)nDefaultDbCache);
  429. settings.setValue(strSettingsVersionKey, CLIENT_VERSION);
  430. }
  431. }