1 // Copyright (c) 2011-2015 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include "sendcoinsentry.h"
6 #include "ui_sendcoinsentry.h"
7 
8 #include "addressbookpage.h"
9 #include "addresstablemodel.h"
10 #include "guiutil.h"
11 #include "optionsmodel.h"
12 #include "platformstyle.h"
13 #include "walletmodel.h"
14 
15 #include <QApplication>
16 #include <QClipboard>
17 
SendCoinsEntry(const PlatformStyle * platformStyle,QWidget * parent)18 SendCoinsEntry::SendCoinsEntry(const PlatformStyle *platformStyle, QWidget *parent) :
19     QStackedWidget(parent),
20     ui(new Ui::SendCoinsEntry),
21     model(0),
22     platformStyle(platformStyle)
23 {
24     ui->setupUi(this);
25 
26     ui->addressBookButton->setIcon(platformStyle->SingleColorIcon(":/icons/address-book"));
27     ui->pasteButton->setIcon(platformStyle->SingleColorIcon(":/icons/editpaste"));
28     ui->deleteButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
29     ui->deleteButton_is->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
30     ui->deleteButton_s->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
31 
32     setCurrentWidget(ui->SendCoins);
33 
34     if (platformStyle->getUseExtraSpacing())
35         ui->payToLayout->setSpacing(4);
36 #if QT_VERSION >= 0x040700
37     ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book"));
38 #endif
39 
40     // normal bitcoin address field
41     GUIUtil::setupAddressWidget(ui->payTo, this);
42     // just a label for displaying bitcoin address(es)
43     ui->payTo_is->setFont(GUIUtil::fixedPitchFont());
44 
45     // Connect signals
46     connect(ui->payAmount, SIGNAL(valueChanged()), this, SIGNAL(payAmountChanged()));
47     connect(ui->checkboxSubtractFeeFromAmount, SIGNAL(toggled(bool)), this, SIGNAL(subtractFeeFromAmountChanged()));
48     connect(ui->deleteButton, SIGNAL(clicked()), this, SLOT(deleteClicked()));
49     connect(ui->deleteButton_is, SIGNAL(clicked()), this, SLOT(deleteClicked()));
50     connect(ui->deleteButton_s, SIGNAL(clicked()), this, SLOT(deleteClicked()));
51 }
52 
~SendCoinsEntry()53 SendCoinsEntry::~SendCoinsEntry()
54 {
55     delete ui;
56 }
57 
on_pasteButton_clicked()58 void SendCoinsEntry::on_pasteButton_clicked()
59 {
60     // Paste text from clipboard into recipient field
61     ui->payTo->setText(QApplication::clipboard()->text());
62 }
63 
on_addressBookButton_clicked()64 void SendCoinsEntry::on_addressBookButton_clicked()
65 {
66     if(!model)
67         return;
68     AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::SendingTab, this);
69     dlg.setModel(model->getAddressTableModel());
70     if(dlg.exec())
71     {
72         ui->payTo->setText(dlg.getReturnValue());
73         ui->payAmount->setFocus();
74     }
75 }
76 
on_payTo_textChanged(const QString & address)77 void SendCoinsEntry::on_payTo_textChanged(const QString &address)
78 {
79     updateLabel(address);
80 }
81 
setModel(WalletModel * model)82 void SendCoinsEntry::setModel(WalletModel *model)
83 {
84     this->model = model;
85 
86     if (model && model->getOptionsModel())
87         connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
88 
89     clear();
90 }
91 
clear()92 void SendCoinsEntry::clear()
93 {
94     // clear UI elements for normal payment
95     ui->payTo->clear();
96     ui->addAsLabel->clear();
97     ui->payAmount->clear();
98     ui->checkboxSubtractFeeFromAmount->setCheckState(Qt::Unchecked);
99     ui->messageTextLabel->clear();
100     ui->messageTextLabel->hide();
101     ui->messageLabel->hide();
102     // clear UI elements for unauthenticated payment request
103     ui->payTo_is->clear();
104     ui->memoTextLabel_is->clear();
105     ui->payAmount_is->clear();
106     // clear UI elements for authenticated payment request
107     ui->payTo_s->clear();
108     ui->memoTextLabel_s->clear();
109     ui->payAmount_s->clear();
110 
111     // update the display unit, to not use the default ("BTC")
112     updateDisplayUnit();
113 }
114 
deleteClicked()115 void SendCoinsEntry::deleteClicked()
116 {
117     Q_EMIT removeEntry(this);
118 }
119 
validate()120 bool SendCoinsEntry::validate()
121 {
122     if (!model)
123         return false;
124 
125     // Check input validity
126     bool retval = true;
127 
128     // Skip checks for payment request
129     if (recipient.paymentRequest.IsInitialized())
130         return retval;
131 
132     if (!model->validateAddress(ui->payTo->text()))
133     {
134         ui->payTo->setValid(false);
135         retval = false;
136     }
137 
138     if (!ui->payAmount->validate())
139     {
140         retval = false;
141     }
142 
143     // Sending a zero amount is invalid
144     if (ui->payAmount->value(0) <= 0)
145     {
146         ui->payAmount->setValid(false);
147         retval = false;
148     }
149 
150     // Reject dust outputs:
151     if (retval && GUIUtil::isDust(ui->payTo->text(), ui->payAmount->value())) {
152         ui->payAmount->setValid(false);
153         retval = false;
154     }
155 
156     return retval;
157 }
158 
getValue()159 SendCoinsRecipient SendCoinsEntry::getValue()
160 {
161     // Payment request
162     if (recipient.paymentRequest.IsInitialized())
163         return recipient;
164 
165     // Normal payment
166     recipient.address = ui->payTo->text();
167     recipient.label = ui->addAsLabel->text();
168     recipient.amount = ui->payAmount->value();
169     recipient.message = ui->messageTextLabel->text();
170     recipient.fSubtractFeeFromAmount = (ui->checkboxSubtractFeeFromAmount->checkState() == Qt::Checked);
171 
172     return recipient;
173 }
174 
setupTabChain(QWidget * prev)175 QWidget *SendCoinsEntry::setupTabChain(QWidget *prev)
176 {
177     QWidget::setTabOrder(prev, ui->payTo);
178     QWidget::setTabOrder(ui->payTo, ui->addAsLabel);
179     QWidget *w = ui->payAmount->setupTabChain(ui->addAsLabel);
180     QWidget::setTabOrder(w, ui->checkboxSubtractFeeFromAmount);
181     QWidget::setTabOrder(ui->checkboxSubtractFeeFromAmount, ui->addressBookButton);
182     QWidget::setTabOrder(ui->addressBookButton, ui->pasteButton);
183     QWidget::setTabOrder(ui->pasteButton, ui->deleteButton);
184     return ui->deleteButton;
185 }
186 
setValue(const SendCoinsRecipient & value)187 void SendCoinsEntry::setValue(const SendCoinsRecipient &value)
188 {
189     recipient = value;
190 
191     if (recipient.paymentRequest.IsInitialized()) // payment request
192     {
193         if (recipient.authenticatedMerchant.isEmpty()) // unauthenticated
194         {
195             ui->payTo_is->setText(recipient.address);
196             ui->memoTextLabel_is->setText(recipient.message);
197             ui->payAmount_is->setValue(recipient.amount);
198             ui->payAmount_is->setReadOnly(true);
199             setCurrentWidget(ui->SendCoins_UnauthenticatedPaymentRequest);
200         }
201         else // authenticated
202         {
203             ui->payTo_s->setText(recipient.authenticatedMerchant);
204             ui->memoTextLabel_s->setText(recipient.message);
205             ui->payAmount_s->setValue(recipient.amount);
206             ui->payAmount_s->setReadOnly(true);
207             setCurrentWidget(ui->SendCoins_AuthenticatedPaymentRequest);
208         }
209     }
210     else // normal payment
211     {
212         // message
213         ui->messageTextLabel->setText(recipient.message);
214         ui->messageTextLabel->setVisible(!recipient.message.isEmpty());
215         ui->messageLabel->setVisible(!recipient.message.isEmpty());
216 
217         ui->addAsLabel->clear();
218         ui->payTo->setText(recipient.address); // this may set a label from addressbook
219         if (!recipient.label.isEmpty()) // if a label had been set from the addressbook, don't overwrite with an empty label
220             ui->addAsLabel->setText(recipient.label);
221         ui->payAmount->setValue(recipient.amount);
222     }
223 }
224 
setAddress(const QString & address)225 void SendCoinsEntry::setAddress(const QString &address)
226 {
227     ui->payTo->setText(address);
228     ui->payAmount->setFocus();
229 }
230 
isClear()231 bool SendCoinsEntry::isClear()
232 {
233     return ui->payTo->text().isEmpty() && ui->payTo_is->text().isEmpty() && ui->payTo_s->text().isEmpty();
234 }
235 
setFocus()236 void SendCoinsEntry::setFocus()
237 {
238     ui->payTo->setFocus();
239 }
240 
updateDisplayUnit()241 void SendCoinsEntry::updateDisplayUnit()
242 {
243     if(model && model->getOptionsModel())
244     {
245         // Update payAmount with the current unit
246         ui->payAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
247         ui->payAmount_is->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
248         ui->payAmount_s->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
249     }
250 }
251 
updateLabel(const QString & address)252 bool SendCoinsEntry::updateLabel(const QString &address)
253 {
254     if(!model)
255         return false;
256 
257     // Fill in label from address book, if address has an associated label
258     QString associatedLabel = model->getAddressTableModel()->labelForAddress(address);
259     if(!associatedLabel.isEmpty())
260     {
261         ui->addAsLabel->setText(associatedLabel);
262         return true;
263     }
264 
265     return false;
266 }
267