Make bible integration into a dynamically loaded plugin.
[kworship.git] / kworship / bible / KwBiblePlugin.cpp
blob715dd942034f79d0db5e572ce25d38c1fac29374
1 /***************************************************************************
2 * This file is part of KWorship. *
3 * Copyright 2008 James Hogan <james@albanarts.com> *
4 * *
5 * KWorship is free software: you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation, either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * KWorship is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with KWorship. If not, write to the Free Software Foundation, *
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ***************************************************************************/
20 /**
21 * @file KwBiblePlugin.cpp
22 * @brief Bibles plugin.
23 * @author James Hogan <james@albanarts.com>
26 #include "KwBiblePlugin.h"
27 #include <KwApplication.h>
28 #include <kworship.h>
29 #include <KwDocument.h>
31 #include "KwBibleManager.h"
32 #include "KwBibleManagerSword.h"
33 #include "KwBibleManagerBibleGateway.h"
34 #include "KwBibleModule.h"
35 #include "KwBiblePlaylistItem.h"
37 #include <KwPlaylistModel.h>
39 #include <KLocale>
40 #include <KAction>
41 #include <KMessageBox>
42 #include <KGenericFactory>
44 #include <QMainWindow>
45 #include <QDockWidget>
46 #include <QHBoxLayout>
47 #include <QVBoxLayout>
48 #include <QComboBox>
49 #include <QLabel>
50 #include <QLineEdit>
51 #include <QTextEdit>
52 #include <QToolBar>
54 K_EXPORT_COMPONENT_FACTORY( kworship_bible, KGenericFactory<KwBiblePlugin>("kworship_bible") )
57 * Constructors + destructor
60 /// Default constructor.
61 KwBiblePlugin::KwBiblePlugin(const QObject* parent, const QStringList& params)
62 : KwPlugin("bible",
63 i18n("Bible"),
64 i18n("The bible plugin allows for the navigation and display of "
65 "bible extracts from SWORD and BibleGateway.com."))
66 , m_managers()
67 , m_insertIntoPlaylistAction(0)
68 , m_showNowAction(0)
69 , m_docker(0)
70 , m_managerTabs(0)
71 , m_comboBook(0)
72 , m_comboChapter(0)
73 , m_editRange(0)
74 , m_textPassage(0)
76 KwBibleManagerSword::registerManager();
77 KwBibleManagerBibleGateway::registerManager();
80 /// Destructor.
81 KwBiblePlugin::~KwBiblePlugin()
83 // Ensure all GUI stuff is cleaned up
84 KwBiblePlugin::_unload();
88 * Accessors
91 /// Get the current bible passage information.
92 bool KwBiblePlugin::resolvePassage(KwBibleManager** manager, KwBibleModule** module, KwBibleModule::Key* key, bool* usedSearch) const
94 // Get the current bible manager
95 int tab = m_managerTabs->currentIndex();
96 if (tab >= 0 && tab < m_managers.size())
98 const BibleManager& mgr = m_managers[tab];
99 *manager = mgr.manager;
101 // Is a bible selected?
102 int bibleInd = mgr.comboBibles->currentIndex();
103 QString bible;
104 KwBibleModule* mod = 0;
105 if (bibleInd >= 0)
107 QString bible = mgr.comboBibles->itemData(bibleInd).toString();
108 mod = mgr.manager->module(bible);
110 if (0 != mod)
112 *module = mod;
113 // Is a book selected?
114 int bookIndex = m_comboBook->currentIndex();
115 int chapterIndex = -1;
116 if (bookIndex >= 0)
118 // Is a chapter selected?
119 chapterIndex = m_comboChapter->currentIndex();
122 bool valid;
123 KwBibleModule::Key relativeKey = mod->createKey(bookIndex, chapterIndex);
124 *key = mod->createKey(relativeKey, m_editRange->text(), &valid);
126 if (0 != usedSearch)
128 *usedSearch = true;
130 return valid;
133 if (0 != usedSearch)
135 *usedSearch = false;
137 return false;
141 * Private slots
144 /// Fired when the connect to bible button is pressed.
145 void KwBiblePlugin::slotConnect()
147 // Get the current bible manager
148 int tab = m_managerTabs->currentIndex();
149 Q_ASSERT(tab >= 0 && tab < m_managers.size());
150 BibleManager* mgr = &m_managers[tab];
152 // This will force the connection
153 fillBiblesList(mgr);
154 if (mgr->comboBibles->count() == 0)
156 KMessageBox::information(m_docker, i18n("No bibles found"));
158 else
160 mgr->comboBibles->setEnabled(true);
164 /// Fired when the bible is changed.
165 void KwBiblePlugin::slotBibleChanged()
167 // Get the current bible manager
168 int tab = m_managerTabs->currentIndex();
169 if (tab >= 0 && tab < m_managers.size())
171 BibleManager& mgr = m_managers[tab];
172 bool enabled = mgr.comboBibles->isEnabled();
174 // Is a bible selected?
175 int bibleInd = mgr.comboBibles->currentIndex();
176 QString bible;
177 KwBibleModule* module = 0;
178 if (bibleInd >= 0)
180 QString bible = mgr.comboBibles->itemData(bibleInd).toString();
181 module = mgr.manager->module(bible);
184 // Update the list of books
185 QString book = m_comboBook->currentText();
186 int chapter = m_comboChapter->currentIndex();
187 m_comboBook->clear();
188 if (0 != module)
190 QStringList bookNames = module->books();
191 for (int i = 0; i < bookNames.size(); ++i)
193 const QString& bookName = bookNames[i];
194 m_comboBook->addItem(bookName, QVariant(i));
196 int index = m_comboBook->findText(book);
197 bool canPreserveBook = (index >= 0);
198 if (!canPreserveBook && bookNames.size() > 0)
200 index = 0;
202 m_comboBook->setCurrentIndex(index);
203 if (canPreserveBook && chapter >= 0)
205 // If we can restore book, also restore chapter
206 m_comboChapter->setCurrentIndex(chapter);
209 else
211 enabled = false;
214 m_comboBook->setEnabled(enabled);
215 m_comboChapter->setEnabled(enabled);
216 m_editRange->setEnabled(enabled);
220 /// Fired when the bible book is changed.
221 void KwBiblePlugin::slotBookChanged()
223 m_comboChapter->clear();
225 // Get the current bible manager
226 int tab = m_managerTabs->currentIndex();
227 if (tab >= 0 && tab < m_managers.size())
229 BibleManager& mgr = m_managers[tab];
231 // Is a bible selected?
232 int bibleInd = mgr.comboBibles->currentIndex();
233 QString bible;
234 KwBibleModule* module = 0;
235 if (bibleInd >= 0)
237 QString bible = mgr.comboBibles->itemData(bibleInd).toString();
238 module = mgr.manager->module(bible);
240 if (0 != module)
242 // Is a book selected?
243 int index = m_comboBook->currentIndex();
244 if (index >= 0)
246 int bookIndex = m_comboBook->itemData(index).toInt();
247 int numChapters = module->numChapters(bookIndex);
248 for (int i = 0; i < numChapters; ++i)
250 m_comboChapter->addItem(QString("%1").arg(i+1), QVariant(i));
255 slotVerseRange();
258 /// Fired when the bible text needs to be retrieved.
259 void KwBiblePlugin::slotVerseRange()
261 KwBibleManager* manager;
262 KwBibleModule* module;
263 KwBibleModule::Key key;
264 bool usedSearch;
265 bool success = resolvePassage(&manager, &module, &key, &usedSearch);
266 if (usedSearch)
268 m_comboBook->setCurrentIndex(key.start.book);
269 m_comboChapter->setCurrentIndex(key.start.chapter);
271 KwBiblePassage passage;
272 module->fillPassage(key, &passage);
273 m_textPassage->document()->setHtml(passage.renderedText());
275 m_insertIntoPlaylistAction->setEnabled(true);
276 m_showNowAction->setEnabled(true);
278 // Update color of search box
279 static QPalette p = m_editRange->palette();
280 QPalette changedPal = p;
281 if (!success)
283 changedPal.setColor( QPalette::Normal, QPalette::Base, QColor(255, 127, 127) );
285 m_editRange->setPalette(changedPal);
287 return;
289 m_textPassage->document()->setPlainText(QString());
290 m_insertIntoPlaylistAction->setEnabled(false);
291 m_showNowAction->setEnabled(false);
294 /// Fired by the insert into playlist action.
295 void KwBiblePlugin::slotInsertIntoPlaylist()
297 KwBibleManager* manager;
298 KwBibleModule* module;
299 KwBibleModule::Key key;
300 bool success = resolvePassage(&manager, &module, &key);
302 if (success)
304 KwBiblePlaylistItem* item = new KwBiblePlaylistItem(module, key);
305 KwPlaylistModel* model = KwApplication::self()->mainWindow()->playlistModel();
306 model->addItem(QModelIndex(), item);
310 /// Fired by the show now action.
311 void KwBiblePlugin::slotShowNow()
316 * Loading and unloading virtual interface
319 void KwBiblePlugin::_load()
321 // Construct the bible managers.
322 QStringList managerNames;
323 managerNames << "SWORD";
324 managerNames << "BibleGateway.com";
325 QList<KwBibleManager*> managers;
326 foreach (QString name, managerNames)
328 KwBibleManager* manager = KwBibleManagerSword::singleton(name);
329 if (0 != manager)
331 managers += manager;
335 // Set up the docker
336 m_docker = new QDockWidget(i18n("Bible"));
337 m_docker->setObjectName("dockBible");
338 QWidget* mainDockWidget = new QWidget(/*m_docker*/);
339 QVBoxLayout* dockLayout = new QVBoxLayout(mainDockWidget);
340 m_docker->setWidget(mainDockWidget);
342 // The tab bar of bible managers
343 m_managerTabs = new QTabWidget(m_docker);
344 m_managerTabs->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
345 connect(m_managerTabs, SIGNAL(currentChanged(int)),
346 this, SLOT(slotBibleChanged()));
347 dockLayout->addWidget(m_managerTabs);
349 // Bible navigation combo boxes
350 QWidget* bibleNavigationWidget = new QWidget(mainDockWidget);
351 QHBoxLayout* bibleNavigationLayout = new QHBoxLayout(bibleNavigationWidget);
352 dockLayout->addWidget(bibleNavigationWidget);
354 m_comboBook = new QComboBox(bibleNavigationWidget);
355 m_comboChapter = new QComboBox(bibleNavigationWidget);
356 bibleNavigationLayout->addWidget(m_comboBook);
357 bibleNavigationLayout->addWidget(m_comboChapter);
359 // Verse range text box and label
360 QWidget* verseRangeWidget = new QWidget(mainDockWidget);
361 QHBoxLayout* verseRangeLayout = new QHBoxLayout(verseRangeWidget);
362 dockLayout->addWidget(verseRangeWidget);
364 QLabel* labelRange = new QLabel(i18n("&Verses"), verseRangeWidget);
365 m_editRange = new QLineEdit(verseRangeWidget);
366 labelRange->setBuddy(m_editRange);
367 verseRangeLayout->addWidget(labelRange);
368 verseRangeLayout->addWidget(m_editRange);
370 m_textPassage = new QTextEdit(mainDockWidget);
371 m_textPassage->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
372 dockLayout->addWidget(m_textPassage);
374 // Toolbar
375 QToolBar* bibleToolBar = new QToolBar("bibleToolBar");
376 bibleToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
377 dockLayout->addWidget(bibleToolBar);
379 m_insertIntoPlaylistAction = new KAction(KIcon("player_playlist"), i18n("Insert Into Playlist"), bibleToolBar);
380 m_insertIntoPlaylistAction->setEnabled(false);
381 connect(m_insertIntoPlaylistAction, SIGNAL(triggered(bool)),
382 this, SLOT(slotInsertIntoPlaylist()));
383 bibleToolBar->addAction(m_insertIntoPlaylistAction);
385 m_showNowAction = new KAction(KIcon("player_playlist"), i18n("Show Now"), bibleToolBar);
386 m_showNowAction->setEnabled(false);
387 connect(m_showNowAction, SIGNAL(triggered(bool)),
388 this, SLOT(slotShowNow()));
389 bibleToolBar->addAction(m_showNowAction);
391 // Fill out tabs and manager data
392 foreach (KwBibleManager* manager, managers)
394 QString name = manager->name();
395 BibleManager mgr;
396 mgr.manager = manager;
398 QWidget* tabWidget = new QWidget();
399 QHBoxLayout* layout = new QHBoxLayout(tabWidget);
401 mgr.comboBibles = new QComboBox();
402 connect(mgr.comboBibles, SIGNAL(currentIndexChanged(int)),
403 this, SLOT(slotBibleChanged()));
405 // Only fill the module list if the manager is local
406 // Otherwise we should wait until the user requests it
407 if (manager->isRemote())
409 mgr.comboBibles->setEnabled(false);
411 mgr.toolBar = new QToolBar();
412 KAction* connectToBible = new KAction(KIcon("network-connect"), i18n("Connect to %1", name), mgr.toolBar);
413 connect(connectToBible, SIGNAL(triggered(bool)),
414 this, SLOT(slotConnect()));
415 mgr.toolBar->addAction(connectToBible);
416 layout->addWidget(mgr.toolBar);
418 // Toolbar should be as small as possible
419 QSizePolicy policy;
421 policy = mgr.toolBar->sizePolicy();
422 policy.setHorizontalStretch(1);
423 mgr.toolBar->setSizePolicy(policy);
425 policy = mgr.comboBibles->sizePolicy();
426 policy.setHorizontalStretch(10);
427 mgr.comboBibles->setSizePolicy(policy);
429 else
431 mgr.toolBar = 0;
432 fillBiblesList(&mgr);
435 layout->addWidget(mgr.comboBibles);
437 m_managerTabs->addTab(tabWidget, name);
438 m_managers.push_back(mgr);
440 // Ensure widgets are apropriately modified
441 connect(m_comboBook, SIGNAL(currentIndexChanged(int)),
442 this, SLOT(slotBookChanged()));
443 connect(m_comboChapter, SIGNAL(currentIndexChanged(int)),
444 this, SLOT(slotVerseRange()));
445 connect(m_editRange, SIGNAL(textChanged(const QString&)),
446 this, SLOT(slotVerseRange()));
448 KwApplication::self()->mainWindow()->addDockWidget(Qt::LeftDockWidgetArea, m_docker);
450 slotBibleChanged();
453 void KwBiblePlugin::_unload()
455 // Clean up the bible managers.
456 /// @todo IMPLEMENT!!!
457 delete m_docker;
461 * Private functions
464 /// Fill up the bibles list for a manager.
465 void KwBiblePlugin::fillBiblesList(BibleManager* mgr)
467 QStringList languages = mgr->manager->languages();
468 mgr->comboBibles->clear();
469 mgr->comboBibles->addItem(i18n("-- select a translation --"));
470 foreach (QString language, languages)
472 QStringList modules = mgr->manager->moduleNamesInLanguage(language);
473 if (!modules.isEmpty())
475 mgr->comboBibles->addItem(language, QVariant(modules.first()));
476 foreach (QString module, modules)
478 mgr->comboBibles->addItem(" " + module, QVariant(module));