aboutsummaryrefslogtreecommitdiff
path: root/src/qt
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2014-01-22 08:07:19 +0100
committerWladimir J. van der Laan <laanwj@gmail.com>2014-01-22 08:07:56 +0100
commitceab53b41da4e812a63a7a7d6d05e9ed246a5cd5 (patch)
treefafe0f2960aff0fa77f2a30c5aadc436a76b7f01 /src/qt
parent6586bc3b51ac0a3891ff6297e1aea791ff331cd3 (diff)
parent4d901023b732efb492d89cebd8555c689ab7663e (diff)
Merge pull request #3521
4d90102 [Qt] Add sorting feature to the requested payments table (Cozz Lovan) 8476d5d [Qt] Permanently store requested payments in wallet (Cozz Lovan) b10e147 wallet: add interface for storing generic data on destinations (Wladimir J. van der Laan)
Diffstat (limited to 'src/qt')
-rw-r--r--src/qt/forms/receivecoinsdialog.ui6
-rw-r--r--src/qt/receivecoinsdialog.cpp2
-rw-r--r--src/qt/recentrequeststablemodel.cpp78
-rw-r--r--src/qt/recentrequeststablemodel.h45
-rw-r--r--src/qt/walletmodel.cpp24
-rw-r--r--src/qt/walletmodel.h42
6 files changed, 191 insertions, 6 deletions
diff --git a/src/qt/forms/receivecoinsdialog.ui b/src/qt/forms/receivecoinsdialog.ui
index 8242763e77..7bf01224ee 100644
--- a/src/qt/forms/receivecoinsdialog.ui
+++ b/src/qt/forms/receivecoinsdialog.ui
@@ -207,7 +207,11 @@
</widget>
</item>
<item>
- <widget class="QTableView" name="recentRequestsView"/>
+ <widget class="QTableView" name="recentRequestsView">
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ </widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index 075a16dabf..38dc88f63b 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -55,6 +55,8 @@ void ReceiveCoinsDialog::setModel(WalletModel *model)
ui->recentRequestsView->horizontalHeader()->setSectionResizeMode(RecentRequestsTableModel::Message, QHeaderView::Stretch);
#endif
ui->recentRequestsView->horizontalHeader()->resizeSection(RecentRequestsTableModel::Amount, 100);
+
+ model->getRecentRequestsTableModel()->sort(RecentRequestsTableModel::Date, Qt::DescendingOrder);
}
}
diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp
index 86c29dd02b..74b43f1d24 100644
--- a/src/qt/recentrequeststablemodel.cpp
+++ b/src/qt/recentrequeststablemodel.cpp
@@ -12,6 +12,13 @@ RecentRequestsTableModel::RecentRequestsTableModel(CWallet *wallet, WalletModel
walletModel(parent)
{
Q_UNUSED(wallet);
+ nReceiveRequestsMaxId = 0;
+
+ // Load entries from wallet
+ std::vector<std::string> vReceiveRequests;
+ parent->loadReceiveRequests(vReceiveRequests);
+ BOOST_FOREACH(const std::string& request, vReceiveRequests)
+ addNewRequest(request);
/* These columns must match the indices in the ColumnIndex enumeration */
columns << tr("Date") << tr("Label") << tr("Message") << tr("Amount");
@@ -104,6 +111,14 @@ bool RecentRequestsTableModel::removeRows(int row, int count, const QModelIndex
if(count > 0 && row >= 0 && (row+count) <= list.size())
{
+ const RecentRequestEntry *rec;
+ for (int i = 0; i < count; ++i)
+ {
+ rec = &list[row+i];
+ if (!walletModel->saveReceiveRequest(rec->recipient.address.toStdString(), rec->id, ""))
+ return false;
+ }
+
beginRemoveRows(parent, row, row + count - 1);
list.erase(list.begin() + row, list.begin() + row + count);
endRemoveRows();
@@ -118,12 +133,73 @@ Qt::ItemFlags RecentRequestsTableModel::flags(const QModelIndex &index) const
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
}
+// called when adding a request from the GUI
void RecentRequestsTableModel::addNewRequest(const SendCoinsRecipient &recipient)
{
RecentRequestEntry newEntry;
+ newEntry.id = ++nReceiveRequestsMaxId;
newEntry.date = QDateTime::currentDateTime();
newEntry.recipient = recipient;
+
+ CDataStream ss(SER_DISK, CLIENT_VERSION);
+ ss << newEntry;
+
+ if (!walletModel->saveReceiveRequest(recipient.address.toStdString(), newEntry.id, ss.str()))
+ return;
+
+ addNewRequest(newEntry);
+}
+
+// called from ctor when loading from wallet
+void RecentRequestsTableModel::addNewRequest(const std::string &recipient)
+{
+ std::vector<char> data(recipient.begin(), recipient.end());
+ CDataStream ss(data, SER_DISK, CLIENT_VERSION);
+
+ RecentRequestEntry entry;
+ ss >> entry;
+
+ if (entry.id == 0) // should not happen
+ return;
+
+ if (entry.id > nReceiveRequestsMaxId)
+ nReceiveRequestsMaxId = entry.id;
+
+ addNewRequest(entry);
+}
+
+// actually add to table in GUI
+void RecentRequestsTableModel::addNewRequest(RecentRequestEntry &recipient)
+{
beginInsertRows(QModelIndex(), 0, 0);
- list.prepend(newEntry);
+ list.prepend(recipient);
endInsertRows();
}
+
+void RecentRequestsTableModel::sort(int column, Qt::SortOrder order)
+{
+ qSort(list.begin(), list.end(), RecentRequestEntryLessThan(column, order));
+ emit dataChanged(index(0, 0, QModelIndex()), index(list.size() - 1, NUMBER_OF_COLUMNS - 1, QModelIndex()));
+}
+
+bool RecentRequestEntryLessThan::operator()(RecentRequestEntry &left, RecentRequestEntry &right) const
+{
+ RecentRequestEntry *pLeft = &left;
+ RecentRequestEntry *pRight = &right;
+ if (order == Qt::DescendingOrder)
+ std::swap(pLeft, pRight);
+
+ switch(column)
+ {
+ case RecentRequestsTableModel::Date:
+ return pLeft->date.toTime_t() < pRight->date.toTime_t();
+ case RecentRequestsTableModel::Label:
+ return pLeft->recipient.label < pRight->recipient.label;
+ case RecentRequestsTableModel::Message:
+ return pLeft->recipient.message < pRight->recipient.message;
+ case RecentRequestsTableModel::Amount:
+ return pLeft->recipient.amount < pRight->recipient.amount;
+ default:
+ return pLeft->id < pRight->id;
+ }
+}
diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h
index 3aab7b0a48..6b20402f78 100644
--- a/src/qt/recentrequeststablemodel.h
+++ b/src/qt/recentrequeststablemodel.h
@@ -13,10 +13,44 @@
class CWallet;
-struct RecentRequestEntry
+class RecentRequestEntry
{
+public:
+ RecentRequestEntry() : nVersion(RecentRequestEntry::CURRENT_VERSION), id(0) { }
+
+ static const int CURRENT_VERSION=1;
+ int nVersion;
+ int64_t id;
QDateTime date;
SendCoinsRecipient recipient;
+
+ IMPLEMENT_SERIALIZE
+ (
+ RecentRequestEntry* pthis = const_cast<RecentRequestEntry*>(this);
+
+ unsigned int nDate = date.toTime_t();
+
+ READWRITE(pthis->nVersion);
+ nVersion = pthis->nVersion;
+ READWRITE(id);
+ READWRITE(nDate);
+ READWRITE(recipient);
+
+ if (fRead)
+ pthis->date = QDateTime::fromTime_t(nDate);
+ )
+};
+
+class RecentRequestEntryLessThan
+{
+public:
+ RecentRequestEntryLessThan(int nColumn, Qt::SortOrder fOrder):
+ column(nColumn), order(fOrder) {}
+ bool operator()(RecentRequestEntry &left, RecentRequestEntry &right ) const;
+
+private:
+ int column;
+ Qt::SortOrder order;
};
/** Model for list of recently generated payment requests / bitcoin URIs.
@@ -34,7 +68,8 @@ public:
Date = 0,
Label = 1,
Message = 2,
- Amount = 3
+ Amount = 3,
+ NUMBER_OF_COLUMNS
};
/** @name Methods overridden from QAbstractTableModel
@@ -51,11 +86,17 @@ public:
const RecentRequestEntry &entry(int row) const { return list[row]; }
void addNewRequest(const SendCoinsRecipient &recipient);
+ void addNewRequest(const std::string &recipient);
+ void addNewRequest(RecentRequestEntry &recipient);
+
+public slots:
+ void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
private:
WalletModel *walletModel;
QStringList columns;
QList<RecentRequestEntry> list;
+ int64_t nReceiveRequestsMaxId;
};
#endif
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 14f29c933b..01f5a304a9 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -554,3 +554,27 @@ void WalletModel::listLockedCoins(std::vector<COutPoint>& vOutpts)
LOCK(wallet->cs_wallet);
wallet->ListLockedCoins(vOutpts);
}
+
+void WalletModel::loadReceiveRequests(std::vector<std::string>& vReceiveRequests)
+{
+ LOCK(wallet->cs_wallet);
+ BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, wallet->mapAddressBook)
+ BOOST_FOREACH(const PAIRTYPE(std::string, std::string)& item2, item.second.destdata)
+ if (item2.first.size() > 2 && item2.first.substr(0,2) == "rr") // receive request
+ vReceiveRequests.push_back(item2.second);
+}
+
+bool WalletModel::saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest)
+{
+ CTxDestination dest = CBitcoinAddress(sAddress).Get();
+
+ std::stringstream ss;
+ ss << nId;
+ std::string key = "rr" + ss.str(); // "rr" prefix = "receive request" in destdata
+
+ LOCK(wallet->cs_wallet);
+ if (sRequest.empty())
+ return wallet->EraseDestData(dest, key);
+ else
+ return wallet->AddDestData(dest, key, sRequest);
+}
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 1a4d25615a..600bef346b 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -36,9 +36,9 @@ QT_END_NAMESPACE
class SendCoinsRecipient
{
public:
- explicit SendCoinsRecipient() : amount(0) { }
+ explicit SendCoinsRecipient() : amount(0), nVersion(SendCoinsRecipient::CURRENT_VERSION) { }
explicit SendCoinsRecipient(const QString &addr, const QString &label, quint64 amount, const QString &message):
- address(addr), label(label), amount(amount), message(message) {}
+ address(addr), label(label), amount(amount), message(message), nVersion(SendCoinsRecipient::CURRENT_VERSION) {}
// If from an insecure payment request, this is used for storing
// the addresses, e.g. address-A<br />address-B<br />address-C.
@@ -55,6 +55,41 @@ public:
PaymentRequestPlus paymentRequest;
// Empty if no authentication or invalid signature/cert/etc.
QString authenticatedMerchant;
+
+ static const int CURRENT_VERSION=1;
+ int nVersion;
+
+ IMPLEMENT_SERIALIZE
+ (
+ SendCoinsRecipient* pthis = const_cast<SendCoinsRecipient*>(this);
+
+ std::string sAddress = pthis->address.toStdString();
+ std::string sLabel = pthis->label.toStdString();
+ std::string sMessage = pthis->message.toStdString();
+ std::string sPaymentRequest;
+ if (!fRead && pthis->paymentRequest.IsInitialized())
+ pthis->paymentRequest.SerializeToString(&sPaymentRequest);
+ std::string sAuthenticatedMerchant = pthis->authenticatedMerchant.toStdString();
+
+ READWRITE(pthis->nVersion);
+ nVersion = pthis->nVersion;
+ READWRITE(sAddress);
+ READWRITE(sLabel);
+ READWRITE(amount);
+ READWRITE(sMessage);
+ READWRITE(sPaymentRequest);
+ READWRITE(sAuthenticatedMerchant);
+
+ if (fRead)
+ {
+ pthis->address = QString::fromStdString(sAddress);
+ pthis->label = QString::fromStdString(sLabel);
+ pthis->message = QString::fromStdString(sMessage);
+ if (!sPaymentRequest.empty())
+ pthis->paymentRequest.parse(QByteArray::fromRawData(sPaymentRequest.data(), sPaymentRequest.size()));
+ pthis->authenticatedMerchant = QString::fromStdString(sAuthenticatedMerchant);
+ }
+ )
};
/** Interface to Bitcoin wallet from Qt view code. */
@@ -152,6 +187,9 @@ public:
void unlockCoin(COutPoint& output);
void listLockedCoins(std::vector<COutPoint>& vOutpts);
+ void loadReceiveRequests(std::vector<std::string>& vReceiveRequests);
+ bool saveReceiveRequest(const std::string &sAddress, const int64_t nId, const std::string &sRequest);
+
private:
CWallet *wallet;