Improved Mac experience; QDoubleSpinBox for BitcoinAmountField
[novacoin.git] / src / qt / optionsdialog.cpp
1 #include "optionsdialog.h"
2 #include "optionsmodel.h"
3 #include "bitcoinamountfield.h"
4 #include "monitoreddatamapper.h"
5 #include "guiutil.h"
6 #include "bitcoinunits.h"
7 #include "qvaluecombobox.h"
8
9 #include <QHBoxLayout>
10 #include <QVBoxLayout>
11 #include <QPushButton>
12 #include <QListWidget>
13 #include <QStackedWidget>
14
15 #include <QCheckBox>
16 #include <QLabel>
17 #include <QLineEdit>
18 #include <QIntValidator>
19 #include <QDoubleValidator>
20 #include <QRegExpValidator>
21 #include <QDialogButtonBox>
22
23 /* First page of options */
24 class MainOptionsPage : public QWidget
25 {
26     Q_OBJECT
27 public:
28     explicit MainOptionsPage(QWidget *parent=0);
29
30     void setMapper(MonitoredDataMapper *mapper);
31 private:
32     QCheckBox *bitcoin_at_startup;
33 #ifndef Q_WS_MAC
34     QCheckBox *minimize_to_tray;
35 #endif
36     QCheckBox *map_port_upnp;
37 #ifndef Q_WS_MAC
38     QCheckBox *minimize_on_close;
39 #endif
40     QCheckBox *connect_socks4;
41     QLineEdit *proxy_ip;
42     QLineEdit *proxy_port;
43     BitcoinAmountField *fee_edit;
44
45 signals:
46
47 public slots:
48
49 };
50
51 class DisplayOptionsPage : public QWidget
52 {
53     Q_OBJECT
54 public:
55     explicit DisplayOptionsPage(QWidget *parent=0);
56
57     void setMapper(MonitoredDataMapper *mapper);
58 private:
59     QValueComboBox *unit;
60     QCheckBox *display_addresses;
61 signals:
62
63 public slots:
64
65 };
66
67 #include "optionsdialog.moc"
68
69 OptionsDialog::OptionsDialog(QWidget *parent):
70     QDialog(parent), contents_widget(0), pages_widget(0),
71     model(0), main_page(0), display_page(0)
72 {
73     contents_widget = new QListWidget();
74     contents_widget->setMaximumWidth(128);
75
76     pages_widget = new QStackedWidget();
77     pages_widget->setMinimumWidth(300);
78
79     QListWidgetItem *item_main = new QListWidgetItem(tr("Main"));
80     contents_widget->addItem(item_main);
81     main_page = new MainOptionsPage(this);
82     pages_widget->addWidget(main_page);
83
84     QListWidgetItem *item_display = new QListWidgetItem(tr("Display"));
85     contents_widget->addItem(item_display);
86     display_page = new DisplayOptionsPage(this);
87     pages_widget->addWidget(display_page);
88
89     contents_widget->setCurrentRow(0);
90
91     QHBoxLayout *main_layout = new QHBoxLayout();
92     main_layout->addWidget(contents_widget);
93     main_layout->addWidget(pages_widget, 1);
94
95     QVBoxLayout *layout = new QVBoxLayout();
96     layout->addLayout(main_layout);
97
98     QDialogButtonBox *buttonbox = new QDialogButtonBox();
99     buttonbox->setStandardButtons(QDialogButtonBox::Apply|QDialogButtonBox::Ok|QDialogButtonBox::Cancel);
100     apply_button = buttonbox->button(QDialogButtonBox::Apply);
101     layout->addWidget(buttonbox);
102
103     setLayout(layout);
104     setWindowTitle(tr("Options"));
105
106     /* Widget-to-option mapper */
107     mapper = new MonitoredDataMapper(this);
108     mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
109     mapper->setOrientation(Qt::Vertical);
110     /* enable apply button when data modified */
111     connect(mapper, SIGNAL(viewModified()), this, SLOT(enableApply()));
112     /* disable apply button when new data loaded */
113     connect(mapper, SIGNAL(currentIndexChanged(int)), this, SLOT(disableApply()));
114
115     /* Event bindings */
116     connect(contents_widget, SIGNAL(currentRowChanged(int)), this, SLOT(changePage(int)));
117     connect(buttonbox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(okClicked()));
118     connect(buttonbox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(cancelClicked()));
119     connect(buttonbox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(applyClicked()));
120 }
121
122 void OptionsDialog::setModel(OptionsModel *model)
123 {
124     this->model = model;
125
126     mapper->setModel(model);
127     main_page->setMapper(mapper);
128     display_page->setMapper(mapper);
129
130     mapper->toFirst();
131 }
132
133 void OptionsDialog::changePage(int index)
134 {
135     pages_widget->setCurrentIndex(index);
136 }
137
138 void OptionsDialog::okClicked()
139 {
140     mapper->submit();
141     accept();
142 }
143
144 void OptionsDialog::cancelClicked()
145 {
146     reject();
147 }
148
149 void OptionsDialog::applyClicked()
150 {
151     mapper->submit();
152     apply_button->setEnabled(false);
153 }
154
155 void OptionsDialog::enableApply()
156 {
157     apply_button->setEnabled(true);
158 }
159
160 void OptionsDialog::disableApply()
161 {
162     apply_button->setEnabled(false);
163 }
164
165 MainOptionsPage::MainOptionsPage(QWidget *parent):
166         QWidget(parent)
167 {
168     QVBoxLayout *layout = new QVBoxLayout();
169
170     bitcoin_at_startup = new QCheckBox(tr("&Start Bitcoin on window system startup"));
171     bitcoin_at_startup->setToolTip(tr("Automatically start Bitcoin after the computer is turned on"));
172     layout->addWidget(bitcoin_at_startup);
173
174 #ifndef Q_WS_MAC
175     minimize_to_tray = new QCheckBox(tr("&Minimize to the tray instead of the taskbar"));
176     minimize_to_tray->setToolTip(tr("Show only a tray icon after minimizing the window"));
177     layout->addWidget(minimize_to_tray);
178 #endif
179
180     map_port_upnp = new QCheckBox(tr("Map port using &UPnP"));
181     map_port_upnp->setToolTip(tr("Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled."));
182     layout->addWidget(map_port_upnp);
183
184 #ifndef Q_WS_MAC
185     minimize_on_close = new QCheckBox(tr("M&inimize on close"));
186     minimize_on_close->setToolTip(tr("Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu."));
187     layout->addWidget(minimize_on_close);
188 #endif
189
190     connect_socks4 = new QCheckBox(tr("&Connect through SOCKS4 proxy:"));
191     connect_socks4->setToolTip(tr("Connect to the Bitcon network through a SOCKS4 proxy (e.g. when connecting through Tor)"));
192     layout->addWidget(connect_socks4);
193
194     QHBoxLayout *proxy_hbox = new QHBoxLayout();
195     proxy_hbox->addSpacing(18);
196     QLabel *proxy_ip_label = new QLabel(tr("Proxy &IP: "));
197     proxy_hbox->addWidget(proxy_ip_label);
198     proxy_ip = new QLineEdit();
199     proxy_ip->setMaximumWidth(140);
200     proxy_ip->setEnabled(false);
201     proxy_ip->setValidator(new QRegExpValidator(QRegExp("[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}"), this));
202     proxy_ip->setToolTip(tr("IP address of the proxy (e.g. 127.0.0.1)"));
203     proxy_ip_label->setBuddy(proxy_ip);
204     proxy_hbox->addWidget(proxy_ip);
205     QLabel *proxy_port_label = new QLabel(tr("&Port: "));
206     proxy_hbox->addWidget(proxy_port_label);
207     proxy_port = new QLineEdit();
208     proxy_port->setMaximumWidth(55);
209     proxy_port->setValidator(new QIntValidator(0, 65535, this));
210     proxy_port->setEnabled(false);
211     proxy_port->setToolTip(tr("Port of the proxy (e.g. 1234)"));
212     proxy_port_label->setBuddy(proxy_port);
213     proxy_hbox->addWidget(proxy_port);
214     proxy_hbox->addStretch(1);
215
216     layout->addLayout(proxy_hbox);
217     QLabel *fee_help = new QLabel(tr("Optional transaction fee per KB that helps make sure your transactions are processed quickly.  Most transactions are 1KB.  Fee 0.01 recommended."));
218     fee_help->setWordWrap(true);
219     layout->addWidget(fee_help);
220
221     QHBoxLayout *fee_hbox = new QHBoxLayout();
222     fee_hbox->addSpacing(18);
223     QLabel *fee_label = new QLabel(tr("Pay transaction &fee"));
224     fee_hbox->addWidget(fee_label);
225     fee_edit = new BitcoinAmountField();
226     fee_edit->setToolTip(tr("Optional transaction fee per KB that helps make sure your transactions are processed quickly. Most transactions are 1KB. Fee 0.01 recommended."));
227
228     fee_label->setBuddy(fee_edit);
229     fee_hbox->addWidget(fee_edit);
230     fee_hbox->addStretch(1);
231
232     layout->addLayout(fee_hbox);
233
234     layout->addStretch(1); // Extra space at bottom
235
236     setLayout(layout);
237
238     connect(connect_socks4, SIGNAL(toggled(bool)), proxy_ip, SLOT(setEnabled(bool)));
239     connect(connect_socks4, SIGNAL(toggled(bool)), proxy_port, SLOT(setEnabled(bool)));
240
241 #ifndef USE_UPNP
242     map_port_upnp->setDisabled(true);
243 #endif
244 }
245
246 void MainOptionsPage::setMapper(MonitoredDataMapper *mapper)
247 {
248     // Map model to widgets
249     mapper->addMapping(bitcoin_at_startup, OptionsModel::StartAtStartup);
250 #ifndef Q_WS_MAC
251     mapper->addMapping(minimize_to_tray, OptionsModel::MinimizeToTray);
252 #endif
253     mapper->addMapping(map_port_upnp, OptionsModel::MapPortUPnP);
254 #ifndef Q_WS_MAC
255     mapper->addMapping(minimize_on_close, OptionsModel::MinimizeOnClose);
256 #endif
257     mapper->addMapping(connect_socks4, OptionsModel::ConnectSOCKS4);
258     mapper->addMapping(proxy_ip, OptionsModel::ProxyIP);
259     mapper->addMapping(proxy_port, OptionsModel::ProxyPort);
260     mapper->addMapping(fee_edit, OptionsModel::Fee);
261 }
262
263 DisplayOptionsPage::DisplayOptionsPage(QWidget *parent):
264         QWidget(parent)
265 {
266     QVBoxLayout *layout = new QVBoxLayout();
267
268     QHBoxLayout *unit_hbox = new QHBoxLayout();
269     unit_hbox->addSpacing(18);
270     QLabel *unit_label = new QLabel(tr("&Unit to show amounts in: "));
271     unit_hbox->addWidget(unit_label);
272     unit = new QValueComboBox(this);
273     unit->setModel(new BitcoinUnits(this));
274     unit->setToolTip(tr("Choose the default subdivision unit to show in the interface, and when sending coins"));
275
276     unit_label->setBuddy(unit);
277     unit_hbox->addWidget(unit);
278
279     layout->addLayout(unit_hbox);
280
281     display_addresses = new QCheckBox(tr("Display addresses in transaction list"), this);
282     layout->addWidget(display_addresses);
283
284     layout->addStretch();
285
286     setLayout(layout);
287 }
288
289 void DisplayOptionsPage::setMapper(MonitoredDataMapper *mapper)
290 {
291     mapper->addMapping(unit, OptionsModel::DisplayUnit);
292     mapper->addMapping(display_addresses, OptionsModel::DisplayAddresses);
293 }