[Qt] massive options/settings rework (no core changes)

- add new options for database cache and script verification threads
- add label which displays options that are overridden by command-line
  parameters
- proxy settings are not applied on-the-fly anymore and require a client
  restart (ApplyProxySettings() was removed and was not working very well
  anyway)
- re-work options reset and require a client shutdown (as it is much
  easier to do it this way without having to mess with what can be changed
  on-the-fly and what needs a restart anyway)
- options reset now writes default values for every single option
- when changing an option which requires a client restart display a 10
  second warning message in statusLabel (via a QTimer)
- when applying the changes via ok change that to a persistent message,
  which is displayed even after closing optionsdialog and re-open it, when
  no client restart was made
- remove dialog boxes used when changing language or proxy settings
- add setRestartRequired() and isRestartRequired() to OptionsModel and
  use the set function when updating options to signal OptionsDialog
  when a restart is needed
- resize optionsdialog a little and add some min sizes for certain GUI
  elements
- remove apply button from optionsdialog
- save and restore optionsdialog window position
- update nTransactionFee in QSettings with a set -paytxfee value when
  opening optionsdialog (I'm not sure about this yet, perhaps revert to
  not updating QSettings and just display current -paytxfee value in
  optionsdialog.)
This commit is contained in:
Philip Kaufmann 2013-12-03 09:10:10 +01:00
parent 65515c0d05
commit 7e195e8459
5 changed files with 442 additions and 242 deletions

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>540</width> <width>560</width>
<height>380</height> <height>400</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -19,9 +19,6 @@
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<widget class="QTabWidget" name="tabWidget"> <widget class="QTabWidget" name="tabWidget">
<property name="tabPosition">
<enum>QTabWidget::North</enum>
</property>
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>0</number>
</property> </property>
@ -86,21 +83,44 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<spacer name="verticalSpacer_Main">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_2_Main"> <layout class="QHBoxLayout" name="horizontalLayout_2_Main">
<item>
<widget class="QLabel" name="databaseCacheLabel">
<property name="text">
<string>Size of &amp;database cache</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="buddy">
<cstring>databaseCache</cstring>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="databaseCache">
<property name="toolTip">
<string>Set database cache size in megabytes (default: 25)</string>
</property>
<property name="maximum">
<number>1024</number>
</property>
<property name="value">
<number>25</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="databaseCacheUnitLabel">
<property name="text">
<string>MB</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
</widget>
</item>
<item> <item>
<spacer name="horizontalSpacer_2_Main"> <spacer name="horizontalSpacer_2_Main">
<property name="orientation"> <property name="orientation">
@ -114,21 +134,64 @@
</property> </property>
</spacer> </spacer>
</item> </item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3_Main">
<item> <item>
<widget class="QPushButton" name="resetButton"> <widget class="QLabel" name="threadsScriptVerifLabel">
<property name="toolTip">
<string>Reset all client options to default.</string>
</property>
<property name="text"> <property name="text">
<string>&amp;Reset Options</string> <string>Number of script &amp;verification threads</string>
</property> </property>
<property name="autoDefault"> <property name="textFormat">
<bool>false</bool> <enum>Qt::PlainText</enum>
</property>
<property name="buddy">
<cstring>threadsScriptVerif</cstring>
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QSpinBox" name="threadsScriptVerif">
<property name="toolTip">
<string>Set the number of script verification threads (up to 16, 0 = auto, &lt;0 = leave that many cores free, default: 0)</string>
</property>
<property name="minimum">
<number>-16</number>
</property>
<property name="maximum">
<number>16</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3_Main">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout> </layout>
</item> </item>
<item>
<spacer name="verticalSpacer_Main">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tabNetwork"> <widget class="QWidget" name="tabNetwork">
@ -149,15 +212,15 @@
<item> <item>
<widget class="QCheckBox" name="connectSocks"> <widget class="QCheckBox" name="connectSocks">
<property name="toolTip"> <property name="toolTip">
<string>Connect to the Bitcoin network through a SOCKS proxy (e.g. when connecting through Tor).</string> <string>Connect to the Bitcoin network through a SOCKS proxy.</string>
</property> </property>
<property name="text"> <property name="text">
<string>&amp;Connect through SOCKS proxy:</string> <string>&amp;Connect through SOCKS proxy (default proxy):</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_Network"> <layout class="QHBoxLayout" name="horizontalLayout_1_Network">
<item> <item>
<widget class="QLabel" name="proxyIpLabel"> <widget class="QLabel" name="proxyIpLabel">
<property name="text"> <property name="text">
@ -173,6 +236,12 @@
</item> </item>
<item> <item>
<widget class="QValidatedLineEdit" name="proxyIp"> <widget class="QValidatedLineEdit" name="proxyIp">
<property name="minimumSize">
<size>
<width>140</width>
<height>0</height>
</size>
</property>
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>140</width> <width>140</width>
@ -180,7 +249,7 @@
</size> </size>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>IP address of the proxy (e.g. 127.0.0.1)</string> <string>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -199,6 +268,12 @@
</item> </item>
<item> <item>
<widget class="QLineEdit" name="proxyPort"> <widget class="QLineEdit" name="proxyPort">
<property name="minimumSize">
<size>
<width>55</width>
<height>0</height>
</size>
</property>
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>55</width> <width>55</width>
@ -231,7 +306,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<spacer name="horizontalSpacer_Network"> <spacer name="horizontalSpacer_1_Network">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
@ -390,8 +465,67 @@
</widget> </widget>
</widget> </widget>
</item> </item>
<item>
<widget class="QFrame" name="frame">
<layout class="QVBoxLayout" name="verticalLayout_Bottom">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_Bottom">
<item>
<widget class="QLabel" name="overriddenByCommandLineInfoLabel">
<property name="text">
<string>Active command-line options that override above options: </string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_Bottom">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="overriddenByCommandLineLabel">
<property name="text">
<string/>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_Buttons"> <layout class="QHBoxLayout" name="horizontalLayout_Buttons">
<item>
<widget class="QPushButton" name="resetButton">
<property name="toolTip">
<string>Reset all client options to default.</string>
</property>
<property name="text">
<string>&amp;Reset Options</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
<item> <item>
<spacer name="horizontalSpacer_1"> <spacer name="horizontalSpacer_1">
<property name="orientation"> <property name="orientation">
@ -407,6 +541,12 @@
</item> </item>
<item> <item>
<widget class="QLabel" name="statusLabel"> <widget class="QLabel" name="statusLabel">
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="font"> <property name="font">
<font> <font>
<weight>75</weight> <weight>75</weight>
@ -454,16 +594,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QPushButton" name="applyButton">
<property name="text">
<string>&amp;Apply</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>
@ -473,17 +603,18 @@
<class>BitcoinAmountField</class> <class>BitcoinAmountField</class>
<extends>QLineEdit</extends> <extends>QLineEdit</extends>
<header>bitcoinamountfield.h</header> <header>bitcoinamountfield.h</header>
</customwidget> <container>1</container>
<customwidget>
<class>QValueComboBox</class>
<extends>QComboBox</extends>
<header>qvaluecombobox.h</header>
</customwidget> </customwidget>
<customwidget> <customwidget>
<class>QValidatedLineEdit</class> <class>QValidatedLineEdit</class>
<extends>QLineEdit</extends> <extends>QLineEdit</extends>
<header>qvalidatedlineedit.h</header> <header>qvalidatedlineedit.h</header>
</customwidget> </customwidget>
<customwidget>
<class>QValueComboBox</class>
<extends>QComboBox</extends>
<header>qvaluecombobox.h</header>
</customwidget>
</customwidgets> </customwidgets>
<resources/> <resources/>
<connections/> <connections/>

