Browse Source

Merge pull request #4673

1c5f0af [Qt] Add column Watch-only to transactions list (Cozz Lovan)
939ed97 Add boolean HaveWatchonly and signal NotifyWatchonlyChanged (Cozz Lovan)
0.10
Wladimir J. van der Laan 10 years ago
parent
commit
d49b0876a4
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6
  1. 3
      src/Makefile.qt.include
  2. 6
      src/keystore.cpp
  3. 2
      src/keystore.h
  4. 3
      src/qt/bitcoin.qrc
  5. 24
      src/qt/overviewpage.cpp
  6. 1
      src/qt/overviewpage.h
  7. BIN
      src/qt/res/icons/eye.png
  8. BIN
      src/qt/res/icons/eye_minus.png
  9. BIN
      src/qt/res/icons/eye_plus.png
  10. 12
      src/qt/transactionfilterproxy.cpp
  11. 9
      src/qt/transactionfilterproxy.h
  12. 32
      src/qt/transactiontablemodel.cpp
  13. 14
      src/qt/transactiontablemodel.h
  14. 32
      src/qt/transactionview.cpp
  15. 4
      src/qt/transactionview.h
  16. 32
      src/qt/walletmodel.cpp
  17. 7
      src/qt/walletmodel.h
  18. 1
      src/wallet.cpp
  19. 3
      src/wallet.h

3
src/Makefile.qt.include

@ -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 \

6
src/keystore.cpp

@ -72,3 +72,9 @@ bool CBasicKeyStore::HaveWatchOnly(const CScript &dest) const
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
return setWatchOnly.count(dest) > 0; return setWatchOnly.count(dest) > 0;
} }
bool CBasicKeyStore::HaveWatchOnly() const
{
LOCK(cs_KeyStore);
return (!setWatchOnly.empty());
}

2
src/keystore.h

@ -41,6 +41,7 @@ public:
// Support for Watch-only addresses // Support for Watch-only addresses
virtual bool AddWatchOnly(const CScript &dest) =0; virtual bool AddWatchOnly(const CScript &dest) =0;
virtual bool HaveWatchOnly(const CScript &dest) const =0; virtual bool HaveWatchOnly(const CScript &dest) const =0;
virtual bool HaveWatchOnly() const =0;
}; };
typedef std::map<CKeyID, CKey> KeyMap; typedef std::map<CKeyID, CKey> KeyMap;
@ -98,6 +99,7 @@ public:
virtual bool AddWatchOnly(const CScript &dest); virtual bool AddWatchOnly(const CScript &dest);
virtual bool HaveWatchOnly(const CScript &dest) const; virtual bool HaveWatchOnly(const CScript &dest) const;
virtual bool HaveWatchOnly() const;
}; };
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial; typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;

3
src/qt/bitcoin.qrc

@ -17,6 +17,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>

24
src/qt/overviewpage.cpp

@ -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)
{ {
@ -160,18 +168,25 @@ void OverviewPage::setBalance(qint64 balance, qint64 unconfirmedBalance, qint64
// for the non-mining users // for the non-mining users
bool showImmature = immatureBalance != 0; bool showImmature = immatureBalance != 0;
bool showWatchOnlyImmature = watchImmatureBalance != 0; bool showWatchOnlyImmature = watchImmatureBalance != 0;
bool showWatchOnly = (watchOnlyBalance != 0 || watchUnconfBalance != 0 || showWatchOnlyImmature);
// for symmetry reasons also show immature label when the watch-only one is shown // for symmetry reasons also show immature label when the watch-only one is shown
ui->labelImmature->setVisible(showImmature || showWatchOnlyImmature); ui->labelImmature->setVisible(showImmature || showWatchOnlyImmature);
ui->labelImmatureText->setVisible(showImmature || showWatchOnlyImmature); ui->labelImmatureText->setVisible(showImmature || showWatchOnlyImmature);
ui->labelWatchImmature->setVisible(showWatchOnlyImmature); // show watch-only immature balance
}
// show/hide watch-only labels
void OverviewPage::updateWatchOnlyLabels(bool showWatchOnly)
{
ui->labelSpendable->setVisible(showWatchOnly); // show spendable label (only when watch-only is active) ui->labelSpendable->setVisible(showWatchOnly); // show spendable label (only when watch-only is active)
ui->labelWatchonly->setVisible(showWatchOnly); // show watch-only label ui->labelWatchonly->setVisible(showWatchOnly); // show watch-only label
ui->lineWatchBalance->setVisible(showWatchOnly); // show watch-only balance separator line ui->lineWatchBalance->setVisible(showWatchOnly); // show watch-only balance separator line
ui->labelWatchAvailable->setVisible(showWatchOnly); // show watch-only available balance ui->labelWatchAvailable->setVisible(showWatchOnly); // show watch-only available balance
ui->labelWatchImmature->setVisible(showWatchOnlyImmature); // show watch-only immature balance
ui->labelWatchPending->setVisible(showWatchOnly); // show watch-only pending balance ui->labelWatchPending->setVisible(showWatchOnly); // show watch-only pending balance
ui->labelWatchTotal->setVisible(showWatchOnly); // show watch-only total balance ui->labelWatchTotal->setVisible(showWatchOnly); // show watch-only total balance
if (!showWatchOnly)
ui->labelWatchImmature->hide();
} }
void OverviewPage::setClientModel(ClientModel *model) void OverviewPage::setClientModel(ClientModel *model)
@ -208,6 +223,9 @@ void OverviewPage::setWalletModel(WalletModel *model)
connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64, qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64, qint64, qint64, qint64))); connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64, qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64, qint64, qint64, qint64)));
connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
updateWatchOnlyLabels(model->haveWatchOnly());
connect(model, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyLabels(bool)));
} }
// update the display unit, to not use the default ("BTC") // update the display unit, to not use the default ("BTC")

