Bugfix: Replace "URL" with "URI" where we aren't actually working with URLs
[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     fNewRecipientAllowed = true;
35 }
36
37 void SendCoinsDialog::setModel(WalletModel *model)
38 {
39     this->model = model;
40
41     for(int i = 0; i < ui->entries->count(); ++i)
42     {
43         SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
44         if(entry)
45         {
46             entry->setModel(model);
47         }
48     }
49     if(model)
50     {
51         setBalance(model->getBalance(), model->getUnconfirmedBalance());
52         connect(model, SIGNAL(balanceChanged(qint64, qint64)), this, SLOT(setBalance(qint64, qint64)));
53     }
54 }
55
56 SendCoinsDialog::~SendCoinsDialog()
57 {
58     delete ui;
59 }
60
61 void SendCoinsDialog::on_sendButton_clicked()
62 {
63     QList<SendCoinsRecipient> recipients;
64     bool valid = true;
65
66     if(!model)
67         return;
68
69     for(int i = 0; i < ui->entries->count(); ++i)
70     {
71         SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
72         if(entry)
73         {
74             if(entry->validate())
75             {
76                 recipients.append(entry->getValue());
77             }
78             else
79             {
80                 valid = false;
81             }
82         }
83     }
84
85     if(!valid || recipients.isEmpty())
86     {
87         return;
88     }
89
90     // Format confirmation message
91     QStringList formatted;
92     foreach(const SendCoinsRecipient &rcp, recipients)
93     {
94         formatted.append(tr("<b>%1</b> to %2 (%3)").arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, rcp.amount), Qt::escape(rcp.label), rcp.address));
95     }
96
97     fNewRecipientAllowed = false;
98
99     QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm send coins"),
100                           tr("Are you sure you want to send %1?").arg(formatted.join(tr(" and "))),
101           QMessageBox::Yes|QMessageBox::Cancel,
102           QMessageBox::Cancel);
103
104     if(retval != QMessageBox::Yes)
105     {
106         fNewRecipientAllowed = true;
107         return;
108     }
109
110     WalletModel::UnlockContext ctx(model->requestUnlock());
111     if(!ctx.isValid())
112     {
113         // Unlock wallet was cancelled
114         fNewRecipientAllowed = true;
115         return;
116     }
117
118     WalletModel::SendCoinsReturn sendstatus = model->sendCoins(recipients);
119     switch(sendstatus.status)
120     {
121     case WalletModel::InvalidAddress:
122         QMessageBox::warning(this, tr("Send Coins"),
123             tr("The recepient address is not valid, please recheck."),
124             QMessageBox::Ok, QMessageBox::Ok);
125         break;
126     case WalletModel::InvalidAmount:
127         QMessageBox::warning(this, tr("Send Coins"),
128             tr("The amount to pay must be larger than 0."),
129             QMessageBox::Ok, QMessageBox::Ok);
130         break;
131     case WalletModel::AmountExceedsBalance:
132         QMessageBox::warning(this, tr("Send Coins"),
133             tr("Amount exceeds your balance"),
134             QMessageBox::Ok, QMessageBox::Ok);
135         break;
136     case WalletModel::AmountWithFeeExceedsBalance:
137         QMessageBox::warning(this, tr("Send Coins"),
138             tr("Total exceeds your balance when the %1 transaction fee is included").
139             arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, sendstatus.fee)),
140             QMessageBox::Ok, QMessageBox::Ok);
141         break;
142     case WalletModel::DuplicateAddress:
143         QMessageBox::warning(this, tr("Send Coins"),
144             tr("Duplicate address found, can only send to each address once in one send operation"),
145             QMessageBox::Ok, QMessageBox::Ok);
146         break;
147     case WalletModel::TransactionCreationFailed:
148         QMessageBox::warning(this, tr("Send Coins"),
149             tr("Error: Transaction creation failed  "),
150             QMessageBox::Ok, QMessageBox::Ok);
151         break;
152     case WalletModel::TransactionCommitFailed:
153         QMessageBox::warning(this, tr("Send Coins"),
154             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."),
155             QMessageBox::Ok, QMessageBox::Ok);
156         break;
157     case WalletModel::OK:
158         accept();
159         break;
160     }
161     fNewRecipientAllowed = true;
162 }
163
164 void SendCoinsDialog::clear()
165 {
166     // Remove entries until only one left
167     while(ui->entries->count())
168     {
169         delete ui->entries->takeAt(0)->widget();
170     }
171     addEntry();
172
173     updateRemoveEnabled();
174
175     ui->sendButton->setDefault(true);
176 }
177
178 void SendCoinsDialog::reject()
179 {
180     clear();
181 }
182
183 void SendCoinsDialog::accept()
184 {
185     clear();
186 }
187
188 SendCoinsEntry *SendCoinsDialog::addEntry()
189 {
190     SendCoinsEntry *entry = new SendCoinsEntry(this);
191     entry->setModel(model);
192     ui->entries->addWidget(entry);
193     connect(entry, SIGNAL(removeEntry(SendCoinsEntry*)), this, SLOT(removeEntry(SendCoinsEntry*)));
194
195     updateRemoveEnabled();
196
197     // Focus the field, so that entry can start immediately
198     entry->clear();
199     entry->setFocus();
200     ui->scrollAreaWidgetContents->resize(ui->scrollAreaWidgetContents->sizeHint());
201     QCoreApplication::instance()->processEvents();
202     QScrollBar* bar = ui->scrollArea->verticalScrollBar();
203     if (bar)
204         bar->setSliderPosition(bar->maximum());
205     return entry;
206 }
207
208 void SendCoinsDialog::updateRemoveEnabled()
209 {
210     // Remove buttons are enabled as soon as there is more than one send-entry
211     bool enabled = (ui->entries->count() > 1);
212     for(int i = 0; i < ui->entries->count(); ++i)
213     {
214         SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
215         if(entry)
216         {
217             entry->setRemoveEnabled(enabled);
218         }
219     }
220     setupTabChain(0);
221 }
222
223 void SendCoinsDialog::removeEntry(SendCoinsEntry* entry)
224 {
225     delete entry;
226     updateRemoveEnabled();
227 }
228
229 QWidget *SendCoinsDialog::setupTabChain(QWidget *prev)
230 {
231     for(int i = 0; i < ui->entries->count(); ++i)
232     {
233         SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
234         if(entry)
235         {
236             prev = entry->setupTabChain(prev);
237         }
238     }
239     QWidget::setTabOrder(prev, ui->addButton);
240     QWidget::setTabOrder(ui->addButton, ui->sendButton);
241     return ui->sendButton;
242 }
243
244 void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv)
245 {
246     if (!fNewRecipientAllowed)
247         return;
248
249     SendCoinsEntry *entry = 0;
250     // Replace the first entry if it is still unused
251     if(ui->entries->count() == 1)
252     {
253         SendCoinsEntry *first = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(0)->widget());
254         if(first->isClear())
255         {
256             entry = first;
257         }
258     }
259     if(!entry)
260     {
261         entry = addEntry();
262     }
263
264     entry->setValue(rv);
265 }
266
267
268 void SendCoinsDialog::handleURI(const QString &uri)
269 {
270     SendCoinsRecipient rv;
271     if(!GUIUtil::parseBitcoinURI(uri, &rv))
272     {
273         return;
274     }
275     pasteEntry(rv);
276 }
277
278 void SendCoinsDialog::setBalance(qint64 balance, qint64 unconfirmedBalance)
279 {
280     Q_UNUSED(unconfirmedBalance);
281     if(!model || !model->getOptionsModel())
282         return;
283
284     int unit = model->getOptionsModel()->getDisplayUnit();
285     ui->labelBalance->setText(BitcoinUnits::formatWithUnit(unit, balance));
286 }