Merge #6285: backport: bitcoin-core/gui#29, gui#123, #164, gui#256, gui#309, gui#313, gui#329, gui#331, gui#333, gui#346, gui#393

6431f71b3a Merge bitcoin-core/gui#393: Fix regression in "Encrypt Wallet" menu item (Hennadii Stepanov)
fc900a8aea Merge bitcoin-core/gui#333: refactor: Signal-slot connections cleanup (Hennadii Stepanov)
9ca2aad0b3 Merge bitcoin-core/gui#164: Handle peer addition/removal in a right way (Hennadii Stepanov)
7d9ce32562 Merge bitcoin-core/gui#29: refactor: Optimize signal-slot connections logic (Hennadii Stepanov)
3be79a9ed9 Merge bitcoin-core/gui#256: Save/restore column sizes of the tables in the Peers tab (Hennadii Stepanov)
f4fccd31cb Merge bitcoin-core/gui#329: Make console buttons look clickable (Hennadii Stepanov)
5a0d524506 Merge bitcoin-core/gui#123: rpc: Do not accept command while executing another one (Hennadii Stepanov)
19310646e0 Merge bitcoin-core/gui#331: Make RPC console welcome message translation-friendly (Hennadii Stepanov)
69a1305978 Merge bitcoin-core/gui#309: Add access to the Peers tab from the network icon (Hennadii Stepanov)
c858325d40 Merge bitcoin-core/gui#346: English translations update (Hennadii Stepanov)
412445afb5 Merge bitcoin-core/gui#313: qt: Optimize string concatenation by default (W. J. van der Laan)

Pull request description:

  ## Issue being fixed or feature implemented
  Gui related backports from bitcoin v22

  ## What was done?
  See commits

  ## How Has This Been Tested?
  Run unit/functional tests

  See also:

  <img alt="right menu" src="https://user-images.githubusercontent.com/32963518/116794314-d64b9b80-aad4-11eb-89ca-7f75c7442ba8.gif"/>

  ## 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:
  UdjinM6:
    light ACK 6431f71b3a
  PastaPastaPasta:
    utACK 6431f71b3a

Tree-SHA512: bb14de71c9375b10da695db6c521c26686815b8b5ca2748bfe3bd2eafa9d332acd60acd85a1f2eed3aa831d16e5741ecc7570130ce9cf5bff011c065b55d62b2
This commit is contained in:
pasta 2024-09-26 20:19:27 -05:00
commit 750475ffaa
No known key found for this signature in database
GPG Key ID: E2F3D7916E722D38
24 changed files with 274 additions and 223 deletions

View File

@ -364,7 +364,7 @@ RES_ANIMATION = $(wildcard $(srcdir)/qt/res/animation/spinner-*.png)
BITCOIN_RC = qt/res/dash-qt-res.rc BITCOIN_RC = qt/res/dash-qt-res.rc
BITCOIN_QT_INCLUDES = -DQT_NO_KEYWORDS BITCOIN_QT_INCLUDES = -DQT_NO_KEYWORDS -DQT_USE_QSTRINGBUILDER
qt_libbitcoinqt_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ qt_libbitcoinqt_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
$(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(QR_CFLAGS) $(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(QR_CFLAGS)

View File

@ -54,7 +54,6 @@
#include <QMessageBox> #include <QMessageBox>
#include <QProcess> #include <QProcess>
#include <QSettings> #include <QSettings>
#include <QStringBuilder>
#include <QThread> #include <QThread>
#include <QTimer> #include <QTimer>
#include <QTranslator> #include <QTranslator>
@ -492,8 +491,8 @@ void BitcoinApplication::handleRunawayException(const QString &message)
{ {
QMessageBox::critical( QMessageBox::critical(
nullptr, tr("Runaway exception"), nullptr, tr("Runaway exception"),
tr("A fatal error occurred. %1 can no longer continue safely and will quit.").arg(PACKAGE_NAME) % tr("A fatal error occurred. %1 can no longer continue safely and will quit.").arg(PACKAGE_NAME) +
QLatin1String("<br><br>") % GUIUtil::MakeHtmlLink(message, PACKAGE_BUGREPORT)); QLatin1String("<br><br>") + GUIUtil::MakeHtmlLink(message, PACKAGE_BUGREPORT));
::exit(EXIT_FAILURE); ::exit(EXIT_FAILURE);
} }
@ -503,8 +502,8 @@ void BitcoinApplication::handleNonFatalException(const QString& message)
QMessageBox::warning( QMessageBox::warning(
nullptr, tr("Internal error"), nullptr, tr("Internal error"),
tr("An internal error occurred. %1 will attempt to continue safely. This is " tr("An internal error occurred. %1 will attempt to continue safely. This is "
"an unexpected bug which can be reported as described below.").arg(PACKAGE_NAME) % "an unexpected bug which can be reported as described below.").arg(PACKAGE_NAME) +
QLatin1String("<br><br>") % GUIUtil::MakeHtmlLink(message, PACKAGE_BUGREPORT)); QLatin1String("<br><br>") + GUIUtil::MakeHtmlLink(message, PACKAGE_BUGREPORT));
} }
WId BitcoinApplication::getMainWinId() const WId BitcoinApplication::getMainWinId() const

View File

