]>
Commit | Line | Data |
---|---|---|
aaa1c3c4 | 1 | /* |
246c20e8 | 2 | * W.J. van der Laan 2011-2012 |
aaa1c3c4 | 3 | */ |
32af5266 PK |
4 | |
5 | #include <QApplication> | |
6 | ||
0fd01780 | 7 | #include "bitcoingui.h" |
18cab09a | 8 | #include "clientmodel.h" |
ef079e18 | 9 | #include "walletmodel.h" |
ee014e5b | 10 | #include "optionsmodel.h" |
7e7bcce2 | 11 | #include "guiutil.h" |
3793fa09 | 12 | #include "guiconstants.h" |
18cab09a | 13 | #include "init.h" |
c8c2fbe0 | 14 | #include "util.h" |
6b6aaa16 | 15 | #include "ui_interface.h" |
8269a095 | 16 | #include "paymentserver.h" |
aaa1c3c4 | 17 | |
467c31ea | 18 | #include <QMessageBox> |
3f0816e3 | 19 | #include <QTextCodec> |
daaee738 | 20 | #include <QLocale> |
8269a095 | 21 | #include <QTimer> |
daaee738 | 22 | #include <QTranslator> |
10d680cf | 23 | #include <QSplashScreen> |
527137e3 | 24 | #include <QLibraryInfo> |
467c31ea | 25 | |
55f69a47 WL |
26 | #if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED) |
27 | #define _BITCOIN_QT_PLUGINS_INCLUDED | |
28 | #define __INSURE__ | |
29 | #include <QtPlugin> | |
30 | Q_IMPORT_PLUGIN(qcncodecs) | |
31 | Q_IMPORT_PLUGIN(qjpcodecs) | |
32 | Q_IMPORT_PLUGIN(qtwcodecs) | |
33 | Q_IMPORT_PLUGIN(qkrcodecs) | |
34 | Q_IMPORT_PLUGIN(qtaccessiblewidgets) | |
35 | #endif | |
36 | ||
00b8acdf | 37 | // Need a global reference for the notifications to find the GUI |
98e61758 WL |
38 | static BitcoinGUI *guiref; |
39 | static QSplashScreen *splashref; | |
467c31ea | 40 | |
f7f3a96b | 41 | static bool ThreadSafeMessageBox(const std::string& message, const std::string& caption, unsigned int style) |
467c31ea WL |
42 | { |
43 | // Message from network thread | |
44 | if(guiref) | |
45 | { | |
239c11d0 | 46 | bool modal = (style & CClientUIInterface::MODAL); |
f7f3a96b | 47 | bool ret = false; |
5350ea41 PK |
48 | // In case of modal message, use blocking connection to wait for user to click a button |
49 | QMetaObject::invokeMethod(guiref, "message", | |
7cfbe1fe | 50 | modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection, |
467c31ea | 51 | Q_ARG(QString, QString::fromStdString(caption)), |
7cfbe1fe | 52 | Q_ARG(QString, QString::fromStdString(message)), |
f7f3a96b PW |
53 | Q_ARG(unsigned int, style), |
54 | Q_ARG(bool*, &ret)); | |
55 | return ret; | |
467c31ea WL |
56 | } |
57 | else | |
58 | { | |
59 | printf("%s: %s\n", caption.c_str(), message.c_str()); | |
60 | fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str()); | |
f7f3a96b | 61 | return false; |
467c31ea | 62 | } |
467c31ea WL |
63 | } |
64 | ||
15d8ff20 | 65 | static bool ThreadSafeAskFee(int64 nFeeRequired) |
467c31ea | 66 | { |
b7726d92 WL |
67 | if(!guiref) |
68 | return false; | |
69 | if(nFeeRequired < MIN_TX_FEE || nFeeRequired <= nTransactionFee || fDaemon) | |
70 | return true; | |
15d8ff20 | 71 | |
b7726d92 WL |
72 | bool payFee = false; |
73 | ||
7e7bcce2 | 74 | QMetaObject::invokeMethod(guiref, "askFee", GUIUtil::blockingGUIThreadConnection(), |
b7726d92 WL |
75 | Q_ARG(qint64, nFeeRequired), |
76 | Q_ARG(bool*, &payFee)); | |
77 | ||
78 | return payFee; | |
467c31ea WL |
79 | } |
80 | ||
ab1b288f | 81 | static void InitMessage(const std::string &message) |
10d680cf WL |
82 | { |
83 | if(splashref) | |
84 | { | |
5762295e | 85 | splashref->showMessage(QString::fromStdString(message), Qt::AlignBottom|Qt::AlignHCenter, QColor(255,255,200)); |
1ce04488 | 86 | qApp->processEvents(); |
10d680cf | 87 | } |
bb41a87d | 88 | printf("init message: %s\n", message.c_str()); |
10d680cf WL |
89 | } |
90 | ||
ab1b288f | 91 | static void QueueShutdown() |
1a3f0da9 | 92 | { |
1ce04488 | 93 | QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection); |
1a3f0da9 WL |
94 | } |
95 | ||
39cf857d WL |
96 | /* |
97 | Translate string to current locale using Qt. | |
98 | */ | |
ab1b288f | 99 | static std::string Translate(const char* psz) |
39cf857d WL |
100 | { |
101 | return QCoreApplication::translate("bitcoin-core", psz).toStdString(); | |
102 | } | |
103 | ||
a7a0c7a1 WL |
104 | /* Handle runaway exceptions. Shows a message box with the problem and quits the program. |
105 | */ | |
106 | static void handleRunawayException(std::exception *e) | |
107 | { | |
108 | PrintExceptionContinue(e, "Runaway exception"); | |
951f7d35 | 109 | 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)); |
a7a0c7a1 WL |
110 | exit(1); |
111 | } | |
112 | ||
24548467 | 113 | #ifndef BITCOIN_QT_TEST |
aaa1c3c4 WL |
114 | int main(int argc, char *argv[]) |
115 | { | |
8ffbd6c3 PK |
116 | // Command-line options take precedence: |
117 | ParseParameters(argc, argv); | |
118 | ||
c75abc9f | 119 | // Internal string conversion is all UTF-8 |
3f0816e3 MSV |
120 | QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8")); |
121 | QTextCodec::setCodecForCStrings(QTextCodec::codecForTr()); | |
122 | ||
45c4a0b3 | 123 | Q_INIT_RESOURCE(bitcoin); |
aaa1c3c4 | 124 | QApplication app(argc, argv); |
daaee738 | 125 | |
8269a095 GA |
126 | // Do this early as we don't want to bother initializing if we are just calling IPC |
127 | // ... but do it after creating app, so QCoreApplication::arguments is initialized: | |
128 | if (PaymentServer::ipcSendCommandLine()) | |
129 | exit(0); | |
130 | PaymentServer* paymentServer = new PaymentServer(&app); | |
131 | ||
3793fa09 WL |
132 | // Install global event filter that makes sure that long tooltips can be word-wrapped |
133 | app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app)); | |
134 | ||
3f8cb2c5 | 135 | // ... then bitcoin.conf: |
f4203de3 | 136 | if (!boost::filesystem::is_directory(GetDataDir(false))) |
3f8cb2c5 | 137 | { |
61fd7269 WL |
138 | // This message can not be translated, as translation is not initialized yet |
139 | // (which not yet possible because lang=XX can be overridden in bitcoin.conf in the data directory) | |
140 | QMessageBox::critical(0, "Bitcoin", | |
141 | QString("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(mapArgs["-datadir"]))); | |
3f8cb2c5 GA |
142 | return 1; |
143 | } | |
f4203de3 | 144 | ReadConfigFile(mapArgs, mapMultiArgs); |
3f8cb2c5 GA |
145 | |
146 | // Application identification (must be set before OptionsModel is initialized, | |
147 | // as it is used to locate QSettings) | |
148 | app.setOrganizationName("Bitcoin"); | |
149 | app.setOrganizationDomain("bitcoin.org"); | |
150 | if(GetBoolArg("-testnet")) // Separate UI settings for testnet | |
151 | app.setApplicationName("Bitcoin-Qt-testnet"); | |
152 | else | |
153 | app.setApplicationName("Bitcoin-Qt"); | |
154 | ||
155 | // ... then GUI settings: | |
156 | OptionsModel optionsModel; | |
157 | ||
aab1f950 | 158 | // Get desired locale (e.g. "de_DE") from command line or use system locale |
72075eda | 159 | QString lang_territory = QString::fromStdString(GetArg("-lang", QLocale::system().name().toStdString())); |
5c92622a | 160 | QString lang = lang_territory; |
aab1f950 PK |
161 | // Convert to "de" only by truncating "_DE" |
162 | lang.truncate(lang_territory.lastIndexOf('_')); | |
72075eda | 163 | |
5c92622a | 164 | QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator; |
aab1f950 PK |
165 | // Load language files for configured locale: |
166 | // - First load the translator for the base language, without territory | |
167 | // - Then load the more specific locale translator | |
5c92622a | 168 | |
aab1f950 PK |
169 | // Load e.g. qt_de.qm |
170 | if (qtTranslatorBase.load("qt_" + lang, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) | |
5c92622a WL |
171 | app.installTranslator(&qtTranslatorBase); |
172 | ||
aab1f950 PK |
173 | // Load e.g. qt_de_DE.qm |
174 | if (qtTranslator.load("qt_" + lang_territory, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) | |
527137e3 | 175 | app.installTranslator(&qtTranslator); |
5c92622a | 176 | |
aab1f950 PK |
177 | // Load e.g. bitcoin_de.qm (shortcut "de" needs to be defined in bitcoin.qrc) |
178 | if (translatorBase.load(lang, ":/translations/")) | |
5c92622a WL |
179 | app.installTranslator(&translatorBase); |
180 | ||
aab1f950 PK |
181 | // Load e.g. bitcoin_de_DE.qm (shortcut "de_DE" needs to be defined in bitcoin.qrc) |
182 | if (translator.load(lang_territory, ":/translations/")) | |
608dacf6 | 183 | app.installTranslator(&translator); |
daaee738 | 184 | |
ab1b288f WL |
185 | // Subscribe to global signals from core |
186 | uiInterface.ThreadSafeMessageBox.connect(ThreadSafeMessageBox); | |
187 | uiInterface.ThreadSafeAskFee.connect(ThreadSafeAskFee); | |
ab1b288f WL |
188 | uiInterface.InitMessage.connect(InitMessage); |
189 | uiInterface.QueueShutdown.connect(QueueShutdown); | |
190 | uiInterface.Translate.connect(Translate); | |
191 | ||
9f5b11e6 WL |
192 | // Show help message immediately after parsing command-line options (for "-lang") and setting locale, |
193 | // but before showing splash screen. | |
194 | if (mapArgs.count("-?") || mapArgs.count("--help")) | |
195 | { | |
5d6b3027 | 196 | GUIUtil::HelpMessageBox help; |
7d72a8c3 | 197 | help.showOrPrint(); |
9f5b11e6 WL |
198 | return 1; |
199 | } | |
200 | ||
8c4738d5 | 201 | QSplashScreen splash(QPixmap(":/images/splash"), 0); |
ec4efde4 CM |
202 | if (GetBoolArg("-splash", true) && !GetBoolArg("-min")) |
203 | { | |
204 | splash.show(); | |
205 | splash.setAutoFillBackground(true); | |
206 | splashref = &splash; | |
207 | } | |
10d680cf WL |
208 | |
209 | app.processEvents(); | |
210 | ||
352083cb | 211 | app.setQuitOnLastWindowClosed(false); |
aaa1c3c4 | 212 | |
8e86dca2 WL |
213 | try |
214 | { | |
67d4cbab WL |
215 | // Regenerate startup link, to fix links to old versions |
216 | if (GUIUtil::GetStartOnSystemStartup()) | |
217 | GUIUtil::SetStartOnSystemStartup(true); | |
218 | ||
c8c2fbe0 | 219 | boost::thread_group threadGroup; |
7cfbe1fe WL |
220 | BitcoinGUI window; |
221 | guiref = &window; | |
c8c2fbe0 | 222 | if(AppInit2(threadGroup)) |
18cab09a | 223 | { |
8fe2308b | 224 | { |
7cfbe1fe WL |
225 | // Put this in a block, so that the Model objects are cleaned up before |
226 | // calling Shutdown(). | |
3f8cb2c5 GA |
227 | |
228 | optionsModel.Upgrade(); // Must be done after AppInit2 | |
229 | ||
ec4efde4 CM |
230 | if (splashref) |
231 | splash.finish(&window); | |
3f8cb2c5 | 232 | |
ee014e5b WL |
233 | ClientModel clientModel(&optionsModel); |
234 | WalletModel walletModel(pwalletMain, &optionsModel); | |
0b814f9e | 235 | |
8fe2308b | 236 | window.setClientModel(&clientModel); |
67155d92 EL |
237 | window.addWallet("~Default", &walletModel); |
238 | window.setCurrentWallet("~Default"); | |
8fe2308b | 239 | |
7915370c WL |
240 | // If -min option passed, start window minimized. |
241 | if(GetBoolArg("-min")) | |
242 | { | |
243 | window.showMinimized(); | |
244 | } | |
245 | else | |
246 | { | |
247 | window.show(); | |
248 | } | |
8fe2308b | 249 | |
8269a095 GA |
250 | // Now that initialization/startup is done, process any command-line |
251 | // bitcoin: URIs | |
252 | QObject::connect(paymentServer, SIGNAL(receivedURI(QString)), &window, SLOT(handleURI(QString))); | |
253 | QTimer::singleShot(100, paymentServer, SLOT(uiReady())); | |
7b90edb5 | 254 | |
8fe2308b WL |
255 | app.exec(); |
256 | ||
46f552a9 | 257 | window.hide(); |
7cfbe1fe | 258 | window.setClientModel(0); |
67155d92 | 259 | window.removeAllWallets(); |
8fe2308b WL |
260 | guiref = 0; |
261 | } | |
b49f1398 | 262 | // Shutdown the core and its threads, but don't exit Bitcoin-Qt here |
18cab09a | 263 | Shutdown(NULL); |
c8c2fbe0 GA |
264 | threadGroup.interrupt_all(); |
265 | threadGroup.join_all(); | |
18cab09a WL |
266 | } |
267 | else | |
268 | { | |
269 | return 1; | |
270 | } | |
271 | } catch (std::exception& e) { | |
a7a0c7a1 | 272 | handleRunawayException(&e); |
18cab09a | 273 | } catch (...) { |
a7a0c7a1 | 274 | handleRunawayException(NULL); |
18cab09a | 275 | } |
8fe2308b | 276 | return 0; |
aaa1c3c4 | 277 | } |
24548467 | 278 | #endif // BITCOIN_QT_TEST |