Remove socks4 support
[novacoin.git] / src / qt / optionsdialog.cpp
1 #include "optionsdialog.h"
2 #include "ui_optionsdialog.h"
3
4 #include "bitcoinunits.h"
5 #include "monitoreddatamapper.h"
6 #include "netbase.h"
7 #include "optionsmodel.h"
8 #include "dialogwindowflags.h"
9
10 #include <QDir>
11 #include <QIntValidator>
12 #include <QLocale>
13 #include <QMessageBox>
14 #include <QRegExp>
15 #include <QRegExpValidator>
16 #include <QKeyEvent>
17 #include <QFileDialog>
18
19 #if QT_VERSION < 0x050000
20 #include <QDesktopServices>
21 #else
22 #include <QStandardPaths>
23 #endif
24
25 OptionsDialog::OptionsDialog(QWidget *parent) :
26     QWidget(parent, DIALOGWINDOWHINTS),
27     ui(new Ui::OptionsDialog),
28     model(0),
29     mapper(0),
30     fRestartWarningDisplayed_Proxy(false),
31     fRestartWarningDisplayed_Tor(false),
32     fRestartWarningDisplayed_Lang(false),
33     fRestartWarningDisplayed_URL(false),
34     fProxyIpValid(true),
35     fTorIpValid(true)
36 {
37     ui->setupUi(this);
38
39     /* Network elements init */
40     ui->proxyIp->setEnabled(false);
41     ui->proxyPort->setEnabled(false);
42     ui->proxyPort->setValidator(new QIntValidator(1, 65535, this));
43
44     ui->torIp->setEnabled(false);
45     ui->torPort->setEnabled(false);
46     ui->torPort->setValidator(new QIntValidator(1, 65535, this));
47     ui->TorOnly->setEnabled(false);
48     ui->torName->setEnabled(false);
49
50     connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyIp, SLOT(setEnabled(bool)));
51     connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyPort, SLOT(setEnabled(bool)));
52     connect(ui->connectSocks, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning_Proxy()));
53
54     connect(ui->connectTor, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning_Tor()));
55     connect(ui->connectTor, SIGNAL(toggled(bool)), ui->torIp, SLOT(setEnabled(bool)));
56     connect(ui->connectTor, SIGNAL(toggled(bool)), ui->torPort, SLOT(setEnabled(bool)));
57     connect(ui->connectTor, SIGNAL(toggled(bool)), ui->TorOnly, SLOT(setEnabled(bool)));
58     connect(ui->connectTor, SIGNAL(toggled(bool)), ui->torName, SLOT(setEnabled(bool)));
59     connect(ui->TorOnly, SIGNAL(toggled(bool)), ui->connectSocks, SLOT(setDisabled(bool)));
60
61     ui->proxyIp->installEventFilter(this);
62     ui->torIp->installEventFilter(this);
63
64     /* Window elements init */
65 #ifdef Q_OS_MAC
66     ui->tabWindow->setVisible(false);
67 #endif
68
69     /* Display elements init */
70     QDir translations(":translations");
71     ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant(""));
72     foreach(const QString &langStr, translations.entryList())
73     {
74         QLocale locale(langStr);
75
76         /** check if the locale name consists of 2 parts (language_country) */
77         if(langStr.contains("_"))
78         {
79 #if QT_VERSION >= 0x040800
80             /** display language strings as "native language - native country (locale name)", e.g. "Deutsch - Deutschland (de)" */
81             ui->lang->addItem(locale.nativeLanguageName() + QString(" - ") + locale.nativeCountryName() + QString(" (") + langStr + QString(")"), QVariant(langStr));
82 #else
83             /** display language strings as "language - country (locale name)", e.g. "German - Germany (de)" */
84             ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" - ") + QLocale::countryToString(locale.country()) + QString(" (") + langStr + QString(")"), QVariant(langStr));
85 #endif
86         }
87         else
88         {
89 #if QT_VERSION >= 0x040800
90             /** display language strings as "native language (locale name)", e.g. "Deutsch (de)" */
91             ui->lang->addItem(locale.nativeLanguageName() + QString(" (") + langStr + QString(")"), QVariant(langStr));
92 #else
93             /** display language strings as "language (locale name)", e.g. "German (de)" */
94             ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" (") + langStr + QString(")"), QVariant(langStr));
95 #endif
96         }
97     }
98
99 #if QT_VERSION >= 0x040700
100     ui->thirdPartyTxUrls->setPlaceholderText("https://example.com/tx/%s");
101 #endif
102
103
104     ui->unit->setModel(new BitcoinUnits(this));
105
106     /* Widget-to-option mapper */
107     mapper = new MonitoredDataMapper(this);
108     mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
109     mapper->setOrientation(Qt::Vertical);
110
111     /* enable apply button when data modified */
112     connect(mapper, SIGNAL(viewModified()), this, SLOT(enableApplyButton()));
113     /* disable apply button when new data loaded */
114     connect(mapper, SIGNAL(currentIndexChanged(int)), this, SLOT(disableApplyButton()));
115     /* setup/change UI elements when proxy IP is invalid/valid */
116     connect(this, SIGNAL(proxyIpValid(QValidatedLineEdit *, bool)), this, SLOT(handleProxyIpValid(QValidatedLineEdit *, bool)));
117     /* setup/change UI elements when Tor IP is invalid/valid */
118     connect(this, SIGNAL(torIpValid(QValidatedLineEdit *, bool)), this, SLOT(handleTorIpValid(QValidatedLineEdit *, bool)));
119 }
120
121 OptionsDialog::~OptionsDialog()
122 {
123     delete ui;
124 }
125
126 void OptionsDialog::setModel(OptionsModel *model)
127 {
128     this->model = model;
129
130     if(model)
131     {
132         connect(model, SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
133
134         mapper->setModel(model);
135         setMapper();
136         mapper->toFirst();
137     }
138
139     /* update the display unit, to not use the default ("BTC") */
140     updateDisplayUnit();
141
142     /* warn only when language selection changes by user action (placed here so init via mapper doesn't trigger this) */
143     connect(ui->lang, SIGNAL(valueChanged()), this, SLOT(showRestartWarning_Lang()));
144     connect(ui->thirdPartyTxUrls, SIGNAL(textChanged(const QString &)), this, SLOT(showRestartWarning_URL()));
145
146     /* disable apply button after settings are loaded as there is nothing to save */
147     disableApplyButton();
148 }
149
150 void OptionsDialog::setMapper()
151 {
152     /* Main */
153     mapper->addMapping(ui->transactionFee, OptionsModel::Fee);
154     mapper->addMapping(ui->bitcoinAtStartup, OptionsModel::StartAtStartup);
155     mapper->addMapping(ui->detachDatabases, OptionsModel::DetachDatabases);
156
157     /* Network */
158     mapper->addMapping(ui->connectSocks, OptionsModel::ProxyUse);
159     mapper->addMapping(ui->proxyIp, OptionsModel::ProxyIP);
160     mapper->addMapping(ui->proxyPort, OptionsModel::ProxyPort);
161
162     mapper->addMapping(ui->connectTor, OptionsModel::TorUse);
163     mapper->addMapping(ui->torIp, OptionsModel::TorIP);
164     mapper->addMapping(ui->torPort, OptionsModel::TorPort);
165     mapper->addMapping(ui->TorOnly, OptionsModel::TorOnly);
166     mapper->addMapping(ui->torName, OptionsModel::TorName);
167     mapper->addMapping(ui->externalSeederCommand, OptionsModel::ExternalSeeder);
168
169
170     /* Window */
171 #ifndef Q_OS_MAC
172     mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray);
173     mapper->addMapping(ui->minimizeOnClose, OptionsModel::MinimizeOnClose);
174 #endif
175
176     /* Display */
177     mapper->addMapping(ui->lang, OptionsModel::Language);
178     mapper->addMapping(ui->unit, OptionsModel::DisplayUnit);
179     mapper->addMapping(ui->displayAddresses, OptionsModel::DisplayAddresses);
180     mapper->addMapping(ui->coinControlFeatures, OptionsModel::CoinControlFeatures);
181     mapper->addMapping(ui->thirdPartyTxUrls, OptionsModel::ThirdPartyTxUrls);
182 }
183
184 void OptionsDialog::enableApplyButton()
185 {
186     ui->applyButton->setEnabled(true);
187 }
188
189 void OptionsDialog::disableApplyButton()
190 {
191     ui->applyButton->setEnabled(false);
192 }
193
194 void OptionsDialog::enableSaveButtons()
195 {
196     /* prevent enabling of the save buttons when data modified, if there is an invalid proxy address present */
197     if(fProxyIpValid && fTorIpValid)
198         setSaveButtonState(true);
199 }
200
201 void OptionsDialog::disableSaveButtons()
202 {
203     setSaveButtonState(false);
204 }
205
206 void OptionsDialog::setSaveButtonState(bool fState)
207 {
208     ui->applyButton->setEnabled(fState);
209     ui->okButton->setEnabled(fState);
210 }
211
212 void OptionsDialog::on_okButton_clicked()
213 {
214     mapper->submit();
215 //    accept();
216     close();
217 }
218
219 void OptionsDialog::on_cancelButton_clicked()
220 {
221 //    reject();
222     close();
223 }
224
225 void OptionsDialog::on_applyButton_clicked()
226 {
227     mapper->submit();
228     disableApplyButton();
229 }
230
231 void OptionsDialog::showRestartWarning_Proxy()
232 {
233     if(!fRestartWarningDisplayed_Proxy)
234     {
235         QMessageBox::warning(this, tr("Warning"), tr("This setting will take effect after restarting NovaCoin."), QMessageBox::Ok);
236         fRestartWarningDisplayed_Proxy = true;
237     }
238 }
239
240 void OptionsDialog::showRestartWarning_Tor()
241 {
242     if(!fRestartWarningDisplayed_Proxy)
243     {
244         QMessageBox::warning(this, tr("Warning"), tr("This setting will take effect after restarting NovaCoin."), QMessageBox::Ok);
245         fRestartWarningDisplayed_Tor = true;
246     }
247 }
248
249 void OptionsDialog::showRestartWarning_Lang()
250 {
251     if(!fRestartWarningDisplayed_Lang)
252     {
253         QMessageBox::warning(this, tr("Warning"), tr("This setting will take effect after restarting NovaCoin."), QMessageBox::Ok);
254         fRestartWarningDisplayed_Lang = true;
255     }
256 }
257
258 void OptionsDialog::showRestartWarning_URL()
259 {
260     if(!fRestartWarningDisplayed_URL)
261     {
262         QMessageBox::warning(this, tr("Warning"), tr("This setting will take effect after restarting NovaCoin."), QMessageBox::Ok);
263         fRestartWarningDisplayed_URL = true;
264     }
265 }
266
267
268 void OptionsDialog::updateDisplayUnit()
269 {
270     if(model)
271     {
272         /* Update transactionFee with the current unit */
273         ui->transactionFee->setDisplayUnit(model->getDisplayUnit());
274     }
275 }
276
277 void OptionsDialog::handleProxyIpValid(QValidatedLineEdit *object, bool fState)
278 {
279     // this is used in a check before re-enabling the save buttons
280     fProxyIpValid = fState;
281
282     if(fProxyIpValid)
283     {
284         enableSaveButtons();
285         ui->statusLabel->clear();
286     }
287     else
288     {
289         disableSaveButtons();
290         object->setValid(fProxyIpValid);
291         ui->statusLabel->setStyleSheet("QLabel { color: red; }");
292         ui->statusLabel->setText(tr("The supplied proxy address is invalid."));
293     }
294 }
295
296 void OptionsDialog::handleTorIpValid(QValidatedLineEdit *object, bool fState)
297 {
298     // this is used in a check before re-enabling the save buttons
299     fTorIpValid = fState;
300
301     if(fTorIpValid)
302     {
303         enableSaveButtons();
304         ui->statusLabel->clear();
305     }
306     else
307     {
308         disableSaveButtons();
309         object->setValid(fTorIpValid);
310         ui->statusLabel->setStyleSheet("QLabel { color: red; }");
311         ui->statusLabel->setText(tr("The supplied tor address is invalid."));
312     }
313 }
314
315 bool OptionsDialog::eventFilter(QObject *object, QEvent *event)
316 {
317     if(event->type() == QEvent::FocusOut)
318     {
319         if(object == ui->proxyIp)
320         {
321             CService addr;
322             /* Check proxyIp for a valid IPv4/IPv6 address and emit the proxyIpValid signal */
323             emit proxyIpValid(ui->proxyIp, LookupNumeric(ui->proxyIp->text().toStdString().c_str(), addr));
324         }
325
326         if(object == ui->torIp)
327         {
328             CService addr;
329             /* Check proxyIp for a valid IPv4/IPv6 address and emit the torIpValid signal */
330             emit torIpValid(ui->torIp, LookupNumeric(ui->torIp->text().toStdString().c_str(), addr));
331         }
332     }
333     return QWidget::eventFilter(object, event);
334 }
335
336 void OptionsDialog::keyPressEvent(QKeyEvent *event)
337 {
338 #ifdef ANDROID
339     if(windowType() != Qt::Widget && event->key() == Qt::Key_Back)
340     {
341         close();
342     }
343 #else
344     if(windowType() != Qt::Widget && event->key() == Qt::Key_Escape)
345     {
346         close();
347     }
348 #endif
349 }
350 void OptionsDialog::on_chooseSeeder_clicked()
351 {
352 #if QT_VERSION < 0x050000
353     QString openDir = QDesktopServices::storageLocation(QDesktopServices::ApplicationsLocation);
354 #else
355     QString openDir = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
356 #endif
357
358     QString filename = QFileDialog::getOpenFileName(this, tr("Choose peer collector application"), openDir, tr("Applications (*.*)"));
359     if(!filename.isEmpty()) {
360         ui->externalSeederCommand->setText(filename);
361     }
362 }