diff --git a/src/qt/bitcoin.h b/src/qt/bitcoin.h --- a/src/qt/bitcoin.h +++ b/src/qt/bitcoin.h @@ -11,6 +11,7 @@ #include +#include #include class BitcoinGUI; @@ -22,6 +23,7 @@ class PaymentServer; class PlatformStyle; class RPCServer; +class SplashScreen; class WalletController; class WalletModel; @@ -60,7 +62,7 @@ class BitcoinApplication : public QApplication { Q_OBJECT public: - explicit BitcoinApplication(interfaces::Node &node); + explicit BitcoinApplication(); ~BitcoinApplication(); #ifdef ENABLE_WALLET @@ -96,6 +98,12 @@ /// Setup platform style void setupPlatformStyle(); + interfaces::Node &node() const { + assert(m_node); + return *m_node; + } + void setNode(interfaces::Node &node); + public Q_SLOTS: void initializeResult(bool success); void shutdownResult(); @@ -112,7 +120,6 @@ private: QThread *coreThread; - interfaces::Node &m_node; OptionsModel *optionsModel; ClientModel *clientModel; BitcoinGUI *window; @@ -124,6 +131,8 @@ int returnValue; const PlatformStyle *platformStyle; std::unique_ptr shutdownWindow; + SplashScreen *m_splash = nullptr; + interfaces::Node *m_node = nullptr; void startThread(); }; diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -185,11 +185,10 @@ static int qt_argc = 1; static const char *qt_argv = "bitcoin-qt"; -BitcoinApplication::BitcoinApplication(interfaces::Node &node) +BitcoinApplication::BitcoinApplication() : QApplication(qt_argc, const_cast(&qt_argv)), coreThread(nullptr), - m_node(node), optionsModel(nullptr), clientModel(nullptr), - window(nullptr), pollShutdownTimer(nullptr), returnValue(0), - platformStyle(nullptr) { + optionsModel(nullptr), clientModel(nullptr), window(nullptr), + pollShutdownTimer(nullptr), returnValue(0), platformStyle(nullptr) { setQuitOnLastWindowClosed(false); } @@ -231,13 +230,14 @@ #endif void BitcoinApplication::createOptionsModel(bool resetSettings) { - optionsModel = new OptionsModel(m_node, nullptr, resetSettings); + optionsModel = new OptionsModel(nullptr, resetSettings); + optionsModel->setNode(node()); } void BitcoinApplication::createWindow(const Config *config, const NetworkStyle *networkStyle) { window = - new BitcoinGUI(m_node, config, platformStyle, networkStyle, nullptr); + new BitcoinGUI(node(), config, platformStyle, networkStyle, nullptr); pollShutdownTimer = new QTimer(window); connect(pollShutdownTimer, &QTimer::timeout, window, @@ -245,19 +245,26 @@ } void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle) { - SplashScreen *splash = new SplashScreen(m_node, networkStyle); + assert(!m_splash); + m_splash = new SplashScreen(networkStyle); + m_splash->setNode(node()); // We don't hold a direct pointer to the splash screen after creation, but // the splash screen will take care of deleting itself when finish() // happens. - splash->show(); - connect(this, &BitcoinApplication::splashFinished, splash, + m_splash->show(); + connect(this, &BitcoinApplication::splashFinished, m_splash, &SplashScreen::finish); - connect(this, &BitcoinApplication::requestedShutdown, splash, + connect(this, &BitcoinApplication::requestedShutdown, m_splash, &QWidget::close); } +void BitcoinApplication::setNode(interfaces::Node &node) { + assert(!m_node); + m_node = &node; +} + bool BitcoinApplication::baseInitialize(Config &config) { - return m_node.baseInitialize(config); + return node().baseInitialize(config); } void BitcoinApplication::startThread() { @@ -265,7 +272,7 @@ return; } coreThread = new QThread(this); - BitcoinABC *executor = new BitcoinABC(m_node); + BitcoinABC *executor = new BitcoinABC(node()); executor->moveToThread(coreThread); /* communication to and from thread */ @@ -338,7 +345,7 @@ window->unsubscribeFromCoreSignals(); // Request node shutdown, which can interrupt long operations, like // rescanning a wallet. - m_node.startShutdown(); + node().startShutdown(); // Unsetting the client model can cause the current thread to wait for node // to complete an operation, like wait for a RPC execution to complete. window->setClientModel(nullptr); @@ -364,12 +371,12 @@ // Log this only after AppInitMain finishes, as then logging setup is // guaranteed complete. qInfo() << "Platform customization:" << platformStyle->getName(); - clientModel = new ClientModel(m_node, optionsModel); + clientModel = new ClientModel(node(), optionsModel); window->setClientModel(clientModel); #ifdef ENABLE_WALLET if (WalletModel::isWalletEnabled()) { m_wallet_controller = - new WalletController(m_node, platformStyle, optionsModel, this); + new WalletController(node(), platformStyle, optionsModel, this); window->setWalletController(m_wallet_controller); if (paymentServer) { paymentServer->setOptionsModel(optionsModel); @@ -545,7 +552,8 @@ QApplication::setAttribute(Qt::AA_DontShowIconsInMenus); #endif - BitcoinApplication app(*node); + BitcoinApplication app; + app.setNode(*node); // Register meta types used for QMetaObject::invokeMethod and // Qt::QueuedConnection @@ -777,10 +785,12 @@ return app.getReturnValue(); } catch (const std::exception &e) { PrintExceptionContinue(&e, "Runaway exception"); - app.handleRunawayException(QString::fromStdString(node->getWarnings())); + app.handleRunawayException( + QString::fromStdString(app.node().getWarnings())); } catch (...) { PrintExceptionContinue(nullptr, "Runaway exception"); - app.handleRunawayException(QString::fromStdString(node->getWarnings())); + app.handleRunawayException( + QString::fromStdString(app.node().getWarnings())); } return EXIT_FAILURE; } diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -9,6 +9,8 @@ #include +#include + namespace interfaces { class Node; } @@ -30,7 +32,7 @@ Q_OBJECT public: - explicit OptionsModel(interfaces::Node &node, QObject *parent = nullptr, + explicit OptionsModel(QObject *parent = nullptr, bool resetSettings = false); enum OptionID { @@ -89,10 +91,17 @@ void setRestartRequired(bool fRequired); bool isRestartRequired() const; - interfaces::Node &node() const { return m_node; } + interfaces::Node &node() const { + assert(m_node); + return *m_node; + } + void setNode(interfaces::Node &node) { + assert(!m_node); + m_node = &node; + } private: - interfaces::Node &m_node; + interfaces::Node *m_node = nullptr; /* Qt-only settings */ bool fHideTrayIcon; bool fMinimizeToTray; diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -26,9 +26,8 @@ static const QString GetDefaultProxyAddress(); -OptionsModel::OptionsModel(interfaces::Node &node, QObject *parent, - bool resetSettings) - : QAbstractListModel(parent), m_node(node) { +OptionsModel::OptionsModel(QObject *parent, bool resetSettings) + : QAbstractListModel(parent) { Init(resetSettings); } @@ -385,7 +384,7 @@ break; case MapPortUPnP: // core option - can be changed on-the-fly settings.setValue("fUseUPnP", value.toBool()); - m_node.mapPort(value.toBool()); + node().mapPort(value.toBool()); break; case MinimizeOnClose: fMinimizeOnClose = value.toBool(); @@ -527,7 +526,7 @@ // Directly query current base proxy, because // GUI settings can be overridden with -proxy. proxyType curProxy; - if (m_node.getProxy(NET_IPV4, curProxy)) { + if (node().getProxy(NET_IPV4, curProxy)) { proxy.setType(QNetworkProxy::Socks5Proxy); proxy.setHostName(QString::fromStdString(curProxy.proxy.ToStringIP())); proxy.setPort(curProxy.proxy.GetPort()); diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h --- a/src/qt/splashscreen.h +++ b/src/qt/splashscreen.h @@ -27,9 +27,9 @@ Q_OBJECT public: - explicit SplashScreen(interfaces::Node &node, - const NetworkStyle *networkStyle); + explicit SplashScreen(const NetworkStyle *networkStyle); ~SplashScreen(); + void setNode(interfaces::Node &node); protected: void paintEvent(QPaintEvent *event) override; @@ -52,6 +52,8 @@ void subscribeToCoreSignals(); /** Disconnect core signals to splash screen */ void unsubscribeFromCoreSignals(); + /** Initiate shutdown */ + void shutdown(); /** Connect wallet signals to splash screen */ void ConnectWallet(std::unique_ptr wallet); @@ -60,7 +62,7 @@ QColor curColor; int curAlignment; - interfaces::Node &m_node; + interfaces::Node *m_node = nullptr; std::unique_ptr m_handler_init_message; std::unique_ptr m_handler_show_progress; std::unique_ptr m_handler_load_wallet; diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -23,9 +23,8 @@ #include #include -SplashScreen::SplashScreen(interfaces::Node &node, - const NetworkStyle *networkStyle) - : QWidget(nullptr), curAlignment(0), m_node(node) { +SplashScreen::SplashScreen(const NetworkStyle *networkStyle) + : QWidget(nullptr), curAlignment(0) { // set reference point, paddings int paddingRight = 50; int paddingTop = 50; @@ -140,19 +139,32 @@ setFixedSize(r.size()); move(QGuiApplication::primaryScreen()->geometry().center() - r.center()); - subscribeToCoreSignals(); installEventFilter(this); } SplashScreen::~SplashScreen() { - unsubscribeFromCoreSignals(); + if (m_node) { + unsubscribeFromCoreSignals(); + } +} + +void SplashScreen::setNode(interfaces::Node &node) { + assert(!m_node); + m_node = &node; + subscribeToCoreSignals(); +} + +void SplashScreen::shutdown() { + if (m_node) { + m_node->startShutdown(); + } } bool SplashScreen::eventFilter(QObject *obj, QEvent *ev) { if (ev->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast(ev); if (keyEvent->text()[0] == 'q') { - m_node.startShutdown(); + shutdown(); } } return QObject::eventFilter(obj, ev); @@ -199,13 +211,13 @@ void SplashScreen::subscribeToCoreSignals() { // Connect signals to client - m_handler_init_message = m_node.handleInitMessage( + m_handler_init_message = m_node->handleInitMessage( std::bind(InitMessage, this, std::placeholders::_1)); - m_handler_show_progress = m_node.handleShowProgress( + m_handler_show_progress = m_node->handleShowProgress( std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); #ifdef ENABLE_WALLET - m_handler_load_wallet = m_node.handleLoadWallet( + m_handler_load_wallet = m_node->handleLoadWallet( [this](std::unique_ptr wallet) { ConnectWallet(std::move(wallet)); }); @@ -241,6 +253,6 @@ void SplashScreen::closeEvent(QCloseEvent *event) { // allows an "emergency" shutdown during startup - m_node.startShutdown(); + shutdown(); event->ignore(); } diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp --- a/src/qt/test/addressbooktests.cpp +++ b/src/qt/test/addressbooktests.cpp @@ -112,7 +112,7 @@ // Initialize relevant QT models. std::unique_ptr platformStyle( PlatformStyle::instantiate("other")); - OptionsModel optionsModel(node); + OptionsModel optionsModel; AddWallet(wallet); WalletModel walletModel(interfaces::MakeWallet(wallet), node, platformStyle.get(), &optionsModel); diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp --- a/src/qt/test/paymentservertests.cpp +++ b/src/qt/test/paymentservertests.cpp @@ -70,7 +70,8 @@ BasicTestingSetup testing_setup(CBaseChainParams::MAIN); auto node = interfaces::MakeNode(); - OptionsModel optionsModel(*node); + OptionsModel optionsModel; + optionsModel.setNode(*node); PaymentServer *server = new PaymentServer(nullptr, false); X509_STORE *caStore = X509_STORE_new(); X509_STORE_add_cert(caStore, parse_b64der_cert(caCert1_BASE64)); diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -68,11 +68,12 @@ // Don't remove this, it's needed to access // QApplication:: and QCoreApplication:: in the tests - BitcoinApplication app(*node); + BitcoinApplication app; + app.setNode(*node); app.setApplicationName("BitcoinABC-Qt-test"); // Make gArgs available in the NodeContext - node->context()->args = &gArgs; + app.node().context()->args = &gArgs; AppTests app_tests(app); if (QTest::qExec(&app_tests) != 0) { @@ -88,7 +89,7 @@ fInvalid = true; } #endif - RPCNestedTests test3(*node); + RPCNestedTests test3(app.node()); if (QTest::qExec(&test3) != 0) { fInvalid = true; } @@ -105,11 +106,11 @@ fInvalid = true; } #ifdef ENABLE_WALLET - WalletTests test7(*node); + WalletTests test7(app.node()); if (QTest::qExec(&test7) != 0) { fInvalid = true; } - AddressBookTests test8(*node); + AddressBookTests test8(app.node()); if (QTest::qExec(&test8) != 0) { fInvalid = true; } diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -147,7 +147,7 @@ // Create widgets for sending coins and listing transactions. std::unique_ptr platformStyle( PlatformStyle::instantiate("other")); - OptionsModel optionsModel(node); + OptionsModel optionsModel; AddWallet(wallet); WalletModel walletModel(interfaces::MakeWallet(wallet), node, platformStyle.get(), &optionsModel);