@ -47,6 +47,7 @@
#include <QApplication> #include <QApplication>
#include <QButtonGroup> #include <QButtonGroup>
#include <QComboBox> #include <QComboBox>
#include <QCursor>
#include <QDateTime> #include <QDateTime>
#include <QDragEnterEvent> #include <QDragEnterEvent>
#include <QKeySequence> #include <QKeySequence>
@ -114,6 +115,11 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const NetworkStyle* networkStyle,
connect(walletFrame, &WalletFrame::message, [this](const QString& title, const QString& message, unsigned int style) { connect(walletFrame, &WalletFrame::message, [this](const QString& title, const QString& message, unsigned int style) {
this->message(title, message, style); this->message(title, message, style);
}); });
connect(walletFrame, &WalletFrame::createWalletButtonClicked, [this] {
auto activity = new CreateWalletActivity(getWalletController(), this);
connect(activity, &CreateWalletActivity::finished, activity, &QObject::deleteLater);
activity->create();
});
} else } else
#endif // ENABLE_WALLET #endif // ENABLE_WALLET
{ {
@ -211,8 +217,6 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const NetworkStyle* networkStyle,
// Subscribe to notifications from core // Subscribe to notifications from core
subscribeToCoreSignals(); subscribeToCoreSignals();
// Jump to peers tab by clicking on connections icon
connect(labelConnectionsIcon, &GUIUtil::ClickableLabel::clicked, this, &BitcoinGUI::showPeers);
connect(labelProxyIcon, &GUIUtil::ClickableLabel::clicked, [this] { connect(labelProxyIcon, &GUIUtil::ClickableLabel::clicked, [this] {
openOptionsDialogWithTab(OptionsDialog::TAB_NETWORK); openOptionsDialogWithTab(OptionsDialog::TAB_NETWORK);
}); });
@ -220,11 +224,6 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const NetworkStyle* networkStyle,
modalOverlay = new ModalOverlay(enableWallet, this->centralWidget()); modalOverlay = new ModalOverlay(enableWallet, this->centralWidget());
connect(labelBlocksIcon, &GUIUtil::ClickableLabel::clicked, this, &BitcoinGUI::showModalOverlay); connect(labelBlocksIcon, &GUIUtil::ClickableLabel::clicked, this, &BitcoinGUI::showModalOverlay);
connect(progressBar, &GUIUtil::ClickableProgressBar::clicked, this, &BitcoinGUI::showModalOverlay); connect(progressBar, &GUIUtil::ClickableProgressBar::clicked, this, &BitcoinGUI::showModalOverlay);
#ifdef ENABLE_WALLET
if(enableWallet) {
connect(walletFrame, &WalletFrame::requestedSyncWarningInfo, this, &BitcoinGUI::showModalOverlay);
}
#endif
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
m_app_nap_inhibitor = new CAppNapInhibitor; m_app_nap_inhibitor = new CAppNapInhibitor;
@ -812,8 +811,11 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel, interfaces::BlockAndH
} }
// Keep up to date with client // Keep up to date with client
updateNetworkState(); setNetworkActive(m_node.getNetworkActive());
setNumConnections(_clientModel->getNumConnections()); setNumConnections(_clientModel->getNumConnections());
connect(labelConnectionsIcon, &GUIUtil::ClickableLabel::clicked, [this] {
GUIUtil::PopupMenu(m_network_context_menu, QCursor::pos());
});
connect(_clientModel, &ClientModel::numConnectionsChanged, this, &BitcoinGUI::setNumConnections); connect(_clientModel, &ClientModel::numConnectionsChanged, this, &BitcoinGUI::setNumConnections);
connect(_clientModel, &ClientModel::networkActiveChanged, this, &BitcoinGUI::setNetworkActive); connect(_clientModel, &ClientModel::networkActiveChanged, this, &BitcoinGUI::setNetworkActive);
@ -911,13 +913,28 @@ WalletController* BitcoinGUI::getWalletController()
void BitcoinGUI::addWallet(WalletModel* walletModel) void BitcoinGUI::addWallet(WalletModel* walletModel)
{ {
if (!walletFrame) return; if (!walletFrame) return;
if (!walletFrame->addWallet(walletModel)) return;
WalletView* wallet_view = new WalletView(walletFrame);
if (!walletFrame->addWallet(walletModel, wallet_view)) return;
rpcConsole->addWallet(walletModel); rpcConsole->addWallet(walletModel);
if (m_wallet_selector->count() == 0) { if (m_wallet_selector->count() == 0) {
setWalletActionsEnabled(true); setWalletActionsEnabled(true);
} else if (m_wallet_selector->count() == 1) { } else if (m_wallet_selector->count() == 1) {
m_wallet_selector_action->setVisible(true); m_wallet_selector_action->setVisible(true);
} }
connect(wallet_view, &WalletView::outOfSyncWarningClicked, this, &BitcoinGUI::showModalOverlay);
connect(wallet_view, &WalletView::transactionClicked, this, &BitcoinGUI::gotoHistoryPage);
connect(wallet_view, &WalletView::coinsSent, this, &BitcoinGUI::gotoHistoryPage);
connect(wallet_view, &WalletView::message, [this](const QString& title, const QString& message, unsigned int style) {
this->message(title, message, style);
});
connect(wallet_view, &WalletView::encryptionStatusChanged, this, &BitcoinGUI::updateWalletStatus);
connect(wallet_view, &WalletView::incomingTransaction, this, &BitcoinGUI::incomingTransaction);
connect(wallet_view, &WalletView::hdEnabledStatusChanged, this, &BitcoinGUI::updateWalletStatus);
connect(this, &BitcoinGUI::setPrivacy, wallet_view, &WalletView::setPrivacy);
wallet_view->setPrivacy(isPrivacyModeActivated());
const QString display_name = walletModel->getDisplayName(); const QString display_name = walletModel->getDisplayName();
m_wallet_selector->addItem(display_name, QVariant::fromValue(walletModel)); m_wallet_selector->addItem(display_name, QVariant::fromValue(walletModel));
} }
@ -1270,14 +1287,21 @@ void BitcoinGUI::updateNetworkState()
nCountPrev = count; nCountPrev = count;
fNetworkActivePrev = fNetworkActive; fNetworkActivePrev = fNetworkActive;
QString tooltip;
if (fNetworkActive) { if (fNetworkActive) {
labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Dash network", "", count)); //: A substring of the tooltip.
tooltip = tr("%n active connection(s) to Dash network", "", count);
} else { } else {
labelConnectionsIcon->setToolTip(tr("Network activity disabled")); tooltip = tr("Network activity disabled");
icon = "connect_4"; icon = "connect_4";
color = GUIUtil::ThemedColor::RED; color = GUIUtil::ThemedColor::RED;
} }
// Don't word-wrap this (fixed-width) tooltip
tooltip = QLatin1String("<nobr>") + tooltip + QLatin1String("<br>") +
//: A substring of the tooltip. "More actions" are available via the context menu.
tr("Click for more actions.") + QLatin1String("</nobr>");
if (fNetworkActive && count == 0) { if (fNetworkActive && count == 0) {
startConnectingAnimation(); startConnectingAnimation();
} }
@ -1285,6 +1309,7 @@ void BitcoinGUI::updateNetworkState()
stopConnectingAnimation(); stopConnectingAnimation();
labelConnectionsIcon->setPixmap(GUIUtil::getIcon(icon, color).pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE)); labelConnectionsIcon->setPixmap(GUIUtil::getIcon(icon, color).pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
} }
labelConnectionsIcon->setToolTip(tooltip);
} }
void BitcoinGUI::setNumConnections(int count) void BitcoinGUI::setNumConnections(int count)
@ -1292,9 +1317,24 @@ void BitcoinGUI::setNumConnections(int count)
updateNetworkState(); updateNetworkState();
} }
void BitcoinGUI::setNetworkActive(bool networkActive) void BitcoinGUI::setNetworkActive(bool network_active)
{ {
updateNetworkState(); updateNetworkState();
m_network_context_menu->clear();
m_network_context_menu->addAction(
//: A context menu item. The "Peers tab" is an element of the "Node window".
tr("Show Peers tab"),
[this] {
rpcConsole->setTabFocus(RPCConsole::TabTypes::PEERS);
showDebugWindow();
});
m_network_context_menu->addAction(
network_active ?
//: A context menu item.
tr("Disable network activity") :
//: A context menu item. The network activity was disabled previously.
tr("Enable network activity"),
[this, new_state = !network_active] { m_node.setNetworkActive(new_state); });
} }
void BitcoinGUI::updateHeadersSyncProgressLabel() void BitcoinGUI::updateHeadersSyncProgressLabel()

View File

@ -16,6 +16,7 @@
#include <QLabel> #include <QLabel>
#include <QMainWindow> #include <QMainWindow>
#include <QMap> #include <QMap>
#include <QMenu>
#include <QPoint> #include <QPoint>
#include <QPushButton> #include <QPushButton>
#include <QSystemTrayIcon> #include <QSystemTrayIcon>
@ -51,7 +52,6 @@ class QAction;
class QButtonGroup; class QButtonGroup;
class QComboBox; class QComboBox;
class QDateTime; class QDateTime;
class QMenu;
class QProgressBar; class QProgressBar;
class QProgressDialog; class QProgressDialog;
class QToolButton; class QToolButton;
@ -190,6 +190,8 @@ private:
ModalOverlay* modalOverlay = nullptr; ModalOverlay* modalOverlay = nullptr;
QButtonGroup* tabGroup = nullptr; QButtonGroup* tabGroup = nullptr;
QMenu* m_network_context_menu = new QMenu(this);
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
CAppNapInhibitor* m_app_nap_inhibitor = nullptr; CAppNapInhibitor* m_app_nap_inhibitor = nullptr;
#endif #endif
@ -264,7 +266,7 @@ public Q_SLOTS:
/** Set number of connections shown in the UI */ /** Set number of connections shown in the UI */
void setNumConnections(int count); void setNumConnections(int count);
/** Set network state shown in the UI */ /** Set network state shown in the UI */
void setNetworkActive(bool networkActive); void setNetworkActive(bool network_active);
/** Get restart command-line parameters and request restart */ /** Get restart command-line parameters and request restart */
void handleRestart(QStringList args); void handleRestart(QStringList args);
/** Set number of blocks and last block date shown in the UI */ /** Set number of blocks and last block date shown in the UI */

