From 1c5f0af0fd8b5630470d471d8319a7c979aa2587 Mon Sep 17 00:00:00 2001 From: Cozz Lovan Date: Sun, 10 Aug 2014 02:26:04 +0200 Subject: [PATCH] [Qt] Add column Watch-only to transactions list --- src/Makefile.qt.include | 3 +++ src/qt/bitcoin.qrc | 3 +++ src/qt/overviewpage.cpp | 10 +++++++++- src/qt/res/icons/eye.png | Bin 0 -> 536 bytes src/qt/res/icons/eye_minus.png | Bin 0 -> 595 bytes src/qt/res/icons/eye_plus.png | Bin 0 -> 661 bytes src/qt/transactionfilterproxy.cpp | 12 +++++++++++ src/qt/transactionfilterproxy.h | 9 +++++++++ src/qt/transactiontablemodel.cpp | 32 ++++++++++++++++++++++-------- src/qt/transactiontablemodel.h | 14 +++++++++---- src/qt/transactionview.cpp | 32 ++++++++++++++++++++++++++++++ src/qt/transactionview.h | 4 ++++ 12 files changed, 106 insertions(+), 13 deletions(-) create mode 100644 src/qt/res/icons/eye.png create mode 100644 src/qt/res/icons/eye_minus.png create mode 100644 src/qt/res/icons/eye_plus.png diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 2052264dc..eef0c317c 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -233,6 +233,9 @@ RES_ICONS = \ qt/res/icons/editcopy.png \ qt/res/icons/editpaste.png \ qt/res/icons/export.png \ + qt/res/icons/eye.png \ + qt/res/icons/eye_minus.png \ + qt/res/icons/eye_plus.png \ qt/res/icons/filesave.png \ qt/res/icons/history.png \ qt/res/icons/key.png \ diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc index 357c6470d..9a7003938 100644 --- a/src/qt/bitcoin.qrc +++ b/src/qt/bitcoin.qrc @@ -18,6 +18,9 @@ res/icons/clock3.png res/icons/clock4.png res/icons/clock5.png + res/icons/eye.png + res/icons/eye_minus.png + res/icons/eye_plus.png res/icons/configure.png res/icons/receive.png res/icons/editpaste.png diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 8eed0856e..15501b8a8 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -57,7 +57,15 @@ public: } painter->setPen(foreground); - painter->drawText(addressRect, Qt::AlignLeft|Qt::AlignVCenter, address); + QRect boundingRect; + painter->drawText(addressRect, Qt::AlignLeft|Qt::AlignVCenter, address, &boundingRect); + + if (index.data(TransactionTableModel::WatchonlyRole).toBool()) + { + QIcon iconWatchonly = qvariant_cast(index.data(TransactionTableModel::WatchonlyDecorationRole)); + QRect watchonlyRect(boundingRect.right() + 5, mainRect.top()+ypad+halfheight, 16, halfheight); + iconWatchonly.paint(painter, watchonlyRect); + } if(amount < 0) { diff --git a/src/qt/res/icons/eye.png b/src/qt/res/icons/eye.png new file mode 100644 index 0000000000000000000000000000000000000000..c4d182adbf4ed1140b7c715517e07802758ddeb5 GIT binary patch literal 536 zcmV+z0_XjSP)W;VR5&6(dO?x@e&|q%ht7 zGdR6~s}6iHbMN{8bI!dp0_U795)QUtENmbktcUq1YhWKJAOw8#yf2`G8h8RDTW1>x zFgSI)-DirTY~^w}zou!cjYh*oo3bp=B9X|XR4NT?wc7i1IxRwXM|Eig4>(UG5*PJ) zU9MCr+oox*2Lb`tWMVJ^A{VXE9_3IjX)LYN=}e>Q<6tnD8iv6MRaH4fv3Sj8`G70R z2}f7l-ltsBkah_!*<>>5L;J4TY-Y_>C=^iHWS5s$)_XV{WuKpK%-*M5(x6b53~pMj z*7|5P+V&tQL6Rh<&*$^^IE!1l6#;YDSCK>m$LVxBn#p9MyAos(@~e-|qt0(OBPc<1Y5Fa$3^1BU(W2><_ISlHlK afB^v9dC^iz-u#^a0000)U=I<(!Y-aX7<9>mi9o?H_F_AoLP-|H z4jl}~6vtoR_rvL6#}518BhI|{{l53}_jCy%=zqd>^#%y}Wnpw3+ygoY1OKA#C+L70 z_y~rM&N1Lg9xICSRM++GY&N@Tn&!1eqv7SGrfJh?G&(AkNcG_r_+$jk3I$2DBb8maYoJZW_OFc=IbmSqXXFbu&_ zES?BWI}p15NMI`AB+ zCf4iqZnfL(b?z9C$A1Nb!G5`1zNl8K7vb^v{T(4bJ(L`rG;P|h%(7N? zksjJjCUg*CEp!mX6%78ugHYL_SD6<<@ZcXH^f1|F6N?lSu~1OyVK)nzLJP&RAmY-) zDt2N!snUU!#|yklGG1}!`*B)`?XLgeCYLh z8Pu&(UmHGL$gOBJdZ$<{O8I<#$~4WfKp-G=yE+gk5@?KaR716-v9vtTpU19ityZh2 z>pCM8MPU?~%p)dAb4->mGn^G0=Bbu6q_v~Vd@L68;q--mzi+K8l}ce}6INEz*7wB3 zG&CAj80M*#G}vgK44zafm9b8zGv&gdf?zNRic*Hz*>je_<#K|<5&Uhii-DR?q~&ck z+n0L1J}8&VW+W0h?)7>{alN2v?;#Wt!Rz&5cMan4Gmti(!rjfKz2%qb&)Va+_vuu~ zz{DNhXf~VMxm@mhtyXJ`qR6}54xw6oBedIFAd2B1e!qX~UgLrN;)P3|Vx#;GY;a?6 z+hcIJ5imScj1eS^oJPixQ5rNC+%h}K`$6FJL?UtO`RWUG|MGx(*x-*~lRTI=-RpB# z<1>eIukveuH!v1QsMABlGMK(5&TKq;w?6|8RQr)GJc9)=@T%{z^&Jy$_0Iu-gNuNj v1N)Kxnid|R!PM==O+cYaVmRT1UjhsOT9g3B;L;7y00000NkvXXu0mjfDrh(C literal 0 HcmV?d00001 diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp index f9546fddb..6ab029173 100644 --- a/src/qt/transactionfilterproxy.cpp +++ b/src/qt/transactionfilterproxy.cpp @@ -22,6 +22,7 @@ TransactionFilterProxy::TransactionFilterProxy(QObject *parent) : dateTo(MAX_DATE), addrPrefix(), typeFilter(ALL_TYPES), + watchOnlyFilter(WatchOnlyFilter_All), minAmount(0), limitRows(-1), showInactive(true) @@ -34,6 +35,7 @@ bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex & int type = index.data(TransactionTableModel::TypeRole).toInt(); QDateTime datetime = index.data(TransactionTableModel::DateRole).toDateTime(); + bool involvesWatchAddress = index.data(TransactionTableModel::WatchonlyRole).toBool(); QString address = index.data(TransactionTableModel::AddressRole).toString(); QString label = index.data(TransactionTableModel::LabelRole).toString(); qint64 amount = llabs(index.data(TransactionTableModel::AmountRole).toLongLong()); @@ -43,6 +45,10 @@ bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex & return false; if(!(TYPE(type) & typeFilter)) return false; + if (involvesWatchAddress && watchOnlyFilter == WatchOnlyFilter_No) + return false; + if (!involvesWatchAddress && watchOnlyFilter == WatchOnlyFilter_Yes) + return false; if(datetime < dateFrom || datetime > dateTo) return false; if (!address.contains(addrPrefix, Qt::CaseInsensitive) && !label.contains(addrPrefix, Qt::CaseInsensitive)) @@ -78,6 +84,12 @@ void TransactionFilterProxy::setMinAmount(qint64 minimum) invalidateFilter(); } +void TransactionFilterProxy::setWatchOnlyFilter(WatchOnlyFilter filter) +{ + this->watchOnlyFilter = filter; + invalidateFilter(); +} + void TransactionFilterProxy::setLimit(int limit) { this->limitRows = limit; diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h index 9919bc3fd..f408317b5 100644 --- a/src/qt/transactionfilterproxy.h +++ b/src/qt/transactionfilterproxy.h @@ -25,6 +25,13 @@ public: static quint32 TYPE(int type) { return 1<getOptionsModel()->getDisplayUnit()); + columns << QString() << QString() << tr("Date") << tr("Type") << tr("Address") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit()); priv->refreshWallet(); connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); @@ -393,22 +394,19 @@ QVariant TransactionTableModel::txAddressDecoration(const TransactionRecord *wtx QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const { - // mark transactions involving watch-only addresses: - QString watchAddress = wtx->involvesWatchAddress ? " (w) " : ""; - switch(wtx->type) { case TransactionRecord::RecvFromOther: - return QString::fromStdString(wtx->address) + watchAddress; + return QString::fromStdString(wtx->address); case TransactionRecord::RecvWithAddress: case TransactionRecord::SendToAddress: case TransactionRecord::Generated: - return lookupAddress(wtx->address, tooltip) + watchAddress; + return lookupAddress(wtx->address, tooltip); case TransactionRecord::SendToOther: - return QString::fromStdString(wtx->address) + watchAddress; + return QString::fromStdString(wtx->address); case TransactionRecord::SendToSelf: default: - return tr("(n/a)") + watchAddress; + return tr("(n/a)"); } } @@ -482,6 +480,14 @@ QVariant TransactionTableModel::txStatusDecoration(const TransactionRecord *wtx) return QColor(0,0,0); } +QVariant TransactionTableModel::txWatchonlyDecoration(const TransactionRecord *wtx) const +{ + if (wtx->involvesWatchAddress) + return QIcon(":/icons/eye"); + else + return QVariant(); +} + QString TransactionTableModel::formatTooltip(const TransactionRecord *rec) const { QString tooltip = formatTxStatus(rec) + QString("\n") + formatTxType(rec); @@ -506,6 +512,8 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const { case Status: return txStatusDecoration(rec); + case Watchonly: + return txWatchonlyDecoration(rec); case ToAddress: return txAddressDecoration(rec); } @@ -533,6 +541,8 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const return rec->time; case Type: return formatTxType(rec); + case Watchonly: + return (rec->involvesWatchAddress ? 1 : 0); case ToAddress: return formatTxToAddress(rec, true); case Amount: @@ -562,6 +572,10 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const return rec->type; case DateRole: return QDateTime::fromTime_t(static_cast(rec->time)); + case WatchonlyRole: + return rec->involvesWatchAddress; + case WatchonlyDecorationRole: + return txWatchonlyDecoration(rec); case LongDescriptionRole: return priv->describe(rec, walletModel->getOptionsModel()->getDisplayUnit()); case AddressRole: @@ -606,6 +620,8 @@ QVariant TransactionTableModel::headerData(int section, Qt::Orientation orientat return tr("Date and time that the transaction was received."); case Type: return tr("Type of transaction."); + case Watchonly: + return tr("Whether or not a watch-only address is involved in this transaction."); case ToAddress: return tr("Destination address of transaction."); case Amount: diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h index 2124d3dd1..413f3f9bf 100644 --- a/src/qt/transactiontablemodel.h +++ b/src/qt/transactiontablemodel.h @@ -28,10 +28,11 @@ public: enum ColumnIndex { Status = 0, - Date = 1, - Type = 2, - ToAddress = 3, - Amount = 4 + Watchonly = 1, + Date = 2, + Type = 3, + ToAddress = 4, + Amount = 5 }; /** Roles to get specific information from a transaction row. @@ -42,6 +43,10 @@ public: TypeRole = Qt::UserRole, /** Date and time this transaction was created */ DateRole, + /** Watch-only boolean */ + WatchonlyRole, + /** Watch-only icon */ + WatchonlyDecorationRole, /** Long description (HTML format) */ LongDescriptionRole, /** Address of transaction */ @@ -83,6 +88,7 @@ private: QString formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed=true, BitcoinUnits::SeparatorStyle separators=BitcoinUnits::separatorStandard) const; QString formatTooltip(const TransactionRecord *rec) const; QVariant txStatusDecoration(const TransactionRecord *wtx) const; + QVariant txWatchonlyDecoration(const TransactionRecord *wtx) const; QVariant txAddressDecoration(const TransactionRecord *wtx) const; public slots: diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index 7e8b71d8e..2d34d5812 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -51,6 +51,13 @@ TransactionView::TransactionView(QWidget *parent) : hlayout->addSpacing(23); #endif + watchOnlyWidget = new QComboBox(this); + watchOnlyWidget->setFixedWidth(24); + watchOnlyWidget->addItem("", TransactionFilterProxy::WatchOnlyFilter_All); + watchOnlyWidget->addItem(QIcon(":/icons/eye_plus"), "", TransactionFilterProxy::WatchOnlyFilter_Yes); + watchOnlyWidget->addItem(QIcon(":/icons/eye_minus"), "", TransactionFilterProxy::WatchOnlyFilter_No); + hlayout->addWidget(watchOnlyWidget); + dateWidget = new QComboBox(this); #ifdef Q_OS_MAC dateWidget->setFixedWidth(121); @@ -150,6 +157,7 @@ TransactionView::TransactionView(QWidget *parent) : connect(dateWidget, SIGNAL(activated(int)), this, SLOT(chooseDate(int))); connect(typeWidget, SIGNAL(activated(int)), this, SLOT(chooseType(int))); + connect(watchOnlyWidget, SIGNAL(activated(int)), this, SLOT(chooseWatchonly(int))); connect(addressWidget, SIGNAL(textChanged(QString)), this, SLOT(changedPrefix(QString))); connect(amountWidget, SIGNAL(textChanged(QString)), this, SLOT(changedAmount(QString))); @@ -187,6 +195,7 @@ void TransactionView::setModel(WalletModel *model) transactionView->verticalHeader()->hide(); transactionView->setColumnWidth(TransactionTableModel::Status, STATUS_COLUMN_WIDTH); + transactionView->setColumnWidth(TransactionTableModel::Watchonly, WATCHONLY_COLUMN_WIDTH); transactionView->setColumnWidth(TransactionTableModel::Date, DATE_COLUMN_WIDTH); transactionView->setColumnWidth(TransactionTableModel::Type, TYPE_COLUMN_WIDTH); transactionView->setColumnWidth(TransactionTableModel::Amount, AMOUNT_MINIMUM_COLUMN_WIDTH); @@ -211,6 +220,12 @@ void TransactionView::setModel(WalletModel *model) } } } + + // show/hide column Watch-only + updateWatchOnlyColumn(model->haveWatchOnly()); + + // Watch-only signal + connect(model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyColumn(bool))); } } @@ -270,6 +285,14 @@ void TransactionView::chooseType(int idx) typeWidget->itemData(idx).toInt()); } +void TransactionView::chooseWatchonly(int idx) +{ + if(!transactionProxyModel) + return; + transactionProxyModel->setWatchOnlyFilter( + (TransactionFilterProxy::WatchOnlyFilter)watchOnlyWidget->itemData(idx).toInt()); +} + void TransactionView::changedPrefix(const QString &prefix) { if(!transactionProxyModel) @@ -307,6 +330,8 @@ void TransactionView::exportClicked() // name, column, role writer.setModel(transactionProxyModel); writer.addColumn(tr("Confirmed"), 0, TransactionTableModel::ConfirmedRole); + if (model && model->haveWatchOnly()) + writer.addColumn(tr("Watchonly"), TransactionTableModel::Watchonly); writer.addColumn(tr("Date"), 0, TransactionTableModel::DateRole); writer.addColumn(tr("Type"), TransactionTableModel::Type, Qt::EditRole); writer.addColumn(tr("Label"), 0, TransactionTableModel::LabelRole); @@ -501,3 +526,10 @@ bool TransactionView::eventFilter(QObject *obj, QEvent *event) } return QWidget::eventFilter(obj, event); } + +// show/hide column Watch-only +void TransactionView::updateWatchOnlyColumn(bool fHaveWatchOnly) +{ + watchOnlyWidget->setVisible(fHaveWatchOnly); + transactionView->setColumnHidden(TransactionTableModel::Watchonly, !fHaveWatchOnly); +} diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h index 618efbc56..b249e0041 100644 --- a/src/qt/transactionview.h +++ b/src/qt/transactionview.h @@ -50,6 +50,7 @@ public: enum ColumnWidths { STATUS_COLUMN_WIDTH = 23, + WATCHONLY_COLUMN_WIDTH = 23, DATE_COLUMN_WIDTH = 120, TYPE_COLUMN_WIDTH = 120, AMOUNT_MINIMUM_COLUMN_WIDTH = 120, @@ -63,6 +64,7 @@ private: QComboBox *dateWidget; QComboBox *typeWidget; + QComboBox *watchOnlyWidget; QLineEdit *addressWidget; QLineEdit *amountWidget; @@ -91,6 +93,7 @@ private slots: void copyAmount(); void copyTxID(); void openThirdPartyTxUrl(QString url); + void updateWatchOnlyColumn(bool fHaveWatchOnly); signals: void doubleClicked(const QModelIndex&); @@ -101,6 +104,7 @@ signals: public slots: void chooseDate(int idx); void chooseType(int idx); + void chooseWatchonly(int idx); void changedPrefix(const QString &prefix); void changedAmount(const QString &amount); void exportClicked();