Master Core  v0.0.9 - 2abfd2849db8ba7a83957c64eb976b406713c123
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
transactiontablemodel.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2014 The Bitcoin developers
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
6 
7 #include "addresstablemodel.h"
8 #include "bitcoinunits.h"
9 #include "guiconstants.h"
10 #include "guiutil.h"
11 #include "optionsmodel.h"
12 #include "transactiondesc.h"
13 #include "transactionrecord.h"
14 #include "walletmodel.h"
15 
16 #include "main.h"
17 #include "sync.h"
18 #include "uint256.h"
19 #include "util.h"
20 #include "wallet.h"
21 
22 #include <boost/filesystem.hpp>
23 
24 #include "leveldb/db.h"
25 #include "leveldb/write_batch.h"
26 
27 // potentially overzealous includes here
28 #include "base58.h"
29 #include "rpcserver.h"
30 #include "init.h"
31 #include "util.h"
32 #include <fstream>
33 #include <algorithm>
34 #include <vector>
35 #include <utility>
36 #include <string>
37 #include <boost/assign/list_of.hpp>
38 #include <boost/algorithm/string.hpp>
39 #include <boost/algorithm/string/find.hpp>
40 #include <boost/algorithm/string/join.hpp>
41 #include <boost/lexical_cast.hpp>
42 #include <boost/format.hpp>
43 #include <boost/filesystem.hpp>
44 #include "json/json_spirit_utils.h"
45 #include "json/json_spirit_value.h"
46 #include "leveldb/db.h"
47 #include "leveldb/write_batch.h"
48 // end potentially overzealous includes
49 using namespace json_spirit; // since now using Array in mastercore.h this needs to come first
50 
51 #include "mastercore.h"
52 using namespace mastercore;
53 
54 // potentially overzealous using here
55 using namespace std;
56 using namespace boost;
57 using namespace boost::assign;
58 using namespace leveldb;
59 // end potentially overzealous using
60 
61 #include "mastercore_dex.h"
62 #include "mastercore_tx.h"
63 #include "mastercore_sp.h"
64 
65 #include <QColor>
66 #include <QDateTime>
67 #include <QDebug>
68 #include <QIcon>
69 #include <QList>
70 
71 extern CWallet* pwalletMain;
72 
73 // Amount column is right-aligned it contains numbers
74 static int column_alignments[] = {
75  Qt::AlignLeft|Qt::AlignVCenter, /* status */
76  Qt::AlignLeft|Qt::AlignVCenter, /* date */
77  Qt::AlignLeft|Qt::AlignVCenter, /* type */
78  Qt::AlignLeft|Qt::AlignVCenter, /* address */
79  Qt::AlignRight|Qt::AlignVCenter /* amount */
80  };
81 
82 // Comparison operator for sort/binary search of model tx list
83 struct TxLessThan
84 {
85  bool operator()(const TransactionRecord &a, const TransactionRecord &b) const
86  {
87  return a.hash < b.hash;
88  }
89  bool operator()(const TransactionRecord &a, const uint256 &b) const
90  {
91  return a.hash < b;
92  }
93  bool operator()(const uint256 &a, const TransactionRecord &b) const
94  {
95  return a < b.hash;
96  }
97 };
98 
99 // Private implementation
101 {
102 public:
104  wallet(wallet),
105  parent(parent)
106  {
107  }
108 
111 
112  /* Local cache of wallet.
113  * As it is in the same order as the CWallet, by definition
114  * this is sorted by sha256.
115  */
116  QList<TransactionRecord> cachedWallet;
117 
118  /* Query entire wallet anew from core.
119  */
121  {
122  qDebug() << "TransactionTablePriv::refreshWallet";
123  cachedWallet.clear();
124  {
125  LOCK2(cs_main, wallet->cs_wallet);
126  for(std::map<uint256, CWalletTx>::iterator it = wallet->mapWallet.begin(); it != wallet->mapWallet.end(); ++it)
127  {
128  if(TransactionRecord::showTransaction(it->second))
129  cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, it->second));
130  }
131  }
132  }
133 
134  /* Update our model of the wallet incrementally, to synchronize our model of the wallet
135  with that of the core.
136 
137  Call with transaction that was added, removed or changed.
138  */
139  void updateWallet(const uint256 &hash, int status)
140  {
141  qDebug() << "TransactionTablePriv::updateWallet : " + QString::fromStdString(hash.ToString()) + " " + QString::number(status);
142  {
143  LOCK2(cs_main, wallet->cs_wallet);
144 
145  // Find transaction in wallet
146  std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(hash);
147  bool inWallet = mi != wallet->mapWallet.end();
148 
149  // Find bounds of this transaction in model
150  QList<TransactionRecord>::iterator lower = qLowerBound(
151  cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
152  QList<TransactionRecord>::iterator upper = qUpperBound(
153  cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
154  int lowerIndex = (lower - cachedWallet.begin());
155  int upperIndex = (upper - cachedWallet.begin());
156  bool inModel = (lower != upper);
157 
158  // Determine whether to show transaction or not
159  bool showTransaction = (inWallet && TransactionRecord::showTransaction(mi->second));
160 
161  if(status == CT_UPDATED)
162  {
163  if(showTransaction && !inModel)
164  status = CT_NEW; /* Not in model, but want to show, treat as new */
165  if(!showTransaction && inModel)
166  status = CT_DELETED; /* In model, but want to hide, treat as deleted */
167  }
168 
169  qDebug() << " inWallet=" + QString::number(inWallet) + " inModel=" + QString::number(inModel) +
170  " Index=" + QString::number(lowerIndex) + "-" + QString::number(upperIndex) +
171  " showTransaction=" + QString::number(showTransaction) + " derivedStatus=" + QString::number(status);
172 
173  switch(status)
174  {
175  case CT_NEW:
176  if(inModel)
177  {
178  qDebug() << "TransactionTablePriv::updateWallet : Warning: Got CT_NEW, but transaction is already in model";
179  break;
180  }
181  if(!inWallet)
182  {
183  qDebug() << "TransactionTablePriv::updateWallet : Warning: Got CT_NEW, but transaction is not in wallet";
184  break;
185  }
186  if(showTransaction)
187  {
188  // Added -- insert at the right position
189  QList<TransactionRecord> toInsert =
190  TransactionRecord::decomposeTransaction(wallet, mi->second);
191  if(!toInsert.isEmpty()) /* only if something to insert */
192  {
193  parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex+toInsert.size()-1);
194  int insert_idx = lowerIndex;
195  foreach(const TransactionRecord &rec, toInsert)
196  {
197  cachedWallet.insert(insert_idx, rec);
198  insert_idx += 1;
199  }
200  parent->endInsertRows();
201  }
202  }
203  break;
204  case CT_DELETED:
205  if(!inModel)
206  {
207  qDebug() << "TransactionTablePriv::updateWallet : Warning: Got CT_DELETED, but transaction is not in model";
208  break;
209  }
210  // Removed -- remove entire transaction from table
211  parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
212  cachedWallet.erase(lower, upper);
213  parent->endRemoveRows();
214  break;
215  case CT_UPDATED:
216  // Miscellaneous updates -- nothing to do, status update will take care of this, and is only computed for
217  // visible transactions.
218  break;
219  }
220  }
221  }
222 
223  int size()
224  {
225  return cachedWallet.size();
226  }
227 
229  {
230  if(idx >= 0 && idx < cachedWallet.size())
231  {
232  TransactionRecord *rec = &cachedWallet[idx];
233 
234  // Get required locks upfront. This avoids the GUI from getting
235  // stuck if the core is holding the locks for a longer time - for
236  // example, during a wallet rescan.
237  //
238  // If a status update is needed (blocks came in since last check),
239  // update the status of this transaction from the wallet. Otherwise,
240  // simply re-use the cached status.
241  TRY_LOCK(cs_main, lockMain);
242  if(lockMain)
243  {
244  TRY_LOCK(wallet->cs_wallet, lockWallet);
245  if(lockWallet && rec->statusUpdateNeeded())
246  {
247  std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash);
248 
249  if(mi != wallet->mapWallet.end())
250  {
251  rec->updateStatus(mi->second);
252  }
253  }
254  }
255  return rec;
256  }
257  else
258  {
259  return 0;
260  }
261  }
262 
263  QString describe(TransactionRecord *rec, int unit)
264  {
265  {
266  LOCK2(cs_main, wallet->cs_wallet);
267  std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash);
268  if(mi != wallet->mapWallet.end())
269  {
270  return TransactionDesc::toHTML(wallet, mi->second, rec->idx, unit);
271  }
272  }
273  return QString("");
274  }
275 };
276 
278  QAbstractTableModel(parent),
279  wallet(wallet),
280  walletModel(parent),
281  priv(new TransactionTablePriv(wallet, this))
282 {
283  columns << QString() << tr("Date") << tr("Type") << tr("Address") << tr("Amount");
284 
285  priv->refreshWallet();
286 
287  connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
288 }
289 
291 {
292  delete priv;
293 }
294 
295 void TransactionTableModel::updateTransaction(const QString &hash, int status)
296 {
297  uint256 updated;
298  updated.SetHex(hash.toStdString());
299 
300  priv->updateWallet(updated, status);
301 }
302 
304 {
305  // Blocks came in since last poll.
306  // Invalidate status (number of confirmations) and (possibly) description
307  // for all rows. Qt is smart enough to only actually request the data for the
308  // visible rows.
309  emit dataChanged(index(0, Status), index(priv->size()-1, Status));
310  emit dataChanged(index(0, ToAddress), index(priv->size()-1, ToAddress));
311 }
312 
313 int TransactionTableModel::rowCount(const QModelIndex &parent) const
314 {
315  Q_UNUSED(parent);
316  return priv->size();
317 }
318 
319 int TransactionTableModel::columnCount(const QModelIndex &parent) const
320 {
321  Q_UNUSED(parent);
322  return columns.length();
323 }
324 
326 {
327  QString status;
328 
329  switch(wtx->status.status)
330  {
332  status = tr("Open for %n more block(s)","",wtx->status.open_for);
333  break;
335  status = tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx->status.open_for));
336  break;
338  status = tr("Offline");
339  break;
341  status = tr("Unconfirmed");
342  break;
344  status = tr("Confirming (%1 of %2 recommended confirmations)").arg(wtx->status.depth).arg(TransactionRecord::RecommendedNumConfirmations);
345  break;
347  status = tr("Confirmed (%1 confirmations)").arg(wtx->status.depth);
348  break;
350  status = tr("Conflicted");
351  break;
353  status = tr("Immature (%1 confirmations, will be available after %2)").arg(wtx->status.depth).arg(wtx->status.depth + wtx->status.matures_in);
354  break;
356  status = tr("This block was not received by any other nodes and will probably not be accepted!");
357  break;
359  status = tr("Generated but not accepted");
360  break;
361  }
362 
363  return status;
364 }
365 
367 {
368  if(wtx->time)
369  {
370  return GUIUtil::dateTimeStr(wtx->time);
371  }
372  else
373  {
374  return QString();
375  }
376 }
377 
378 /* Look up address in address book, if found return label (address)
379  otherwise just return (address)
380  */
381 QString TransactionTableModel::lookupAddress(const std::string &address, bool tooltip) const
382 {
383  QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(address));
384  QString description;
385  if(!label.isEmpty())
386  {
387  description += label + QString(" ");
388  }
389  if(label.isEmpty() || walletModel->getOptionsModel()->getDisplayAddresses() || tooltip)
390  {
391  description += QString("(") + QString::fromStdString(address) + QString(")");
392  }
393  return description;
394 }
395 
397 {
398  switch(wtx->type)
399  {
401  return tr("Received with");
403  return tr("Received from");
406  return tr("Sent to");
408  return tr("Payment to yourself");
410  return tr("Mined");
411  default:
412  return QString();
413  }
414 }
415 
417 {
418  switch(wtx->type)
419  {
421  return QIcon(":/icons/tx_mined");
424  return QIcon(":/icons/tx_input");
427  return QIcon(":/icons/tx_output");
428  default:
429  return QIcon(":/icons/tx_inout");
430  }
431  return QVariant();
432 }
433 
434 QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const
435 {
436  switch(wtx->type)
437  {
439  return QString::fromStdString(wtx->address);
443  return lookupAddress(wtx->address, tooltip);
445  return QString::fromStdString(wtx->address);
447  default:
448  return tr("(n/a)");
449  }
450 }
451 
453 {
454  // Show addresses without label in a less visible color
455  switch(wtx->type)
456  {
460  {
461  QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(wtx->address));
462  if(label.isEmpty())
463  return COLOR_BAREADDRESS;
464  } break;
466  return COLOR_BAREADDRESS;
467  default:
468  break;
469  }
470  return QVariant();
471 }
472 
473 QString TransactionTableModel::formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed) const
474 {
476  if(showUnconfirmed)
477  {
478  if(!wtx->status.countsForBalance)
479  {
480  str = QString("[") + str + QString("]");
481  }
482  }
483  return QString(str);
484 }
485 
487 {
488  switch(wtx->status.status)
489  {
492  return QColor(64,64,255);
494  return QColor(192,192,192);
496  return QIcon(":/icons/transaction_0");
498  switch(wtx->status.depth)
499  {
500  case 1: return QIcon(":/icons/transaction_1");
501  case 2: return QIcon(":/icons/transaction_2");
502  case 3: return QIcon(":/icons/transaction_3");
503  case 4: return QIcon(":/icons/transaction_4");
504  default: return QIcon(":/icons/transaction_5");
505  };
507  return QIcon(":/icons/transaction_confirmed");
509  return QIcon(":/icons/transaction_conflicted");
511  int total = wtx->status.depth + wtx->status.matures_in;
512  int part = (wtx->status.depth * 4 / total) + 1;
513  return QIcon(QString(":/icons/transaction_%1").arg(part));
514  }
517  return QIcon(":/icons/transaction_0");
518  }
519  return QColor(0,0,0);
520 }
521 
523 {
524  QString tooltip = formatTxStatus(rec) + QString("\n") + formatTxType(rec);
527  {
528  tooltip += QString(" ") + formatTxToAddress(rec, true);
529  }
530  return tooltip;
531 }
532 
533 QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
534 {
535  if(!index.isValid())
536  return QVariant();
537  TransactionRecord *rec = static_cast<TransactionRecord*>(index.internalPointer());
538 
539  switch(role)
540  {
541  case Qt::DecorationRole:
542  switch(index.column())
543  {
544  case Status:
545  return txStatusDecoration(rec);
546  case ToAddress:
547  return txAddressDecoration(rec);
548  }
549  break;
550  case Qt::DisplayRole:
551  switch(index.column())
552  {
553  case Date:
554  return formatTxDate(rec);
555  case Type:
556  return formatTxType(rec);
557  case ToAddress:
558  return formatTxToAddress(rec, false);
559  case Amount:
560  return formatTxAmount(rec);
561  }
562  break;
563  case Qt::EditRole:
564  // Edit role is used for sorting, so return the unformatted values
565  switch(index.column())
566  {
567  case Status:
568  return QString::fromStdString(rec->status.sortKey);
569  case Date:
570  return rec->time;
571  case Type:
572  return formatTxType(rec);
573  case ToAddress:
574  return formatTxToAddress(rec, true);
575  case Amount:
576  return rec->credit + rec->debit;
577  }
578  break;
579  case Qt::ToolTipRole:
580  return formatTooltip(rec);
581  case Qt::TextAlignmentRole:
582  return column_alignments[index.column()];
583  case Qt::ForegroundRole:
584  // Non-confirmed (but not immature) as transactions are grey
586  {
587  return COLOR_UNCONFIRMED;
588  }
589  if(index.column() == Amount && (rec->credit+rec->debit) < 0)
590  {
591  return COLOR_NEGATIVE;
592  }
593  if(index.column() == ToAddress)
594  {
595  return addressColor(rec);
596  }
597  break;
598  case TypeRole:
599  return rec->type;
600  case DateRole:
601  return QDateTime::fromTime_t(static_cast<uint>(rec->time));
602  case LongDescriptionRole:
604  case AddressRole:
605  return QString::fromStdString(rec->address);
606  case LabelRole:
607  return walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(rec->address));
608  case AmountRole:
609  return rec->credit + rec->debit;
610  case TxIDRole:
611  return rec->getTxID();
612  case TxHashRole:
613  return QString::fromStdString(rec->hash.ToString());
614  case ConfirmedRole:
615  return rec->status.countsForBalance;
616  case FormattedAmountRole:
617  return formatTxAmount(rec, false);
618  case StatusRole:
619  return rec->status.status;
620  }
621  return QVariant();
622 }
623 
624 QVariant TransactionTableModel::headerData(int section, Qt::Orientation orientation, int role) const
625 {
626  if(orientation == Qt::Horizontal)
627  {
628  if(role == Qt::DisplayRole)
629  {
630  return columns[section];
631  }
632  else if (role == Qt::TextAlignmentRole)
633  {
634  return column_alignments[section];
635  } else if (role == Qt::ToolTipRole)
636  {
637  switch(section)
638  {
639  case Status:
640  return tr("Transaction status. Hover over this field to show number of confirmations.");
641  case Date:
642  return tr("Date and time that the transaction was received.");
643  case Type:
644  return tr("Type of transaction.");
645  case ToAddress:
646  return tr("Destination address of transaction.");
647  case Amount:
648  return tr("Amount removed from or added to balance.");
649  }
650  }
651  }
652  return QVariant();
653 }
654 
655 QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex &parent) const
656 {
657  Q_UNUSED(parent);
658  TransactionRecord *data = priv->index(row);
659  if(data)
660  {
661  return createIndex(row, column, priv->index(row));
662  }
663  else
664  {
665  return QModelIndex();
666  }
667 }
668 
670 {
671  // emit dataChanged to update Amount column with the current unit
672  emit dataChanged(index(0, Amount), index(priv->size()-1, Amount));
673 }
674 
675 
677 // Private implementation
679 {
680 public:
682  QList<msc_AddressTableEntry> msc_cachedAddressTable;
684 
686  wallet(wallet), parent(parent) {}
687 
689  {
690  int my_count = 0;
691 
692  qDebug() << "msc_AddressTablePriv::refreshAddressTable()";
693  qDebug() << __FUNCTION__ << __LINE__ << __FILE__;
694  msc_cachedAddressTable.clear();
695  {
696  LOCK(wallet->cs_wallet);
697  BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, wallet->mapAddressBook)
698  {
699  const CBitcoinAddress& address = item.first;
700 // bool fMine = IsMine(*wallet, address.Get());
701  ++my_count;
702  const std::string& strName = item.second.name;
703  msc_cachedAddressTable.append(msc_AddressTableEntry(
704  QString::fromStdString(strName),
705  QString::fromStdString(address.ToString())));
706  }
707 
708  qDebug() << __FUNCTION__ << " found " << my_count << " entries for the cachedAddressTable !!!";
709  }
710  // qLowerBound() and qUpperBound() require our cachedAddressTable list to be sorted in asc order
711  // Even though the map is already sorted this re-sorting step is needed because the originating map
712  // is sorted by binary address, not by base58() address.
713  qSort(msc_cachedAddressTable.begin(), msc_cachedAddressTable.end(), msc_AddressTableEntryLessThan());
714  }
715 
716  void updateEntry(const QString &address, const QString &label, bool isMine, const QString &purpose, int status)
717  {
718  qDebug() << "msc_AddressTablePriv::updateEntry()";
719 
720  // Find address / label in model
721  QList<msc_AddressTableEntry>::iterator lower = qLowerBound(
722  msc_cachedAddressTable.begin(), msc_cachedAddressTable.end(), address, msc_AddressTableEntryLessThan());
723  QList<msc_AddressTableEntry>::iterator upper = qUpperBound(
724  msc_cachedAddressTable.begin(), msc_cachedAddressTable.end(), address, msc_AddressTableEntryLessThan());
725  int lowerIndex = (lower - msc_cachedAddressTable.begin());
726  int upperIndex = (upper - msc_cachedAddressTable.begin());
727  bool inModel = (lower != upper);
728 
729  switch(status)
730  {
731  case CT_NEW:
732  if(inModel)
733  {
734  qDebug() << "msc_AddressTablePriv::updateEntry : Warning: Got CT_NOW, but entry is already in model";
735  break;
736  }
737  parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex);
738  msc_cachedAddressTable.insert(lowerIndex, msc_AddressTableEntry(label, address));
739  parent->endInsertRows();
740  break;
741  case CT_UPDATED:
742  if(!inModel)
743  {
744  qDebug() << "msc_AddressTablePriv::updateEntry : Warning: Got CT_UPDATED, but entry is not in model";
745  break;
746  }
747  lower->label = label;
748  parent->emitDataChanged(lowerIndex);
749  break;
750  case CT_DELETED:
751  if(!inModel)
752  {
753  qDebug() << "msc_AddressTablePriv::updateEntry : Warning: Got CT_DELETED, but entry is not in model";
754  break;
755  }
756  parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
757  msc_cachedAddressTable.erase(lower, upper);
758  parent->endRemoveRows();
759  break;
760  }
761  }
762 
763  int size()
764  {
765  return msc_cachedAddressTable.size();
766  }
767 
769  {
770  if(idx >= 0 && idx < msc_cachedAddressTable.size())
771  {
772  return &msc_cachedAddressTable[idx];
773  }
774  else
775  {
776  return 0;
777  }
778  }
779 };
780 
781 // Return the data to which index points.
782 QVariant MatrixModel::data(const QModelIndex& index, int role) const
783 {
784  if (!index.isValid() || role != Qt::DisplayRole)
785  return QVariant();
786 
787 // qDebug() << __FUNCTION__ << "row=" << index.row() << "column=" << index.column();
788 
789  switch(index.column())
790  {
791  case 0: return (ql_lab[index.row()]);
792  case 1: return (ql_addr[index.row()]);
793  case 2: return (ql_res[index.row()]);
794  case 3: return (ql_avl[index.row()]);
795  default:
796 // return m_data[index.row() * m_numColumns + index.column()];
797  return QString("*NONE*");
798  }
799 }
800 
802 {
803 }
804 
805 
806 
808  : m_numRows(3),
809  m_numColumns(5)
810  {
811  qDebug() << "CONSTRUCTOR-wallet" << __FILE__ << __FUNCTION__ << __LINE__;
812  priv = new msc_AddressTablePriv(wallet, this);
814  }
815 
816  MatrixModel::MatrixModel(int numRows, int numColumns, uint* data, unsigned int propertyId)
817  : m_numRows(numRows),
818  m_numColumns(numColumns),
819  m_data(data)
820  {
821  qDebug() << "CONSTRUCTOR-Mastercoin" << __FILE__ << __FUNCTION__ << __LINE__;
822  if(propertyId==2147483646)
823  {
824  columns << tr("Property ID") << tr("Name") << tr("Reserved") << tr("Available");
825  }
826  else
827  {
828  columns << tr("Label") << tr("Address") << tr("Reserved") << tr("Available");
829  }
830 
831  m_numRows=fillin(propertyId);
832  m_numColumns=4;
833 
834  qDebug() << "numRows=" << m_numRows << "numColumns=" << m_numColumns;
835  }
836 
838 {
839  qDebug() << "DESTRUCTOR" << __FILE__ << __FUNCTION__ << __LINE__;
840  // QList is a RAII container and automatically frees all resources upon destruction
841 }
842 
843  int MatrixModel::rowCount(const QModelIndex& parent) const
844  {
845  return m_numRows;
846  }
847 
848  int MatrixModel::columnCount(const QModelIndex& parent) const
849  {
850  return m_numColumns;
851  }
852 
854 {
855  emit dataChanged(index(idx, 0, QModelIndex()), index(idx, columns.length()-1, QModelIndex()));
856 }
857 
858 QVariant MatrixModel::headerData(int section, Qt::Orientation orientation, int role) const
859 {
860  if(orientation == Qt::Horizontal)
861  {
862  if(role == Qt::DisplayRole && section < columns.size())
863  {
864  return columns[section];
865  }
866  }
867 
868  if(orientation == Qt::Vertical)
869  {
870  if(role == Qt::DisplayRole)
871  {
872  return 1+section;
873  }
874  }
875 
876  return QVariant();
877 }
878 
879 int MatrixModel::fillin(unsigned int propertyId)
880 {
881  int count = 0;
882  //are we summary?
883  if(propertyId==2147483646)
884  {
886  for (unsigned int propertyId = 1; propertyId<100000; propertyId++)
887  {
888  if ((global_balance_money_maineco[propertyId] > 0) || (global_balance_reserved_maineco[propertyId] > 0))
889  {
890  string spName;
891  spName = getPropertyName(propertyId).c_str();
892  string spId = static_cast<ostringstream*>( &(ostringstream() << propertyId) )->str();
893  ql_lab.append(spId.c_str());
894  ql_addr.append(spName.c_str());
895  int64_t available = global_balance_money_maineco[propertyId];
896  int64_t reserved = global_balance_reserved_maineco[propertyId];
897  bool divisible = isPropertyDivisible(propertyId);
898  if (divisible)
899  {
900  ql_avl.append(QString::fromStdString(FormatDivisibleMP(available)));
901  ql_res.append(QString::fromStdString(FormatDivisibleMP(reserved)));
902  }
903  else
904  {
905  ql_avl.append(QString::fromStdString(FormatIndivisibleMP(available)));
906  ql_res.append(QString::fromStdString(FormatIndivisibleMP(reserved)));
907  }
908  ++count;
909  }
910  }
911  for (unsigned int propertyId = 1; propertyId<100000; propertyId++)
912  {
913  if ((global_balance_money_testeco[propertyId] > 0) || (global_balance_reserved_testeco[propertyId] > 0))
914  {
915  string spName;
916  spName = getPropertyName(propertyId+2147483647).c_str();
917  string spId = static_cast<ostringstream*>( &(ostringstream() << propertyId+2147483647) )->str();
918  ql_lab.append(spId.c_str());
919  ql_addr.append(spName.c_str());
920  int64_t available = global_balance_money_testeco[propertyId];
921  int64_t reserved = global_balance_reserved_testeco[propertyId];
922  bool divisible = isPropertyDivisible(propertyId+2147483647);
923  if (divisible)
924  {
925  ql_avl.append(QString::fromStdString(FormatDivisibleMP(available)));
926  ql_res.append(QString::fromStdString(FormatDivisibleMP(reserved)));
927  }
928  else
929  {
930  ql_avl.append(QString::fromStdString(FormatIndivisibleMP(available)));
931  ql_res.append(QString::fromStdString(FormatIndivisibleMP(reserved)));
932  }
933  ++count;
934  }
935  }
936  }
937  else
938  {
939  LOCK(cs_tally);
940  bool divisible = isPropertyDivisible(propertyId);
941  for(map<string, CMPTally>::iterator my_it = mp_tally_map.begin(); my_it != mp_tally_map.end(); ++my_it)
942  {
943  string address = (my_it->first).c_str();
944  unsigned int id;
945  bool includeAddress=false;
946  (my_it->second).init();
947  while (0 != (id = (my_it->second).next()))
948  {
949  if(id==propertyId) { includeAddress=true; break; }
950  }
951  if (!includeAddress) continue; //ignore this address, has never transacted in this propertyId
952  if (!IsMyAddress(address)) continue; //ignore this address, it's not ours
953 
954  //int64_t available = getMPbalance(address, propertyId, MONEY);
955  int64_t available = getUserAvailableMPbalance(address, propertyId);
956  int64_t reserved = getMPbalance(address, propertyId, SELLOFFER_RESERVE);
957  if (propertyId<3) reserved += getMPbalance(address, propertyId, ACCEPT_RESERVE);
958 
959  ql_lab.append(QString::fromStdString(getLabel(my_it->first)));
960  ql_addr.append((my_it->first).c_str());
961  if (divisible)
962  {
963  ql_avl.append(QString::fromStdString(FormatDivisibleMP(available)));
964  ql_res.append(QString::fromStdString(FormatDivisibleMP(reserved)));
965  }
966  else
967  {
968  ql_avl.append(QString::fromStdString(FormatIndivisibleMP(available)));
969  ql_res.append(QString::fromStdString(FormatIndivisibleMP(reserved)));
970  }
971  ++count;
972  }
973  }
974  qDebug() << "fillin()=" << count;
975  return count;
976 }
977 
QVariant addressColor(const TransactionRecord *wtx) const
int columnCount(const QModelIndex &parent) const
void SetHex(const char *psz)
Definition: uint256.h:305
QVariant data(const QModelIndex &index, int role) const
QVariant txStatusDecoration(const TransactionRecord *wtx) const
QString describe(TransactionRecord *rec, int unit)
TransactionTableModel(CWallet *wallet, WalletModel *parent=0)
Confirmed, but waiting for the recommended number of confirmations.
bool operator()(const uint256 &a, const TransactionRecord &b) const
Transaction not yet final, waiting for block.
Transaction status (TransactionRecord::Status)
int idx
Subtransaction index, for sort key.
#define TRY_LOCK(cs, name)
Definition: sync.h:158
Definition: init.h:13
QString getTxID() const
Return the unique identifier for this transaction (part)
Not sent to any other nodes.
msc_AddressTableEntry * index(int idx)
std::map< CTxDestination, CAddressBookData > mapAddressBook
Definition: wallet.h:173
#define PAIRTYPE(t1, t2)
Definition: util.h:48
CCriticalSection cs_wallet
Main wallet lock.
Definition: wallet.h:132
Generated (mined) transactions.
static int column_alignments[]
void updateWallet(const uint256 &hash, int status)
QString formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const
int fillin(unsigned int propertyId)
Have 6 or more confirmations (normal tx) or fully mature (mined tx)
std::string sortKey
Sorting key based on status.
QString dateTimeStr(const QDateTime &date)
Definition: guiutil.cpp:73
QVariant txAddressDecoration(const TransactionRecord *wtx) const
CCriticalSection cs_main
Definition: main.cpp:43
TransactionRecord * index(int idx)
Mined but not accepted.
Not yet mined into a block.
STL namespace.
uint64_t global_balance_reserved_testeco[100000]
Definition: mastercore.cpp:93
void updateEntry(const QString &address, const QString &label, bool isMine, const QString &purpose, int status)
QString lookupAddress(const std::string &address, bool tooltip) const
std::string name
Definition: wallet.h:85
void updateTransaction(const QString &hash, int status)
static bool showTransaction(const CWalletTx &wtx)
Decompose CWallet transaction to model transaction records.
base58-encoded Bitcoin addresses.
Definition: base58.h:101
AddressTableModel * getAddressTableModel()
TransactionTableModel * parent
QVariant headerData(int section, Qt::Orientation orientation, int role) const
bool isPropertyDivisible(unsigned int propertyId)
TransactionTablePriv * priv
int rowCount(const QModelIndex &parent=QModelIndex()) const
QString formatTxStatus(const TransactionRecord *wtx) const
QList< TransactionRecord > cachedWallet
bool IsMyAddress(const std::string &address)
#define LOCK2(cs1, cs2)
Definition: sync.h:157
QList< QString > ql_avl
UI model for a transaction.
TransactionStatus status
Status: can change with block chain update.
string getLabel(const string &address)
static QList< TransactionRecord > decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx)
int columnCount(const QModelIndex &parent=QModelIndex()) const
#define LOCK(cs)
Definition: sync.h:156
QString formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed=true) const
bool operator()(const TransactionRecord &a, const uint256 &b) const
uint64_t global_balance_money_testeco[100000]
Definition: mastercore.cpp:92
bool countsForBalance
Transaction counts towards available balance.
QVariant headerData(int section, Qt::Orientation orientation, int role) const
std::map< string, CMPTally > mp_tally_map
Definition: mastercore.cpp:423
void updateStatus(const CWalletTx &wtx)
Update status from core wallet tx.
std::string ToString() const
Definition: base58.cpp:174
void emitDataChanged(int idx)
uint64_t global_balance_reserved_maineco[100000]
Definition: mastercore.cpp:91
Date and time this transaction was created.
void updateConfirmations(void)
int getDisplayUnit()
Definition: optionsmodel.h:58
QList< QString > ql_lab
QList< msc_AddressTableEntry > msc_cachedAddressTable
UI model for the transaction table of a wallet.
#define COLOR_UNCONFIRMED
Definition: guiconstants.h:21
bool getDisplayAddresses()
Definition: optionsmodel.h:59
Normal (sent/received) transactions.
QString formatTxType(const TransactionRecord *wtx) const
QString formatTooltip(const TransactionRecord *rec) const
CCriticalSection cs_tally
Definition: mastercore.cpp:357
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
string getPropertyName(unsigned int propertyId)
msc_AddressTablePriv(CWallet *wallet, MatrixModel *parent)
256-bit unsigned integer
Definition: uint256.h:531
bool operator()(const TransactionRecord &a, const TransactionRecord &b) const
QString labelForAddress(const QString &address) const
int set_wallet_totals()
Definition: mastercore.cpp:943
Address book data.
Definition: wallet.h:82
Conflicts with other transaction or mempool.
CWallet * pwalletMain
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:96
std::string ToString() const
Definition: uint256.h:340
int rowCount(const QModelIndex &parent) const
friend class msc_AddressTablePriv
std::string FormatIndivisibleMP(int64_t n)
Definition: mastercore.cpp:343
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances...
Definition: wallet.h:100
Label of address related to transaction.
bool statusUpdateNeeded()
Return whether a status update is needed.
std::map< uint256, CWalletTx > mapWallet
Definition: wallet.h:168
string FormatDivisibleMP(int64_t n, bool fSign)
Definition: mastercore.cpp:325
QList< QString > ql_res
TransactionTablePriv(CWallet *wallet, TransactionTableModel *parent)
msc_AddressTablePriv * priv
boost::variant< CNoDestination, CKeyID, CScriptID > CTxDestination
A txout script template with a specific destination.
Definition: script.h:218
static const CCheckpointData data
Definition: checkpoints.cpp:56
qint64 open_for
Timestamp if status==OpenUntilDate, otherwise number of additional blocks that need to be mined befor...
Formatted amount, without brackets when unconfirmed.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const
QList< QString > ql_addr
#define COLOR_BAREADDRESS
Definition: guiconstants.h:25
static QString toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int unit)
static QString format(int unit, qint64 amount, bool plussign=false)
Format as string.
int64_t getMPbalance(const string &Address, unsigned int property, TallyType ttype)
Definition: mastercore.cpp:437
MatrixModel(CWallet *wallet, WalletModel *parent=0)
#define COLOR_NEGATIVE
Definition: guiconstants.h:23
QString formatTxDate(const TransactionRecord *wtx) const
static const int RecommendedNumConfirmations
Number of confirmation recommended for accepting a transaction.
Transaction will likely not mature because no nodes have confirmed.
int64_t getUserAvailableMPbalance(const string &Address, unsigned int property)
Definition: mastercore.cpp:455
uint64_t global_balance_money_maineco[100000]
Definition: mastercore.cpp:90
OptionsModel * getOptionsModel()