[Qt] Add column Watch-only to transactions list

This commit is contained in:
Cozz Lovan 2014-08-10 02:26:04 +02:00
parent 939ed97373
commit 1c5f0af0fd
12 changed files with 106 additions and 13 deletions

View file

@ -233,6 +233,9 @@ RES_ICONS = \
qt/res/icons/editcopy.png \ qt/res/icons/editcopy.png \
qt/res/icons/editpaste.png \ qt/res/icons/editpaste.png \
qt/res/icons/export.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/filesave.png \
qt/res/icons/history.png \ qt/res/icons/history.png \
qt/res/icons/key.png \ qt/res/icons/key.png \

View file

@ -18,6 +18,9 @@
<file alias="transaction_3">res/icons/clock3.png</file> <file alias="transaction_3">res/icons/clock3.png</file>
<file alias="transaction_4">res/icons/clock4.png</file> <file alias="transaction_4">res/icons/clock4.png</file>
<file alias="transaction_5">res/icons/clock5.png</file> <file alias="transaction_5">res/icons/clock5.png</file>
<file alias="eye">res/icons/eye.png</file>
<file alias="eye_minus">res/icons/eye_minus.png</file>
<file alias="eye_plus">res/icons/eye_plus.png</file>
<file alias="options">res/icons/configure.png</file> <file alias="options">res/icons/configure.png</file>
<file alias="receiving_addresses">res/icons/receive.png</file> <file alias="receiving_addresses">res/icons/receive.png</file>
<file alias="editpaste">res/icons/editpaste.png</file> <file alias="editpaste">res/icons/editpaste.png</file>

View file

