mirror of
https://github.com/dashpay/dash.git
synced 2024-12-24 19:42:46 +01:00
Merge #6168: backport: bitcoin-core#gui18, #121, #257, #263, #281, #335, #362, #828, bitcoin#21912, #21942, #21988
c7d3161b3b
Merge bitcoin-core/gui#362: Add keyboard shortcuts to context menus (Hennadii Stepanov)25f87b9434
Merge bitcoin-core/gui#121: Early subscribe core signals in transaction table model (Hennadii Stepanov)ed56e28a7c
Merge bitcoin-core/gui#335: test: Use QSignalSpy instead of QEventLoop (Hennadii Stepanov)c52b75609b
Merge bitcoin-core/gui#281: set shortcuts for console's resize buttons (W. J. van der Laan)b442a59b6d
Merge bitcoin/bitcoin#21988: doc: note that brew installed qt is not supported (W. J. van der Laan)0e2e315fcc
Merge bitcoin/bitcoin#21942: docs: improve make with parallel jobs description. (MarcoFalke)c2735a8a67
Merge bitcoin/bitcoin#21912: doc: Remove mention of priority estimation (W. J. van der Laan)1d56d207cd
Merge bitcoin-core/gui#257: refactor: Use template function qOverload in signal-slot connections (Hennadii Stepanov)b5fb559706
Merge bitcoin-core/gui#18: Add peertablesortproxy module (Hennadii Stepanov)1cdd9fbdf5
refactor: use new QAction style for governance list and masternode list (Konstantin Akimov)4f89c98dc4
Merge bitcoin-core/gui#263: Revamp context menus (Hennadii Stepanov)c36bb8e6fb
fix: use && in governance urls instead & (Konstantin Akimov)1e585b1987
Merge bitcoin-core/gui#828: Rendering an amp characters in the wallet name for QMenu (Hennadii Stepanov) Pull request description: ## Issue being fixed or feature implemented Just regular backports from bitcoin v22, mostly Qt related ## What was done? See commits for a list of backports. This PR also fixes a rendering an url on Governance tab if it has any '&' inside. see screenshots. Original url: `https://example.com/?test=nothing&to=see&&lol` - yes, double '&&' just for test even if url is silly. Failed behaviour: ![image](https://github.com/user-attachments/assets/ac45c192-7d0e-4cd2-97f8-060af8f3911b) Correctly rendered: ![image](https://github.com/user-attachments/assets/5e345197-776a-4bb8-9476-cab4aba3429e) ## How Has This Been Tested? Run unit/functional tests ## Breaking Changes N/A ## Checklist: - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation - [x] I have assigned this pull request to a milestone ACKs for top commit: PastaPastaPasta: utACKc7d3161b3b
UdjinM6: utACKc7d3161b3b
Tree-SHA512: 67e7e8e0ec1a768d1f13baa48c123e4a415d3f32177a427d8117339a5eacf70864ebf46e9f1165bb8a3bf9c231f7929d33ac6aa19742e06a4e19d2f86dda6dc3
This commit is contained in:
commit
f2940c4e9c
@ -131,6 +131,6 @@ This explicitly enables the GUI and disables legacy wallet support. If `qt5` is
|
||||
**Important**: Use `gmake` (the non-GNU `make` will exit with an error).
|
||||
|
||||
```bash
|
||||
gmake # use -jX here for parallelism
|
||||
gmake # use "-j N" for N parallel jobs
|
||||
gmake check # Run tests if Python 3 is available
|
||||
```
|
||||
|
@ -79,6 +79,6 @@ Without wallet:
|
||||
|
||||
Build and run the tests:
|
||||
```bash
|
||||
gmake # use -jX here for parallelism
|
||||
gmake # use "-j N" here for N parallel jobs
|
||||
gmake check
|
||||
```
|
||||
|
@ -85,7 +85,7 @@ To configure with GUI:
|
||||
|
||||
Build and run the tests:
|
||||
```bash
|
||||
gmake # use -jX here for parallelism
|
||||
gmake # use "-j N" here for N parallel jobs
|
||||
gmake check
|
||||
```
|
||||
|
||||
|
@ -138,6 +138,14 @@ Skip if you don't intend to use the GUI.
|
||||
brew install qt@5
|
||||
```
|
||||
|
||||
Ensure that the `qt@5` package is installed, not the `qt` package.
|
||||
If 'qt' is installed, the build process will fail.
|
||||
if installed, remove the `qt` package with the following command:
|
||||
|
||||
``` bash
|
||||
brew uninstall qt
|
||||
```
|
||||
|
||||
Note: Building with Qt binaries downloaded from the Qt website is not officially supported.
|
||||
See the notes in [#7714](https://github.com/dashpay/dash/issues/7714).
|
||||
|
||||
@ -276,7 +284,7 @@ After configuration, you are ready to compile.
|
||||
Run the following in your terminal to compile Dash Core:
|
||||
|
||||
``` bash
|
||||
make -jx # use -jX here for parallelism
|
||||
make # use "-j N" here for N parallel jobs
|
||||
make check # Run tests if Python 3 is available
|
||||
```
|
||||
|
||||
|
@ -22,7 +22,7 @@ To Build
|
||||
```sh
|
||||
./autogen.sh
|
||||
./configure
|
||||
make
|
||||
make # use "-j N" for N parallel jobs
|
||||
make install # optional
|
||||
```
|
||||
|
||||
|
@ -65,7 +65,7 @@ Subdirectory | File(s) | Description
|
||||
`./` | `governance.dat` | stores data for governance objects
|
||||
`./` | `mncache.dat` | stores data for masternode list
|
||||
`./` | `netfulfilled.dat` | stores data about recently made network requests
|
||||
`./` | `fee_estimates.dat` | Stores statistics used to estimate minimum transaction fees and priorities required for confirmation
|
||||
`./` | `fee_estimates.dat` | Stores statistics used to estimate minimum transaction fees required for confirmation
|
||||
`./` | `guisettings.ini.bak` | Backup of former [GUI settings](#gui-settings) after `-resetguisettings` option is used
|
||||
`./` | `ip_asn.map` | IP addresses to Autonomous System Numbers (ASNs) mapping used for bucketing of the peers; path can be specified with the `-asmap` option
|
||||
`./` | `mempool.dat` | Dump of the mempool's transactions
|
||||
|
@ -69,6 +69,7 @@ QT_MOC_CPP = \
|
||||
qt/moc_optionsmodel.cpp \
|
||||
qt/moc_overviewpage.cpp \
|
||||
qt/moc_peertablemodel.cpp \
|
||||
qt/moc_peertablesortproxy.cpp \
|
||||
qt/moc_paymentserver.cpp \
|
||||
qt/moc_psbtoperationsdialog.cpp \
|
||||
qt/moc_qrdialog.cpp \
|
||||
@ -146,6 +147,7 @@ BITCOIN_QT_H = \
|
||||
qt/overviewpage.h \
|
||||
qt/paymentserver.h \
|
||||
qt/peertablemodel.h \
|
||||
qt/peertablesortproxy.h \
|
||||
qt/psbtoperationsdialog.h \
|
||||
qt/qrdialog.h \
|
||||
qt/qrimagewidget.h \
|
||||
@ -227,6 +229,7 @@ BITCOIN_QT_BASE_CPP = \
|
||||
qt/optionsdialog.cpp \
|
||||
qt/optionsmodel.cpp \
|
||||
qt/peertablemodel.cpp \
|
||||
qt/peertablesortproxy.cpp \
|
||||
qt/qvalidatedlineedit.cpp \
|
||||
qt/qvaluecombobox.cpp \
|
||||
qt/rpcconsole.cpp \
|
||||
|
@ -107,32 +107,20 @@ AddressBookPage::AddressBookPage(Mode _mode, Tabs _tab, QWidget* parent) :
|
||||
break;
|
||||
}
|
||||
|
||||
// Context menu actions
|
||||
QAction *copyAddressAction = new QAction(tr("&Copy Address"), this);
|
||||
QAction *copyLabelAction = new QAction(tr("Copy &Label"), this);
|
||||
QAction *editAction = new QAction(tr("&Edit"), this);
|
||||
QAction *showAddressQRCodeAction = new QAction(tr("&Show address QR code"), this);
|
||||
deleteAction = new QAction(ui->deleteAddress->text(), this);
|
||||
#ifndef USE_QRCODE
|
||||
showAddressQRCodeAction->setEnabled(false);
|
||||
#endif
|
||||
|
||||
// Build context menu
|
||||
contextMenu = new QMenu(this);
|
||||
contextMenu->addAction(copyAddressAction);
|
||||
contextMenu->addAction(copyLabelAction);
|
||||
contextMenu->addAction(editAction);
|
||||
if(tab == SendingTab)
|
||||
contextMenu->addAction(deleteAction);
|
||||
contextMenu->addSeparator();
|
||||
contextMenu->addAction(showAddressQRCodeAction);
|
||||
contextMenu->addAction(tr("&Copy Address"), this, &AddressBookPage::on_copyAddress_clicked);
|
||||
contextMenu->addAction(tr("Copy &Label"), this, &AddressBookPage::onCopyLabelAction);
|
||||
contextMenu->addAction(tr("&Edit"), this, &AddressBookPage::onEditAction);
|
||||
[[maybe_unused]] QAction* qrAction = contextMenu->addAction(tr("Show address &QR code"), this, &AddressBookPage::on_showAddressQRCode_clicked);
|
||||
#ifndef USE_QRCODE
|
||||
qrAction->setEnabled(false);
|
||||
#endif
|
||||
|
||||
if (tab == SendingTab) {
|
||||
contextMenu->addAction(tr("&Delete"), this, &AddressBookPage::on_deleteAddress_clicked);
|
||||
}
|
||||
|
||||
// Connect signals for context menu actions
|
||||
connect(copyAddressAction, &QAction::triggered, this, &AddressBookPage::on_copyAddress_clicked);
|
||||
connect(copyLabelAction, &QAction::triggered, this, &AddressBookPage::onCopyLabelAction);
|
||||
connect(editAction, &QAction::triggered, this, &AddressBookPage::onEditAction);
|
||||
connect(deleteAction, &QAction::triggered, this, &AddressBookPage::on_deleteAddress_clicked);
|
||||
connect(showAddressQRCodeAction, &QAction::triggered, this, &AddressBookPage::on_showAddressQRCode_clicked);
|
||||
connect(ui->tableView, &QWidget::customContextMenuRequested, this, &AddressBookPage::contextualMenu);
|
||||
connect(ui->closeButton, &QPushButton::clicked, this, &QDialog::accept);
|
||||
|
||||
@ -267,13 +255,11 @@ void AddressBookPage::selectionChanged()
|
||||
// In sending tab, allow deletion of selection
|
||||
ui->deleteAddress->setEnabled(true);
|
||||
ui->deleteAddress->setVisible(true);
|
||||
deleteAction->setEnabled(true);
|
||||
break;
|
||||
case ReceivingTab:
|
||||
// Deleting receiving addresses, however, is not allowed
|
||||
ui->deleteAddress->setEnabled(false);
|
||||
ui->deleteAddress->setVisible(false);
|
||||
deleteAction->setEnabled(false);
|
||||
break;
|
||||
}
|
||||
ui->copyAddress->setEnabled(true);
|
||||
|
@ -54,7 +54,6 @@ private:
|
||||
QString returnValue;
|
||||
AddressBookSortFilterProxyModel *proxyModel;
|
||||
QMenu *contextMenu;
|
||||
QAction *deleteAction; // to be able to explicitly disable it
|
||||
QString newAddressToSelect;
|
||||
|
||||
private Q_SLOTS:
|
||||
|
@ -520,10 +520,9 @@ void BitcoinGUI::createActions()
|
||||
for (const std::pair<const std::string, bool>& i : m_wallet_controller->listWalletDir()) {
|
||||
const std::string& path = i.first;
|
||||
QString name = path.empty() ? QString("["+tr("default wallet")+"]") : QString::fromStdString(path);
|
||||
// Menu items remove single &. Single & are shown when && is in
|
||||
// the string, but only the first occurrence. So replace only
|
||||
// the first & with &&.
|
||||
name.replace(name.indexOf(QChar('&')), 1, QString("&&"));
|
||||
// An single ampersand in the menu item's text sets a shortcut for this item.
|
||||
// Single & are shown when && is in the string. So replace & with &&.
|
||||
name.replace(QChar('&'), QString("&&"));
|
||||
QAction* action = m_open_wallet_menu->addAction(name);
|
||||
|
||||
if (i.second) {
|
||||
@ -747,7 +746,7 @@ void BitcoinGUI::createToolBars()
|
||||
#ifdef ENABLE_WALLET
|
||||
m_wallet_selector = new QComboBox(this);
|
||||
m_wallet_selector->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
connect(m_wallet_selector, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &BitcoinGUI::setCurrentWalletBySelectorIndex);
|
||||
connect(m_wallet_selector, qOverload<int>(&QComboBox::currentIndexChanged), this, &BitcoinGUI::setCurrentWalletBySelectorIndex);
|
||||
|
||||
QVBoxLayout* walletSelectorLayout = new QVBoxLayout(this);
|
||||
walletSelectorLayout->addWidget(m_wallet_selector);
|
||||
@ -2055,11 +2054,8 @@ void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent *event)
|
||||
void UnitDisplayStatusBarControl::createContextMenu()
|
||||
{
|
||||
menu = new QMenu(this);
|
||||
for (const BitcoinUnits::Unit u : BitcoinUnits::availableUnits())
|
||||
{
|
||||
QAction *menuAction = new QAction(QString(BitcoinUnits::name(u)), this);
|
||||
menuAction->setData(QVariant(u));
|
||||
menu->addAction(menuAction);
|
||||
for (const BitcoinUnits::Unit u : BitcoinUnits::availableUnits()) {
|
||||
menu->addAction(BitcoinUnits::name(u))->setData(QVariant(u));
|
||||
}
|
||||
connect(menu, &QMenu::triggered, this, &UnitDisplayStatusBarControl::onMenuSelection);
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <qt/guiconstants.h>
|
||||
#include <qt/guiutil.h>
|
||||
#include <qt/peertablemodel.h>
|
||||
#include <qt/peertablesortproxy.h>
|
||||
|
||||
#include <evo/deterministicmns.h>
|
||||
|
||||
@ -42,7 +43,11 @@ ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QO
|
||||
{
|
||||
cachedBestHeaderHeight = -1;
|
||||
cachedBestHeaderTime = -1;
|
||||
|
||||
peerTableModel = new PeerTableModel(m_node, this);
|
||||
m_peer_table_sort_proxy = new PeerTableSortProxy(this);
|
||||
m_peer_table_sort_proxy->setSourceModel(peerTableModel);
|
||||
|
||||
banTableModel = new BanTableModel(m_node, this);
|
||||
mnListCached = std::make_shared<CDeterministicMNList>();
|
||||
|
||||
@ -219,6 +224,11 @@ PeerTableModel *ClientModel::getPeerTableModel()
|
||||
return peerTableModel;
|
||||
}
|
||||
|
||||
PeerTableSortProxy* ClientModel::peerTableSortProxy()
|
||||
{
|
||||
return m_peer_table_sort_proxy;
|
||||
}
|
||||
|
||||
BanTableModel *ClientModel::getBanTableModel()
|
||||
{
|
||||
return banTableModel;
|
||||
|
@ -20,6 +20,7 @@ class BanTableModel;
|
||||
class CBlockIndex;
|
||||
class OptionsModel;
|
||||
class PeerTableModel;
|
||||
class PeerTableSortProxy;
|
||||
enum class SynchronizationState;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
@ -58,6 +59,7 @@ public:
|
||||
interfaces::CoinJoin::Options& coinJoinOptions() const { return m_node.coinJoinOptions(); }
|
||||
OptionsModel *getOptionsModel();
|
||||
PeerTableModel *getPeerTableModel();
|
||||
PeerTableSortProxy* peerTableSortProxy();
|
||||
BanTableModel *getBanTableModel();
|
||||
|
||||
//! Return number of connections, default is in- and outbound (total)
|
||||
@ -109,6 +111,7 @@ private:
|
||||
std::unique_ptr<interfaces::Handler> m_handler_notify_additional_data_sync_progess_changed;
|
||||
OptionsModel *optionsModel;
|
||||
PeerTableModel *peerTableModel;
|
||||
PeerTableSortProxy* m_peer_table_sort_proxy{nullptr};
|
||||
BanTableModel *banTableModel;
|
||||
|
||||
//! A thread to interact with m_node asynchronously
|
||||
|
@ -62,32 +62,16 @@ CoinControlDialog::CoinControlDialog(CCoinControl& coin_control, WalletModel* _m
|
||||
|
||||
GUIUtil::disableMacFocusRect(this);
|
||||
|
||||
// context menu actions
|
||||
QAction *copyAddressAction = new QAction(tr("Copy address"), this);
|
||||
QAction *copyLabelAction = new QAction(tr("Copy label"), this);
|
||||
QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
|
||||
copyTransactionHashAction = new QAction(tr("Copy transaction ID"), this); // we need to enable/disable this
|
||||
lockAction = new QAction(tr("Lock unspent"), this); // we need to enable/disable this
|
||||
unlockAction = new QAction(tr("Unlock unspent"), this); // we need to enable/disable this
|
||||
|
||||
// context menu
|
||||
contextMenu = new QMenu(this);
|
||||
contextMenu->addAction(copyAddressAction);
|
||||
contextMenu->addAction(copyLabelAction);
|
||||
contextMenu->addAction(copyAmountAction);
|
||||
contextMenu->addAction(copyTransactionHashAction);
|
||||
contextMenu->addAction(tr("&Copy address"), this, &CoinControlDialog::copyAddress);
|
||||
contextMenu->addAction(tr("Copy &label"), this, &CoinControlDialog::copyLabel);
|
||||
contextMenu->addAction(tr("Copy &amount"), this, &CoinControlDialog::copyAmount);
|
||||
copyTransactionHashAction = contextMenu->addAction(tr("Copy transaction &ID"), this, &CoinControlDialog::copyTransactionHash);
|
||||
contextMenu->addSeparator();
|
||||
contextMenu->addAction(lockAction);
|
||||
contextMenu->addAction(unlockAction);
|
||||
|
||||
// context menu signals
|
||||
lockAction = contextMenu->addAction(tr("L&ock unspent"), this, &CoinControlDialog::lockCoin);
|
||||
unlockAction = contextMenu->addAction(tr("&Unlock unspent"), this, &CoinControlDialog::unlockCoin);
|
||||
connect(ui->treeWidget, &QWidget::customContextMenuRequested, this, &CoinControlDialog::showMenu);
|
||||
connect(copyAddressAction, &QAction::triggered, this, &CoinControlDialog::copyAddress);
|
||||
connect(copyLabelAction, &QAction::triggered, this, &CoinControlDialog::copyLabel);
|
||||
connect(copyAmountAction, &QAction::triggered, this, &CoinControlDialog::copyAmount);
|
||||
connect(copyTransactionHashAction, &QAction::triggered, this, &CoinControlDialog::copyTransactionHash);
|
||||
connect(lockAction, &QAction::triggered, this, &CoinControlDialog::lockCoin);
|
||||
connect(unlockAction, &QAction::triggered, this, &CoinControlDialog::unlockCoin);
|
||||
|
||||
// clipboard actions
|
||||
QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this);
|
||||
|
@ -388,10 +388,11 @@ void GovernanceList::showProposalContextMenu(const QPoint& pos)
|
||||
}
|
||||
|
||||
// right click menu with option to open proposal url
|
||||
QAction* openProposalUrl = new QAction(proposal->url(), this);
|
||||
QString proposal_url = proposal->url();
|
||||
proposal_url.replace(QChar('&'), QString("&&"));
|
||||
|
||||
proposalContextMenu->clear();
|
||||
proposalContextMenu->addAction(openProposalUrl);
|
||||
connect(openProposalUrl, &QAction::triggered, proposal, &Proposal::openUrl);
|
||||
proposalContextMenu->addAction(proposal_url, proposal, &Proposal::openUrl);
|
||||
proposalContextMenu->exec(QCursor::pos());
|
||||
}
|
||||
|
||||
|
@ -345,6 +345,11 @@ void setupAppearance(QWidget* parent, OptionsModel* model)
|
||||
}
|
||||
}
|
||||
|
||||
void AddButtonShortcut(QAbstractButton* button, const QKeySequence& shortcut)
|
||||
{
|
||||
QObject::connect(new QShortcut(shortcut, button), &QShortcut::activated, [button]() { button->animateClick(); });
|
||||
}
|
||||
|
||||
bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
|
||||
{
|
||||
// return if URI is not valid or is no dash: URI
|
||||
|
@ -44,6 +44,7 @@ class QAction;
|
||||
class QButtonGroup;
|
||||
class QDateTime;
|
||||
class QFont;
|
||||
class QKeySequence;
|
||||
class QLineEdit;
|
||||
class QMenu;
|
||||
class QPoint;
|
||||
@ -135,6 +136,14 @@ namespace GUIUtil
|
||||
// Setup appearance settings if not done yet
|
||||
void setupAppearance(QWidget* parent, OptionsModel* model);
|
||||
|
||||
/**
|
||||
* Connects an additional shortcut to a QAbstractButton. Works around the
|
||||
* one shortcut limitation of the button's shortcut property.
|
||||
* @param[in] button QAbstractButton to assign shortcut to
|
||||
* @param[in] shortcut QKeySequence to use as shortcut
|
||||
*/
|
||||
void AddButtonShortcut(QAbstractButton* button, const QKeySequence& shortcut);
|
||||
|
||||
// Parse "dash:" URI into recipient object, return true on successful parsing
|
||||
bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out);
|
||||
bool parseBitcoinURI(QString uri, SendCoinsRecipient *out);
|
||||
|
@ -156,7 +156,7 @@ Intro::Intro(QWidget *parent, int64_t blockchain_size_gb, int64_t chain_state_si
|
||||
UpdatePruneLabels(prune_checked);
|
||||
UpdateFreeSpaceLabel();
|
||||
});
|
||||
connect(ui->pruneGB, QOverload<int>::of(&QSpinBox::valueChanged), [this](int prune_GB) {
|
||||
connect(ui->pruneGB, qOverload<int>(&QSpinBox::valueChanged), [this](int prune_GB) {
|
||||
m_prune_target_gb = prune_GB;
|
||||
UpdatePruneLabels(ui->prune->isChecked());
|
||||
UpdateFreeSpaceLabel();
|
||||
|
@ -81,15 +81,12 @@ MasternodeList::MasternodeList(QWidget* parent) :
|
||||
|
||||
ui->checkBoxMyMasternodesOnly->setEnabled(false);
|
||||
|
||||
QAction* copyProTxHashAction = new QAction(tr("Copy ProTx Hash"), this);
|
||||
QAction* copyCollateralOutpointAction = new QAction(tr("Copy Collateral Outpoint"), this);
|
||||
contextMenuDIP3 = new QMenu(this);
|
||||
contextMenuDIP3->addAction(copyProTxHashAction);
|
||||
contextMenuDIP3->addAction(copyCollateralOutpointAction);
|
||||
contextMenuDIP3->addAction(tr("Copy ProTx Hash"), this, &MasternodeList::copyProTxHash_clicked);
|
||||
contextMenuDIP3->addAction(tr("Copy Collateral Outpoint"), this, &MasternodeList::copyCollateralOutpoint_clicked);
|
||||
|
||||
connect(ui->tableWidgetMasternodesDIP3, &QTableWidget::customContextMenuRequested, this, &MasternodeList::showContextMenuDIP3);
|
||||
connect(ui->tableWidgetMasternodesDIP3, &QTableWidget::doubleClicked, this, &MasternodeList::extraInfoDIP3_clicked);
|
||||
connect(copyProTxHashAction, &QAction::triggered, this, &MasternodeList::copyProTxHash_clicked);
|
||||
connect(copyCollateralOutpointAction, &QAction::triggered, this, &MasternodeList::copyCollateralOutpoint_clicked);
|
||||
|
||||
timer = new QTimer(this);
|
||||
connect(timer, &QTimer::timeout, this, &MasternodeList::updateDIP3ListScheduled);
|
||||
|
@ -258,9 +258,9 @@ void OptionsDialog::setModel(OptionsModel *_model)
|
||||
/* Main */
|
||||
connect(ui->prune, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning);
|
||||
connect(ui->prune, &QCheckBox::clicked, this, &OptionsDialog::togglePruneWarning);
|
||||
connect(ui->pruneSize, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &OptionsDialog::showRestartWarning);
|
||||
connect(ui->databaseCache, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &OptionsDialog::showRestartWarning);
|
||||
connect(ui->threadsScriptVerif, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &OptionsDialog::showRestartWarning);
|
||||
connect(ui->pruneSize, qOverload<int>(&QSpinBox::valueChanged), this, &OptionsDialog::showRestartWarning);
|
||||
connect(ui->databaseCache, qOverload<int>(&QSpinBox::valueChanged), this, &OptionsDialog::showRestartWarning);
|
||||
connect(ui->threadsScriptVerif, qOverload<int>(&QSpinBox::valueChanged), this, &OptionsDialog::showRestartWarning);
|
||||
/* Wallet */
|
||||
connect(ui->showMasternodesTab, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning);
|
||||
connect(ui->showGovernanceTab, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning);
|
||||
@ -270,8 +270,8 @@ void OptionsDialog::setModel(OptionsModel *_model)
|
||||
connect(ui->connectSocks, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning);
|
||||
connect(ui->connectSocksTor, &QCheckBox::clicked, this, &OptionsDialog::showRestartWarning);
|
||||
/* Display */
|
||||
connect(ui->digits, static_cast<void (QValueComboBox::*)()>(&QValueComboBox::valueChanged), [this]{ showRestartWarning(); });
|
||||
connect(ui->lang, static_cast<void (QValueComboBox::*)()>(&QValueComboBox::valueChanged), [this]{ showRestartWarning(); });
|
||||
connect(ui->digits, qOverload<>(&QValueComboBox::valueChanged), [this]{ showRestartWarning(); });
|
||||
connect(ui->lang, qOverload<>(&QValueComboBox::valueChanged), [this]{ showRestartWarning(); });
|
||||
connect(ui->thirdPartyTxUrls, &QLineEdit::textChanged, [this]{ showRestartWarning(); });
|
||||
|
||||
connect(ui->coinJoinEnabled, &QCheckBox::clicked, [=](bool fChecked) {
|
||||
@ -296,8 +296,8 @@ void OptionsDialog::setModel(OptionsModel *_model)
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->coinJoinDenomsGoal, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &OptionsDialog::updateCoinJoinDenomGoal);
|
||||
connect(ui->coinJoinDenomsHardCap, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &OptionsDialog::updateCoinJoinDenomHardCap);
|
||||
connect(ui->coinJoinDenomsGoal, qOverload<int>(&QSpinBox::valueChanged), this, &OptionsDialog::updateCoinJoinDenomGoal);
|
||||
connect(ui->coinJoinDenomsHardCap, qOverload<int>(&QSpinBox::valueChanged), this, &OptionsDialog::updateCoinJoinDenomHardCap);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -11,56 +11,19 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QList>
|
||||
#include <QTimer>
|
||||
|
||||
bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombinedStats &right) const
|
||||
{
|
||||
const CNodeStats *pLeft = &(left.nodeStats);
|
||||
const CNodeStats *pRight = &(right.nodeStats);
|
||||
|
||||
if (order == Qt::DescendingOrder)
|
||||
std::swap(pLeft, pRight);
|
||||
|
||||
switch (static_cast<PeerTableModel::ColumnIndex>(column)) {
|
||||
case PeerTableModel::NetNodeId:
|
||||
return pLeft->nodeid < pRight->nodeid;
|
||||
case PeerTableModel::Address:
|
||||
return pLeft->m_addr_name.compare(pRight->m_addr_name) < 0;
|
||||
case PeerTableModel::ConnectionType:
|
||||
return pLeft->m_conn_type < pRight->m_conn_type;
|
||||
case PeerTableModel::Network:
|
||||
return pLeft->m_network < pRight->m_network;
|
||||
case PeerTableModel::Ping:
|
||||
return pLeft->m_min_ping_time < pRight->m_min_ping_time;
|
||||
case PeerTableModel::Sent:
|
||||
return pLeft->nSendBytes < pRight->nSendBytes;
|
||||
case PeerTableModel::Received:
|
||||
return pLeft->nRecvBytes < pRight->nRecvBytes;
|
||||
case PeerTableModel::Subversion:
|
||||
return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0;
|
||||
} // no default case, so the compiler can warn about missing cases
|
||||
assert(false);
|
||||
}
|
||||
|
||||
// private implementation
|
||||
class PeerTablePriv
|
||||
{
|
||||
public:
|
||||
/** Local cache of peer information */
|
||||
QList<CNodeCombinedStats> cachedNodeStats;
|
||||
/** Column to sort nodes by (default to unsorted) */
|
||||
int sortColumn{-1};
|
||||
/** Order (ascending or descending) to sort nodes by */
|
||||
Qt::SortOrder sortOrder;
|
||||
/** Index of rows by node ID */
|
||||
std::map<NodeId, int> mapNodeRows;
|
||||
|
||||
/** Pull a full list of peers from vNodes into our cache */
|
||||
void refreshPeers(interfaces::Node& node)
|
||||
{
|
||||
{
|
||||
cachedNodeStats.clear();
|
||||
|
||||
interfaces::Node::NodesStats nodes_stats;
|
||||
@ -75,17 +38,6 @@ public:
|
||||
stats.nodeStateStats = std::get<2>(node_stats);
|
||||
cachedNodeStats.append(stats);
|
||||
}
|
||||
}
|
||||
|
||||
if (sortColumn >= 0)
|
||||
// sort cacheNodeStats (use stable sort to prevent rows jumping around unnecessarily)
|
||||
std::stable_sort(cachedNodeStats.begin(), cachedNodeStats.end(), NodeLessThan(sortColumn, sortOrder));
|
||||
|
||||
// build index map
|
||||
mapNodeRows.clear();
|
||||
int row = 0;
|
||||
for (const CNodeCombinedStats& stats : cachedNodeStats)
|
||||
mapNodeRows.insert(std::pair<NodeId, int>(stats.nodeStats.nodeid, row++));
|
||||
}
|
||||
|
||||
int size() const
|
||||
@ -196,10 +148,7 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const
|
||||
} // no default case, so the compiler can warn about missing cases
|
||||
assert(false);
|
||||
} else if (role == StatsRole) {
|
||||
switch (index.column()) {
|
||||
case NetNodeId: return QVariant::fromValue(rec);
|
||||
default: return QVariant();
|
||||
}
|
||||
return QVariant::fromValue(rec);
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
@ -241,19 +190,3 @@ void PeerTableModel::refresh()
|
||||
priv->refreshPeers(m_node);
|
||||
Q_EMIT layoutChanged();
|
||||
}
|
||||
|
||||
int PeerTableModel::getRowByNodeId(NodeId nodeid)
|
||||
{
|
||||
std::map<NodeId, int>::iterator it = priv->mapNodeRows.find(nodeid);
|
||||
if (it == priv->mapNodeRows.end())
|
||||
return -1;
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void PeerTableModel::sort(int column, Qt::SortOrder order)
|
||||
{
|
||||
priv->sortColumn = column;
|
||||
priv->sortOrder = order;
|
||||
refresh();
|
||||
}
|
||||
|
@ -30,18 +30,6 @@ struct CNodeCombinedStats {
|
||||
};
|
||||
Q_DECLARE_METATYPE(CNodeCombinedStats*)
|
||||
|
||||
class NodeLessThan
|
||||
{
|
||||
public:
|
||||
NodeLessThan(int nColumn, Qt::SortOrder fOrder) :
|
||||
column(nColumn), order(fOrder) {}
|
||||
bool operator()(const CNodeCombinedStats &left, const CNodeCombinedStats &right) const;
|
||||
|
||||
private:
|
||||
int column;
|
||||
Qt::SortOrder order;
|
||||
};
|
||||
|
||||
/**
|
||||
Qt model providing information about connected peers, similar to the
|
||||
"getpeerinfo" RPC call. Used by the rpc console UI.
|
||||
@ -53,7 +41,6 @@ class PeerTableModel : public QAbstractTableModel
|
||||
public:
|
||||
explicit PeerTableModel(interfaces::Node& node, QObject* parent);
|
||||
~PeerTableModel();
|
||||
int getRowByNodeId(NodeId nodeid);
|
||||
void startAutoRefresh();
|
||||
void stopAutoRefresh();
|
||||
|
||||
@ -80,7 +67,6 @@ public:
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
void sort(int column, Qt::SortOrder order) override;
|
||||
/*@}*/
|
||||
|
||||
public Q_SLOTS:
|
||||
|
43
src/qt/peertablesortproxy.cpp
Normal file
43
src/qt/peertablesortproxy.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2020 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <qt/peertablesortproxy.h>
|
||||
|
||||
#include <qt/peertablemodel.h>
|
||||
#include <util/check.h>
|
||||
|
||||
#include <QModelIndex>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
PeerTableSortProxy::PeerTableSortProxy(QObject* parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
bool PeerTableSortProxy::lessThan(const QModelIndex& left_index, const QModelIndex& right_index) const
|
||||
{
|
||||
const CNodeStats left_stats = Assert(sourceModel()->data(left_index, PeerTableModel::StatsRole).value<CNodeCombinedStats*>())->nodeStats;
|
||||
const CNodeStats right_stats = Assert(sourceModel()->data(right_index, PeerTableModel::StatsRole).value<CNodeCombinedStats*>())->nodeStats;
|
||||
|
||||
switch (static_cast<PeerTableModel::ColumnIndex>(left_index.column())) {
|
||||
case PeerTableModel::NetNodeId:
|
||||
return left_stats.nodeid < right_stats.nodeid;
|
||||
case PeerTableModel::Address:
|
||||
return left_stats.m_addr_name.compare(right_stats.m_addr_name) < 0;
|
||||
case PeerTableModel::ConnectionType:
|
||||
return left_stats.m_conn_type < right_stats.m_conn_type;
|
||||
case PeerTableModel::Network:
|
||||
return left_stats.m_network < right_stats.m_network;
|
||||
case PeerTableModel::Ping:
|
||||
return left_stats.m_min_ping_time < right_stats.m_min_ping_time;
|
||||
case PeerTableModel::Sent:
|
||||
return left_stats.nSendBytes < right_stats.nSendBytes;
|
||||
case PeerTableModel::Received:
|
||||
return left_stats.nRecvBytes < right_stats.nRecvBytes;
|
||||
case PeerTableModel::Subversion:
|
||||
return left_stats.cleanSubVer.compare(right_stats.cleanSubVer) < 0;
|
||||
} // no default case, so the compiler can warn about missing cases
|
||||
assert(false);
|
||||
}
|
25
src/qt/peertablesortproxy.h
Normal file
25
src/qt/peertablesortproxy.h
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2020 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_QT_PEERTABLESORTPROXY_H
|
||||
#define BITCOIN_QT_PEERTABLESORTPROXY_H
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QModelIndex;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class PeerTableSortProxy : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PeerTableSortProxy(QObject* parent = nullptr);
|
||||
|
||||
protected:
|
||||
bool lessThan(const QModelIndex& left_index, const QModelIndex& right_index) const override;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_QT_PEERTABLESORTPROXY_H
|
@ -27,12 +27,8 @@ QRImageWidget::QRImageWidget(QWidget *parent):
|
||||
QLabel(parent), contextMenu(nullptr)
|
||||
{
|
||||
contextMenu = new QMenu(this);
|
||||
QAction *saveImageAction = new QAction(tr("&Save Image…"), this);
|
||||
connect(saveImageAction, &QAction::triggered, this, &QRImageWidget::saveImage);
|
||||
contextMenu->addAction(saveImageAction);
|
||||
QAction *copyImageAction = new QAction(tr("&Copy Image"), this);
|
||||
connect(copyImageAction, &QAction::triggered, this, &QRImageWidget::copyImage);
|
||||
contextMenu->addAction(copyImageAction);
|
||||
contextMenu->addAction(tr("&Save Image…"), this, &QRImageWidget::saveImage);
|
||||
contextMenu->addAction(tr("&Copy Image"), this, &QRImageWidget::copyImage);
|
||||
}
|
||||
|
||||
bool QRImageWidget::setQR(const QString& data, const QString& text)
|
||||
|
@ -7,7 +7,7 @@
|
||||
QValueComboBox::QValueComboBox(QWidget *parent) :
|
||||
QComboBox(parent), role(Qt::UserRole)
|
||||
{
|
||||
connect(this, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &QValueComboBox::handleSelectionChanged);
|
||||
connect(this, qOverload<int>(&QComboBox::currentIndexChanged), this, &QValueComboBox::handleSelectionChanged);
|
||||
}
|
||||
|
||||
QVariant QValueComboBox::value() const
|
||||
|
@ -31,28 +31,14 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(QWidget* parent) :
|
||||
ui->label_3}, GUIUtil::FontWeight::Normal, 15);
|
||||
GUIUtil::updateFonts();
|
||||
|
||||
// context menu actions
|
||||
QAction *copyURIAction = new QAction(tr("Copy URI"), this);
|
||||
QAction* copyAddressAction = new QAction(tr("Copy address"), this);
|
||||
copyLabelAction = new QAction(tr("Copy label"), this);
|
||||
copyMessageAction = new QAction(tr("Copy message"), this);
|
||||
copyAmountAction = new QAction(tr("Copy amount"), this);
|
||||
|
||||
// context menu
|
||||
contextMenu = new QMenu(this);
|
||||
contextMenu->addAction(copyURIAction);
|
||||
contextMenu->addAction(copyAddressAction);
|
||||
contextMenu->addAction(copyLabelAction);
|
||||
contextMenu->addAction(copyMessageAction);
|
||||
contextMenu->addAction(copyAmountAction);
|
||||
|
||||
// context menu signals
|
||||
contextMenu->addAction(tr("Copy &URI"), this, &ReceiveCoinsDialog::copyURI);
|
||||
contextMenu->addAction(tr("&Copy address"), this, &ReceiveCoinsDialog::copyAddress);
|
||||
copyLabelAction = contextMenu->addAction(tr("Copy &label"), this, &ReceiveCoinsDialog::copyLabel);
|
||||
copyMessageAction = contextMenu->addAction(tr("Copy &message"), this, &ReceiveCoinsDialog::copyMessage);
|
||||
copyAmountAction = contextMenu->addAction(tr("Copy &amount"), this, &ReceiveCoinsDialog::copyAmount);
|
||||
connect(ui->recentRequestsView, &QWidget::customContextMenuRequested, this, &ReceiveCoinsDialog::showMenu);
|
||||
connect(copyURIAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyURI);
|
||||
connect(copyAddressAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyAddress);
|
||||
connect(copyLabelAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyLabel);
|
||||
connect(copyMessageAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyMessage);
|
||||
connect(copyAmountAction, &QAction::triggered, this, &ReceiveCoinsDialog::copyAmount);
|
||||
|
||||
connect(ui->clearButton, &QPushButton::clicked, this, &ReceiveCoinsDialog::clear);
|
||||
}
|
||||
|
@ -12,12 +12,13 @@
|
||||
|
||||
#include <evo/deterministicmns.h>
|
||||
|
||||
#include <qt/bantablemodel.h>
|
||||
#include <qt/clientmodel.h>
|
||||
#include <qt/walletmodel.h>
|
||||
#include <chainparams.h>
|
||||
#include <interfaces/node.h>
|
||||
#include <netbase.h>
|
||||
#include <qt/bantablemodel.h>
|
||||
#include <qt/clientmodel.h>
|
||||
#include <qt/peertablesortproxy.h>
|
||||
#include <qt/walletmodel.h>
|
||||
#include <rpc/client.h>
|
||||
#include <rpc/server.h>
|
||||
#include <util/strencodings.h>
|
||||
@ -694,7 +695,7 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_
|
||||
|
||||
|
||||
// set up peer table
|
||||
ui->peerWidget->setModel(model->getPeerTableModel());
|
||||
ui->peerWidget->setModel(model->peerTableSortProxy());
|
||||
ui->peerWidget->verticalHeader()->hide();
|
||||
ui->peerWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
ui->peerWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
@ -705,36 +706,18 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_
|
||||
ui->peerWidget->horizontalHeader()->setStretchLastSection(true);
|
||||
ui->peerWidget->setItemDelegateForColumn(PeerTableModel::NetNodeId, new PeerIdViewDelegate(this));
|
||||
|
||||
// create peer table context menu actions
|
||||
QAction* disconnectAction = new QAction(tr("&Disconnect"), this);
|
||||
QAction* banAction1h = new QAction(ts.ban_for + " " + tr("1 &hour"), this);
|
||||
QAction* banAction24h = new QAction(ts.ban_for + " " + tr("1 &day"), this);
|
||||
QAction* banAction7d = new QAction(ts.ban_for + " " + tr("1 &week"), this);
|
||||
QAction* banAction365d = new QAction(ts.ban_for + " " + tr("1 &year"), this);
|
||||
|
||||
// create peer table context menu
|
||||
peersTableContextMenu = new QMenu(this);
|
||||
peersTableContextMenu->addAction(disconnectAction);
|
||||
peersTableContextMenu->addAction(banAction1h);
|
||||
peersTableContextMenu->addAction(banAction24h);
|
||||
peersTableContextMenu->addAction(banAction7d);
|
||||
peersTableContextMenu->addAction(banAction365d);
|
||||
|
||||
connect(banAction1h, &QAction::triggered, [this] { banSelectedNode(60 * 60); });
|
||||
connect(banAction24h, &QAction::triggered, [this] { banSelectedNode(60 * 60 * 24); });
|
||||
connect(banAction7d, &QAction::triggered, [this] { banSelectedNode(60 * 60 * 24 * 7); });
|
||||
connect(banAction365d, &QAction::triggered, [this] { banSelectedNode(60 * 60 * 24 * 365); });
|
||||
|
||||
// peer table context menu signals
|
||||
peersTableContextMenu->addAction(tr("&Disconnect"), this, &RPCConsole::disconnectSelectedNode);
|
||||
peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 &hour"), [this] { banSelectedNode(60 * 60); });
|
||||
peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 d&ay"), [this] { banSelectedNode(60 * 60 * 24); });
|
||||
peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 &week"), [this] { banSelectedNode(60 * 60 * 24 * 7); });
|
||||
peersTableContextMenu->addAction(ts.ban_for + " " + tr("1 &year"), [this] { banSelectedNode(60 * 60 * 24 * 365); });
|
||||
connect(ui->peerWidget, &QTableView::customContextMenuRequested, this, &RPCConsole::showPeersTableContextMenu);
|
||||
connect(disconnectAction, &QAction::triggered, this, &RPCConsole::disconnectSelectedNode);
|
||||
|
||||
// peer table signal handling - update peer details when selecting new node
|
||||
connect(ui->peerWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this, &RPCConsole::updateDetailWidget);
|
||||
// peer table signal handling - update peer details when new nodes are added to the model
|
||||
connect(model->getPeerTableModel(), &PeerTableModel::layoutChanged, this, &RPCConsole::peerLayoutChanged);
|
||||
// peer table signal handling - cache selected node ids
|
||||
connect(model->getPeerTableModel(), &PeerTableModel::layoutAboutToBeChanged, this, &RPCConsole::peerLayoutAboutToChange);
|
||||
connect(model->getPeerTableModel(), &PeerTableModel::layoutChanged, this, &RPCConsole::updateDetailWidget);
|
||||
|
||||
// set up ban table
|
||||
ui->banlistWidget->setModel(model->getBanTableModel());
|
||||
@ -746,16 +729,10 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_
|
||||
ui->banlistWidget->setColumnWidth(BanTableModel::Bantime, BANTIME_COLUMN_WIDTH);
|
||||
ui->banlistWidget->horizontalHeader()->setStretchLastSection(true);
|
||||
|
||||
// create ban table context menu action
|
||||
QAction* unbanAction = new QAction(tr("&Unban"), this);
|
||||
|
||||
// create ban table context menu
|
||||
banTableContextMenu = new QMenu(this);
|
||||
banTableContextMenu->addAction(unbanAction);
|
||||
|
||||
// ban table context menu signals
|
||||
banTableContextMenu->addAction(tr("&Unban"), this, &RPCConsole::unbanSelectedNode);
|
||||
connect(ui->banlistWidget, &QTableView::customContextMenuRequested, this, &RPCConsole::showBanTableContextMenu);
|
||||
connect(unbanAction, &QAction::triggered, this, &RPCConsole::unbanSelectedNode);
|
||||
|
||||
// ban table signal handling - clear peer details when clicking a peer in the ban table
|
||||
connect(ui->banlistWidget, &QTableView::clicked, this, &RPCConsole::clearSelectedNode);
|
||||
@ -959,20 +936,23 @@ void RPCConsole::clear(bool keep_prompt)
|
||||
).arg(consoleFontSize)
|
||||
);
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QString clsKey = "(⌘)-L";
|
||||
#else
|
||||
QString clsKey = "Ctrl-L";
|
||||
#endif
|
||||
|
||||
message(CMD_REPLY, (tr("Welcome to the %1 RPC console.").arg(PACKAGE_NAME) + "<br>" +
|
||||
tr("Use up and down arrows to navigate history, and %1 to clear screen.").arg("<b>"+clsKey+"</b>") + "<br>" +
|
||||
tr("Type %1 for an overview of available commands.").arg("<b>help</b>") + "<br>" +
|
||||
tr("For more information on using this console type %1.").arg("<b>help-console</b>") +
|
||||
"<br><span class=\"secwarning\"><br>" +
|
||||
tr("WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.") +
|
||||
"</span>"),
|
||||
true);
|
||||
message(CMD_REPLY,
|
||||
tr("Welcome to the %1 RPC console.").arg(PACKAGE_NAME) +
|
||||
"<br>" +
|
||||
tr("Use up and down arrows to navigate history, and %1 to clear screen.")
|
||||
.arg("<b>" + ui->clearButton->shortcut().toString(QKeySequence::NativeText) + "</b>") +
|
||||
"<br>" +
|
||||
tr("Use %1 and %2 to increase or decrease the font size.")
|
||||
.arg("<b>" + ui->fontBiggerButton->shortcut().toString(QKeySequence::NativeText) + "</b>")
|
||||
.arg("<b>" + ui->fontSmallerButton->shortcut().toString(QKeySequence::NativeText) + "</b>") +
|
||||
"<br>" +
|
||||
tr("Type %1 for an overview of available commands.").arg("<b>help</b>") +
|
||||
"<br>" +
|
||||
tr("For more information on using this console type %1.").arg("<b>help-console</b>") +
|
||||
"<br><span class=\"secwarning\"><br>" +
|
||||
tr("WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.") +
|
||||
"</span>",
|
||||
true);
|
||||
}
|
||||
|
||||
void RPCConsole::keyPressEvent(QKeyEvent *event)
|
||||
@ -1174,7 +1154,7 @@ void RPCConsole::startExecutor()
|
||||
executor->moveToThread(&thread);
|
||||
|
||||
// Replies from executor object must go to this object
|
||||
connect(executor, &RPCExecutor::reply, this, static_cast<void (RPCConsole::*)(int, const QString&)>(&RPCConsole::message));
|
||||
connect(executor, &RPCExecutor::reply, this, qOverload<int, const QString&>(&RPCConsole::message));
|
||||
|
||||
// Requests from this object must go to executor
|
||||
connect(this, &RPCConsole::cmdRequest, executor, &RPCExecutor::request);
|
||||
@ -1219,67 +1199,6 @@ void RPCConsole::setTrafficGraphRange(TrafficGraphData::GraphRange range)
|
||||
ui->lblGraphRange->setText(GUIUtil::formatDurationStr(std::chrono::minutes{TrafficGraphData::RangeMinutes[range]}));
|
||||
}
|
||||
|
||||
void RPCConsole::peerLayoutAboutToChange()
|
||||
{
|
||||
cachedNodeids.clear();
|
||||
for (const QModelIndex& peer : GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId)) {
|
||||
const auto stats = peer.data(PeerTableModel::StatsRole).value<CNodeCombinedStats*>();
|
||||
cachedNodeids.append(stats->nodeStats.nodeid);
|
||||
}
|
||||
}
|
||||
|
||||
void RPCConsole::peerLayoutChanged()
|
||||
{
|
||||
if (!clientModel || !clientModel->getPeerTableModel())
|
||||
return;
|
||||
|
||||
bool fUnselect = false;
|
||||
bool fReselect = false;
|
||||
|
||||
if (cachedNodeids.empty()) // no node selected yet
|
||||
return;
|
||||
|
||||
// find the currently selected row
|
||||
int selectedRow = -1;
|
||||
QModelIndexList selectedModelIndex = ui->peerWidget->selectionModel()->selectedIndexes();
|
||||
if (!selectedModelIndex.isEmpty()) {
|
||||
selectedRow = selectedModelIndex.first().row();
|
||||
}
|
||||
|
||||
// check if our detail node has a row in the table (it may not necessarily
|
||||
// be at selectedRow since its position can change after a layout change)
|
||||
int detailNodeRow = clientModel->getPeerTableModel()->getRowByNodeId(cachedNodeids.first());
|
||||
|
||||
if (detailNodeRow < 0)
|
||||
{
|
||||
// detail node disappeared from table (node disconnected)
|
||||
fUnselect = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (detailNodeRow != selectedRow)
|
||||
{
|
||||
// detail node moved position
|
||||
fUnselect = true;
|
||||
fReselect = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (fUnselect && selectedRow >= 0) {
|
||||
clearSelectedNode();
|
||||
}
|
||||
|
||||
if (fReselect)
|
||||
{
|
||||
for(int i = 0; i < cachedNodeids.size(); i++)
|
||||
{
|
||||
ui->peerWidget->selectRow(clientModel->getPeerTableModel()->getRowByNodeId(cachedNodeids.at(i)));
|
||||
}
|
||||
}
|
||||
|
||||
updateDetailWidget();
|
||||
}
|
||||
|
||||
void RPCConsole::updateDetailWidget()
|
||||
{
|
||||
const QList<QModelIndex> selected_peers = GUIUtil::getEntryData(ui->peerWidget, PeerTableModel::NetNodeId);
|
||||
@ -1369,8 +1288,18 @@ void RPCConsole::setButtonIcons()
|
||||
{
|
||||
const QSize consoleButtonsSize(BUTTON_ICONSIZE * 0.8, BUTTON_ICONSIZE * 0.8);
|
||||
GUIUtil::setIcon(ui->clearButton, "remove", GUIUtil::ThemedColor::RED, consoleButtonsSize);
|
||||
|
||||
GUIUtil::setIcon(ui->fontBiggerButton, "fontbigger", GUIUtil::ThemedColor::BLUE, consoleButtonsSize);
|
||||
//: Main shortcut to increase the RPC console font size.
|
||||
ui->fontBiggerButton->setShortcut(tr("Ctrl++"));
|
||||
//: Secondary shortcut to increase the RPC console font size.
|
||||
GUIUtil::AddButtonShortcut(ui->fontBiggerButton, tr("Ctrl+="));
|
||||
|
||||
GUIUtil::setIcon(ui->fontSmallerButton, "fontsmaller", GUIUtil::ThemedColor::BLUE, consoleButtonsSize);
|
||||
//: Main shortcut to decrease the RPC console font size.
|
||||
ui->fontSmallerButton->setShortcut(tr("Ctrl+-"));
|
||||
//: Secondary shortcut to decrease the RPC console font size.
|
||||
GUIUtil::AddButtonShortcut(ui->fontSmallerButton, tr("Ctrl+_"));
|
||||
}
|
||||
|
||||
void RPCConsole::reloadThemedWidgets()
|
||||
|
@ -134,10 +134,6 @@ public Q_SLOTS:
|
||||
void browseHistory(int offset);
|
||||
/** Scroll console view to end */
|
||||
void scrollToEnd();
|
||||
/** Handle selection caching before update */
|
||||
void peerLayoutAboutToChange();
|
||||
/** Handle updated peer information */
|
||||
void peerLayoutChanged();
|
||||
/** Disconnect a selected node on the Peers tab */
|
||||
void disconnectSelectedNode();
|
||||
/** Ban a selected node on the Peers tab */
|
||||
|
@ -210,15 +210,15 @@ void SendCoinsDialog::setModel(WalletModel *_model)
|
||||
for (const int n : confTargets) {
|
||||
ui->confTargetSelector->addItem(tr("%1 (%2 blocks)").arg(GUIUtil::formatNiceTimeOffset(n*Params().GetConsensus().nPowTargetSpacing)).arg(n));
|
||||
}
|
||||
connect(ui->confTargetSelector, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &SendCoinsDialog::updateSmartFeeLabel);
|
||||
connect(ui->confTargetSelector, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &SendCoinsDialog::coinControlUpdateLabels);
|
||||
connect(ui->confTargetSelector, qOverload<int>(&QComboBox::currentIndexChanged), this, &SendCoinsDialog::updateSmartFeeLabel);
|
||||
connect(ui->confTargetSelector, qOverload<int>(&QComboBox::currentIndexChanged), this, &SendCoinsDialog::coinControlUpdateLabels);
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
||||
connect(ui->groupFee, &QButtonGroup::idClicked, this, &SendCoinsDialog::updateFeeSectionControls);
|
||||
connect(ui->groupFee, &QButtonGroup::idClicked, this, &SendCoinsDialog::coinControlUpdateLabels);
|
||||
#else
|
||||
connect(ui->groupFee, static_cast<void (QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::updateFeeSectionControls);
|
||||
connect(ui->groupFee, static_cast<void (QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::coinControlUpdateLabels);
|
||||
connect(ui->groupFee, qOverload<int>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::updateFeeSectionControls);
|
||||
connect(ui->groupFee, qOverload<int>(&QButtonGroup::buttonClicked), this, &SendCoinsDialog::coinControlUpdateLabels);
|
||||
#endif
|
||||
|
||||
connect(ui->customFee, &BitcoinAmountField::valueChanged, this, &SendCoinsDialog::coinControlUpdateLabels);
|
||||
|
@ -20,10 +20,10 @@
|
||||
#endif
|
||||
|
||||
#include <QAction>
|
||||
#include <QEventLoop>
|
||||
#include <QLineEdit>
|
||||
#include <QScopedPointer>
|
||||
#include <QSettings>
|
||||
#include <QSignalSpy>
|
||||
#include <QTest>
|
||||
#include <QTextEdit>
|
||||
#include <QtGlobal>
|
||||
@ -34,13 +34,14 @@ namespace {
|
||||
//! Call getblockchaininfo RPC and check first field of JSON output.
|
||||
void TestRpcCommand(RPCConsole* console)
|
||||
{
|
||||
QEventLoop loop;
|
||||
QTextEdit* messagesWidget = console->findChild<QTextEdit*>("messagesWidget");
|
||||
QObject::connect(messagesWidget, &QTextEdit::textChanged, &loop, &QEventLoop::quit);
|
||||
QLineEdit* lineEdit = console->findChild<QLineEdit*>("lineEdit");
|
||||
QSignalSpy mw_spy(messagesWidget, &QTextEdit::textChanged);
|
||||
QVERIFY(mw_spy.isValid());
|
||||
QTest::keyClicks(lineEdit, "getblockchaininfo");
|
||||
QTest::keyClick(lineEdit, Qt::Key_Return);
|
||||
loop.exec();
|
||||
QVERIFY(mw_spy.wait(1000));
|
||||
QCOMPARE(mw_spy.count(), 2);
|
||||
QString output = messagesWidget->toPlainText();
|
||||
UniValue value;
|
||||
value.read(output.right(output.size() - output.indexOf("{")).toStdString());
|
||||
|
@ -95,21 +95,23 @@ public:
|
||||
*/
|
||||
QList<TransactionRecord> cachedWallet;
|
||||
|
||||
bool fQueueNotifications = false;
|
||||
/** True when model finishes loading all wallet transactions on start */
|
||||
bool m_loaded = false;
|
||||
/** True when transactions are being notified, for instance when scanning */
|
||||
bool m_loading = false;
|
||||
std::vector< TransactionNotification > vQueueNotifications;
|
||||
|
||||
void NotifyTransactionChanged(const uint256 &hash, ChangeType status);
|
||||
void NotifyAddressBookChanged(const CTxDestination &address, const std::string &label, bool isMine, const std::string &purpose, ChangeType status);
|
||||
void ShowProgress(const std::string &title, int nProgress);
|
||||
void DispatchNotifications();
|
||||
|
||||
/* Query entire wallet anew from core.
|
||||
*/
|
||||
void refreshWallet(interfaces::Wallet& wallet)
|
||||
{
|
||||
qDebug() << "TransactionTablePriv::refreshWallet";
|
||||
parent->beginResetModel();
|
||||
assert(!m_loaded);
|
||||
try {
|
||||
cachedWallet.clear();
|
||||
for (const auto& wtx : wallet.getWalletTxs()) {
|
||||
if (TransactionRecord::showTransaction()) {
|
||||
cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, wtx));
|
||||
@ -119,6 +121,8 @@ public:
|
||||
QMessageBox::critical(nullptr, PACKAGE_NAME, QString("Failed to refresh wallet table: ") + QString::fromStdString(e.what()));
|
||||
}
|
||||
parent->endResetModel();
|
||||
m_loaded = true;
|
||||
DispatchNotifications();
|
||||
}
|
||||
|
||||
/* Update our model of the wallet incrementally, to synchronize our model of the wallet
|
||||
@ -267,12 +271,12 @@ TransactionTableModel::TransactionTableModel(WalletModel *parent):
|
||||
fProcessingQueuedTransactions(false),
|
||||
cachedChainLockHeight(-1)
|
||||
{
|
||||
subscribeToCoreSignals();
|
||||
|
||||
columns << QString() << QString() << tr("Date") << tr("Type") << tr("Address / Label") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
|
||||
priv->refreshWallet(walletModel->wallet());
|
||||
|
||||
connect(walletModel->getOptionsModel(), &OptionsModel::displayUnitChanged, this, &TransactionTableModel::updateDisplayUnit);
|
||||
|
||||
subscribeToCoreSignals();
|
||||
}
|
||||
|
||||
TransactionTableModel::~TransactionTableModel()
|
||||
@ -806,7 +810,7 @@ void TransactionTablePriv::NotifyTransactionChanged(const uint256 &hash, ChangeT
|
||||
|
||||
TransactionNotification notification(hash, status, showTransaction);
|
||||
|
||||
if (fQueueNotifications)
|
||||
if (!m_loaded || m_loading)
|
||||
{
|
||||
vQueueNotifications.push_back(notification);
|
||||
return;
|
||||
@ -825,35 +829,30 @@ void TransactionTablePriv::NotifyAddressBookChanged(const CTxDestination &addres
|
||||
assert(invoked);
|
||||
}
|
||||
|
||||
void TransactionTablePriv::ShowProgress(const std::string &title, int nProgress)
|
||||
void TransactionTablePriv::DispatchNotifications()
|
||||
{
|
||||
if (nProgress == 0)
|
||||
fQueueNotifications = true;
|
||||
if (!m_loaded || m_loading) return;
|
||||
|
||||
if (nProgress == 100)
|
||||
{
|
||||
fQueueNotifications = false;
|
||||
if (vQueueNotifications.size() < 10000) {
|
||||
if (vQueueNotifications.size() > 10) { // prevent balloon spam, show maximum 10 balloons
|
||||
bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true));
|
||||
assert(invoked);
|
||||
}
|
||||
for (unsigned int i = 0; i < vQueueNotifications.size(); ++i)
|
||||
{
|
||||
if (vQueueNotifications.size() - i <= 10) {
|
||||
bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, false));
|
||||
assert(invoked);
|
||||
}
|
||||
|
||||
vQueueNotifications[i].invoke(parent);
|
||||
}
|
||||
} else {
|
||||
// it's much faster to just refresh the whole thing instead
|
||||
bool invoked = QMetaObject::invokeMethod(parent, "refreshWallet", Qt::QueuedConnection);
|
||||
if (vQueueNotifications.size() < 10000) {
|
||||
if (vQueueNotifications.size() > 10) { // prevent balloon spam, show maximum 10 balloons
|
||||
bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true));
|
||||
assert(invoked);
|
||||
}
|
||||
vQueueNotifications.clear();
|
||||
for (unsigned int i = 0; i < vQueueNotifications.size(); ++i)
|
||||
{
|
||||
if (vQueueNotifications.size() - i <= 10) {
|
||||
bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, false));
|
||||
assert(invoked);
|
||||
}
|
||||
|
||||
vQueueNotifications[i].invoke(parent);
|
||||
}
|
||||
} else {
|
||||
// it's much faster to just refresh the whole thing instead
|
||||
bool invoked = QMetaObject::invokeMethod(parent, "refreshWallet", Qt::QueuedConnection);
|
||||
assert(invoked);
|
||||
}
|
||||
vQueueNotifications.clear();
|
||||
}
|
||||
|
||||
void TransactionTableModel::subscribeToCoreSignals()
|
||||
@ -861,7 +860,10 @@ void TransactionTableModel::subscribeToCoreSignals()
|
||||
// Connect signals to wallet
|
||||
m_handler_transaction_changed = walletModel->wallet().handleTransactionChanged(std::bind(&TransactionTablePriv::NotifyTransactionChanged, priv, std::placeholders::_1, std::placeholders::_2));
|
||||
m_handler_address_book_changed = walletModel->wallet().handleAddressBookChanged(std::bind(&TransactionTablePriv::NotifyAddressBookChanged, priv, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
|
||||
m_handler_show_progress = walletModel->wallet().handleShowProgress(std::bind(&TransactionTablePriv::ShowProgress, priv, std::placeholders::_1, std::placeholders::_2));
|
||||
m_handler_show_progress = walletModel->wallet().handleShowProgress([this](const std::string&, int progress) {
|
||||
priv->m_loading = progress < 100;
|
||||
priv->DispatchNotifications();
|
||||
});
|
||||
}
|
||||
|
||||
void TransactionTableModel::unsubscribeFromCoreSignals()
|
||||
|
@ -146,60 +146,36 @@ TransactionView::TransactionView(QWidget* parent) :
|
||||
|
||||
transactionView->setObjectName("transactionView");
|
||||
|
||||
// Actions
|
||||
abandonAction = new QAction(tr("Abandon transaction"), this);
|
||||
resendAction = new QAction(tr("Resend transaction"), this);
|
||||
copyAddressAction = new QAction(tr("Copy address"), this);
|
||||
copyLabelAction = new QAction(tr("Copy label"), this);
|
||||
QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
|
||||
QAction *copyTxIDAction = new QAction(tr("Copy transaction ID"), this);
|
||||
QAction *copyTxHexAction = new QAction(tr("Copy raw transaction"), this);
|
||||
QAction *copyTxPlainText = new QAction(tr("Copy full transaction details"), this);
|
||||
QAction *editLabelAction = new QAction(tr("Edit address label"), this);
|
||||
QAction *showDetailsAction = new QAction(tr("Show transaction details"), this);
|
||||
QAction *showAddressQRCodeAction = new QAction(tr("Show address QR code"), this);
|
||||
contextMenu = new QMenu(this);
|
||||
contextMenu->setObjectName("contextMenu");
|
||||
copyAddressAction = contextMenu->addAction(tr("&Copy address"), this, &TransactionView::copyAddress);
|
||||
copyLabelAction = contextMenu->addAction(tr("Copy &label"), this, &TransactionView::copyLabel);
|
||||
contextMenu->addAction(tr("Copy &amount"), this, &TransactionView::copyAmount);
|
||||
contextMenu->addAction(tr("Copy transaction &ID"), this, &TransactionView::copyTxID);
|
||||
contextMenu->addAction(tr("Copy &raw transaction"), this, &TransactionView::copyTxHex);
|
||||
contextMenu->addAction(tr("Copy full transaction &details"), this, &TransactionView::copyTxPlainText);
|
||||
contextMenu->addAction(tr("&Show transaction details"), this, &TransactionView::showDetails);
|
||||
contextMenu->addSeparator();
|
||||
abandonAction = contextMenu->addAction(tr("A&bandon transaction"), this, &TransactionView::abandonTx);
|
||||
resendAction = contextMenu->addAction(tr("Rese&nd transaction"), this, &TransactionView::resendTx);
|
||||
contextMenu->addAction(tr("&Edit address label"), this, &TransactionView::editLabel);
|
||||
[[maybe_unused]] QAction* showAddressQRCodeAction = contextMenu->addAction(tr("Show address &QR code"), this, &TransactionView::showAddressQRCode);
|
||||
#ifndef USE_QRCODE
|
||||
showAddressQRCodeAction->setEnabled(false);
|
||||
#endif
|
||||
|
||||
contextMenu = new QMenu(this);
|
||||
contextMenu->setObjectName("contextMenu");
|
||||
contextMenu->addAction(copyAddressAction);
|
||||
contextMenu->addAction(copyLabelAction);
|
||||
contextMenu->addAction(copyAmountAction);
|
||||
contextMenu->addAction(copyTxIDAction);
|
||||
contextMenu->addAction(copyTxHexAction);
|
||||
contextMenu->addAction(copyTxPlainText);
|
||||
contextMenu->addAction(showDetailsAction);
|
||||
contextMenu->addAction(showAddressQRCodeAction);
|
||||
contextMenu->addSeparator();
|
||||
contextMenu->addAction(abandonAction);
|
||||
contextMenu->addAction(resendAction);
|
||||
contextMenu->addAction(editLabelAction);
|
||||
|
||||
connect(dateWidget, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TransactionView::chooseDate);
|
||||
connect(typeWidget, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TransactionView::chooseType);
|
||||
connect(watchOnlyWidget, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &TransactionView::chooseWatchonly);
|
||||
connect(amountWidget, &QLineEdit::textChanged, amount_typing_delay, static_cast<void (QTimer::*)()>(&QTimer::start));
|
||||
connect(dateWidget, qOverload<int>(&QComboBox::activated), this, &TransactionView::chooseDate);
|
||||
connect(typeWidget, qOverload<int>(&QComboBox::activated), this, &TransactionView::chooseType);
|
||||
connect(watchOnlyWidget, qOverload<int>(&QComboBox::activated), this, &TransactionView::chooseWatchonly);
|
||||
connect(amountWidget, &QLineEdit::textChanged, amount_typing_delay, qOverload<>(&QTimer::start));
|
||||
connect(amount_typing_delay, &QTimer::timeout, this, &TransactionView::changedAmount);
|
||||
connect(search_widget, &QLineEdit::textChanged, prefix_typing_delay, static_cast<void (QTimer::*)()>(&QTimer::start));
|
||||
connect(search_widget, &QLineEdit::textChanged, prefix_typing_delay, qOverload<>(&QTimer::start));
|
||||
connect(prefix_typing_delay, &QTimer::timeout, this, &TransactionView::changedSearch);
|
||||
|
||||
connect(transactionView, &QTableView::doubleClicked, this, &TransactionView::doubleClicked);
|
||||
connect(transactionView, &QTableView::clicked, this, &TransactionView::computeSum);
|
||||
connect(transactionView, &QTableView::customContextMenuRequested, this, &TransactionView::contextualMenu);
|
||||
|
||||
connect(abandonAction, &QAction::triggered, this, &TransactionView::abandonTx);
|
||||
connect(resendAction, &QAction::triggered, this, &TransactionView::resendTx);
|
||||
connect(copyAddressAction, &QAction::triggered, this, &TransactionView::copyAddress);
|
||||
connect(copyLabelAction, &QAction::triggered, this, &TransactionView::copyLabel);
|
||||
connect(copyAmountAction, &QAction::triggered, this, &TransactionView::copyAmount);
|
||||
connect(copyTxIDAction, &QAction::triggered, this, &TransactionView::copyTxID);
|
||||
connect(copyTxHexAction, &QAction::triggered, this, &TransactionView::copyTxHex);
|
||||
connect(copyTxPlainText, &QAction::triggered, this, &TransactionView::copyTxPlainText);
|
||||
connect(editLabelAction, &QAction::triggered, this, &TransactionView::editLabel);
|
||||
connect(showDetailsAction, &QAction::triggered, this, &TransactionView::showDetails);
|
||||
connect(showAddressQRCodeAction, &QAction::triggered, this, &TransactionView::showAddressQRCode);
|
||||
// Double-clicking on a transaction on the transaction history page shows details
|
||||
connect(this, &TransactionView::doubleClicked, this, &TransactionView::showDetails);
|
||||
}
|
||||
|
@ -99,14 +99,14 @@ WalletView::WalletView(QWidget* parent) :
|
||||
|
||||
connect(overviewPage, &OverviewPage::transactionClicked, this, &WalletView::transactionClicked);
|
||||
// Clicking on a transaction on the overview pre-selects the transaction on the transaction history page
|
||||
connect(overviewPage, &OverviewPage::transactionClicked, transactionView, static_cast<void (TransactionView::*)(const QModelIndex&)>(&TransactionView::focusTransaction));
|
||||
connect(overviewPage, &OverviewPage::transactionClicked, transactionView, qOverload<const QModelIndex&>(&TransactionView::focusTransaction));
|
||||
connect(overviewPage, &OverviewPage::outOfSyncWarningClicked, this, &WalletView::requestedSyncWarningInfo);
|
||||
|
||||
connect(sendCoinsPage, &SendCoinsDialog::coinsSent, this, &WalletView::coinsSent);
|
||||
connect(coinJoinCoinsPage, &SendCoinsDialog::coinsSent, this, &WalletView::coinsSent);
|
||||
// Highlight transaction after send
|
||||
connect(sendCoinsPage, &SendCoinsDialog::coinsSent, transactionView, static_cast<void (TransactionView::*)(const uint256&)>(&TransactionView::focusTransaction));
|
||||
connect(coinJoinCoinsPage, &SendCoinsDialog::coinsSent, transactionView, static_cast<void (TransactionView::*)(const uint256&)>(&TransactionView::focusTransaction));
|
||||
connect(sendCoinsPage, &SendCoinsDialog::coinsSent, transactionView, qOverload<const uint256&>(&TransactionView::focusTransaction));
|
||||
connect(coinJoinCoinsPage, &SendCoinsDialog::coinsSent, transactionView, qOverload<const uint256&>(&TransactionView::focusTransaction));
|
||||
|
||||
// Update wallet with sum of selected transactions
|
||||
connect(transactionView, &TransactionView::trxAmount, this, &WalletView::trxAmount);
|
||||
|
Loading…
Reference in New Issue
Block a user