diff options
-rw-r--r-- | src/main.cpp | 21 | ||||
-rw-r--r-- | src/main.h | 6 | ||||
-rw-r--r-- | src/qt/addressbookpage.cpp | 9 | ||||
-rw-r--r-- | src/qt/addressbookpage.h | 3 | ||||
-rw-r--r-- | src/qt/bitcoingui.cpp | 2 | ||||
-rw-r--r-- | src/qt/clientmodel.cpp | 2 | ||||
-rw-r--r-- | src/qt/forms/qrcodedialog.ui | 242 | ||||
-rw-r--r-- | src/qt/forms/transactiondescdialog.ui | 2 | ||||
-rw-r--r-- | src/qt/guiconstants.h | 6 | ||||
-rw-r--r-- | src/qt/qrcodedialog.cpp | 87 | ||||
-rw-r--r-- | src/qt/qrcodedialog.h | 18 | ||||
-rw-r--r-- | src/qt/transactiondesc.cpp | 84 | ||||
-rw-r--r-- | src/qt/walletmodel.cpp | 56 | ||||
-rw-r--r-- | src/qt/walletmodel.h | 11 |
14 files changed, 334 insertions, 215 deletions
diff --git a/src/main.cpp b/src/main.cpp index b4e827098e..3052cfb8c4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -268,6 +268,9 @@ bool CTransaction::ReadFromDisk(COutPoint prevout) bool CTransaction::IsStandard() const { + if (nVersion > CTransaction::CURRENT_VERSION) + return false; + BOOST_FOREACH(const CTxIn& txin, vin) { // Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG @@ -1620,6 +1623,24 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str(), DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); + // Check the version of the last 100 blocks to see if we need to upgrade: + if (!fIsInitialDownload) + { + int nUpgraded = 0; + const CBlockIndex* pindex = pindexBest; + for (int i = 0; i < 100 && pindex != NULL; i++) + { + if (pindex->nVersion > CBlock::CURRENT_VERSION) + ++nUpgraded; + pindex = pindex->pprev; + } + if (nUpgraded > 0) + printf("SetBestChain: %d of last 100 blocks above version %d\n", nUpgraded, CBlock::CURRENT_VERSION); + if (nUpgraded > 100/2) + // strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user: + strMiscWarning = _("Warning: this version is obsolete, upgrade required"); + } + std::string strCmd = GetArg("-blocknotify", ""); if (!fIsInitialDownload && !strCmd.empty()) diff --git a/src/main.h b/src/main.h index c841fdaf18..b3cc9ab40e 100644 --- a/src/main.h +++ b/src/main.h @@ -386,6 +386,7 @@ typedef std::map<uint256, std::pair<CTxIndex, CTransaction> > MapPrevTx; class CTransaction { public: + static const int CURRENT_VERSION=1; int nVersion; std::vector<CTxIn> vin; std::vector<CTxOut> vout; @@ -411,7 +412,7 @@ public: void SetNull() { - nVersion = 1; + nVersion = CTransaction::CURRENT_VERSION; vin.clear(); vout.clear(); nLockTime = 0; @@ -817,6 +818,7 @@ class CBlock { public: // header + static const int CURRENT_VERSION=1; int nVersion; uint256 hashPrevBlock; uint256 hashMerkleRoot; @@ -858,7 +860,7 @@ public: void SetNull() { - nVersion = 1; + nVersion = CBlock::CURRENT_VERSION; hashPrevBlock = 0; hashMerkleRoot = 0; nTime = 0; diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp index 9859893321..e502d9bc31 100644 --- a/src/qt/addressbookpage.cpp +++ b/src/qt/addressbookpage.cpp @@ -2,6 +2,7 @@ #include "ui_addressbookpage.h" #include "addresstablemodel.h" +#include "optionsmodel.h" #include "bitcoingui.h" #include "editaddressdialog.h" #include "csvmodelwriter.h" @@ -20,6 +21,7 @@ AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) : QDialog(parent), ui(new Ui::AddressBookPage), model(0), + optionsModel(0), mode(mode), tab(tab) { @@ -143,6 +145,11 @@ void AddressBookPage::setModel(AddressTableModel *model) selectionChanged(); } +void AddressBookPage::setOptionsModel(OptionsModel *optionsModel) +{ + this->optionsModel = optionsModel; +} + void AddressBookPage::on_copyToClipboard_clicked() { GUIUtil::copyEntryData(ui->tableView, AddressTableModel::Address); @@ -341,6 +348,8 @@ void AddressBookPage::on_showQRCode_clicked() QString address = index.data().toString(), label = index.sibling(index.row(), 0).data(Qt::EditRole).toString(); QRCodeDialog *dialog = new QRCodeDialog(address, label, tab == ReceivingTab, this); + if(optionsModel) + dialog->setModel(optionsModel); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->show(); } diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h index 6bd56ffe33..fae688fc9d 100644 --- a/src/qt/addressbookpage.h +++ b/src/qt/addressbookpage.h @@ -7,6 +7,7 @@ namespace Ui { class AddressBookPage; } class AddressTableModel; +class OptionsModel; QT_BEGIN_NAMESPACE class QTableView; @@ -37,6 +38,7 @@ public: ~AddressBookPage(); void setModel(AddressTableModel *model); + void setOptionsModel(OptionsModel *optionsModel); const QString &getReturnValue() const { return returnValue; } public slots: @@ -46,6 +48,7 @@ public slots: private: Ui::AddressBookPage *ui; AddressTableModel *model; + OptionsModel *optionsModel; Mode mode; Tabs tab; QString returnValue; diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index e8ecf8ad4e..775d676ee5 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -368,6 +368,8 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel) connect(clientModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool))); rpcConsole->setClientModel(clientModel); + addressBookPage->setOptionsModel(clientModel->getOptionsModel()); + receiveCoinsPage->setOptionsModel(clientModel->getOptionsModel()); } } diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index cabbd5d240..8fcc4e650e 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -18,7 +18,7 @@ ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) : { numBlocksAtStartup = -1; - pollTimer = new QTimer(); + pollTimer = new QTimer(this); pollTimer->setInterval(MODEL_UPDATE_DELAY); pollTimer->start(); connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer())); diff --git a/src/qt/forms/qrcodedialog.ui b/src/qt/forms/qrcodedialog.ui index 6199b68749..52e9db3762 100644 --- a/src/qt/forms/qrcodedialog.ui +++ b/src/qt/forms/qrcodedialog.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>334</width> - <height>425</height> + <width>340</width> + <height>530</height> </rect> </property> <property name="windowTitle"> @@ -28,8 +28,8 @@ <height>300</height> </size> </property> - <property name="text"> - <string>QR Code</string> + <property name="textFormat"> + <enum>Qt::PlainText</enum> </property> <property name="alignment"> <set>Qt::AlignCenter</set> @@ -40,133 +40,122 @@ </widget> </item> <item> + <widget class="QPlainTextEdit" name="outUri"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>50</height> + </size> + </property> + <property name="tabChangesFocus"> + <bool>true</bool> + </property> + <property name="textInteractionFlags"> + <set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item> <widget class="QWidget" name="widget" native="true"> <layout class="QVBoxLayout" name="verticalLayout_2"> <item> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <item> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QCheckBox" name="chkReqPayment"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="text"> - <string>Request Payment</string> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QLabel" name="lblAmount"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Amount:</string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - <property name="buddy"> - <cstring>lnReqAmount</cstring> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="lnReqAmount"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="minimumSize"> - <size> - <width>60</width> - <height>0</height> - </size> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="lblBTC"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>BTC</string> - </property> - <property name="buddy"> - <cstring>lnReqAmount</cstring> - </property> - </widget> - </item> - </layout> - </item> - </layout> + <widget class="QCheckBox" name="chkReqPayment"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Request Payment</string> + </property> + </widget> + </item> + <item> + <layout class="QFormLayout" name="formLayout"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::AllNonFixedFieldsGrow</enum> + </property> + <item row="1" column="0"> + <widget class="QLabel" name="lblLabel"> + <property name="text"> + <string>Label:</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="buddy"> + <cstring>lnLabel</cstring> + </property> + </widget> </item> - <item> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0"> - <widget class="QLabel" name="lblLabel"> - <property name="text"> - <string>Label:</string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - <property name="buddy"> - <cstring>lnLabel</cstring> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLineEdit" name="lnLabel"> - <property name="minimumSize"> - <size> - <width>100</width> - <height>0</height> - </size> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="lblMessage"> - <property name="text"> - <string>Message:</string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - <property name="buddy"> - <cstring>lnMessage</cstring> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QLineEdit" name="lnMessage"> - <property name="minimumSize"> - <size> - <width>100</width> - <height>0</height> - </size> - </property> - </widget> - </item> - </layout> + <item row="1" column="1"> + <widget class="QLineEdit" name="lnLabel"/> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="lblMessage"> + <property name="text"> + <string>Message:</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="buddy"> + <cstring>lnMessage</cstring> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="lnMessage"/> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="lblAmount"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Amount:</string> + </property> + <property name="textFormat"> + <enum>Qt::PlainText</enum> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="buddy"> + <cstring>lnReqAmount</cstring> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="BitcoinAmountField" name="lnReqAmount"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> + </widget> </item> </layout> </item> <item> - <layout class="QHBoxLayout" name="horizontalLayout_3"> + <layout class="QHBoxLayout" name="horizontalLayout"> <item> <spacer name="horizontalSpacer"> <property name="orientation"> @@ -194,6 +183,13 @@ </item> </layout> </widget> + <customwidgets> + <customwidget> + <class>BitcoinAmountField</class> + <extends>QSpinBox</extends> + <header>bitcoinamountfield.h</header> + </customwidget> + </customwidgets> <resources/> <connections> <connection> diff --git a/src/qt/forms/transactiondescdialog.ui b/src/qt/forms/transactiondescdialog.ui index 039cb082cc..b38dffcc12 100644 --- a/src/qt/forms/transactiondescdialog.ui +++ b/src/qt/forms/transactiondescdialog.ui @@ -6,7 +6,7 @@ <rect> <x>0</x> <y>0</y> - <width>600</width> + <width>620</width> <height>250</height> </rect> </property> diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h index 54e9d644fe..6f6fa7f261 100644 --- a/src/qt/guiconstants.h +++ b/src/qt/guiconstants.h @@ -25,4 +25,10 @@ static const int STATUSBAR_ICONSIZE = 16; */ static const int TOOLTIP_WRAP_THRESHOLD = 80; +/* Maximum allowed URI length */ +static const int MAX_URI_LENGTH = 255; + +/* QRCodeDialog -- size of exported QR Code image */ +#define EXPORT_IMAGE_SIZE 256 + #endif // GUICONSTANTS_H diff --git a/src/qt/qrcodedialog.cpp b/src/qt/qrcodedialog.cpp index 32e5462cee..ca94975128 100644 --- a/src/qt/qrcodedialog.cpp +++ b/src/qt/qrcodedialog.cpp @@ -1,28 +1,34 @@ #include "qrcodedialog.h" #include "ui_qrcodedialog.h" + +#include "bitcoinunits.h" +#include "guiconstants.h" #include "guiutil.h" +#include "optionsmodel.h" #include <QPixmap> #include <QUrl> -#include <QDebug> #include <qrencode.h> -#define EXPORT_IMAGE_SIZE 256 - QRCodeDialog::QRCodeDialog(const QString &addr, const QString &label, bool enableReq, QWidget *parent) : - QDialog(parent), ui(new Ui::QRCodeDialog), address(addr) + QDialog(parent), + ui(new Ui::QRCodeDialog), + model(0), + address(addr) { ui->setupUi(this); + setWindowTitle(QString("%1").arg(address)); ui->chkReqPayment->setVisible(enableReq); - ui->lnReqAmount->setVisible(enableReq); ui->lblAmount->setVisible(enableReq); - ui->lblBTC->setVisible(enableReq); + ui->lnReqAmount->setVisible(enableReq); ui->lnLabel->setText(label); + ui->btnSaveAs->setEnabled(false); + genCode(); } @@ -31,6 +37,17 @@ QRCodeDialog::~QRCodeDialog() delete ui; } +void QRCodeDialog::setModel(OptionsModel *model) +{ + this->model = model; + + if (model) + connect(model, SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); + + // update the display unit, to not use the default ("BTC") + updateDisplayUnit(); +} + void QRCodeDialog::genCode() { QString uri = getURI(); @@ -57,26 +74,34 @@ void QRCodeDialog::genCode() } } QRcode_free(code); + ui->lblQRCode->setPixmap(QPixmap::fromImage(myImage).scaled(300, 300)); + + ui->outUri->setPlainText(uri); } - else - ui->lblQRCode->setText(tr("Resulting URI too long, try to reduce the text for label / message.")); } QString QRCodeDialog::getURI() { QString ret = QString("bitcoin:%1").arg(address); - int paramCount = 0; - if (ui->chkReqPayment->isChecked() && !ui->lnReqAmount->text().isEmpty()) + + ui->outUri->clear(); + + if (ui->chkReqPayment->isChecked()) { - bool ok = false; - ui->lnReqAmount->text().toDouble(&ok); - if (ok) + if (ui->lnReqAmount->validate()) { - ret += QString("?amount=%1").arg(ui->lnReqAmount->text()); + // even if we allow a non BTC unit input in lnReqAmount, we generate the URI with BTC as unit (as defined in BIP21) + ret += QString("?amount=%1").arg(BitcoinUnits::format(BitcoinUnits::BTC, ui->lnReqAmount->value())); paramCount++; } + else + { + ui->btnSaveAs->setEnabled(false); + ui->lblQRCode->setText(tr("The entered amount is invalid, please check.")); + return QString(""); + } } if (!ui->lnLabel->text().isEmpty()) @@ -93,24 +118,29 @@ QString QRCodeDialog::getURI() paramCount++; } - // limit URI length to 255 chars, to prevent a DoS against the QR-Code dialog - if (ret.length() < 256) - return ret; - else + // limit URI length to prevent a DoS against the QR-Code dialog + if (ret.length() > MAX_URI_LENGTH) + { + ui->btnSaveAs->setEnabled(false); + ui->lblQRCode->setText(tr("Resulting URI too long, try to reduce the text for label / message.")); return QString(""); + } + + ui->btnSaveAs->setEnabled(true); + return ret; } -void QRCodeDialog::on_lnReqAmount_textChanged(const QString &arg1) +void QRCodeDialog::on_lnReqAmount_textChanged() { genCode(); } -void QRCodeDialog::on_lnLabel_textChanged(const QString &arg1) +void QRCodeDialog::on_lnLabel_textChanged() { genCode(); } -void QRCodeDialog::on_lnMessage_textChanged(const QString &arg1) +void QRCodeDialog::on_lnMessage_textChanged() { genCode(); } @@ -122,7 +152,20 @@ void QRCodeDialog::on_btnSaveAs_clicked() myImage.scaled(EXPORT_IMAGE_SIZE, EXPORT_IMAGE_SIZE).save(fn); } -void QRCodeDialog::on_chkReqPayment_toggled(bool) +void QRCodeDialog::on_chkReqPayment_toggled(bool fChecked) { + if (!fChecked) + // if chkReqPayment is not active, don't display lnReqAmount as invalid + ui->lnReqAmount->setValid(true); + genCode(); } + +void QRCodeDialog::updateDisplayUnit() +{ + if (model) + { + // Update lnReqAmount with the current unit + ui->lnReqAmount->setDisplayUnit(model->getDisplayUnit()); + } +} diff --git a/src/qt/qrcodedialog.h b/src/qt/qrcodedialog.h index ad0611605b..c55c34bce6 100644 --- a/src/qt/qrcodedialog.h +++ b/src/qt/qrcodedialog.h @@ -7,6 +7,7 @@ namespace Ui { class QRCodeDialog; } +class OptionsModel; class QRCodeDialog : public QDialog { @@ -16,22 +17,25 @@ public: explicit QRCodeDialog(const QString &addr, const QString &label, bool enableReq, QWidget *parent = 0); ~QRCodeDialog(); + void setModel(OptionsModel *model); + private slots: - void on_lnReqAmount_textChanged(const QString &arg1); - void on_lnLabel_textChanged(const QString &arg1); - void on_lnMessage_textChanged(const QString &arg1); + void on_lnReqAmount_textChanged(); + void on_lnLabel_textChanged(); + void on_lnMessage_textChanged(); void on_btnSaveAs_clicked(); + void on_chkReqPayment_toggled(bool fChecked); - void on_chkReqPayment_toggled(bool checked); + void updateDisplayUnit(); private: Ui::QRCodeDialog *ui; - QImage myImage; - - QString getURI(); + OptionsModel *model; QString address; + QImage myImage; void genCode(); + QString getURI(); }; #endif // QRCODEDIALOG_H diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 834abee470..3e7eca59ca 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -9,16 +9,12 @@ #include "ui_interface.h" #include "base58.h" -#include <QString> - -using namespace std; - QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx) { if (!wtx.IsFinal()) { if (wtx.nLockTime < LOCKTIME_THRESHOLD) - return tr("Open for %1 blocks").arg(nBestHeight - wtx.nLockTime); + return tr("Open for %n block(s)", "", nBestHeight - wtx.nLockTime); else return tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx.nLockTime)); } @@ -26,7 +22,7 @@ QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx) { int nDepth = wtx.GetDepthInMainChain(); if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0) - return tr("%1/offline?").arg(nDepth); + return tr("%1/offline").arg(nDepth); else if (nDepth < 6) return tr("%1/unconfirmed").arg(nDepth); else @@ -48,33 +44,31 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) int64 nDebit = wtx.GetDebit(); int64 nNet = nCredit - nDebit; - strHTML += tr("<b>Status:</b> ") + FormatTxStatus(wtx); + strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx); int nRequests = wtx.GetRequestCount(); if (nRequests != -1) { if (nRequests == 0) strHTML += tr(", has not been successfully broadcast yet"); - else if (nRequests == 1) - strHTML += tr(", broadcast through %1 node").arg(nRequests); - else - strHTML += tr(", broadcast through %1 nodes").arg(nRequests); + else if (nRequests > 0) + strHTML += tr(", broadcast through %n node(s)", "", nRequests); } strHTML += "<br>"; - strHTML += tr("<b>Date:</b> ") + (nTime ? GUIUtil::dateTimeStr(nTime) : QString("")) + "<br>"; + strHTML += "<b>" + tr("Date") + ":</b> " + (nTime ? GUIUtil::dateTimeStr(nTime) : "") + "<br>"; // // From // if (wtx.IsCoinBase()) { - strHTML += tr("<b>Source:</b> Generated<br>"); + strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>"; } else if (!wtx.mapValue["from"].empty()) { // Online transaction if (!wtx.mapValue["from"].empty()) - strHTML += tr("<b>From:</b> ") + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "<br>"; + strHTML += "<b>" + tr("From") + ":</b> " + GUIUtil::HtmlEscape(wtx.mapValue["from"]) + "<br>"; } else { @@ -91,13 +85,13 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) { if (wallet->mapAddressBook.count(address)) { - strHTML += tr("<b>From:</b> ") + tr("unknown") + "<br>"; - strHTML += tr("<b>To:</b> "); + strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>"; + strHTML += "<b>" + tr("To") + ":</b> "; strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString()); if (!wallet->mapAddressBook[address].empty()) - strHTML += tr(" (yours, label: ") + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")"; + strHTML += " (" + tr("own address") + ", " + tr("label") + ": " + GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + ")"; else - strHTML += tr(" (yours)"); + strHTML += " (" + tr("own address") + ")"; strHTML += "<br>"; } } @@ -110,12 +104,11 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) // // To // - string strAddress; if (!wtx.mapValue["to"].empty()) { // Online transaction - strAddress = wtx.mapValue["to"]; - strHTML += tr("<b>To:</b> "); + std::string strAddress = wtx.mapValue["to"]; + strHTML += "<b>" + tr("To") + ":</b> "; CTxDestination dest = CBitcoinAddress(strAddress).Get(); if (wallet->mapAddressBook.count(dest) && !wallet->mapAddressBook[dest].empty()) strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[dest]) + " "; @@ -133,13 +126,11 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) int64 nUnmatured = 0; BOOST_FOREACH(const CTxOut& txout, wtx.vout) nUnmatured += wallet->GetCredit(txout); - strHTML += tr("<b>Credit:</b> "); + strHTML += "<b>" + tr("Credit") + ":</b> "; if (wtx.IsInMainChain()) - strHTML += tr("(%1 matures in %2 more blocks)") - .arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nUnmatured)) - .arg(wtx.GetBlocksToMaturity()); + strHTML += BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", wtx.GetBlocksToMaturity()) + ")"; else - strHTML += tr("(not accepted)"); + strHTML += "(" + tr("not accepted") + ")"; strHTML += "<br>"; } else if (nNet > 0) @@ -147,7 +138,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) // // Credit // - strHTML += tr("<b>Credit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet) + "<br>"; + strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet) + "<br>"; } else { @@ -175,7 +166,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) CTxDestination address; if (ExtractDestination(txout.scriptPubKey, address)) { - strHTML += tr("<b>To:</b> "); + strHTML += "<b>" + tr("To") + ":</b> "; if (wallet->mapAddressBook.count(address) && !wallet->mapAddressBook[address].empty()) strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " "; strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString()); @@ -183,7 +174,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) } } - strHTML += tr("<b>Debit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -txout.nValue) + "<br>"; + strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -txout.nValue) + "<br>"; } if (fAllToMe) @@ -191,13 +182,13 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) // Payment to self int64 nChange = wtx.GetChange(); int64 nValue = nCredit - nChange; - strHTML += tr("<b>Debit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nValue) + "<br>"; - strHTML += tr("<b>Credit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nValue) + "<br>"; + strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nValue) + "<br>"; + strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nValue) + "<br>"; } int64 nTxFee = nDebit - wtx.GetValueOut(); if (nTxFee > 0) - strHTML += tr("<b>Transaction fee:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,-nTxFee) + "<br>"; + strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -nTxFee) + "<br>"; } else { @@ -206,47 +197,47 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) // BOOST_FOREACH(const CTxIn& txin, wtx.vin) if (wallet->IsMine(txin)) - strHTML += tr("<b>Debit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,-wallet->GetDebit(txin)) + "<br>"; + strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "<br>"; BOOST_FOREACH(const CTxOut& txout, wtx.vout) if (wallet->IsMine(txout)) - strHTML += tr("<b>Credit:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,wallet->GetCredit(txout)) + "<br>"; + strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "<br>"; } } - strHTML += tr("<b>Net amount:</b> ") + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,nNet, true) + "<br>"; + strHTML += "<b>" + tr("Net amount") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, nNet, true) + "<br>"; // // Message // if (!wtx.mapValue["message"].empty()) - strHTML += QString("<br><b>") + tr("Message:") + "</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "<br>"; + strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["message"], true) + "<br>"; if (!wtx.mapValue["comment"].empty()) - strHTML += QString("<br><b>") + tr("Comment:") + "</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "<br>"; + strHTML += "<br><b>" + tr("Comment") + ":</b><br>" + GUIUtil::HtmlEscape(wtx.mapValue["comment"], true) + "<br>"; - strHTML += QString("<b>") + tr("Transaction ID:") + "</b> " + wtx.GetHash().ToString().c_str() + "<br>"; + strHTML += "<b>" + tr("Transaction ID") + ":</b> " + wtx.GetHash().ToString().c_str() + "<br>"; if (wtx.IsCoinBase()) - strHTML += QString("<br>") + tr("Generated coins must mature 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.") + "<br>"; + strHTML += "<br>" + tr("Generated coins must mature 120 blocks before they can be spent. When you generated this block, it was broadcast to the network to be added to the block chain. If it fails to get into the chain, its state will change to \"not accepted\" and it won't be spendable. This may occasionally happen if another node generates a block within a few seconds of yours.") + "<br>"; // // Debug view // if (fDebug) { - strHTML += "<hr><br>Debug information<br><br>"; + strHTML += "<hr><br>" + tr("Debug information") + "<br><br>"; BOOST_FOREACH(const CTxIn& txin, wtx.vin) if(wallet->IsMine(txin)) - strHTML += "<b>Debit:</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,-wallet->GetDebit(txin)) + "<br>"; + strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, -wallet->GetDebit(txin)) + "<br>"; BOOST_FOREACH(const CTxOut& txout, wtx.vout) if(wallet->IsMine(txout)) - strHTML += "<b>Credit:</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,wallet->GetCredit(txout)) + "<br>"; + strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, wallet->GetCredit(txout)) + "<br>"; - strHTML += "<br><b>Transaction:</b><br>"; + strHTML += "<br><b>" + tr("Transaction") + ":</b><br>"; strHTML += GUIUtil::HtmlEscape(wtx.ToString(), true); CTxDB txdb("r"); // To fetch source txouts - strHTML += "<br><b>Inputs:</b>"; + strHTML += "<br><b>" + tr("Inputs") + ":</b>"; strHTML += "<ul>"; { @@ -269,12 +260,13 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) strHTML += GUIUtil::HtmlEscape(wallet->mapAddressBook[address]) + " "; strHTML += QString::fromStdString(CBitcoinAddress(address).ToString()); } - strHTML = strHTML + " Amount=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC,vout.nValue); - strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? "true" : "false") + "</li>"; + strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, vout.nValue); + strHTML = strHTML + " IsMine=" + (wallet->IsMine(vout) ? tr("true") : tr("false")) + "</li>"; } } } } + strHTML += "</ul>"; } diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 9245f774a4..0111e0cd91 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -10,17 +10,27 @@ #include "base58.h" #include <QSet> +#include <QTimer> WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) : QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0), transactionTableModel(0), cachedBalance(0), cachedUnconfirmedBalance(0), cachedImmatureBalance(0), cachedNumTransactions(0), - cachedEncryptionStatus(Unencrypted) + cachedEncryptionStatus(Unencrypted), + cachedNumBlocks(0) { addressTableModel = new AddressTableModel(wallet, this); transactionTableModel = new TransactionTableModel(wallet, this); + // This single-shot timer will be fired from the 'checkBalancedChanged' + // method repeatedly while either of the unconfirmed or immature balances + // are non-zero + pollTimer = new QTimer(this); + pollTimer->setInterval(MODEL_UPDATE_DELAY); + pollTimer->setSingleShot(true); + connect(pollTimer, SIGNAL(timeout()), this, SLOT(pollBalanceChanged())); + subscribeToCoreSignals(); } @@ -62,27 +72,47 @@ void WalletModel::updateStatus() emit encryptionStatusChanged(newEncryptionStatus); } -void WalletModel::updateTransaction(const QString &hash, int status) +void WalletModel::pollBalanceChanged() { - if(transactionTableModel) - transactionTableModel->updateTransaction(hash, status); + if(nBestHeight != cachedNumBlocks) { + cachedNumBlocks = nBestHeight; + checkBalanceChanged(); + } - // Balance and number of transactions might have changed + if(cachedUnconfirmedBalance || cachedImmatureBalance) + pollTimer->start(); +} + +void WalletModel::checkBalanceChanged() +{ qint64 newBalance = getBalance(); qint64 newUnconfirmedBalance = getUnconfirmedBalance(); qint64 newImmatureBalance = getImmatureBalance(); - int newNumTransactions = getNumTransactions(); - if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance || cachedImmatureBalance != newImmatureBalance) + if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance || cachedImmatureBalance != newImmatureBalance) { + cachedBalance = newBalance; + cachedUnconfirmedBalance = newUnconfirmedBalance; + cachedImmatureBalance = newImmatureBalance; emit balanceChanged(newBalance, newUnconfirmedBalance, newImmatureBalance); + } +} - if(cachedNumTransactions != newNumTransactions) - emit numTransactionsChanged(newNumTransactions); +void WalletModel::updateTransaction(const QString &hash, int status) +{ + if(transactionTableModel) + transactionTableModel->updateTransaction(hash, status); - cachedBalance = newBalance; - cachedUnconfirmedBalance = newUnconfirmedBalance; - cachedImmatureBalance = newImmatureBalance; - cachedNumTransactions = newNumTransactions; + // Balance and number of transactions might have changed + checkBalanceChanged(); + + if(cachedUnconfirmedBalance || cachedImmatureBalance) + pollTimer->start(); + + int newNumTransactions = getNumTransactions(); + if(cachedNumTransactions != newNumTransactions) { + emit numTransactionsChanged(newNumTransactions); + cachedNumTransactions = newNumTransactions; + } } void WalletModel::updateAddressBook(const QString &address, const QString &label, bool isMine, int status) diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index c973c5cf53..62558a49df 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -10,6 +10,10 @@ class AddressTableModel; class TransactionTableModel; class CWallet; +QT_BEGIN_NAMESPACE +class QTimer; +QT_END_NAMESPACE + class SendCoinsRecipient { public: @@ -120,9 +124,14 @@ private: qint64 cachedImmatureBalance; qint64 cachedNumTransactions; EncryptionStatus cachedEncryptionStatus; + int cachedNumBlocks; + + QTimer *pollTimer; void subscribeToCoreSignals(); void unsubscribeFromCoreSignals(); + void checkBalanceChanged(); + signals: // Signal that balance in wallet changed void balanceChanged(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance); @@ -148,6 +157,8 @@ public slots: void updateTransaction(const QString &hash, int status); /* New, updated or removed address book entry */ void updateAddressBook(const QString &address, const QString &label, bool isMine, int status); + /* Current, immature or unconfirmed balance might have changed - emit 'balanceChanged' if so */ + void pollBalanceChanged(); }; |