@ -57,7 +57,15 @@ public:
} }
painter->setPen(foreground); 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<QIcon>(index.data(TransactionTableModel::WatchonlyDecorationRole));
QRect watchonlyRect(boundingRect.right() + 5, mainRect.top()+ypad+halfheight, 16, halfheight);
iconWatchonly.paint(painter, watchonlyRect);
}
if(amount < 0) if(amount < 0)
{ {

BIN
src/qt/res/icons/eye.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 595 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 B

View file

@ -22,6 +22,7 @@ TransactionFilterProxy::TransactionFilterProxy(QObject *parent) :
dateTo(MAX_DATE), dateTo(MAX_DATE),
addrPrefix(), addrPrefix(),
typeFilter(ALL_TYPES), typeFilter(ALL_TYPES),
watchOnlyFilter(WatchOnlyFilter_All),
minAmount(0), minAmount(0),
limitRows(-1), limitRows(-1),
showInactive(true) showInactive(true)
@ -34,6 +35,7 @@ bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex &
int type = index.data(TransactionTableModel::TypeRole).toInt(); int type = index.data(TransactionTableModel::TypeRole).toInt();
QDateTime datetime = index.data(TransactionTableModel::DateRole).toDateTime(); QDateTime datetime = index.data(TransactionTableModel::DateRole).toDateTime();
bool involvesWatchAddress = index.data(TransactionTableModel::WatchonlyRole).toBool();
QString address = index.data(TransactionTableModel::AddressRole).toString(); QString address = index.data(TransactionTableModel::AddressRole).toString();
QString label = index.data(TransactionTableModel::LabelRole).toString(); QString label = index.data(TransactionTableModel::LabelRole).toString();
qint64 amount = llabs(index.data(TransactionTableModel::AmountRole).toLongLong()); qint64 amount = llabs(index.data(TransactionTableModel::AmountRole).toLongLong());
@ -43,6 +45,10 @@ bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex &
return false; return false;
if(!(TYPE(type) & typeFilter)) if(!(TYPE(type) & typeFilter))
return false; return false;
if (involvesWatchAddress && watchOnlyFilter == WatchOnlyFilter_No)
return false;
if (!involvesWatchAddress && watchOnlyFilter == WatchOnlyFilter_Yes)
return false;
if(datetime < dateFrom || datetime > dateTo) if(datetime < dateFrom || datetime > dateTo)
return false; return false;
if (!address.contains(addrPrefix, Qt::CaseInsensitive) && !label.contains(addrPrefix, Qt::CaseInsensitive)) if (!address.contains(addrPrefix, Qt::CaseInsensitive) && !label.contains(addrPrefix, Qt::CaseInsensitive))
@ -78,6 +84,12 @@ void TransactionFilterProxy::setMinAmount(qint64 minimum)
invalidateFilter(); invalidateFilter();
} }
void TransactionFilterProxy::setWatchOnlyFilter(WatchOnlyFilter filter)
{
this->watchOnlyFilter = filter;
invalidateFilter();
}
void TransactionFilterProxy::setLimit(int limit) void TransactionFilterProxy::setLimit(int limit)
{ {
this->limitRows = limit; this->limitRows = limit;

View file

@ -25,6 +25,13 @@ public:
static quint32 TYPE(int type) { return 1<<type; } static quint32 TYPE(int type) { return 1<<type; }
enum WatchOnlyFilter
{
WatchOnlyFilter_All,
WatchOnlyFilter_Yes,
WatchOnlyFilter_No
};
void setDateRange(const QDateTime &from, const QDateTime &to); void setDateRange(const QDateTime &from, const QDateTime &to);
void setAddressPrefix(const QString &addrPrefix); void setAddressPrefix(const QString &addrPrefix);
/** /**
@ -32,6 +39,7 @@ public:
*/ */
void setTypeFilter(quint32 modes); void setTypeFilter(quint32 modes);
void setMinAmount(qint64 minimum); void setMinAmount(qint64 minimum);
void setWatchOnlyFilter(WatchOnlyFilter filter);
/** Set maximum number of rows returned, -1 if unlimited. */ /** Set maximum number of rows returned, -1 if unlimited. */
void setLimit(int limit); void setLimit(int limit);
@ -49,6 +57,7 @@ private:
QDateTime dateTo; QDateTime dateTo;
QString addrPrefix; QString addrPrefix;
quint32 typeFilter; quint32 typeFilter;
WatchOnlyFilter watchOnlyFilter;
qint64 minAmount; qint64 minAmount;
int limitRows; int limitRows;
bool showInactive; bool showInactive;

View file

@ -27,6 +27,7 @@
// Amount column is right-aligned it contains numbers // Amount column is right-aligned it contains numbers
static int column_alignments[] = { static int column_alignments[] = {
Qt::AlignLeft|Qt::AlignVCenter, /* status */ Qt::AlignLeft|Qt::AlignVCenter, /* status */
Qt::AlignLeft|Qt::AlignVCenter, /* watchonly */
Qt::AlignLeft|Qt::AlignVCenter, /* date */ Qt::AlignLeft|Qt::AlignVCenter, /* date */
Qt::AlignLeft|Qt::AlignVCenter, /* type */ Qt::AlignLeft|Qt::AlignVCenter, /* type */
Qt::AlignLeft|Qt::AlignVCenter, /* address */ Qt::AlignLeft|Qt::AlignVCenter, /* address */
@ -234,7 +235,7 @@ TransactionTableModel::TransactionTableModel(CWallet* wallet, WalletModel *paren
walletModel(parent), walletModel(parent),
priv(new TransactionTablePriv(wallet, this)) priv(new TransactionTablePriv(wallet, this))
{ {
columns << QString() << tr("Date") << tr("Type") << tr("Address") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit()); columns << QString() << QString() << tr("Date") << tr("Type") << tr("Address") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
priv->refreshWallet(); priv->refreshWallet();
connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); 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 QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const
{ {
// mark transactions involving watch-only addresses:
QString watchAddress = wtx->involvesWatchAddress ? " (w) " : "";
switch(wtx->type) switch(wtx->type)
{ {
case TransactionRecord::RecvFromOther: case TransactionRecord::RecvFromOther:
return QString::fromStdString(wtx->address) + watchAddress; return QString::fromStdString(wtx->address);
case TransactionRecord::RecvWithAddress: case TransactionRecord::RecvWithAddress:
case TransactionRecord::SendToAddress: case TransactionRecord::SendToAddress:
case TransactionRecord::Generated: case TransactionRecord::Generated:
return lookupAddress(wtx->address, tooltip) + watchAddress; return lookupAddress(wtx->address, tooltip);
case TransactionRecord::SendToOther: case TransactionRecord::SendToOther:
return QString::fromStdString(wtx->address) + watchAddress; return QString::fromStdString(wtx->address);
case TransactionRecord::SendToSelf: case TransactionRecord::SendToSelf:
default: 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); 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 TransactionTableModel::formatTooltip(const TransactionRecord *rec) const
{ {
QString tooltip = formatTxStatus(rec) + QString("\n") + formatTxType(rec); QString tooltip = formatTxStatus(rec) + QString("\n") + formatTxType(rec);
@ -506,6 +512,8 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
{ {
case Status: case Status:
return txStatusDecoration(rec); return txStatusDecoration(rec);
case Watchonly:
return txWatchonlyDecoration(rec);
case ToAddress: case ToAddress:
return txAddressDecoration(rec); return txAddressDecoration(rec);
} }
@ -533,6 +541,8 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
return rec->time; return rec->time;
case Type: case Type:
return formatTxType(rec); return formatTxType(rec);
case Watchonly:
return (rec->involvesWatchAddress ? 1 : 0);
case ToAddress: case ToAddress:
return formatTxToAddress(rec, true); return formatTxToAddress(rec, true);
case Amount: case Amount:
@ -562,6 +572,10 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
return rec->type; return rec->type;
case DateRole: case DateRole:
return QDateTime::fromTime_t(static_cast<uint>(rec->time)); return QDateTime::fromTime_t(static_cast<uint>(rec->time));
case WatchonlyRole:
return rec->involvesWatchAddress;
case WatchonlyDecorationRole:
return txWatchonlyDecoration(rec);
case LongDescriptionRole: case LongDescriptionRole:
return priv->describe(rec, walletModel->getOptionsModel()->getDisplayUnit()); return priv->describe(rec, walletModel->getOptionsModel()->getDisplayUnit());
case AddressRole: case AddressRole:
@ -606,6 +620,8 @@ QVariant TransactionTableModel::headerData(int section, Qt::Orientation orientat
return tr("Date and time that the transaction was received."); return tr("Date and time that the transaction was received.");
case Type: case Type:
return tr("Type of transaction."); return tr("Type of transaction.");
case Watchonly:
return tr("Whether or not a watch-only address is involved in this transaction.");
case ToAddress: case ToAddress:
return tr("Destination address of transaction."); return tr("Destination address of transaction.");
case Amount: case Amount:

View file

@ -28,10 +28,11 @@ public:
enum ColumnIndex { enum ColumnIndex {
Status = 0, Status = 0,
Date = 1, Watchonly = 1,
Type = 2, Date = 2,
ToAddress = 3, Type = 3,
Amount = 4 ToAddress = 4,
Amount = 5
}; };
/** Roles to get specific information from a transaction row. /** Roles to get specific information from a transaction row.
@ -42,6 +43,10 @@ public:
TypeRole = Qt::UserRole, TypeRole = Qt::UserRole,
/** Date and time this transaction was created */ /** Date and time this transaction was created */
DateRole, DateRole,
/** Watch-only boolean */
WatchonlyRole,
/** Watch-only icon */
WatchonlyDecorationRole,
/** Long description (HTML format) */ /** Long description (HTML format) */
LongDescriptionRole, LongDescriptionRole,
/** Address of transaction */ /** Address of transaction */
@ -83,6 +88,7 @@ private:
QString formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed=true, BitcoinUnits::SeparatorStyle separators=BitcoinUnits::separatorStandard) const; QString formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed=true, BitcoinUnits::SeparatorStyle separators=BitcoinUnits::separatorStandard) const;
QString formatTooltip(const TransactionRecord *rec) const; QString formatTooltip(const TransactionRecord *rec) const;
QVariant txStatusDecoration(const TransactionRecord *wtx) const; QVariant txStatusDecoration(const TransactionRecord *wtx) const;
QVariant txWatchonlyDecoration(const TransactionRecord *wtx) const;
QVariant txAddressDecoration(const TransactionRecord *wtx) const; QVariant txAddressDecoration(const TransactionRecord *wtx) const;
public slots: public slots:

View file

@ -51,6 +51,13 @@ TransactionView::TransactionView(QWidget *parent) :
hlayout->addSpacing(23); hlayout->addSpacing(23);
#endif #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); dateWidget = new QComboBox(this);
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
dateWidget->setFixedWidth(121); dateWidget->setFixedWidth(121);
@ -150,6 +157,7 @@ TransactionView::TransactionView(QWidget *parent) :
connect(dateWidget, SIGNAL(activated(int)), this, SLOT(chooseDate(int))); connect(dateWidget, SIGNAL(activated(int)), this, SLOT(chooseDate(int)));
connect(typeWidget, SIGNAL(activated(int)), this, SLOT(chooseType(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(addressWidget, SIGNAL(textChanged(QString)), this, SLOT(changedPrefix(QString)));
connect(amountWidget, SIGNAL(textChanged(QString)), this, SLOT(changedAmount(QString))); connect(amountWidget, SIGNAL(textChanged(QString)), this, SLOT(changedAmount(QString)));
@ -187,6 +195,7 @@ void TransactionView::setModel(WalletModel *model)
transactionView->verticalHeader()->hide(); transactionView->verticalHeader()->hide();
transactionView->setColumnWidth(TransactionTableModel::Status, STATUS_COLUMN_WIDTH); transactionView->setColumnWidth(TransactionTableModel::Status, STATUS_COLUMN_WIDTH);
transactionView->setColumnWidth(TransactionTableModel::Watchonly, WATCHONLY_COLUMN_WIDTH);
transactionView->setColumnWidth(TransactionTableModel::Date, DATE_COLUMN_WIDTH); transactionView->setColumnWidth(TransactionTableModel::Date, DATE_COLUMN_WIDTH);
transactionView->setColumnWidth(TransactionTableModel::Type, TYPE_COLUMN_WIDTH); transactionView->setColumnWidth(TransactionTableModel::Type, TYPE_COLUMN_WIDTH);
transactionView->setColumnWidth(TransactionTableModel::Amount, AMOUNT_MINIMUM_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()); 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) void TransactionView::changedPrefix(const QString &prefix)
{ {
if(!transactionProxyModel) if(!transactionProxyModel)
@ -307,6 +330,8 @@ void TransactionView::exportClicked()
// name, column, role // name, column, role
writer.setModel(transactionProxyModel); writer.setModel(transactionProxyModel);
writer.addColumn(tr("Confirmed"), 0, TransactionTableModel::ConfirmedRole); 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("Date"), 0, TransactionTableModel::DateRole);
writer.addColumn(tr("Type"), TransactionTableModel::Type, Qt::EditRole); writer.addColumn(tr("Type"), TransactionTableModel::Type, Qt::EditRole);
writer.addColumn(tr("Label"), 0, TransactionTableModel::LabelRole); writer.addColumn(tr("Label"), 0, TransactionTableModel::LabelRole);
@ -501,3 +526,10 @@ bool TransactionView::eventFilter(QObject *obj, QEvent *event)
} }
return QWidget::eventFilter(obj, event); return QWidget::eventFilter(obj, event);
} }
// show/hide column Watch-only
void TransactionView::updateWatchOnlyColumn(bool fHaveWatchOnly)
{
watchOnlyWidget->setVisible(fHaveWatchOnly);
transactionView->setColumnHidden(TransactionTableModel::Watchonly, !fHaveWatchOnly);
}

View file

@ -50,6 +50,7 @@ public:
enum ColumnWidths { enum ColumnWidths {
STATUS_COLUMN_WIDTH = 23, STATUS_COLUMN_WIDTH = 23,
WATCHONLY_COLUMN_WIDTH = 23,
DATE_COLUMN_WIDTH = 120, DATE_COLUMN_WIDTH = 120,
TYPE_COLUMN_WIDTH = 120, TYPE_COLUMN_WIDTH = 120,
AMOUNT_MINIMUM_COLUMN_WIDTH = 120, AMOUNT_MINIMUM_COLUMN_WIDTH = 120,
@ -63,6 +64,7 @@ private:
QComboBox *dateWidget; QComboBox *dateWidget;
QComboBox *typeWidget; QComboBox *typeWidget;
QComboBox *watchOnlyWidget;
QLineEdit *addressWidget; QLineEdit *addressWidget;
QLineEdit *amountWidget; QLineEdit *amountWidget;
@ -91,6 +93,7 @@ private slots:
void copyAmount(); void copyAmount();
void copyTxID(); void copyTxID();
void openThirdPartyTxUrl(QString url); void openThirdPartyTxUrl(QString url);
void updateWatchOnlyColumn(bool fHaveWatchOnly);
signals: signals:
void doubleClicked(const QModelIndex&); void doubleClicked(const QModelIndex&);
@ -101,6 +104,7 @@ signals:
public slots: public slots:
void chooseDate(int idx); void chooseDate(int idx);
void chooseType(int idx); void chooseType(int idx);
void chooseWatchonly(int idx);
void changedPrefix(const QString &prefix); void changedPrefix(const QString &prefix);
void changedAmount(const QString &amount); void changedAmount(const QString &amount);
void exportClicked(); void exportClicked();