Raven Core  3.0.0
P2P Digital Currency
sendassetsentry.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2016 The Bitcoin Core developers
2 // Copyright (c) 2017-2019 The Raven Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 #include "sendassetsentry.h"
6 #include "ui_sendassetsentry.h"
7 //#include "sendcoinsentry.h"
8 //#include "ui_sendcoinsentry.h"
9 
10 #include "addressbookpage.h"
11 #include "addresstablemodel.h"
12 #include "guiutil.h"
13 #include "optionsmodel.h"
14 #include "platformstyle.h"
15 #include "walletmodel.h"
16 #include "assetcontroldialog.h"
17 #include "guiconstants.h"
18 
19 #include "wallet/coincontrol.h"
20 #include "assets/assets.h"
21 
22 #include <QGraphicsDropShadowEffect>
23 #include <QApplication>
24 #include <QClipboard>
25 #include <validation.h>
26 #include <core_io.h>
27 #include <QStringListModel>
28 #include <QSortFilterProxyModel>
29 #include <QCompleter>
30 
31 SendAssetsEntry::SendAssetsEntry(const PlatformStyle *_platformStyle, const QStringList myAssetsNames, QWidget *parent) :
32  QStackedWidget(parent),
33  ui(new Ui::SendAssetsEntry),
34  model(0),
35  platformStyle(_platformStyle)
36 {
37  ui->setupUi(this);
38 
39  ui->addressBookButton->setIcon(platformStyle->SingleColorIcon(":/icons/address-book"));
40  ui->pasteButton->setIcon(platformStyle->SingleColorIcon(":/icons/editpaste"));
41  ui->deleteButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
42  ui->deleteButton_is->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
43  ui->deleteButton_s->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
44 
45  setCurrentWidget(ui->SendCoins);
46 
48  ui->payToLayout->setSpacing(4);
49 #if QT_VERSION >= 0x040700
50  ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book"));
51 #endif
52 
53  // normal raven address field
54  GUIUtil::setupAddressWidget(ui->payTo, this);
55  // just a label for displaying raven address(es)
56  ui->payTo_is->setFont(GUIUtil::fixedPitchFont());
57 
58  // Connect signals
59  connect(ui->payAssetAmount, SIGNAL(valueChanged()), this, SIGNAL(payAmountChanged()));
60  connect(ui->deleteButton, SIGNAL(clicked()), this, SLOT(deleteClicked()));
61  connect(ui->deleteButton_is, SIGNAL(clicked()), this, SLOT(deleteClicked()));
62  connect(ui->deleteButton_s, SIGNAL(clicked()), this, SLOT(deleteClicked()));
63  connect(ui->assetSelectionBox, SIGNAL(activated(int)), this, SLOT(onAssetSelected(int)));
64  connect(ui->administratorCheckbox, SIGNAL(clicked()), this, SLOT(onSendOwnershipChanged()));
65 
66  ui->administratorCheckbox->setToolTip(tr("Select to view administrator assets to transfer"));
67 
69  stringModel = new QStringListModel;
70  stringModel->insertRow(stringModel->rowCount());
71  stringModel->setData(stringModel->index(stringModel->rowCount() - 1, 0), "", Qt::DisplayRole);
72 
73  for (auto name : myAssetsNames)
74  {
75  stringModel->insertRow(stringModel->rowCount());
76  stringModel->setData(stringModel->index(stringModel->rowCount() - 1, 0), name, Qt::DisplayRole);
77  }
78 
79  proxy = new QSortFilterProxyModel;
80  proxy->setSourceModel(stringModel);
81  proxy->setFilterCaseSensitivity(Qt::CaseInsensitive);
82 
83  ui->assetSelectionBox->setModel(proxy);
84  ui->assetSelectionBox->setEditable(true);
85 
86  completer = new QCompleter(proxy,this);
87  completer->setCompletionMode(QCompleter::PopupCompletion);
88  completer->setCaseSensitivity(Qt::CaseInsensitive);
89  ui->assetSelectionBox->setCompleter(completer);
90 
91  ui->assetSelectionBox->lineEdit()->setPlaceholderText(tr("Select an asset to transfer"));
92  ui->assetSelectionBox->setMinimumWidth(32);
93 
95  ui->ownershipWarningMessage->hide();
96 
97  fShowAdministratorList = false;
98 
99  this->setStyleSheet(QString(".SendAssetsEntry {background-color: %1; padding-top: 10px; padding-right: 30px; border: none;}").arg(platformStyle->SendEntriesBackGroundColor().name()));
100 
101  this->setGraphicsEffect(GUIUtil::getShadowEffect());
102 
103  ui->assetBoxLabel->setStyleSheet(STRING_LABEL_COLOR);
104  ui->assetBoxLabel->setFont(GUIUtil::getSubLabelFont());
105 
106  ui->payToLabel->setStyleSheet(STRING_LABEL_COLOR);
107  ui->payToLabel->setFont(GUIUtil::getSubLabelFont());
108 
109  ui->labellLabel->setStyleSheet(STRING_LABEL_COLOR);
110  ui->labellLabel->setFont(GUIUtil::getSubLabelFont());
111 
112  ui->amountLabel->setStyleSheet(STRING_LABEL_COLOR);
113  ui->amountLabel->setFont(GUIUtil::getSubLabelFont());
114 
115  ui->messageLabel->setStyleSheet(STRING_LABEL_COLOR);
116  ui->messageLabel->setFont(GUIUtil::getSubLabelFont());
117 
118  ui->payAssetAmount->setUnit(MAX_UNIT);
119  ui->payAssetAmount->setDisabled(false);
120 
121  ui->administratorCheckbox->setStyleSheet(QString(".QCheckBox{ %1; }").arg(STRING_LABEL_COLOR));
122 
123  ui->assetSelectionBox->setFont(GUIUtil::getSubLabelFont());
124  ui->administratorCheckbox->setFont(GUIUtil::getSubLabelFont());
125  ui->payTo->setFont(GUIUtil::getSubLabelFont());
126  ui->addAsLabel->setFont(GUIUtil::getSubLabelFont());
127  ui->payAssetAmount->setFont(GUIUtil::getSubLabelFont());
128  ui->messageTextLabel->setFont(GUIUtil::getSubLabelFont());
129  ui->assetAmountLabel->setFont(GUIUtil::getSubLabelFont());
130  ui->ownershipWarningMessage->setFont(GUIUtil::getSubLabelFont());
131 
132  ui->memoBox->installEventFilter(this);
133  ui->memoLabel->setFont(GUIUtil::getSubLabelFont());
134  ui->memoLabel->setStyleSheet(STRING_LABEL_COLOR);
135  ui->memoBox->setFont(GUIUtil::getSubLabelFont());
136 }
137 
139 {
140  delete ui;
141 }
142 
144 {
145  // Paste text from clipboard into recipient field
146  ui->payTo->setText(QApplication::clipboard()->text());
147 }
148 
150 {
151  if(!model)
152  return;
155  if(dlg.exec())
156  {
157  ui->payTo->setText(dlg.getReturnValue());
158  ui->payAssetAmount->setFocus();
159  }
160 }
161 
162 void SendAssetsEntry::on_payTo_textChanged(const QString &address)
163 {
164  updateLabel(address);
165 }
166 
168 {
169  this->model = _model;
170 
171 // if (_model && _model->getOptionsModel())
172 // connect(_model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
173 
174  clear();
175 }
176 
178 {
179  // clear UI elements for normal payment
180  ui->payTo->clear();
181  ui->addAsLabel->clear();
182  ui->messageTextLabel->clear();
183  ui->messageTextLabel->hide();
184  ui->messageLabel->hide();
185  // clear UI elements for unauthenticated payment request
186  ui->memoTextLabel_is->clear();
187  // clear UI elements for authenticated payment request
188  ui->payTo_s->clear();
189  ui->memoTextLabel_s->clear();
190 
191  ui->payAssetAmount->clear();
192 
193  // Reset the selected asset
194  ui->assetSelectionBox->setCurrentIndex(0);
195 }
196 
198 {
199  Q_EMIT removeEntry(this);
200 }
201 
203 {
204  if (!model)
205  return false;
206 
207  // Check input validity
208  bool retval = true;
209 
210  // Skip checks for payment request
212  return retval;
213 
214  if (!model->validateAddress(ui->payTo->text()))
215  {
216  ui->payTo->setValid(false);
217  retval = false;
218  }
219 
220  if (ui->assetSelectionBox->currentIndex() == 0) {
221  ui->assetSelectionBox->lineEdit()->setStyleSheet(STYLE_INVALID);
222  retval = false;
223  }
224 
225  if (!ui->payAssetAmount->validate())
226  {
227  retval = false;
228  }
229 
230  if (ui->payAssetAmount->value(0) <= 0)
231  {
232  ui->payAssetAmount->setValid(false);
233  retval = false;
234  }
235 
236  if (!ui->memoBox->text().isEmpty()) {
237  if (!AreMessagingDeployed()) {
238  ui->messageTextLabel->show();
239  ui->messageTextLabel->setText(tr("Memos can only be added once RIP5 is voted in"));
240  ui->memoBox->setStyleSheet(STYLE_INVALID);
241  retval = false;
242  }
243 
244  size_t size = ui->memoBox->text().size();
245 
246  if (size != 46) {
247  if (!AreMessagingDeployed()) {
248 
249  ui->memoBox->setStyleSheet(STYLE_INVALID);
250  retval = false;
251  } else {
252  if (size != 64) {
253  ui->memoBox->setStyleSheet(STYLE_INVALID);
254  retval = false;
255  }
256  }
257  }
258 
259  std::string error = "";
260  if(!CheckEncoded(DecodeAssetData(ui->memoBox->text().toStdString()), error)) {
261  ui->memoBox->setStyleSheet(STYLE_INVALID);
262  retval = false;
263  }
264 
265  }
266 
267  // TODO check to make sure the payAmount value is within the constraints of how much you own
268 
269  return retval;
270 }
271 
273 {
274  // Payment request
276  return recipient;
277 
278  // Normal payment
279  recipient.assetName = ui->assetSelectionBox->currentText();
280  recipient.address = ui->payTo->text();
281  recipient.label = ui->addAsLabel->text();
282  recipient.amount = ui->payAssetAmount->value();
283  recipient.message = ui->messageTextLabel->text();
284 
285  return recipient;
286 }
287 
288 QWidget *SendAssetsEntry::setupTabChain(QWidget *prev)
289 {
290  QWidget::setTabOrder(prev, ui->payTo);
291  QWidget::setTabOrder(ui->payTo, ui->addAsLabel);
292  QWidget::setTabOrder(ui->addressBookButton, ui->pasteButton);
293  QWidget::setTabOrder(ui->pasteButton, ui->deleteButton);
294  QWidget::setTabOrder(ui->deleteButton, ui->payAssetAmount);
295  QWidget::setTabOrder(ui->payAssetAmount, ui->memoBox);
296  return ui->memoBox;
297 }
298 
300 {
301  recipient = value;
302 
303  if (recipient.assetName != "") {
304  int index = ui->assetSelectionBox->findText(recipient.assetName);
305  ui->assetSelectionBox->setCurrentIndex(index);
306  onAssetSelected(index);
307  }
308 }
309 
310 void SendAssetsEntry::setAddress(const QString &address)
311 {
312  ui->payTo->setText(address);
313  ui->payAssetAmount->setFocus();
314 }
315 
317 {
318  return ui->payTo->text().isEmpty() && ui->payTo_is->text().isEmpty() && ui->payTo_s->text().isEmpty();
319 }
320 
322 {
323  ui->payTo->setFocus();
324 }
325 
327 {
328  ui->assetSelectionBox->setFocus();
329 }
330 
331 bool SendAssetsEntry::updateLabel(const QString &address)
332 {
333  if(!model)
334  return false;
335 
336  // Fill in label from address book, if address has an associated label
337  QString associatedLabel = model->getAddressTableModel()->labelForAddress(address);
338  if(!associatedLabel.isEmpty())
339  {
340  ui->addAsLabel->setText(associatedLabel);
341  return true;
342  }
343 
344  return false;
345 }
346 
348 {
349  ui->assetSelectionBox->lineEdit()->setStyleSheet("");
350  QString name = ui->assetSelectionBox->currentText();
351  // If the name
352  if (index == 0) {
353  ui->assetAmountLabel->clear();
354  if(!ui->administratorCheckbox->isChecked())
355  ui->payAssetAmount->setDisabled(false);
356  ui->payAssetAmount->clear();
357  return;
358  }
359 
360  // Check to see if the asset selected is an ownership asset
361  bool fIsOwnerAsset = false;
362  if (IsAssetNameAnOwner(name.toStdString())) {
363  fIsOwnerAsset = true;
364  name = name.split("!").first();
365  }
366 
367  LOCK(cs_main);
368  auto currentActiveAssetCache = GetCurrentAssetCache();
369  CNewAsset asset;
370 
371  // Get the asset metadata if it exists. This isn't called on the administrator token because that doesn't have metadata
372  if (!currentActiveAssetCache->GetAssetMetaDataIfExists(name.toStdString(), asset)) {
373  // This should only happen if the user, selected an asset that was issued from assetcontrol and tries to transfer it before it is mined.
374  clear();
375  ui->messageLabel->show();
376  ui->messageTextLabel->show();
377  ui->messageTextLabel->setText(tr("Failed to get asset metadata for: ") + name + "." + tr(" The transaction in which the asset was issued must be mined into a block before you can transfer it"));
378  ui->assetAmountLabel->clear();
379  return;
380  }
381 
382  CAmount amount = 0;
383 
384  if(!model || !model->getWallet())
385  return;
386 
387  std::map<std::string, std::vector<COutput> > mapAssets;
389 
390  // Add back the OWNER_TAG (!) that was removed above
391  if (fIsOwnerAsset)
392  name = name + OWNER_TAG;
393 
394 
395  if (!mapAssets.count(name.toStdString())) {
396  clear();
397  ui->messageLabel->show();
398  ui->messageTextLabel->show();
399  ui->messageTextLabel->setText(tr("Failed to get asset outpoints from database"));
400  return;
401  }
402 
403  auto vec = mapAssets.at(name.toStdString());
404 
405  // Go through all of the mapAssets to get the total count of assets
406  for (auto txout : vec) {
407  CAssetOutputEntry data;
408  if (GetAssetData(txout.tx->tx->vout[txout.i].scriptPubKey, data))
409  amount += data.nAmount;
410  }
411 
412  int units = fIsOwnerAsset ? OWNER_UNITS : asset.units;
413 
414  QString displayBalance = AssetControlDialog::assetControl->HasAssetSelected() ? tr("Selected Balance") : tr("Wallet Balance");
415 
416  ui->assetAmountLabel->setText(
417  displayBalance + ": <b>" + QString::fromStdString(ValueFromAmountString(amount, units)) + "</b> " + name);
418 
419  ui->messageLabel->hide();
420  ui->messageTextLabel->hide();
421 
422  // If it is an ownership asset lock the amount
423  if (!fIsOwnerAsset) {
424  ui->payAssetAmount->setUnit(asset.units);
425  ui->payAssetAmount->setDisabled(false);
426  }
427 }
428 
430 {
432 }
433 
435  fUsingAssetControl = true;
437 }
438 
439 void SendAssetsEntry::IsAssetControl(bool fIsAssetControl, bool fIsOwner)
440 {
441  if (fIsOwner) {
442  CheckOwnerBox();
443  }
444  if (fIsAssetControl) {
445  ui->administratorCheckbox->setDisabled(true);
446  fUsingAssetControl = true;
447  }
448 }
449 
451 {
452  if (index < ui->assetSelectionBox->count()) {
453  ui->assetSelectionBox->setCurrentIndex(index);
454  ui->assetSelectionBox->activated(index);
455  }
456 }
457 
459 {
461 }
462 
464 {
465  if(!model)
466  return;
467 
468  if (fSwitchStatus)
470 
472  ui->administratorCheckbox->setChecked(true);
473  if (!AssetControlDialog::assetControl->HasAssetSelected()) {
474  std::vector<std::string> names;
476 
477  QStringList list;
478  list << "";
479  for (auto name: names)
480  list << QString::fromStdString(name);
481 
482  stringModel->setStringList(list);
483 
484  ui->assetSelectionBox->lineEdit()->setPlaceholderText(tr("Select an administrator asset to transfer"));
485  ui->assetSelectionBox->setFocus();
486  } else {
487  ui->payTo->setFocus();
488  }
489 
490  ui->payAssetAmount->setUnit(MIN_UNIT); // Min unit because this is an administrator asset
491  ui->payAssetAmount->setValue(1); // When using AssetAmountField, you must use 1 instead of 1 * COIN, because of the way that AssetAmountField uses the unit and value to display the amount
492  ui->payAssetAmount->setDisabled(true);
493 
494 
495  ui->assetAmountLabel->clear();
496 
497  ui->ownershipWarningMessage->setText(tr("Warning: Transferring administrator asset"));
498  ui->ownershipWarningMessage->setStyleSheet("color: red");
499  ui->ownershipWarningMessage->show();
500  } else {
501  ui->administratorCheckbox->setChecked(false);
502  if (!AssetControlDialog::assetControl->HasAssetSelected()) {
503  std::vector<std::string> names;
504  GetAllMyAssets(model->getWallet(), names, 0);
505  QStringList list;
506  list << "";
507  for (auto name : names) {
508  if (!IsAssetNameAnOwner(name))
509  list << QString::fromStdString(name);
510  }
511 
512  stringModel->setStringList(list);
513  ui->assetSelectionBox->lineEdit()->setPlaceholderText(tr("Select an asset to transfer"));
514  ui->payAssetAmount->clear();
515  ui->payAssetAmount->setUnit(MAX_UNIT);
516  ui->assetAmountLabel->clear();
517  ui->assetSelectionBox->setFocus();
518  } else {
519  ui->payTo->setFocus();
520  }
521  ui->ownershipWarningMessage->hide();
522  }
523 }
524 
525 bool SendAssetsEntry::eventFilter(QObject *object, QEvent *event)
526 {
527  if (object == ui->memoBox && event->type() == QEvent::FocusIn)
528  {
529  // Clear invalid flag on focus
530  ui->memoBox->setStyleSheet("");
531  }
532  return QWidget::eventFilter(object, event);
533 }
void on_pasteButton_clicked()
QFont fixedPitchFont()
Definition: guiutil.cpp:168
int8_t units
Definition: assettypes.h:102
QGraphicsDropShadowEffect * getShadowEffect()
Definition: guiutil.cpp:146
void deleteClicked()
SendAssetsEntry(const PlatformStyle *platformStyle, const QStringList myAssetsNames, QWidget *parent=0)
void setModel(AddressTableModel *model)
void onSendOwnershipChanged()
bool getUseExtraSpacing() const
Definition: platformstyle.h:25
void onAssetSelected(int index)
void setValue(const SendAssetsRecipient &value)
CCriticalSection cs_main
Global state.
Definition: validation.cpp:72
QIcon SingleColorIcon(const QString &filename) const
Colorize an icon (given filename) with the icon color.
QWidget * setupTabChain(QWidget *prev)
Set up the tab chain manually, as Qt messes up the tab chain by default in some cases (issue https://...
WalletModel * model
Open address book to pick address.
bool eventFilter(QObject *object, QEvent *event)
QCompleter * completer
AddressTableModel * getAddressTableModel()
PaymentRequestPlus paymentRequest
Definition: walletmodel.h:122
void on_addressBookButton_clicked()
#define OWNER_UNITS
Definition: assets.h:34
A single entry in the dialog for sending ravens.
RVN START.
Definition: wallet.h:191
bool GetAssetData(const CScript &script, CAssetOutputEntry &data)
Definition: assets.cpp:3440
int64_t CAmount
Amount in corbies (Can be negative)
Definition: amount.h:13
void setFocusAssetListBox()
bool fShowAdministratorList
void GetAllMyAssets(CWallet *pwallet, std::vector< std::string > &names, int nMinConf, bool fIncludeAdministrator, bool fOnlyAdministrator)
Definition: assets.cpp:3507
QFont getSubLabelFont()
Definition: guiutil.cpp:86
void setAddress(const QString &address)
bool AreMessagingDeployed()
#define MAX_UNIT
Definition: assettypes.h:16
Ui::SendAssetsEntry * ui
void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent)
Definition: guiutil.cpp:201
std::string DecodeAssetData(std::string encoded)
Decode and Encode IPFS hashes, or OIP hashes.
Definition: assets.cpp:3699
static CCoinControl * assetControl
CAssetsCache * GetCurrentAssetCache()
#define STRING_LABEL_COLOR
Definition: guiconstants.h:90
bool fUsingAssetControl
#define LOCK(cs)
Definition: sync.h:176
#define OWNER_TAG
Definition: assets.h:32
void CheckOwnerBox()
QString labelForAddress(const QString &address) const
#define MIN_UNIT
Definition: assettypes.h:17
bool validate()
#define STYLE_INVALID
Definition: guiconstants.h:21
std::string ValueFromAmountString(const CAmount &amount, const int8_t units)
Definition: core_write.cpp:22
const PlatformStyle * platformStyle
Widget that shows a list of sending or receiving addresses.
bool isClear()
Return whether the entry is still empty and unedited.
void removeEntry(SendAssetsEntry *entry)
void GetAllAdministrativeAssets(CWallet *pwallet, std::vector< std::string > &names, int nMinConf)
Definition: assets.cpp:3499
bool validateAddress(const QString &address)
bool HasAssetSelected() const
Definition: coincontrol.h:66
void AvailableAssets(std::map< std::string, std::vector< COutput > > &mapAssetCoins, bool fOnlySafe=true, const CCoinControl *coinControl=nullptr, const CAmount &nMinimumAmount=1, const CAmount &nMaximumAmount=MAX_MONEY, const CAmount &nMinimumSumAmount=MAX_MONEY, const uint64_t &nMaximumCount=0, const int &nMinDepth=0, const int &nMaxDepth=9999999) const
Helper function that calls AvailableCoinsAll, used for transfering assets.
Definition: wallet.cpp:2165
bool updateLabel(const QString &address)
void setModel(WalletModel *model)
void setFocus()
void refreshAssetList()
Interface to Raven wallet from Qt view code.
Definition: walletmodel.h:165
void setCurrentIndex(int index)
void clear()
QSortFilterProxyModel * proxy
void switchAdministratorList(bool fSwitchStatus=true)
void on_payTo_textChanged(const QString &address)
bool CheckEncoded(const std::string &hash, std::string &strError)
Check the Encoded hash and make sure it is either an IPFS hash or a OIP hash.
Definition: assets.cpp:4282
SendAssetsRecipient getValue()
bool error(const char *fmt, const Args &... args)
Definition: util.h:168
QColor SendEntriesBackGroundColor() const
void IsAssetControl(bool fIsAssetControl, bool fIsOwner)
CAmount nAmount
Definition: wallet.h:196
QStringListModel * stringModel
CWallet * getWallet() const
void payAmountChanged()
~SendAssetsEntry()
SendAssetsRecipient recipient
const QString & getReturnValue() const
bool IsAssetNameAnOwner(const std::string &name)
Check if an asset is an owner.
Definition: assets.cpp:296