1 /*********
2 *
3 * This file is part of BibleTime's source code, http://www.bibletime.info/.
4 *
5 * Copyright 1999-2016 by the BibleTime developers.
6 * The BibleTime source code is licensed under the GNU General Public License version 2.0.
7 *
8 **********/
9
10 #include "bibletime.h"
11
12 #include <QApplication>
13 #include <QDebug>
14 #include <QDockWidget>
15 #include <QLabel>
16 #include <QMenu>
17 #include <QMenuBar>
18 #include <QPointer>
19 #include <QSplitter>
20 #include <QToolBar>
21 #include <QToolButton>
22 #include <QVBoxLayout>
23 #include "backend/config/btconfig.h"
24 #include "backend/managers/btstringmgr.h"
25 #include "backend/managers/clanguagemgr.h"
26 #include "backend/managers/cswordbackend.h"
27 #include "bibletimeapp.h"
28 #include "frontend/btbookshelfdockwidget.h"
29 #include "frontend/btopenworkaction.h"
30 #include "frontend/cinfodisplay.h"
31 #include "frontend/cmdiarea.h"
32 #include "frontend/display/btfindwidget.h"
33 #include "frontend/displaywindow/btactioncollection.h"
34 #include "frontend/displaywindow/btmodulechooserbar.h"
35 #include "frontend/keychooser/ckeychooser.h"
36 #include "frontend/bookmarks/cbookmarkindex.h"
37 #include "frontend/settingsdialogs/cdisplaysettings.h"
38 #include "util/btassert.h"
39 #include "util/btconnect.h"
40 #include "util/cresmgr.h"
41 #include "util/directory.h"
42
43 // Sword includes:
44 #include <swlog.h>
45 #include <swmgr.h>
46
47 #ifndef NDEBUG
48 #include <QLabel>
49 #include <QMetaObject>
50 #include <QMutexLocker>
51 #include <QTimer>
52 #endif
53
54
55 using namespace InfoDisplay;
56
57 /**Initializes the view of this widget*/
initView()58 void BibleTime::initView() {
59
60 // Create menu and toolbar before the mdi area
61 createMenuAndToolBar();
62
63 createCentralWidget();
64
65 m_bookshelfDock = new BtBookshelfDockWidget(this);
66 addDockWidget(Qt::LeftDockWidgetArea, m_bookshelfDock);
67
68 m_bookmarksDock = new QDockWidget(this);
69 m_bookmarksDock->setObjectName("BookmarksDock");
70 m_bookmarksPage = new CBookmarkIndex(nullptr);
71 m_bookmarksDock->setWidget(m_bookmarksPage);
72 addDockWidget(Qt::LeftDockWidgetArea, m_bookmarksDock);
73 tabifyDockWidget(m_bookmarksDock, m_bookshelfDock);
74
75 m_magDock = new QDockWidget(this);
76 m_magDock->setObjectName("MagDock");
77 m_infoDisplay = new CInfoDisplay(this);
78 m_infoDisplay->resize(150, 150);
79 m_magDock->setWidget(m_infoDisplay);
80 addDockWidget(Qt::LeftDockWidgetArea, m_magDock);
81
82 BT_CONNECT(m_bookshelfDock, SIGNAL(moduleHovered(CSwordModuleInfo *)),
83 m_infoDisplay, SLOT(setInfo(CSwordModuleInfo *)));
84
85 m_mdi->setMinimumSize(100, 100);
86 m_mdi->setFocusPolicy(Qt::ClickFocus);
87 }
88
initAction(QAction * action,QString text,QIcon const & icon,QKeySequence accel,const QString & tooltip,const QString & actionName,const char * slot)89 QAction* BibleTime::initAction(QAction* action, QString text, QIcon const & icon,
90 QKeySequence accel, const QString& tooltip,
91 const QString& actionName, const char* slot) {
92 action->setText(text);
93 action->setIcon(icon);
94 action->setShortcut(accel);
95 if (tooltip != QString::null)
96 action->setToolTip(tooltip);
97 m_actionCollection->addAction(actionName, action);
98 if (slot)
99 BT_CONNECT(action, SIGNAL(triggered()), this, slot);
100 return action;
101 }
102
103 // Creates QAction's for all actions that can have keyboard shortcuts
104 // Used in creating the main window and by the configuration dialog for setting shortcuts
insertKeyboardActions(BtActionCollection * const a)105 void BibleTime::insertKeyboardActions( BtActionCollection* const a ) {
106 QAction* action = new QAction(a);
107 action->setText(tr("&Quit"));
108 action->setIcon(CResMgr::mainMenu::window::quit::icon());
109 action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
110 action->setToolTip(tr("Quit BibleTime"));
111 a->addAction("quit", action);
112
113 action = new QAction(a);
114 action->setText(tr("&Fullscreen mode"));
115 action->setIcon(CResMgr::mainMenu::window::showFullscreen::icon());
116 action->setShortcut(QKeySequence(CResMgr::mainMenu::window::showFullscreen::accel));
117 action->setToolTip(tr("Toggle fullscreen mode of the main window"));
118 a->addAction("toggleFullscreen", action);
119
120 action = new QAction(a);
121 action->setText(tr("&Show toolbar"));
122 action->setShortcut(QKeySequence(Qt::Key_F6));
123 a->addAction("showToolbar", action);
124
125 action = new QAction(a);
126 action->setText(tr("Search in &open works..."));
127 action->setIcon(CResMgr::mainMenu::mainIndex::search::icon());
128 action->setShortcut(QKeySequence(CResMgr::mainMenu::mainIndex::search::accel));
129 action->setToolTip(tr("Search in all works that are currently open"));
130 a->addAction("searchOpenWorks", action);
131
132 action = new QAction(a);
133 action->setText(tr("Search in standard &Bible..."));
134 action->setIcon(CResMgr::mainMenu::mainIndex::searchdefaultbible::icon());
135 action->setShortcut(QKeySequence(CResMgr::mainMenu::mainIndex::searchdefaultbible::accel));
136 action->setToolTip(tr("Search in the standard Bible"));
137 a->addAction("searchStdBible", action);
138
139 action = new QAction(a);
140 action->setText(tr("Save as &new session..."));
141 action->setIcon(CResMgr::mainMenu::window::saveToNewProfile::icon());
142 action->setShortcut(QKeySequence(CResMgr::mainMenu::window::saveToNewProfile::accel));
143 action->setToolTip(tr("Create and save a new session"));
144 a->addAction("saveNewSession", action);
145
146 action = new QAction(a);
147 action->setText(tr("&Manual mode"));
148 action->setIcon(CResMgr::mainMenu::window::arrangementMode::manual::icon());
149 action->setShortcut(QKeySequence(CResMgr::mainMenu::window::arrangementMode::manual::accel));
150 action->setToolTip(tr("Manually arrange the open windows"));
151 a->addAction("manualArrangement", action);
152
153 action = new QAction(a);
154 action->setText(tr("Auto-tile &vertically"));
155 action->setIcon(CResMgr::mainMenu::window::arrangementMode::autoTileVertical::icon());
156 action->setShortcut(QKeySequence(CResMgr::mainMenu::window::arrangementMode::autoTileVertical::accel));
157 action->setToolTip(tr("Automatically tile the open windows vertically (arrange side by side)"));
158 a->addAction("autoVertical", action);
159
160 action = new QAction(a);
161 action->setText(tr("Auto-tile &horizontally"));
162 action->setIcon(CResMgr::mainMenu::window::arrangementMode::autoTileHorizontal::icon());
163 action->setShortcut(QKeySequence(CResMgr::mainMenu::window::arrangementMode::autoTileHorizontal::accel));
164 action->setToolTip(tr("Automatically tile the open windows horizontally (arrange on top of each other)"));
165 a->addAction("autoHorizontal", action);
166
167 action = new QAction(a);
168 action->setText(tr("Auto-&tile"));
169 action->setIcon(CResMgr::mainMenu::window::arrangementMode::autoTile::icon());
170 action->setShortcut(QKeySequence(CResMgr::mainMenu::window::arrangementMode::autoTile::accel));
171 action->setToolTip(tr("Automatically tile the open windows"));
172 a->addAction("autoTile", action);
173
174 action = new QAction(a);
175 action->setText(tr("Ta&bbed"));
176 action->setIcon(CResMgr::mainMenu::window::arrangementMode::autoTabbed::icon());
177 action->setShortcut(QKeySequence(CResMgr::mainMenu::window::arrangementMode::autoTabbed::accel));
178 action->setToolTip(tr("Automatically tab the open windows"));
179 a->addAction("autoTabbed", action);
180
181 action = new QAction(a);
182 action->setText(tr("Auto-&cascade"));
183 action->setIcon(CResMgr::mainMenu::window::arrangementMode::autoCascade::icon());
184 action->setShortcut(QKeySequence(CResMgr::mainMenu::window::arrangementMode::autoCascade::accel));
185 action->setToolTip(tr("Automatically cascade the open windows"));
186 a->addAction("autoCascade", action);
187
188 action = new QAction(a);
189 action->setText(tr("&Cascade"));
190 action->setIcon(CResMgr::mainMenu::window::cascade::icon());
191 action->setShortcut(QKeySequence(CResMgr::mainMenu::window::cascade::accel));
192 action->setToolTip(tr("Cascade the open windows"));
193 a->addAction("cascade", action);
194
195 action = new QAction(a);
196 action->setText(tr("&Tile"));
197 action->setIcon(CResMgr::mainMenu::window::tile::icon());
198 action->setShortcut(QKeySequence(CResMgr::mainMenu::window::tile::accel));
199 action->setToolTip(tr("Tile the open windows"));
200 a->addAction("tile", action);
201
202 action = new QAction(a);
203 action->setText(tr("Tile &vertically"));
204 action->setIcon(CResMgr::mainMenu::window::tileVertical::icon());
205 action->setShortcut(QKeySequence(CResMgr::mainMenu::window::tileVertical::accel));
206 action->setToolTip(tr("Vertically tile (arrange side by side) the open windows"));
207 a->addAction("tileVertically", action);
208
209 action = new QAction(a);
210 action->setText(tr("Tile &horizontally"));
211 action->setIcon(CResMgr::mainMenu::window::tileHorizontal::icon());
212 action->setShortcut(QKeySequence(CResMgr::mainMenu::window::tileHorizontal::accel));
213 action->setToolTip(tr("Horizontally tile (arrange on top of each other) the open windows"));
214 a->addAction("tileHorizontally", action);
215
216 action = new QAction(a);
217 action->setText(tr("Close &window"));
218 action->setIcon(CResMgr::mainMenu::window::close::icon());
219 action->setShortcut(QKeySequence(CResMgr::mainMenu::window::close::accel));
220 action->setToolTip(tr("Close the current open window"));
221 a->addAction("closeWindow", action);
222
223 action = new QAction(a);
224 action->setText(tr("Cl&ose all windows"));
225 action->setIcon(CResMgr::mainMenu::window::closeAll::icon());
226 action->setShortcut(QKeySequence(CResMgr::mainMenu::window::closeAll::accel));
227 action->setToolTip(tr("Close all open windows inside BibleTime"));
228 a->addAction("closeAllWindows", action);
229
230 action = new QAction(a);
231 action->setText(tr("&Configure BibleTime..."));
232 action->setIcon(CResMgr::mainMenu::settings::configureDialog::icon());
233 action->setToolTip(tr("Set BibleTime's preferences"));
234 a->addAction("setPreferences", action);
235
236 action = new QAction(a);
237 action->setText(tr("Bookshelf Manager..."));
238 action->setIcon(CResMgr::mainMenu::settings::swordSetupDialog::icon());
239 action->setShortcut(QKeySequence(CResMgr::mainMenu::settings::swordSetupDialog::accel));
240 action->setToolTip(tr("Configure your bookshelf and install/update/remove/index works"));
241 a->addAction("bookshelfWizard", action);
242
243 action = new QAction(a);
244 action->setText(tr("&Handbook"));
245 action->setIcon(CResMgr::mainMenu::help::handbook::icon());
246 action->setShortcut(QKeySequence(CResMgr::mainMenu::help::handbook::accel));
247 action->setToolTip(tr("Open BibleTime's handbook"));
248 a->addAction("openHandbook", action);
249
250 action = new QAction(a);
251 action->setText(tr("&Bible Study Howto"));
252 action->setIcon(CResMgr::mainMenu::help::bibleStudyHowTo::icon());
253 action->setShortcut(QKeySequence(CResMgr::mainMenu::help::bibleStudyHowTo::accel));
254 action->setToolTip(tr("Open the Bible study HowTo included with BibleTime.<br/>This HowTo is an introduction on how to study the Bible in an efficient way."));
255 a->addAction("bibleStudyHowto", action);
256
257 action = new QAction(a);
258 action->setText(tr("&About BibleTime"));
259 action->setIcon(CResMgr::mainMenu::help::aboutBibleTime::icon());
260 action->setToolTip(tr("Information about the BibleTime program"));
261 a->addAction("aboutBibleTime", action);
262
263 action = new QAction(a);
264 action->setText(tr("&Tip of the day..."));
265 action->setIcon(CResMgr::mainMenu::help::tipOfTheDay::icon());
266 action->setShortcut(QKeySequence(CResMgr::mainMenu::help::tipOfTheDay::accel));
267 action->setToolTip(tr("Show tips about BibleTime"));
268 a->addAction("tipOfTheDay", action);
269
270 action = new QAction(a);
271 a->addAction("showToolbarsInTextWindows", action);
272
273 action = new QAction(a);
274 a->addAction("showNavigation", action);
275
276 action = new QAction(a);
277 a->addAction("showWorks", action);
278
279 action = new QAction(a);
280 a->addAction("showTools", action);
281
282 action = new QAction(a);
283 a->addAction("showFormat", action);
284
285 action = new QAction(a);
286 a->addAction("showParallelTextHeaders", action);
287
288 action = new QAction(a);
289 a->addAction("showBookshelf", action);
290
291 action = new QAction(a);
292 a->addAction("showBookmarks", action);
293
294 action = new QAction(a);
295 a->addAction("showMag", action);
296
297 retranslateUiActions(a);
298 }
299
createToolBar(const QString & name,QWidget * parent,bool visible)300 static QToolBar* createToolBar(const QString& name, QWidget* parent, bool visible) {
301 QToolBar* bar = new QToolBar(parent);
302 bar->setObjectName(name);
303 bar->setFloatable(false);
304 bar->setMovable(true);
305 bar->setVisible(visible);
306 return bar;
307 }
308
clearMdiToolBars()309 void BibleTime::clearMdiToolBars() {
310 // Clear main window toolbars
311 m_navToolBar->clear();
312 m_worksToolBar->clear();
313 m_toolsToolBar->clear();
314 m_formatToolBar->clear();
315 }
316
keyChooser() const317 CKeyChooser* BibleTime::keyChooser() const {
318 BT_ASSERT(m_navToolBar);
319
320 CKeyChooser* keyChooser = m_navToolBar->findChild<CKeyChooser*>();
321 return keyChooser;
322 }
323
createMenuAndToolBar()324 void BibleTime::createMenuAndToolBar()
325 {
326 // Create menubar
327 menuBar();
328
329 m_mainToolBar = createToolBar("MainToolBar", this, true);
330 addToolBar(m_mainToolBar);
331
332 // Set visibility of main window toolbars based on config
333 bool visible = ! btConfig().sessionValue<bool>("GUI/showToolbarsInEachWindow", true);
334
335 m_navToolBar = createToolBar("NavToolBar", this, visible);
336 addToolBar(m_navToolBar);
337
338 m_worksToolBar = new BtModuleChooserBar(this);
339 m_worksToolBar->setObjectName("WorksToolBar");
340 m_worksToolBar->setVisible(visible);
341 addToolBar(m_worksToolBar);
342
343 m_toolsToolBar = createToolBar("ToolsToolBar", this, visible);
344 addToolBar(m_toolsToolBar);
345
346 m_formatToolBar = createToolBar("FormatToolBar", this, visible);
347 addToolBar(m_formatToolBar);
348 }
349
createCentralWidget()350 void BibleTime::createCentralWidget()
351 {
352 m_mdi = new CMDIArea(this);
353 m_findWidget = new BtFindWidget(this);
354 m_findWidget->setVisible(false);
355
356 QVBoxLayout* layout = new QVBoxLayout();
357 QMargins margins(0, 0, 0, 0);
358 layout->setContentsMargins(margins);
359 layout->addWidget(m_mdi);
360 layout->addWidget(m_findWidget);
361
362 QWidget* widget = new QWidget(this);
363 widget->setLayout(layout);
364 setCentralWidget(widget);
365
366 BT_CONNECT(m_findWidget, SIGNAL(findNext(QString const &,bool)),
367 m_mdi, SLOT(findNextTextInActiveWindow(QString const &, bool)));
368
369 BT_CONNECT(m_findWidget, SIGNAL(findPrevious(QString const &,bool)),
370 m_mdi,
371 SLOT(findPreviousTextInActiveWindow(QString const &, bool)));
372
373 BT_CONNECT(m_findWidget, SIGNAL(highlightText(QString const &,bool)),
374 m_mdi, SLOT(highlightTextInActiveWindow(QString const &, bool)));
375
376 BT_CONNECT(m_mdi, SIGNAL(subWindowActivated(QMdiSubWindow *)),
377 this, SLOT(slotActiveWindowChanged(QMdiSubWindow *)));
378 }
379
380 /** Initializes the action objects of the GUI */
initActions()381 void BibleTime::initActions() {
382 m_actionCollection = new BtActionCollection(this);
383 insertKeyboardActions(m_actionCollection);
384
385 // Create the window to signal mapper and connect it up:
386 m_windowMapper = new QSignalMapper(this);
387 BT_CONNECT(m_windowMapper, SIGNAL(mapped(QWidget *)),
388 this, SLOT(slotSetActiveSubWindow(QWidget *)));
389
390 // File menu actions:
391 m_openWorkAction = new BtOpenWorkAction("GUI/mainWindow/openWorkAction/grouping", this);
392 BT_CONNECT(m_openWorkAction, SIGNAL(triggered(CSwordModuleInfo *)),
393 this, SLOT(createReadDisplayWindow(CSwordModuleInfo *)));
394
395 m_quitAction = &m_actionCollection->action("quit");
396 m_quitAction->setMenuRole(QAction::QuitRole);
397 BT_CONNECT(m_quitAction, SIGNAL(triggered()),
398 this, SLOT(quit()));
399
400
401 // View menu actions:
402 m_windowFullscreenAction = &m_actionCollection->action("toggleFullscreen");
403 m_windowFullscreenAction->setCheckable(true);
404 BT_CONNECT(m_windowFullscreenAction, SIGNAL(triggered()),
405 this, SLOT(toggleFullscreen()));
406
407 // Special case these actions, overwrite those already in collection
408 m_showBookshelfAction = m_bookshelfDock->toggleViewAction();
409 m_showBookshelfAction->setIcon(CResMgr::mainMenu::view::showBookshelf::icon());
410 m_showBookshelfAction->setToolTip(tr("Toggle visibility of the bookshelf window"));
411 m_actionCollection->removeAction("showBookshelf");
412 m_actionCollection->addAction("showBookshelf", m_showBookshelfAction);
413 m_showBookmarksAction = m_bookmarksDock->toggleViewAction();
414 m_showBookmarksAction->setIcon(CResMgr::mainMenu::view::showBookmarks::icon());
415 m_showBookmarksAction->setToolTip(tr("Toggle visibility of the bookmarks window"));
416 m_actionCollection->removeAction("showBookmarks");
417 m_actionCollection->addAction("showBookmarks", m_showBookmarksAction);
418 m_showMagAction = m_magDock->toggleViewAction();
419 m_showMagAction->setIcon(CResMgr::mainMenu::view::showMag::icon());
420 m_showMagAction->setToolTip(tr("Toggle visibility of the mag window"));
421 m_actionCollection->removeAction("showMag");
422 m_actionCollection->addAction("showMag", m_showMagAction);
423
424 m_showTextAreaHeadersAction =
425 &m_actionCollection->action("showParallelTextHeaders");
426 m_showTextAreaHeadersAction->setCheckable(true);
427 m_showTextAreaHeadersAction->setChecked(btConfig().sessionValue<bool>("GUI/showTextWindowHeaders", true));
428 BT_CONNECT(m_showTextAreaHeadersAction, SIGNAL(toggled(bool)),
429 this, SLOT(slotToggleTextWindowHeader()));
430
431 m_showMainWindowToolbarAction = &m_actionCollection->action("showToolbar");
432 m_showMainWindowToolbarAction->setCheckable(true);
433 m_showMainWindowToolbarAction->setChecked(btConfig().sessionValue<bool>("GUI/showMainToolbar", true));
434 BT_CONNECT(m_showMainWindowToolbarAction, SIGNAL(triggered()),
435 this, SLOT(slotToggleMainToolbar()));
436
437 m_showTextWindowNavigationAction =
438 &m_actionCollection->action("showNavigation");
439 m_showTextWindowNavigationAction->setCheckable(true);
440 m_showTextWindowNavigationAction->setChecked(btConfig().sessionValue<bool>("GUI/showTextWindowNavigator", true));
441 BT_CONNECT(m_showTextWindowNavigationAction, SIGNAL(toggled(bool)),
442 this, SLOT(slotToggleNavigatorToolbar()));
443
444 m_showTextWindowModuleChooserAction =
445 &m_actionCollection->action("showWorks");
446 m_showTextWindowModuleChooserAction->setCheckable(true);
447 m_showTextWindowModuleChooserAction->setChecked(btConfig().sessionValue<bool>("GUI/showTextWindowModuleSelectorButtons", true));
448 BT_CONNECT(m_showTextWindowModuleChooserAction, SIGNAL(toggled(bool)),
449 this, SLOT(slotToggleWorksToolbar()));
450
451 m_showTextWindowToolButtonsAction =
452 &m_actionCollection->action("showTools");
453 m_showTextWindowToolButtonsAction->setCheckable(true);
454 m_showTextWindowToolButtonsAction->setChecked(btConfig().sessionValue<bool>("GUI/showTextWindowToolButtons", true));
455 BT_CONNECT(m_showTextWindowToolButtonsAction, SIGNAL(toggled(bool)),
456 this, SLOT(slotToggleToolsToolbar()));
457
458 m_showFormatToolbarAction = &m_actionCollection->action("showFormat");
459 m_showFormatToolbarAction->setCheckable(true);
460 m_showFormatToolbarAction->setChecked(btConfig().sessionValue<bool>("GUI/showFormatToolbarButtons", true));
461 BT_CONNECT(m_showFormatToolbarAction, SIGNAL(toggled(bool)),
462 this, SLOT(slotToggleFormatToolbar()));
463
464 m_toolbarsInEachWindow =
465 &m_actionCollection->action("showToolbarsInTextWindows");
466 m_toolbarsInEachWindow->setCheckable(true);
467 m_toolbarsInEachWindow->setChecked(btConfig().sessionValue<bool>("GUI/showToolbarsInEachWindow", true));
468 BT_CONNECT(m_toolbarsInEachWindow, SIGNAL(toggled(bool)),
469 this, SLOT(slotToggleToolBarsInEachWindow()));
470
471 // Search menu actions:
472 m_searchOpenWorksAction = &m_actionCollection->action("searchOpenWorks");
473 BT_CONNECT(m_searchOpenWorksAction, SIGNAL(triggered()),
474 this, SLOT(slotSearchModules()));
475
476 m_searchStandardBibleAction = &m_actionCollection->action("searchStdBible");
477 BT_CONNECT(m_searchStandardBibleAction, SIGNAL(triggered()),
478 this, SLOT(slotSearchDefaultBible()));
479
480 // Window menu actions:
481 m_windowCloseAction = &m_actionCollection->action("closeWindow");
482 BT_CONNECT(m_windowCloseAction, SIGNAL(triggered()),
483 m_mdi, SLOT(closeActiveSubWindow()));
484
485 m_windowCloseAllAction = &m_actionCollection->action("closeAllWindows");
486 BT_CONNECT(m_windowCloseAllAction, SIGNAL(triggered()),
487 m_mdi, SLOT(closeAllSubWindows()));
488
489 m_windowCascadeAction = &m_actionCollection->action("cascade");
490 BT_CONNECT(m_windowCascadeAction, SIGNAL(triggered()),
491 this, SLOT(slotCascade()));
492
493 m_windowTileAction = &m_actionCollection->action("tile");
494 BT_CONNECT(m_windowTileAction, SIGNAL(triggered()),
495 this, SLOT(slotTile()));
496
497 m_windowTileVerticalAction = &m_actionCollection->action("tileVertically");
498 BT_CONNECT(m_windowTileVerticalAction, SIGNAL(triggered()),
499 this, SLOT(slotTileVertical()));
500
501 m_windowTileHorizontalAction =
502 &m_actionCollection->action("tileHorizontally");
503 BT_CONNECT(m_windowTileHorizontalAction, SIGNAL(triggered()),
504 this, SLOT(slotTileHorizontal()));
505
506 alignmentMode alignment = btConfig().sessionValue<alignmentMode>("GUI/alignmentMode", autoTileVertical);
507
508 m_windowManualModeAction = &m_actionCollection->action("manualArrangement");
509 m_windowManualModeAction->setCheckable(true);
510
511 m_windowAutoTabbedAction = &m_actionCollection->action("autoTabbed");
512 m_windowAutoTabbedAction->setCheckable(true);
513
514 //: Vertical tiling means that windows are vertical, placed side by side
515 m_windowAutoTileVerticalAction =
516 &m_actionCollection->action("autoVertical");
517 m_windowAutoTileVerticalAction->setCheckable(true);
518
519 //: Horizontal tiling means that windows are horizontal, placed on top of each other
520 m_windowAutoTileHorizontalAction =
521 &m_actionCollection->action("autoHorizontal");
522 m_windowAutoTileHorizontalAction->setCheckable(true);
523
524 m_windowAutoTileAction = &m_actionCollection->action("autoTile");
525 m_windowAutoTileAction->setCheckable(true);
526
527 m_windowAutoCascadeAction = &m_actionCollection->action("autoCascade");
528 m_windowAutoCascadeAction->setCheckable(true);
529
530 /*
531 * All actions related to arrangement modes have to be initialized before calling a slot on them,
532 * thus we call them afterwards now.
533 */
534 QAction * alignmentAction;
535 switch (alignment) {
536 case autoTabbed:
537 alignmentAction = m_windowAutoTabbedAction; break;
538 case autoTileVertical:
539 alignmentAction = m_windowAutoTileVerticalAction; break;
540 case autoTileHorizontal:
541 alignmentAction = m_windowAutoTileHorizontalAction; break;
542 case autoTile:
543 alignmentAction = m_windowAutoTileAction; break;
544 case autoCascade:
545 alignmentAction = m_windowAutoCascadeAction; break;
546 case manual:
547 default:
548 alignmentAction = m_windowManualModeAction; break;
549 }
550 alignmentAction->setChecked(true);
551 slotUpdateWindowArrangementActions(alignmentAction);
552
553 m_windowSaveToNewProfileAction =
554 &m_actionCollection->action("saveNewSession");
555 BT_CONNECT(m_windowSaveToNewProfileAction, SIGNAL(triggered()),
556 this, SLOT(saveToNewProfile()));
557
558 m_setPreferencesAction = &m_actionCollection->action("setPreferences");
559 m_setPreferencesAction->setMenuRole( QAction::PreferencesRole );
560 BT_CONNECT(m_setPreferencesAction, SIGNAL(triggered()),
561 this, SLOT(slotSettingsOptions()));
562
563 m_bookshelfWizardAction = &m_actionCollection->action("bookshelfWizard");
564 m_bookshelfWizardAction->setMenuRole( QAction::ApplicationSpecificRole );
565 BT_CONNECT(m_bookshelfWizardAction, SIGNAL(triggered()),
566 this, SLOT(slotBookshelfWizard()));
567
568 m_openHandbookAction = &m_actionCollection->action("openHandbook");
569 BT_CONNECT(m_openHandbookAction, SIGNAL(triggered()),
570 this, SLOT(openOnlineHelp_Handbook()));
571
572 m_bibleStudyHowtoAction = &m_actionCollection->action("bibleStudyHowto");
573 BT_CONNECT(m_bibleStudyHowtoAction, SIGNAL(triggered()),
574 this, SLOT(openOnlineHelp_Howto()));
575
576 m_aboutBibleTimeAction = &m_actionCollection->action("aboutBibleTime");
577 m_aboutBibleTimeAction->setMenuRole( QAction::AboutRole );
578 BT_CONNECT(m_aboutBibleTimeAction, SIGNAL(triggered()),
579 this, SLOT(slotOpenAboutDialog()) );
580
581 m_tipOfTheDayAction = &m_actionCollection->action("tipOfTheDay");
582 BT_CONNECT(m_tipOfTheDayAction, SIGNAL(triggered()),
583 this, SLOT(slotOpenTipDialog()) );
584
585 #ifndef NDEBUG
586 m_debugWidgetAction = new QAction(this);
587 m_debugWidgetAction->setCheckable(true);
588 BT_CONNECT(m_debugWidgetAction, &QAction::triggered,
589 this, &BibleTime::slotShowDebugWindow);
590 #endif
591
592 retranslateUiActions(m_actionCollection);
593 }
594
initMenubar()595 void BibleTime::initMenubar() {
596 // File menu:
597 m_fileMenu = new QMenu(this);
598 m_fileMenu->addAction(m_openWorkAction);
599 m_fileMenu->addSeparator();
600 m_fileMenu->addAction(m_quitAction);
601 menuBar()->addMenu(m_fileMenu);
602
603 // View menu:
604 m_viewMenu = new QMenu(this);
605 m_viewMenu->addAction(m_windowFullscreenAction);
606 m_viewMenu->addAction(m_showBookshelfAction);
607 m_viewMenu->addAction(m_showBookmarksAction);
608 m_viewMenu->addAction(m_showMagAction);
609 m_viewMenu->addAction(m_showTextAreaHeadersAction);
610 m_viewMenu->addSeparator();
611 m_toolBarsMenu = new QMenu(this);
612 m_toolBarsMenu->addAction( m_showMainWindowToolbarAction);
613 m_toolBarsMenu->addAction(m_showTextWindowNavigationAction);
614 m_toolBarsMenu->addAction(m_showTextWindowModuleChooserAction);
615 m_toolBarsMenu->addAction(m_showTextWindowToolButtonsAction);
616 m_toolBarsMenu->addAction(m_showFormatToolbarAction);
617 m_toolBarsMenu->addSeparator();
618 m_toolBarsMenu->addAction(m_toolbarsInEachWindow);
619 m_viewMenu->addMenu(m_toolBarsMenu);
620 menuBar()->addMenu(m_viewMenu);
621
622 // Search menu:
623 m_searchMenu = new QMenu(this);
624 m_searchMenu->addAction(m_searchOpenWorksAction);
625 m_searchMenu->addAction(m_searchStandardBibleAction);
626 menuBar()->addMenu(m_searchMenu);
627
628 // Window menu:
629 m_windowMenu = new QMenu(this);
630 m_openWindowsMenu = new QMenu(this);
631 BT_CONNECT(m_openWindowsMenu, SIGNAL(aboutToShow()),
632 this, SLOT(slotOpenWindowsMenuAboutToShow()));
633 m_windowMenu->addMenu(m_openWindowsMenu);
634 m_windowMenu->addAction(m_windowCloseAction);
635 m_windowMenu->addAction(m_windowCloseAllAction);
636 m_windowMenu->addSeparator();
637 m_windowMenu->addAction(m_windowCascadeAction);
638 m_windowMenu->addAction(m_windowTileAction);
639 m_windowMenu->addAction(m_windowTileVerticalAction);
640 m_windowMenu->addAction(m_windowTileHorizontalAction);
641 m_windowArrangementMenu = new QMenu(this);
642 m_windowArrangementActionGroup = new QActionGroup(m_windowArrangementMenu);
643 m_windowArrangementMenu->addAction(m_windowManualModeAction);
644 m_windowArrangementActionGroup->addAction(m_windowManualModeAction);
645 m_windowArrangementMenu->addAction(m_windowAutoTabbedAction);
646 m_windowArrangementActionGroup->addAction(m_windowAutoTabbedAction);
647 m_windowArrangementMenu->addAction(m_windowAutoTileVerticalAction);
648 m_windowArrangementActionGroup->addAction(m_windowAutoTileVerticalAction);
649 m_windowArrangementMenu->addAction(m_windowAutoTileHorizontalAction);
650 m_windowArrangementActionGroup->addAction(m_windowAutoTileHorizontalAction);
651 m_windowArrangementMenu->addAction(m_windowAutoTileAction);
652 m_windowArrangementActionGroup->addAction(m_windowAutoTileAction);
653 m_windowArrangementMenu->addAction(m_windowAutoCascadeAction);
654 m_windowArrangementActionGroup->addAction(m_windowAutoCascadeAction);
655 BT_CONNECT(m_windowArrangementActionGroup, SIGNAL(triggered(QAction *)),
656 this, SLOT(slotUpdateWindowArrangementActions(QAction *)));
657
658 m_windowMenu->addMenu(m_windowArrangementMenu);
659 m_windowMenu->addSeparator();
660 m_windowMenu->addAction(m_windowSaveToNewProfileAction);
661 m_windowLoadProfileMenu = new QMenu(this);
662 m_windowLoadProfileActionGroup = new QActionGroup(m_windowLoadProfileMenu);
663 m_windowMenu->addMenu(m_windowLoadProfileMenu);
664 m_windowDeleteProfileMenu = new QMenu(this);
665 m_windowMenu->addMenu(m_windowDeleteProfileMenu);
666 BT_CONNECT(m_windowLoadProfileMenu, SIGNAL(triggered(QAction *)),
667 this, SLOT(loadProfile(QAction *)));
668 BT_CONNECT(m_windowDeleteProfileMenu, SIGNAL(triggered(QAction *)),
669 this, SLOT(deleteProfile(QAction *)));
670 refreshProfileMenus();
671 menuBar()->addMenu(m_windowMenu);
672 BT_CONNECT(m_windowMenu, SIGNAL(aboutToShow()),
673 this, SLOT(slotWindowMenuAboutToShow()));
674
675 #ifndef Q_OS_MAC
676 m_settingsMenu = new QMenu(this);
677 m_settingsMenu->addAction(m_setPreferencesAction);
678 m_settingsMenu->addSeparator();
679 m_settingsMenu->addAction(m_bookshelfWizardAction);
680 menuBar()->addMenu(m_settingsMenu);
681 #else
682 // On MAC OS, the settings actions will be moved to a system menu item.
683 // Therefore the settings menu would be empty, so we do not show it.
684 m_fileMenu->addAction(m_setPreferencesAction);
685 m_fileMenu->addAction(m_bookshelfWizardAction);
686 #endif
687
688 // Help menu:
689 m_helpMenu = new QMenu(this);
690 m_helpMenu->addAction(m_openHandbookAction);
691 m_helpMenu->addAction(m_bibleStudyHowtoAction);
692 m_helpMenu->addAction(m_tipOfTheDayAction);
693 m_helpMenu->addSeparator();
694 m_helpMenu->addAction(m_aboutBibleTimeAction);
695 #ifndef NDEBUG
696 m_helpMenu->addSeparator();
697 m_helpMenu->addAction(m_debugWidgetAction);
698 #endif
699 menuBar()->addMenu(m_helpMenu);
700 }
701
initToolbars()702 void BibleTime::initToolbars() {
703 QToolButton *openWorkButton = new QToolButton(this);
704 openWorkButton->setDefaultAction(m_openWorkAction);
705 openWorkButton->setPopupMode(QToolButton::InstantPopup);
706 m_mainToolBar->addWidget(openWorkButton);
707
708 m_mainToolBar->addAction(m_windowFullscreenAction);
709 m_mainToolBar->addAction(&m_actionCollection->action("showBookshelf"));
710 m_mainToolBar->addAction(&m_actionCollection->action("showBookmarks"));
711 m_mainToolBar->addAction(&m_actionCollection->action("showMag"));
712 m_mainToolBar->addAction(m_searchOpenWorksAction);
713 m_mainToolBar->addAction(m_openHandbookAction);
714 }
715
retranslateUi()716 void BibleTime::retranslateUi() {
717 m_bookmarksDock->setWindowTitle(tr("Bookmarks"));
718 m_magDock->setWindowTitle(tr("Mag"));
719 m_mainToolBar->setWindowTitle(tr("Main toolbar"));
720 m_navToolBar->setWindowTitle(tr("Navigation toolbar"));
721 m_worksToolBar->setWindowTitle(tr("Works toolbar"));
722 m_toolsToolBar->setWindowTitle(tr("Tools toolbar"));
723 m_formatToolBar->setWindowTitle(tr("Format toolbar"));
724
725 m_fileMenu->setTitle(tr("&File"));
726 m_viewMenu->setTitle(tr("&View"));
727 m_toolBarsMenu->setTitle(tr("Toolbars"));
728
729 m_searchMenu->setTitle(tr("&Search"));
730 m_windowMenu->setTitle(tr("&Window"));
731 m_openWindowsMenu->setTitle(tr("O&pen windows"));
732 m_windowArrangementMenu->setTitle(tr("&Arrangement mode"));
733 m_windowLoadProfileMenu->setTitle(tr("Sw&itch session"));
734 m_windowDeleteProfileMenu->setTitle(tr("&Delete session"));
735
736 #ifndef Q_OS_MAC
737 // This item is not present on Mac OS
738 m_settingsMenu->setTitle(tr("Se&ttings"));
739 #endif
740
741 m_helpMenu->setTitle(tr("&Help"));
742
743 #ifndef NDEBUG
744 m_debugWidgetAction->setText(tr("Show \"Whats this widget\" dialog"));
745 #endif
746
747 retranslateUiActions(m_actionCollection);
748 }
749
750 /** retranslation for actions used in this class
751 * This is called for two different collections of actions
752 * One set is for the actual use in the menus, etc
753 * The second is used during the use of the configuration shortcut editor
754 */
retranslateUiActions(BtActionCollection * ac)755 void BibleTime::retranslateUiActions(BtActionCollection* ac) {
756 ac->action("showToolbarsInTextWindows")
757 .setText(tr("Show toolbars in text windows"));
758 ac->action("showToolbar").setText(tr("Show main toolbar"));
759 ac->action("showNavigation").setText(tr("Show navigation bar"));
760 ac->action("showWorks").setText(tr("Show works toolbar"));
761 ac->action("showTools").setText(tr("Show tools toolbar"));
762 ac->action("showFormat").setText(tr("Show formatting toolbar"));
763 ac->action("showBookshelf").setText(tr("Show bookshelf"));
764 ac->action("showBookmarks").setText(tr("Show bookmarks"));
765 ac->action("showMag").setText(tr("Show mag"));
766 ac->action("showParallelTextHeaders")
767 .setText(tr("Show parallel text headers"));
768 }
769
770 /** Initializes the SIGNAL / SLOT connections */
initConnections()771 void BibleTime::initConnections() {
772 // Bookmarks page connections:
773 BT_CONNECT(m_bookmarksPage,
774 SIGNAL(createReadDisplayWindow(QList<CSwordModuleInfo *>,
775 QString const &)),
776 this,
777 SLOT(createReadDisplayWindow(QList<CSwordModuleInfo *>,
778 QString const &)));
779
780 // Bookshelf dock connections:
781 BT_CONNECT(m_bookshelfDock, SIGNAL(moduleOpenTriggered(CSwordModuleInfo *)),
782 this, SLOT(createReadDisplayWindow(CSwordModuleInfo *)));
783 BT_CONNECT(m_bookshelfDock,
784 SIGNAL(moduleSearchTriggered(CSwordModuleInfo *)),
785 this, SLOT(searchInModule(CSwordModuleInfo *)));
786 BT_CONNECT(m_bookshelfDock,
787 SIGNAL(moduleEditPlainTriggered(CSwordModuleInfo *)),
788 this, SLOT(moduleEditPlain(CSwordModuleInfo *)));
789 BT_CONNECT(m_bookshelfDock,
790 SIGNAL(moduleEditHtmlTriggered(CSwordModuleInfo *)),
791 this, SLOT(moduleEditHtml(CSwordModuleInfo *)));
792 BT_CONNECT(m_bookshelfDock,
793 SIGNAL(moduleUnlockTriggered(CSwordModuleInfo *)),
794 this, SLOT(slotModuleUnlock(CSwordModuleInfo *)));
795 BT_CONNECT(m_bookshelfDock,
796 SIGNAL(moduleAboutTriggered(CSwordModuleInfo *)),
797 this, SLOT(moduleAbout(CSwordModuleInfo *)));
798 }
799
initSwordConfigFile()800 void BibleTime::initSwordConfigFile() {
801 // On Windows the sword.conf must be created before the initialization of sword
802 // It will contain the LocalePath which is used for sword locales
803 // It also contains a DataPath to the %ProgramData%\Sword directory
804 // If this is not done here, the sword locales.d won't be found
805 #ifdef Q_OS_WIN
806 QString configFile = util::directory::getUserHomeSwordDir().filePath("sword.conf");
807 QFile file(configFile);
808 if (file.exists()) {
809 return;
810 }
811 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
812 return;
813 }
814 QTextStream out(&file);
815 out << "\n";
816 out << "[Install]\n";
817 out << "DataPath=" << util::directory::convertDirSeparators( util::directory::getSharedSwordDir().absolutePath()) << "\n";
818 out << "LocalePath=" << util::directory::convertDirSeparators(util::directory::getApplicationSwordDir().absolutePath()) << "\n";
819 out << "\n";
820 file.close();
821 #endif
822
823 #ifdef Q_OS_MAC
824 QString configFile = util::directory::getUserHomeSwordDir().filePath("sword.conf");
825 QFile file(configFile);
826 if (file.exists()) {
827 return;
828 }
829 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
830 return;
831 }
832 QTextStream out(&file);
833 out << "\n";
834 out << "[Install]\n";
835 out << "DataPath=" << util::directory::convertDirSeparators( util::directory::getUserHomeSwordDir().absolutePath()) << "\n";
836 out << "\n";
837 file.close();
838 #endif
839 }
840
841 /** Initializes the backend */
initBackends()842 void BibleTime::initBackends() {
843 initSwordConfigFile();
844
845 if (!sword::SWMgr::isICU)
846 sword::StringMgr::setSystemStringMgr(new BtStringMgr());
847
848 sword::SWLog::getSystemLog()->setLogLevel(btApp->debugMode()
849 ? sword::SWLog::LOG_DEBUG
850 : sword::SWLog::LOG_ERROR);
851
852 #ifdef Q_OS_MAC
853 // set a LocaleMgr with a fixed path to the locales.d of the DMG image on MacOS
854 // note: this must be done after setting the BTStringMgr, because this will reset the LocaleMgr
855 qDebug() << "Using sword locales dir: " << util::directory::getSwordLocalesDir().absolutePath().toUtf8();
856 sword::LocaleMgr::setSystemLocaleMgr(new sword::LocaleMgr(util::directory::getSwordLocalesDir().absolutePath().toUtf8()));
857 #endif
858
859 /*
860 Set book names language if not set. This is a hack. We do this call here,
861 because we need to keep the setting displayed in BtLanguageSettingsPage in
862 sync with the language of the book names displayed, so that both would
863 always use the same setting.
864 */
865 CDisplaySettingsPage::resetLanguage(); /// \todo refactor this hack
866
867
868 CSwordBackend *backend = CSwordBackend::createInstance();
869 backend->booknameLanguage(btConfig().value<QString>("GUI/booknameLanguage", QLocale::system().name()));
870
871 CSwordBackend::instance()->initModules(CSwordBackend::OtherChange);
872
873 // This function will
874 // - delete all orphaned indexes (no module present) if autoDeleteOrphanedIndices is true
875 // - delete all indices of modules where hasIndex() returns false
876 backend->deleteOrphanedIndices();
877
878 }
879
880 #ifndef NDEBUG
881
882 QLabel *BibleTime::m_debugWindow = nullptr;
883 QMutex BibleTime::m_debugWindowLock;
884
slotShowDebugWindow(bool show)885 void BibleTime::slotShowDebugWindow(bool show) {
886 if (show) {
887 QMutexLocker lock(&m_debugWindowLock);
888 if (m_debugWindow == nullptr) {
889 m_debugWindow = new QLabel(nullptr, Qt::Dialog);
890 m_debugWindow->setAttribute(Qt::WA_DeleteOnClose);
891 m_debugWindow->setTextFormat(Qt::RichText);
892 m_debugWindow->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
893 m_debugWindow->setWindowTitle(tr("Whats this widget?"));
894 }
895 m_debugWindow->show();
896 BT_CONNECT(m_debugWindow, &QObject::destroyed,
897 this, &BibleTime::slotDebugWindowClosing,
898 Qt::DirectConnection);
899 #if QT_VERSION < 0x050400
900 QTimer::singleShot(0, this, SLOT(slotDebugTimeout()));
901 #else
902 QTimer::singleShot(0, this, &BibleTime::slotDebugTimeout);
903 #endif
904 } else {
905 deleteDebugWindow();
906 }
907 }
908
deleteDebugWindow()909 void BibleTime::deleteDebugWindow() {
910 QMutexLocker lock(&m_debugWindowLock);
911 if (m_debugWindow != nullptr) {
912 disconnect(m_debugWindow, &QObject::destroyed,
913 this, &BibleTime::slotDebugWindowClosing);
914 delete m_debugWindow;
915 m_debugWindow = nullptr;
916 }
917 }
918
slotDebugWindowClosing()919 void BibleTime::slotDebugWindowClosing() {
920 QMutexLocker lock(&m_debugWindowLock);
921 m_debugWindow = nullptr;
922 m_debugWidgetAction->setChecked(false);
923 }
924
slotDebugTimeout()925 void BibleTime::slotDebugTimeout() {
926 QMutexLocker lock(&m_debugWindowLock);
927 if (!m_debugWindow || m_debugWindow->isVisible() == false)
928 return;
929 #if QT_VERSION < 0x050400
930 QTimer::singleShot(0, this, SLOT(slotDebugTimeout()));
931 #else
932 QTimer::singleShot(0, this, &BibleTime::slotDebugTimeout);
933 #endif
934 if (QObject const * w = QApplication::widgetAt(QCursor::pos())) {
935 QString objectHierarchy;
936 do {
937 QMetaObject const * m = w->metaObject();
938 QString classHierarchy;
939 do {
940 if (!classHierarchy.isEmpty())
941 classHierarchy += ": ";
942 classHierarchy += m->className();
943 m = m->superClass();
944 } while (m);
945 if (!objectHierarchy.isEmpty()) {
946 objectHierarchy += "<br/><b>child of:</b> ";
947 } else {
948 objectHierarchy += "<b>This widget is:</b> ";
949 }
950 objectHierarchy += classHierarchy;
951 w = w->parent();
952 } while (w);
953 m_debugWindow->setText(objectHierarchy);
954 } else {
955 m_debugWindow->setText("No widget");
956 }
957 m_debugWindow->resize(m_debugWindow->minimumSizeHint());
958 }
959
960 #endif
961