LCOV - code coverage report
Current view: top level - src/qt - transactionview.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 0 414 0.0 %
Date: 2020-09-26 01:30:44 Functions: 0 34 0.0 %

          Line data    Source code
       1             : // Copyright (c) 2011-2019 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.
       4             : 
       5             : #include <qt/transactionview.h>
       6             : 
       7             : #include <qt/addresstablemodel.h>
       8             : #include <qt/bitcoinunits.h>
       9             : #include <qt/csvmodelwriter.h>
      10             : #include <qt/editaddressdialog.h>
      11             : #include <qt/guiutil.h>
      12             : #include <qt/optionsmodel.h>
      13             : #include <qt/platformstyle.h>
      14             : #include <qt/transactiondescdialog.h>
      15             : #include <qt/transactionfilterproxy.h>
      16             : #include <qt/transactionrecord.h>
      17             : #include <qt/transactiontablemodel.h>
      18             : #include <qt/walletmodel.h>
      19             : 
      20             : #include <node/ui_interface.h>
      21             : 
      22             : #include <QApplication>
      23             : #include <QComboBox>
      24             : #include <QDateTimeEdit>
      25             : #include <QDesktopServices>
      26             : #include <QDoubleValidator>
      27             : #include <QHBoxLayout>
      28             : #include <QHeaderView>
      29             : #include <QLabel>
      30             : #include <QLineEdit>
      31             : #include <QMenu>
      32             : #include <QPoint>
      33             : #include <QScrollBar>
      34             : #include <QTableView>
      35             : #include <QTimer>
      36             : #include <QUrl>
      37             : #include <QVBoxLayout>
      38             : 
      39           0 : TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *parent) :
      40           0 :     QWidget(parent)
      41           0 : {
      42             :     // Build filter row
      43           0 :     setContentsMargins(0,0,0,0);
      44             : 
      45           0 :     QHBoxLayout *hlayout = new QHBoxLayout();
      46           0 :     hlayout->setContentsMargins(0,0,0,0);
      47             : 
      48           0 :     if (platformStyle->getUseExtraSpacing()) {
      49           0 :         hlayout->setSpacing(5);
      50           0 :         hlayout->addSpacing(26);
      51             :     } else {
      52           0 :         hlayout->setSpacing(0);
      53           0 :         hlayout->addSpacing(23);
      54             :     }
      55             : 
      56           0 :     watchOnlyWidget = new QComboBox(this);
      57           0 :     watchOnlyWidget->setFixedWidth(24);
      58           0 :     watchOnlyWidget->addItem("", TransactionFilterProxy::WatchOnlyFilter_All);
      59           0 :     watchOnlyWidget->addItem(platformStyle->SingleColorIcon(":/icons/eye_plus"), "", TransactionFilterProxy::WatchOnlyFilter_Yes);
      60           0 :     watchOnlyWidget->addItem(platformStyle->SingleColorIcon(":/icons/eye_minus"), "", TransactionFilterProxy::WatchOnlyFilter_No);
      61           0 :     hlayout->addWidget(watchOnlyWidget);
      62             : 
      63           0 :     dateWidget = new QComboBox(this);
      64           0 :     if (platformStyle->getUseExtraSpacing()) {
      65           0 :         dateWidget->setFixedWidth(121);
      66             :     } else {
      67           0 :         dateWidget->setFixedWidth(120);
      68             :     }
      69           0 :     dateWidget->addItem(tr("All"), All);
      70           0 :     dateWidget->addItem(tr("Today"), Today);
      71           0 :     dateWidget->addItem(tr("This week"), ThisWeek);
      72           0 :     dateWidget->addItem(tr("This month"), ThisMonth);
      73           0 :     dateWidget->addItem(tr("Last month"), LastMonth);
      74           0 :     dateWidget->addItem(tr("This year"), ThisYear);
      75           0 :     dateWidget->addItem(tr("Range..."), Range);
      76           0 :     hlayout->addWidget(dateWidget);
      77             : 
      78           0 :     typeWidget = new QComboBox(this);
      79           0 :     if (platformStyle->getUseExtraSpacing()) {
      80           0 :         typeWidget->setFixedWidth(121);
      81           0 :     } else {
      82           0 :         typeWidget->setFixedWidth(120);
      83             :     }
      84             : 
      85           0 :     typeWidget->addItem(tr("All"), TransactionFilterProxy::ALL_TYPES);
      86           0 :     typeWidget->addItem(tr("Received with"), TransactionFilterProxy::TYPE(TransactionRecord::RecvWithAddress) |
      87           0 :                                         TransactionFilterProxy::TYPE(TransactionRecord::RecvFromOther));
      88           0 :     typeWidget->addItem(tr("Sent to"), TransactionFilterProxy::TYPE(TransactionRecord::SendToAddress) |
      89           0 :                                   TransactionFilterProxy::TYPE(TransactionRecord::SendToOther));
      90           0 :     typeWidget->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf));
      91           0 :     typeWidget->addItem(tr("Mined"), TransactionFilterProxy::TYPE(TransactionRecord::Generated));
      92           0 :     typeWidget->addItem(tr("Other"), TransactionFilterProxy::TYPE(TransactionRecord::Other));
      93             : 
      94           0 :     hlayout->addWidget(typeWidget);
      95             : 
      96           0 :     search_widget = new QLineEdit(this);
      97           0 :     search_widget->setPlaceholderText(tr("Enter address, transaction id, or label to search"));
      98           0 :     hlayout->addWidget(search_widget);
      99             : 
     100           0 :     amountWidget = new QLineEdit(this);
     101           0 :     amountWidget->setPlaceholderText(tr("Min amount"));
     102           0 :     if (platformStyle->getUseExtraSpacing()) {
     103           0 :         amountWidget->setFixedWidth(97);
     104             :     } else {
     105           0 :         amountWidget->setFixedWidth(100);
     106             :     }
     107           0 :     QDoubleValidator *amountValidator = new QDoubleValidator(0, 1e20, 8, this);
     108           0 :     QLocale amountLocale(QLocale::C);
     109           0 :     amountLocale.setNumberOptions(QLocale::RejectGroupSeparator);
     110           0 :     amountValidator->setLocale(amountLocale);
     111           0 :     amountWidget->setValidator(amountValidator);
     112           0 :     hlayout->addWidget(amountWidget);
     113             : 
     114             :     // Delay before filtering transactions in ms
     115             :     static const int input_filter_delay = 200;
     116             : 
     117           0 :     QTimer* amount_typing_delay = new QTimer(this);
     118           0 :     amount_typing_delay->setSingleShot(true);
     119           0 :     amount_typing_delay->setInterval(input_filter_delay);
     120             : 
     121           0 :     QTimer* prefix_typing_delay = new QTimer(this);
     122           0 :     prefix_typing_delay->setSingleShot(true);
     123           0 :     prefix_typing_delay->setInterval(input_filter_delay);
     124             : 
     125           0 :     QVBoxLayout *vlayout = new QVBoxLayout(this);
     126           0 :     vlayout->setContentsMargins(0,0,0,0);
     127           0 :     vlayout->setSpacing(0);
     128             : 
     129           0 :     QTableView *view = new QTableView(this);
     130           0 :     vlayout->addLayout(hlayout);
     131           0 :     vlayout->addWidget(createDateRangeWidget());
     132           0 :     vlayout->addWidget(view);
     133           0 :     vlayout->setSpacing(0);
     134           0 :     int width = view->verticalScrollBar()->sizeHint().width();
     135             :     // Cover scroll bar width with spacing
     136           0 :     if (platformStyle->getUseExtraSpacing()) {
     137           0 :         hlayout->addSpacing(width+2);
     138             :     } else {
     139           0 :         hlayout->addSpacing(width);
     140             :     }
     141             :     // Always show scroll bar
     142           0 :     view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
     143           0 :     view->setTabKeyNavigation(false);
     144           0 :     view->setContextMenuPolicy(Qt::CustomContextMenu);
     145             : 
     146           0 :     view->installEventFilter(this);
     147             : 
     148           0 :     transactionView = view;
     149           0 :     transactionView->setObjectName("transactionView");
     150             : 
     151             :     // Actions
     152           0 :     abandonAction = new QAction(tr("Abandon transaction"), this);
     153           0 :     bumpFeeAction = new QAction(tr("Increase transaction fee"), this);
     154           0 :     bumpFeeAction->setObjectName("bumpFeeAction");
     155           0 :     copyAddressAction = new QAction(tr("Copy address"), this);
     156           0 :     copyLabelAction = new QAction(tr("Copy label"), this);
     157           0 :     QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
     158           0 :     QAction *copyTxIDAction = new QAction(tr("Copy transaction ID"), this);
     159           0 :     QAction *copyTxHexAction = new QAction(tr("Copy raw transaction"), this);
     160           0 :     QAction *copyTxPlainText = new QAction(tr("Copy full transaction details"), this);
     161           0 :     QAction *editLabelAction = new QAction(tr("Edit label"), this);
     162           0 :     QAction *showDetailsAction = new QAction(tr("Show transaction details"), this);
     163             : 
     164           0 :     contextMenu = new QMenu(this);
     165           0 :     contextMenu->setObjectName("contextMenu");
     166           0 :     contextMenu->addAction(copyAddressAction);
     167           0 :     contextMenu->addAction(copyLabelAction);
     168           0 :     contextMenu->addAction(copyAmountAction);
     169           0 :     contextMenu->addAction(copyTxIDAction);
     170           0 :     contextMenu->addAction(copyTxHexAction);
     171           0 :     contextMenu->addAction(copyTxPlainText);
     172           0 :     contextMenu->addAction(showDetailsAction);
     173           0 :     contextMenu->addSeparator();
     174           0 :     contextMenu->addAction(bumpFeeAction);
     175           0 :     contextMenu->addAction(abandonAction);
     176           0 :     contextMenu->addAction(editLabelAction);
     177             : 
     178           0 :     connect(dateWidget, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TransactionView::chooseDate);
     179           0 :     connect(typeWidget, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TransactionView::chooseType);
     180           0 :     connect(watchOnlyWidget, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TransactionView::chooseWatchonly);
     181           0 :     connect(amountWidget, &QLineEdit::textChanged, amount_typing_delay, static_cast<void (QTimer::*)()>(&QTimer::start));
     182           0 :     connect(amount_typing_delay, &QTimer::timeout, this, &TransactionView::changedAmount);
     183           0 :     connect(search_widget, &QLineEdit::textChanged, prefix_typing_delay, static_cast<void (QTimer::*)()>(&QTimer::start));
     184           0 :     connect(prefix_typing_delay, &QTimer::timeout, this, &TransactionView::changedSearch);
     185             : 
     186           0 :     connect(view, &QTableView::doubleClicked, this, &TransactionView::doubleClicked);
     187           0 :     connect(view, &QTableView::customContextMenuRequested, this, &TransactionView::contextualMenu);
     188             : 
     189           0 :     connect(bumpFeeAction, &QAction::triggered, this, &TransactionView::bumpFee);
     190           0 :     connect(abandonAction, &QAction::triggered, this, &TransactionView::abandonTx);
     191           0 :     connect(copyAddressAction, &QAction::triggered, this, &TransactionView::copyAddress);
     192           0 :     connect(copyLabelAction, &QAction::triggered, this, &TransactionView::copyLabel);
     193           0 :     connect(copyAmountAction, &QAction::triggered, this, &TransactionView::copyAmount);
     194           0 :     connect(copyTxIDAction, &QAction::triggered, this, &TransactionView::copyTxID);
     195           0 :     connect(copyTxHexAction, &QAction::triggered, this, &TransactionView::copyTxHex);
     196           0 :     connect(copyTxPlainText, &QAction::triggered, this, &TransactionView::copyTxPlainText);
     197           0 :     connect(editLabelAction, &QAction::triggered, this, &TransactionView::editLabel);
     198           0 :     connect(showDetailsAction, &QAction::triggered, this, &TransactionView::showDetails);
     199             :     // Double-clicking on a transaction on the transaction history page shows details
     200           0 :     connect(this, &TransactionView::doubleClicked, this, &TransactionView::showDetails);
     201             :     // Highlight transaction after fee bump
     202           0 :     connect(this, &TransactionView::bumpedFee, [this](const uint256& txid) {
     203           0 :       focusTransaction(txid);
     204           0 :     });
     205           0 : }
     206             : 
     207           0 : void TransactionView::setModel(WalletModel *_model)
     208             : {
     209           0 :     this->model = _model;
     210           0 :     if(_model)
     211             :     {
     212           0 :         transactionProxyModel = new TransactionFilterProxy(this);
     213           0 :         transactionProxyModel->setSourceModel(_model->getTransactionTableModel());
     214           0 :         transactionProxyModel->setDynamicSortFilter(true);
     215           0 :         transactionProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
     216           0 :         transactionProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
     217             : 
     218           0 :         transactionProxyModel->setSortRole(Qt::EditRole);
     219             : 
     220           0 :         transactionView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
     221           0 :         transactionView->setModel(transactionProxyModel);
     222           0 :         transactionView->setAlternatingRowColors(true);
     223           0 :         transactionView->setSelectionBehavior(QAbstractItemView::SelectRows);
     224           0 :         transactionView->setSelectionMode(QAbstractItemView::ExtendedSelection);
     225           0 :         transactionView->horizontalHeader()->setSortIndicator(TransactionTableModel::Date, Qt::DescendingOrder);
     226           0 :         transactionView->setSortingEnabled(true);
     227           0 :         transactionView->verticalHeader()->hide();
     228             : 
     229           0 :         transactionView->setColumnWidth(TransactionTableModel::Status, STATUS_COLUMN_WIDTH);
     230           0 :         transactionView->setColumnWidth(TransactionTableModel::Watchonly, WATCHONLY_COLUMN_WIDTH);
     231           0 :         transactionView->setColumnWidth(TransactionTableModel::Date, DATE_COLUMN_WIDTH);
     232           0 :         transactionView->setColumnWidth(TransactionTableModel::Type, TYPE_COLUMN_WIDTH);
     233           0 :         transactionView->setColumnWidth(TransactionTableModel::Amount, AMOUNT_MINIMUM_COLUMN_WIDTH);
     234             : 
     235           0 :         columnResizingFixer = new GUIUtil::TableViewLastColumnResizingFixer(transactionView, AMOUNT_MINIMUM_COLUMN_WIDTH, MINIMUM_COLUMN_WIDTH, this);
     236             : 
     237           0 :         if (_model->getOptionsModel())
     238             :         {
     239             :             // Add third party transaction URLs to context menu
     240           0 :             QStringList listUrls = _model->getOptionsModel()->getThirdPartyTxUrls().split("|", QString::SkipEmptyParts);
     241           0 :             for (int i = 0; i < listUrls.size(); ++i)
     242             :             {
     243           0 :                 QString url = listUrls[i].trimmed();
     244           0 :                 QString host = QUrl(url, QUrl::StrictMode).host();
     245           0 :                 if (!host.isEmpty())
     246             :                 {
     247           0 :                     QAction *thirdPartyTxUrlAction = new QAction(host, this); // use host as menu item label
     248           0 :                     if (i == 0)
     249           0 :                         contextMenu->addSeparator();
     250           0 :                     contextMenu->addAction(thirdPartyTxUrlAction);
     251           0 :                     connect(thirdPartyTxUrlAction, &QAction::triggered, [this, url] { openThirdPartyTxUrl(url); });
     252           0 :                 }
     253           0 :             }
     254           0 :         }
     255             : 
     256             :         // show/hide column Watch-only
     257           0 :         updateWatchOnlyColumn(_model->wallet().haveWatchOnly());
     258             : 
     259             :         // Watch-only signal
     260           0 :         connect(_model, &WalletModel::notifyWatchonlyChanged, this, &TransactionView::updateWatchOnlyColumn);
     261           0 :     }
     262           0 : }
     263             : 
     264           0 : void TransactionView::chooseDate(int idx)
     265             : {
     266           0 :     if (!transactionProxyModel) return;
     267           0 :     QDate current = QDate::currentDate();
     268           0 :     dateRangeWidget->setVisible(false);
     269           0 :     switch(dateWidget->itemData(idx).toInt())
     270             :     {
     271             :     case All:
     272           0 :         transactionProxyModel->setDateRange(
     273             :                 TransactionFilterProxy::MIN_DATE,
     274             :                 TransactionFilterProxy::MAX_DATE);
     275           0 :         break;
     276             :     case Today:
     277           0 :         transactionProxyModel->setDateRange(
     278           0 :                 QDateTime(current),
     279             :                 TransactionFilterProxy::MAX_DATE);
     280           0 :         break;
     281             :     case ThisWeek: {
     282             :         // Find last Monday
     283           0 :         QDate startOfWeek = current.addDays(-(current.dayOfWeek()-1));
     284           0 :         transactionProxyModel->setDateRange(
     285           0 :                 QDateTime(startOfWeek),
     286             :                 TransactionFilterProxy::MAX_DATE);
     287             : 
     288           0 :         } break;
     289             :     case ThisMonth:
     290           0 :         transactionProxyModel->setDateRange(
     291           0 :                 QDateTime(QDate(current.year(), current.month(), 1)),
     292             :                 TransactionFilterProxy::MAX_DATE);
     293           0 :         break;
     294             :     case LastMonth:
     295           0 :         transactionProxyModel->setDateRange(
     296           0 :                 QDateTime(QDate(current.year(), current.month(), 1).addMonths(-1)),
     297           0 :                 QDateTime(QDate(current.year(), current.month(), 1)));
     298           0 :         break;
     299             :     case ThisYear:
     300           0 :         transactionProxyModel->setDateRange(
     301           0 :                 QDateTime(QDate(current.year(), 1, 1)),
     302             :                 TransactionFilterProxy::MAX_DATE);
     303           0 :         break;
     304             :     case Range:
     305           0 :         dateRangeWidget->setVisible(true);
     306           0 :         dateRangeChanged();
     307           0 :         break;
     308             :     }
     309           0 : }
     310             : 
     311           0 : void TransactionView::chooseType(int idx)
     312             : {
     313           0 :     if(!transactionProxyModel)
     314             :         return;
     315           0 :     transactionProxyModel->setTypeFilter(
     316           0 :         typeWidget->itemData(idx).toInt());
     317           0 : }
     318             : 
     319           0 : void TransactionView::chooseWatchonly(int idx)
     320             : {
     321           0 :     if(!transactionProxyModel)
     322             :         return;
     323           0 :     transactionProxyModel->setWatchOnlyFilter(
     324           0 :         static_cast<TransactionFilterProxy::WatchOnlyFilter>(watchOnlyWidget->itemData(idx).toInt()));
     325           0 : }
     326             : 
     327           0 : void TransactionView::changedSearch()
     328             : {
     329           0 :     if(!transactionProxyModel)
     330             :         return;
     331           0 :     transactionProxyModel->setSearchString(search_widget->text());
     332           0 : }
     333             : 
     334           0 : void TransactionView::changedAmount()
     335             : {
     336           0 :     if(!transactionProxyModel)
     337             :         return;
     338           0 :     CAmount amount_parsed = 0;
     339           0 :     if (BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), amountWidget->text(), &amount_parsed)) {
     340           0 :         transactionProxyModel->setMinAmount(amount_parsed);
     341           0 :     }
     342             :     else
     343             :     {
     344           0 :         transactionProxyModel->setMinAmount(0);
     345             :     }
     346           0 : }
     347             : 
     348           0 : void TransactionView::exportClicked()
     349             : {
     350           0 :     if (!model || !model->getOptionsModel()) {
     351             :         return;
     352             :     }
     353             : 
     354             :     // CSV is currently the only supported format
     355           0 :     QString filename = GUIUtil::getSaveFileName(this,
     356           0 :         tr("Export Transaction History"), QString(),
     357           0 :         tr("Comma separated file (*.csv)"), nullptr);
     358             : 
     359           0 :     if (filename.isNull())
     360           0 :         return;
     361             : 
     362           0 :     CSVModelWriter writer(filename);
     363             : 
     364             :     // name, column, role
     365           0 :     writer.setModel(transactionProxyModel);
     366           0 :     writer.addColumn(tr("Confirmed"), 0, TransactionTableModel::ConfirmedRole);
     367           0 :     if (model->wallet().haveWatchOnly())
     368           0 :         writer.addColumn(tr("Watch-only"), TransactionTableModel::Watchonly);
     369           0 :     writer.addColumn(tr("Date"), 0, TransactionTableModel::DateRole);
     370           0 :     writer.addColumn(tr("Type"), TransactionTableModel::Type, Qt::EditRole);
     371           0 :     writer.addColumn(tr("Label"), 0, TransactionTableModel::LabelRole);
     372           0 :     writer.addColumn(tr("Address"), 0, TransactionTableModel::AddressRole);
     373           0 :     writer.addColumn(BitcoinUnits::getAmountColumnTitle(model->getOptionsModel()->getDisplayUnit()), 0, TransactionTableModel::FormattedAmountRole);
     374           0 :     writer.addColumn(tr("ID"), 0, TransactionTableModel::TxHashRole);
     375             : 
     376           0 :     if(!writer.write()) {
     377           0 :         Q_EMIT message(tr("Exporting Failed"), tr("There was an error trying to save the transaction history to %1.").arg(filename),
     378             :             CClientUIInterface::MSG_ERROR);
     379           0 :     }
     380             :     else {
     381           0 :         Q_EMIT message(tr("Exporting Successful"), tr("The transaction history was successfully saved to %1.").arg(filename),
     382             :             CClientUIInterface::MSG_INFORMATION);
     383             :     }
     384           0 : }
     385             : 
     386           0 : void TransactionView::contextualMenu(const QPoint &point)
     387             : {
     388           0 :     QModelIndex index = transactionView->indexAt(point);
     389           0 :     QModelIndexList selection = transactionView->selectionModel()->selectedRows(0);
     390           0 :     if (selection.empty())
     391           0 :         return;
     392             : 
     393             :     // check if transaction can be abandoned, disable context menu action in case it doesn't
     394           0 :     uint256 hash;
     395           0 :     hash.SetHex(selection.at(0).data(TransactionTableModel::TxHashRole).toString().toStdString());
     396           0 :     abandonAction->setEnabled(model->wallet().transactionCanBeAbandoned(hash));
     397           0 :     bumpFeeAction->setEnabled(model->wallet().transactionCanBeBumped(hash));
     398           0 :     copyAddressAction->setEnabled(GUIUtil::hasEntryData(transactionView, 0, TransactionTableModel::AddressRole));
     399           0 :     copyLabelAction->setEnabled(GUIUtil::hasEntryData(transactionView, 0, TransactionTableModel::LabelRole));
     400             : 
     401           0 :     if (index.isValid()) {
     402           0 :         GUIUtil::PopupMenu(contextMenu, transactionView->viewport()->mapToGlobal(point));
     403           0 :     }
     404           0 : }
     405             : 
     406           0 : void TransactionView::abandonTx()
     407             : {
     408           0 :     if(!transactionView || !transactionView->selectionModel())
     409             :         return;
     410           0 :     QModelIndexList selection = transactionView->selectionModel()->selectedRows(0);
     411             : 
     412             :     // get the hash from the TxHashRole (QVariant / QString)
     413           0 :     uint256 hash;
     414           0 :     QString hashQStr = selection.at(0).data(TransactionTableModel::TxHashRole).toString();
     415           0 :     hash.SetHex(hashQStr.toStdString());
     416             : 
     417             :     // Abandon the wallet transaction over the walletModel
     418           0 :     model->wallet().abandonTransaction(hash);
     419             : 
     420             :     // Update the table
     421           0 :     model->getTransactionTableModel()->updateTransaction(hashQStr, CT_UPDATED, false);
     422           0 : }
     423             : 
     424           0 : void TransactionView::bumpFee()
     425             : {
     426           0 :     if(!transactionView || !transactionView->selectionModel())
     427             :         return;
     428           0 :     QModelIndexList selection = transactionView->selectionModel()->selectedRows(0);
     429             : 
     430             :     // get the hash from the TxHashRole (QVariant / QString)
     431           0 :     uint256 hash;
     432           0 :     QString hashQStr = selection.at(0).data(TransactionTableModel::TxHashRole).toString();
     433           0 :     hash.SetHex(hashQStr.toStdString());
     434             : 
     435             :     // Bump tx fee over the walletModel
     436           0 :     uint256 newHash;
     437           0 :     if (model->bumpFee(hash, newHash)) {
     438             :         // Update the table
     439           0 :         transactionView->selectionModel()->clearSelection();
     440           0 :         model->getTransactionTableModel()->updateTransaction(hashQStr, CT_UPDATED, true);
     441             : 
     442           0 :         qApp->processEvents();
     443           0 :         Q_EMIT bumpedFee(newHash);
     444             :     }
     445           0 : }
     446             : 
     447           0 : void TransactionView::copyAddress()
     448             : {
     449           0 :     GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::AddressRole);
     450           0 : }
     451             : 
     452           0 : void TransactionView::copyLabel()
     453             : {
     454           0 :     GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::LabelRole);
     455           0 : }
     456             : 
     457           0 : void TransactionView::copyAmount()
     458             : {
     459           0 :     GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::FormattedAmountRole);
     460           0 : }
     461             : 
     462           0 : void TransactionView::copyTxID()
     463             : {
     464           0 :     GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxHashRole);
     465           0 : }
     466             : 
     467           0 : void TransactionView::copyTxHex()
     468             : {
     469           0 :     GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxHexRole);
     470           0 : }
     471             : 
     472           0 : void TransactionView::copyTxPlainText()
     473             : {
     474           0 :     GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxPlainTextRole);
     475           0 : }
     476             : 
     477           0 : void TransactionView::editLabel()
     478             : {
     479           0 :     if(!transactionView->selectionModel() ||!model)
     480             :         return;
     481           0 :     QModelIndexList selection = transactionView->selectionModel()->selectedRows();
     482           0 :     if(!selection.isEmpty())
     483             :     {
     484           0 :         AddressTableModel *addressBook = model->getAddressTableModel();
     485           0 :         if(!addressBook)
     486           0 :             return;
     487           0 :         QString address = selection.at(0).data(TransactionTableModel::AddressRole).toString();
     488           0 :         if(address.isEmpty())
     489             :         {
     490             :             // If this transaction has no associated address, exit
     491           0 :             return;
     492             :         }
     493             :         // Is address in address book? Address book can miss address when a transaction is
     494             :         // sent from outside the UI.
     495           0 :         int idx = addressBook->lookupAddress(address);
     496           0 :         if(idx != -1)
     497             :         {
     498             :             // Edit sending / receiving address
     499           0 :             QModelIndex modelIdx = addressBook->index(idx, 0, QModelIndex());
     500             :             // Determine type of address, launch appropriate editor dialog type
     501           0 :             QString type = modelIdx.data(AddressTableModel::TypeRole).toString();
     502             : 
     503           0 :             EditAddressDialog dlg(
     504           0 :                 type == AddressTableModel::Receive
     505             :                 ? EditAddressDialog::EditReceivingAddress
     506           0 :                 : EditAddressDialog::EditSendingAddress, this);
     507           0 :             dlg.setModel(addressBook);
     508           0 :             dlg.loadRow(idx);
     509           0 :             dlg.exec();
     510           0 :         }
     511             :         else
     512             :         {
     513             :             // Add sending address
     514           0 :             EditAddressDialog dlg(EditAddressDialog::NewSendingAddress,
     515           0 :                 this);
     516           0 :             dlg.setModel(addressBook);
     517           0 :             dlg.setAddress(address);
     518           0 :             dlg.exec();
     519           0 :         }
     520           0 :     }
     521           0 : }
     522             : 
     523           0 : void TransactionView::showDetails()
     524             : {
     525           0 :     if(!transactionView->selectionModel())
     526             :         return;
     527           0 :     QModelIndexList selection = transactionView->selectionModel()->selectedRows();
     528           0 :     if(!selection.isEmpty())
     529             :     {
     530           0 :         TransactionDescDialog *dlg = new TransactionDescDialog(selection.at(0));
     531           0 :         dlg->setAttribute(Qt::WA_DeleteOnClose);
     532           0 :         dlg->show();
     533           0 :     }
     534           0 : }
     535             : 
     536           0 : void TransactionView::openThirdPartyTxUrl(QString url)
     537             : {
     538           0 :     if(!transactionView || !transactionView->selectionModel())
     539             :         return;
     540           0 :     QModelIndexList selection = transactionView->selectionModel()->selectedRows(0);
     541           0 :     if(!selection.isEmpty())
     542           0 :          QDesktopServices::openUrl(QUrl::fromUserInput(url.replace("%s", selection.at(0).data(TransactionTableModel::TxHashRole).toString())));
     543           0 : }
     544             : 
     545           0 : QWidget *TransactionView::createDateRangeWidget()
     546             : {
     547           0 :     dateRangeWidget = new QFrame();
     548           0 :     dateRangeWidget->setFrameStyle(QFrame::Panel | QFrame::Raised);
     549           0 :     dateRangeWidget->setContentsMargins(1,1,1,1);
     550           0 :     QHBoxLayout *layout = new QHBoxLayout(dateRangeWidget);
     551           0 :     layout->setContentsMargins(0,0,0,0);
     552           0 :     layout->addSpacing(23);
     553           0 :     layout->addWidget(new QLabel(tr("Range:")));
     554             : 
     555           0 :     dateFrom = new QDateTimeEdit(this);
     556           0 :     dateFrom->setDisplayFormat("dd/MM/yy");
     557           0 :     dateFrom->setCalendarPopup(true);
     558           0 :     dateFrom->setMinimumWidth(100);
     559           0 :     dateFrom->setDate(QDate::currentDate().addDays(-7));
     560           0 :     layout->addWidget(dateFrom);
     561           0 :     layout->addWidget(new QLabel(tr("to")));
     562             : 
     563           0 :     dateTo = new QDateTimeEdit(this);
     564           0 :     dateTo->setDisplayFormat("dd/MM/yy");
     565           0 :     dateTo->setCalendarPopup(true);
     566           0 :     dateTo->setMinimumWidth(100);
     567           0 :     dateTo->setDate(QDate::currentDate());
     568           0 :     layout->addWidget(dateTo);
     569           0 :     layout->addStretch();
     570             : 
     571             :     // Hide by default
     572           0 :     dateRangeWidget->setVisible(false);
     573             : 
     574             :     // Notify on change
     575           0 :     connect(dateFrom, &QDateTimeEdit::dateChanged, this, &TransactionView::dateRangeChanged);
     576           0 :     connect(dateTo, &QDateTimeEdit::dateChanged, this, &TransactionView::dateRangeChanged);
     577             : 
     578           0 :     return dateRangeWidget;
     579           0 : }
     580             : 
     581           0 : void TransactionView::dateRangeChanged()
     582             : {
     583           0 :     if(!transactionProxyModel)
     584             :         return;
     585           0 :     transactionProxyModel->setDateRange(
     586           0 :             QDateTime(dateFrom->date()),
     587           0 :             QDateTime(dateTo->date()).addDays(1));
     588           0 : }
     589             : 
     590           0 : void TransactionView::focusTransaction(const QModelIndex &idx)
     591             : {
     592           0 :     if(!transactionProxyModel)
     593             :         return;
     594           0 :     QModelIndex targetIdx = transactionProxyModel->mapFromSource(idx);
     595           0 :     transactionView->scrollTo(targetIdx);
     596           0 :     transactionView->setCurrentIndex(targetIdx);
     597           0 :     transactionView->setFocus();
     598           0 : }
     599             : 
     600           0 : void TransactionView::focusTransaction(const uint256& txid)
     601             : {
     602           0 :     if (!transactionProxyModel)
     603             :         return;
     604             : 
     605           0 :     const QModelIndexList results = this->model->getTransactionTableModel()->match(
     606           0 :         this->model->getTransactionTableModel()->index(0,0),
     607             :         TransactionTableModel::TxHashRole,
     608           0 :         QString::fromStdString(txid.ToString()), -1);
     609             : 
     610           0 :     transactionView->setFocus();
     611           0 :     transactionView->selectionModel()->clearSelection();
     612           0 :     for (const QModelIndex& index : results) {
     613           0 :         const QModelIndex targetIndex = transactionProxyModel->mapFromSource(index);
     614           0 :         transactionView->selectionModel()->select(
     615             :             targetIndex,
     616           0 :             QItemSelectionModel::Rows | QItemSelectionModel::Select);
     617             :         // Called once per destination to ensure all results are in view, unless
     618             :         // transactions are not ordered by (ascending or descending) date.
     619           0 :         transactionView->scrollTo(targetIndex);
     620             :         // scrollTo() does not scroll far enough the first time when transactions
     621             :         // are ordered by ascending date.
     622           0 :         if (index == results[0]) transactionView->scrollTo(targetIndex);
     623           0 :     }
     624           0 : }
     625             : 
     626             : // We override the virtual resizeEvent of the QWidget to adjust tables column
     627             : // sizes as the tables width is proportional to the dialogs width.
     628           0 : void TransactionView::resizeEvent(QResizeEvent* event)
     629             : {
     630           0 :     QWidget::resizeEvent(event);
     631           0 :     columnResizingFixer->stretchColumnWidth(TransactionTableModel::ToAddress);
     632           0 : }
     633             : 
     634             : // Need to override default Ctrl+C action for amount as default behaviour is just to copy DisplayRole text
     635           0 : bool TransactionView::eventFilter(QObject *obj, QEvent *event)
     636             : {
     637           0 :     if (event->type() == QEvent::KeyPress)
     638             :     {
     639           0 :         QKeyEvent *ke = static_cast<QKeyEvent *>(event);
     640           0 :         if (ke->key() == Qt::Key_C && ke->modifiers().testFlag(Qt::ControlModifier))
     641             :         {
     642           0 :              GUIUtil::copyEntryData(transactionView, 0, TransactionTableModel::TxPlainTextRole);
     643           0 :              return true;
     644             :         }
     645           0 :     }
     646           0 :     return QWidget::eventFilter(obj, event);
     647           0 : }
     648             : 
     649             : // show/hide column Watch-only
     650           0 : void TransactionView::updateWatchOnlyColumn(bool fHaveWatchOnly)
     651             : {
     652           0 :     watchOnlyWidget->setVisible(fHaveWatchOnly);
     653           0 :     transactionView->setColumnHidden(TransactionTableModel::Watchonly, !fHaveWatchOnly);
     654           0 : }

Generated by: LCOV version 1.15