1 // Copyright (c) 2011-2016 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 #include "transactionview.h"
7 #include "addresstablemodel.h"
8 #include "bitcoinunits.h"
9 #include "csvmodelwriter.h"
10 #include "editaddressdialog.h"
12 #include "optionsmodel.h"
13 #include "platformstyle.h"
14 #include "sendcoinsdialog.h"
15 #include "transactiondescdialog.h"
16 #include "transactionfilterproxy.h"
17 #include "transactionrecord.h"
18 #include "transactiontablemodel.h"
19 #include "walletmodel.h"
21 #include "ui_interface.h"
24 #include <QDateTimeEdit>
25 #include <QDesktopServices>
26 #include <QDoubleValidator>
27 #include <QHBoxLayout>
28 #include <QHeaderView>
34 #include <QSignalMapper>
37 #include <QVBoxLayout>
39 TransactionView::TransactionView(const PlatformStyle
*platformStyle
, QWidget
*parent
) :
40 QWidget(parent
), model(0), transactionProxyModel(0),
41 transactionView(0), abandonAction(0), bumpFeeAction(0), columnResizingFixer(0)
44 setContentsMargins(0,0,0,0);
46 QHBoxLayout
*hlayout
= new QHBoxLayout();
47 hlayout
->setContentsMargins(0,0,0,0);
49 if (platformStyle
->getUseExtraSpacing()) {
50 hlayout
->setSpacing(5);
51 hlayout
->addSpacing(26);
53 hlayout
->setSpacing(0);
54 hlayout
->addSpacing(23);
57 watchOnlyWidget
= new QComboBox(this);
58 watchOnlyWidget
->setFixedWidth(24);
59 watchOnlyWidget
->addItem("", TransactionFilterProxy::WatchOnlyFilter_All
);
60 watchOnlyWidget
->addItem(platformStyle
->SingleColorIcon(":/icons/eye_plus"), "", TransactionFilterProxy::WatchOnlyFilter_Yes
);
61 watchOnlyWidget
->addItem(platformStyle
->SingleColorIcon(":/icons/eye_minus"), "", TransactionFilterProxy::WatchOnlyFilter_No
);
62 hlayout
->addWidget(watchOnlyWidget
);
64 dateWidget
= new QComboBox(this);
65 if (platformStyle
->getUseExtraSpacing()) {
66 dateWidget
->setFixedWidth(121);
68 dateWidget
->setFixedWidth(120);
70 dateWidget
->addItem(tr("All"), All
);
71 dateWidget
->addItem(tr("Today"), Today
);
72 dateWidget
->addItem(tr("This week"), ThisWeek
);
73 dateWidget
->addItem(tr("This month"), ThisMonth
);
74 dateWidget
->addItem(tr("Last month"), LastMonth
);
75 dateWidget
->addItem(tr("This year"), ThisYear
);
76 dateWidget
->addItem(tr("Range..."), Range
);
77 hlayout
->addWidget(dateWidget
);
79 typeWidget
= new QComboBox(this);
80 if (platformStyle
->getUseExtraSpacing()) {
81 typeWidget
->setFixedWidth(121);
83 typeWidget
->setFixedWidth(120);
86 typeWidget
->addItem(tr("All"), TransactionFilterProxy::ALL_TYPES
);
87 typeWidget
->addItem(tr("Received with"), TransactionFilterProxy::TYPE(TransactionRecord::RecvWithAddress
) |
88 TransactionFilterProxy::TYPE(TransactionRecord::RecvFromOther
));
89 typeWidget
->addItem(tr("Sent to"), TransactionFilterProxy::TYPE(TransactionRecord::SendToAddress
) |
90 TransactionFilterProxy::TYPE(TransactionRecord::SendToOther
));
91 typeWidget
->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf
));
92 typeWidget
->addItem(tr("Mined"), TransactionFilterProxy::TYPE(TransactionRecord::Generated
));
93 typeWidget
->addItem(tr("Other"), TransactionFilterProxy::TYPE(TransactionRecord::Other
));
95 hlayout
->addWidget(typeWidget
);
97 addressWidget
= new QLineEdit(this);
98 #if QT_VERSION >= 0x040700
99 addressWidget
->setPlaceholderText(tr("Enter address or label to search"));
101 hlayout
->addWidget(addressWidget
);
103 amountWidget
= new QLineEdit(this);
104 #if QT_VERSION >= 0x040700
105 amountWidget
->setPlaceholderText(tr("Min amount"));
107 if (platformStyle
->getUseExtraSpacing()) {
108 amountWidget
->setFixedWidth(97);
110 amountWidget
->setFixedWidth(100);
112 amountWidget
->setValidator(new QDoubleValidator(0, 1e20
, 8, this));
113 hlayout
->addWidget(amountWidget
);
115 QVBoxLayout
*vlayout
= new QVBoxLayout(this);
116 vlayout
->setContentsMargins(0,0,0,0);
117 vlayout
->setSpacing(0);
119 QTableView
*view
= new QTableView(this);
120 vlayout
->addLayout(hlayout
);
121 vlayout
->addWidget(createDateRangeWidget());
122 vlayout
->addWidget(view
);
123 vlayout
->setSpacing(0);
124 int width
= view
->verticalScrollBar()->sizeHint().width();
125 // Cover scroll bar width with spacing
126 if (platformStyle
->getUseExtraSpacing()) {
127 hlayout
->addSpacing(width
+2);
129 hlayout
->addSpacing(width
);
131 // Always show scroll bar
132 view
->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn
);
133 view
->setTabKeyNavigation(false);
134 view
->setContextMenuPolicy(Qt::CustomContextMenu
);
136 view
->installEventFilter(this);
138 transactionView
= view
;
139 transactionView
->setObjectName("transactionView");
142 abandonAction
= new QAction(tr("Abandon transaction"), this);
143 bumpFeeAction
= new QAction(tr("Increase transaction fee"), this);
144 bumpFeeAction
->setObjectName("bumpFeeAction");
145 QAction
*copyAddressAction
= new QAction(tr("Copy address"), this);
146 QAction
*copyLabelAction
= new QAction(tr("Copy label"), this);
147 QAction
*copyAmountAction
= new QAction(tr("Copy amount"), this);
148 QAction
*copyTxIDAction
= new QAction(tr("Copy transaction ID"), this);
149 QAction
*copyTxHexAction
= new QAction(tr("Copy raw transaction"), this);
150 QAction
*copyTxPlainText
= new QAction(tr("Copy full transaction details"), this);
151 QAction
*editLabelAction
= new QAction(tr("Edit label"), this);
152 QAction
*showDetailsAction
= new QAction(tr("Show transaction details"), this);
154 contextMenu
= new QMenu(this);
155 contextMenu
->setObjectName("contextMenu");
156 contextMenu
->addAction(copyAddressAction
);
157 contextMenu
->addAction(copyLabelAction
);
158 contextMenu
->addAction(copyAmountAction
);
159 contextMenu
->addAction(copyTxIDAction
);
160 contextMenu
->addAction(copyTxHexAction
);
161 contextMenu
->addAction(copyTxPlainText
);
162 contextMenu
->addAction(showDetailsAction
);
163 contextMenu
->addSeparator();
164 contextMenu
->addAction(bumpFeeAction
);
165 contextMenu
->addAction(abandonAction
);
166 contextMenu
->addAction(editLabelAction
);
168 mapperThirdPartyTxUrls
= new QSignalMapper(this);
171 connect(mapperThirdPartyTxUrls
, SIGNAL(mapped(QString
)), this, SLOT(openThirdPartyTxUrl(QString
)));
173 connect(dateWidget
, SIGNAL(activated(int)), this, SLOT(chooseDate(int)));
174 connect(typeWidget
, SIGNAL(activated(int)), this, SLOT(chooseType(int)));
175 connect(watchOnlyWidget
, SIGNAL(activated(int)), this, SLOT(chooseWatchonly(int)));
176 connect(addressWidget
, SIGNAL(textChanged(QString
)), this, SLOT(changedPrefix(QString
)));
177 connect(amountWidget
, SIGNAL(textChanged(QString
)), this, SLOT(changedAmount(QString
)));
179 connect(view
, SIGNAL(doubleClicked(QModelIndex
)), this, SIGNAL(doubleClicked(QModelIndex
)));
180 connect(view
, SIGNAL(customContextMenuRequested(QPoint
)), this, SLOT(contextualMenu(QPoint
)));
182 connect(bumpFeeAction
, SIGNAL(triggered()), this, SLOT(bumpFee()));
183 connect(abandonAction
, SIGNAL(triggered()), this, SLOT(abandonTx()));
184 connect(copyAddressAction
, SIGNAL(triggered()), this, SLOT(copyAddress()));
185 connect(copyLabelAction
, SIGNAL(triggered()), this, SLOT(copyLabel()));
186 connect(copyAmountAction
, SIGNAL(triggered()), this, SLOT(copyAmount()));
187 connect(copyTxIDAction
, SIGNAL(triggered()), this, SLOT(copyTxID()));
188 connect(copyTxHexAction
, SIGNAL(triggered()), this, SLOT(copyTxHex()));
189 connect(copyTxPlainText
, SIGNAL(triggered()), this, SLOT(copyTxPlainText()));
190 connect(editLabelAction
, SIGNAL(triggered()), this, SLOT(editLabel()));
191 connect(showDetailsAction
, SIGNAL(triggered()), this, SLOT(showDetails()));
194 void TransactionView::setModel(WalletModel
*_model
)
196 this->model
= _model
;
199 transactionProxyModel
= new TransactionFilterProxy(this);
200 transactionProxyModel
->setSourceModel(_model
->getTransactionTableModel());
201 transactionProxyModel
->setDynamicSortFilter(true);
202 transactionProxyModel
->setSortCaseSensitivity(Qt::CaseInsensitive
);
203 transactionProxyModel
->setFilterCaseSensitivity(Qt::CaseInsensitive
);
205 transactionProxyModel
->setSortRole(Qt::EditRole
);
207 transactionView
->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff
);
208 transactionView
->setModel(transactionProxyModel
);
209 transactionView
->setAlternatingRowColors(true);
210 transactionView
->setSelectionBehavior(QAbstractItemView::SelectRows
);
211 transactionView
->setSelectionMode(QAbstractItemView::ExtendedSelection
);
212 transactionView
->setSortingEnabled(true);
213 transactionView
->sortByColumn(TransactionTableModel::Date
, Qt::DescendingOrder
);
214 transactionView
->verticalHeader()->hide();
216 transactionView
->setColumnWidth(TransactionTableModel::Status
, STATUS_COLUMN_WIDTH
);
217 transactionView
->setColumnWidth(TransactionTableModel::Watchonly
, WATCHONLY_COLUMN_WIDTH
);
218 transactionView
->setColumnWidth(TransactionTableModel::Date
, DATE_COLUMN_WIDTH
);
219 transactionView
->setColumnWidth(TransactionTableModel::Type
, TYPE_COLUMN_WIDTH
);
220 transactionView
->setColumnWidth(TransactionTableModel::Amount
, AMOUNT_MINIMUM_COLUMN_WIDTH
);
222 columnResizingFixer
= new GUIUtil::TableViewLastColumnResizingFixer(transactionView
, AMOUNT_MINIMUM_COLUMN_WIDTH
, MINIMUM_COLUMN_WIDTH
, this);
224 if (_model
->getOptionsModel())
226 // Add third party transaction URLs to context menu
227 QStringList listUrls
= _model
->getOptionsModel()->getThirdPartyTxUrls().split("|", QString::SkipEmptyParts
);
228 for (int i
= 0; i
< listUrls
.size(); ++i
)
230 QString host
= QUrl(listUrls
[i
].trimmed(), QUrl::StrictMode
).host();
233 QAction
*thirdPartyTxUrlAction
= new QAction(host
, this); // use host as menu item label
235 contextMenu
->addSeparator();
236 contextMenu
->addAction(thirdPartyTxUrlAction
);
237 connect(thirdPartyTxUrlAction
, SIGNAL(triggered()), mapperThirdPartyTxUrls
, SLOT(map()));
238 mapperThirdPartyTxUrls
->setMapping(thirdPartyTxUrlAction
, listUrls
[i
].trimmed());
243 // show/hide column Watch-only
244 updateWatchOnlyColumn(_model
->haveWatchOnly());
247 connect(_model
, SIGNAL(notifyWatchonlyChanged(bool)), this, SLOT(updateWatchOnlyColumn(bool)));
251 void TransactionView::chooseDate(int idx
)
253 if(!transactionProxyModel
)
255 QDate current
= QDate::currentDate();
256 dateRangeWidget
->setVisible(false);
257 switch(dateWidget
->itemData(idx
).toInt())
260 transactionProxyModel
->setDateRange(
261 TransactionFilterProxy::MIN_DATE
,
262 TransactionFilterProxy::MAX_DATE
);
265 transactionProxyModel
->setDateRange(
267 TransactionFilterProxy::MAX_DATE
);
271 QDate startOfWeek
= current
.addDays(-(current
.dayOfWeek()-1));
272 transactionProxyModel
->setDateRange(
273 QDateTime(startOfWeek
),
274 TransactionFilterProxy::MAX_DATE
);
278 transactionProxyModel
->setDateRange(
279 QDateTime(QDate(current
.year(), current
.month(), 1)),
280 TransactionFilterProxy::MAX_DATE
);
283 transactionProxyModel
->setDateRange(
284 QDateTime(QDate(current
.year(), current
.month(), 1).addMonths(-1)),
285 QDateTime(QDate(current
.year(), current
.month(), 1)));
288 transactionProxyModel
->setDateRange(
289 QDateTime(QDate(current
.year(), 1, 1)),
290 TransactionFilterProxy::MAX_DATE
);
293 dateRangeWidget
->setVisible(true);
299 void TransactionView::chooseType(int idx
)
301 if(!transactionProxyModel
)
303 transactionProxyModel
->setTypeFilter(
304 typeWidget
->itemData(idx
).toInt());
307 void TransactionView::chooseWatchonly(int idx
)
309 if(!transactionProxyModel
)
311 transactionProxyModel
->setWatchOnlyFilter(
312 (TransactionFilterProxy::WatchOnlyFilter
)watchOnlyWidget
->itemData(idx
).toInt());
315 void TransactionView::changedPrefix(const QString
&prefix
)
317 if(!transactionProxyModel
)
319 transactionProxyModel
->setAddressPrefix(prefix
);
322 void TransactionView::changedAmount(const QString
&amount
)
324 if(!transactionProxyModel
)
326 CAmount amount_parsed
= 0;
327 if(BitcoinUnits::parse(model
->getOptionsModel()->getDisplayUnit(), amount
, &amount_parsed
))
329 transactionProxyModel
->setMinAmount(amount_parsed
);
333 transactionProxyModel
->setMinAmount(0);
337 void TransactionView::exportClicked()
339 if (!model
|| !model
->getOptionsModel()) {
343 // CSV is currently the only supported format
344 QString filename
= GUIUtil::getSaveFileName(this,
345 tr("Export Transaction History"), QString(),
346 tr("Comma separated file (*.csv)"), nullptr);
348 if (filename
.isNull())
351 CSVModelWriter
writer(filename
);
353 // name, column, role
354 writer
.setModel(transactionProxyModel
);
355 writer
.addColumn(tr("Confirmed"), 0, TransactionTableModel::ConfirmedRole
);
356 if (model
&& model
->haveWatchOnly())
357 writer
.addColumn(tr("Watch-only"), TransactionTableModel::Watchonly
);
358 writer
.addColumn(tr("Date"), 0, TransactionTableModel::DateRole
);
359 writer
.addColumn(tr("Type"), TransactionTableModel::Type
, Qt::EditRole
);
360 writer
.addColumn(tr("Label"), 0, TransactionTableModel::LabelRole
);
361 writer
.addColumn(tr("Address"), 0, TransactionTableModel::AddressRole
);
362 writer
.addColumn(BitcoinUnits::getAmountColumnTitle(model
->getOptionsModel()->getDisplayUnit()), 0, TransactionTableModel::FormattedAmountRole
);
363 writer
.addColumn(tr("ID"), 0, TransactionTableModel::TxIDRole
);
365 if(!writer
.write()) {
366 Q_EMIT
message(tr("Exporting Failed"), tr("There was an error trying to save the transaction history to %1.").arg(filename
),
367 CClientUIInterface::MSG_ERROR
);
370 Q_EMIT
message(tr("Exporting Successful"), tr("The transaction history was successfully saved to %1.").arg(filename
),
371 CClientUIInterface::MSG_INFORMATION
);
375 void TransactionView::contextualMenu(const QPoint
&point
)
377 QModelIndex index
= transactionView
->indexAt(point
);
378 QModelIndexList selection
= transactionView
->selectionModel()->selectedRows(0);
379 if (selection
.empty())
382 // check if transaction can be abandoned, disable context menu action in case it doesn't
384 hash
.SetHex(selection
.at(0).data(TransactionTableModel::TxHashRole
).toString().toStdString());
385 abandonAction
->setEnabled(model
->transactionCanBeAbandoned(hash
));
386 bumpFeeAction
->setEnabled(model
->transactionCanBeBumped(hash
));
390 contextMenu
->popup(transactionView
->viewport()->mapToGlobal(point
));
394 void TransactionView::abandonTx()
396 if(!transactionView
|| !transactionView
->selectionModel())
398 QModelIndexList selection
= transactionView
->selectionModel()->selectedRows(0);
400 // get the hash from the TxHashRole (QVariant / QString)
402 QString hashQStr
= selection
.at(0).data(TransactionTableModel::TxHashRole
).toString();
403 hash
.SetHex(hashQStr
.toStdString());
405 // Abandon the wallet transaction over the walletModel
406 model
->abandonTransaction(hash
);
409 model
->getTransactionTableModel()->updateTransaction(hashQStr
, CT_UPDATED
, false);
412 void TransactionView::bumpFee()
414 if(!transactionView
|| !transactionView
->selectionModel())
416 QModelIndexList selection
= transactionView
->selectionModel()->selectedRows(0);
418 // get the hash from the TxHashRole (QVariant / QString)
420 QString hashQStr
= selection
.at(0).data(TransactionTableModel::TxHashRole
).toString();
421 hash
.SetHex(hashQStr
.toStdString());
423 // Bump tx fee over the walletModel
424 if (model
->bumpFee(hash
)) {
426 model
->getTransactionTableModel()->updateTransaction(hashQStr
, CT_UPDATED
, true);
430 void TransactionView::copyAddress()
432 GUIUtil::copyEntryData(transactionView
, 0, TransactionTableModel::AddressRole
);
435 void TransactionView::copyLabel()
437 GUIUtil::copyEntryData(transactionView
, 0, TransactionTableModel::LabelRole
);
440 void TransactionView::copyAmount()
442 GUIUtil::copyEntryData(transactionView
, 0, TransactionTableModel::FormattedAmountRole
);
445 void TransactionView::copyTxID()
447 GUIUtil::copyEntryData(transactionView
, 0, TransactionTableModel::TxIDRole
);
450 void TransactionView::copyTxHex()
452 GUIUtil::copyEntryData(transactionView
, 0, TransactionTableModel::TxHexRole
);
455 void TransactionView::copyTxPlainText()
457 GUIUtil::copyEntryData(transactionView
, 0, TransactionTableModel::TxPlainTextRole
);
460 void TransactionView::editLabel()
462 if(!transactionView
->selectionModel() ||!model
)
464 QModelIndexList selection
= transactionView
->selectionModel()->selectedRows();
465 if(!selection
.isEmpty())
467 AddressTableModel
*addressBook
= model
->getAddressTableModel();
470 QString address
= selection
.at(0).data(TransactionTableModel::AddressRole
).toString();
471 if(address
.isEmpty())
473 // If this transaction has no associated address, exit
476 // Is address in address book? Address book can miss address when a transaction is
477 // sent from outside the UI.
478 int idx
= addressBook
->lookupAddress(address
);
481 // Edit sending / receiving address
482 QModelIndex modelIdx
= addressBook
->index(idx
, 0, QModelIndex());
483 // Determine type of address, launch appropriate editor dialog type
484 QString type
= modelIdx
.data(AddressTableModel::TypeRole
).toString();
486 EditAddressDialog
dlg(
487 type
== AddressTableModel::Receive
488 ? EditAddressDialog::EditReceivingAddress
489 : EditAddressDialog::EditSendingAddress
, this);
490 dlg
.setModel(addressBook
);
496 // Add sending address
497 EditAddressDialog
dlg(EditAddressDialog::NewSendingAddress
,
499 dlg
.setModel(addressBook
);
500 dlg
.setAddress(address
);
506 void TransactionView::showDetails()
508 if(!transactionView
->selectionModel())
510 QModelIndexList selection
= transactionView
->selectionModel()->selectedRows();
511 if(!selection
.isEmpty())
513 TransactionDescDialog
*dlg
= new TransactionDescDialog(selection
.at(0));
514 dlg
->setAttribute(Qt::WA_DeleteOnClose
);
519 void TransactionView::openThirdPartyTxUrl(QString url
)
521 if(!transactionView
|| !transactionView
->selectionModel())
523 QModelIndexList selection
= transactionView
->selectionModel()->selectedRows(0);
524 if(!selection
.isEmpty())
525 QDesktopServices::openUrl(QUrl::fromUserInput(url
.replace("%s", selection
.at(0).data(TransactionTableModel::TxHashRole
).toString())));
528 QWidget
*TransactionView::createDateRangeWidget()
530 dateRangeWidget
= new QFrame();
531 dateRangeWidget
->setFrameStyle(QFrame::Panel
| QFrame::Raised
);
532 dateRangeWidget
->setContentsMargins(1,1,1,1);
533 QHBoxLayout
*layout
= new QHBoxLayout(dateRangeWidget
);
534 layout
->setContentsMargins(0,0,0,0);
535 layout
->addSpacing(23);
536 layout
->addWidget(new QLabel(tr("Range:")));
538 dateFrom
= new QDateTimeEdit(this);
539 dateFrom
->setDisplayFormat("dd/MM/yy");
540 dateFrom
->setCalendarPopup(true);
541 dateFrom
->setMinimumWidth(100);
542 dateFrom
->setDate(QDate::currentDate().addDays(-7));
543 layout
->addWidget(dateFrom
);
544 layout
->addWidget(new QLabel(tr("to")));
546 dateTo
= new QDateTimeEdit(this);
547 dateTo
->setDisplayFormat("dd/MM/yy");
548 dateTo
->setCalendarPopup(true);
549 dateTo
->setMinimumWidth(100);
550 dateTo
->setDate(QDate::currentDate());
551 layout
->addWidget(dateTo
);
552 layout
->addStretch();
555 dateRangeWidget
->setVisible(false);
558 connect(dateFrom
, SIGNAL(dateChanged(QDate
)), this, SLOT(dateRangeChanged()));
559 connect(dateTo
, SIGNAL(dateChanged(QDate
)), this, SLOT(dateRangeChanged()));
561 return dateRangeWidget
;
564 void TransactionView::dateRangeChanged()
566 if(!transactionProxyModel
)
568 transactionProxyModel
->setDateRange(
569 QDateTime(dateFrom
->date()),
570 QDateTime(dateTo
->date()).addDays(1));
573 void TransactionView::focusTransaction(const QModelIndex
&idx
)
575 if(!transactionProxyModel
)
577 QModelIndex targetIdx
= transactionProxyModel
->mapFromSource(idx
);
578 transactionView
->scrollTo(targetIdx
);
579 transactionView
->setCurrentIndex(targetIdx
);
580 transactionView
->setFocus();
583 // We override the virtual resizeEvent of the QWidget to adjust tables column
584 // sizes as the tables width is proportional to the dialogs width.
585 void TransactionView::resizeEvent(QResizeEvent
* event
)
587 QWidget::resizeEvent(event
);
588 columnResizingFixer
->stretchColumnWidth(TransactionTableModel::ToAddress
);
591 // Need to override default Ctrl+C action for amount as default behaviour is just to copy DisplayRole text
592 bool TransactionView::eventFilter(QObject
*obj
, QEvent
*event
)
594 if (event
->type() == QEvent::KeyPress
)
596 QKeyEvent
*ke
= static_cast<QKeyEvent
*>(event
);
597 if (ke
->key() == Qt::Key_C
&& ke
->modifiers().testFlag(Qt::ControlModifier
))
599 GUIUtil::copyEntryData(transactionView
, 0, TransactionTableModel::TxPlainTextRole
);
603 return QWidget::eventFilter(obj
, event
);
606 // show/hide column Watch-only
607 void TransactionView::updateWatchOnlyColumn(bool fHaveWatchOnly
)
609 watchOnlyWidget
->setVisible(fHaveWatchOnly
);
610 transactionView
->setColumnHidden(TransactionTableModel::Watchonly
, !fHaveWatchOnly
);