View File

@ -69,7 +69,6 @@
#include <QShortcut> #include <QShortcut>
#include <QSize> #include <QSize>
#include <QString> #include <QString>
#include <QStringBuilder>
#include <QTextDocument> // for Qt::mightBeRichText #include <QTextDocument> // for Qt::mightBeRichText
#include <QThread> #include <QThread>
#include <QTimer> #include <QTimer>
@ -1931,7 +1930,7 @@ QString MakeHtmlLink(const QString& source, const QString& link)
{ {
return QString(source).replace( return QString(source).replace(
link, link,
QLatin1String("<a href=\"") % link % QLatin1String("\">") % link % QLatin1String("</a>")); QLatin1String("<a href=\"") + link + QLatin1String("\">") + link + QLatin1String("</a>"));
} }
void PrintSlotException( void PrintSlotException(

View File

@ -26,6 +26,7 @@
#endif #endif
#include <QDebug> #include <QDebug>
#include <QLatin1Char>
#include <QSettings> #include <QSettings>
#include <QStringList> #include <QStringList>
@ -376,7 +377,7 @@ static ProxySetting GetProxySetting(QSettings &settings, const QString &name)
static void SetProxySetting(QSettings &settings, const QString &name, const ProxySetting &ip_port) static void SetProxySetting(QSettings &settings, const QString &name, const ProxySetting &ip_port)
{ {
settings.setValue(name, ip_port.ip + ":" + ip_port.port); settings.setValue(name, QString{ip_port.ip + QLatin1Char(':') + ip_port.port});
} }
static const QString GetDefaultProxyAddress() static const QString GetDefaultProxyAddress()

View File

@ -199,11 +199,6 @@ void OverviewPage::handleTransactionClicked(const QModelIndex &index)
Q_EMIT transactionClicked(filter->mapToSource(index)); Q_EMIT transactionClicked(filter->mapToSource(index));
} }
void OverviewPage::handleOutOfSyncWarningClicks()
{
Q_EMIT outOfSyncWarningClicked();
}
void OverviewPage::setPrivacy(bool privacy) void OverviewPage::setPrivacy(bool privacy)
{ {
m_privacy = privacy; m_privacy = privacy;
@ -469,7 +464,7 @@ void OverviewPage::updateCoinJoinProgress()
ui->coinJoinProgress->setValue(progress); ui->coinJoinProgress->setValue(progress);
QString strToolPip = ("<b>" + tr("Overall progress") + ": %1%</b><br/>" + QString strToolPip = QString("<b>" + tr("Overall progress") + ": %1%</b><br/>" +
tr("Denominated") + ": %2%<br/>" + tr("Denominated") + ": %2%<br/>" +
tr("Partially mixed") + ": %3%<br/>" + tr("Partially mixed") + ": %3%<br/>" +
tr("Mixed") + ": %4%<br/>" + tr("Mixed") + ": %4%<br/>" +

View File

@ -70,7 +70,6 @@ private Q_SLOTS:
void handleTransactionClicked(const QModelIndex &index); void handleTransactionClicked(const QModelIndex &index);
void updateAlerts(const QString &warnings); void updateAlerts(const QString &warnings);
void updateWatchOnlyLabels(bool showWatchOnly); void updateWatchOnlyLabels(bool showWatchOnly);
void handleOutOfSyncWarningClicks();
}; };
#endif // BITCOIN_QT_OVERVIEWPAGE_H #endif // BITCOIN_QT_OVERVIEWPAGE_H

View File

@ -14,53 +14,11 @@
#include <QList> #include <QList>
#include <QTimer> #include <QTimer>
// private implementation
class PeerTablePriv
{
public:
/** Local cache of peer information */
QList<CNodeCombinedStats> cachedNodeStats;
/** Pull a full list of peers from vNodes into our cache */
void refreshPeers(interfaces::Node& node)
{
cachedNodeStats.clear();
interfaces::Node::NodesStats nodes_stats;
node.getNodesStats(nodes_stats);
cachedNodeStats.reserve(nodes_stats.size());
for (const auto& node_stats : nodes_stats)
{
CNodeCombinedStats stats;
stats.nodeStats = std::get<0>(node_stats);
stats.fNodeStateStatsAvailable = std::get<1>(node_stats);
stats.nodeStateStats = std::get<2>(node_stats);
cachedNodeStats.append(stats);
}
}
int size() const
{
return cachedNodeStats.size();
}
CNodeCombinedStats *index(int idx)
{
if (idx >= 0 && idx < cachedNodeStats.size())
return &cachedNodeStats[idx];
return nullptr;
}
};
PeerTableModel::PeerTableModel(interfaces::Node& node, QObject* parent) : PeerTableModel::PeerTableModel(interfaces::Node& node, QObject* parent) :
QAbstractTableModel(parent), QAbstractTableModel(parent),
m_node(node), m_node(node),
timer(nullptr) timer(nullptr)
{ {
priv.reset(new PeerTablePriv());
// set up timer for auto refresh // set up timer for auto refresh
timer = new QTimer(this); timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &PeerTableModel::refresh); connect(timer, &QTimer::timeout, this, &PeerTableModel::refresh);
@ -90,7 +48,7 @@ int PeerTableModel::rowCount(const QModelIndex &parent) const
if (parent.isValid()) { if (parent.isValid()) {
return 0; return 0;
} }
return priv->size(); return m_peers_data.size();
} }
int PeerTableModel::columnCount(const QModelIndex& parent) const int PeerTableModel::columnCount(const QModelIndex& parent) const
@ -115,7 +73,7 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const
return (qint64)rec->nodeStats.nodeid; return (qint64)rec->nodeStats.nodeid;
case Address: case Address:
// prepend to peer address down-arrow symbol for inbound connection and up-arrow for outbound connection // prepend to peer address down-arrow symbol for inbound connection and up-arrow for outbound connection
return QString(rec->nodeStats.fInbound ? "" : "") + QString::fromStdString(rec->nodeStats.m_addr_name); return QString::fromStdString((rec->nodeStats.fInbound ? "" : "") + rec->nodeStats.m_addr_name);
case ConnectionType: case ConnectionType:
return GUIUtil::ConnectionTypeToQString(rec->nodeStats.m_conn_type, /* prepend_direction */ false); return GUIUtil::ConnectionTypeToQString(rec->nodeStats.m_conn_type, /* prepend_direction */ false);
case Network: case Network:
@ -177,16 +135,49 @@ Qt::ItemFlags PeerTableModel::flags(const QModelIndex &index) const
QModelIndex PeerTableModel::index(int row, int column, const QModelIndex& parent) const QModelIndex PeerTableModel::index(int row, int column, const QModelIndex& parent) const
{ {
Q_UNUSED(parent); Q_UNUSED(parent);
CNodeCombinedStats *data = priv->index(row);
if (data) if (0 <= row && row < rowCount() && 0 <= column && column < columnCount()) {
return createIndex(row, column, data); return createIndex(row, column, const_cast<CNodeCombinedStats*>(&m_peers_data[row]));
}
return QModelIndex(); return QModelIndex();
} }
void PeerTableModel::refresh() void PeerTableModel::refresh()
{ {
Q_EMIT layoutAboutToBeChanged(); interfaces::Node::NodesStats nodes_stats;
priv->refreshPeers(m_node); m_node.getNodesStats(nodes_stats);
Q_EMIT layoutChanged(); decltype(m_peers_data) new_peers_data;
new_peers_data.reserve(nodes_stats.size());
for (const auto& node_stats : nodes_stats) {
const CNodeCombinedStats stats{std::get<0>(node_stats), std::get<2>(node_stats), std::get<1>(node_stats)};
new_peers_data.append(stats);
}
// Handle peer addition or removal as suggested in Qt Docs. See:
// - https://doc.qt.io/qt-5/model-view-programming.html#inserting-and-removing-rows
// - https://doc.qt.io/qt-5/model-view-programming.html#resizable-models
// We take advantage of the fact that the std::vector returned
// by interfaces::Node::getNodesStats is sorted by nodeid.
for (int i = 0; i < m_peers_data.size();) {
if (i < new_peers_data.size() && m_peers_data.at(i).nodeStats.nodeid == new_peers_data.at(i).nodeStats.nodeid) {
++i;
continue;
}
// A peer has been removed from the table.
beginRemoveRows(QModelIndex(), i, i);
m_peers_data.erase(m_peers_data.begin() + i);
endRemoveRows();
}
if (m_peers_data.size() < new_peers_data.size()) {
// Some peers have been added to the end of the table.
beginInsertRows(QModelIndex(), m_peers_data.size(), new_peers_data.size() - 1);
m_peers_data.swap(new_peers_data);
endInsertRows();
} else {
m_peers_data.swap(new_peers_data);
}
Q_EMIT changed();
} }

View File

@ -8,10 +8,11 @@
#include <net_processing.h> // For CNodeStateStats #include <net_processing.h> // For CNodeStateStats
#include <net.h> #include <net.h>
#include <memory>
#include <QAbstractTableModel> #include <QAbstractTableModel>
#include <QList>
#include <QModelIndex>
#include <QStringList> #include <QStringList>
#include <QVariant>
class PeerTablePriv; class PeerTablePriv;
@ -61,18 +62,23 @@ public:
/** @name Methods overridden from QAbstractTableModel /** @name Methods overridden from QAbstractTableModel
@{*/ @{*/
int rowCount(const QModelIndex &parent) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
QModelIndex index(int row, int column, const QModelIndex &parent) const override; QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override; Qt::ItemFlags flags(const QModelIndex &index) const override;
/*@}*/ /*@}*/
public Q_SLOTS: public Q_SLOTS:
void refresh(); void refresh();
Q_SIGNALS:
void changed();
private: private:
//! Internal peer data structure.
QList<CNodeCombinedStats> m_peers_data{};
interfaces::Node& m_node; interfaces::Node& m_node;
const QStringList columns{ const QStringList columns{
/*: Title of Peers Table column which contains a /*: Title of Peers Table column which contains a
@ -99,7 +105,6 @@ private:
/*: Title of Peers Table column which contains the peer's /*: Title of Peers Table column which contains the peer's
User Agent string. */ User Agent string. */
tr("User Agent")}; tr("User Agent")};
std::unique_ptr<PeerTablePriv> priv;
QTimer *timer; QTimer *timer;
}; };

