PIVX Core  5.6.99
P2P Digital Currency
addresseswidget.cpp
Go to the documentation of this file.
1 // Copyright (c) 2019-2022 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 "addresseswidget.h"
6 #include "ui_addresseswidget.h"
7 
9 #include "addresslabelrow.h"
10 #include "tooltipmenu.h"
11 #include "addnewcontactdialog.h"
12 #include "guiutil.h"
13 #include "qtutils.h"
14 #include "walletmodel.h"
15 
16 #include <QModelIndex>
17 #include <QRegExpValidator>
18 
19 #define DECORATION_SIZE 60
20 #define NUM_ITEMS 3
21 
22 class ContactsHolder : public FurListRow<QWidget*>
23 {
24 public:
25  explicit ContactsHolder(bool _isLightTheme) : FurListRow(), isLightTheme(_isLightTheme){}
26 
27  AddressLabelRow* createHolder(int pos) override
28  {
29  if (!cachedRow) cachedRow = new AddressLabelRow();
30  cachedRow->init(isLightTheme, false);
31  return cachedRow;
32  }
33 
34  void init(QWidget* holder,const QModelIndex &index, bool isHovered, bool isSelected) const override
35  {
36  AddressLabelRow* row = dynamic_cast<AddressLabelRow*>(holder);
37 
38  row->updateState(isLightTheme, isHovered, isSelected);
39 
40  QString address = index.data(Qt::DisplayRole).toString();
41  if (index.data(AddressTableModel::TypeRole).toString() == AddressTableModel::ShieldedSend) {
42  address = address.left(26) + "..." + address.right(26);
43  }
44  QModelIndex sibling = index.sibling(index.row(), AddressTableModel::Label);
45  QString label = sibling.data(Qt::DisplayRole).toString();
46 
47  row->updateView(address, label);
48  }
49 
50  QColor rectColor(bool isHovered, bool isSelected) override
51  {
52  return getRowColor(isLightTheme, isHovered, isSelected);
53  }
54 
55  ~ContactsHolder() override{}
56 
59 };
60 
61 
63  PWidget(parent),
64  ui(new Ui::AddressesWidget)
65 {
66  ui->setupUi(this);
67 
68  this->setStyleSheet(parent->styleSheet());
69 
73  this
74  );
75 
76  /* Containers */
77  setCssProperty(ui->left, "container");
78  ui->left->setContentsMargins(0,20,0,20);
79  setCssProperty(ui->right, "container-right");
80  ui->right->setContentsMargins(20,10,20,20);
81  setCssProperty(ui->listAddresses, "container");
82 
83  // Title
84  setCssTitleScreen(ui->labelTitle);
85  setCssSubtitleScreen(ui->labelSubtitle1);
86 
87  // Change address option
88  ui->btnAddContact->setTitleClassAndText("btn-title-grey", tr("Add new contact"));
89  ui->btnAddContact->setSubTitleClassAndText("text-subtitle", tr("Generate a new address to receive tokens."));
90  ui->btnAddContact->setRightIconClass("ic-arrow-down");
91 
92  // List Addresses
93  ui->listAddresses->setItemDelegate(delegate);
94  ui->listAddresses->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE));
95  ui->listAddresses->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2));
96  ui->listAddresses->setAttribute(Qt::WA_MacShowFocusRect, false);
97  ui->listAddresses->setSelectionBehavior(QAbstractItemView::SelectRows);
98  ui->listAddresses->setUniformItemSizes(true);
99 
100  // Sort Controls
101  SortEdit* lineEdit = new SortEdit(ui->comboBoxSort);
102  connect(lineEdit, &SortEdit::Mouse_Pressed, [this](){ui->comboBoxSort->showPopup();});
103  connect(ui->comboBoxSort, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &AddressesWidget::onSortChanged);
104  SortEdit* lineEditOrder = new SortEdit(ui->comboBoxSortOrder);
105  connect(lineEditOrder, &SortEdit::Mouse_Pressed, [this](){ui->comboBoxSortOrder->showPopup();});
106  connect(ui->comboBoxSortOrder, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &AddressesWidget::onSortOrderChanged);
107  fillAddressSortControls(lineEdit, lineEditOrder, ui->comboBoxSort, ui->comboBoxSortOrder);
108 
109  //Empty List
110  ui->emptyContainer->setVisible(false);
111  setCssProperty(ui->pushImgEmpty, "img-empty-contacts");
112  setCssProperty(ui->labelEmpty, "text-empty");
113 
114  // Add Contact
115  setCssProperty(ui->layoutNewContact, "container-options");
116 
117  // Name
118  setCssProperty(ui->labelName, "text-title");
119  setCssEditLine(ui->lineEditName, true);
120 
121  // Address
122  setCssProperty(ui->labelAddress, "text-title");
123  setCssEditLine(ui->lineEditAddress, true);
124  ui->lineEditAddress->setValidator(new QRegExpValidator(QRegExp("^[A-Za-z0-9]+"), ui->lineEditName));
125 
126  // Buttons
127  setCssBtnPrimary(ui->btnSave);
128 
129  connect(ui->listAddresses, &QListView::clicked, this, &AddressesWidget::handleAddressClicked);
130  connect(ui->btnSave, &QPushButton::clicked, this, &AddressesWidget::onStoreContactClicked);
132 }
133 
134 void AddressesWidget::handleAddressClicked(const QModelIndex& _index)
135 {
136  ui->listAddresses->setCurrentIndex(_index);
137  QRect rect = ui->listAddresses->visualRect(_index);
138  QPoint pos = rect.topRight();
139  pos.setX(pos.x() - (DECORATION_SIZE * 2));
140  pos.setY(pos.y() + (DECORATION_SIZE));
141 
142  QModelIndex rIndex = filter->mapToSource(_index);
143 
144  if (!this->menu) {
145  this->menu = new TooltipMenu(window, this);
146  connect(this->menu, &TooltipMenu::message, this, &AddressesWidget::message);
150  } else {
151  this->menu->hide();
152  }
153  index = rIndex;
154  menu->move(pos);
155  menu->show();
156 }
157 
159 {
160  if (walletModel) {
162  this->filter = new AddressFilterProxyModel(
164  this);
165  this->filter->setSourceModel(addressTablemodel);
166  this->filter->sort(sortType, sortOrder);
167  ui->listAddresses->setModel(this->filter);
168  ui->listAddresses->setModelColumn(AddressTableModel::Address);
169 
170  updateListView();
171  }
172 }
173 
175 {
176  bool empty = addressTablemodel->sizeSendAll() == 0;
177  ui->emptyContainer->setVisible(empty);
178  ui->listAddresses->setVisible(!empty);
179 }
180 
182 {
183  if (walletModel) {
184  QString label = ui->lineEditName->text();
185  QString address = ui->lineEditAddress->text();
186 
187  bool isStaking = false, isExchange = false, isShield = false;
188  auto pivAdd = Standard::DecodeDestination(address.toUtf8().constData(), isStaking, isExchange, isShield);
189 
190  if (!Standard::IsValidDestination(pivAdd)) {
191  setCssEditLine(ui->lineEditAddress, false, true);
192  inform(tr("Invalid Contact Address"));
193  return;
194  }
195 
196  if (walletModel->isMine(pivAdd)) {
197  setCssEditLine(ui->lineEditAddress, false, true);
198  inform(tr("Cannot store your own address as contact"));
199  return;
200  }
201 
202  QString storedLabel = walletModel->getAddressTableModel()->labelForAddress(address);
203 
204  if (!storedLabel.isEmpty()) {
205  inform(tr("Address already stored, label: %1").arg("\'"+storedLabel+"\'"));
206  return;
207  }
208 
209  bool isShielded = walletModel->IsShieldedDestination(pivAdd);
210  if (walletModel->updateAddressBookLabels(pivAdd, label.toUtf8().constData(),
213  ) {
214  ui->lineEditAddress->setText("");
215  ui->lineEditName->setText("");
216  setCssEditLine(ui->lineEditAddress, true, true);
217  setCssEditLine(ui->lineEditName, true, true);
218 
219  if (ui->emptyContainer->isVisible()) {
220  ui->emptyContainer->setVisible(false);
221  ui->listAddresses->setVisible(true);
222  }
223  inform(tr("New Contact Stored"));
224  } else {
225  inform(tr("Error Storing Contact"));
226  }
227  }
228 }
229 
231 {
232  QString address = index.data(Qt::DisplayRole).toString();
233  QString currentLabel = index.sibling(index.row(), AddressTableModel::Label).data(Qt::DisplayRole).toString();
234  showHideOp(true);
236  dialog->setData(address, currentLabel);
237  if (openDialogWithOpaqueBackground(dialog, window)) {
239  Standard::DecodeDestination(address.toStdString()), dialog->getLabel().toStdString(), addressTablemodel->purposeForAddress(address.toStdString()))){
240  inform(tr("Contact edited"));
241  } else {
242  inform(tr("Contact edit failed"));
243  }
244  }
245  dialog->deleteLater();
246 }
247 
249 {
250  if (walletModel) {
251  if (ask(tr("Delete Contact"),
252  tr("You are just about to remove the contact:\n\n%1\n\nAre you sure?")
253  .arg(index.data(Qt::DisplayRole).toString().toUtf8().constData()))) {
254  if (this->walletModel->getAddressTableModel()->removeRows(index.row(), 1, index)) {
255  updateListView();
256  inform(tr("Contact Deleted"));
257  } else {
258  inform(tr("Error deleting a contact"));
259  }
260  }
261  }
262 }
263 
265 {
266  GUIUtil::setClipboard(index.data(Qt::DisplayRole).toString());
267  inform(tr("Address copied"));
268 }
269 
271 {
272  if (!ui->layoutNewContact->isVisible()){
273  ui->btnAddContact->setRightIconClass("btn-dropdown", true);
274  ui->layoutNewContact->setVisible(true);
275  } else {
276  ui->btnAddContact->setRightIconClass("ic-arrow", true);
277  ui->layoutNewContact->setVisible(false);
278  }
279 }
280 
282 {
283  sortType = (AddressTableModel::ColumnIndex) ui->comboBoxSort->itemData(idx).toInt();
284  sortAddresses();
285 }
286 
288 {
289  sortOrder = (Qt::SortOrder) ui->comboBoxSortOrder->itemData(idx).toInt();
290  sortAddresses();
291 }
292 
294 {
295  if (this->filter)
296  this->filter->sort(sortType, sortOrder);
297 }
298 
299 void AddressesWidget::changeTheme(bool isLightTheme, QString& theme)
300 {
301  dynamic_cast<ContactsHolder*>(this->delegate->getRowFactory())->isLightTheme = isLightTheme;
302 }
303 
305 {
306  delete ui;
307 }
#define DECORATION_SIZE
#define NUM_ITEMS
void setData(QString address, QString label)
void updateState(bool isLightTheme, bool isHovered, bool isSelected)
void init(bool isLightTheme, bool isHover)
void updateView(const QString &address, const QString &label)
@ TypeRole
Type of address (Send, Receive, ColdStaking, ColdStakingSend, Delegator, Delegable)
static const QString ColdStakingSend
Specifies send cold staking addresses (simil 'contacts')
static const QString ShieldedSend
Specifies shielded receive address.
@ Address
Bitcoin address.
@ Label
User specified label.
std::string purposeForAddress(const std::string &address) const
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex())
static const QString Send
Specifies send address.
QString labelForAddress(const QString &address) const
AddressTableModel::ColumnIndex sortType
void onAddContactShowHideClicked()
FurAbstractListItemDelegate * delegate
AddressesWidget(PIVXGUI *parent)
AddressFilterProxyModel * filter
void loadWalletModel() override
void handleAddressClicked(const QModelIndex &index)
void onSortChanged(int idx)
void changeTheme(bool isLightTheme, QString &theme) override
void onSortOrderChanged(int idx)
AddressTableModel * addressTablemodel
QModelIndex index
Ui::AddressesWidget * ui
Qt::SortOrder sortOrder
TooltipMenu * menu
ContactsHolder(bool _isLightTheme)
~ContactsHolder() override
AddressLabelRow * createHolder(int pos) override
AddressLabelRow * cachedRow
QColor rectColor(bool isHovered, bool isSelected) override
void init(QWidget *holder, const QModelIndex &index, bool isHovered, bool isSelected) const override
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 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 Mouse_Pressed()
void onDeleteClicked()
void onEditClicked()
void onCopyClicked()
bool isMine(const CWDestination &address)
bool updateAddressBookLabels(const CWDestination &address, const std::string &strName, const std::string &strPurpose)
AddressTableModel * getAddressTableModel()
bool IsShieldedDestination(const CWDestination &address)
const std::string COLD_STAKING_SEND
Definition: addressbook.cpp:16
const std::string SHIELDED_SEND
Definition: addressbook.cpp:18
void setClipboard(const QString &str)
Definition: guiutil.cpp:670
bool IsValidDestination(const CWDestination &address)
CWDestination DecodeDestination(const std::string &strAddress)
bool isLightTheme()
Definition: qtutils.cpp:210
void setCssTitleScreen(QLabel *label)
Definition: qtutils.cpp:324
bool openDialogWithOpaqueBackground(QDialog *widget, PIVXGUI *gui, double posX)
Definition: qtutils.cpp:76
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 setCssEditLine(QLineEdit *edit, bool isValid, bool forceUpdate)
Definition: qtutils.cpp:282
void fillAddressSortControls(SortEdit *seType, SortEdit *seOrder, QComboBox *boxType, QComboBox *boxOrder)
Definition: qtutils.cpp:257