BibleTime
bibletimeapp.cpp
Go to the documentation of this file.
1/*********
2*
3* In the name of the Father, and of the Son, and of the Holy Spirit.
4*
5* This file is part of BibleTime's source code, https://bibletime.info/
6*
7* Copyright 1999-2025 by the BibleTime developers.
8* The BibleTime source code is licensed under the GNU General Public License
9* version 2.0.
10*
11**********/
12
13#include "bibletimeapp.h"
14
15#ifdef Q_OS_WIN
16#include <array>
17#endif
18#include <cstdio>
19#include <cstdlib>
20#include <memory>
21#include <QByteArray>
22#include <QColor>
23#include <QDebug>
24#ifdef Q_OS_WIN
25#include <QDir>
26#endif
27#include <QFile>
28#include <QIODevice>
29#include <QMessageBox>
30#include <QPalette>
31#include <QString>
32#include <Qt>
33#include <QtGlobal>
34#ifdef Q_OS_WIN
35#include <QTextStream>
36#endif
37#ifdef Q_OS_WIN
38#include <windows.h>
39#endif
40#include "../backend/config/btconfig.h"
41#include "../backend/managers/cdisplaytemplatemgr.h"
42#include "../util/btassert.h"
43#include "../util/bticons.h"
44#ifdef Q_OS_WIN
45#include "../util/directory.h"
46#endif
47#include "messagedialog.h"
49
50// Sword includes:
51#pragma GCC diagnostic push
52#pragma GCC diagnostic ignored "-Wextra-semi"
53#include <swlog.h>
54#pragma GCC diagnostic pop
55
56
57class QMessageLogContext;
58
59namespace {
60
61std::unique_ptr<QFile> debugStream;
62
63void myMessageOutput(QtMsgType type,
64 QMessageLogContext const &,
65 QString const & message)
66{
67 QByteArray msg = message.toLatin1();
68 #define MY_OUTPUT_LITERAL(literal) \
69 debugStream->write(literal, sizeof(literal) - 1u)
70 switch (type) {
71 case QtDebugMsg:
72 if (btApp->debugMode()) { // Only show messages if they are enabled!
73 MY_OUTPUT_LITERAL("(BibleTime " BT_VERSION ") Debug: ");
74 debugStream->write(msg);
75 debugStream->putChar('\n');
76 debugStream->flush();
77 }
78 break;
79 case QtInfoMsg:
80 MY_OUTPUT_LITERAL("(BibleTime " BT_VERSION ") INFO: ");
81 debugStream->write(msg);
82 debugStream->putChar('\n');
83 debugStream->flush();
84 break;
85 case QtWarningMsg:
86 MY_OUTPUT_LITERAL("(BibleTime " BT_VERSION ") WARNING: ");
87 debugStream->write(msg);
88 debugStream->putChar('\n');
89 debugStream->flush();
90 break;
91 case QtCriticalMsg:
92 MY_OUTPUT_LITERAL("(BibleTime " BT_VERSION ") CRITICAL: ");
93 debugStream->write(msg);
94 MY_OUTPUT_LITERAL("\nPlease report this bug at "
95 "https://github.com/bibletime/bibletime/issues\n");
96 debugStream->flush();
97 break;
98 case QtFatalMsg:
99 MY_OUTPUT_LITERAL("(BibleTime " BT_VERSION ") FATAL: ");
100 debugStream->write(msg);
101 MY_OUTPUT_LITERAL("\nPlease report this bug at "
102 "https://github.com/bibletime/bibletime/issues\n");
103
104 // Dump core on purpose (see qInstallMsgHandler documentation):
105 debugStream->close();
106 std::abort();
107 }
108 #undef MY_OUTPUT_LITERAL
109}
110
111} // anonymous namespace
112
113BibleTimeApp::BibleTimeApp(int &argc, char **argv)
114 : QApplication(argc, argv)
115 , m_init(false)
116 , m_debugMode(qgetenv("BIBLETIME_DEBUG") == QByteArrayLiteral("1"))
117 , m_icons(nullptr)
118{
119 setApplicationName(QStringLiteral("bibletime"));
120 setApplicationVersion(BT_VERSION);
121 setDesktopFileName(QStringLiteral("info.bibletime.BibleTime"));
122
123 #ifdef Q_OS_WIN
124 // On Windows, add a path for Qt plugins to be loaded from:
125 addLibraryPath(applicationDirPath() + QStringLiteral("/plugins"));
126
127 // Must set HOME var on Windows:
128 // getenv and qgetenv don't work right on Windows with unicode characters
129 std::array<wchar_t, 4096u> homeDir;
130 GetEnvironmentVariable(TEXT("APPDATA"), homeDir.data(), homeDir.size());
131 SetEnvironmentVariable(TEXT("HOME"), homeDir.data());
132 #endif
133
134 // Setup message handler:
135 #ifdef Q_OS_WIN
136 // Use the default Qt message handler if --debug is not specified
137 // This works with Visual Studio debugger Output Window
138 if (m_debugMode) {
139 debugStream =
140 std::make_unique<QFile>(
141 QDir::home().filePath(
142 QStringLiteral("/BibleTime Debug.txt")));
143 debugStream->open(QIODevice::WriteOnly | QIODevice::Text);
144 qInstallMessageHandler(myMessageOutput);
145 }
146 #else
147 debugStream = std::make_unique<QFile>();
148 debugStream->open(stderr, QIODevice::WriteOnly | QIODevice::Text);
149 qInstallMessageHandler(myMessageOutput);
150 #endif
151}
152
154 // Prevent writing to the log file before the directory cache is init:
155 if (!m_init || BtConfig::m_instance == nullptr)
156 return;
157
158 //we can set this safely now because we close now (hopyfully without crash)
159 btConfig().setValue(QStringLiteral("state/crashedLastTime"), false);
160 btConfig().setValue(QStringLiteral("state/crashedTwoTimes"), false);
161
163 m_backend.reset();
164 delete m_icons;
165
167}
168
171
173 if (r == BtConfig::INIT_OK)
174 return true;
176 /// \todo Migrate from btConfigOldApi to BTCONFIG_API_VERSION
177 qWarning() << "BibleTime configuration migration is not yet implemented!!!";
179 nullptr,
180 tr("Warning!"),
181 tr("Migration to the new configuration system is not yet "
182 "implemented. Proceeding might result in <b>loss of data"
183 "</b>. Please backup your configuration files before "
184 "you continue!<br/><br/>Do you want to continue? Press "
185 "\"No\" to quit BibleTime immediately."),
186 QMessageBox::Yes | QMessageBox::No,
187 QMessageBox::No) == QMessageBox::No)
188 return false;
189 } else {
192 nullptr,
193 tr("Error loading configuration!"),
194 tr("Failed to load BibleTime's configuration, because it "
195 "appears that the configuration file corresponds to a "
196 "newer version of BibleTime. This is likely caused by "
197 "BibleTime being downgraded. Loading the new "
198 "configuration file may result in <b>loss of data</b>."
199 "<br/><br/>Do you still want to try to load the new "
200 "configuration file? Press \"No\" to quit BibleTime "
201 "immediately."),
202 QMessageBox::Yes | QMessageBox::No,
203 QMessageBox::No) == QMessageBox::No)
204 return false;
205 }
207 return true;
208}
209
211 enum LightDarkMode {
212 systemDefault = 0,
213 light = 1,
214 dark = 2
215 };
216
217 auto const lightDarkMode =
218 btConfig().value<int>(QStringLiteral("GUI/lightDarkMode"), 0);
219 if (lightDarkMode == LightDarkMode::systemDefault)
220 return;
221 QPalette p;
222 if (lightDarkMode == LightDarkMode::dark) {
223 p.setColor(QPalette::WindowText,QColor(0xfc, 0xfc, 0xfc));
224 p.setColor(QPalette::Button,QColor(0x31, 0x36, 0x3b));
225 p.setColor(QPalette::Light,QColor(0x18, 0x1b, 0x1d));
226 p.setColor(QPalette::Midlight,QColor(0x25, 0x29, 0x2c));
227 p.setColor(QPalette::Dark,QColor(0x62, 0x6c, 0x76));
228 p.setColor(QPalette::Mid,QColor(0x41, 0x48, 0x4e));
229 p.setColor(QPalette::Text,QColor(0xfc, 0xfc, 0xfc));
230 p.setColor(QPalette::BrightText,QColor(0xff, 0xff, 0xff));
231 p.setColor(QPalette::ButtonText,QColor(0xfc, 0xfc, 0xfc));
232 p.setColor(QPalette::Base,QColor(0x1b, 0x1e, 0x20));
233 p.setColor(QPalette::Window,QColor(0x2a, 0x2e, 0x32));
234 p.setColor(QPalette::Shadow,QColor(0x76, 0x76, 0x76));
235 p.setColor(QPalette::Highlight,QColor(0x3d, 0xae, 0xe9));
236 p.setColor(QPalette::HighlightedText,QColor(0xfc, 0xfc, 0xfc));
237 p.setColor(QPalette::Link,QColor(0x1d, 0x99, 0xf3));
238 p.setColor(QPalette::LinkVisited,QColor(0x9b, 0x59, 0xb6));
239 } else {
240 p.setColor(QPalette::WindowText,QColor(0x23, 0x26, 0x29));
241 p.setColor(QPalette::Button,QColor(0xf7, 0xf7, 0xf7));
242 p.setColor(QPalette::Light,QColor(0x0, 0x0, 0x0));
243 p.setColor(QPalette::Midlight,QColor(0x0, 0x0, 0x0));
244 p.setColor(QPalette::Dark,QColor(0x7b, 0x7b, 0x7b));
245 p.setColor(QPalette::Mid,QColor(0xa5, 0xa5, 0xa5));
246 p.setColor(QPalette::Text,QColor(0x23, 0x26, 0x29));
247 p.setColor(QPalette::BrightText,QColor(0xff, 0xff, 0xff));
248 p.setColor(QPalette::ButtonText,QColor(0x23, 0x26, 0x29));
249 p.setColor(QPalette::Base,QColor(0xff, 0xff, 0xff));
250 p.setColor(QPalette::Window,QColor(0xef, 0xf0, 0xf1));
251 p.setColor(QPalette::Shadow,QColor(0x76, 0x76, 0x76));
252 p.setColor(QPalette::Highlight,QColor(0x3d, 0xae, 0xe9));
253 p.setColor(QPalette::HighlightedText,QColor(0xff, 0xff, 0xff));
254 p.setColor(QPalette::Link,QColor(0x29, 0x80, 0xb9));
255 p.setColor(QPalette::LinkVisited,QColor(0x9b, 0x59, 0xb6));
256 }
257 setPalette(p);
258}
259
262
263 QString errorMessage;
264 new CDisplayTemplateMgr(errorMessage);
265 if (errorMessage.isNull())
266 return true;
267 message::showCritical(nullptr, tr("Fatal error!"), errorMessage);
268 return false;
269}
270
272
274 // On Windows the sword.conf must be created before the initialization of sword
275 // It will contain the LocalePath which is used for sword locales
276 // It also contains a DataPath to the %ProgramData%\Sword directory
277 // If this is not done here, the sword locales.d won't be found
278
279 #ifdef Q_OS_WIN
280 {
281 QFile file(
283 QStringLiteral("sword.conf")));
284 if (!file.exists() && file.open(QIODevice::WriteOnly | QIODevice::Text))
285 {
286 QTextStream(&file)
287 << QStringLiteral("\n[Install]\nDataPath=")
288 << QDir::toNativeSeparators(
289 util::directory::getSharedSwordDir().absolutePath())
290 << QStringLiteral("\nLocalePath=")
291 << QDir::toNativeSeparators(
292 util::directory::getApplicationSwordDir().absolutePath())
293 << '\n';
294 }
295 }
296 #endif
297
298 sword::SWLog::getSystemLog()->setLogLevel(btApp->debugMode()
299 ? sword::SWLog::LOG_DEBUG
300 : sword::SWLog::LOG_ERROR);
301
302 /*
303 Set book names language if not set. This is a hack. We do this call here,
304 because we need to keep the setting displayed in BtLanguageSettingsPage in
305 sync with the language of the book names displayed, so that both would
306 always use the same setting.
307 */
308 CDisplaySettingsPage::resetLanguage(); /// \todo refactor this hack
309
310 m_backend.emplace();
311}
#define MY_OUTPUT_LITERAL(literal)
#define btApp
#define BT_ASSERT(...)
Definition btassert.h:17
BtConfig & btConfig()
This is a shortchand for BtConfig::getInstance().
Definition btconfig.h:305
bool initDisplayTemplateManager()
std::optional< CSwordBackend > m_backend
BibleTimeApp(int &argc, char **argv)
void initLightDarkPalette()
BtIcons * m_icons
~BibleTimeApp() override
T value(QString const &key, T const &defaultValue=T()) const
Returns the settings value for the given global key.
void setValue(QString const &key, T const &value)
Sets a value for a key.
static InitState initBtConfig()
Definition btconfig.cpp:140
static void destroyInstance()
Definition btconfig.cpp:215
static void forceMigrate()
Definition btconfig.cpp:160
static BtConfig * m_instance
singleton instance
Definition btconfig.h:285
@ INIT_NEED_UNIMPLEMENTED_FORWARD_MIGRATE
Definition btconfig.h:56
@ INIT_NEED_UNIMPLEMENTED_BACKWARD_MIGRATE
Definition btconfig.h:54
@ INIT_OK
Definition btconfig.h:55
static CDisplayTemplateMgr * instance()
QStringList r(content.left(bodyIndex))
void myMessageOutput(QtMsgType type, QMessageLogContext const &, QString const &message)
std::unique_ptr< QFile > debugStream
QMessageBox::StandardButton showCritical(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
QMessageBox::StandardButton showWarning(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
const QDir & getUserHomeSwordDir()