BibleTime
bibletime.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-2026 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 "bibletime.h"
14
15#include <cmath>
16#include <cstdlib>
17#include <exception>
18#include <random>
19#include <QAction>
20#include <QApplication>
21#include <QCloseEvent>
22#include <QDebug>
23#include <QInputDialog>
24#include <QLabel>
25#include <QMdiSubWindow>
26#include <QSplashScreen>
27#include <QSplitter>
28#include <type_traits>
29#include "../backend/config/btconfig.h"
30#include "../backend/drivers/cswordmoduleinfo.h"
31#include "../backend/keys/cswordversekey.h"
32#include "../backend/managers/cswordbackend.h"
33#include "../util/btassert.h"
34#include "../util/cresmgr.h"
35#include "../util/directory.h"
36#include "bibletimeapp.h"
37#include "btaboutmoduledialog.h"
40#include "cmdiarea.h"
48#include "messagedialog.h"
50
51
52namespace {
53
54template <typename T>
55auto randInt(T min, T max)
56 -> std::enable_if_t<std::is_integral_v<std::decay_t<T>>, T>
57{
58 static std::mt19937 rng((std::random_device()()));
59 return std::uniform_int_distribution<std::decay_t<T>>(min, max)(rng);
60}
61
62QString const splashes[] = {
63 QStringLiteral("startuplogo.png"),
64 QStringLiteral("startuplogo_christmas.png"),
65 QStringLiteral("startuplogo_easter.jpg"),
66};
67
68auto const splashHtml =
69 QStringLiteral(
70 "<div style='background:transparent;color:white;font-weight:bold'>"
71 "%1</div>");
72
73} // anonymous namespace
74
76
77BibleTime::BibleTime(BibleTimeApp & app, QWidget *parent, Qt::WindowFlags flags)
78 : QMainWindow(parent, flags)
79{
80 namespace DU = util::directory;
81
83 m_instance = this;
84
85 QSplashScreen * splash = nullptr;
86 constexpr static auto const splashTextAlignment =
87 Qt::AlignHCenter | Qt::AlignTop;
88
89 if (btConfig().value<bool>(QStringLiteral("GUI/showSplashScreen"), true)) {
90 auto const splashNumber =
91 randInt<std::size_t>(0u,
92 std::extent_v<decltype(splashes)> - 1u);
93 QPixmap pm;
94 if (pm.load(DU::getPicsDir().filePath(splashes[splashNumber]))) {
95 splash = new QSplashScreen(pm);
96 splash->showMessage(
97 splashHtml.arg(tr("Initializing the SWORD engine...")),
98 splashTextAlignment);
99 splash->show();
100 qApp->processEvents();
101 } else {
102 qWarning("Can't load startuplogo! Check your installation.");
103 }
104 }
105 app.initBackends();
106
107 if (splash) {
108 splash->showMessage(
109 splashHtml.arg(
110 tr("Creating BibleTime's user interface...")),
111 splashTextAlignment);
112 qApp->processEvents();
113 }
114 initView();
115
116 if (splash) {
117 splash->showMessage(
118 splashHtml.arg(tr("Initializing menu- and toolbars...")),
119 splashTextAlignment);
120 qApp->processEvents();
121 splash->setAttribute(Qt::WA_DeleteOnClose);
122 splash->finish(this);
123 }
124 initActions();
125 initMenubar();
126 initToolbars();
128
129 setWindowTitle(QStringLiteral("BibleTime " BT_VERSION));
130 setWindowIcon(CResMgr::mainWindow::icon());
132}
133
139
140/** \brief Creates a new presenter in the MDI area according to the type of the
141 module. */
143 QList<CSwordModuleInfo *> modules,
144 QString const & key)
145{
146 qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
147
148 CDisplayWindow * displayWindow;
149 switch (modules.first()->type()) {
151 displayWindow = new CBibleReadWindow(modules, key, m_mdi);
152 break;
154 displayWindow = new CCommentaryReadWindow(modules, key, m_mdi);
155 break;
157 displayWindow = new CLexiconReadWindow(modules, key, m_mdi);
158 break;
160 displayWindow = new CBookReadWindow(modules, key, m_mdi);
161 break;
162 default:
163 qFatal("unknown module type");
164 std::terminate();
165 }
166 m_mdi->addDisplayWindow(displayWindow);
167 displayWindow->show();
168
169 /* We have to process pending events here, otherwise displayWindow is not
170 fully painted. */
171 qApp->processEvents();
172 qApp->restoreOverrideCursor();
173 return displayWindow;
174}
175
176
177/** \brief Creates a new presenter in the MDI area according to the type of the
178 module. */
180 CSwordModuleInfo * const module,
181 QString const & key)
182{ return createReadDisplayWindow(QList<CSwordModuleInfo*>() << module, key); }
183
184bool BibleTime::moduleUnlock(CSwordModuleInfo * module, QWidget * const parent){
185 BT_ASSERT(module);
186
187 /// \todo Write a proper unlocking dialog with integrated error messages.
188 BtMessageInputDialog unlockKeyInputDialog(
189 tr("Unlock Work"),
190 tr("Enter the unlock key for %1.").arg(module->name()),
193 module->getUnlockInfo(),
194 parent);
195
196 while (unlockKeyInputDialog.exec() == QDialog::Accepted) {
197 module->unlock(unlockKeyInputDialog.getUserInput());
198
199 /// \todo refactor this module reload
200 /* There is currently a deficiency in SWORD 1.8.1 in that
201 backend->setCipherKey() does not work correctly for modules from
202 which data was already fetched. Therefore we have to reload the
203 modules. */
204 {
205 auto const moduleName(module->name());
206 auto & backend = CSwordBackend::instance();
207 backend.reloadModules();
208 module = backend.findModuleByName(moduleName);
209 BT_ASSERT(module);
210 }
211
212 // Return true if the module was succesfully unlocked:
213 if (!module->isLocked())
214 return true;
215
217 parent,
218 tr("Warning: Invalid unlock key!"),
219 tr("The unlock key you provided did not properly unlock "
220 "this module. Please try again."));
221 }
222 return false;
223}
224
226 moduleUnlock(module, this);
227}
228
230 BTAboutModuleDialog *dialog = new BTAboutModuleDialog(module, this);
231 dialog->setAttribute(Qt::WA_DeleteOnClose); // Destroy dialog when closed
232 dialog->show();
233 dialog->raise();
234}
235
236/** Refreshes all presenters.*/
238 for (auto const * const subWindow : m_mdi->subWindowList())
239 if (CDisplayWindow * const window =
240 dynamic_cast<CDisplayWindow*>(subWindow->widget()))
241 window->reload();
242}
243
244void BibleTime::processCommandline(bool const ignoreSession,
245 QString const & bibleKey)
246{
247 if (btConfig().value<bool>(QStringLiteral("state/crashedTwoTimes"), false))
248 return;
249
250 // Restore workspace if not not ignoring session data:
251 if (!ignoreSession)
253
254 if (btConfig().value<bool>(QStringLiteral("state/crashedLastTime"), false))
255 return;
256
257 if (!bibleKey.isNull()) {
258 auto * const bible =
260 QStringLiteral("standardBible"));
261 if (bibleKey == QStringLiteral("random")) {
262 CSwordVerseKey vk(nullptr);
263 auto const newIndex = randInt<decltype(vk.index())>(0, 31100);
264 vk.positionToTop();
265 vk.setIndex(newIndex);
266 createReadDisplayWindow(bible, vk.key());
267 } else {
268 createReadDisplayWindow(bible, bibleKey);
269 }
270
271 /*
272 We are sure only one window is open - it should be displayed
273 fullscreen in the working area:
274 */
276 }
277
278 if (btConfig().value<bool>(QStringLiteral("state/crashedLastTime"), false)){
279 btConfig().setValue(QStringLiteral("state/crashedTwoTimes"), true);
280 } else {
281 btConfig().setValue(QStringLiteral("state/crashedLastTime"), true);
282 }
283 btConfig().sync();
284}
285
286bool BibleTime::event(QEvent* event) {
287 if (event->type() == QEvent::PaletteChange) {
288 Q_EMIT colorThemeChanged();
289 // allow to continue to update other parts of Qt widgets
290 } else if (event->type() == QEvent::KeyPress) {
291 if (static_cast<QKeyEvent *>(event)->modifiers() > 0)
292 return false;
293 if (autoScrollAnyKey())
294 return true;
295 }
296 return QMainWindow::event(event);
297}
298
300 if (auto * const activeSubWindow = m_mdi->activeSubWindow())
301 if (auto * const displayWindow =
302 dynamic_cast<CDisplayWindow *>(activeSubWindow->widget()))
303 return displayWindow->firstModule();
304 return nullptr;
305}
306
308 if (auto * const activeSubWindow = m_mdi->activeSubWindow())
309 if (auto * const displayWindow =
310 dynamic_cast<CDisplayWindow *>(activeSubWindow->widget()))
311 return displayWindow->displayWidget();
312 return nullptr;
313}
314
316 if (auto * const display = getCurrentDisplay())
317 display->setDisplayFocus();
318}
319
321 QString const & searchText)
322{
323 if (!m_searchDialog)
325 m_searchDialog->reset(std::move(modules), searchText);
326}
327
#define BT_ASSERT(...)
Definition btassert.h:17
BtConfig & btConfig()
This is a shortchand for BtConfig::getInstance().
Definition btconfig.h:305
QList< CSwordModuleInfo const * > BtConstModuleList
QPointer< QWidget > m_debugWindow
Definition bibletime.h:481
void slotModuleUnlock(CSwordModuleInfo *module)
BtBookshelfDockWidget * m_bookshelfDock
Definition bibletime.h:445
static bool moduleUnlock(CSwordModuleInfo *module, QWidget *parent=nullptr)
void retranslateUi()
void moduleAbout(CSwordModuleInfo *module)
void openFindWidget()
CMDIArea * m_mdi
Definition bibletime.h:473
bool event(QEvent *event) override
void initToolbars()
void openSearchDialog(BtConstModuleList modules, QString const &searchText={})
static BibleTime * m_instance
Definition bibletime.h:442
void colorThemeChanged()
void setDisplayFocus()
void initConnections()
BtFindWidget * m_findWidget
Definition bibletime.h:474
QPointer< Search::CSearchDialog > m_searchDialog
Definition bibletime.h:478
CSwordModuleInfo const * getCurrentModule()
BtModelViewReadDisplay * getCurrentDisplay()
~BibleTime() override
void processCommandline(bool ignoreSession, QString const &bibleKey)
CDisplayWindow * createReadDisplayWindow(QList< CSwordModuleInfo * > modules, QString const &key)
Creates a new presenter in the MDI area according to the type of the module.
void refreshDisplayWindows() const
bool autoScrollAnyKey()
BibleTime(BibleTimeApp &app, QWidget *parent=nullptr, Qt::WindowFlags flags=Qt::WindowFlags())
Definition bibletime.cpp:77
void sync()
Synchronizes the configuration to disk.
void setValue(QString const &key, T const &value)
Sets a value for a key.
CSwordModuleInfo * getDefaultSwordModuleByType(const QString &moduleType)
Returns default sword module info class for a given module type.
Definition btconfig.cpp:493
void showAndSelect()
The BtMessageInputDialog class provides a editable field for user input. Optionally it displays a lar...
The base class for all display windows of BibleTime.
The class used to display lexicons.
void myTileVertical()
Definition cmdiarea.cpp:154
QMdiSubWindow * addDisplayWindow(CDisplayWindow *displayWindow)
Definition cmdiarea.cpp:85
static CSwordBackend & instance() noexcept
QString config(const CSwordModuleInfo::ConfigEntry entry) const
QString const & name() const
CSwordKey implementation for Sword's VerseKey.
void setIndex(long v)
QString key() const final override
long index() const
#define T(f)
auto randInt(T min, T max) -> std::enable_if_t< std::is_integral_v< std::decay_t< T > >, T >
Definition bibletime.cpp:55
QMessageBox::StandardButton showWarning(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)