View File

@ -10,6 +10,7 @@
#include "ui_optionsdialog.h" #include "ui_optionsdialog.h"
#include "bitcoinunits.h" #include "bitcoinunits.h"
#include "guiutil.h"
#include "monitoreddatamapper.h" #include "monitoreddatamapper.h"
#include "optionsmodel.h" #include "optionsmodel.h"
@ -19,17 +20,20 @@
#include <QIntValidator> #include <QIntValidator>
#include <QLocale> #include <QLocale>
#include <QMessageBox> #include <QMessageBox>
#include <QTimer>
OptionsDialog::OptionsDialog(QWidget *parent) : OptionsDialog::OptionsDialog(QWidget *parent) :
QDialog(parent), QDialog(parent),
ui(new Ui::OptionsDialog), ui(new Ui::OptionsDialog),
model(0), model(0),
mapper(0), mapper(0),
fRestartWarningDisplayed_Proxy(false),
fRestartWarningDisplayed_Lang(false),
fProxyIpValid(true) fProxyIpValid(true)
{ {
ui->setupUi(this); ui->setupUi(this);
GUIUtil::restoreWindowGeometry("nOptionsDialogWindow", this->size(), this);
/* Main elements init */
ui->databaseCache->setMaximum(sizeof(void*) > 4 ? 4096 : 1024);
/* Network elements init */ /* Network elements init */
#ifndef USE_UPNP #ifndef USE_UPNP
@ -40,6 +44,7 @@ OptionsDialog::OptionsDialog(QWidget *parent) :
ui->proxyPort->setEnabled(false); ui->proxyPort->setEnabled(false);
ui->proxyPort->setValidator(new QIntValidator(1, 65535, this)); ui->proxyPort->setValidator(new QIntValidator(1, 65535, this));
/** SOCKS version is only selectable for default proxy and is always 5 for IPv6 and Tor */
ui->socksVersion->setEnabled(false); ui->socksVersion->setEnabled(false);
ui->socksVersion->addItem("5", 5); ui->socksVersion->addItem("5", 5);
ui->socksVersion->addItem("4", 4); ui->socksVersion->addItem("4", 4);
@ -95,16 +100,13 @@ OptionsDialog::OptionsDialog(QWidget *parent) :
mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit); mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
mapper->setOrientation(Qt::Vertical); mapper->setOrientation(Qt::Vertical);
/* enable apply button when data modified */
connect(mapper, SIGNAL(viewModified()), this, SLOT(enableApplyButton()));
/* disable apply button when new data loaded */
connect(mapper, SIGNAL(currentIndexChanged(int)), this, SLOT(disableApplyButton()));
/* setup/change UI elements when proxy IP is invalid/valid */ /* setup/change UI elements when proxy IP is invalid/valid */
connect(this, SIGNAL(proxyIpValid(QValidatedLineEdit *, bool)), this, SLOT(handleProxyIpValid(QValidatedLineEdit *, bool))); connect(this, SIGNAL(proxyIpChecks(QValidatedLineEdit *, int)), this, SLOT(doProxyIpChecks(QValidatedLineEdit *, int)));
} }
OptionsDialog::~OptionsDialog() OptionsDialog::~OptionsDialog()
{ {
GUIUtil::saveWindowGeometry("nOptionsDialogWindow", this);
delete ui; delete ui;
} }
@ -114,6 +116,15 @@ void OptionsDialog::setModel(OptionsModel *model)
if(model) if(model)
{ {
/* check if client restart is needed and show persistent message */
if (model->isRestartRequired())
showRestartWarning(true);
QString strLabel = model->getOverriddenByCommandLine();
if (strLabel.isEmpty())
strLabel = tr("none");
ui->overriddenByCommandLineLabel->setText(strLabel);
connect(model, SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); connect(model, SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
mapper->setModel(model); mapper->setModel(model);
@ -124,11 +135,15 @@ void OptionsDialog::setModel(OptionsModel *model)
/* update the display unit, to not use the default ("BTC") */ /* update the display unit, to not use the default ("BTC") */
updateDisplayUnit(); updateDisplayUnit();
/* warn only when language selection changes by user action (placed here so init via mapper doesn't trigger this) */ /* warn when one of the following settings changes by user action (placed here so init via mapper doesn't trigger them) */
connect(ui->lang, SIGNAL(valueChanged()), this, SLOT(showRestartWarning_Lang()));
/* disable apply button after settings are loaded as there is nothing to save */ /* Main */
disableApplyButton(); connect(ui->databaseCache, SIGNAL(valueChanged(int)), this, SLOT(showRestartWarning()));
connect(ui->threadsScriptVerif, SIGNAL(valueChanged(int)), this, SLOT(showRestartWarning()));
/* Network */
connect(ui->connectSocks, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning()));
/* Display */
connect(ui->lang, SIGNAL(valueChanged()), this, SLOT(showRestartWarning()));
} }
void OptionsDialog::setMapper() void OptionsDialog::setMapper()
@ -136,6 +151,8 @@ void OptionsDialog::setMapper()
/* Main */ /* Main */
mapper->addMapping(ui->transactionFee, OptionsModel::Fee); mapper->addMapping(ui->transactionFee, OptionsModel::Fee);
mapper->addMapping(ui->bitcoinAtStartup, OptionsModel::StartAtStartup); mapper->addMapping(ui->bitcoinAtStartup, OptionsModel::StartAtStartup);
mapper->addMapping(ui->threadsScriptVerif, OptionsModel::ThreadsScriptVerif);
mapper->addMapping(ui->databaseCache, OptionsModel::DatabaseCache);
/* Network */ /* Network */
mapper->addMapping(ui->mapPortUpnp, OptionsModel::MapPortUPnP); mapper->addMapping(ui->mapPortUpnp, OptionsModel::MapPortUPnP);
@ -158,31 +175,20 @@ void OptionsDialog::setMapper()
mapper->addMapping(ui->coinControlFeatures, OptionsModel::CoinControlFeatures); mapper->addMapping(ui->coinControlFeatures, OptionsModel::CoinControlFeatures);
} }
void OptionsDialog::enableApplyButton() void OptionsDialog::enableOkButton()
{ {
ui->applyButton->setEnabled(true); /* prevent enabling of the OK button when data modified, if there is an invalid proxy address present */
}
void OptionsDialog::disableApplyButton()
{
ui->applyButton->setEnabled(false);
}
void OptionsDialog::enableSaveButtons()
{
/* prevent enabling of the save buttons when data modified, if there is an invalid proxy address present */
if(fProxyIpValid) if(fProxyIpValid)
setSaveButtonState(true); setOkButtonState(true);
} }
void OptionsDialog::disableSaveButtons() void OptionsDialog::disableOkButton()
{ {
setSaveButtonState(false); setOkButtonState(false);
} }
void OptionsDialog::setSaveButtonState(bool fState) void OptionsDialog::setOkButtonState(bool fState)
{ {
ui->applyButton->setEnabled(fState);
ui->okButton->setEnabled(fState); ui->okButton->setEnabled(fState);
} }
@ -192,24 +198,15 @@ void OptionsDialog::on_resetButton_clicked()
{ {
// confirmation dialog // confirmation dialog
QMessageBox::StandardButton btnRetVal = QMessageBox::question(this, tr("Confirm options reset"), QMessageBox::StandardButton btnRetVal = QMessageBox::question(this, tr("Confirm options reset"),
tr("Some settings may require a client restart to take effect.") + "<br><br>" + tr("Do you want to proceed?"), tr("Client restart required to activate changes.") + "<br><br>" + tr("Client will be shutdown, do you want to proceed?"),
QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel); QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);
if(btnRetVal == QMessageBox::Cancel) if(btnRetVal == QMessageBox::Cancel)
return; return;
disableApplyButton(); /* reset all options and close Bitcoin-Qt */
/* disable restart warning messages display */
fRestartWarningDisplayed_Lang = fRestartWarningDisplayed_Proxy = true;
/* reset all options and save the default values (QSettings) */
model->Reset(); model->Reset();
mapper->toFirst(); QApplication::quit();
mapper->submit();
/* re-enable restart warning messages display */
fRestartWarningDisplayed_Lang = fRestartWarningDisplayed_Proxy = false;
} }
} }
@ -224,28 +221,26 @@ void OptionsDialog::on_cancelButton_clicked()
reject(); reject();
} }
void OptionsDialog::on_applyButton_clicked() void OptionsDialog::showRestartWarning(bool fPersistent)
{ {
mapper->submit(); ui->statusLabel->setStyleSheet("QLabel { color: red; }");
disableApplyButton();
}
void OptionsDialog::showRestartWarning_Proxy() if(fPersistent)
{
if(!fRestartWarningDisplayed_Proxy)
{ {
QMessageBox::warning(this, tr("Warning"), tr("This setting will take effect after restarting Bitcoin."), QMessageBox::Ok); ui->statusLabel->setText(tr("Client restart required to activate changes."));
fRestartWarningDisplayed_Proxy = true; }
else
{
ui->statusLabel->setText(tr("This change would require a client restart."));
// clear non-persistent status label after 10 seconds
// Todo: should perhaps be a class attribute, if we extend the use of statusLabel
QTimer::singleShot(10000, this, SLOT(clearStatusLabel()));
} }
} }
void OptionsDialog::showRestartWarning_Lang() void OptionsDialog::clearStatusLabel()
{ {
if(!fRestartWarningDisplayed_Lang) ui->statusLabel->clear();
{
QMessageBox::warning(this, tr("Warning"), tr("This setting will take effect after restarting Bitcoin."), QMessageBox::Ok);
fRestartWarningDisplayed_Lang = true;
}
} }
void OptionsDialog::updateDisplayUnit() void OptionsDialog::updateDisplayUnit()
@ -257,22 +252,25 @@ void OptionsDialog::updateDisplayUnit()
} }
} }
void OptionsDialog::handleProxyIpValid(QValidatedLineEdit *object, bool fState) void OptionsDialog::doProxyIpChecks(QValidatedLineEdit *pUiProxyIp, int nProxyPort)
{ {
// this is used in a check before re-enabling the save buttons Q_UNUSED(nProxyPort);
fProxyIpValid = fState;
if(fProxyIpValid) const std::string strAddrProxy = pUiProxyIp->text().toStdString();
CService addrProxy;
/* Check for a valid IPv4 / IPv6 address */
if (!(fProxyIpValid = LookupNumeric(strAddrProxy.c_str(), addrProxy)))
{ {
enableSaveButtons(); disableOkButton();
ui->statusLabel->clear(); pUiProxyIp->setValid(false);
ui->statusLabel->setStyleSheet("QLabel { color: red; }");
ui->statusLabel->setText(tr("The supplied proxy address is invalid."));
} }
else else
{ {
disableSaveButtons(); enableOkButton();
object->setValid(fProxyIpValid); ui->statusLabel->clear();
ui->statusLabel->setStyleSheet("QLabel { color: red; }");
ui->statusLabel->setText(tr("The supplied proxy address is invalid."));
} }
} }
@ -282,9 +280,7 @@ bool OptionsDialog::eventFilter(QObject *object, QEvent *event)
{ {
if(object == ui->proxyIp) if(object == ui->proxyIp)
{ {
CService addr; emit proxyIpChecks(ui->proxyIp, ui->proxyPort->text().toInt());
/* Check proxyIp for a valid IPv4/IPv6 address and emit the proxyIpValid signal */
emit proxyIpValid(ui->proxyIp, LookupNumeric(ui->proxyIp->text().toStdString().c_str(), addr));
} }
} }
return QDialog::eventFilter(object, event); return QDialog::eventFilter(object, event);

