/ src / qt / sendcoinsentry.cpp
sendcoinsentry.cpp
  1  // Copyright (c) 2011-2022 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 <qt/sendcoinsentry.h>
  6  #include <qt/forms/ui_sendcoinsentry.h>
  7  
  8  #include <qt/addressbookpage.h>
  9  #include <qt/addresstablemodel.h>
 10  #include <qt/guiutil.h>
 11  #include <qt/optionsmodel.h>
 12  #include <qt/platformstyle.h>
 13  #include <qt/walletmodel.h>
 14  
 15  #include <QApplication>
 16  #include <QClipboard>
 17  
 18  SendCoinsEntry::SendCoinsEntry(const PlatformStyle *_platformStyle, QWidget *parent) :
 19      QWidget(parent),
 20      ui(new Ui::SendCoinsEntry),
 21      platformStyle(_platformStyle)
 22  {
 23      ui->setupUi(this);
 24  
 25      ui->addressBookButton->setIcon(platformStyle->SingleColorIcon(":/icons/address-book"));
 26      ui->pasteButton->setIcon(platformStyle->SingleColorIcon(":/icons/editpaste"));
 27      ui->deleteButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
 28  
 29      if (platformStyle->getUseExtraSpacing())
 30          ui->payToLayout->setSpacing(4);
 31  
 32      GUIUtil::setupAddressWidget(ui->payTo, this);
 33  
 34      // Connect signals
 35      connect(ui->payAmount, &BitcoinAmountField::valueChanged, this, &SendCoinsEntry::payAmountChanged);
 36      connect(ui->checkboxSubtractFeeFromAmount, &QCheckBox::toggled, this, &SendCoinsEntry::subtractFeeFromAmountChanged);
 37      connect(ui->deleteButton, &QPushButton::clicked, this, &SendCoinsEntry::deleteClicked);
 38      connect(ui->useAvailableBalanceButton, &QPushButton::clicked, this, &SendCoinsEntry::useAvailableBalanceClicked);
 39  }
 40  
 41  SendCoinsEntry::~SendCoinsEntry()
 42  {
 43      delete ui;
 44  }
 45  
 46  void SendCoinsEntry::on_pasteButton_clicked()
 47  {
 48      // Paste text from clipboard into recipient field
 49      ui->payTo->setText(QApplication::clipboard()->text());
 50  }
 51  
 52  void SendCoinsEntry::on_addressBookButton_clicked()
 53  {
 54      if(!model)
 55          return;
 56      AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::SendingTab, this);
 57      dlg.setModel(model->getAddressTableModel());
 58      if(dlg.exec())
 59      {
 60          ui->payTo->setText(dlg.getReturnValue());
 61          ui->payAmount->setFocus();
 62      }
 63  }
 64  
 65  void SendCoinsEntry::on_payTo_textChanged(const QString &address)
 66  {
 67      updateLabel(address);
 68  }
 69  
 70  void SendCoinsEntry::setModel(WalletModel *_model)
 71  {
 72      this->model = _model;
 73  
 74      if (_model && _model->getOptionsModel())
 75          connect(_model->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &SendCoinsEntry::updateDisplayUnit);
 76  
 77      clear();
 78  }
 79  
 80  void SendCoinsEntry::clear()
 81  {
 82      // clear UI elements for normal payment
 83      ui->payTo->clear();
 84      ui->addAsLabel->clear();
 85      ui->payAmount->clear();
 86      if (model && model->getOptionsModel()) {
 87          ui->checkboxSubtractFeeFromAmount->setChecked(model->getOptionsModel()->getSubFeeFromAmount());
 88      }
 89      ui->messageTextLabel->clear();
 90      ui->messageTextLabel->hide();
 91      ui->messageLabel->hide();
 92  
 93      // update the display unit, to not use the default ("BTC")
 94      updateDisplayUnit();
 95  }
 96  
 97  void SendCoinsEntry::checkSubtractFeeFromAmount()
 98  {
 99      ui->checkboxSubtractFeeFromAmount->setChecked(true);
100  }
101  
102  void SendCoinsEntry::deleteClicked()
103  {
104      Q_EMIT removeEntry(this);
105  }
106  
107  void SendCoinsEntry::useAvailableBalanceClicked()
108  {
109      Q_EMIT useAvailableBalance(this);
110  }
111  
112  bool SendCoinsEntry::validate(interfaces::Node& node)
113  {
114      if (!model)
115          return false;
116  
117      // Check input validity
118      bool retval = true;
119  
120      if (!model->validateAddress(ui->payTo->text()))
121      {
122          ui->payTo->setValid(false);
123          retval = false;
124      }
125  
126      if (!ui->payAmount->validate())
127      {
128          retval = false;
129      }
130  
131      // Sending a zero amount is invalid
132      if (ui->payAmount->value(nullptr) <= 0)
133      {
134          ui->payAmount->setValid(false);
135          retval = false;
136      }
137  
138      // Reject dust outputs:
139      if (retval && GUIUtil::isDust(node, ui->payTo->text(), ui->payAmount->value())) {
140          ui->payAmount->setValid(false);
141          retval = false;
142      }
143  
144      return retval;
145  }
146  
147  SendCoinsRecipient SendCoinsEntry::getValue()
148  {
149      recipient.address = ui->payTo->text();
150      recipient.label = ui->addAsLabel->text();
151      recipient.amount = ui->payAmount->value();
152      recipient.message = ui->messageTextLabel->text();
153      recipient.fSubtractFeeFromAmount = (ui->checkboxSubtractFeeFromAmount->checkState() == Qt::Checked);
154  
155      return recipient;
156  }
157  
158  QWidget *SendCoinsEntry::setupTabChain(QWidget *prev)
159  {
160      QWidget::setTabOrder(prev, ui->payTo);
161      QWidget::setTabOrder(ui->payTo, ui->addAsLabel);
162      QWidget *w = ui->payAmount->setupTabChain(ui->addAsLabel);
163      QWidget::setTabOrder(w, ui->checkboxSubtractFeeFromAmount);
164      QWidget::setTabOrder(ui->checkboxSubtractFeeFromAmount, ui->addressBookButton);
165      QWidget::setTabOrder(ui->addressBookButton, ui->pasteButton);
166      QWidget::setTabOrder(ui->pasteButton, ui->deleteButton);
167      return ui->deleteButton;
168  }
169  
170  void SendCoinsEntry::setValue(const SendCoinsRecipient &value)
171  {
172      recipient = value;
173      {
174          // message
175          ui->messageTextLabel->setText(recipient.message);
176          ui->messageTextLabel->setVisible(!recipient.message.isEmpty());
177          ui->messageLabel->setVisible(!recipient.message.isEmpty());
178  
179          ui->addAsLabel->clear();
180          ui->payTo->setText(recipient.address); // this may set a label from addressbook
181          if (!recipient.label.isEmpty()) // if a label had been set from the addressbook, don't overwrite with an empty label
182              ui->addAsLabel->setText(recipient.label);
183          ui->payAmount->setValue(recipient.amount);
184      }
185  }
186  
187  void SendCoinsEntry::setAddress(const QString &address)
188  {
189      ui->payTo->setText(address);
190      ui->payAmount->setFocus();
191  }
192  
193  void SendCoinsEntry::setAmount(const CAmount &amount)
194  {
195      ui->payAmount->setValue(amount);
196  }
197  
198  bool SendCoinsEntry::isClear()
199  {
200      return ui->payTo->text().isEmpty();
201  }
202  
203  void SendCoinsEntry::setFocus()
204  {
205      ui->payTo->setFocus();
206  }
207  
208  void SendCoinsEntry::updateDisplayUnit()
209  {
210      if (model && model->getOptionsModel()) {
211          ui->payAmount->setDisplayUnit(model->getOptionsModel()->getDisplayUnit());
212      }
213  }
214  
215  void SendCoinsEntry::changeEvent(QEvent* e)
216  {
217      if (e->type() == QEvent::PaletteChange) {
218          ui->addressBookButton->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/address-book")));
219          ui->pasteButton->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/editpaste")));
220          ui->deleteButton->setIcon(platformStyle->SingleColorIcon(QStringLiteral(":/icons/remove")));
221      }
222  
223      QWidget::changeEvent(e);
224  }
225  
226  bool SendCoinsEntry::updateLabel(const QString &address)
227  {
228      if(!model)
229          return false;
230  
231      // Fill in label from address book, if address has an associated label
232      QString associatedLabel = model->getAddressTableModel()->labelForAddress(address);
233      if(!associatedLabel.isEmpty())
234      {
235          ui->addAsLabel->setText(associatedLabel);
236          return true;
237      }
238  
239      return false;
240  }