qt: Remove global references in bitcoin.cpp

Remove the need for global references `guiref` and
`splashref` by making the BitcoinGUI and SplashScreen
classes register for the UI interface signals themselves.
This commit is contained in:
Wladimir J. van der Laan 2014-01-08 08:59:24 +01:00
parent 55fe4de960
commit 35ecf854c0
5 changed files with 103 additions and 48 deletions

View File

@ -30,7 +30,6 @@
#include <QSettings> #include <QSettings>
#include <QTimer> #include <QTimer>
#include <QTranslator> #include <QTranslator>
#include <QWeakPointer>
#include <QThread> #include <QThread>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QLabel> #include <QLabel>
@ -56,43 +55,8 @@ Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
// Declare meta types used for QMetaObject::invokeMethod // Declare meta types used for QMetaObject::invokeMethod
Q_DECLARE_METATYPE(bool*) Q_DECLARE_METATYPE(bool*)
// Need a global reference for the notifications to find the GUI and splash screen
static QWeakPointer<BitcoinGUI> guiref;
static QWeakPointer<SplashScreen> splashref;
static bool ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style)
{
if(!guiref.isNull())
{
bool modal = (style & CClientUIInterface::MODAL);
bool ret = false;
// In case of modal message, use blocking connection to wait for user to click a button
QMetaObject::invokeMethod(guiref.data(), "message",
modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(caption)),
Q_ARG(QString, QString::fromStdString(message)),
Q_ARG(unsigned int, style),
Q_ARG(bool*, &ret));
return ret;
}
else
{
LogPrintf("%s: %s\n", caption.c_str(), message.c_str());
fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str());
return false;
}
}
static void InitMessage(const std::string &message) static void InitMessage(const std::string &message)
{ {
if(!splashref.isNull())
{
QMetaObject::invokeMethod(splashref.data(), "showMessage",
Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(message)),
Q_ARG(int, Qt::AlignBottom|Qt::AlignHCenter),
Q_ARG(QColor, QColor(55,55,55)));
}
LogPrintf("init message: %s\n", message.c_str()); LogPrintf("init message: %s\n", message.c_str());
} }
@ -199,6 +163,8 @@ public:
void createOptionsModel(); void createOptionsModel();
/// Create main window /// Create main window
void createWindow(bool isaTestNet); void createWindow(bool isaTestNet);
/// Create splash screen
void createSplashScreen(bool isaTestNet);
/// Request core initialization /// Request core initialization
void requestInitialize(); void requestInitialize();
@ -218,6 +184,7 @@ signals:
void requestedInitialize(); void requestedInitialize();
void requestedShutdown(); void requestedShutdown();
void stopThread(); void stopThread();
void splashFinished(QWidget *window);
private: private:
QThread *coreThread; QThread *coreThread;
@ -295,6 +262,10 @@ BitcoinApplication::~BitcoinApplication()
emit stopThread(); emit stopThread();
coreThread->wait(); coreThread->wait();
LogPrintf("Stopped thread\n"); LogPrintf("Stopped thread\n");
delete window;
delete paymentServer;
delete optionsModel;
} }
void BitcoinApplication::createPaymentServer() void BitcoinApplication::createPaymentServer()
@ -310,13 +281,20 @@ void BitcoinApplication::createOptionsModel()
void BitcoinApplication::createWindow(bool isaTestNet) void BitcoinApplication::createWindow(bool isaTestNet)
{ {
window = new BitcoinGUI(isaTestNet, 0); window = new BitcoinGUI(isaTestNet, 0);
guiref = window;
QTimer* pollShutdownTimer = new QTimer(window); QTimer* pollShutdownTimer = new QTimer(window);
connect(pollShutdownTimer, SIGNAL(timeout()), window, SLOT(detectShutdown())); connect(pollShutdownTimer, SIGNAL(timeout()), window, SLOT(detectShutdown()));
pollShutdownTimer->start(200); pollShutdownTimer->start(200);
} }
void BitcoinApplication::createSplashScreen(bool isaTestNet)
{
SplashScreen *splash = new SplashScreen(QPixmap(), 0, isaTestNet);
splash->setAttribute(Qt::WA_DeleteOnClose);
splash->show();
connect(this, SIGNAL(splashFinished(QWidget*)), splash, SLOT(slotFinish(QWidget*)));
}
void BitcoinApplication::startThread() void BitcoinApplication::startThread()
{ {
coreThread = new QThread(this); coreThread = new QThread(this);
@ -348,9 +326,11 @@ void BitcoinApplication::requestShutdown()
window->hide(); window->hide();
window->setClientModel(0); window->setClientModel(0);
window->removeAllWallets(); window->removeAllWallets();
guiref.clear();
delete walletModel; delete walletModel;
walletModel = 0;
delete clientModel;
clientModel = 0;
// Show a simple window indicating shutdown status // Show a simple window indicating shutdown status
QWidget *shutdownWindow = new QWidget(); QWidget *shutdownWindow = new QWidget();
@ -382,8 +362,7 @@ void BitcoinApplication::initializeResult(int retval)
PaymentServer::LoadRootCAs(); PaymentServer::LoadRootCAs();
paymentServer->setOptionsModel(optionsModel); paymentServer->setOptionsModel(optionsModel);
if (!splashref.isNull()) emit splashFinished(window);
splashref.data()->finish(window);
clientModel = new ClientModel(optionsModel); clientModel = new ClientModel(optionsModel);
window->setClientModel(clientModel); window->setClientModel(clientModel);
@ -489,6 +468,7 @@ int main(int argc, char *argv[])
// Now that QSettings are accessible, initialize translations // Now that QSettings are accessible, initialize translations
QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator; QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator;
initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator); initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator);
uiInterface.Translate.connect(Translate);
// Show help message immediately after parsing command-line options (for "-lang") and setting locale, // Show help message immediately after parsing command-line options (for "-lang") and setting locale,
// but before showing splash screen. // but before showing splash screen.
@ -543,9 +523,7 @@ int main(int argc, char *argv[])
app.createOptionsModel(); app.createOptionsModel();
// Subscribe to global signals from core // Subscribe to global signals from core
uiInterface.ThreadSafeMessageBox.connect(ThreadSafeMessageBox);
uiInterface.InitMessage.connect(InitMessage); uiInterface.InitMessage.connect(InitMessage);
uiInterface.Translate.connect(Translate);
// Show help message immediately after parsing command-line options (for "-lang") and setting locale, // Show help message immediately after parsing command-line options (for "-lang") and setting locale,
// but before showing splash screen. // but before showing splash screen.
@ -557,12 +535,7 @@ int main(int argc, char *argv[])
} }
if (GetBoolArg("-splash", true) && !GetBoolArg("-min", false)) if (GetBoolArg("-splash", true) && !GetBoolArg("-min", false))
{ app.createSplashScreen(isaTestNet);
SplashScreen *splash = new SplashScreen(QPixmap(), 0, isaTestNet);
splash->setAttribute(Qt::WA_DeleteOnClose);
splash->show();
splashref = splash;
}
try try
{ {

View File

@ -170,10 +170,16 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) :
// Initially wallet actions should be disabled // Initially wallet actions should be disabled
setWalletActionsEnabled(false); setWalletActionsEnabled(false);
// Subscribe to notifications from core
subscribeToCoreSignals();
} }
BitcoinGUI::~BitcoinGUI() BitcoinGUI::~BitcoinGUI()
{ {
// Unsubscribe from notifications from core
unsubscribeFromCoreSignals();
GUIUtil::saveWindowGeometry("nWindow", this); GUIUtil::saveWindowGeometry("nWindow", this);
if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu) if(trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu)
trayIcon->hide(); trayIcon->hide();
@ -851,3 +857,29 @@ void BitcoinGUI::detectShutdown()
if (ShutdownRequested()) if (ShutdownRequested())
QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection); QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection);
} }
static bool ThreadSafeMessageBox(BitcoinGUI *gui, const std::string& message, const std::string& caption, unsigned int style)
{
bool modal = (style & CClientUIInterface::MODAL);
bool ret = false;
// In case of modal message, use blocking connection to wait for user to click a button
QMetaObject::invokeMethod(gui, "message",
modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(caption)),
Q_ARG(QString, QString::fromStdString(message)),
Q_ARG(unsigned int, style),
Q_ARG(bool*, &ret));
return ret;
}
void BitcoinGUI::subscribeToCoreSignals()
{
// Connect signals to client
uiInterface.ThreadSafeMessageBox.connect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3));
}
void BitcoinGUI::unsubscribeFromCoreSignals()
{
// Disconnect signals from client
uiInterface.ThreadSafeMessageBox.disconnect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3));
}