View File

@ -31,35 +31,28 @@ protected:
bool eventFilter(QObject *object, QEvent *event); bool eventFilter(QObject *object, QEvent *event);
private slots: private slots:
/* enable only apply button */ /* enable OK button */
void enableApplyButton(); void enableOkButton();
/* disable only apply button */ /* disable OK button */
void disableApplyButton(); void disableOkButton();
/* enable apply button and OK button */ /* set OK button state (enabled / disabled) */
void enableSaveButtons(); void setOkButtonState(bool fState);
/* disable apply button and OK button */
void disableSaveButtons();
/* set apply button and OK button state (enabled / disabled) */
void setSaveButtonState(bool fState);
void on_resetButton_clicked(); void on_resetButton_clicked();
void on_okButton_clicked(); void on_okButton_clicked();
void on_cancelButton_clicked(); void on_cancelButton_clicked();
void on_applyButton_clicked();
void showRestartWarning_Proxy(); void showRestartWarning(bool fPersistent = false);
void showRestartWarning_Lang(); void clearStatusLabel();
void updateDisplayUnit(); void updateDisplayUnit();
void handleProxyIpValid(QValidatedLineEdit *object, bool fState); void doProxyIpChecks(QValidatedLineEdit *pUiProxyIp, int nProxyPort);
signals: signals:
void proxyIpValid(QValidatedLineEdit *object, bool fValid); void proxyIpChecks(QValidatedLineEdit *pUiProxyIp, int nProxyPort);
private: private:
Ui::OptionsDialog *ui; Ui::OptionsDialog *ui;
OptionsModel *model; OptionsModel *model;
MonitoredDataMapper *mapper; MonitoredDataMapper *mapper;
bool fRestartWarningDisplayed_Proxy;
bool fRestartWarningDisplayed_Lang;
bool fProxyIpValid; bool fProxyIpValid;
}; };

