diff options
Diffstat (limited to 'src/qt/bitcoin.cpp')
| -rw-r--r-- | src/qt/bitcoin.cpp | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp new file mode 100644 index 000000000..1083f9bfe --- /dev/null +++ b/src/qt/bitcoin.cpp @@ -0,0 +1,294 @@ +/* + * W.J. van der Laan 2011-2012 + */ + +#include <QApplication> + +#include "bitcoingui.h" +#include "clientmodel.h" +#include "walletmodel.h" +#include "optionsmodel.h" +#include "guiutil.h" +#include "guiconstants.h" +#include "init.h" +#include "util.h" +#include "ui_interface.h" +#include "paymentserver.h" +#include "splashscreen.h" + +#include <QMessageBox> +#include <QTextCodec> +#include <QLocale> +#include <QTimer> +#include <QTranslator> +#include <QLibraryInfo> + +#ifdef Q_OS_MAC +#include "macdockiconhandler.h" +#endif + +#if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED) +#define _BITCOIN_QT_PLUGINS_INCLUDED +#define __INSURE__ +#include <QtPlugin> +Q_IMPORT_PLUGIN(qcncodecs) +Q_IMPORT_PLUGIN(qjpcodecs) +Q_IMPORT_PLUGIN(qtwcodecs) +Q_IMPORT_PLUGIN(qkrcodecs) +Q_IMPORT_PLUGIN(qtaccessiblewidgets) +#endif + +// Declare meta types used for QMetaObject::invokeMethod +Q_DECLARE_METATYPE(bool*) + +// Need a global reference for the notifications to find the GUI +static BitcoinGUI *guiref; +static SplashScreen *splashref; + +static bool ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style) +{ + // Message from network thread + if(guiref) + { + 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, "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 + { + printf("%s: %s\n", caption.c_str(), message.c_str()); + fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str()); + return false; + } +} + +static bool ThreadSafeAskFee(int64 nFeeRequired) +{ + if(!guiref) + return false; + if(nFeeRequired < MIN_TX_FEE || nFeeRequired <= nTransactionFee || fDaemon) + return true; + + bool payFee = false; + + QMetaObject::invokeMethod(guiref, "askFee", GUIUtil::blockingGUIThreadConnection(), + Q_ARG(qint64, nFeeRequired), + Q_ARG(bool*, &payFee)); + + return payFee; +} + +static void InitMessage(const std::string &message) +{ + if(splashref) + { + splashref->showMessage(QString::fromStdString(message), Qt::AlignBottom|Qt::AlignHCenter, QColor(55,55,55)); + qApp->processEvents(); + } + printf("init message: %s\n", message.c_str()); +} + +/* + Translate string to current locale using Qt. + */ +static std::string Translate(const char* psz) +{ + return QCoreApplication::translate("bitcoin-core", psz).toStdString(); +} + +/* Handle runaway exceptions. Shows a message box with the problem and quits the program. + */ +static void handleRunawayException(std::exception *e) +{ + PrintExceptionContinue(e, "Runaway exception"); + QMessageBox::critical(0, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. Bitcoin can no longer continue safely and will quit.") + QString("\n\n") + QString::fromStdString(strMiscWarning)); + exit(1); +} + +#ifndef BITCOIN_QT_TEST +int main(int argc, char *argv[]) +{ + // Command-line options take precedence: + ParseParameters(argc, argv); + + // Internal string conversion is all UTF-8 + QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8")); + QTextCodec::setCodecForCStrings(QTextCodec::codecForTr()); + + Q_INIT_RESOURCE(bitcoin); + QApplication app(argc, argv); + + // Register meta types used for QMetaObject::invokeMethod + qRegisterMetaType< bool* >(); + + // Do this early as we don't want to bother initializing if we are just calling IPC + // ... but do it after creating app, so QCoreApplication::arguments is initialized: + if (PaymentServer::ipcSendCommandLine()) + exit(0); + PaymentServer* paymentServer = new PaymentServer(&app); + + // Install global event filter that makes sure that long tooltips can be word-wrapped + app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app)); + + // ... then bitcoin.conf: + if (!boost::filesystem::is_directory(GetDataDir(false))) + { + // This message can not be translated, as translation is not initialized yet + // (which not yet possible because lang=XX can be overridden in bitcoin.conf in the data directory) + QMessageBox::critical(0, "Bitcoin", + QString("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(mapArgs["-datadir"]))); + return 1; + } + ReadConfigFile(mapArgs, mapMultiArgs); + + // Application identification (must be set before OptionsModel is initialized, + // as it is used to locate QSettings) + QApplication::setOrganizationName("Bitcoin"); + QApplication::setOrganizationDomain("bitcoin.org"); + if(GetBoolArg("-testnet")) // Separate UI settings for testnet + QApplication::setApplicationName("Bitcoin-Qt-testnet"); + else + QApplication::setApplicationName("Bitcoin-Qt"); + + // ... then GUI settings: + OptionsModel optionsModel; + + // Get desired locale (e.g. "de_DE") from command line or use system locale + QString lang_territory = QString::fromStdString(GetArg("-lang", QLocale::system().name().toStdString())); + QString lang = lang_territory; + // Convert to "de" only by truncating "_DE" + lang.truncate(lang_territory.lastIndexOf('_')); + + QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator; + // 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))) + app.installTranslator(&qtTranslatorBase); + + // Load e.g. qt_de_DE.qm + if (qtTranslator.load("qt_" + lang_territory, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) + app.installTranslator(&qtTranslator); + + // Load e.g. bitcoin_de.qm (shortcut "de" needs to be defined in bitcoin.qrc) + if (translatorBase.load(lang, ":/translations/")) + app.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/")) + app.installTranslator(&translator); + + // Subscribe to global signals from core + uiInterface.ThreadSafeMessageBox.connect(ThreadSafeMessageBox); + uiInterface.ThreadSafeAskFee.connect(ThreadSafeAskFee); + uiInterface.InitMessage.connect(InitMessage); + uiInterface.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("--help")) + { + GUIUtil::HelpMessageBox help; + help.showOrPrint(); + return 1; + } + +#ifdef Q_OS_MAC + // on mac, also change the icon now because it would look strange to have a testnet splash (green) and a std app icon (orange) + if(GetBoolArg("-testnet")) { + MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet")); + } +#endif + + SplashScreen splash(QPixmap(), 0); + if (GetBoolArg("-splash", true) && !GetBoolArg("-min")) + { + splash.show(); + splash.setAutoFillBackground(true); + splashref = &splash; + } + + app.processEvents(); + app.setQuitOnLastWindowClosed(false); + + try + { + // Regenerate startup link, to fix links to old versions + if (GUIUtil::GetStartOnSystemStartup()) + GUIUtil::SetStartOnSystemStartup(true); + + boost::thread_group threadGroup; + + BitcoinGUI window; + guiref = &window; + + QTimer* pollShutdownTimer = new QTimer(guiref); + QObject::connect(pollShutdownTimer, SIGNAL(timeout()), guiref, SLOT(detectShutdown())); + pollShutdownTimer->start(200); + + if(AppInit2(threadGroup)) + { + { + // Put this in a block, so that the Model objects are cleaned up before + // calling Shutdown(). + + optionsModel.Upgrade(); // Must be done after AppInit2 + + if (splashref) + splash.finish(&window); + + ClientModel clientModel(&optionsModel); + WalletModel walletModel(pwalletMain, &optionsModel); + + window.setClientModel(&clientModel); + window.addWallet("~Default", &walletModel); + window.setCurrentWallet("~Default"); + + // If -min option passed, start window minimized. + if(GetBoolArg("-min")) + { + window.showMinimized(); + } + else + { + window.show(); + } + + // Now that initialization/startup is done, process any command-line + // bitcoin: URIs + QObject::connect(paymentServer, SIGNAL(receivedURI(QString)), &window, SLOT(handleURI(QString))); + QTimer::singleShot(100, paymentServer, SLOT(uiReady())); + + app.exec(); + + window.hide(); + window.setClientModel(0); + window.removeAllWallets(); + guiref = 0; + } + // Shutdown the core and its threads, but don't exit Bitcoin-Qt here + threadGroup.interrupt_all(); + threadGroup.join_all(); + Shutdown(); + } + else + { + return 1; + } + } catch (std::exception& e) { + handleRunawayException(&e); + } catch (...) { + handleRunawayException(NULL); + } + return 0; +} +#endif // BITCOIN_QT_TEST |