6d32891172fe200c21c6056fb200ecfe8abdf9f2
[novacoin.git] / src / qt / sendcoinsdialog.cpp
1 #include "sendcoinsdialog.h"
2 #include "ui_sendcoinsdialog.h"
3 #include "walletmodel.h"
4 #include "bitcoinunits.h"
5 #include "addressbookpage.h"
6 #include "optionsmodel.h"
7 #include "sendcoinsentry.h"
8 #include "guiutil.h"
9 #include "askpassphrasedialog.h"
10
11 #include <QMessageBox>
12 #include <QLocale>
13 #include <QTextDocument>
14 #include <QScrollBar>
15
16 SendCoinsDialog::SendCoinsDialog(QWidget *parent) :
17     QDialog(parent),
18     ui(new Ui::SendCoinsDialog),
19     model(0)
20 {
21     ui->setupUi(this);
22
23 #ifdef Q_WS_MAC // Icons on push buttons are very uncommon on Mac
24     ui->addButton->setIcon(QIcon());
25     ui->clearButton->setIcon(QIcon());
26     ui->sendButton->setIcon(QIcon());
27 #endif
28
29     addEntry();
30
31     connect(ui->addButton, SIGNAL(clicked()), this, SLOT(addEntry()));
32     connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
33 }
34
35 void SendCoinsDialog::setModel(WalletModel *model)
36 {
37     this->model = model;
38
39     for(int i = 0; i < ui->entries->count(); ++i)
40     {
41         SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
42         if(entry)
43         {
44             entry->setModel(model);
45         }
46     }
47     if(model)
48     {
49         setBalance(model->getBalance(), model->getUnconfirmedBalance());
50         connect(model, SIGNAL(balanceChanged(qint64, qint64)), this, SLOT(setBalance(qint64, qint64)));
51     }
52 }
53
54 SendCoinsDialog::~SendCoinsDialog()
55 {
56     delete ui;
57 }
58
59 void SendCoinsDialog::on_sendButton_clicked()
60 {
61     QList<SendCoinsRecipient> recipients;
62     bool valid = true;
63
64     if(!model)
65         return;
66
67     for(int i = 0; i < ui->entries->count(); ++i)
68     {
69         SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
70         if(entry)
71         {
72             if(entry->validate())
73             {
74                 recipients.append(entry->getValue());
75             }
76             else
77             {
78                 valid = false;
79             }
80         }
81     }
82
83     if(!valid || recipients.isEmpty())
84     {
85         return;
86     }
87
88     // Format confirmation message
89     QStringList formatted;
90     foreach(const SendCoinsRecipient &rcp, recipients)
91     {
92         formatted.append(tr("<b>%1</b> to %2 (%3)").arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, rcp.amount), Qt::escape(rcp.label), rcp.address));
93     }
94
95     QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm send coins"),
96                           tr("Are you sure you want to send %1?").arg(formatted.join(tr(" and "))),
97           QMessageBox::Yes|QMessageBox::Cancel,
98           QMessageBox::Cancel);
99
100     if(retval != QMessageBox::Yes)
101     {
102         return;
103     }
104
105     WalletModel::UnlockContext ctx(model->requestUnlock());
106     if(!ctx.isValid())
107     {
108         // Unlock wallet was cancelled
109         return;
110     }
111
112     WalletModel::SendCoinsReturn sendstatus = model->sendCoins(recipients);
113     switch(sendstatus.status)
114     {
115     case WalletModel::InvalidAddress:
116         QMessageBox::warning(this, tr("Send Coins"),
117             tr("The recepient address is not valid, please recheck."),
118             QMessageBox::Ok, QMessageBox::Ok);
119         break;
120     case WalletModel::InvalidAmount:
121         QMessageBox::warning(this, tr("Send Coins"),
122             tr("The amount to pay must be larger than 0."),
123             QMessageBox::Ok, QMessageBox::Ok);
124         break;
125     case WalletModel::AmountExceedsBalance:
126         QMessageBox::warning(this, tr("Send Coins"),
127             tr("Amount exceeds your balance"),
128             QMessageBox::Ok, QMessageBox::Ok);
129         break;
130     case WalletModel::AmountWithFeeExceedsBalance:
131         QMessageBox::warning(this, tr("Send Coins"),
132             tr("Total exceeds your balance when the %1 transaction fee is included").
133             arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, sendstatus.fee)),
134             QMessageBox::Ok, QMessageBox::Ok);
135         break;
136     case WalletModel::DuplicateAddress:
137         QMessageBox::warning(this, tr("Send Coins"),
138             tr("Duplicate address found, can only send to each address once in one send operation"),
139             QMessageBox::Ok, QMessageBox::Ok);
140         break;
141     case WalletModel::TransactionCreationFailed:
142         QMessageBox::warning(this, tr("Send Coins"),
143             tr("Error: Transaction creation failed  "),
144             QMessageBox::Ok, QMessageBox::Ok);
145         break;
146     case WalletModel::TransactionCommitFailed:
147         QMessageBox::warning(this, tr("Send Coins"),
148             tr("Error: The transaction was rejected.  This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."),
149             QMessageBox::Ok, QMessageBox::Ok);
150         break;
151     case WalletModel::OK:
152         accept();
153         break;
154     }
155 }
156
157 void SendCoinsDialog::clear()
158 {
159     // Remove entries until only one left
160     while(ui->entries->count())
161     {
162         delete ui->entries->takeAt(0)->widget();
163     }
164     addEntry();
165
166     updateRemoveEnabled();
167
168     ui->sendButton->setDefault(true);
169 }
170
171 void SendCoinsDialog::reject()
172 {
173     clear();
174 }
175
176 void SendCoinsDialog::accept()
177 {
178     clear();
179 }
180
181 SendCoinsEntry *SendCoinsDialog::addEntry()
182 {
183     SendCoinsEntry *entry = new SendCoinsEntry(this);
184     entry->setModel(model);
185     ui->entries->addWidget(entry);
186     connect(entry, SIGNAL(removeEntry(SendCoinsEntry*)), this, SLOT(removeEntry(SendCoinsEntry*)));
187
188     updateRemoveEnabled();
189
190     // Focus the field, so that entry can start immediately
191     entry->clear();
192     entry->setFocus();
193     ui->scrollAreaWidgetContents->resize(ui->scrollAreaWidgetContents->sizeHint());
194     QCoreApplication::instance()->processEvents();
195     QScrollBar* bar = ui->scrollArea->verticalScrollBar();
196     if (bar)
197         bar->setSliderPosition(bar->maximum());
198     return entry;
199 }
200
201 void SendCoinsDialog::updateRemoveEnabled()
202 {
203     // Remove buttons are enabled as soon as there is more than one send-entry
204     bool enabled = (ui->entries->count() > 1);
205     for(int i = 0; i < ui->entries->count(); ++i)
206     {
207         SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
208         if(entry)
209         {
210             entry->setRemoveEnabled(enabled);
211         }
212     }
213     setupTabChain(0);
214 }
215
216 void SendCoinsDialog::removeEntry(SendCoinsEntry* entry)
217 {
218     delete entry;
219     updateRemoveEnabled();
220 }
221
222 QWidget *SendCoinsDialog::setupTabChain(QWidget *prev)
223 {
224     for(int i = 0; i < ui->entries->count(); ++i)
225     {
226         SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
227         if(entry)
228         {
229             prev = entry->setupTabChain(prev);
230         }
231     }
232     QWidget::setTabOrder(prev, ui->addButton);
233     QWidget::setTabOrder(ui->addButton, ui->sendButton);
234     return ui->sendButton;
235 }
236
237 void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv)
238 {
239     SendCoinsEntry *entry = 0;
240     // Replace the first entry if it is still unused
241     if(ui->entries->count() == 1)
242     {
243         SendCoinsEntry *first = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(0)->widget());
244         if(first->isClear())
245         {
246             entry = first;
247         }
248     }
249     if(!entry)
250     {
251         entry = addEntry();
252     }
253
254     entry->setValue(rv);
255 }
256
257
258 void SendCoinsDialog::handleURL(const QUrl *url)
259 {
260     SendCoinsRecipient rv;
261     if(!GUIUtil::parseBitcoinURL(url, &rv))
262     {
263         return;
264     }
265     pasteEntry(rv);
266 }
267
268 void SendCoinsDialog::setBalance(qint64 balance, qint64 unconfirmedBalance)
269 {
270     Q_UNUSED(unconfirmedBalance);
271     if(!model || !model->getOptionsModel())
272         return;
273
274     int unit = model->getOptionsModel()->getDisplayUnit();
275     ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance));
276 }