View File

@ -17,6 +17,9 @@
#include <utility> #include <utility>
#include <QLatin1Char>
#include <QLatin1String>
RecentRequestsTableModel::RecentRequestsTableModel(WalletModel *parent) : RecentRequestsTableModel::RecentRequestsTableModel(WalletModel *parent) :
QAbstractTableModel(parent), walletModel(parent) QAbstractTableModel(parent), walletModel(parent)
{ {
@ -126,7 +129,11 @@ void RecentRequestsTableModel::updateAmountColumnTitle()
/** Gets title for amount column including current display unit if optionsModel reference available. */ /** Gets title for amount column including current display unit if optionsModel reference available. */
QString RecentRequestsTableModel::getAmountTitle() QString RecentRequestsTableModel::getAmountTitle()
{ {
return (this->walletModel->getOptionsModel() != nullptr) ? tr("Requested") + " ("+BitcoinUnits::name(this->walletModel->getOptionsModel()->getDisplayUnit()) + ")" : ""; if (!walletModel->getOptionsModel()) return {};
return tr("Requested") +
QLatin1String(" (") +
BitcoinUnits::name(this->walletModel->getOptionsModel()->getDisplayUnit()) +
QLatin1Char(')');
} }
QModelIndex RecentRequestsTableModel::index(int row, int column, const QModelIndex &parent) const QModelIndex RecentRequestsTableModel::index(int row, int column, const QModelIndex &parent) const

View File

@ -37,6 +37,7 @@
#include <wallet/walletutil.h> #include <wallet/walletutil.h>
#endif #endif
#include <QAbstractButton>
#include <QButtonGroup> #include <QButtonGroup>
#include <QDir> #include <QDir>
#include <QFont> #include <QFont>
@ -504,6 +505,9 @@ RPCConsole::RPCConsole(interfaces::Node& node, QWidget* parent, Qt::WindowFlags
ui->splitter->restoreState(settings.value("RPCConsoleWidgetPeersTabSplitterSizes").toByteArray()); ui->splitter->restoreState(settings.value("RPCConsoleWidgetPeersTabSplitterSizes").toByteArray());
} }
m_peer_widget_header_state = settings.value("PeersTabPeerHeaderState").toByteArray();
m_banlist_widget_header_state = settings.value("PeersTabBanlistHeaderState").toByteArray();
constexpr QChar nonbreaking_hyphen(8209); constexpr QChar nonbreaking_hyphen(8209);
const std::vector<QString> CONNECTION_TYPE_DOC{ const std::vector<QString> CONNECTION_TYPE_DOC{
//: Explanatory text for an inbound peer connection. //: Explanatory text for an inbound peer connection.
@ -547,9 +551,9 @@ RPCConsole::RPCConsole(interfaces::Node& node, QWidget* parent, Qt::WindowFlags
ui->lineEdit->setMaxLength(16 * 1024 * 1024); ui->lineEdit->setMaxLength(16 * 1024 * 1024);
ui->messagesWidget->installEventFilter(this); ui->messagesWidget->installEventFilter(this);
connect(ui->clearButton, &QPushButton::clicked, [this] { clear(); }); connect(ui->clearButton, &QAbstractButton::clicked, [this] { clear(); });
connect(ui->fontBiggerButton, &QPushButton::clicked, this, &RPCConsole::fontBigger); connect(ui->fontBiggerButton, &QAbstractButton::clicked, this, &RPCConsole::fontBigger);
connect(ui->fontSmallerButton, &QPushButton::clicked, this, &RPCConsole::fontSmaller); connect(ui->fontSmallerButton, &QAbstractButton::clicked, this, &RPCConsole::fontSmaller);
connect(ui->btnClearTrafficGraph, &QPushButton::clicked, ui->trafficGraph, &TrafficGraphWidget::clear); connect(ui->btnClearTrafficGraph, &QPushButton::clicked, ui->trafficGraph, &TrafficGraphWidget::clear);
// disable the wallet selector by default // disable the wallet selector by default
@ -609,6 +613,9 @@ RPCConsole::~RPCConsole()
settings.setValue("RPCConsoleWidgetPeersTabSplitterSizes", ui->splitter->saveState()); settings.setValue("RPCConsoleWidgetPeersTabSplitterSizes", ui->splitter->saveState());
} }
settings.setValue("PeersTabPeerHeaderState", m_peer_widget_header_state);
settings.setValue("PeersTabBanlistHeaderState", m_banlist_widget_header_state);
m_node.rpcUnsetTimerInterface(rpcTimerInterface); m_node.rpcUnsetTimerInterface(rpcTimerInterface);
delete rpcTimerInterface; delete rpcTimerInterface;
delete pageButtons; delete pageButtons;
@ -700,9 +707,12 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_
ui->peerWidget->setSelectionBehavior(QAbstractItemView::SelectRows); ui->peerWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->peerWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); ui->peerWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
ui->peerWidget->setContextMenuPolicy(Qt::CustomContextMenu); ui->peerWidget->setContextMenuPolicy(Qt::CustomContextMenu);
if (!ui->peerWidget->horizontalHeader()->restoreState(m_peer_widget_header_state)) {
ui->peerWidget->setColumnWidth(PeerTableModel::Address, ADDRESS_COLUMN_WIDTH); ui->peerWidget->setColumnWidth(PeerTableModel::Address, ADDRESS_COLUMN_WIDTH);
ui->peerWidget->setColumnWidth(PeerTableModel::Subversion, SUBVERSION_COLUMN_WIDTH); ui->peerWidget->setColumnWidth(PeerTableModel::Subversion, SUBVERSION_COLUMN_WIDTH);
ui->peerWidget->setColumnWidth(PeerTableModel::Ping, PING_COLUMN_WIDTH); ui->peerWidget->setColumnWidth(PeerTableModel::Ping, PING_COLUMN_WIDTH);
}
ui->peerWidget->horizontalHeader()->setStretchLastSection(true); ui->peerWidget->horizontalHeader()->setStretchLastSection(true);
ui->peerWidget->setItemDelegateForColumn(PeerTableModel::NetNodeId, new PeerIdViewDelegate(this)); ui->peerWidget->setItemDelegateForColumn(PeerTableModel::NetNodeId, new PeerIdViewDelegate(this));
@ -717,7 +727,7 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_
// peer table signal handling - update peer details when selecting new node // peer table signal handling - update peer details when selecting new node
connect(ui->peerWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this, &RPCConsole::updateDetailWidget); connect(ui->peerWidget->selectionModel(), &QItemSelectionModel::selectionChanged, this, &RPCConsole::updateDetailWidget);
connect(model->getPeerTableModel(), &PeerTableModel::layoutChanged, this, &RPCConsole::updateDetailWidget); connect(model->getPeerTableModel(), &PeerTableModel::changed, this, &RPCConsole::updateDetailWidget);
// set up ban table // set up ban table
ui->banlistWidget->setModel(model->getBanTableModel()); ui->banlistWidget->setModel(model->getBanTableModel());
@ -725,8 +735,11 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_
ui->banlistWidget->setSelectionBehavior(QAbstractItemView::SelectRows); ui->banlistWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->banlistWidget->setSelectionMode(QAbstractItemView::SingleSelection); ui->banlistWidget->setSelectionMode(QAbstractItemView::SingleSelection);
ui->banlistWidget->setContextMenuPolicy(Qt::CustomContextMenu); ui->banlistWidget->setContextMenuPolicy(Qt::CustomContextMenu);
if (!ui->banlistWidget->horizontalHeader()->restoreState(m_banlist_widget_header_state)) {
ui->banlistWidget->setColumnWidth(BanTableModel::Address, BANSUBNET_COLUMN_WIDTH); ui->banlistWidget->setColumnWidth(BanTableModel::Address, BANSUBNET_COLUMN_WIDTH);
ui->banlistWidget->setColumnWidth(BanTableModel::Bantime, BANTIME_COLUMN_WIDTH); ui->banlistWidget->setColumnWidth(BanTableModel::Bantime, BANTIME_COLUMN_WIDTH);
}
ui->banlistWidget->horizontalHeader()->setStretchLastSection(true); ui->banlistWidget->horizontalHeader()->setStretchLastSection(true);
// create ban table context menu // create ban table context menu
@ -936,23 +949,29 @@ void RPCConsole::clear(bool keep_prompt)
).arg(consoleFontSize) ).arg(consoleFontSize)
); );
message(CMD_REPLY, static const QString welcome_message =
tr("Welcome to the %1 RPC console.").arg(PACKAGE_NAME) + /*: RPC console welcome message.
"<br>" + Placeholders %7 and %8 are style tags for the warning content, and
tr("Use up and down arrows to navigate history, and %1 to clear screen.") they are not space separated from the rest of the text intentionally. */
.arg("<b>" + ui->clearButton->shortcut().toString(QKeySequence::NativeText) + "</b>") + tr("Welcome to the %1 RPC console.\n"
"<br>" + "Use up and down arrows to navigate history, and %2 to clear screen.\n"
tr("Use %1 and %2 to increase or decrease the font size.") "Use %3 and %4 to increase or decrease the font size.\n"
.arg("<b>" + ui->fontBiggerButton->shortcut().toString(QKeySequence::NativeText) + "</b>") "Type %5 for an overview of available commands.\n"
.arg("<b>" + ui->fontSmallerButton->shortcut().toString(QKeySequence::NativeText) + "</b>") + "For more information on using this console, type %6.\n"
"<br>" + "\n"
tr("Type %1 for an overview of available commands.").arg("<b>help</b>") + "%7WARNING: Scammers have been active, telling users to type"
"<br>" + " commands here, stealing their wallet contents. Do not use this console"
tr("For more information on using this console type %1.").arg("<b>help-console</b>") + " without fully understanding the ramifications of a command.%8")
"<br><span class=\"secwarning\"><br>" + .arg(PACKAGE_NAME,
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.") + "<b>" + ui->clearButton->shortcut().toString(QKeySequence::NativeText) + "</b>",
"</span>", "<b>" + ui->fontBiggerButton->shortcut().toString(QKeySequence::NativeText) + "</b>",
true); "<b>" + ui->fontSmallerButton->shortcut().toString(QKeySequence::NativeText) + "</b>",
"<b>help</b>",
"<b>help-console</b>",
"<span class=\"secwarning\">",
"<span>");
message(CMD_REPLY, welcome_message, true);
} }
void RPCConsole::keyPressEvent(QKeyEvent *event) void RPCConsole::keyPressEvent(QKeyEvent *event)
@ -1074,10 +1093,12 @@ void RPCConsole::showPage(int index)
void RPCConsole::on_lineEdit_returnPressed() void RPCConsole::on_lineEdit_returnPressed()
{ {
QString cmd = ui->lineEdit->text(); QString cmd = ui->lineEdit->text().trimmed();
if (cmd.isEmpty()) {
return;
}
if(!cmd.isEmpty())
{
std::string strFilteredCmd; std::string strFilteredCmd;
try { try {
std::string dummy; std::string dummy;
@ -1090,9 +1111,18 @@ void RPCConsole::on_lineEdit_returnPressed()
return; return;
} }
ui->lineEdit->clear(); // A special case allows to request shutdown even a long-running command is executed.
if (cmd == QLatin1String("stop")) {
std::string dummy;
RPCExecuteCommandLine(m_node, dummy, cmd.toStdString());
return;
}
cmdBeforeBrowsing = QString(); if (m_is_executing) {
return;
}
ui->lineEdit->clear();
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
WalletModel* wallet_model = ui->WalletSelector->currentData().value<WalletModel*>(); WalletModel* wallet_model = ui->WalletSelector->currentData().value<WalletModel*>();
@ -1105,9 +1135,12 @@ void RPCConsole::on_lineEdit_returnPressed()
} }
m_last_wallet_model = wallet_model; m_last_wallet_model = wallet_model;
} }
#endif #endif // ENABLE_WALLET
message(CMD_REQUEST, QString::fromStdString(strFilteredCmd)); message(CMD_REQUEST, QString::fromStdString(strFilteredCmd));
//: A console message indicating an entered command is currently being executed.
message(CMD_REPLY, tr("Executing…"));
m_is_executing = true;
Q_EMIT cmdRequest(cmd, m_last_wallet_model); Q_EMIT cmdRequest(cmd, m_last_wallet_model);
cmd = QString::fromStdString(strFilteredCmd); cmd = QString::fromStdString(strFilteredCmd);
@ -1117,15 +1150,15 @@ void RPCConsole::on_lineEdit_returnPressed()
// Append command to history // Append command to history
history.append(cmd); history.append(cmd);
// Enforce maximum history size // Enforce maximum history size
while(history.size() > CONSOLE_HISTORY) while (history.size() > CONSOLE_HISTORY) {
history.removeFirst(); history.removeFirst();
}
// Set pointer to end of history // Set pointer to end of history
historyPtr = history.size(); historyPtr = history.size();
// Scroll console view to end // Scroll console view to end
scrollToEnd(); scrollToEnd();
} }
}
void RPCConsole::browseHistory(int offset) void RPCConsole::browseHistory(int offset)
{ {
@ -1154,7 +1187,13 @@ void RPCConsole::startExecutor()
executor->moveToThread(&thread); executor->moveToThread(&thread);
// Replies from executor object must go to this object // Replies from executor object must go to this object
connect(executor, &RPCExecutor::reply, this, qOverload<int, const QString&>(&RPCConsole::message)); connect(executor, &RPCExecutor::reply, this, [this](int category, const QString& command) {
// Remove "Executing…" message.
ui->messagesWidget->undo();
message(category, command);
scrollToEnd();
m_is_executing = false;
});
// Requests from this object must go to executor // Requests from this object must go to executor
connect(this, &RPCConsole::cmdRequest, executor, &RPCExecutor::request); connect(this, &RPCConsole::cmdRequest, executor, &RPCExecutor::request);
@ -1330,6 +1369,11 @@ void RPCConsole::showEvent(QShowEvent *event)
void RPCConsole::hideEvent(QHideEvent *event) void RPCConsole::hideEvent(QHideEvent *event)
{ {
// It is too late to call QHeaderView::saveState() in ~RPCConsole(), as all of
// the columns of QTableView child widgets will have zero width at that moment.
m_peer_widget_header_state = ui->peerWidget->horizontalHeader()->saveState();
m_banlist_widget_header_state = ui->banlistWidget->horizontalHeader()->saveState();
QWidget::hideEvent(event); QWidget::hideEvent(event);
if (!clientModel || !clientModel->getPeerTableModel()) if (!clientModel || !clientModel->getPeerTableModel())

View File

@ -12,9 +12,10 @@
#include <net.h> #include <net.h>
#include <uint256.h> #include <uint256.h>
#include <QWidget> #include <QByteArray>
#include <QCompleter> #include <QCompleter>
#include <QThread> #include <QThread>
#include <QWidget>
class ClientModel; class ClientModel;
class RPCTimerInterface; class RPCTimerInterface;
@ -189,6 +190,9 @@ private:
QCompleter *autoCompleter = nullptr; QCompleter *autoCompleter = nullptr;
QThread thread; QThread thread;
WalletModel* m_last_wallet_model{nullptr}; WalletModel* m_last_wallet_model{nullptr};
bool m_is_executing{false};
QByteArray m_peer_widget_header_state;
QByteArray m_banlist_widget_header_state;
/** Update UI with latest network info from model. */ /** Update UI with latest network info from model. */
void updateNetworkState(); void updateNetworkState();

View File

@ -41,7 +41,7 @@ void TestRpcCommand(RPCConsole* console)
QTest::keyClicks(lineEdit, "getblockchaininfo"); QTest::keyClicks(lineEdit, "getblockchaininfo");
QTest::keyClick(lineEdit, Qt::Key_Return); QTest::keyClick(lineEdit, Qt::Key_Return);
QVERIFY(mw_spy.wait(1000)); QVERIFY(mw_spy.wait(1000));
QCOMPARE(mw_spy.count(), 2); QCOMPARE(mw_spy.count(), 4);
QString output = messagesWidget->toPlainText(); QString output = messagesWidget->toPlainText();
UniValue value; UniValue value;
value.read(output.right(output.size() - output.indexOf("{")).toStdString()); value.read(output.right(output.size() - output.indexOf("{")).toStdString());

View File

@ -201,7 +201,7 @@ void TestGUI(interfaces::Node& node)
QCOMPARE(uri.count("amount=0.00000001"), 2); QCOMPARE(uri.count("amount=0.00000001"), 2);
QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("amount_tag")->text(), QString("Amount:")); QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("amount_tag")->text(), QString("Amount:"));
QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("amount_content")->text(), QString("0.00000001 ") + BitcoinUnits::name(unit)); QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("amount_content")->text(), QString::fromStdString("0.00000001 ") + BitcoinUnits::name(unit));
QCOMPARE(uri.count("label=TEST_LABEL_1"), 2); QCOMPARE(uri.count("label=TEST_LABEL_1"), 2);
QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("label_tag")->text(), QString("Label:")); QCOMPARE(receiveRequestDialog->QObject::findChild<QLabel*>("label_tag")->text(), QString("Label:"));

