PRCYCoin  2.0.0.7rc1
P2P Digital Currency
addresstablemodel.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2014 The Bitcoin developers
2 // Copyright (c) 2014-2015 The Dash developers
3 // Copyright (c) 2015-2018 The PIVX developers
4 // Copyright (c) 2018-2020 The DAPS Project developers
5 // Distributed under the MIT/X11 software license, see the accompanying
6 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
7 
8 #include "addresstablemodel.h"
9 
10 #include "guiutil.h"
11 #include "walletmodel.h"
12 
13 #include "base58.h"
14 #include "wallet/wallet.h"
15 #include "askpassphrasedialog.h"
16 
17 #include <algorithm>
18 
19 #include <QDebug>
20 #include <QFont>
21 
22 const QString AddressTableModel::Send = "S";
23 const QString AddressTableModel::Receive = "R";
24 
26  enum Type {
29  Hidden /* QSortFilterProxyModel will filter these out */
30  };
31 
33  QString label;
34  QString address;
35  QString pubcoin;
36 
39  AddressTableEntry(Type type, const QString& label, const QString& address) : type(type), label(label), address(address) {}
40 };
41 
43  bool operator()(const AddressTableEntry& a, const AddressTableEntry& b) const
44  {
45  return a.address < b.address;
46  }
47  bool operator()(const AddressTableEntry& a, const QString& b) const
48  {
49  return a.address < b;
50  }
51  bool operator()(const QString& a, const AddressTableEntry& b) const
52  {
53  return a < b.address;
54  }
55 };
56 
57 /* Determine address type from address purpose */
58 static AddressTableEntry::Type translateTransactionType(const QString& strPurpose, bool isMine)
59 {
61  // "refund" addresses aren't shown, and change addresses aren't in mapAddressBook at all.
62  if (strPurpose == "send")
63  addressType = AddressTableEntry::Sending;
64  else if (strPurpose == "receive")
65  addressType = AddressTableEntry::Receiving;
66  else if (strPurpose == "unknown" || strPurpose == "") // if purpose not set, guess
68  return addressType;
69 }
70 
71 // Private implementation
73 {
74 public:
76  QList<AddressTableEntry> cachedAddressTable;
78 
80 
82  {
83  cachedAddressTable.clear();
84  {
87  const CBitcoinAddress& address = item.first;
88  bool fMine = IsMine(*wallet, address.Get());
89  AddressTableEntry::Type addressType = translateTransactionType(
90  QString::fromStdString(item.second.purpose), fMine);
91  const std::string& strName = item.second.name;
92  cachedAddressTable.append(AddressTableEntry(addressType,
93  QString::fromStdString(strName),
94  QString::fromStdString(address.ToString())));
95  }
96  }
97  // std::lower_bound() and std::upper_bound() require our cachedAddressTable list to be sorted in asc order
98  // Even though the map is already sorted this re-sorting step is needed because the originating map
99  // is sorted by binary address, not by base58() address.
101  }
102 
103  void updateEntry(const QString& address, const QString& label, bool isMine, const QString& purpose, int status)
104  {
105  // Find address / label in model
106  QList<AddressTableEntry>::iterator lower = std::lower_bound(
108  QList<AddressTableEntry>::iterator upper = std::upper_bound(
110  int lowerIndex = (lower - cachedAddressTable.begin());
111  int upperIndex = (upper - cachedAddressTable.begin());
112  bool inModel = (lower != upper);
113  AddressTableEntry::Type newEntryType = translateTransactionType(purpose, isMine);
114 
115  switch (status) {
116  case CT_NEW:
117  if (inModel) {
118  qWarning() << "AddressTablePriv::updateEntry : Warning: Got CT_NEW, but entry is already in model";
119  break;
120  }
121  parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex);
122  cachedAddressTable.insert(lowerIndex, AddressTableEntry(newEntryType, label, address));
123  parent->endInsertRows();
124  break;
125  case CT_UPDATED:
126  if (!inModel) {
127  qWarning() << "AddressTablePriv::updateEntry : Warning: Got CT_UPDATED, but entry is not in model";
128  break;
129  }
130  lower->type = newEntryType;
131  lower->label = label;
132  parent->emitDataChanged(lowerIndex);
133  break;
134  case CT_DELETED:
135  if (!inModel) {
136  qWarning() << "AddressTablePriv::updateEntry : Warning: Got CT_DELETED, but entry is not in model";
137  break;
138  }
139  parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex - 1);
140  cachedAddressTable.erase(lower, upper);
141  parent->endRemoveRows();
142  break;
143  }
144  }
145 
146  void updateEntry(const QString &pubCoin, const QString &isUsed, int status)
147  {
148  //Do nothing right now, might be changed in the future to have stealth address book
149  }
150 
151 
152  int size()
153  {
154  return cachedAddressTable.size();
155  }
156 
158  {
159  if (idx >= 0 && idx < cachedAddressTable.size()) {
160  return &cachedAddressTable[idx];
161  } else {
162  return 0;
163  }
164  }
165 };
166 
167 AddressTableModel::AddressTableModel(CWallet* wallet, WalletModel* parent) : QAbstractTableModel(parent), walletModel(parent), wallet(wallet), priv(0)
168 {
169  columns << tr("Label") << tr("Address");
170  priv = new AddressTablePriv(wallet, this);
172 }
173 
175 {
176  delete priv;
177 }
178 
179 int AddressTableModel::rowCount(const QModelIndex& parent) const
180 {
181  Q_UNUSED(parent);
182  return priv->size();
183 }
184 
185 int AddressTableModel::columnCount(const QModelIndex& parent) const
186 {
187  Q_UNUSED(parent);
188  return columns.length();
189 }
190 
191 QVariant AddressTableModel::data(const QModelIndex& index, int role) const
192 {
193  if (!index.isValid())
194  return QVariant();
195 
196  AddressTableEntry* rec = static_cast<AddressTableEntry*>(index.internalPointer());
197 
198  if (role == Qt::DisplayRole || role == Qt::EditRole) {
199  switch (index.column()) {
200  case Label:
201  if (rec->label.isEmpty() && role == Qt::DisplayRole) {
202  return tr("(no label)");
203  } else {
204  return rec->label;
205  }
206  case Address:
207  return rec->address;
208  }
209  } else if (role == Qt::FontRole) {
210  QFont font;
211  if (index.column() == Address) {
213  }
214  return font;
215  } else if (role == TypeRole) {
216  switch (rec->type) {
218  return Send;
220  return Receive;
221  default:
222  break;
223  }
224  }
225  return QVariant();
226 }
227 
228 bool AddressTableModel::setData(const QModelIndex& index, const QVariant& value, int role)
229 {
230  if (!index.isValid())
231  return false;
232  AddressTableEntry* rec = static_cast<AddressTableEntry*>(index.internalPointer());
233  std::string strPurpose = (rec->type == AddressTableEntry::Sending ? "send" : "receive");
234  editStatus = OK;
235 
236  if (role == Qt::EditRole) {
237  LOCK(wallet->cs_wallet); /* For SetAddressBook / DelAddressBook */
238  CTxDestination curAddress = CBitcoinAddress(rec->address.toStdString()).Get();
239  if (index.column() == Label) {
240  // Do nothing, if old label == new label
241  if (rec->label == value.toString()) {
243  return false;
244  }
245  wallet->SetAddressBook(curAddress, value.toString().toStdString(), strPurpose);
246  } else if (index.column() == Address) {
247  CTxDestination newAddress = CBitcoinAddress(value.toString().toStdString()).Get();
248  // Refuse to set invalid address, set error status and return false
249  if (boost::get<CNoDestination>(&newAddress)) {
251  return false;
252  }
253  // Do nothing, if old address == new address
254  else if (newAddress == curAddress) {
256  return false;
257  }
258  // Check for duplicate addresses to prevent accidental deletion of addresses, if you try
259  // to paste an existing address over another address (with a different label)
260  else if (wallet->mapAddressBook.count(newAddress)) {
262  return false;
263  }
264  // Double-check that we're not overwriting a receiving address
265  else if (rec->type == AddressTableEntry::Sending) {
266  // Remove old entry
267  wallet->DelAddressBook(curAddress);
268  // Add new entry with new address
269  wallet->SetAddressBook(newAddress, rec->label.toStdString(), strPurpose);
270  }
271  }
272  return true;
273  }
274  return false;
275 }
276 
277 QVariant AddressTableModel::headerData(int section, Qt::Orientation orientation, int role) const
278 {
279  if (orientation == Qt::Horizontal) {
280  if (role == Qt::DisplayRole && section < columns.size()) {
281  return columns[section];
282  }
283  }
284  return QVariant();
285 }
286 
287 Qt::ItemFlags AddressTableModel::flags(const QModelIndex& index) const
288 {
289  if (!index.isValid())
290  return 0;
291  AddressTableEntry* rec = static_cast<AddressTableEntry*>(index.internalPointer());
292 
293  Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
294  // Can edit address and label for sending addresses,
295  // and only label for receiving addresses.
296  if (rec->type == AddressTableEntry::Sending ||
297  (rec->type == AddressTableEntry::Receiving && index.column() == Label)) {
298  retval |= Qt::ItemIsEditable;
299  }
300  return retval;
301 }
302 
303 QModelIndex AddressTableModel::index(int row, int column, const QModelIndex& parent) const
304 {
305  Q_UNUSED(parent);
306  AddressTableEntry* data = priv->index(row);
307  if (data) {
308  return createIndex(row, column, data);
309  } else {
310  return QModelIndex();
311  }
312 }
313 
314 void AddressTableModel::updateEntry(const QString& address,
315  const QString& label,
316  bool isMine,
317  const QString& purpose,
318  int status)
319 {
320  // Update address book model from Prcycoin core
321  priv->updateEntry(address, label, isMine, purpose, status);
322 }
323 
324 
325 void AddressTableModel::updateEntry(const QString &pubCoin, const QString &isUsed, int status)
326 {
327  // Update stealth address book model from Bitcoin core
328  priv->updateEntry(pubCoin, isUsed, status);
329 }
330 
331 
332 
333 QString AddressTableModel::addRow(const QString& type, const QString& label, const QString& address)
334 {
335  std::string strLabel = label.toStdString();
336  std::string strAddress = address.toStdString();
337 
338  editStatus = OK;
339 
340  if (type == Send) {
341  if (!walletModel->validateAddress(address)) {
343  return QString();
344  }
345  // Check for duplicate addresses
346  {
348  if (wallet->mapAddressBook.count(CBitcoinAddress(strAddress).Get())) {
350  return QString();
351  }
352  }
353  } else if (type == Receive) {
354  // Generate a new address to associate with given label
355  CPubKey newKey;
356  if (!wallet->GetKeyFromPool(newKey)) {
358  if (!ctx.isValid()) {
359  // Unlock wallet failed or was cancelled
361  return QString();
362  }
363  if (!wallet->GetKeyFromPool(newKey)) {
365  return QString();
366  }
367  }
368  strAddress = CBitcoinAddress(newKey.GetID()).ToString();
369  } else {
370  return QString();
371  }
372 
373  // Add entry
374  {
376  wallet->SetAddressBook(CBitcoinAddress(strAddress).Get(), strLabel,
377  (type == Send ? "send" : "receive"));
378  }
379  return QString::fromStdString(strAddress);
380 }
381 
382 bool AddressTableModel::removeRows(int row, int count, const QModelIndex& parent)
383 {
384  Q_UNUSED(parent);
385  AddressTableEntry* rec = priv->index(row);
386  if (count != 1 || !rec || rec->type == AddressTableEntry::Receiving) {
387  // Can only remove one row at a time, and cannot remove rows not in model.
388  // Also refuse to remove receiving addresses.
389  return false;
390  }
391  {
393  wallet->DelAddressBook(CBitcoinAddress(rec->address.toStdString()).Get());
394  }
395  return true;
396 }
397 
398 /* Look up label for address in address book, if not found return empty string.
399  */
400 QString AddressTableModel::labelForAddress(const QString& address) const
401 {
402  {
404  CBitcoinAddress address_parsed(address.toStdString());
405  std::map<CTxDestination, CAddressBookData>::iterator mi = wallet->mapAddressBook.find(address_parsed.Get());
406  if (mi != wallet->mapAddressBook.end()) {
407  return QString::fromStdString(mi->second.name);
408  }
409  }
410  return QString();
411 }
412 
413 int AddressTableModel::lookupAddress(const QString& address) const
414 {
415  QModelIndexList lst = match(index(0, Address, QModelIndex()),
416  Qt::EditRole, address, 1, Qt::MatchExactly);
417  if (lst.isEmpty()) {
418  return -1;
419  } else {
420  return lst.at(0).row();
421  }
422 }
423 
425 {
426  Q_EMIT dataChanged(index(idx, 0, QModelIndex()), index(idx, columns.length() - 1, QModelIndex()));
427 }
AddressTableModel::columnCount
int columnCount(const QModelIndex &parent) const
Definition: addresstablemodel.cpp:185
IsMine
isminetype IsMine(const CKeyStore &keystore, const CTxDestination &dest)
Definition: wallet_ismine.cpp:30
GUIUtil::bitcoinAddressFont
QFont bitcoinAddressFont()
Definition: guiutil.cpp:81
AddressTableEntry::Receiving
@ Receiving
Definition: addresstablemodel.cpp:28
AddressTableEntry::AddressTableEntry
AddressTableEntry(Type type, const QString &pubcoin)
Definition: addresstablemodel.cpp:38
AddressTableEntry::Sending
@ Sending
Definition: addresstablemodel.cpp:27
CT_DELETED
@ CT_DELETED
Definition: guiinterface.h:24
WalletModel::UnlockContext::isValid
bool isValid() const
Definition: walletmodel.h:195
AddressTableModel::rowCount
int rowCount(const QModelIndex &parent) const
Definition: addresstablemodel.cpp:179
WalletModel
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:102
b
void const uint64_t * b
Definition: field_5x52_asm_impl.h:10
AddressTableModel::addRow
QString addRow(const QString &type, const QString &label, const QString &address)
Definition: addresstablemodel.cpp:333
AddressTableEntry::label
QString label
Definition: addresstablemodel.cpp:33
walletmodel.h
CWallet::GetKeyFromPool
bool GetKeyFromPool(CPubKey &key)
Definition: wallet.cpp:4829
CBitcoinAddress
base58-encoded PRCY addresses.
Definition: base58.h:109
AddressTableModel
Qt model of the address book in the core.
Definition: addresstablemodel.h:19
AddressTableModel::~AddressTableModel
~AddressTableModel()
Definition: addresstablemodel.cpp:174
AddressTableModel::labelForAddress
QString labelForAddress(const QString &address) const
Definition: addresstablemodel.cpp:400
AddressTableModel::KEY_GENERATION_FAILURE
@ KEY_GENERATION_FAILURE
Generating a new public key for a receiving address failed.
Definition: addresstablemodel.h:43
wallet.h
AddressTableModel::Receive
static const QString Receive
Specifies receive address.
Definition: addresstablemodel.h:47
AddressTableModel::columns
QStringList columns
Definition: addresstablemodel.h:81
AddressTableEntry::address
QString address
Definition: addresstablemodel.cpp:34
AddressTableEntryLessThan
Definition: addresstablemodel.cpp:42
CBase58Data::ToString
std::string ToString() const
Definition: base58.cpp:200
AddressTableEntryLessThan::operator()
bool operator()(const AddressTableEntry &a, const QString &b) const
Definition: addresstablemodel.cpp:47
AddressTableModel::emitDataChanged
void emitDataChanged(int index)
Notify listeners that data changed.
Definition: addresstablemodel.cpp:424
AddressTableModel::headerData
QVariant headerData(int section, Qt::Orientation orientation, int role) const
Definition: addresstablemodel.cpp:277
CWallet::SetAddressBook
bool SetAddressBook(const CTxDestination &address, const std::string &strName, const std::string &purpose)
Definition: wallet.cpp:4589
AddressTableModel::walletModel
WalletModel * walletModel
Definition: addresstablemodel.h:78
AddressTableModel::data
QVariant data(const QModelIndex &index, int role) const
Definition: addresstablemodel.cpp:191
CWallet::DelAddressBook
bool DelAddressBook(const CTxDestination &address)
Definition: wallet.cpp:4609
CT_NEW
@ CT_NEW
Definition: guiinterface.h:22
AddressTableEntryLessThan::operator()
bool operator()(const AddressTableEntry &a, const AddressTableEntry &b) const
Definition: addresstablemodel.cpp:43
WalletModel::validateAddress
bool validateAddress(const QString &address)
Definition: walletmodel.cpp:262
AddressTableModel::priv
AddressTablePriv * priv
Definition: addresstablemodel.h:80
AddressTablePriv::index
AddressTableEntry * index(int idx)
Definition: addresstablemodel.cpp:157
AddressTableModel::index
QModelIndex index(int row, int column, const QModelIndex &parent) const
Definition: addresstablemodel.cpp:303
AddressTableEntry::AddressTableEntry
AddressTableEntry()
Definition: addresstablemodel.cpp:37
AddressTableEntry::pubcoin
QString pubcoin
Definition: addresstablemodel.cpp:35
AddressTableModel::removeRows
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex())
Definition: addresstablemodel.cpp:382
AddressTablePriv::refreshAddressTable
void refreshAddressTable()
Definition: addresstablemodel.cpp:81
CAddressBookData
Address book data.
Definition: wallet.h:148
AddressTableEntry::AddressTableEntry
AddressTableEntry(Type type, const QString &label, const QString &address)
Definition: addresstablemodel.cpp:39
AddressTableModel::wallet
CWallet * wallet
Definition: addresstablemodel.h:79
AskPassphraseDialog::Context::Unlock_Full
@ Unlock_Full
Unlock wallet from menu
PAIRTYPE
#define PAIRTYPE(t1, t2)
This is needed because the foreach macro can't get over the comma in pair<t1, t2>
Definition: utilstrencodings.h:24
guiutil.h
AddressTableEntry::Hidden
@ Hidden
Definition: addresstablemodel.cpp:29
AddressTableModel::Label
@ Label
User specified label.
Definition: addresstablemodel.h:28
AddressTablePriv
Definition: addresstablemodel.cpp:72
AddressTableModel::lookupAddress
int lookupAddress(const QString &address) const
Definition: addresstablemodel.cpp:413
CTxDestination
boost::variant< CNoDestination, CKeyID, CScriptID > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:81
CT_UPDATED
@ CT_UPDATED
Definition: guiinterface.h:23
CAddressBookData::purpose
std::string purpose
Definition: wallet.h:152
AddressTableModel::WALLET_UNLOCK_FAILURE
@ WALLET_UNLOCK_FAILURE
Wallet could not be unlocked to create new receiving address.
Definition: addresstablemodel.h:42
CPubKey
An encapsulated public key.
Definition: pubkey.h:37
AddressTablePriv::AddressTablePriv
AddressTablePriv(CWallet *wallet, AddressTableModel *parent)
Definition: addresstablemodel.cpp:79
AddressTableModel::TypeRole
@ TypeRole
Type of address (Send or Receive)
Definition: addresstablemodel.h:33
WalletModel::UnlockContext
Definition: walletmodel.h:189
AddressTablePriv::cachedAddressTable
QList< AddressTableEntry > cachedAddressTable
Definition: addresstablemodel.cpp:76
AddressTableModel::AddressTableModel
AddressTableModel(CWallet *wallet, WalletModel *parent=0)
Definition: addresstablemodel.cpp:167
AddressTablePriv::wallet
CWallet * wallet
Definition: addresstablemodel.cpp:75
LOCK
#define LOCK(cs)
Definition: sync.h:182
AddressTableEntry
Definition: addresstablemodel.cpp:25
CWallet
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,...
Definition: wallet.h:243
AddressTableModel::INVALID_ADDRESS
@ INVALID_ADDRESS
Unparseable address.
Definition: addresstablemodel.h:40
CWallet::cs_wallet
RecursiveMutex cs_wallet
Definition: wallet.h:301
AddressTableModel::OK
@ OK
Everything ok.
Definition: addresstablemodel.h:38
base58.h
AddressTableModel::NO_CHANGES
@ NO_CHANGES
No changes were made during edit operation.
Definition: addresstablemodel.h:39
AddressTableModel::Send
static const QString Send
Specifies send address.
Definition: addresstablemodel.h:46
AddressTablePriv::updateEntry
void updateEntry(const QString &address, const QString &label, bool isMine, const QString &purpose, int status)
Definition: addresstablemodel.cpp:103
AddressTablePriv::size
int size()
Definition: addresstablemodel.cpp:152
AddressTableModel::flags
Qt::ItemFlags flags(const QModelIndex &index) const
Definition: addresstablemodel.cpp:287
AddressTableModel::updateEntry
void updateEntry(const QString &address, const QString &label, bool isMine, const QString &purpose, int status)
Definition: addresstablemodel.cpp:314
AddressTablePriv::parent
AddressTableModel * parent
Definition: addresstablemodel.cpp:77
AddressTableModel::editStatus
EditStatus editStatus
Definition: addresstablemodel.h:82
AddressTableEntry::type
Type type
Definition: addresstablemodel.cpp:32
CAddressBookData::name
std::string name
Definition: wallet.h:151
CBitcoinAddress::Get
CTxDestination Get() const
Definition: base58.cpp:267
AddressTableEntryLessThan::operator()
bool operator()(const QString &a, const AddressTableEntry &b) const
Definition: addresstablemodel.cpp:51
WalletModel::requestUnlock
UnlockContext requestUnlock(AskPassphraseDialog::Context context, bool relock=false)
Definition: walletmodel.cpp:546
AddressTableModel::DUPLICATE_ADDRESS
@ DUPLICATE_ADDRESS
Address already in address book.
Definition: addresstablemodel.h:41
AddressTableEntry::Type
Type
Definition: addresstablemodel.cpp:26
askpassphrasedialog.h
addresstablemodel.h
AddressTablePriv::updateEntry
void updateEntry(const QString &pubCoin, const QString &isUsed, int status)
Definition: addresstablemodel.cpp:146
AddressTableModel::setData
bool setData(const QModelIndex &index, const QVariant &value, int role)
Definition: addresstablemodel.cpp:228
AddressTableModel::AddressTablePriv
friend class AddressTablePriv
Definition: addresstablemodel.h:92
CWallet::mapAddressBook
std::map< CTxDestination, CAddressBookData > mapAddressBook
Definition: wallet.h:354
AddressTableModel::Address
@ Address
Bitcoin address.
Definition: addresstablemodel.h:29
CPubKey::GetID
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:143