Wallet encryption part 2: ask passphrase when needed, add menu options
[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
15 SendCoinsDialog::SendCoinsDialog(QWidget *parent) :
16     QDialog(parent),
17     ui(new Ui::SendCoinsDialog),
18     model(0)
19 {
20     ui->setupUi(this);
21
22     addEntry();
23
24     connect(ui->addButton, SIGNAL(clicked()), this, SLOT(addEntry()));
25 }
26
27 void SendCoinsDialog::setModel(WalletModel *model)
28 {
29     this->model = model;
30
31     for(int i = 0; i < ui->entries->count(); ++i)
32     {
33         SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
34         if(entry)
35         {
36             entry->setModel(model);
37         }
38     }
39 }
40
41 SendCoinsDialog::~SendCoinsDialog()
42 {
43     delete ui;
44 }
45
46 void SendCoinsDialog::on_sendButton_clicked()
47 {
48     QList<SendCoinsRecipient> recipients;
49     bool valid = true;
50     for(int i = 0; i < ui->entries->count(); ++i)
51     {
52         SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
53         if(entry)
54         {
55             if(entry->validate())
56             {
57                 recipients.append(entry->getValue());
58             }
59             else
60             {
61                 valid = false;
62             }
63         }
64     }
65
66     if(!valid || recipients.isEmpty())
67     {
68         return;
69     }
70
71     // Format confirmation message
72     QStringList formatted;
73     foreach(const SendCoinsRecipient &rcp, recipients)
74     {
75         formatted.append(tr("<b>%1</b> to %2 (%3)").arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, rcp.amount), Qt::escape(rcp.label), rcp.address));
76     }
77
78     QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm send coins"),
79                           tr("Are you sure you want to send %1?").arg(formatted.join(tr(" and "))),
80           QMessageBox::Yes|QMessageBox::Cancel,
81           QMessageBox::Cancel);
82
83     if(retval != QMessageBox::Yes)
84     {
85         return;
86     }
87
88     WalletModel::UnlockContext ctx(model->requestUnlock());
89     if(!ctx.isValid())
90     {
91         // Unlock wallet was cancelled
92         return;
93     }
94
95     WalletModel::SendCoinsReturn sendstatus = model->sendCoins(recipients);
96     switch(sendstatus.status)
97     {
98     case WalletModel::InvalidAddress:
99         QMessageBox::warning(this, tr("Send Coins"),
100             tr("The recepient address is not valid, please recheck."),
101             QMessageBox::Ok, QMessageBox::Ok);
102         break;
103     case WalletModel::InvalidAmount:
104         QMessageBox::warning(this, tr("Send Coins"),
105             tr("The amount to pay must be larger than 0."),
106             QMessageBox::Ok, QMessageBox::Ok);
107         break;
108     case WalletModel::AmountExceedsBalance:
109         QMessageBox::warning(this, tr("Send Coins"),
110             tr("Amount exceeds your balance"),
111             QMessageBox::Ok, QMessageBox::Ok);
112         break;
113     case WalletModel::AmountWithFeeExceedsBalance:
114         QMessageBox::warning(this, tr("Send Coins"),
115             tr("Total exceeds your balance when the %1 transaction fee is included").
116             arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, sendstatus.fee)),
117             QMessageBox::Ok, QMessageBox::Ok);
118         break;
119     case WalletModel::DuplicateAddress:
120         QMessageBox::warning(this, tr("Send Coins"),
121             tr("Duplicate address found, can only send to each address once in one send operation"),
122             QMessageBox::Ok, QMessageBox::Ok);
123         break;
124     case WalletModel::TransactionCreationFailed:
125         QMessageBox::warning(this, tr("Send Coins"),
126             tr("Error: Transaction creation failed  "),
127             QMessageBox::Ok, QMessageBox::Ok);
128         break;
129     case WalletModel::TransactionCommitFailed:
130         QMessageBox::warning(this, tr("Send Coins"),
131             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."),
132             QMessageBox::Ok, QMessageBox::Ok);
133         break;
134     case WalletModel::OK:
135         accept();
136         break;
137     }
138 }
139
140 void SendCoinsDialog::clear()
141 {
142     // Remove entries until only one left
143     while(ui->entries->count())
144     {
145         delete ui->entries->takeAt(0)->widget();
146     }
147     addEntry();
148
149     updateRemoveEnabled();
150
151     ui->sendButton->setDefault(true);
152 }
153
154 void SendCoinsDialog::reject()
155 {
156     clear();
157 }
158
159 void SendCoinsDialog::accept()
160 {
161     clear();
162 }
163
164 SendCoinsEntry *SendCoinsDialog::addEntry()
165 {
166     SendCoinsEntry *entry = new SendCoinsEntry(this);
167     entry->setModel(model);
168     ui->entries->addWidget(entry);
169     connect(entry, SIGNAL(removeEntry(SendCoinsEntry*)), this, SLOT(removeEntry(SendCoinsEntry*)));
170
171     updateRemoveEnabled();
172
173     // Focus the field, so that entry can start immediately
174     entry->clear();
175     return entry;
176 }
177
178 void SendCoinsDialog::updateRemoveEnabled()
179 {
180     // Remove buttons are enabled as soon as there is more than one send-entry
181     bool enabled = (ui->entries->count() > 1);
182     for(int i = 0; i < ui->entries->count(); ++i)
183     {
184         SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
185         if(entry)
186         {
187             entry->setRemoveEnabled(enabled);
188         }
189     }
190     setupTabChain(0);
191 }
192
193 void SendCoinsDialog::removeEntry(SendCoinsEntry* entry)
194 {
195     delete entry;
196     updateRemoveEnabled();
197 }
198
199 QWidget *SendCoinsDialog::setupTabChain(QWidget *prev)
200 {
201     for(int i = 0; i < ui->entries->count(); ++i)
202     {
203         SendCoinsEntry *entry = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(i)->widget());
204         if(entry)
205         {
206             prev = entry->setupTabChain(prev);
207         }
208     }
209     QWidget::setTabOrder(prev, ui->addButton);
210     QWidget::setTabOrder(ui->addButton, ui->sendButton);
211     return ui->sendButton;
212 }
213
214 void SendCoinsDialog::pasteEntry(const SendCoinsRecipient &rv)
215 {
216     SendCoinsEntry *entry = 0;
217     // Replace the first entry if it is still unused
218     if(ui->entries->count() == 1)
219     {
220         SendCoinsEntry *first = qobject_cast<SendCoinsEntry*>(ui->entries->itemAt(0)->widget());
221         if(first->isClear())
222         {
223             entry = first;
224         }
225     }
226     if(!entry)
227     {
228         entry = addEntry();
229     }
230
231     entry->setValue(rv);
232 }
233
234
235 void SendCoinsDialog::handleURL(const QUrl *url)
236 {
237     SendCoinsRecipient rv;
238     if(!GUIUtil::parseBitcoinURL(url, &rv))
239     {
240         return;
241     }
242     pasteEntry(rv);
243 }