View File

@ -26,6 +26,8 @@
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>
#include <QLatin1String>
QString TransactionDesc::FormatTxStatus(const interfaces::WalletTx& wtx, const interfaces::WalletTxStatus& status, bool inMempool, int numBlocks) QString TransactionDesc::FormatTxStatus(const interfaces::WalletTx& wtx, const interfaces::WalletTxStatus& status, bool inMempool, int numBlocks)
{ {
if (!status.is_final) if (!status.is_final)
@ -44,19 +46,20 @@ QString TransactionDesc::FormatTxStatus(const interfaces::WalletTx& wtx, const i
bool fChainLocked = status.is_chainlocked; bool fChainLocked = status.is_chainlocked;
if (nDepth == 0) { if (nDepth == 0) {
strTxStatus = tr("0/unconfirmed, %1").arg((inMempool ? tr("in memory pool") : tr("not in memory pool"))) + (status.is_abandoned ? ", "+tr("abandoned") : ""); const QString abandoned{status.is_abandoned ? QLatin1String(", ") + tr("abandoned") : QString()};
strTxStatus = tr("0/unconfirmed, %1").arg((inMempool ? tr("in memory pool") : tr("not in memory pool"))) + abandoned;
} else if (!fChainLocked && nDepth < 6) { } else if (!fChainLocked && nDepth < 6) {
strTxStatus = tr("%1/unconfirmed").arg(nDepth); strTxStatus = tr("%1/unconfirmed").arg(nDepth);
} else { } else {
strTxStatus = tr("%1 confirmations").arg(nDepth); strTxStatus = tr("%1 confirmations").arg(nDepth);
if (fChainLocked) { if (fChainLocked) {
strTxStatus += ", " + tr("locked via ChainLocks"); strTxStatus += QLatin1String(", ") + tr("locked via ChainLocks");
return strTxStatus; return strTxStatus;
} }
} }
if (status.is_islocked) { if (status.is_islocked) {
strTxStatus += ", " + tr("verified via InstantSend"); strTxStatus += QLatin1String(", ") + tr("verified via InstantSend");
} }
return strTxStatus; return strTxStatus;

View File

@ -23,6 +23,8 @@
#include <QDateTime> #include <QDateTime>
#include <QDebug> #include <QDebug>
#include <QIcon> #include <QIcon>
#include <QLatin1Char>
#include <QLatin1String>
#include <QList> #include <QList>
#include <QMessageBox> #include <QMessageBox>
@ -466,9 +468,9 @@ QVariant TransactionTableModel::txAddressDecoration(const TransactionRecord *wtx
QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const
{ {
QString watchAddress; QString watchAddress;
if (tooltip) { if (tooltip && wtx->involvesWatchAddress) {
// Mark transactions involving watch-only addresses by adding " (watch-only)" // Mark transactions involving watch-only addresses by adding " (watch-only)"
watchAddress = wtx->involvesWatchAddress ? QString(" (") + tr("watch-only") + QString(")") : ""; watchAddress = QLatin1String(" (") + tr("watch-only") + QLatin1Char(')');
} }
switch(wtx->type) switch(wtx->type)

View File

@ -7,14 +7,11 @@
#include <fs.h> #include <fs.h>
#include <node/ui_interface.h> #include <node/ui_interface.h>
#include <psbt.h> #include <psbt.h>
#include <qt/bitcoingui.h>
#include <qt/createwalletdialog.h>
#include <qt/governancelist.h> #include <qt/governancelist.h>
#include <qt/guiutil.h> #include <qt/guiutil.h>
#include <qt/masternodelist.h> #include <qt/masternodelist.h>
#include <qt/overviewpage.h> #include <qt/overviewpage.h>
#include <qt/psbtoperationsdialog.h> #include <qt/psbtoperationsdialog.h>
#include <qt/walletcontroller.h>
#include <qt/walletmodel.h> #include <qt/walletmodel.h>
#include <qt/walletview.h> #include <qt/walletview.h>
#include <util/system.h> #include <util/system.h>
@ -30,9 +27,8 @@
#include <QPushButton> #include <QPushButton>
#include <QVBoxLayout> #include <QVBoxLayout>
WalletFrame::WalletFrame(BitcoinGUI* _gui) WalletFrame::WalletFrame(QWidget* parent)
: QFrame(_gui), : QFrame(parent),
gui(_gui),
m_size_hint(OverviewPage{nullptr}.sizeHint()) m_size_hint(OverviewPage{nullptr}.sizeHint())
{ {
// Leave HBox hook for adding a list view later // Leave HBox hook for adding a list view later
@ -53,11 +49,7 @@ WalletFrame::WalletFrame(BitcoinGUI* _gui)
// A button for create wallet dialog // A button for create wallet dialog
QPushButton* create_wallet_button = new QPushButton(tr("Create a new wallet"), walletStack); QPushButton* create_wallet_button = new QPushButton(tr("Create a new wallet"), walletStack);
connect(create_wallet_button, &QPushButton::clicked, [this] { connect(create_wallet_button, &QPushButton::clicked, this, &WalletFrame::createWalletButtonClicked);
auto activity = new CreateWalletActivity(gui->getWalletController(), this);
connect(activity, &CreateWalletActivity::finished, activity, &QObject::deleteLater);
activity->create();
});
no_wallet_layout->addWidget(create_wallet_button, 0, Qt::AlignHCenter | Qt::AlignTop); no_wallet_layout->addWidget(create_wallet_button, 0, Qt::AlignHCenter | Qt::AlignTop);
no_wallet_group->setLayout(no_wallet_layout); no_wallet_group->setLayout(no_wallet_layout);
@ -86,17 +78,15 @@ void WalletFrame::setClientModel(ClientModel *_clientModel)
} }
} }
bool WalletFrame::addWallet(WalletModel *walletModel) bool WalletFrame::addWallet(WalletModel* walletModel, WalletView* walletView)
{ {
if (!gui || !clientModel || !walletModel) return false; if (!clientModel || !walletModel) return false;
if (mapWalletViews.count(walletModel) > 0) return false; if (mapWalletViews.count(walletModel) > 0) return false;
WalletView* walletView = new WalletView(this);
walletView->setClientModel(clientModel); walletView->setClientModel(clientModel);
walletView->setWalletModel(walletModel); walletView->setWalletModel(walletModel);
walletView->showOutOfSyncWarning(bOutOfSync); walletView->showOutOfSyncWarning(bOutOfSync);
walletView->setPrivacy(gui->isPrivacyModeActivated());
WalletView* current_wallet_view = currentWalletView(); WalletView* current_wallet_view = currentWalletView();
if (current_wallet_view) { if (current_wallet_view) {
@ -108,17 +98,6 @@ bool WalletFrame::addWallet(WalletModel *walletModel)
walletStack->addWidget(walletView); walletStack->addWidget(walletView);
mapWalletViews[walletModel] = walletView; mapWalletViews[walletModel] = walletView;
connect(walletView, &WalletView::outOfSyncWarningClicked, this, &WalletFrame::outOfSyncWarningClicked);
connect(walletView, &WalletView::transactionClicked, gui, &BitcoinGUI::gotoHistoryPage);
connect(walletView, &WalletView::coinsSent, gui, &BitcoinGUI::gotoHistoryPage);
connect(walletView, &WalletView::message, [this](const QString& title, const QString& message, unsigned int style) {
gui->message(title, message, style);
});
connect(walletView, &WalletView::encryptionStatusChanged, gui, &BitcoinGUI::updateWalletStatus);
connect(walletView, &WalletView::incomingTransaction, gui, &BitcoinGUI::incomingTransaction);
connect(walletView, &WalletView::hdEnabledStatusChanged, gui, &BitcoinGUI::updateWalletStatus);
connect(gui, &BitcoinGUI::setPrivacy, walletView, &WalletView::setPrivacy);
return true; return true;
} }
@ -364,8 +343,3 @@ WalletModel* WalletFrame::currentWalletModel() const
WalletView* wallet_view = currentWalletView(); WalletView* wallet_view = currentWalletView();
return wallet_view ? wallet_view->getWalletModel() : nullptr; return wallet_view ? wallet_view->getWalletModel() : nullptr;
} }
void WalletFrame::outOfSyncWarningClicked()
{
Q_EMIT requestedSyncWarningInfo();
}

View File

@ -9,7 +9,6 @@
#include <QGroupBox> #include <QGroupBox>
#include <QMap> #include <QMap>
class BitcoinGUI;
class ClientModel; class ClientModel;
class SendCoinsRecipient; class SendCoinsRecipient;
class WalletModel; class WalletModel;
@ -33,12 +32,12 @@ class WalletFrame : public QFrame
Q_OBJECT Q_OBJECT
public: public:
explicit WalletFrame(BitcoinGUI* _gui = nullptr); explicit WalletFrame(QWidget* parent);
~WalletFrame(); ~WalletFrame();
void setClientModel(ClientModel *clientModel); void setClientModel(ClientModel *clientModel);
bool addWallet(WalletModel *walletModel); bool addWallet(WalletModel* walletModel, WalletView* walletView);
void setCurrentWallet(WalletModel* wallet_model); void setCurrentWallet(WalletModel* wallet_model);
void removeWallet(WalletModel* wallet_model); void removeWallet(WalletModel* wallet_model);
void removeAllWallets(); void removeAllWallets();
@ -51,12 +50,11 @@ public:
Q_SIGNALS: Q_SIGNALS:
void message(const QString& title, const QString& message, unsigned int style); void message(const QString& title, const QString& message, unsigned int style);
/** Notify that the user has requested more information about the out-of-sync warning */
void requestedSyncWarningInfo(); void createWalletButtonClicked();
private: private:
QStackedWidget *walletStack; QStackedWidget *walletStack;
BitcoinGUI *gui;
ClientModel *clientModel; ClientModel *clientModel;
QMap<WalletModel*, WalletView*> mapWalletViews; QMap<WalletModel*, WalletView*> mapWalletViews;
QGroupBox* no_wallet_group; QGroupBox* no_wallet_group;
@ -110,8 +108,6 @@ public Q_SLOTS:
void usedSendingAddresses(); void usedSendingAddresses();
/** Show used receiving addresses */ /** Show used receiving addresses */
void usedReceivingAddresses(); void usedReceivingAddresses();
/** Pass on signal over requested out-of-sync-warning information */
void outOfSyncWarningClicked();
}; };
#endif // BITCOIN_QT_WALLETFRAME_H #endif // BITCOIN_QT_WALLETFRAME_H

View File

@ -100,7 +100,7 @@ WalletView::WalletView(QWidget* parent) :
connect(overviewPage, &OverviewPage::transactionClicked, this, &WalletView::transactionClicked); connect(overviewPage, &OverviewPage::transactionClicked, this, &WalletView::transactionClicked);
// Clicking on a transaction on the overview pre-selects the transaction on the transaction history page // Clicking on a transaction on the overview pre-selects the transaction on the transaction history page
connect(overviewPage, &OverviewPage::transactionClicked, transactionView, qOverload<const QModelIndex&>(&TransactionView::focusTransaction)); connect(overviewPage, &OverviewPage::transactionClicked, transactionView, qOverload<const QModelIndex&>(&TransactionView::focusTransaction));
connect(overviewPage, &OverviewPage::outOfSyncWarningClicked, this, &WalletView::requestedSyncWarningInfo); connect(overviewPage, &OverviewPage::outOfSyncWarningClicked, this, &WalletView::outOfSyncWarningClicked);
connect(sendCoinsPage, &SendCoinsDialog::coinsSent, this, &WalletView::coinsSent); connect(sendCoinsPage, &SendCoinsDialog::coinsSent, this, &WalletView::coinsSent);
connect(coinJoinCoinsPage, &SendCoinsDialog::coinsSent, this, &WalletView::coinsSent); connect(coinJoinCoinsPage, &SendCoinsDialog::coinsSent, this, &WalletView::coinsSent);
@ -408,11 +408,6 @@ void WalletView::showProgress(const QString &title, int nProgress)
} }
} }
void WalletView::requestedSyncWarningInfo()
{
Q_EMIT outOfSyncWarningClicked();
}
/** Update wallet with the sum of the selected transactions */ /** Update wallet with the sum of the selected transactions */
void WalletView::trxAmount(QString amount) void WalletView::trxAmount(QString amount)
{ {

View File

@ -122,10 +122,6 @@ public Q_SLOTS:
/** Show progress dialog e.g. for rescan */ /** Show progress dialog e.g. for rescan */
void showProgress(const QString &title, int nProgress); void showProgress(const QString &title, int nProgress);
/** User has requested more information about the out of sync state */
void requestedSyncWarningInfo();
/** Update selected DASH amount from transactionview */ /** Update selected DASH amount from transactionview */
void trxAmount(QString amount); void trxAmount(QString amount);
Q_SIGNALS: Q_SIGNALS:

View File

@ -115,7 +115,7 @@ bool LoadWallets(interfaces::Chain& chain, interfaces::CoinJoin::Loader& coinjoi
if (!database && status == DatabaseStatus::FAILED_NOT_FOUND) { if (!database && status == DatabaseStatus::FAILED_NOT_FOUND) {
continue; continue;
} }
chain.initMessage(_("Loading wallet...").translated); chain.initMessage(_("Loading wallet").translated);
std::shared_ptr<CWallet> pwallet = database ? CWallet::Create(&chain, &coinjoin_loader, name, std::move(database), options.create_flags, error_string, warnings) : nullptr; std::shared_ptr<CWallet> pwallet = database ? CWallet::Create(&chain, &coinjoin_loader, name, std::move(database), options.create_flags, error_string, warnings) : nullptr;
if (!warnings.empty()) chain.initWarning(Join(warnings, Untranslated("\n"))); if (!warnings.empty()) chain.initWarning(Join(warnings, Untranslated("\n")));
if (!pwallet) { if (!pwallet) {

View File

@ -238,7 +238,7 @@ std::shared_ptr<CWallet> LoadWalletInternal(interfaces::Chain& chain, interfaces
return nullptr; return nullptr;
} }
chain.initMessage(_("Loading wallet...").translated); chain.initMessage(_("Loading wallet").translated);
std::shared_ptr<CWallet> wallet = CWallet::Create(&chain, &coinjoin_loader, name, std::move(database), options.create_flags, error, warnings); std::shared_ptr<CWallet> wallet = CWallet::Create(&chain, &coinjoin_loader, name, std::move(database), options.create_flags, error, warnings);
if (!wallet) { if (!wallet) {
error = Untranslated("Wallet loading failed.") + Untranslated(" ") + error; error = Untranslated("Wallet loading failed.") + Untranslated(" ") + error;
@ -304,7 +304,7 @@ std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, interfaces::Coin
} }
// Make the wallet // Make the wallet
chain.initMessage(_("Loading wallet...").translated); chain.initMessage(_("Loading wallet").translated);
std::shared_ptr<CWallet> wallet = CWallet::Create(&chain, &coinjoin_loader, name, std::move(database), wallet_creation_flags, error, warnings); std::shared_ptr<CWallet> wallet = CWallet::Create(&chain, &coinjoin_loader, name, std::move(database), wallet_creation_flags, error, warnings);
if (!wallet) { if (!wallet) {
error = Untranslated("Wallet creation failed.") + Untranslated(" ") + error; error = Untranslated("Wallet creation failed.") + Untranslated(" ") + error;

View File

@ -16,7 +16,6 @@ EXPECTED_CIRCULAR_DEPENDENCIES=(
"index/coinstatsindex -> node/coinstats -> index/coinstatsindex" "index/coinstatsindex -> node/coinstats -> index/coinstatsindex"
"policy/fees -> txmempool -> policy/fees" "policy/fees -> txmempool -> policy/fees"
"qt/addresstablemodel -> qt/walletmodel -> qt/addresstablemodel" "qt/addresstablemodel -> qt/walletmodel -> qt/addresstablemodel"
"qt/bitcoingui -> qt/walletframe -> qt/bitcoingui"
"qt/recentrequeststablemodel -> qt/walletmodel -> qt/recentrequeststablemodel" "qt/recentrequeststablemodel -> qt/walletmodel -> qt/recentrequeststablemodel"
"qt/transactiontablemodel -> qt/walletmodel -> qt/transactiontablemodel" "qt/transactiontablemodel -> qt/walletmodel -> qt/transactiontablemodel"
"txmempool -> validation -> txmempool" "txmempool -> validation -> txmempool"