1
src/qt/overviewpage.h

@ -58,6 +58,7 @@ private slots:
void updateDisplayUnit(); void updateDisplayUnit();
void handleTransactionClicked(const QModelIndex &index); void handleTransactionClicked(const QModelIndex &index);
void updateAlerts(const QString &warnings); void updateAlerts(const QString &warnings);
void updateWatchOnlyLabels(bool showWatchOnly);
}; };
#endif // OVERVIEWPAGE_H #endif // OVERVIEWPAGE_H

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 B

BIN
src/qt/res/icons/eye_minus.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 595 B

BIN
src/qt/res/icons/eye_plus.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 B

12
src/qt/transactionfilterproxy.cpp

@ -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;

9
src/qt/transactionfilterproxy.h

@ -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;

32
src/qt/transactiontablemodel.cpp

@ -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:

14
src/qt/transactiontablemodel.h

@ -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:

32
src/qt/transactionview.cpp

@ -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);
}

4
src/qt/transactionview.h

@ -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();

32
src/qt/walletmodel.cpp

@ -35,6 +35,7 @@ WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *p
cachedNumBlocks(0) cachedNumBlocks(0)
{ {
fProcessingQueuedTransactions = false; fProcessingQueuedTransactions = false;
fHaveWatchOnly = wallet->HaveWatchOnly();
addressTableModel = new AddressTableModel(wallet, this); addressTableModel = new AddressTableModel(wallet, this);
transactionTableModel = new TransactionTableModel(wallet, this); transactionTableModel = new TransactionTableModel(wallet, this);
@ -80,6 +81,11 @@ qint64 WalletModel::getImmatureBalance() const
return wallet->GetImmatureBalance(); return wallet->GetImmatureBalance();
} }
bool WalletModel::haveWatchOnly() const
{
return fHaveWatchOnly;
}
qint64 WalletModel::getWatchBalance() const qint64 WalletModel::getWatchBalance() const
{ {
return wallet->GetWatchOnlyBalance(); return wallet->GetWatchOnlyBalance();
@ -131,9 +137,15 @@ void WalletModel::checkBalanceChanged()
qint64 newBalance = getBalance(); qint64 newBalance = getBalance();
qint64 newUnconfirmedBalance = getUnconfirmedBalance(); qint64 newUnconfirmedBalance = getUnconfirmedBalance();
qint64 newImmatureBalance = getImmatureBalance(); qint64 newImmatureBalance = getImmatureBalance();
qint64 newWatchOnlyBalance = getWatchBalance(); qint64 newWatchOnlyBalance = 0;
qint64 newWatchUnconfBalance = getWatchUnconfirmedBalance(); qint64 newWatchUnconfBalance = 0;
qint64 newWatchImmatureBalance = getWatchImmatureBalance(); qint64 newWatchImmatureBalance = 0;
if (haveWatchOnly())
{
newWatchOnlyBalance = getWatchBalance();
newWatchUnconfBalance = getWatchUnconfirmedBalance();
newWatchImmatureBalance = getWatchImmatureBalance();
}
if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance || cachedImmatureBalance != newImmatureBalance || if(cachedBalance != newBalance || cachedUnconfirmedBalance != newUnconfirmedBalance || cachedImmatureBalance != newImmatureBalance ||
cachedWatchOnlyBalance != newWatchOnlyBalance || cachedWatchUnconfBalance != newWatchUnconfBalance || cachedWatchImmatureBalance != newWatchImmatureBalance) cachedWatchOnlyBalance != newWatchOnlyBalance || cachedWatchUnconfBalance != newWatchUnconfBalance || cachedWatchImmatureBalance != newWatchImmatureBalance)
@ -165,6 +177,12 @@ void WalletModel::updateAddressBook(const QString &address, const QString &label
addressTableModel->updateEntry(address, label, isMine, purpose, status); addressTableModel->updateEntry(address, label, isMine, purpose, status);
} }
void WalletModel::updateWatchOnlyFlag(bool fHaveWatchonly)
{
fHaveWatchOnly = fHaveWatchonly;
emit notifyWatchonlyChanged(fHaveWatchonly);
}
bool WalletModel::validateAddress(const QString &address) bool WalletModel::validateAddress(const QString &address)
{ {
CBitcoinAddress addressParsed(address.toStdString()); CBitcoinAddress addressParsed(address.toStdString());
@ -479,6 +497,12 @@ static void ShowProgress(WalletModel *walletmodel, const std::string &title, int
} }
} }
static void NotifyWatchonlyChanged(WalletModel *walletmodel, bool fHaveWatchonly)
{
QMetaObject::invokeMethod(walletmodel, "updateWatchOnlyFlag", Qt::QueuedConnection,
Q_ARG(bool, fHaveWatchonly));
}
void WalletModel::subscribeToCoreSignals() void WalletModel::subscribeToCoreSignals()
{ {
// Connect signals to wallet // Connect signals to wallet
@ -486,6 +510,7 @@ void WalletModel::subscribeToCoreSignals()
wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5, _6)); wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5, _6));
wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
wallet->NotifyWatchonlyChanged.connect(boost::bind(NotifyWatchonlyChanged, this, _1));
} }
void WalletModel::unsubscribeFromCoreSignals() void WalletModel::unsubscribeFromCoreSignals()
@ -495,6 +520,7 @@ void WalletModel::unsubscribeFromCoreSignals()
wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5, _6)); wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5, _6));
wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3));
wallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); wallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
wallet->NotifyWatchonlyChanged.disconnect(boost::bind(NotifyWatchonlyChanged, this, _1));
} }
// WalletModel::UnlockContext implementation // WalletModel::UnlockContext implementation

