175096b2bd
Move some files back to the server "library". Merge the 'console' lib with server, as it doesn't really make sense with just one file and nobody exclusively linking to it. The server "libary" is not really a library, its the place we put all the files shared by hub-qt hub-cli and hub. We no longer depend on these files from other places (mostly due to moving to the new logging framework) and as such we can move the files back.
742 lines
24 KiB
C++
742 lines
24 KiB
C++
/*
|
|
* This file is part of the Flowee project
|
|
* Copyright (C) 2011-2015 The Bitcoin Core developers
|
|
* Copyright (C) 2018-2019 Tom Zander <tomz@freedommail.ch>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#if defined(HAVE_CONFIG_H)
|
|
#include "config/flowee-config.h"
|
|
#endif
|
|
|
|
#include "bitcoingui.h"
|
|
|
|
#include "chainparams.h"
|
|
#include <server/util.h>
|
|
#include "clientmodel.h"
|
|
#include "guiconstants.h"
|
|
#include "guiutil.h"
|
|
#include "intro.h"
|
|
#include "networkstyle.h"
|
|
#include "optionsmodel.h"
|
|
#include "platformstyle.h"
|
|
#include "splashscreen.h"
|
|
#include "utilitydialog.h"
|
|
#include "winshutdownmonitor.h"
|
|
|
|
#ifdef ENABLE_WALLET
|
|
#include "paymentserver.h"
|
|
#include "walletmodel.h"
|
|
#endif
|
|
|
|
#include "init.h"
|
|
#include "rpcserver.h"
|
|
#include "scheduler.h"
|
|
#include "UiInterface.h"
|
|
#include <serverutil.h>
|
|
#include <SettingsDefaults.h>
|
|
|
|
#ifdef ENABLE_WALLET
|
|
#include "wallet/wallet.h"
|
|
#endif
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <boost/filesystem/operations.hpp>
|
|
#include <boost/thread.hpp>
|
|
|
|
#include <QApplication>
|
|
#include <QDebug>
|
|
#include <QLibraryInfo>
|
|
#include <QLocale>
|
|
#include <QMessageBox>
|
|
#include <QSettings>
|
|
#include <QThread>
|
|
#include <QTimer>
|
|
#include <QTranslator>
|
|
#include <QSslConfiguration>
|
|
#include <APIServer.h>
|
|
#include <Application.h>
|
|
#include <AddressMonitorService.h>
|
|
#include <BlockNotificationService.h>
|
|
|
|
#if defined(QT_STATICPLUGIN)
|
|
#include <QtPlugin>
|
|
#if QT_VERSION < 0x050000
|
|
Q_IMPORT_PLUGIN(qcncodecs)
|
|
Q_IMPORT_PLUGIN(qjpcodecs)
|
|
Q_IMPORT_PLUGIN(qtwcodecs)
|
|
Q_IMPORT_PLUGIN(qkrcodecs)
|
|
Q_IMPORT_PLUGIN(qtaccessiblewidgets)
|
|
#else
|
|
#if QT_VERSION < 0x050400
|
|
Q_IMPORT_PLUGIN(AccessibleFactory)
|
|
#endif
|
|
#if defined(QT_QPA_PLATFORM_XCB)
|
|
Q_IMPORT_PLUGIN(QXcbIntegrationPlugin);
|
|
#elif defined(QT_QPA_PLATFORM_WINDOWS)
|
|
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
|
|
#elif defined(QT_QPA_PLATFORM_COCOA)
|
|
Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin);
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#if QT_VERSION < 0x050000
|
|
#include <QTextCodec>
|
|
#endif
|
|
|
|
// Declare meta types used for QMetaObject::invokeMethod
|
|
Q_DECLARE_METATYPE(bool*)
|
|
Q_DECLARE_METATYPE(CAmount)
|
|
|
|
static void InitMessage(const std::string &message)
|
|
{
|
|
logCritical(Log::Bitcoin) << "init message:" << message;
|
|
}
|
|
|
|
/** Signals for translation. */
|
|
class CTranslationInterface
|
|
{
|
|
public:
|
|
/** Translate a message to the native language of the user. */
|
|
boost::signals2::signal<std::string (const char* psz)> Translate;
|
|
};
|
|
CTranslationInterface translationInterface;
|
|
|
|
|
|
/*
|
|
Translate string to current locale using Qt.
|
|
*/
|
|
static std::string Translate(const char* psz)
|
|
{
|
|
return QCoreApplication::translate("Flowee the Hub", psz).toStdString();
|
|
}
|
|
|
|
static QString GetLangTerritory()
|
|
{
|
|
QSettings settings;
|
|
// Get desired locale (e.g. "de_DE")
|
|
// 1) System default language
|
|
QString lang_territory = QLocale::system().name();
|
|
// 2) Language from QSettings
|
|
QString lang_territory_qsettings = settings.value("language", "").toString();
|
|
if(!lang_territory_qsettings.isEmpty())
|
|
lang_territory = lang_territory_qsettings;
|
|
// 3) -lang command line argument
|
|
lang_territory = QString::fromStdString(GetArg("-lang", lang_territory.toStdString()));
|
|
return lang_territory;
|
|
}
|
|
|
|
/** Set up translations */
|
|
static void initTranslations(QTranslator &qtTranslatorBase, QTranslator &qtTranslator, QTranslator &translatorBase, QTranslator &translator)
|
|
{
|
|
// Remove old translators
|
|
QApplication::removeTranslator(&qtTranslatorBase);
|
|
QApplication::removeTranslator(&qtTranslator);
|
|
QApplication::removeTranslator(&translatorBase);
|
|
QApplication::removeTranslator(&translator);
|
|
|
|
// Get desired locale (e.g. "de_DE")
|
|
// 1) System default language
|
|
QString lang_territory = GetLangTerritory();
|
|
|
|
// Convert to "de" only by truncating "_DE"
|
|
QString lang = lang_territory;
|
|
lang.truncate(lang_territory.lastIndexOf('_'));
|
|
|
|
// Load language files for configured locale:
|
|
// - First load the translator for the base language, without territory
|
|
// - Then load the more specific locale translator
|
|
|
|
// Load e.g. qt_de.qm
|
|
if (qtTranslatorBase.load("qt_" + lang, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
|
|
QApplication::installTranslator(&qtTranslatorBase);
|
|
|
|
// Load e.g. qt_de_DE.qm
|
|
if (qtTranslator.load("qt_" + lang_territory, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
|
|
QApplication::installTranslator(&qtTranslator);
|
|
|
|
// Load e.g. bitcoin_de.qm (shortcut "de" needs to be defined in bitcoin.qrc)
|
|
if (translatorBase.load(lang, ":/translations/"))
|
|
QApplication::installTranslator(&translatorBase);
|
|
|
|
// Load e.g. bitcoin_de_DE.qm (shortcut "de_DE" needs to be defined in bitcoin.qrc)
|
|
if (translator.load(lang_territory, ":/translations/"))
|
|
QApplication::installTranslator(&translator);
|
|
}
|
|
|
|
/* qDebug() message handler --> hub.log */
|
|
#if QT_VERSION < 0x050000
|
|
void DebugMessageHandler(QtMsgType type, const char *msg)
|
|
{
|
|
const char *category = (type == QtDebugMsg) ? "qt" : NULL;
|
|
LogPrint(category, "GUI: %s\n", msg);
|
|
}
|
|
#else
|
|
void DebugMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &msg)
|
|
{
|
|
Log::Item(context.file, context.line, context.function, Log::QtGui, type)
|
|
<< msg.toUtf8().constData();
|
|
}
|
|
#endif
|
|
|
|
/** Class encapsulating the hub startup and shutdown.
|
|
* Allows running startup and shutdown in a different thread from the UI thread.
|
|
*/
|
|
class BitcoinCore: public QObject
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
BitcoinCore();
|
|
|
|
public Q_SLOTS:
|
|
void initialize();
|
|
void shutdown();
|
|
|
|
Q_SIGNALS:
|
|
void initializeResult(int retval);
|
|
void shutdownResult(int retval);
|
|
void runawayException(const QString &message);
|
|
|
|
private:
|
|
boost::thread_group threadGroup;
|
|
CScheduler scheduler;
|
|
std::unique_ptr<Api::Server> apiServer;
|
|
std::unique_ptr<AddressMonitorService> addressMonitorService;
|
|
std::unique_ptr<BlockNotificationService> blockNotificationService;
|
|
|
|
/// Pass fatal exception message to UI thread
|
|
void handleRunawayException(const std::exception *e);
|
|
};
|
|
|
|
/** Main Bitcoin application object */
|
|
class BitcoinApplication: public QApplication
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
explicit BitcoinApplication(int &argc, char **argv);
|
|
~BitcoinApplication();
|
|
|
|
#ifdef ENABLE_WALLET
|
|
/// Create payment server
|
|
void createPaymentServer();
|
|
#endif
|
|
/// parameter interaction/setup based on rules
|
|
void parameterSetup();
|
|
/// Create platform style
|
|
void createPlatformStyle();
|
|
/// Create options model
|
|
void createOptionsModel(bool resetSettings);
|
|
/// Create main window
|
|
void createWindow(const NetworkStyle &networkStyle);
|
|
/// Create splash screen
|
|
void createSplashScreen(const NetworkStyle &networkStyle);
|
|
|
|
/// Request core initialization
|
|
void requestInitialize();
|
|
/// Request core shutdown
|
|
void requestShutdown();
|
|
|
|
/// Get process return value
|
|
int getReturnValue() { return returnValue; }
|
|
|
|
/// Get window identifier of QMainWindow (BitcoinGUI)
|
|
WId getMainWinId() const;
|
|
|
|
public Q_SLOTS:
|
|
void initializeResult(int retval);
|
|
void shutdownResult(int retval);
|
|
/// Handle runaway exceptions. Shows a message box with the problem and quits the program.
|
|
void handleRunawayException(const QString &message);
|
|
|
|
Q_SIGNALS:
|
|
void requestedInitialize();
|
|
void requestedShutdown();
|
|
void stopThread();
|
|
void splashFinished(QWidget *window);
|
|
|
|
private:
|
|
QThread *coreThread;
|
|
OptionsModel *optionsModel;
|
|
ClientModel *clientModel;
|
|
BitcoinGUI *window;
|
|
QTimer *pollShutdownTimer;
|
|
#ifdef ENABLE_WALLET
|
|
PaymentServer* paymentServer;
|
|
WalletModel *walletModel;
|
|
#endif
|
|
int returnValue;
|
|
const PlatformStyle *platformStyle;
|
|
|
|
void startThread();
|
|
};
|
|
|
|
#include "bitcoin.moc"
|
|
|
|
BitcoinCore::BitcoinCore()
|
|
{
|
|
}
|
|
|
|
void BitcoinCore::handleRunawayException(const std::exception *e)
|
|
{
|
|
PrintExceptionContinue(e, "Runaway exception");
|
|
Q_EMIT runawayException(QString::fromStdString(strMiscWarning));
|
|
}
|
|
|
|
void BitcoinCore::initialize()
|
|
{
|
|
try
|
|
{
|
|
qDebug() << __func__ << ": Running AppInit2 in thread";
|
|
int rv = AppInit2(threadGroup, scheduler);
|
|
Q_EMIT initializeResult(rv);
|
|
|
|
if (GetBoolArg("-api", true)) {
|
|
apiServer.reset(new Api::Server(Application::instance()->ioService()));
|
|
addressMonitorService.reset(new AddressMonitorService());
|
|
blockNotificationService.reset(new BlockNotificationService());
|
|
extern CTxMemPool mempool;
|
|
addressMonitorService->setMempool(&mempool);
|
|
apiServer->addService(addressMonitorService.get());
|
|
apiServer->addService(blockNotificationService.get());
|
|
}
|
|
} catch (const std::exception& e) {
|
|
handleRunawayException(&e);
|
|
} catch (...) {
|
|
handleRunawayException(NULL);
|
|
}
|
|
}
|
|
|
|
void BitcoinCore::shutdown()
|
|
{
|
|
try
|
|
{
|
|
qDebug() << __func__ << ": Running Shutdown in thread";
|
|
blockNotificationService.reset();
|
|
addressMonitorService.reset();
|
|
apiServer.reset();
|
|
Interrupt(threadGroup);
|
|
threadGroup.join_all();
|
|
Shutdown();
|
|
qDebug() << __func__ << ": Shutdown finished";
|
|
Q_EMIT shutdownResult(1);
|
|
} catch (const std::exception& e) {
|
|
handleRunawayException(&e);
|
|
} catch (...) {
|
|
handleRunawayException(NULL);
|
|
}
|
|
}
|
|
|
|
BitcoinApplication::BitcoinApplication(int &argc, char **argv):
|
|
QApplication(argc, argv),
|
|
coreThread(0),
|
|
optionsModel(0),
|
|
clientModel(0),
|
|
window(0),
|
|
pollShutdownTimer(0),
|
|
#ifdef ENABLE_WALLET
|
|
paymentServer(0),
|
|
walletModel(0),
|
|
#endif
|
|
returnValue(0),
|
|
platformStyle(0)
|
|
{
|
|
setQuitOnLastWindowClosed(false);
|
|
}
|
|
|
|
BitcoinApplication::~BitcoinApplication()
|
|
{
|
|
if(coreThread)
|
|
{
|
|
qDebug() << __func__ << ": Stopping thread";
|
|
Q_EMIT stopThread();
|
|
coreThread->wait();
|
|
qDebug() << __func__ << ": Stopped thread";
|
|
}
|
|
|
|
delete window;
|
|
window = 0;
|
|
#ifdef ENABLE_WALLET
|
|
delete paymentServer;
|
|
paymentServer = 0;
|
|
#endif
|
|
delete optionsModel;
|
|
optionsModel = 0;
|
|
delete platformStyle;
|
|
platformStyle = 0;
|
|
}
|
|
|
|
#ifdef ENABLE_WALLET
|
|
void BitcoinApplication::createPaymentServer()
|
|
{
|
|
paymentServer = new PaymentServer(this);
|
|
}
|
|
#endif
|
|
|
|
void BitcoinApplication::createPlatformStyle()
|
|
{
|
|
std::string platformName;
|
|
platformName = GetArg("-uiplatform", Settings::DefaultUIPlatform);
|
|
platformStyle = PlatformStyle::instantiate(QString::fromStdString(platformName));
|
|
if (!platformStyle) // Fall back to "other" if specified name not found
|
|
platformStyle = PlatformStyle::instantiate("other");
|
|
assert(platformStyle);
|
|
}
|
|
|
|
void BitcoinApplication::createOptionsModel(bool resetSettings)
|
|
{
|
|
optionsModel = new OptionsModel(NULL, resetSettings);
|
|
}
|
|
|
|
void BitcoinApplication::createWindow(const NetworkStyle &networkStyle)
|
|
{
|
|
window = new BitcoinGUI(platformStyle, networkStyle);
|
|
|
|
pollShutdownTimer = new QTimer(window);
|
|
connect(pollShutdownTimer, SIGNAL(timeout()), window, SLOT(detectShutdown()));
|
|
pollShutdownTimer->start(200);
|
|
}
|
|
|
|
void BitcoinApplication::createSplashScreen(const NetworkStyle &networkStyle)
|
|
{
|
|
SplashScreen *splash = new SplashScreen(networkStyle);
|
|
// We don't hold a direct pointer to the splash screen after creation, so use
|
|
// Qt::WA_DeleteOnClose to make sure that the window will be deleted eventually.
|
|
splash->setAttribute(Qt::WA_DeleteOnClose);
|
|
splash->show();
|
|
connect(this, SIGNAL(splashFinished(QWidget*)), splash, SLOT(slotFinish(QWidget*)));
|
|
}
|
|
|
|
void BitcoinApplication::startThread()
|
|
{
|
|
if(coreThread)
|
|
return;
|
|
coreThread = new QThread(this);
|
|
BitcoinCore *executor = new BitcoinCore();
|
|
executor->moveToThread(coreThread);
|
|
|
|
/* communication to and from thread */
|
|
connect(executor, SIGNAL(initializeResult(int)), this, SLOT(initializeResult(int)));
|
|
connect(executor, SIGNAL(shutdownResult(int)), this, SLOT(shutdownResult(int)));
|
|
connect(executor, SIGNAL(runawayException(QString)), this, SLOT(handleRunawayException(QString)));
|
|
connect(this, SIGNAL(requestedInitialize()), executor, SLOT(initialize()));
|
|
connect(this, SIGNAL(requestedShutdown()), executor, SLOT(shutdown()));
|
|
/* make sure executor object is deleted in its own thread */
|
|
connect(this, SIGNAL(stopThread()), executor, SLOT(deleteLater()));
|
|
connect(this, SIGNAL(stopThread()), coreThread, SLOT(quit()));
|
|
|
|
coreThread->start();
|
|
}
|
|
|
|
void BitcoinApplication::parameterSetup()
|
|
{
|
|
InitLogging();
|
|
InitParameterInteraction();
|
|
}
|
|
|
|
void BitcoinApplication::requestInitialize()
|
|
{
|
|
qDebug() << __func__ << ": Requesting initialize";
|
|
startThread();
|
|
Q_EMIT requestedInitialize();
|
|
}
|
|
|
|
void BitcoinApplication::requestShutdown()
|
|
{
|
|
qDebug() << __func__ << ": Requesting shutdown";
|
|
StartShutdown(); // shut down bitcoind processes (for instance reindex)
|
|
startThread();
|
|
window->hide();
|
|
window->setClientModel(0);
|
|
pollShutdownTimer->stop();
|
|
|
|
#ifdef ENABLE_WALLET
|
|
window->removeAllWallets();
|
|
delete walletModel;
|
|
walletModel = 0;
|
|
#endif
|
|
delete clientModel;
|
|
clientModel = 0;
|
|
|
|
// Show a simple window indicating shutdown status
|
|
ShutdownWindow::showShutdownWindow(window);
|
|
|
|
// Request shutdown from core thread
|
|
Q_EMIT requestedShutdown();
|
|
}
|
|
|
|
void BitcoinApplication::initializeResult(int retval)
|
|
{
|
|
qDebug() << __func__ << ": Initialization result: " << retval;
|
|
// Set exit result: 0 if successful, 1 if failure
|
|
returnValue = retval ? 0 : 1;
|
|
if(retval)
|
|
{
|
|
// Log this only after AppInit2 finishes, as then logging setup is guaranteed complete
|
|
qWarning() << "Platform customization:" << platformStyle->getName();
|
|
#ifdef ENABLE_WALLET
|
|
PaymentServer::LoadRootCAs();
|
|
paymentServer->setOptionsModel(optionsModel);
|
|
#endif
|
|
|
|
clientModel = new ClientModel(optionsModel);
|
|
window->setClientModel(clientModel);
|
|
|
|
#ifdef ENABLE_WALLET
|
|
if(pwalletMain)
|
|
{
|
|
walletModel = new WalletModel(platformStyle, pwalletMain, optionsModel);
|
|
|
|
window->addWallet(BitcoinGUI::DEFAULT_WALLET, walletModel);
|
|
window->setCurrentWallet(BitcoinGUI::DEFAULT_WALLET);
|
|
|
|
connect(walletModel, SIGNAL(coinsSent(CWallet*,SendCoinsRecipient,QByteArray)),
|
|
paymentServer, SLOT(fetchPaymentACK(CWallet*,const SendCoinsRecipient&,QByteArray)));
|
|
}
|
|
#endif
|
|
|
|
// If -min option passed, start window minimized.
|
|
if(GetBoolArg("-min", false))
|
|
{
|
|
window->showMinimized();
|
|
}
|
|
else
|
|
{
|
|
window->show();
|
|
}
|
|
Q_EMIT splashFinished(window);
|
|
|
|
#ifdef ENABLE_WALLET
|
|
// Now that initialization/startup is done, process any command-line
|
|
// bitcoin: URIs or payment requests:
|
|
connect(paymentServer, SIGNAL(receivedPaymentRequest(SendCoinsRecipient)),
|
|
window, SLOT(handlePaymentRequest(SendCoinsRecipient)));
|
|
connect(window, SIGNAL(receivedURI(QString)),
|
|
paymentServer, SLOT(handleURIOrFile(QString)));
|
|
connect(paymentServer, SIGNAL(message(QString,QString,unsigned int)),
|
|
window, SLOT(message(QString,QString,unsigned int)));
|
|
QTimer::singleShot(100, paymentServer, SLOT(uiReady()));
|
|
#endif
|
|
} else {
|
|
quit(); // Exit main loop
|
|
}
|
|
}
|
|
|
|
void BitcoinApplication::shutdownResult(int retval)
|
|
{
|
|
qDebug() << __func__ << ": Shutdown result: " << retval;
|
|
quit(); // Exit main loop after shutdown finished
|
|
}
|
|
|
|
void BitcoinApplication::handleRunawayException(const QString &message)
|
|
{
|
|
QMessageBox::critical(0, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. Bitcoin can no longer continue safely and will quit.") + QString("\n\n") + message);
|
|
::exit(1);
|
|
}
|
|
|
|
WId BitcoinApplication::getMainWinId() const
|
|
{
|
|
if (!window)
|
|
return 0;
|
|
|
|
return window->winId();
|
|
}
|
|
|
|
static bool SelectChain()
|
|
{
|
|
// Check for -testnet or -regtest parameter (Params() calls are only valid after this)
|
|
try {
|
|
SelectParams(ChainNameFromCommandLine());
|
|
return true;
|
|
} catch(std::exception &e) {
|
|
QMessageBox::critical(0, QObject::tr("Flowee"), QObject::tr("Error: %1").arg(e.what()));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#ifndef BITCOIN_QT_TEST
|
|
int main(int argc, char *argv[])
|
|
{
|
|
SetupEnvironment();
|
|
|
|
// Do not refer to data directory yet, this can be overridden by Intro::pickDataDirectory
|
|
|
|
/// 1. Basic Qt initialization (not dependent on parameters or configuration)
|
|
#if QT_VERSION < 0x050000
|
|
// Internal string conversion is all UTF-8
|
|
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
|
|
QTextCodec::setCodecForCStrings(QTextCodec::codecForTr());
|
|
#endif
|
|
|
|
BitcoinApplication app(argc, argv);
|
|
#if QT_VERSION > 0x050100
|
|
// Generate high-dpi pixmaps
|
|
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
|
#endif
|
|
#ifdef Q_OS_MAC
|
|
QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
|
|
#endif
|
|
|
|
// Register meta types used for QMetaObject::invokeMethod
|
|
qRegisterMetaType< bool* >();
|
|
// Need to pass name here as CAmount is a typedef (see http://qt-project.org/doc/qt-5/qmetatype.html#qRegisterMetaType)
|
|
// IMPORTANT if it is no longer a typedef use the normal variant above
|
|
qRegisterMetaType< CAmount >("CAmount");
|
|
|
|
/// 2. Parse command-line options. These take precedence over anything else.
|
|
// Command-line options take precedence:
|
|
try {
|
|
ParseParameters(argc, argv, Settings::HubQt());
|
|
} catch (const std::exception& e) {
|
|
QMessageBox::critical(0, QObject::tr("Flowee"),
|
|
QObject::tr("Error: Cannot parse program options: %1.").arg(e.what()));
|
|
return false;
|
|
}
|
|
|
|
/// 3. Application identification
|
|
// must be set before OptionsModel is initialized or translations are loaded,
|
|
// as it is used to locate QSettings
|
|
QApplication::setOrganizationName(QAPP_ORG_NAME);
|
|
QApplication::setOrganizationDomain(QAPP_ORG_DOMAIN);
|
|
QApplication::setApplicationName(QAPP_APP_NAME_DEFAULT);
|
|
GUIUtil::SubstituteFonts(GetLangTerritory());
|
|
|
|
/// 4. Initialization of translations, so that intro dialog is in user's language
|
|
// Now that QSettings are accessible, initialize translations
|
|
QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator;
|
|
initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator);
|
|
translationInterface.Translate.connect(Translate);
|
|
|
|
// Show help message immediately after parsing command-line options (for "-lang") and setting locale,
|
|
// but before showing splash screen.
|
|
if (mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help") || mapArgs.count("-version"))
|
|
{
|
|
HelpMessageDialog help(NULL, mapArgs.count("-version"));
|
|
help.showOrPrint();
|
|
return 1;
|
|
}
|
|
|
|
/// 5. Now that settings and translations are available, ask user for data directory
|
|
// User language is set up: pick a data directory
|
|
Intro::pickDataDirectory();
|
|
|
|
// 6. Determine network (and switch to network specific options)
|
|
// - Do not call Params() before this step
|
|
// - QSettings() will use the new application name after this, resulting in network-specific settings
|
|
// - Needs to be done before createOptionsModel
|
|
// - Do not call GetDataDir(true) before this step finishes
|
|
|
|
// 7. Determine availability of data directory and parse flowee.conf
|
|
std::string dd = GetArg("-datadir", "");
|
|
if (!dd.empty()) {
|
|
auto path = boost::filesystem::system_complete(dd);
|
|
if (!boost::filesystem::is_directory(path)) {
|
|
QMessageBox::critical(0, QObject::tr("Flowee"),
|
|
QObject::tr("Error: Specified data directory \"%1\" does not exist.")
|
|
.arg(QString::fromStdString(dd)));
|
|
return 1;
|
|
}
|
|
}
|
|
boost::filesystem::path pathConfigFile = GetArg("-conf", "");
|
|
const bool confPathSet = pathConfigFile.is_complete();
|
|
|
|
if (!confPathSet) // first select chain, so we read the right conf file.
|
|
SelectChain();
|
|
try {
|
|
ReadConfigFile(mapArgs, mapMultiArgs);
|
|
} catch (const std::exception& e) {
|
|
QMessageBox::critical(0, QObject::tr("Flowee"),
|
|
QObject::tr("Error: Cannot parse configuration file: %1. Only use key=value syntax.").arg(e.what()));
|
|
return false;
|
|
}
|
|
if (confPathSet) // after raeding the user-indicated conf file, select chain (including conf file opts)
|
|
SelectChain();
|
|
|
|
// UI per-platform customization
|
|
app.createPlatformStyle();
|
|
|
|
#ifdef ENABLE_WALLET
|
|
// Parse URIs on command line
|
|
PaymentServer::ipcParseCommandLine(argc, argv);
|
|
#endif
|
|
|
|
NetworkStyle networkStyle(QString::fromStdString(Params().NetworkIDString()));
|
|
// Allow for separate UI settings for testnets
|
|
QApplication::setApplicationName(networkStyle.getAppName());
|
|
// Re-initialize translations after changing application name (language in network-specific settings can be different)
|
|
initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator);
|
|
|
|
#ifdef ENABLE_WALLET
|
|
/// 8. URI IPC sending
|
|
// - Do this early as we don't want to bother initializing if we are just calling IPC
|
|
// - Do this *after* setting up the data directory, as the data directory hash is used in the name
|
|
// of the server.
|
|
// - Do this after creating app and setting up translations, so errors are
|
|
// translated properly.
|
|
if (PaymentServer::ipcSendCommandLine())
|
|
exit(0);
|
|
|
|
// Start up the payment server early, too, so impatient users that click on
|
|
// bitcoin: links repeatedly have their payment requests routed to this process:
|
|
app.createPaymentServer();
|
|
#endif
|
|
|
|
/// 9. Main GUI initialization
|
|
// Install global event filter that makes sure that long tooltips can be word-wrapped
|
|
app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app));
|
|
#if QT_VERSION < 0x050000
|
|
// Install qDebug() message handler to route to hub.log
|
|
qInstallMsgHandler(DebugMessageHandler);
|
|
#else
|
|
#if defined(Q_OS_WIN)
|
|
// Install global event filter for processing Windows session related Windows messages (WM_QUERYENDSESSION and WM_ENDSESSION)
|
|
qApp->installNativeEventFilter(new WinShutdownMonitor());
|
|
#endif
|
|
// Install qDebug() message handler to route to hub.log
|
|
qInstallMessageHandler(DebugMessageHandler);
|
|
#endif
|
|
// Allow parameter interaction before we create the options model
|
|
app.parameterSetup();
|
|
// Load GUI settings from QSettings
|
|
app.createOptionsModel(GetBoolArg("-resetguisettings", false));
|
|
|
|
// Subscribe to global signals from core
|
|
uiInterface.InitMessage.connect(InitMessage);
|
|
|
|
if (GetBoolArg("-splash", Settings::DefaultSplashscreen) && !GetBoolArg("-min", false))
|
|
app.createSplashScreen(networkStyle);
|
|
|
|
try
|
|
{
|
|
app.createWindow(networkStyle);
|
|
app.requestInitialize();
|
|
#if defined(Q_OS_WIN) && QT_VERSION >= 0x050000
|
|
WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("Flowee the Hub didn't yet exit safely..."), (HWND)app.getMainWinId());
|
|
#endif
|
|
app.exec();
|
|
app.requestShutdown();
|
|
app.exec();
|
|
} catch (const std::exception& e) {
|
|
PrintExceptionContinue(&e, "Runaway exception");
|
|
app.handleRunawayException(QString::fromStdString(strMiscWarning));
|
|
} catch (...) {
|
|
PrintExceptionContinue(NULL, "Runaway exception");
|
|
app.handleRunawayException(QString::fromStdString(strMiscWarning));
|
|
}
|
|
return app.getReturnValue();
|
|
}
|
|
#endif // BITCOIN_QT_TEST
|