diff options
Diffstat (limited to 'src')
30 files changed, 413 insertions, 99 deletions
diff --git a/src/qt/Makefile.am b/src/qt/Makefile.am index 3dfe8ee6ca..cac6039663 100644 --- a/src/qt/Makefile.am +++ b/src/qt/Makefile.am @@ -133,7 +133,7 @@ QT_MOC_CPP = \ moc_transactionfilterproxy.cpp \ moc_transactiontablemodel.cpp \ moc_transactionview.cpp \ - moc_utilitydialog.cpp \ + moc_utilitydialog.cpp \ moc_walletframe.cpp \ moc_walletmodel.cpp \ moc_walletview.cpp diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 1008ef2b08..f548c65161 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -308,11 +308,15 @@ void BitcoinGUI::createActions(bool fIsTestnet) openAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_FileIcon), tr("Open &URI..."), this); openAction->setStatusTip(tr("Open a bitcoin: URI or payment request")); + showHelpMessageAction = new QAction(QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation), tr("&Command-line options"), this); + showHelpMessageAction->setStatusTip(tr("Show the Bitcoin Core help message to get a list with possible Bitcoin command-line options")); + connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked())); connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked())); connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden())); + connect(showHelpMessageAction, SIGNAL(triggered()), this, SLOT(showHelpMessageClicked())); #ifdef ENABLE_WALLET if(walletFrame) { @@ -366,8 +370,9 @@ void BitcoinGUI::createMenuBar() if(walletFrame) { help->addAction(openRPCConsoleAction); - help->addSeparator(); } + help->addAction(showHelpMessageAction); + help->addSeparator(); help->addAction(aboutAction); help->addAction(aboutQtAction); } @@ -546,6 +551,13 @@ void BitcoinGUI::aboutClicked() dlg.exec(); } +void BitcoinGUI::showHelpMessageClicked() +{ + HelpMessageDialog *help = new HelpMessageDialog(this); + help->setAttribute(Qt::WA_DeleteOnClose); + help->show(); +} + #ifdef ENABLE_WALLET void BitcoinGUI::openClicked() { diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index d5bbdca484..4dce4431ba 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -93,6 +93,7 @@ private: QAction *aboutQtAction; QAction *openRPCConsoleAction; QAction *openAction; + QAction *showHelpMessageAction; QSystemTrayIcon *trayIcon; Notificator *notificator; @@ -176,6 +177,8 @@ private slots: void optionsClicked(); /** Show about dialog */ void aboutClicked(); + /** Show help message dialog */ + void showHelpMessageClicked(); #ifndef Q_OS_MAC /** Handle tray icon clicked */ void trayIconActivated(QSystemTrayIcon::ActivationReason reason); diff --git a/src/qt/forms/askpassphrasedialog.ui b/src/qt/forms/askpassphrasedialog.ui index 25169042a1..bc4921455f 100644 --- a/src/qt/forms/askpassphrasedialog.ui +++ b/src/qt/forms/askpassphrasedialog.ui @@ -122,12 +122,12 @@ <slot>accept()</slot> <hints> <hint type="sourcelabel"> - <x>248</x> - <y>254</y> + <x>20</x> + <y>20</y> </hint> <hint type="destinationlabel"> - <x>157</x> - <y>274</y> + <x>20</x> + <y>20</y> </hint> </hints> </connection> @@ -138,12 +138,12 @@ <slot>reject()</slot> <hints> <hint type="sourcelabel"> - <x>316</x> - <y>260</y> + <x>20</x> + <y>20</y> </hint> <hint type="destinationlabel"> - <x>286</x> - <y>274</y> + <x>20</x> + <y>20</y> </hint> </hints> </connection> diff --git a/src/qt/forms/editaddressdialog.ui b/src/qt/forms/editaddressdialog.ui index 8ff3805226..915b3679a1 100644 --- a/src/qt/forms/editaddressdialog.ui +++ b/src/qt/forms/editaddressdialog.ui @@ -76,12 +76,12 @@ <slot>accept()</slot> <hints> <hint type="sourcelabel"> - <x>248</x> - <y>254</y> + <x>20</x> + <y>20</y> </hint> <hint type="destinationlabel"> - <x>157</x> - <y>274</y> + <x>20</x> + <y>20</y> </hint> </hints> </connection> @@ -92,12 +92,12 @@ <slot>reject()</slot> <hints> <hint type="sourcelabel"> - <x>316</x> - <y>260</y> + <x>20</x> + <y>20</y> </hint> <hint type="destinationlabel"> - <x>286</x> - <y>274</y> + <x>20</x> + <y>20</y> </hint> </hints> </connection> diff --git a/src/qt/forms/intro.ui b/src/qt/forms/intro.ui index 05ee9466c4..09e7bdb024 100644 --- a/src/qt/forms/intro.ui +++ b/src/qt/forms/intro.ui @@ -237,12 +237,12 @@ <slot>accept()</slot> <hints> <hint type="sourcelabel"> - <x>248</x> - <y>254</y> + <x>20</x> + <y>20</y> </hint> <hint type="destinationlabel"> - <x>157</x> - <y>274</y> + <x>20</x> + <y>20</y> </hint> </hints> </connection> @@ -253,12 +253,12 @@ <slot>reject()</slot> <hints> <hint type="sourcelabel"> - <x>316</x> - <y>260</y> + <x>20</x> + <y>20</y> </hint> <hint type="destinationlabel"> - <x>286</x> - <y>274</y> + <x>20</x> + <y>20</y> </hint> </hints> </connection> 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/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui index 69504f3159..31d61ec468 100644 --- a/src/qt/forms/rpcconsole.ui +++ b/src/qt/forms/rpcconsole.ui @@ -339,32 +339,6 @@ </widget> </item> <item row="16" column="0"> - <widget class="QLabel" name="labelCLOptions"> - <property name="font"> - <font> - <weight>75</weight> - <bold>true</bold> - </font> - </property> - <property name="text"> - <string>Command-line options</string> - </property> - </widget> - </item> - <item row="17" column="0"> - <widget class="QPushButton" name="showCLOptionsButton"> - <property name="toolTip"> - <string>Show the Bitcoin-Core help message to get a list with possible Bitcoin command-line options.</string> - </property> - <property name="text"> - <string>&Show</string> - </property> - <property name="autoDefault"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="18" column="0"> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> diff --git a/src/qt/forms/sendcoinsentry.ui b/src/qt/forms/sendcoinsentry.ui index b6cec5baf0..96c922af4d 100644 --- a/src/qt/forms/sendcoinsentry.ui +++ b/src/qt/forms/sendcoinsentry.ui @@ -141,6 +141,23 @@ <item row="2" column="1"> <widget class="BitcoinAmountField" name="payAmount"/> </item> + <item row="3" column="0"> + <widget class="QLabel" name="messageLabel"> + <property name="text"> + <string>Message:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QLabel" name="messageTextLabel"> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + </widget> + </item> </layout> </widget> <widget class="QFrame" name="SendCoins_InsecurePaymentRequest"> diff --git a/src/qt/forms/signverifymessagedialog.ui b/src/qt/forms/signverifymessagedialog.ui index 04d614a1cd..989522bb58 100644 --- a/src/qt/forms/signverifymessagedialog.ui +++ b/src/qt/forms/signverifymessagedialog.ui @@ -19,9 +19,6 @@ <layout class="QVBoxLayout" name="verticalLayout"> <item> <widget class="QTabWidget" name="tabWidget"> - <property name="currentIndex"> - <number>0</number> - </property> <widget class="QWidget" name="tabSignMessage"> <attribute name="title"> <string>&Sign Message</string> diff --git a/src/qt/forms/transactiondescdialog.ui b/src/qt/forms/transactiondescdialog.ui index b38dffcc12..5ae1e12856 100644 --- a/src/qt/forms/transactiondescdialog.ui +++ b/src/qt/forms/transactiondescdialog.ui @@ -45,12 +45,12 @@ <slot>accept()</slot> <hints> <hint type="sourcelabel"> - <x>248</x> - <y>254</y> + <x>20</x> + <y>20</y> </hint> <hint type="destinationlabel"> - <x>157</x> - <y>274</y> + <x>20</x> + <y>20</y> </hint> </hints> </connection> @@ -61,12 +61,12 @@ <slot>reject()</slot> <hints> <hint type="sourcelabel"> - <x>316</x> - <y>260</y> + <x>20</x> + <y>20</y> </hint> <hint type="destinationlabel"> - <x>286</x> - <y>274</y> + <x>20</x> + <y>20</y> </hint> </hints> </connection> diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index d024e3b7aa..f61bb3ed2c 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -53,7 +53,6 @@ OptionsDialog::OptionsDialog(QWidget *parent) : connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyIp, SLOT(setEnabled(bool))); connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyPort, SLOT(setEnabled(bool))); connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->socksVersion, SLOT(setEnabled(bool))); - connect(ui->connectSocks, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning_Proxy())); ui->proxyIp->installEventFilter(this); @@ -204,7 +203,7 @@ void OptionsDialog::on_resetButton_clicked() if(btnRetVal == QMessageBox::Cancel) return; - /* reset all options and close Bitcoin-Qt */ + /* reset all options and close GUI */ model->Reset(); QApplication::quit(); } diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 1133c457b3..a18fd1d514 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -19,6 +19,7 @@ #include "walletdb.h" #endif +#include <QNetworkProxy> #include <QSettings> #include <QStringList> @@ -375,14 +376,25 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in return successful; } -bool OptionsModel::getProxySettings(QString& proxyIP, quint16 &proxyPort) const +bool OptionsModel::getProxySettings(QNetworkProxy& proxy) const { - std::string proxy = GetArg("-proxy", ""); - if (proxy.empty()) return false; + // Directly query current base proxy, because + // GUI settings can be overridden with -proxy. + proxyType curProxy; + if (GetProxy(NET_IPV4, curProxy)) { + if (curProxy.second == 5) { + proxy.setType(QNetworkProxy::Socks5Proxy); + proxy.setHostName(QString::fromStdString(curProxy.first.ToStringIP())); + proxy.setPort(curProxy.first.GetPort()); + + return true; + } + else + return false; + } + else + proxy.setType(QNetworkProxy::NoProxy); - CService addrProxy(proxy); - proxyIP = QString(addrProxy.ToStringIP().c_str()); - proxyPort = addrProxy.GetPort(); return true; } diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index d05cb46746..7a71b772b2 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -7,6 +7,10 @@ #include <QAbstractListModel> +QT_BEGIN_NAMESPACE +class QNetworkProxy; +QT_END_NAMESPACE + /** Interface from Qt to configuration data structure for Bitcoin client. To Qt, the options are presented as a list with the different options laid out vertically. @@ -54,7 +58,7 @@ public: bool getMinimizeOnClose() { return fMinimizeOnClose; } int getDisplayUnit() { return nDisplayUnit; } bool getDisplayAddresses() { return bDisplayAddresses; } - bool getProxySettings(QString& proxyIP, quint16 &proxyPort) const; + bool getProxySettings(QNetworkProxy& proxy) const; bool getCoinControlFeatures() { return fCoinControlFeatures; } const QString& getOverriddenByCommandLine() { return strOverriddenByCommandLine; } diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 7642cd117a..ca6ae17990 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -335,17 +335,22 @@ void PaymentServer::initNetManager() // netManager is used to fetch paymentrequests given in bitcoin: URIs netManager = new QNetworkAccessManager(this); - // Use proxy settings from optionsModel - QString proxyIP; - quint16 proxyPort; - if (optionsModel->getProxySettings(proxyIP, proxyPort)) - { - QNetworkProxy proxy; - proxy.setType(QNetworkProxy::Socks5Proxy); - proxy.setHostName(proxyIP); - proxy.setPort(proxyPort); - netManager->setProxy(proxy); + QNetworkProxy proxy; + + // Query active proxy (fails if no SOCKS5 proxy) + if (optionsModel->getProxySettings(proxy)) { + if (proxy.type() == QNetworkProxy::Socks5Proxy) { + netManager->setProxy(proxy); + + qDebug() << "PaymentServer::initNetManager : Using SOCKS5 proxy" << proxy.hostName() << ":" << proxy.port(); + } + else + qDebug() << "PaymentServer::initNetManager : No active proxy server found."; } + else + emit message(tr("Net manager warning"), + tr("Your active proxy doesn't support SOCKS5, which is required for payment requests via proxy."), + CClientUIInterface::MSG_WARNING); connect(netManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(netRequestFinished(QNetworkReply*))); 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..51aef9decf 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/rpcconsole.cpp b/src/qt/rpcconsole.cpp index abb6ceb139..b1671b8a0e 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -7,7 +7,6 @@ #include "clientmodel.h" #include "guiutil.h" -#include "utilitydialog.h" #include "rpcserver.h" #include "rpcclient.h" @@ -201,7 +200,6 @@ RPCConsole::RPCConsole(QWidget *parent) : #ifndef Q_OS_MAC ui->openDebugLogfileButton->setIcon(QIcon(":/icons/export")); - ui->showCLOptionsButton->setIcon(QIcon(":/icons/options")); #endif // Install event filter for up and down arrow @@ -442,12 +440,6 @@ void RPCConsole::scrollToEnd() scrollbar->setValue(scrollbar->maximum()); } -void RPCConsole::on_showCLOptionsButton_clicked() -{ - HelpMessageDialog *help = new HelpMessageDialog(this); - help->show(); -} - void RPCConsole::on_sldGraphRange_valueChanged(int value) { const int multiplier = 5; // each position on the slider represents 5 min diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 6fbf197728..0cfd1c80d1 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -40,8 +40,6 @@ private slots: void on_tabWidget_currentChanged(int index); /** open the debug.log from the current datadir */ void on_openDebugLogfileButton_clicked(); - /** display messagebox with program parameters (same as bitcoin-qt --help) */ - void on_showCLOptionsButton_clicked(); /** change the time range of the network traffic graph */ void on_sldGraphRange_valueChanged(int value); /** update traffic statistics */ diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp index 3f5d0cda3a..b4e74b078c 100644 --- a/src/qt/sendcoinsentry.cpp +++ b/src/qt/sendcoinsentry.cpp @@ -88,6 +88,9 @@ void SendCoinsEntry::clear() ui->payTo->clear(); ui->addAsLabel->clear(); ui->payAmount->clear(); + ui->messageTextLabel->clear(); + ui->messageTextLabel->hide(); + ui->messageLabel->hide(); // clear UI elements for insecure payment request ui->payTo_is->clear(); ui->memoTextLabel_is->clear(); @@ -148,6 +151,7 @@ SendCoinsRecipient SendCoinsEntry::getValue() recipient.address = ui->payTo->text(); recipient.label = ui->addAsLabel->text(); recipient.amount = ui->payAmount->value(); + recipient.message = ui->messageTextLabel->text(); return recipient; } @@ -188,6 +192,11 @@ void SendCoinsEntry::setValue(const SendCoinsRecipient &value) } else // normal payment { + // message + ui->messageTextLabel->setText(recipient.message); + ui->messageTextLabel->setVisible(!recipient.message.isEmpty()); + ui->messageLabel->setVisible(!recipient.message.isEmpty()); + ui->payTo->setText(recipient.address); ui->addAsLabel->setText(recipient.label); ui->payAmount->setValue(recipient.amount); diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 8b16496c18..c21679ea8a 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -5,8 +5,8 @@ #include "splashscreen.h" #include "clientversion.h" -#include "util.h" #include "ui_interface.h" +#include "util.h" #include <QApplication> #include <QPainter> diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index c0c4d53732..2c3a9e3a5c 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -224,6 +224,11 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u strHTML += "<b>" + tr("Transaction ID") + ":</b> " + TransactionRecord::formatSubTxId(wtx.GetHash(), vout) + "<br>"; + // Message from normal bitcoin:URI (bitcoin:123...?message=example) + foreach (const PAIRTYPE(string, string)& r, wtx.vOrderForm) + if (r.first == "Message") + strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(r.second, true) + "<br>"; + // // PaymentRequest info: // diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 14f29c933b..ddc8c6ea79 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -269,6 +269,8 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran rcp.paymentRequest.SerializeToString(&value); newTx->vOrderForm.push_back(make_pair(key, value)); } + else if (!rcp.message.isEmpty()) // Message from normal bitcoin:URI (bitcoin:123...?message=example) + newTx->vOrderForm.push_back(make_pair("Message", rcp.message.toStdString())); } CReserveKey *keyChange = transaction.getPossibleKeyChange(); @@ -554,3 +556,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..6d9d866b25 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; diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index c801b284cb..18c8bb6e61 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -116,9 +116,14 @@ Value importprivkey(const Array& params, bool fHelp) if (pwalletMain->HaveKey(vchAddress)) return Value::null; + pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1; + if (!pwalletMain->AddKeyPubKey(key, pubkey)) throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); + // whenever a key is imported, we need to scan the whole chain + pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value' + if (fRescan) { pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); pwalletMain->ReacceptWalletTransactions(); diff --git a/src/wallet.cpp b/src/wallet.cpp index 9065ba8483..84642bee62 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1534,7 +1534,19 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const string& strNam bool CWallet::DelAddressBook(const CTxDestination& address) { + AssertLockHeld(cs_wallet); // mapAddressBook + + if(fFileBacked) + { + // Delete destdata tuples associated with address + std::string strAddress = CBitcoinAddress(address).ToString(); + BOOST_FOREACH(const PAIRTYPE(string, string) &item, mapAddressBook[address].destdata) + { + CWalletDB(strWalletFile).EraseDestData(strAddress, item.first); + } + } + mapAddressBook.erase(address); NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address), "", CT_DELETED); if (!fFileBacked) @@ -2008,3 +2020,45 @@ void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const { for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++) mapKeyBirth[it->first] = it->second->nTime - 7200; // block times can be 2h off } + +bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value) +{ + if (boost::get<CNoDestination>(&dest)) + return false; + + mapAddressBook[dest].destdata.insert(std::make_pair(key, value)); + if (!fFileBacked) + return true; + return CWalletDB(strWalletFile).WriteDestData(CBitcoinAddress(dest).ToString(), key, value); +} + +bool CWallet::EraseDestData(const CTxDestination &dest, const std::string &key) +{ + if (!mapAddressBook[dest].destdata.erase(key)) + return false; + if (!fFileBacked) + return true; + return CWalletDB(strWalletFile).EraseDestData(CBitcoinAddress(dest).ToString(), key); +} + +bool CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value) +{ + mapAddressBook[dest].destdata.insert(std::make_pair(key, value)); + return true; +} + +bool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const +{ + std::map<CTxDestination, CAddressBookData>::const_iterator i = mapAddressBook.find(dest); + if(i != mapAddressBook.end()) + { + CAddressBookData::StringMap::const_iterator j = i->second.destdata.find(key); + if(j != i->second.destdata.end()) + { + if(value) + *value = j->second; + return true; + } + } + return false; +} diff --git a/src/wallet.h b/src/wallet.h index e4452a3093..dc8c007ac8 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -83,6 +83,9 @@ public: { purpose = "unknown"; } + + typedef std::map<std::string, std::string> StringMap; + StringMap destdata; }; /** A CWallet is an extension of a keystore, which also maintains a set of transactions and balances, @@ -189,6 +192,15 @@ public: bool AddCScript(const CScript& redeemScript); bool LoadCScript(const CScript& redeemScript) { return CCryptoKeyStore::AddCScript(redeemScript); } + /// Adds a destination data tuple to the store, and saves it to disk + bool AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value); + /// Erases a destination data tuple in the store and on disk + bool EraseDestData(const CTxDestination &dest, const std::string &key); + /// Adds a destination data tuple to the store, without saving it to disk + bool LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value); + /// Look up a destination data tuple in the store, return true if found false otherwise + bool GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const; + bool Unlock(const SecureString& strWalletPassphrase); bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase); bool EncryptWallet(const SecureString& strWalletPassphrase); diff --git a/src/walletdb.cpp b/src/walletdb.cpp index 9c5bddba60..2e61c6cd58 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -564,6 +564,18 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, { ssValue >> pwallet->nOrderPosNext; } + else if (strType == "destdata") + { + std::string strAddress, strKey, strValue; + ssKey >> strAddress; + ssKey >> strKey; + ssValue >> strValue; + if (!pwallet->LoadDestData(CBitcoinAddress(strAddress).Get(), strKey, strValue)) + { + strErr = "Error reading wallet database: LoadDestData failed"; + return false; + } + } } catch (...) { return false; @@ -865,3 +877,15 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename) { return CWalletDB::Recover(dbenv, filename, false); } + +bool CWalletDB::WriteDestData(const std::string &address, const std::string &key, const std::string &value) +{ + nWalletDBUpdated++; + return Write(boost::make_tuple(std::string("destdata"), address, key), value); +} + +bool CWalletDB::EraseDestData(const std::string &address, const std::string &key) +{ + nWalletDBUpdated++; + return Erase(boost::make_tuple(string("destdata"), address, key)); +} diff --git a/src/walletdb.h b/src/walletdb.h index 88ba89f9d5..15af287245 100644 --- a/src/walletdb.h +++ b/src/walletdb.h @@ -124,6 +124,11 @@ public: bool ReadAccount(const std::string& strAccount, CAccount& account); bool WriteAccount(const std::string& strAccount, const CAccount& account); + + /// Write destination data key,value tuple to database + bool WriteDestData(const std::string &address, const std::string &key, const std::string &value); + /// Erase destination data tuple from wallet database + bool EraseDestData(const std::string &address, const std::string &key); private: bool WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry); public: |