PIVX Core  5.6.99
P2P Digital Currency
receivewidget.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 "receivewidget.h"
6 #include "ui_receivewidget.h"
7 
8 #include "addnewcontactdialog.h"
9 #include "addressholder.h"
10 #include "guiutil.h"
11 #include "myaddressrow.h"
12 #include "qtutils.h"
13 #include "requestdialog.h"
14 #include "walletmodel.h"
15 
16 #include <QModelIndex>
17 #include <QColor>
18 #include <QDateTime>
19 
20 #define DECORATION_SIZE 70
21 #define NUM_ITEMS 3
22 
24  PWidget(parent),
25  ui(new Ui::ReceiveWidget)
26 {
27  ui->setupUi(this);
28  this->setStyleSheet(parent->styleSheet());
29 
33  this
34  );
35 
36  // Containers
37  setCssProperty(ui->left, "container");
38  ui->left->setContentsMargins(20,20,20,20);
39  setCssProperty(ui->right, "container-right");
40  ui->right->setContentsMargins(0,9,0,0);
41 
42  // Title
43  setCssTitleScreen(ui->labelTitle);
44  setCssSubtitleScreen(ui->labelSubtitle1);
45 
46  // Address
47  setCssProperty(ui->labelAddress, "label-address-box");
48 
49  /* Button Group */
50  setCssProperty(ui->pushLeft, "btn-check-left");
51  setCssProperty(ui->pushRight, "btn-check-right");
52  setCssSubtitleScreen(ui->labelSubtitle2);
53  ui->labelSubtitle2->setContentsMargins(0,2,4,0);
54 
55  setCssSubtitleScreen(ui->labelDate);
56  setCssSubtitleScreen(ui->labelLabel);
57 
58  // Options
59  ui->btnMyAddresses->setTitleClassAndText("btn-title-grey", tr("My Addresses"));
60  ui->btnMyAddresses->setSubTitleClassAndText("text-subtitle", tr("List your own addresses"));
61  ui->btnMyAddresses->layout()->setMargin(0);
62  ui->btnMyAddresses->setRightIconClass("ic-arrow");
63 
64  ui->btnRequest->setTitleClassAndText("btn-title-grey", tr("Create Request"));
65  ui->btnRequest->setSubTitleClassAndText("text-subtitle", tr("Request payment with a fixed amount"));
66  ui->btnRequest->layout()->setMargin(0);
67 
68  ui->pushButtonLabel->setLayoutDirection(Qt::RightToLeft);
69  setCssProperty(ui->pushButtonLabel, "btn-secundary-label");
70 
71  ui->pushButtonNewAddress->setLayoutDirection(Qt::RightToLeft);
72  setCssProperty(ui->pushButtonNewAddress, "btn-secundary-new-address");
73 
74  ui->pushButtonCopy->setLayoutDirection(Qt::RightToLeft);
75  setCssProperty(ui->pushButtonCopy, "btn-secundary-copy");
76 
77  setCssProperty(ui->labelQrImg, "text-subtitle");
78 
79  // List Addresses
80  setCssProperty(ui->listViewAddress, "container");
81  ui->listViewAddress->setItemDelegate(delegate);
82  ui->listViewAddress->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE));
83  ui->listViewAddress->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2));
84  ui->listViewAddress->setAttribute(Qt::WA_MacShowFocusRect, false);
85  ui->listViewAddress->setSelectionBehavior(QAbstractItemView::SelectRows);
86  ui->listViewAddress->setUniformItemSizes(true);
87 
88  spacer = new QSpacerItem(40, 20, QSizePolicy::Maximum, QSizePolicy::Expanding);
89  ui->btnMyAddresses->setChecked(true);
90  ui->container_right->addItem(spacer);
91  ui->listViewAddress->setVisible(false);
92 
93  // My Address search filter
94  initCssEditLine(ui->lineEditFilter, true);
95  ui->lineEditFilter->setStyleSheet("font: 14px;");
96 
97  // Sort Controls
98  SortEdit* lineEdit = new SortEdit(ui->comboBoxSort);
99  connect(lineEdit, &SortEdit::Mouse_Pressed, [this](){ui->comboBoxSort->showPopup();});
100  connect(ui->comboBoxSort, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ReceiveWidget::onSortChanged);
101  SortEdit* lineEditOrder = new SortEdit(ui->comboBoxSortOrder);
102  connect(lineEditOrder, &SortEdit::Mouse_Pressed, [this](){ui->comboBoxSortOrder->showPopup();});
103  connect(ui->comboBoxSortOrder, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ReceiveWidget::onSortOrderChanged);
104  fillAddressSortControls(lineEdit, lineEditOrder, ui->comboBoxSort, ui->comboBoxSortOrder);
105  ui->sortWidget->setVisible(false);
106 
107  // Connect
108  connect(ui->pushButtonLabel, &QPushButton::clicked, this, &ReceiveWidget::onLabelClicked);
109  connect(ui->pushButtonCopy, &QPushButton::clicked, this, &ReceiveWidget::onCopyClicked);
110  connect(ui->pushButtonNewAddress, &QPushButton::clicked, this, &ReceiveWidget::onNewAddressClicked);
111  connect(ui->listViewAddress, &QListView::clicked, this, &ReceiveWidget::handleAddressClicked);
112  connect(ui->btnRequest, &OptionButton::clicked, this, &ReceiveWidget::onRequestClicked);
113  connect(ui->btnMyAddresses, &OptionButton::clicked, this, &ReceiveWidget::onMyAddressesClicked);
114  connect(ui->lineEditFilter, &QLineEdit::textChanged, this, &ReceiveWidget::filterChanged);
115 
116  ui->pushLeft->setChecked(true);
117  connect(ui->pushLeft, &QPushButton::clicked, [this](){onTransparentSelected(true);});
118  connect(ui->pushRight, &QPushButton::clicked, [this](){onTransparentSelected(false);});
119 }
120 
122 {
123  if (walletModel) {
126  this->filter->setSourceModel(addressTableModel);
127  this->filter->sort(sortType, sortOrder);
128  ui->listViewAddress->setModel(this->filter);
129  ui->listViewAddress->setModelColumn(AddressTableModel::Address);
130 
131  if (!info) info = new SendCoinsRecipient();
132  refreshView();
133 
134  // data change
135  connect(this->addressTableModel, &AddressTableModel::dataChanged, [this](const QModelIndex& tl, const QModelIndex& br){ refreshView(tl, br); });
136  }
137 }
138 
139 void ReceiveWidget::refreshView(const QModelIndex& tl, const QModelIndex& br)
140 {
141  const QModelIndex& index = tl.sibling(tl.row(), AddressTableModel::Address);
142  const QString& typeRole = index.data(AddressTableModel::TypeRole).toString();
143  if (shieldedMode && typeRole != AddressTableModel::ShieldedReceive) return;
144  if (!shieldedMode && typeRole != AddressTableModel::Receive) return;
145  return refreshView(index.data(Qt::DisplayRole).toString());
146 }
147 
148 void ReceiveWidget::refreshView(const QString& refreshAddress)
149 {
150  try {
151  const QString& latestAddress = (refreshAddress.isEmpty()) ? addressTableModel->getAddressToShow(shieldedMode) : refreshAddress;
152  if (latestAddress.isEmpty()) {
153  // Check for generation errors
154  ui->labelQrImg->setText(tr("No available address\ntry unlocking the wallet"));
155  inform(tr("Error generating address"));
156  return;
157  }
158 
159  QString addressToShow = latestAddress;
160  int64_t time = walletModel->getKeyCreationTime(latestAddress.toStdString());
161  if (shieldedMode) {
162  addressToShow = addressToShow.left(20) + "..." + addressToShow.right(19);
163  }
164 
165  ui->labelAddress->setText(addressToShow);
166  ui->labelDate->setText(GUIUtil::dateTimeStr(QDateTime::fromTime_t(static_cast<uint>(time))));
167  updateQr(latestAddress);
168  updateLabel();
169  } catch (const std::runtime_error& error) {
170  ui->labelQrImg->setText(tr("No available address\ntry unlocking the wallet"));
171  inform(tr("Error generating address"));
172  }
173 }
174 
176 {
177  if (!info->address.isEmpty()) {
178  // Check if address label exists
179  QString label = addressTableModel->labelForAddress(info->address);
180  if (!label.isEmpty()) {
181  ui->labelLabel->setVisible(true);
182  ui->labelLabel->setText(label);
183  ui->pushButtonLabel->setText(tr("Edit Label"));
184  } else {
185  ui->labelLabel->setVisible(false);
186  ui->pushButtonLabel->setText(tr("Add Label"));
187  }
188  }
189 }
190 
191 void ReceiveWidget::updateQr(const QString& address)
192 {
193  info->address = address;
194  QString uri = GUIUtil::formatBitcoinURI(*info);
195  ui->labelQrImg->setText("");
196 
197  QString error;
198  QColor qrColor("#382d4d");
199  QPixmap pixmap = encodeToQr(uri, error, qrColor);
200  if (!pixmap.isNull()) {
201  ui->labelQrImg->setPixmap(pixmap.scaled(ui->labelQrImg->width(), ui->labelQrImg->height()));
202  } else {
203  ui->labelQrImg->setText(!error.isEmpty() ? error : "Error encoding address");
204  }
205 }
206 
207 void ReceiveWidget::handleAddressClicked(const QModelIndex &index)
208 {
209  QModelIndex rIndex = filter->mapToSource(index);
210  refreshView(rIndex.data(Qt::DisplayRole).toString());
211 }
212 
214 {
215  if (walletModel && !isShowingDialog) {
216  isShowingDialog = true;
217  showHideOp(true);
219  dialog->setTexts(tr("Edit Address Label"));
221  if (openDialogWithOpaqueBackgroundY(dialog, window, 3.5, 6)) {
222  QString label = dialog->getLabel();
223  const CWDestination address = Standard::DecodeDestination(info->address.toUtf8().constData());
224  if (!label.isEmpty() && walletModel->updateAddressBookLabels(
225  address,
226  label.toUtf8().constData(),
228  )
229  ) {
230  // update label status (icon color)
231  updateLabel();
232  inform(tr("Address label saved"));
233  } else {
234  inform(tr("Error storing address label"));
235  }
236  }
237  dialog->deleteLater();
238  isShowingDialog = false;
239  }
240 }
241 
243 {
244  try {
246  if (!ctx.isValid()) {
247  // Unlock wallet was cancelled
248  inform(tr("Cannot create new address, wallet locked"));
249  return;
250  }
251 
254 
255  // Check validity
256  if (!r) {
257  inform(r.getError().c_str());
258  return;
259  }
260 
261  refreshView(QString::fromStdString(r.getObjResult()->ToString()));
262  inform(tr("New address created"));
263  } catch (const std::runtime_error& error) {
264  // Error generating address
265  inform("Error generating address");
266  }
267 }
268 
270 {
272  inform(tr("Address copied"));
273 }
274 
275 
277 {
279 }
280 
282 {
283  if (walletModel && !isShowingDialog) {
285  if (!ctx.isValid()) {
286  // Unlock wallet was cancelled
287  inform(tr("Cannot perform operation, wallet locked"));
288  return;
289  }
290  isShowingDialog = true;
291  showHideOp(true);
292  RequestDialog *dialog = new RequestDialog(window);
293  dialog->setWalletModel(walletModel);
294  dialog->setPaymentRequest(isPaymentRequest);
295  openDialogWithOpaqueBackgroundY(dialog, window, 3.5, 12);
296  if (dialog->res == 1) {
297  inform(tr("URI copied to clipboard"));
298  } else if (dialog->res == 2) {
299  inform(tr("Address copied to clipboard"));
300  }
301  dialog->deleteLater();
302  isShowingDialog = false;
303  }
304 }
305 
307 {
308  bool isVisible = ui->listViewAddress->isVisible();
309  if (!isVisible) {
310  ui->btnMyAddresses->setRightIconClass("btn-dropdown", true);
311  ui->listViewAddress->setVisible(true);
312  ui->sortWidget->setVisible(true);
313  ui->container_right->removeItem(spacer);
314  ui->listViewAddress->update();
315  } else {
316  ui->btnMyAddresses->setRightIconClass("ic-arrow", true);
317  ui->container_right->addItem(spacer);
318  ui->listViewAddress->setVisible(false);
319  ui->sortWidget->setVisible(false);
320  }
321 }
322 
324 {
325  sortType = (AddressTableModel::ColumnIndex) ui->comboBoxSort->itemData(idx).toInt();
326  sortAddresses();
327 }
328 
330 {
331  sortOrder = (Qt::SortOrder) ui->comboBoxSortOrder->itemData(idx).toInt();
332  sortAddresses();
333 }
334 
335 void ReceiveWidget::filterChanged(const QString& str)
336 {
337  this->filter->setFilterRegExp(str);
338 }
339 
341 {
342  if (this->filter)
343  this->filter->sort(sortType, sortOrder);
344 }
345 
346 void ReceiveWidget::onTransparentSelected(bool transparentSelected)
347 {
348  shieldedMode = !transparentSelected;
349  refreshView();
351 };
352 
353 void ReceiveWidget::changeTheme(bool isLightTheme, QString& theme)
354 {
355  static_cast<AddressHolder*>(this->delegate->getRowFactory())->isLightTheme = isLightTheme;
356 }
357 
359 {
360  delete ui;
361 }
void setTexts(QString title, const char *message=nullptr)
void setData(QString address, QString label)
void setType(const QString &type)
@ TypeRole
Type of address (Send, Receive, ColdStaking, ColdStakingSend, Delegator, Delegable)
@ Address
Bitcoin address.
static const QString ShieldedReceive
Specifies shielded send address.
QString getAddressToShow(bool shielded=false) const
Return last unused address.
static const QString Receive
Specifies receive address.
QString labelForAddress(const QString &address) const
const Optional< T > & getObjResult() const
std::string getError() const
void clicked()
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 showHideOp(bool show)
Definition: pwidget.cpp:40
void changeTheme(bool isLightTheme, QString &theme) override
void refreshView(const QModelIndex &tl, const QModelIndex &br)
QSpacerItem * spacer
Definition: receivewidget.h:61
AddressTableModel::ColumnIndex sortType
Definition: receivewidget.h:67
void updateQr(const QString &address)
void handleAddressClicked(const QModelIndex &index)
bool isShowingDialog
Definition: receivewidget.h:76
AddressFilterProxyModel * filter
Definition: receivewidget.h:59
void onSortOrderChanged(int idx)
void showAddressGenerationDialog(bool isPaymentRequest)
void onTransparentSelected(bool transparentSelected)
SendCoinsRecipient * info
Definition: receivewidget.h:64
ReceiveWidget(PIVXGUI *parent)
Qt::SortOrder sortOrder
Definition: receivewidget.h:68
FurAbstractListItemDelegate * delegate
Definition: receivewidget.h:57
void filterChanged(const QString &str)
void onRequestClicked()
AddressTableModel * addressTableModel
Definition: receivewidget.h:58
void onMyAddressesClicked()
void onSortChanged(int idx)
void onNewAddressClicked()
Ui::ReceiveWidget * ui
Definition: receivewidget.h:55
void loadWalletModel() override
void setWalletModel(WalletModel *model)
void setPaymentRequest(bool _isPaymentRequest)
void Mouse_Pressed()
CallResult< Destination > getNewAddress(const std::string &label="") const
bool updateAddressBookLabels(const CWDestination &address, const std::string &strName, const std::string &strPurpose)
CallResult< Destination > getNewShieldedAddress(std::string strLabel="")
Return a new shielded address.
AddressTableModel * getAddressTableModel()
int64_t getKeyCreationTime(const CPubKey &key)
UnlockContext requestUnlock()
boost::variant< CTxDestination, libzcash::SaplingPaymentAddress > CWDestination
QString dateTimeStr(const QDateTime &date)
Definition: guiutil.cpp:69
QString formatBitcoinURI(const SendCoinsRecipient &info)
Definition: guiutil.cpp:218
void setClipboard(const QString &str)
Definition: guiutil.cpp:670
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 setCssProperty(std::initializer_list< QWidget * > args, const QString &value)
Definition: qtutils.cpp:334
void setCssSubtitleScreen(QWidget *wid)
Definition: qtutils.cpp:329
QPixmap encodeToQr(const QString &str, QString &errorStr, const QColor &qrColor)
Definition: qtutils.cpp:102
void fillAddressSortControls(SortEdit *seType, SortEdit *seOrder, QComboBox *boxType, QComboBox *boxOrder)
Definition: qtutils.cpp:257
#define DECORATION_SIZE
#define NUM_ITEMS
bool error(const char *fmt, const Args &... args)
Definition: system.h:77