Fabcoin Core  0.16.2
P2P Digital Currency
contracttablemodel.cpp
Go to the documentation of this file.
1 #include <contracttablemodel.h>
2 
3 #include <guiutil.h>
4 #include <walletmodel.h>
5 
6 #include <wallet/wallet.h>
7 
8 #include <QFont>
9 #include <QDebug>
10 #include <utility>
11 
13 {
14  QString label;
15  QString address;
16  QString abi;
17 
19  ContractTableEntry(const QString &_label, const QString &_address, const QString &_abi):
20  label(_label), address(_address), abi(_abi) {}
21 };
22 
24 {
25  bool operator()(const ContractTableEntry &a, const ContractTableEntry &b) const
26  {
27  return a.address < b.address;
28  }
29  bool operator()(const ContractTableEntry &a, const QString &b) const
30  {
31  return a.address < b;
32  }
33  bool operator()(const QString &a, const ContractTableEntry &b) const
34  {
35  return a < b.address;
36  }
37 };
38 
39 // Private implementation
41 {
42 public:
44  QList<ContractTableEntry> cachedContractTable;
46 
48  wallet(_wallet), parent(_parent) {}
49 
51  {
52  cachedContractTable.clear();
53  {
54  LOCK(wallet->cs_wallet);
55  for(const std::pair<std::string, CContractBookData>& item : wallet->mapContractBook)
56  {
57  const std::string& address = item.first;
58  const std::string& strName = item.second.name;
59  const std::string& strAbi = item.second.abi;
60  cachedContractTable.append(ContractTableEntry(
61  QString::fromStdString(strName),
62  QString::fromStdString(address),
63  QString::fromStdString(strAbi)));
64  }
65  }
66  // qLowerBound() and qUpperBound() require our cachedContractTable list to be sorted in asc order
67  qSort(cachedContractTable.begin(), cachedContractTable.end(), ContractTableEntryLessThan());
68  }
69 
70  void updateEntry(const QString &address, const QString &label, const QString &abi, int status)
71  {
72  // Find address / label in model
73  QList<ContractTableEntry>::iterator lower = qLowerBound(
74  cachedContractTable.begin(), cachedContractTable.end(), address, ContractTableEntryLessThan());
75  QList<ContractTableEntry>::iterator upper = qUpperBound(
76  cachedContractTable.begin(), cachedContractTable.end(), address, ContractTableEntryLessThan());
77  int lowerIndex = (lower - cachedContractTable.begin());
78  int upperIndex = (upper - cachedContractTable.begin());
79  bool inModel = (lower != upper);
80 
81  switch(status)
82  {
83  case CT_NEW:
84  if(inModel)
85  {
86  qWarning() << "ContractTablePriv::updateEntry: Warning: Got CT_NEW, but entry is already in model";
87  break;
88  }
89  parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex);
90  cachedContractTable.insert(lowerIndex, ContractTableEntry(label, address, abi));
91  parent->endInsertRows();
92  break;
93  case CT_UPDATED:
94  if(!inModel)
95  {
96  qWarning() << "ContractTablePriv::updateEntry: Warning: Got CT_UPDATED, but entry is not in model";
97  break;
98  }
99  lower->label = label;
100  lower->abi = abi;
101  parent->emitDataChanged(lowerIndex);
102  break;
103  case CT_DELETED:
104  if(!inModel)
105  {
106  qWarning() << "ContractTablePriv::updateEntry: Warning: Got CT_DELETED, but entry is not in model";
107  break;
108  }
109  parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
110  cachedContractTable.erase(lower, upper);
111  parent->endRemoveRows();
112  break;
113  }
114  }
115 
116  int size()
117  {
118  return cachedContractTable.size();
119  }
120 
122  {
123  if(idx >= 0 && idx < cachedContractTable.size())
124  {
125  return &cachedContractTable[idx];
126  }
127  else
128  {
129  return 0;
130  }
131  }
132 };
133 
135  QAbstractTableModel(parent),walletModel(parent),wallet(_wallet),priv(0)
136 {
137  columns << tr("Label") << tr("Contract Address") << tr("Interface (ABI)");
138  priv = new ContractTablePriv(wallet, this);
140 }
141 
143 {
144  delete priv;
145 }
146 
147 int ContractTableModel::rowCount(const QModelIndex &parent) const
148 {
149  Q_UNUSED(parent);
150  return priv->size();
151 }
152 
153 int ContractTableModel::columnCount(const QModelIndex &parent) const
154 {
155  Q_UNUSED(parent);
156  return columns.length();
157 }
158 
159 QVariant ContractTableModel::data(const QModelIndex &index, int role) const
160 {
161  if(!index.isValid())
162  return QVariant();
163 
164  ContractTableEntry *rec = static_cast<ContractTableEntry*>(index.internalPointer());
165 
166  if(role == Qt::DisplayRole || role == Qt::EditRole)
167  {
168  switch(index.column())
169  {
170  case Label:
171  if(rec->label.isEmpty() && role == Qt::DisplayRole)
172  {
173  return tr("(no label)");
174  }
175  else
176  {
177  return rec->label;
178  }
179  case Address:
180  return rec->address;
181  case ABI:
182  return rec->abi;
183  }
184  }
185  else if (role == Qt::FontRole)
186  {
187  QFont font;
188  if(index.column() == Address)
189  {
190  font = GUIUtil::fixedPitchFont();
191  }
192  return font;
193  }
194 
195  return QVariant();
196 }
197 
198 bool ContractTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
199 {
200  if(!index.isValid())
201  return false;
202  ContractTableEntry *rec = static_cast<ContractTableEntry*>(index.internalPointer());
203 
204  if(role == Qt::EditRole)
205  {
206  LOCK(wallet->cs_wallet); /* For SetContractBook / DelContractBook */
207  std::string curAddress = rec->address.toStdString();
208  std::string curLabel = rec->label.toStdString();
209  std::string curAbi = rec->abi.toStdString();
210  if(index.column() == Label)
211  {
212  // Do nothing, if old label == new label
213  if(rec->label == value.toString())
214  {
216  return false;
217  }
218  wallet->SetContractBook(curAddress, value.toString().toStdString(), curAbi);
219  } else if(index.column() == Address) {
220  std::string newAddress = value.toString().toStdString();
221 
222  // Do nothing, if old address == new address
223  if(newAddress == curAddress)
224  {
226  return false;
227  }
228  // Check for duplicate addresses to prevent accidental deletion of addresses, if you try
229  // to paste an existing address over another address (with a different label)
230  else if(wallet->mapContractBook.count(newAddress))
231  {
233  return false;
234  }
235  else
236  {
237  // Remove old entry
238  wallet->DelContractBook(curAddress);
239  // Add new entry with new address
240  wallet->SetContractBook(newAddress, curLabel, curAbi);
241  }
242  }
243  else if(index.column() == ABI) {
244  // Do nothing, if old abi == new abi
245  if(rec->abi == value.toString())
246  {
248  return false;
249  }
250  wallet->SetContractBook(curAddress, curLabel, value.toString().toStdString());
251  }
252  return true;
253  }
254  return false;
255 }
256 
257 QVariant ContractTableModel::headerData(int section, Qt::Orientation orientation, int role) const
258 {
259  if(orientation == Qt::Horizontal)
260  {
261  if(role == Qt::DisplayRole && section < columns.size())
262  {
263  return columns[section];
264  }
265  }
266  return QVariant();
267 }
268 
269 QModelIndex ContractTableModel::index(int row, int column, const QModelIndex &parent) const
270 {
271  Q_UNUSED(parent);
273  if(data)
274  {
275  return createIndex(row, column, priv->index(row));
276  }
277  else
278  {
279  return QModelIndex();
280  }
281 }
282 
284  const QString &label, const QString &abi, int status)
285 {
286  // Update contract book model from Fabcoin core
287  priv->updateEntry(address, label, abi, status);
288 }
289 
290 QString ContractTableModel::addRow(const QString &label, const QString &address, const QString &abi)
291 {
292  // Check for duplicate entry
293  if(lookupAddress(address) != -1)
294  {
296  return "";
297  }
298 
299  // Add new entry
300  std::string strLabel = label.toStdString();
301  std::string strAddress = address.toStdString();
302  std::string strAbi = abi.toStdString();
303  editStatus = OK;
304  {
306  wallet->SetContractBook(strAddress, strLabel, strAbi);
307  }
308  return address;
309 }
310 
311 bool ContractTableModel::removeRows(int row, int count, const QModelIndex &parent)
312 {
313  Q_UNUSED(parent);
314  ContractTableEntry *rec = priv->index(row);
315  if(count != 1 || !rec )
316  {
317  // Can only remove one row at a time, and cannot remove rows not in model.
318  return false;
319  }
320  {
322  wallet->DelContractBook(rec->address.toStdString());
323  }
324  return true;
325 }
326 
327 /* Label for address in contract book, if not found return empty string.
328  */
329 QString ContractTableModel::labelForAddress(const QString &address) const
330 {
331  {
333  std::string address_parsed(address.toStdString());
334  std::map<std::string, CContractBookData>::iterator mi = wallet->mapContractBook.find(address_parsed);
335  if (mi != wallet->mapContractBook.end())
336  {
337  return QString::fromStdString(mi->second.name);
338  }
339  }
340  return QString();
341 }
342 
343 /* ABI for address in contract book, if not found return empty string.
344  */
345 QString ContractTableModel::abiForAddress(const QString &address) const
346 {
347  {
349  std::string address_parsed(address.toStdString());
350  std::map<std::string, CContractBookData>::iterator mi = wallet->mapContractBook.find(address_parsed);
351  if (mi != wallet->mapContractBook.end())
352  {
353  return QString::fromStdString(mi->second.abi);
354  }
355  }
356  return QString();
357 }
358 
360 {
361  QModelIndexList lst = match(index(0, Address, QModelIndex()),
362  Qt::EditRole, address, 1, Qt::MatchExactly);
363  if(lst.isEmpty())
364  {
365  return -1;
366  }
367  else
368  {
369  return lst.at(0).row();
370  }
371 }
372 
374 {
375  editStatus = OK;
376 }
377 
379 {
380  Q_EMIT dataChanged(index(idx, 0, QModelIndex()), index(idx, columns.length()-1, QModelIndex()));
381 }
382 
384 {
385  if(status > editStatus)
386  {
387  editStatus = status;
388  }
389 }
ContractTablePriv(CWallet *_wallet, ContractTableModel *_parent)
QVariant data(const QModelIndex &index, int role) const
bool setData(const QModelIndex &index, const QVariant &value, int role)
int lookupAddress(const QString &address) const
Address already in contract book.
QFont fixedPitchFont()
Definition: guiutil.cpp:90
bool DelContractBook(const std::string &strAddress)
Definition: wallet.cpp:4663
int columnCount(const QModelIndex &parent) const
QString addRow(const QString &label, const QString &address, const QString &abi)
CCriticalSection cs_wallet
Definition: wallet.h:748
bool SetContractBook(const std::string &strAddress, const std::string &strName, const std::string &strAbi)
Definition: wallet.cpp:4644
void emitDataChanged(int index)
Notify listeners that data changed.
size_t count
Definition: ExecStats.cpp:37
void updateEntry(const QString &address, const QString &label, const QString &abi, int status)
bool operator()(const ContractTableEntry &a, const QString &b) const
bool operator()(const ContractTableEntry &a, const ContractTableEntry &b) const
ContractTableEntry()
int rowCount(const QModelIndex &parent) const
No changes were made during edit operation.
QList< ContractTableEntry > cachedContractTable
QString abiForAddress(const QString &address) const
QString address
#define a(i)
ContractTableModel(CWallet *wallet, WalletModel *parent=0)
QVariant headerData(int section, Qt::Orientation orientation, int role) const
QString abi
#define LOCK(cs)
Definition: sync.h:175
QString labelForAddress(const QString &address) const
ContractTablePriv * priv
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex())
void updateEntry(const QString &address, const QString &label, const QString &abi, int status)
bool operator()(const QString &a, const ContractTableEntry &b) const
#define b(i, j)
ContractTableEntry * index(int idx)
QModelIndex index(int row, int column, const QModelIndex &parent) const
Qt model of the contract book in the core.
ContractTableEntry(const QString &_label, const QString &_address, const QString &_abi)
friend class ContractTablePriv
std::map< std::string, CContractBookData > mapContractBook
Definition: wallet.h:828
Interface to Fabcoin wallet from Qt view code.
Definition: walletmodel.h:103
QString label
void updateEditStatus(EditStatus status)
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances...
Definition: wallet.h:672
struct evm_uint160be address(struct evm_env *env)
Definition: capi.c:13
ContractTableModel * parent
User specified label.
EditStatus
Return status of edit/insert operation.