View File

@ -18,6 +18,7 @@
#include "walletdb.h" #include "walletdb.h"
#include <QSettings> #include <QSettings>
#include <QStringList>
OptionsModel::OptionsModel(QObject *parent) : OptionsModel::OptionsModel(QObject *parent) :
QAbstractListModel(parent) QAbstractListModel(parent)
@ -25,79 +26,114 @@ OptionsModel::OptionsModel(QObject *parent) :
Init(); Init();
} }
bool static ApplyProxySettings() // Writes all missing QSettings with their default values
{
QSettings settings;
CService addrProxy(settings.value("addrProxy", "127.0.0.1:9050").toString().toStdString());
int nSocksVersion(settings.value("nSocksVersion", 5).toInt());
if (!settings.value("fUseProxy", false).toBool()) {
addrProxy = CService();
nSocksVersion = 0;
return false;
}
if (nSocksVersion && !addrProxy.IsValid())
return false;
if (!IsLimited(NET_IPV4))
SetProxy(NET_IPV4, addrProxy, nSocksVersion);
if (nSocksVersion > 4) {
#ifdef USE_IPV6
if (!IsLimited(NET_IPV6))
SetProxy(NET_IPV6, addrProxy, nSocksVersion);
#endif
SetNameProxy(addrProxy, nSocksVersion);
}
return true;
}
void OptionsModel::Init() void OptionsModel::Init()
{ {
QSettings settings; QSettings settings;
// Ensure restart flag is unset on client startup
setRestartRequired(false);
// These are Qt-only settings: // These are Qt-only settings:
nDisplayUnit = settings.value("nDisplayUnit", BitcoinUnits::BTC).toInt();
// Window
if (!settings.contains("fMinimizeToTray"))
settings.setValue("fMinimizeToTray", false);
fMinimizeToTray = settings.value("fMinimizeToTray").toBool();
if (!settings.contains("fMinimizeOnClose"))
settings.setValue("fMinimizeOnClose", false);
fMinimizeOnClose = settings.value("fMinimizeOnClose").toBool();
// Display
if (!settings.contains("nDisplayUnit"))
settings.setValue("nDisplayUnit", BitcoinUnits::BTC);
nDisplayUnit = settings.value("nDisplayUnit").toInt();
if (!settings.contains("bDisplayAddresses"))
settings.setValue("bDisplayAddresses", false);
bDisplayAddresses = settings.value("bDisplayAddresses", false).toBool(); bDisplayAddresses = settings.value("bDisplayAddresses", false).toBool();
fMinimizeToTray = settings.value("fMinimizeToTray", false).toBool();
fMinimizeOnClose = settings.value("fMinimizeOnClose", false).toBool(); if (!settings.contains("fCoinControlFeatures"))
nTransactionFee = settings.value("nTransactionFee").toLongLong(); settings.setValue("fCoinControlFeatures", false);
language = settings.value("language", "").toString();
fCoinControlFeatures = settings.value("fCoinControlFeatures", false).toBool(); fCoinControlFeatures = settings.value("fCoinControlFeatures", false).toBool();
// These are shared with core Bitcoin; we want // These are shared with the core or have a command-line parameter
// command-line options to override the GUI settings: // and we want command-line parameters to overwrite the GUI settings.
if (settings.contains("fUseUPnP")) //
SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool()); // If setting doesn't exist create it with defaults.
if (settings.contains("addrProxy") && settings.value("fUseProxy").toBool()) //
SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString()); // If SoftSetArg() or SoftSetBoolArg() return false we were overridden
if (settings.contains("nSocksVersion") && settings.value("fUseProxy").toBool()) // by command-line and show this in the UI.
SoftSetArg("-socks", settings.value("nSocksVersion").toString().toStdString());
if (!language.isEmpty()) // Main
SoftSetArg("-lang", language.toStdString()); if (!settings.contains("nTransactionFee"))
settings.setValue("nTransactionFee", 0);
if (!settings.contains("nDatabaseCache"))
settings.setValue("nDatabaseCache", 25);
if (!SoftSetArg("-dbcache", settings.value("nDatabaseCache").toString().toStdString()))
strOverriddenByCommandLine += "-dbcache ";
if (!settings.contains("nThreadsScriptVerif"))
settings.setValue("nThreadsScriptVerif", 0);
if (!SoftSetArg("-par", settings.value("nThreadsScriptVerif").toString().toStdString()))
strOverriddenByCommandLine += "-par ";
// Network
if (!settings.contains("fUseUPnP"))
#ifdef USE_UPNP
settings.setValue("fUseUPnP", true);
#else
settings.setValue("fUseUPnP", false);
#endif
if (!SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool()))
strOverriddenByCommandLine += "-upnp ";
if (!settings.contains("fUseProxy"))
settings.setValue("fUseProxy", false);
if (!settings.contains("addrProxy"))
settings.setValue("addrProxy", "127.0.0.1:9050");
// Only try to set -proxy, if user has enabled fUseProxy
if (settings.value("fUseProxy").toBool() && !SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString()))
strOverriddenByCommandLine += "-proxy ";
if (!settings.contains("nSocksVersion"))
settings.setValue("nSocksVersion", 5);
// Only try to set -socks, if user has enabled fUseProxy
if (settings.value("fUseProxy").toBool() && !SoftSetArg("-socks", settings.value("nSocksVersion").toString().toStdString()))
strOverriddenByCommandLine += "-socks ";
// Display
if (!settings.contains("language"))
settings.setValue("language", "");
if (!SoftSetArg("-lang", settings.value("language").toString().toStdString()))
strOverriddenByCommandLine += "-lang";
language = settings.value("language").toString();
} }
void OptionsModel::Reset() void OptionsModel::Reset()
{ {
QSettings settings; QSettings settings;
// Remove all entries in this QSettings object // Remove all entries from our QSettings object
settings.clear(); settings.clear();
// default setting for OptionsModel::StartAtStartup - disabled // default setting for OptionsModel::StartAtStartup - disabled
if (GUIUtil::GetStartOnSystemStartup()) if (GUIUtil::GetStartOnSystemStartup())
GUIUtil::SetStartOnSystemStartup(false); GUIUtil::SetStartOnSystemStartup(false);
// Re-Init to get default values
Init();
// Ensure Upgrade() is not running again by setting the bImportFinished flag // Ensure Upgrade() is not running again by setting the bImportFinished flag
settings.setValue("bImportFinished", true); settings.setValue("bImportFinished", true);
} }
bool OptionsModel::Upgrade() void OptionsModel::Upgrade()
{ {
QSettings settings; QSettings settings;
// Already upgraded
if (settings.contains("bImportFinished")) if (settings.contains("bImportFinished"))
return false; // Already upgraded return;
settings.setValue("bImportFinished", true); settings.setValue("bImportFinished", true);
@ -145,18 +181,16 @@ bool OptionsModel::Upgrade()
walletdb.EraseSetting("addrProxy"); walletdb.EraseSetting("addrProxy");
} }
} }
ApplyProxySettings();
Init(); Init();
return true;
} }
int OptionsModel::rowCount(const QModelIndex & parent) const int OptionsModel::rowCount(const QModelIndex & parent) const
{ {
return OptionIDRowCount; return OptionIDRowCount;
} }
// read QSettings values and return them
QVariant OptionsModel::data(const QModelIndex & index, int role) const QVariant OptionsModel::data(const QModelIndex & index, int role) const
{ {
if(role == Qt::EditRole) if(role == Qt::EditRole)
@ -165,52 +199,55 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
switch(index.row()) switch(index.row())
{ {
case StartAtStartup: case StartAtStartup:
return QVariant(GUIUtil::GetStartOnSystemStartup()); return GUIUtil::GetStartOnSystemStartup();
case MinimizeToTray: case MinimizeToTray:
return QVariant(fMinimizeToTray); return fMinimizeToTray;
case MapPortUPnP: case MapPortUPnP:
#ifdef USE_UPNP #ifdef USE_UPNP
return settings.value("fUseUPnP", GetBoolArg("-upnp", true)); return settings.value("fUseUPnP");
#else #else
return QVariant(false); return false;
#endif #endif
case MinimizeOnClose: case MinimizeOnClose:
return QVariant(fMinimizeOnClose); return fMinimizeOnClose;
case ProxyUse: {
proxyType proxy; // default proxy
return QVariant(GetProxy(NET_IPV4, proxy)); case ProxyUse:
} return settings.value("fUseProxy", false);
case ProxyIP: { case ProxyIP: {
proxyType proxy; // contains IP at index 0 and port at index 1
if (GetProxy(NET_IPV4, proxy)) QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts);
return QVariant(QString::fromStdString(proxy.first.ToStringIP())); return strlIpPort.at(0);
else
return QVariant(QString::fromStdString("127.0.0.1"));
} }
case ProxyPort: { case ProxyPort: {
proxyType proxy; // contains IP at index 0 and port at index 1
if (GetProxy(NET_IPV4, proxy)) QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts);
return QVariant(proxy.first.GetPort()); return strlIpPort.at(1);
else
return QVariant(9050);
}
case ProxySocksVersion: {
proxyType proxy;
if (GetProxy(NET_IPV4, proxy))
return QVariant(proxy.second);
else
return QVariant(5);
} }
case ProxySocksVersion:
return settings.value("nSocksVersion", 5);
case Fee: case Fee:
return QVariant((qint64) nTransactionFee); // Attention: Init() is called before nTransactionFee is set in AppInit2()!
// To ensure we can change the fee on-the-fly update our QSetting when
// opening OptionsDialog, which queries Fee via the mapper.
if (nTransactionFee != settings.value("nTransactionFee").toLongLong())
settings.setValue("nTransactionFee", (qint64)nTransactionFee);
// Todo: Consider to revert back to use just nTransactionFee here, if we don't want
// -paytxfee to update our QSettings!
return settings.value("nTransactionFee");
case DisplayUnit: case DisplayUnit:
return QVariant(nDisplayUnit); return nDisplayUnit;
case DisplayAddresses: case DisplayAddresses:
return QVariant(bDisplayAddresses); return bDisplayAddresses;
case Language: case Language:
return settings.value("language", ""); return settings.value("language");
case CoinControlFeatures: case CoinControlFeatures:
return QVariant(fCoinControlFeatures); return fCoinControlFeatures;
case DatabaseCache:
return settings.value("nDatabaseCache");
case ThreadsScriptVerif:
return settings.value("nThreadsScriptVerif");
default: default:
return QVariant(); return QVariant();
} }
@ -218,6 +255,7 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
return QVariant(); return QVariant();
} }
// write QSettings values
bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, int role) bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, int role)
{ {
bool successful = true; /* set to false on parse error */ bool successful = true; /* set to false on parse error */
@ -233,7 +271,7 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
fMinimizeToTray = value.toBool(); fMinimizeToTray = value.toBool();
settings.setValue("fMinimizeToTray", fMinimizeToTray); settings.setValue("fMinimizeToTray", fMinimizeToTray);
break; break;
case MapPortUPnP: case MapPortUPnP: // core option - can be changed on-the-fly
settings.setValue("fUseUPnP", value.toBool()); settings.setValue("fUseUPnP", value.toBool());
MapPort(value.toBool()); MapPort(value.toBool());
break; break;
@ -241,44 +279,50 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
fMinimizeOnClose = value.toBool(); fMinimizeOnClose = value.toBool();
settings.setValue("fMinimizeOnClose", fMinimizeOnClose); settings.setValue("fMinimizeOnClose", fMinimizeOnClose);
break; break;
// default proxy
case ProxyUse: case ProxyUse:
settings.setValue("fUseProxy", value.toBool()); if (settings.value("fUseProxy") != value) {
successful = ApplyProxySettings(); settings.setValue("fUseProxy", value.toBool());
setRestartRequired(true);
}
break; break;
case ProxyIP: { case ProxyIP: {
proxyType proxy; // contains current IP at index 0 and current port at index 1
proxy.first = CService("127.0.0.1", 9050); QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts);
GetProxy(NET_IPV4, proxy); // if that key doesn't exist or has a changed IP
if (!settings.contains("addrProxy") || strlIpPort.at(0) != value.toString()) {
CNetAddr addr(value.toString().toStdString()); // construct new value from new IP and current port
proxy.first.SetIP(addr); QString strNewValue = value.toString() + ":" + strlIpPort.at(1);
settings.setValue("addrProxy", proxy.first.ToStringIPPort().c_str()); settings.setValue("addrProxy", strNewValue);
successful = ApplyProxySettings(); setRestartRequired(true);
}
} }
break; break;
case ProxyPort: { case ProxyPort: {
proxyType proxy; // contains current IP at index 0 and current port at index 1
proxy.first = CService("127.0.0.1", 9050); QStringList strlIpPort = settings.value("addrProxy").toString().split(":", QString::SkipEmptyParts);
GetProxy(NET_IPV4, proxy); // if that key doesn't exist or has a changed port
if (!settings.contains("addrProxy") || strlIpPort.at(1) != value.toString()) {
proxy.first.SetPort(value.toInt()); // construct new value from current IP and new port
settings.setValue("addrProxy", proxy.first.ToStringIPPort().c_str()); QString strNewValue = strlIpPort.at(0) + ":" + value.toString();
successful = ApplyProxySettings(); settings.setValue("addrProxy", strNewValue);
setRestartRequired(true);
}
} }
break; break;
case ProxySocksVersion: { case ProxySocksVersion: {
proxyType proxy; if (settings.value("nSocksVersion") != value) {
proxy.second = 5; settings.setValue("nSocksVersion", value.toInt());
GetProxy(NET_IPV4, proxy); setRestartRequired(true);
}
proxy.second = value.toInt();
settings.setValue("nSocksVersion", proxy.second);
successful = ApplyProxySettings();
} }
break; break;
case Fee:
case Fee: // core option - can be changed on-the-fly
// Todo: Add is valid check and warn via message, if not
nTransactionFee = value.toLongLong(); nTransactionFee = value.toLongLong();
settings.setValue("nTransactionFee", (qint64) nTransactionFee); settings.setValue("nTransactionFee", (qint64)nTransactionFee);
emit transactionFeeChanged(nTransactionFee); emit transactionFeeChanged(nTransactionFee);
break; break;
case DisplayUnit: case DisplayUnit:
@ -291,13 +335,28 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
settings.setValue("bDisplayAddresses", bDisplayAddresses); settings.setValue("bDisplayAddresses", bDisplayAddresses);
break; break;
case Language: case Language:
settings.setValue("language", value); if (settings.value("language") != value) {
settings.setValue("language", value);
setRestartRequired(true);
}
break; break;
case CoinControlFeatures: case CoinControlFeatures:
fCoinControlFeatures = value.toBool(); fCoinControlFeatures = value.toBool();
settings.setValue("fCoinControlFeatures", fCoinControlFeatures); settings.setValue("fCoinControlFeatures", fCoinControlFeatures);
emit coinControlFeaturesChanged(fCoinControlFeatures); emit coinControlFeaturesChanged(fCoinControlFeatures);
break; break;
case DatabaseCache:
if (settings.value("nDatabaseCache") != value) {
settings.setValue("nDatabaseCache", value);
setRestartRequired(true);
}
break;
case ThreadsScriptVerif:
if (settings.value("nThreadsScriptVerif") != value) {
settings.setValue("nThreadsScriptVerif", value);
setRestartRequired(true);
}
break;
default: default:
break; break;
} }
@ -317,3 +376,15 @@ bool OptionsModel::getProxySettings(QString& proxyIP, quint16 &proxyPort) const
proxyPort = addrProxy.GetPort(); proxyPort = addrProxy.GetPort();
return true; return true;
} }
void OptionsModel::setRestartRequired(bool fRequired)
{
QSettings settings;
return settings.setValue("fRestartRequired", fRequired);
}
bool OptionsModel::isRestartRequired()
{
QSettings settings;
return settings.value("fRestartRequired", false).toBool();
}

