PIVX Core  5.6.99
P2P Digital Currency
coldstakingwidget.cpp
Go to the documentation of this file.
1 // Copyright (c) 2019-2021 The PIVX 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 "coldstakingwidget.h"
6 #include "ui_coldstakingwidget.h"
7 
8 #include "addnewcontactdialog.h"
9 #include "amount.h"
10 #include "coincontrol.h"
11 #include "coincontroldialog.h"
12 #include "csrow.h"
13 #include "furlistrow.h"
14 #include "guitransactionsutils.h"
15 #include "guiutil.h"
16 #include "optionsmodel.h"
17 #include "qtutils.h"
18 #include "requestdialog.h"
19 #include "sendconfirmdialog.h"
20 #include "tooltipmenu.h"
21 #include "walletmodel.h"
22 
23 #define DECORATION_SIZE 70
24 #define NUM_ITEMS 3
25 #define LOAD_MIN_TIME_INTERVAL 15
26 #define REQUEST_LOAD_TASK 1
27 
28 
29 class CSDelegationHolder : public FurListRow<QWidget*>
30 {
31 public:
33 
34  explicit CSDelegationHolder(bool _isLightTheme) : FurListRow(), isLightTheme(_isLightTheme) {}
35 
36  CSRow* createHolder(int pos) override
37  {
38  if (!cachedRow) cachedRow = new CSRow();
39  return cachedRow;
40  }
41 
42  void init(QWidget* holder,const QModelIndex &index, bool isHovered, bool isSelected) const override
43  {
44  CSRow *row = static_cast<CSRow*>(holder);
45  row->updateState(isLightTheme, isHovered, isSelected);
46 
47  QString address = index.data(Qt::DisplayRole).toString();
48  QString label = index.sibling(index.row(), ColdStakingModel::OWNER_ADDRESS_LABEL).data(Qt::DisplayRole).toString();
49  if (label.isEmpty()) {
50  label = QObject::tr("Address with no label");
51  }
52  bool isWhitelisted = index.sibling(index.row(), ColdStakingModel::IS_WHITELISTED).data(Qt::DisplayRole).toBool();
53  QString amountStr = index.sibling(index.row(), ColdStakingModel::TOTAL_STACKEABLE_AMOUNT_STR).data(Qt::DisplayRole).toString();
54  bool isReceivedDelegation = index.sibling(index.row(), ColdStakingModel::IS_RECEIVED_DELEGATION).data(Qt::DisplayRole).toBool();
55  row->updateView(address, label, isWhitelisted, isReceivedDelegation, amountStr);
56  row->showMenuButton(isReceivedDelegation);
57  }
58 
59  QColor rectColor(bool isHovered, bool isSelected) override
60  {
61  return getRowColor(isLightTheme, isHovered, isSelected);
62  }
63 
65  {
66  if (cachedRow)
67  delete cachedRow;
68  }
69 
71 private:
72  CSRow *cachedRow = nullptr;
73 };
74 
76  PWidget(parent),
77  ui(new Ui::ColdStakingWidget),
78  isLoading(false)
79 {
80  ui->setupUi(this);
81  this->setStyleSheet(parent->styleSheet());
82 
83  /* Containers */
84  setCssProperty(ui->left, "container");
85  ui->left->setContentsMargins(0,20,0,0);
86  setCssProperty(ui->right, "container-right");
87  ui->right->setContentsMargins(0,10,0,20);
88 
89  /* Light Font */
90  QFont fontLight;
91  fontLight.setWeight(QFont::Light);
92 
93  /* Title */
94  setCssTitleScreen(ui->labelTitle);
95  ui->labelTitle->setFont(fontLight);
96 
97  /* Button Group */
98  setCssProperty(ui->pushLeft, "btn-check-left");
99  setCssProperty(ui->pushRight, "btn-check-right");
100 
101  /* Subtitle */
102  setCssSubtitleScreen(ui->labelSubtitle1);
103  spacerDiv = new QSpacerItem(40, 20, QSizePolicy::Maximum, QSizePolicy::Expanding);
104 
105  setCssProperty(ui->labelSubtitleDescription, "text-title");
106  btnOwnerContact = ui->lineEditOwnerAddress->addAction(QIcon("://ic-contact-arrow-down"), QLineEdit::TrailingPosition);
107  setCssProperty(ui->lineEditOwnerAddress, "edit-primary-multi-book");
108  ui->lineEditOwnerAddress->setAttribute(Qt::WA_MacShowFocusRect, 0);
109  setShadow(ui->lineEditOwnerAddress);
110  connect(ui->lineEditOwnerAddress, &QLineEdit::textChanged, this, &ColdStakingWidget::onOwnerAddressChanged);
111 
112  setCssSubtitleScreen(ui->labelSubtitle2);
113  ui->labelSubtitle2->setContentsMargins(0,2,0,0);
114 
115  setCssBtnPrimary(ui->pushButtonSend);
116  setCssBtnSecondary(ui->pushButtonClear);
117 
118  connect(ui->pushButtonClear, &QPushButton::clicked, this, &ColdStakingWidget::clearAll);
119 
120  setCssProperty(ui->labelEditTitle, "text-title");
121  sendMultiRow = new SendMultiRow(window, this);
123  ((QVBoxLayout*)ui->containerSend->layout())->insertWidget(1, sendMultiRow);
124  connect(sendMultiRow, &SendMultiRow::onContactsClicked, [this](){ onContactsClicked(false); });
125 
126  // List
127  setCssProperty(ui->labelStakingTotal, "text-title-right");
128  setCssProperty(ui->labelListHistory, "text-title");
129  setCssProperty(ui->pushImgEmpty, "img-empty-transactions");
130  setCssProperty(ui->labelEmpty, "text-empty");
131 
132  ui->btnCoinControl->setTitleClassAndText("btn-title-grey", tr("Coin Control"));
133  ui->btnCoinControl->setSubTitleClassAndText("text-subtitle", tr("Select %1 outputs to delegate.").arg(CURRENCY_UNIT.c_str()));
134 
135  ui->btnColdStaking->setTitleClassAndText("btn-title-grey", tr("Create Cold Staking Address"));
136  ui->btnColdStaking->setSubTitleClassAndText("text-subtitle", tr("Creates an address to receive delegated coins\nand stake them on their owner's behalf."));
137  ui->btnColdStaking->layout()->setMargin(0);
138 
139  connect(ui->btnCoinControl, &OptionButton::clicked, this, &ColdStakingWidget::onCoinControlClicked);
140  connect(ui->btnColdStaking, &OptionButton::clicked, this, &ColdStakingWidget::onColdStakeClicked);
141 
142  onDelegateSelected(true);
143  ui->pushRight->setChecked(true);
144  connect(ui->pushLeft, &QPushButton::clicked, [this](){onDelegateSelected(false);});
145  connect(ui->pushRight, &QPushButton::clicked, [this](){onDelegateSelected(true);});
146 
147  // List
148  setCssProperty(ui->listView, "container");
152  txHolder,
153  this
154  );
155 
160  this
161  );
162 
163  ui->listView->setItemDelegate(delegate);
164  ui->listView->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE));
165  ui->listView->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2));
166  ui->listView->setAttribute(Qt::WA_MacShowFocusRect, false);
167  ui->listView->setSelectionBehavior(QAbstractItemView::SelectRows);
168 
169  ui->btnMyStakingAddresses->setChecked(true);
170  ui->listViewStakingAddress->setVisible(false);
171 
172  // My ColdStaking Addresses search filter
173  initCssEditLine(ui->lineEditFilter, true);
174  ui->lineEditFilter->setStyleSheet("font: 14px;");
175 
176  ui->btnMyStakingAddresses->setTitleClassAndText("btn-title-grey", tr("My Cold Staking Addresses"));
177  ui->btnMyStakingAddresses->setSubTitleClassAndText("text-subtitle", tr("List your own cold staking addresses."));
178  ui->btnMyStakingAddresses->layout()->setMargin(0);
179  ui->btnMyStakingAddresses->setRightIconClass("ic-arrow");
180 
181  // List Addresses
182  setCssProperty(ui->listViewStakingAddress, "container");
183  ui->listViewStakingAddress->setItemDelegate(addressDelegate);
184  ui->listViewStakingAddress->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE));
185  ui->listViewStakingAddress->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2));
186  ui->listViewStakingAddress->setAttribute(Qt::WA_MacShowFocusRect, false);
187  ui->listViewStakingAddress->setSelectionBehavior(QAbstractItemView::SelectRows);
188  ui->listViewStakingAddress->setUniformItemSizes(true);
189 
190  // Sort Controls
191  SortEdit* lineEdit = new SortEdit(ui->comboBoxSort);
192  connect(lineEdit, &SortEdit::Mouse_Pressed, [this](){ui->comboBoxSort->showPopup();});
193  connect(ui->comboBoxSort, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ColdStakingWidget::onSortChanged);
194  SortEdit* lineEditOrder = new SortEdit(ui->comboBoxSortOrder);
195  connect(lineEditOrder, &SortEdit::Mouse_Pressed, [this](){ui->comboBoxSortOrder->showPopup();});
196  connect(ui->comboBoxSortOrder, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ColdStakingWidget::onSortOrderChanged);
197  fillAddressSortControls(lineEdit, lineEditOrder, ui->comboBoxSort, ui->comboBoxSortOrder);
198  ui->sortWidget->setVisible(false);
199 
200  connect(ui->pushButtonSend, &QPushButton::clicked, this, &ColdStakingWidget::onSendClicked);
201  connect(btnOwnerContact, &QAction::triggered, [this](){ onContactsClicked(true); });
202  connect(ui->listView, &QListView::clicked, this, &ColdStakingWidget::handleAddressClicked);
203  connect(ui->listViewStakingAddress, &QListView::clicked, this, &ColdStakingWidget::handleMyColdAddressClicked);
204  connect(ui->btnMyStakingAddresses, &OptionButton::clicked, this, &ColdStakingWidget::onMyStakingAddressesClicked);
205  connect(ui->lineEditFilter, &QLineEdit::textChanged, this, &ColdStakingWidget::filterChanged);
206 
207  coinControlDialog = new CoinControlDialog(nullptr, true);
208 }
209 
211 {
212  if (walletModel) {
216  ui->listView->setModel(csModel);
217  ui->listView->setModelColumn(ColdStakingModel::OWNER_ADDRESS);
218 
221  addressesFilter->setSourceModel(addressTableModel);
223  ui->listViewStakingAddress->setModel(addressesFilter);
224  ui->listViewStakingAddress->setModelColumn(AddressTableModel::Address);
225 
227 
229 
230  ui->containerHistoryLabel->setVisible(false);
231  ui->emptyContainer->setVisible(false);
232  ui->listView->setVisible(false);
233  }
234 
235 }
236 
237 void ColdStakingWidget::onTxArrived(const QString& hash, const bool isCoinStake, const bool isMNReward, const bool isCSAnyType)
238 {
239  if (isCSAnyType) {
241  }
242 }
243 
245 {
246  if (this->isChainSync != sync) {
247  this->isChainSync = sync;
249  }
250 }
251 
252 void ColdStakingWidget::showEvent(QShowEvent *event)
253 {
255 }
256 
258 {
259  if (!isVisible()) return;
260  // Check for min update time to not reload the UI so often if the node is syncing.
261  int64_t now = GetTime();
263  lastRefreshTime = now;
265  }
266 }
267 
269 {
270  if (isLoading) return false;
271  isLoading = true;
272  return execute(REQUEST_LOAD_TASK);
273 }
274 
276 {
277  isLoading = false;
278  bool hasDel = csModel->rowCount() > 0;
279 
281 
282  // Update list if we are showing that section.
283  if (!isInDelegation) {
284  showList(hasDel);
285  ui->labelStakingTotal->setVisible(hasDel);
286  }
287 }
288 
290 {
291  if (type == REQUEST_LOAD_TASK) {
293  QMetaObject::invokeMethod(this, "onDelegationsRefreshed", Qt::QueuedConnection);
294  }
295 }
296 void ColdStakingWidget::onError(QString error, int type)
297 {
298  isLoading = false;
299  inform(tr("Error loading delegations: %1").arg(error));
300 }
301 
303 {
304  isContactOwnerSelected = ownerAdd;
306 }
307 
309 {
310  if (menu && menu->isVisible()) {
311  menu->hide();
312  }
313 
315  if (contactsSize == 0) {
317  tr( "No receive addresses available, you can go to the receive screen and create some there!") :
318  tr("No contacts available, you can go to the contacts screen and add some there!")
319  );
320  return;
321  }
322 
323  int height;
324  int width;
325  QPoint pos;
326 
328  height = ui->lineEditOwnerAddress->height();
329  width = ui->lineEditOwnerAddress->width();
330  pos = ui->containerSend->rect().bottomLeft();
331  pos.setY((pos.y() + (height - 12) * 3));
332  } else {
333  height = sendMultiRow->getEditHeight();
334  width = sendMultiRow->getEditWidth();
335  pos = sendMultiRow->getEditLineRect().bottomLeft();
336  pos.setY((pos.y() + (height - 14) * 4));
337  }
338 
339  int margin1, margin2;
340  ui->verticalLayoutTop->getContentsMargins(&margin1, nullptr, nullptr, nullptr);
341  ui->vContainerOwner->getContentsMargins(&margin2, nullptr, nullptr, nullptr);
342  pos.setX(pos.x() + margin1 + margin2);
343 
344  height = (contactsSize <= 2) ? height * ( 2 * (contactsSize + 1 )) : height * 6;
345 
346  if (!menuContacts) {
348  width,
349  height,
350  this
351  );
352  connect(menuContacts, &ContactsDropdown::contactSelected, [this](QString address, QString label) {
354  ui->lineEditOwnerAddress->setText(address);
355  } else {
356  sendMultiRow->setLabel(label);
357  sendMultiRow->setAddress(address);
358  }
359  });
360  }
361 
362  if (menuContacts->isVisible()) {
363  menuContacts->hide();
364  return;
365  }
366 
368  menuContacts->resizeList(width, height);
369  menuContacts->setStyleSheet(styleSheet());
370  menuContacts->adjustSize();
371  menuContacts->move(pos);
372  menuContacts->show();
373 }
374 
376 {
378  if (menu && menu->isVisible()) {
379  menu->hide();
380  }
381 
382  if (menuAddresses && menuAddresses->isVisible()) {
383  menuAddresses->hide();
384  }
385 
386  if (isInDelegation) {
387  ui->btnCoinControl->setVisible(true);
388  ui->containerSend->setVisible(true);
389  ui->containerBtn->setVisible(true);
390  ui->emptyContainer->setVisible(false);
391  ui->listView->setVisible(false);
392  ui->containerHistoryLabel->setVisible(false);
393  ui->btnColdStaking->setVisible(false);
394  ui->btnMyStakingAddresses->setVisible(false);
395  ui->listViewStakingAddress->setVisible(false);
396  ui->sortWidget->setVisible(false);
397  ui->rightContainer->addItem(spacerDiv);
398  } else {
399  ui->btnCoinControl->setVisible(false);
400  ui->containerSend->setVisible(false);
401  ui->containerBtn->setVisible(false);
402  ui->btnColdStaking->setVisible(true);
403  showList(csModel->rowCount() > 0);
404  ui->btnMyStakingAddresses->setVisible(true);
405  // Show address list, if it was previously open
406  ui->listViewStakingAddress->setVisible(isStakingAddressListVisible);
407  ui->sortWidget->setVisible(isStakingAddressListVisible);
408  }
409 }
410 
414  }
415 }
416 
418 {
419  ui->emptyContainer->setVisible(!show);
420  ui->listView->setVisible(show);
421  ui->containerHistoryLabel->setVisible(show);
422 }
423 
425 {
427  return;
428 
430  inform(tr("Cold staking is networkely disabled"));
431  return;
432  }
433 
434  if (!sendMultiRow->validate()) {
435  inform(tr("Invalid entry"));
436  return;
437  }
438 
440  dest.isP2CS = true;
441 
442  // Amount must be >= minColdStakingAmount
443  const CAmount& minColdStakingAmount = walletModel->getMinColdStakingAmount();
444  if (dest.amount < minColdStakingAmount) {
445  inform(tr("Invalid entry, minimum delegable amount is ") +
446  BitcoinUnits::formatWithUnit(nDisplayUnit, minColdStakingAmount));
447  return;
448  }
449 
450  QString inputOwner = ui->lineEditOwnerAddress->text();
451  bool isOwnerEmpty = inputOwner.isEmpty();
452  if (!isOwnerEmpty && !walletModel->validateAddress(inputOwner)) {
453  inform(tr("Owner address invalid"));
454  return;
455  }
456 
457 
458  bool isStakingAddressFromThisWallet = walletModel->isMine(dest.address);
459  bool isOwnerAddressFromThisWallet = isOwnerEmpty || walletModel->isMine(inputOwner);
460 
461  // Warn the user if the owner address is not from this wallet
462  if (!isOwnerAddressFromThisWallet && !ask(tr("ALERT!"),
463  tr("Delegating to an external owner address!\n\n"
464  "The delegated coins will NOT be spendable by this wallet.\nSpending these coins will need to be done from the wallet or\ndevice containing the owner address.\n\n"
465  "Do you wish to proceed?"))) {
466  return;
467  }
468 
469  // Don't try to delegate the balance if both addresses are from this wallet
470  if (isStakingAddressFromThisWallet && isOwnerAddressFromThisWallet) {
471  inform(tr("Staking address corresponds to this wallet, change it to an external node"));
472  return;
473  }
474 
475  // Unlock wallet
477  if (!ctx.isValid()) {
478  // Unlock wallet was cancelled
479  inform(tr("Cannot send delegation, wallet locked"));
480  return;
481  }
482 
483  dest.ownerAddress = inputOwner;
484  QList<SendCoinsRecipient> recipients;
485  recipients.append(dest);
486 
487  // Prepare transaction for getting txFee earlier (exclude delegated coins)
488  WalletModelTransaction currentTransaction(recipients);
489  WalletModel::SendCoinsReturn prepareStatus = walletModel->prepareTransaction(&currentTransaction, coinControlDialog->coinControl, false);
490 
491  // process prepareStatus and on error generate message shown to user
493  this,
494  prepareStatus,
495  walletModel,
497  true
498  );
499 
500  if (prepareStatus.status != WalletModel::OK) {
501  inform(tr("Cannot create transaction."));
502  return;
503  }
504 
505  showHideOp(true);
506  TxDetailDialog* dialog = new TxDetailDialog(window);
507  dialog->setDisplayUnit(nDisplayUnit);
508  dialog->setData(walletModel, &currentTransaction);
509  dialog->adjustSize();
511 
512  if (dialog->isConfirm()) {
513  // now send the prepared transaction
514  WalletModel::SendCoinsReturn sendStatus = dialog->getStatus();
515  // process sendStatus and on error generate message shown to user
517  this,
518  sendStatus,
520  );
521 
522  if (sendStatus.status == WalletModel::OK) {
523  clearAll();
524  inform(tr("Coins delegated"));
525  }
526  }
527 
528  dialog->deleteLater();
529 }
530 
532 {
534  ui->lineEditOwnerAddress->clear();
537  ui->btnCoinControl->setActive(false);
538  }
539 }
540 
542 {
543  if (isInDelegation) {
544  if (walletModel->getBalance() > 0) {
548  coinControlDialog->exec();
549  ui->btnCoinControl->setActive(coinControlDialog->coinControl->HasSelected());
550  } else {
551  inform(tr("You don't have any %1 to select.").arg(CURRENCY_UNIT.c_str()));
552  }
553  }
554 }
555 
557 {
558  if (!coinControlDialog) return;
561 }
562 
564 {
566 }
567 
569 {
570  if (walletModel && !isShowingDialog) {
572  if (!ctx.isValid()) {
573  // Unlock wallet was cancelled
574  inform(tr("Cannot perform operation, wallet locked"));
575  return;
576  }
577  isShowingDialog = true;
578  showHideOp(true);
579  RequestDialog *dialog = new RequestDialog(window);
580  dialog->setWalletModel(walletModel);
581  dialog->setPaymentRequest(isPaymentRequest);
582  openDialogWithOpaqueBackgroundY(dialog, window, 3.5, 12);
583  if (dialog->res == 1) {
584  inform(tr("URI copied to clipboard"));
585  } else if (dialog->res == 2) {
586  inform(tr("Address copied to clipboard"));
587  }
588  dialog->deleteLater();
589  isShowingDialog = false;
590  }
591 }
592 
593 void ColdStakingWidget::handleMyColdAddressClicked(const QModelIndex &_index)
594 {
595  ui->listViewStakingAddress->setCurrentIndex(_index);
596 
597  QRect rect = ui->listViewStakingAddress->visualRect(_index);
598  QPoint pos = rect.topRight();
599  pos.setX( parentWidget()->rect().right() - (DECORATION_SIZE * 1.5) );
600  pos.setY(pos.y() + (DECORATION_SIZE * 2.5));
601 
602  QModelIndex rIndex = addressesFilter->mapToSource(_index);
603 
604  if (!menuAddresses) {
605  menuAddresses = new TooltipMenu(window, this);
606  menuAddresses->setEditBtnText(tr("Copy"));
607  menuAddresses->setDeleteBtnText(tr("Edit"));
609  menuAddresses->adjustSize();
613  } else {
614  menuAddresses->hide();
615  }
616 
617  this->addressIndex = rIndex;
618 
619  menuAddresses->move(pos);
620  menuAddresses->show();
621 }
622 
623 void ColdStakingWidget::handleAddressClicked(const QModelIndex &rIndex)
624 {
625  bool isReceivedDelegation = rIndex.sibling(rIndex.row(), ColdStakingModel::IS_RECEIVED_DELEGATION).data(Qt::DisplayRole).toBool();
626 
627  ui->listView->setCurrentIndex(rIndex);
628  QRect rect = ui->listView->visualRect(rIndex);
629  QPoint pos = rect.topRight();
630  pos.setX(pos.x() - (DECORATION_SIZE * 2));
631  pos.setY(pos.y() + (DECORATION_SIZE * 2));
632 
633  if (!this->menu) {
634  this->menu = new TooltipMenu(window, this);
635  this->menu->setEditBtnText(tr("Stake"));
636  this->menu->setDeleteBtnText(tr("Blacklist"));
637  this->menu->setCopyBtnText(tr("Edit Label"));
638  this->menu->setLastBtnText(tr("Copy owner\naddress"), 40);
639  this->menu->setLastBtnVisible(true);
640  this->menu->setMinimumHeight(157);
641  this->menu->setFixedHeight(157);
642  this->menu->setMinimumWidth(125);
643  connect(this->menu, &TooltipMenu::message, this, &AddressesWidget::message);
646  connect(this->menu, &TooltipMenu::onCopyClicked, [this](){onLabelClicked();});
648  } else {
649  this->menu->hide();
650  }
651 
652  this->index = rIndex;
653 
654  if (isReceivedDelegation) {
655  bool isWhitelisted = rIndex.sibling(rIndex.row(), ColdStakingModel::IS_WHITELISTED).data(
656  Qt::DisplayRole).toBool();
657  this->menu->setDeleteBtnVisible(isWhitelisted);
658  this->menu->setEditBtnVisible(!isWhitelisted);
659  this->menu->setCopyBtnVisible(true);
660  this->menu->setMinimumHeight(157);
661  } else {
662  // owner side
663  this->menu->setDeleteBtnVisible(false);
664  this->menu->setEditBtnVisible(false);
665  this->menu->setCopyBtnVisible(false);
666  this->menu->setMinimumHeight(60);
667  }
668 
669  this->menu->adjustSize();
670 
671  menu->move(pos);
672  menu->show();
673 }
674 
676 {
677  GUIUtil::setClipboard(addressIndex.data(Qt::DisplayRole).toString());
678  inform(tr("Address copied"));
679 }
680 
682 {
684  tr("Edit Cold Address Label"),
685  addressIndex,
686  false
687  );
688 }
689 
691 {
692  // whitelist address
693  if (!csModel->whitelist(index)) {
694  inform(tr("Whitelist failed, please check the logs"));
695  return;
696  }
697  QString label = index.sibling(index.row(), ColdStakingModel::OWNER_ADDRESS_LABEL).data(Qt::DisplayRole).toString();
698  if (label.isEmpty()) {
699  label = index.data(Qt::DisplayRole).toString();
700  }
702  inform(label + tr(" staking!"));
703 }
704 
706 {
707  // blacklist address
708  if (!csModel->blacklist(index)) {
709  inform(tr("Blacklist failed, please check the logs"));
710  return;
711  }
712  QString label = index.sibling(index.row(), ColdStakingModel::OWNER_ADDRESS_LABEL).data(Qt::DisplayRole).toString();
713  if (label.isEmpty()) {
714  label = index.data(Qt::DisplayRole).toString();
715  }
717  inform(label + tr(" blacklisted from staking"));
718 }
719 
721 {
722  // show address info
723 }
724 
726 {
727  QString owner = index.data(Qt::DisplayRole).toString();
728  GUIUtil::setClipboard(owner);
729  inform(tr("Owner address copied"));
730 }
731 
733 {
735  tr("Edit Owner Address Label"),
736  index,
737  false
738  );
739 }
740 
741 void ColdStakingWidget::onLabelClicked(QString dialogTitle, const QModelIndex &index, const bool isMyColdStakingAddresses)
742 {
743  if (walletModel && !isShowingDialog) {
744  isShowingDialog = true;
745  showHideOp(true);
747  dialog->setTexts(dialogTitle);
748  QString qAddress = index.data(Qt::DisplayRole).toString();
749  dialog->setData(qAddress, walletModel->getAddressTableModel()->labelForAddress(qAddress));
750  if (openDialogWithOpaqueBackgroundY(dialog, window, 3.5, 6)) {
751  QString label = dialog->getLabel();
752  std::string stdString = qAddress.toStdString();
753  std::string purpose = walletModel->getAddressTableModel()->purposeForAddress(stdString);
754  const CTxDestination address = DecodeDestination(stdString.data());
755  if (!label.isEmpty() && walletModel->updateAddressBookLabels(
756  address,
757  label.toUtf8().constData(),
758  purpose
759  )) {
760  if (isMyColdStakingAddresses) {
762  } else
764  inform(tr("Address label saved"));
765  } else {
766  inform(tr("Error storing address label"));
767  }
768  }
769  isShowingDialog = false;
770  }
771 }
772 
774 {
775  isStakingAddressListVisible = !ui->listViewStakingAddress->isVisible();
776  ui->btnMyStakingAddresses->setRightIconClass((isStakingAddressListVisible ?
777  "btn-dropdown" : "ic-arrow"), true);
778  ui->listViewStakingAddress->setVisible(isStakingAddressListVisible);
780  ui->sortWidget->setVisible(true);
781  ui->rightContainer->removeItem(spacerDiv);
782  ui->listViewStakingAddress->update();
783  } else {
784  ui->sortWidget->setVisible(false);
785  ui->rightContainer->addItem(spacerDiv);
786  }
787 }
788 
790 {
791  const bool isValid = ui->lineEditOwnerAddress->text().isEmpty() || (
792  walletModel && walletModel->validateAddress(ui->lineEditOwnerAddress->text()));
793 
794  setCssProperty(ui->lineEditOwnerAddress, isValid ? "edit-primary-multi-book" : "edit-primary-multi-book-error", true);
795 }
796 
798 {
801  ui->listView->update();
802 }
803 
805 {
806  const CAmount& total = csModel->getTotalAmount();
807  ui->labelStakingTotal->setText(tr("Total Staking: %1").arg(
808  (total == 0) ? "0.00 " + QString(CURRENCY_UNIT.c_str()) : GUIUtil::formatBalance(total, nDisplayUnit))
809  );
810 }
811 
813 {
814  sortType = (AddressTableModel::ColumnIndex) ui->comboBoxSort->itemData(idx).toInt();
815  sortAddresses();
816 }
817 
819 {
820  sortOrder = (Qt::SortOrder) ui->comboBoxSortOrder->itemData(idx).toInt();
821  sortAddresses();
822 }
823 
824 void ColdStakingWidget::filterChanged(const QString& str)
825 {
826  this->addressesFilter->setFilterRegExp(str);
827 }
828 
830 {
831  if (this->addressesFilter)
832  this->addressesFilter->sort(sortType, sortOrder);
833 }
834 
835 
837 {
838  if (sendMultiRow)
839  delete sendMultiRow;
840  if (txHolder)
841  delete txHolder;
842  if (csModel)
843  delete csModel;
844  if (addressHolder)
845  delete addressHolder;
846 
847  ui->rightContainer->removeItem(spacerDiv);
848  delete spacerDiv;
849  delete ui;
850  delete coinControlDialog;
851 }
int64_t CAmount
Amount in PIV (Can be negative)
Definition: amount.h:13
false
Definition: bls_dkg.cpp:151
void setTexts(QString title, const char *message=nullptr)
void setData(QString address, QString label)
static const QString ColdStakingSend
Specifies send cold staking addresses (simil 'contacts')
@ Address
Bitcoin address.
std::string purposeForAddress(const std::string &address) const
void notifyChange(const QModelIndex &index)
static const QString Receive
Specifies receive address.
static const QString ColdStaking
Specifies cold staking own addresses.
QString labelForAddress(const QString &address) const
static QString formatWithUnit(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard)
Format as string (with unit)
bool HasSelected() const
Definition: coincontrol.h:66
void SetNull()
Definition: coincontrol.h:55
QColor rectColor(bool isHovered, bool isSelected) override
CSDelegationHolder(bool _isLightTheme)
~CSDelegationHolder() override
CSRow * createHolder(int pos) override
void init(QWidget *holder, const QModelIndex &index, bool isHovered, bool isSelected) const override
Definition: csrow.h:15
void updateState(bool isLightTheme, bool isHovered, bool isSelected)
Definition: csrow.cpp:31
void updateView(const QString &address, const QString &label, bool isStaking, bool isReceivedDelegation, const QString &amount)
Definition: csrow.cpp:19
void showMenuButton(bool show)
Definition: csrow.cpp:38
void setModel(WalletModel *model)
CCoinControl * coinControl
void addPayAmount(const CAmount &amount, bool isShieldedRecipient)
int rowCount(const QModelIndex &parent=QModelIndex()) const override
CAmount getTotalAmount() const
bool whitelist(const QModelIndex &modelIndex)
bool blacklist(const QModelIndex &index)
void onSortOrderChanged(int idx)
void showAddressGenerationDialog(bool isPaymentRequest)
std::atomic< bool > isLoading
Qt::SortOrder sortOrder
AddressTableModel * addressTableModel
void run(int type) override
void onDelegateSelected(bool delegate)
FurAbstractListItemDelegate * addressDelegate
AddressHolder * addressHolder
TooltipMenu * menuAddresses
CoinControlDialog * coinControlDialog
TransactionTableModel * txModel
SendMultiRow * sendMultiRow
void onTxArrived(const QString &hash, const bool isCoinStake, const bool isMNReward, const bool isCSAnyType)
void handleMyColdAddressClicked(const QModelIndex &rIndex)
ColdStakingModel * csModel
AddressFilterProxyModel * addressesFilter
void loadWalletModel() override
void onError(QString error, int type) override
ContactsDropdown * menuContacts
void onSortChanged(int idx)
void walletSynced(bool sync)
QSpacerItem * spacerDiv
AddressTableModel::ColumnIndex sortType
CSDelegationHolder * txHolder
Ui::ColdStakingWidget * ui
void changeTheme(bool isLightTheme, QString &theme) override
void filterChanged(const QString &str)
ColdStakingWidget(PIVXGUI *parent)
void showList(bool show)
void showEvent(QShowEvent *event) override
FurAbstractListItemDelegate * delegate
void handleAddressClicked(const QModelIndex &index)
QModelIndex addressIndex
void resizeList(int minWidth, int mintHeight)
void contactSelected(QString address, QString label)
void setWalletModel(WalletModel *_model, const QStringList &type)
void clicked()
int getDisplayUnit()
Definition: optionsmodel.h:74
PIVX GUI main class.
Definition: pivxgui.h:46
PIVXGUI * window
Definition: pwidget.h:59
void inform(const QString &message)
Definition: pwidget.cpp:45
WalletModel * walletModel
Definition: pwidget.h:61
void setWalletModel(WalletModel *model)
Definition: pwidget.cpp:27
bool execute(int type, std::unique_ptr< WalletModel::UnlockContext > pctx=nullptr)
Definition: pwidget.cpp:94
void showHideOp(bool show)
Definition: pwidget.cpp:40
void message(const QString &title, const QString &body, unsigned int style, bool *ret=nullptr)
bool ask(const QString &title, const QString &message)
Definition: pwidget.cpp:55
void setWalletModel(WalletModel *model)
void setPaymentRequest(bool _isPaymentRequest)
QString ownerAddress
Definition: walletmodel.h:67
SendCoinsRecipient getValue()
void setLabel(const QString &label)
QRect getEditLineRect()
void onContactsClicked(SendMultiRow *entry)
void setOnlyStakingAddressAccepted(bool onlyStakingAddress)
CAmount getAmountValue()
void setAddress(const QString &address)
void Mouse_Pressed()
void setDeleteBtnText(const QString &btnText)
Definition: tooltipmenu.cpp:30
void setEditBtnText(const QString &btnText)
Definition: tooltipmenu.cpp:26
void onDeleteClicked()
void setLastBtnVisible(bool visible)
Definition: tooltipmenu.cpp:61
void setDeleteBtnVisible(bool visible)
Definition: tooltipmenu.cpp:53
void setEditBtnVisible(bool visible)
Definition: tooltipmenu.cpp:57
void setCopyBtnText(const QString &btnText)
Definition: tooltipmenu.cpp:34
void onEditClicked()
void setLastBtnText(const QString &btnText, int minHeight=30)
Definition: tooltipmenu.cpp:38
void setCopyBtnVisible(bool visible)
Definition: tooltipmenu.cpp:49
void onCopyClicked()
void onLastClicked()
void txArrived(const QString &hash, const bool isCoinStake, const bool isMNReward, const bool isCSAnyType)
WalletModel::SendCoinsReturn getStatus()
void setDisplayUnit(int unit)
void setData(WalletModel *model, WalletModelTransaction *tx)
bool validateAddress(const QString &address)
bool isMine(const CWDestination &address)
bool updateAddressBookLabels(const CWDestination &address, const std::string &strName, const std::string &strPurpose)
CAmount getMinColdStakingAmount() const
AddressTableModel * getAddressTableModel()
OptionsModel * getOptionsModel()
SendCoinsReturn prepareTransaction(WalletModelTransaction *transaction, const CCoinControl *coinControl=nullptr, bool fIncludeDelegations=true)
bool isColdStakingNetworkelyEnabled() const
Whether cold staking is enabled or disabled in the network.
Definition: walletmodel.cpp:91
CAmount getBalance(const CCoinControl *coinControl=nullptr, bool fIncludeDelegated=true, bool fUnlockedOnly=false, bool fIncludeShielded=true) const
UnlockContext requestUnlock()
TransactionTableModel * getTransactionTableModel()
Data model for a walletmodel transaction.
#define REQUEST_LOAD_TASK
#define LOAD_MIN_TIME_INTERVAL
#define DECORATION_SIZE
#define NUM_ITEMS
const std::string CURRENCY_UNIT
Definition: feerate.cpp:11
QString formatBalance(CAmount amount, int nDisplayUnit, bool isZpiv)
Definition: guiutil.cpp:119
void setClipboard(const QString &str)
Definition: guiutil.cpp:670
void ProcessSendCoinsReturnAndInform(PWidget *parent, const WalletModel::SendCoinsReturn &sendCoinsReturn, WalletModel *walletModel, const QString &msgArg, bool fPrepare)
CWDestination DecodeDestination(const std::string &strAddress)
bool isLightTheme()
Definition: qtutils.cpp:210
bool openDialogWithOpaqueBackgroundY(QDialog *widget, PIVXGUI *gui, double posX, int posY, bool hideOpaqueBackground)
Definition: qtutils.cpp:59
void setCssTitleScreen(QLabel *label)
Definition: qtutils.cpp:324
void initCssEditLine(QLineEdit *edit, bool isDialog)
Definition: qtutils.cpp:272
void setShadow(QWidget *edit)
Definition: qtutils.cpp:292
void setCssProperty(std::initializer_list< QWidget * > args, const QString &value)
Definition: qtutils.cpp:334
QColor getRowColor(bool isLightTheme, bool isHovered, bool isSelected)
Definition: qtutils.cpp:233
void setCssSubtitleScreen(QWidget *wid)
Definition: qtutils.cpp:329
void setCssBtnPrimary(QPushButton *btn, bool forceUpdate)
Definition: qtutils.cpp:302
void setCssBtnSecondary(QPushButton *btn, bool forceUpdate)
Definition: qtutils.cpp:307
void fillAddressSortControls(SortEdit *seType, SortEdit *seOrder, QComboBox *boxType, QComboBox *boxOrder)
Definition: qtutils.cpp:257
boost::variant< CNoDestination, CKeyID, CScriptID, CExchangeKeyID > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:72
bool error(const char *fmt, const Args &... args)
Definition: system.h:77
int64_t GetTime()
DEPRECATED Use either GetSystemTimeInSeconds (not mockable) or GetTime<T> (mockable)
Definition: utiltime.cpp:27