7
src/qt/walletmodel.h

@ -128,6 +128,7 @@ public:
qint64 getBalance(const CCoinControl *coinControl = NULL) const; qint64 getBalance(const CCoinControl *coinControl = NULL) const;
qint64 getUnconfirmedBalance() const; qint64 getUnconfirmedBalance() const;
qint64 getImmatureBalance() const; qint64 getImmatureBalance() const;
bool haveWatchOnly() const;
qint64 getWatchBalance() const; qint64 getWatchBalance() const;
qint64 getWatchUnconfirmedBalance() const; qint64 getWatchUnconfirmedBalance() const;
qint64 getWatchImmatureBalance() const; qint64 getWatchImmatureBalance() const;
@ -197,6 +198,7 @@ public:
private: private:
CWallet *wallet; CWallet *wallet;
bool fProcessingQueuedTransactions; bool fProcessingQueuedTransactions;
bool fHaveWatchOnly;
// Wallet has an options model for wallet-specific options // Wallet has an options model for wallet-specific options
// (transaction fee, for example) // (transaction fee, for example)
@ -244,6 +246,9 @@ signals:
// Show progress dialog e.g. for rescan // Show progress dialog e.g. for rescan
void showProgress(const QString &title, int nProgress); void showProgress(const QString &title, int nProgress);
// Watch-only address added
void notifyWatchonlyChanged(bool fHaveWatchonly);
public slots: public slots:
/* Wallet status might have changed */ /* Wallet status might have changed */
void updateStatus(); void updateStatus();
@ -251,6 +256,8 @@ public slots:
void updateTransaction(const QString &hash, int status); void updateTransaction(const QString &hash, int status);
/* New, updated or removed address book entry */ /* New, updated or removed address book entry */
void updateAddressBook(const QString &address, const QString &label, bool isMine, const QString &purpose, int status); void updateAddressBook(const QString &address, const QString &label, bool isMine, const QString &purpose, int status);
/* Watchonly added */
void updateWatchOnlyFlag(bool fHaveWatchonly);
/* Current, immature or unconfirmed balance might have changed - emit 'balanceChanged' if so */ /* Current, immature or unconfirmed balance might have changed - emit 'balanceChanged' if so */
void pollBalanceChanged(); void pollBalanceChanged();
/* Needed to update fProcessingQueuedTransactions through a QueuedConnection */ /* Needed to update fProcessingQueuedTransactions through a QueuedConnection */

1
src/wallet.cpp

@ -161,6 +161,7 @@ bool CWallet::AddWatchOnly(const CScript &dest)
if (!CCryptoKeyStore::AddWatchOnly(dest)) if (!CCryptoKeyStore::AddWatchOnly(dest))
return false; return false;
nTimeFirstKey = 1; // No birthday information for watch-only keys. nTimeFirstKey = 1; // No birthday information for watch-only keys.
NotifyWatchonlyChanged(true);
if (!fFileBacked) if (!fFileBacked)
return true; return true;
return CWalletDB(strWalletFile).WriteWatchOnly(dest); return CWalletDB(strWalletFile).WriteWatchOnly(dest);

3
src/wallet.h

@ -399,6 +399,9 @@ public:
/** Show progress e.g. for rescan */ /** Show progress e.g. for rescan */
boost::signals2::signal<void (const std::string &title, int nProgress)> ShowProgress; boost::signals2::signal<void (const std::string &title, int nProgress)> ShowProgress;
/** Watch-only address added */
boost::signals2::signal<void (bool fHaveWatchOnly)> NotifyWatchonlyChanged;
}; };
/** A key allocated from the key pool. */ /** A key allocated from the key pool. */

Loading…
Cancel
Save