View File

@ -111,6 +111,11 @@ private:
/** Enable or disable all wallet-related actions */ /** Enable or disable all wallet-related actions */
void setWalletActionsEnabled(bool enabled); void setWalletActionsEnabled(bool enabled);
/** Connect core signals to GUI client */
void subscribeToCoreSignals();
/** Disconnect core signals from GUI client */
void unsubscribeFromCoreSignals();
signals: signals:
/** Signal raised when a URI was entered or dragged to the GUI */ /** Signal raised when a URI was entered or dragged to the GUI */
void receivedURI(const QString &uri); void receivedURI(const QString &uri);

View File

@ -6,6 +6,7 @@
#include "clientversion.h" #include "clientversion.h"
#include "util.h" #include "util.h"
#include "ui_interface.h"
#include <QApplication> #include <QApplication>
#include <QPainter> #include <QPainter>
@ -85,4 +86,37 @@ SplashScreen::SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f, bool isTest
pixPaint.end(); pixPaint.end();
this->setPixmap(newPixmap); this->setPixmap(newPixmap);
subscribeToCoreSignals();
}
SplashScreen::~SplashScreen()
{
unsubscribeFromCoreSignals();
}
void SplashScreen::slotFinish(QWidget *mainWin)
{
finish(mainWin);
}
static void InitMessage(SplashScreen *splash, const std::string &message)
{
QMetaObject::invokeMethod(splash, "showMessage",
Qt::QueuedConnection,
Q_ARG(QString, QString::fromStdString(message)),
Q_ARG(int, Qt::AlignBottom|Qt::AlignHCenter),
Q_ARG(QColor, QColor(55,55,55)));
}
void SplashScreen::subscribeToCoreSignals()
{
// Connect signals to client
uiInterface.InitMessage.connect(boost::bind(InitMessage, this, _1));
}
void SplashScreen::unsubscribeFromCoreSignals()
{
// Disconnect signals from client
uiInterface.InitMessage.disconnect(boost::bind(InitMessage, this, _1));
} }

View File

@ -15,6 +15,17 @@ class SplashScreen : public QSplashScreen
public: public:
explicit SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f, bool isTestNet); explicit SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f, bool isTestNet);
~SplashScreen();
public slots:
/** Slot to call finish() method as it's not defined as slot */
void slotFinish(QWidget *mainWin);
private:
/** Connect core signals to splash screen */
void subscribeToCoreSignals();
/** Disconnect core signals to splash screen */
void unsubscribeFromCoreSignals();
}; };
#endif // SPLASHSCREEN_H #endif // SPLASHSCREEN_H