View File

@ -34,6 +34,8 @@ public:
DisplayAddresses, // bool DisplayAddresses, // bool
Language, // QString Language, // QString
CoinControlFeatures, // bool CoinControlFeatures, // bool
ThreadsScriptVerif, // int
DatabaseCache, // int
OptionIDRowCount, OptionIDRowCount,
}; };
@ -41,7 +43,7 @@ public:
void Reset(); void Reset();
/* Migrate settings from wallet.dat after app initialization */ /* Migrate settings from wallet.dat after app initialization */
bool Upgrade(); /* returns true if settings upgraded */ void Upgrade();
int rowCount(const QModelIndex & parent = QModelIndex()) const; int rowCount(const QModelIndex & parent = QModelIndex()) const;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
@ -52,17 +54,24 @@ public:
bool getMinimizeOnClose() { return fMinimizeOnClose; } bool getMinimizeOnClose() { return fMinimizeOnClose; }
int getDisplayUnit() { return nDisplayUnit; } int getDisplayUnit() { return nDisplayUnit; }
bool getDisplayAddresses() { return bDisplayAddresses; } bool getDisplayAddresses() { return bDisplayAddresses; }
QString getLanguage() { return language; }
bool getProxySettings(QString& proxyIP, quint16 &proxyPort) const; bool getProxySettings(QString& proxyIP, quint16 &proxyPort) const;
bool getCoinControlFeatures() { return fCoinControlFeatures; } bool getCoinControlFeatures() { return fCoinControlFeatures; }
const QString& getOverriddenByCommandLine() { return strOverriddenByCommandLine; }
/* Restart flag helper */
void setRestartRequired(bool fRequired);
bool isRestartRequired();
private: private:
int nDisplayUnit; /* Qt-only settings */
bool bDisplayAddresses;
bool fMinimizeToTray; bool fMinimizeToTray;
bool fMinimizeOnClose; bool fMinimizeOnClose;
QString language; QString language;
int nDisplayUnit;
bool bDisplayAddresses;
bool fCoinControlFeatures; bool fCoinControlFeatures;
/* settings that were overriden by command-line */
QString strOverriddenByCommandLine;
signals: signals:
void displayUnitChanged(int unit); void displayUnitChanged(int unit);