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