BibleManager: add module fetch error checking
[kworship.git] / kworship / bible / KwBiblePlugin.cpp
blobe16ac7a6b4e39441e10198eb22d67ca6a9b73953
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 "KwBibleModule.h"
33 #include "KwBiblePlaylistItem.h"
35 #include <KwPlaylistModel.h>
37 #include <KLocale>
38 #include <KAction>
39 #include <KMessageBox>
40 #include <KGenericFactory>
41 #include <KServiceTypeTrader>
43 #include <QMainWindow>
44 #include <QDockWidget>
45 #include <QHBoxLayout>
46 #include <QVBoxLayout>
47 #include <QComboBox>
48 #include <QLabel>
49 #include <QLineEdit>
50 #include <QTextEdit>
51 #include <QToolBar>
53 K_EXPORT_COMPONENT_FACTORY( kworship_bible, KGenericFactory<KwBiblePlugin>("kworship_bible") )
56 * Constructors + destructor
59 /// Default constructor.
60 KwBiblePlugin::KwBiblePlugin(QObject* parent, const QStringList& params)
61 : KwPlugin(parent, "bible",
62 i18n("Bible"),
63 i18n("The bible plugin allows for the navigation and display of "
64 "bible extracts from various sources."))
65 , m_managers()
66 , m_insertIntoPlaylistAction(0)
67 , m_showNowAction(0)
68 , m_docker(0)
69 , m_managerTabs(0)
70 , m_comboBook(0)
71 , m_comboChapter(0)
72 , m_editRange(0)
73 , m_textPassage(0)
75 Q_UNUSED(params);
76 setXMLFile("bible/kworship_bibleui.rc");
79 /// Destructor.
80 KwBiblePlugin::~KwBiblePlugin()
85 * Accessors
88 /// Get the current bible passage information.
89 bool KwBiblePlugin::resolvePassage(KwBibleManager** manager, KwBibleModule** module, KwBibleModule::Key* key, bool* usedSearch) const
91 // Get the current bible manager
92 int tab = m_managerTabs->currentIndex();
93 if (tab >= 0 && tab < m_managers.size())
95 const BibleManager& mgr = m_managers[tab];
96 *manager = mgr.manager;
98 // Is a bible selected?
99 int bibleInd = mgr.comboBibles->currentIndex();
100 QString bible;
101 KwBibleModule* mod = 0;
102 if (bibleInd >= 0)
104 QString bible = mgr.comboBibles->itemData(bibleInd).toString();
105 mod = mgr.manager->module(bible);
107 if (0 != mod)
109 *module = mod;
110 // Is a book selected?
111 int bookIndex = m_comboBook->currentIndex();
112 int chapterIndex = -1;
113 if (bookIndex >= 0)
115 // Is a chapter selected?
116 chapterIndex = m_comboChapter->currentIndex()-1;
117 if (chapterIndex < 0)
119 return false;
123 bool valid;
124 KwBibleModule::Key relativeKey = mod->createKey(bookIndex, chapterIndex);
125 *key = mod->createKey(relativeKey, m_editRange->text(), &valid);
127 if (0 != usedSearch)
129 *usedSearch = true;
131 return valid;
134 if (0 != usedSearch)
136 *usedSearch = false;
138 return false;
142 * Private slots
145 /// Fired when the connect to bible button is pressed.
146 void KwBiblePlugin::slotConnect()
148 // Get the current bible manager
149 int tab = m_managerTabs->currentIndex();
150 Q_ASSERT(tab >= 0 && tab < m_managers.size());
151 BibleManager* mgr = &m_managers[tab];
153 // This will force the connection
154 fillBiblesList(mgr);
157 /// Fired when the bible is changed.
158 void KwBiblePlugin::slotBibleChanged()
160 // Get the current bible manager
161 int tab = m_managerTabs->currentIndex();
162 if (tab >= 0 && tab < m_managers.size())
164 BibleManager& mgr = m_managers[tab];
165 bool enabled = mgr.comboBibles->isEnabled();
167 // Is a bible selected?
168 int bibleInd = mgr.comboBibles->currentIndex();
169 QString bible;
170 KwBibleModule* module = 0;
171 if (bibleInd >= 0)
173 QString bible = mgr.comboBibles->itemData(bibleInd).toString();
174 module = mgr.manager->module(bible);
177 // Update the list of books
178 QString book = m_comboBook->currentText();
179 int chapter = m_comboChapter->currentIndex()-1;
180 m_comboBook->clear();
181 if (0 != module)
183 QStringList bookNames = module->books();
184 for (int i = 0; i < bookNames.size(); ++i)
186 const QString& bookName = bookNames[i];
187 m_comboBook->addItem(bookName, QVariant(i));
189 int index = m_comboBook->findText(book);
190 bool canPreserveBook = (index >= 0);
191 if (!canPreserveBook && bookNames.size() > 0)
193 index = 0;
195 m_comboBook->setCurrentIndex(index);
196 if (canPreserveBook && chapter >= 0)
198 // If we can restore book, also restore chapter
199 m_comboChapter->setCurrentIndex(chapter+1);
202 else
204 enabled = false;
207 m_comboBook->setEnabled(enabled);
208 m_comboChapter->setEnabled(enabled);
209 m_editRange->setEnabled(enabled);
213 /// Fired when the bible book is changed.
214 void KwBiblePlugin::slotBookChanged()
216 m_comboChapter->clear();
217 m_comboChapter->addItem(QString(), QVariant(-1));
219 // Get the current bible manager
220 int tab = m_managerTabs->currentIndex();
221 if (tab >= 0 && tab < m_managers.size())
223 BibleManager& mgr = m_managers[tab];
225 // Is a bible selected?
226 int bibleInd = mgr.comboBibles->currentIndex();
227 QString bible;
228 KwBibleModule* module = 0;
229 if (bibleInd >= 0)
231 QString bible = mgr.comboBibles->itemData(bibleInd).toString();
232 module = mgr.manager->module(bible);
234 if (0 != module)
236 // Is a book selected?
237 int index = m_comboBook->currentIndex();
238 if (index >= 0)
240 int bookIndex = m_comboBook->itemData(index).toInt();
241 int numChapters = module->numChapters(bookIndex);
242 for (int i = 0; i < numChapters; ++i)
244 m_comboChapter->addItem(QString("%1").arg(i+1), QVariant(i));
249 slotVerseRange();
252 /// Fired when the bible text needs to be retrieved.
253 void KwBiblePlugin::slotVerseRange()
255 KwBibleManager* manager;
256 KwBibleModule* module;
257 KwBibleModule::Key key;
258 bool usedSearch;
259 bool success = resolvePassage(&manager, &module, &key, &usedSearch);
260 if (usedSearch)
262 m_comboBook->setCurrentIndex(key.start.book);
263 m_comboChapter->setCurrentIndex(key.start.chapter+1);
265 KwBiblePassage passage;
266 module->fillPassage(key, &passage);
267 m_textPassage->document()->setHtml(passage.renderedText());
269 m_insertIntoPlaylistAction->setEnabled(true);
270 m_showNowAction->setEnabled(true);
272 // Update color of search box
273 static QPalette p = m_editRange->palette();
274 QPalette changedPal = p;
275 if (!success)
277 changedPal.setColor( QPalette::Normal, QPalette::Base, QColor(255, 127, 127) );
279 m_editRange->setPalette(changedPal);
281 return;
283 m_textPassage->document()->setPlainText(QString());
284 m_insertIntoPlaylistAction->setEnabled(false);
285 m_showNowAction->setEnabled(false);
288 /// Fired by the insert into playlist action.
289 void KwBiblePlugin::slotInsertIntoPlaylist()
291 KwBibleManager* manager;
292 KwBibleModule* module;
293 KwBibleModule::Key key;
294 bool success = resolvePassage(&manager, &module, &key);
296 if (success)
298 KwBiblePlaylistItem* item = new KwBiblePlaylistItem();
299 module->fillPassage(key, &item->passage());
300 KwPlaylistModel* model = KwApplication::self()->mainWindow()->playlistModel();
301 model->addItem(QModelIndex(), item);
305 /// Fired by the show now action.
306 void KwBiblePlugin::slotShowNow()
311 * Loading and unloading virtual interface
314 #include <QtDebug>
315 void KwBiblePlugin::_load()
317 // Construct the bible managers and put into a list.
318 // Have the local bible managers first in the list.
319 KService::List offers = KServiceTypeTrader::self()->query("KWorship/Bible");
320 QList<KwBibleManager*> managers;
321 QList<KwBibleManager*> remoteManagers;
322 foreach (KService::Ptr service, offers)
324 qDebug() << " Found KWorship bible backend: " << service->desktopEntryName();
325 QString err;
326 KwBibleManager* backend = service->createInstance<KwBibleManager>(this, QVariantList(), &err);
327 if (backend)
329 qDebug() << " Loaded successfully";
330 if (backend->isRemote())
332 remoteManagers += backend;
334 else
336 managers += backend;
339 else
341 qDebug() << " Could not be loaded: " << err;
344 managers += remoteManagers;
346 // Set up the docker
347 m_docker = new QDockWidget(i18n("Bible"));
348 m_docker->setObjectName("dockBible");
349 QWidget* mainDockWidget = new QWidget(/*m_docker*/);
350 QVBoxLayout* dockLayout = new QVBoxLayout(mainDockWidget);
351 m_docker->setWidget(mainDockWidget);
353 // The tab bar of bible managers
354 m_managerTabs = new QTabWidget(m_docker);
355 m_managerTabs->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
356 connect(m_managerTabs, SIGNAL(currentChanged(int)),
357 this, SLOT(slotBibleChanged()));
358 dockLayout->addWidget(m_managerTabs);
360 // Bible navigation combo boxes
361 QWidget* bibleNavigationWidget = new QWidget(mainDockWidget);
362 QHBoxLayout* bibleNavigationLayout = new QHBoxLayout(bibleNavigationWidget);
363 dockLayout->addWidget(bibleNavigationWidget);
365 m_comboBook = new QComboBox(bibleNavigationWidget);
366 m_comboChapter = new QComboBox(bibleNavigationWidget);
367 bibleNavigationLayout->addWidget(m_comboBook);
368 bibleNavigationLayout->addWidget(m_comboChapter);
370 // Verse range text box and label
371 QWidget* verseRangeWidget = new QWidget(mainDockWidget);
372 QHBoxLayout* verseRangeLayout = new QHBoxLayout(verseRangeWidget);
373 dockLayout->addWidget(verseRangeWidget);
375 QLabel* labelRange = new QLabel(i18n("&Verses"), verseRangeWidget);
376 m_editRange = new QLineEdit(verseRangeWidget);
377 labelRange->setBuddy(m_editRange);
378 verseRangeLayout->addWidget(labelRange);
379 verseRangeLayout->addWidget(m_editRange);
381 m_textPassage = new QTextEdit(mainDockWidget);
382 m_textPassage->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
383 dockLayout->addWidget(m_textPassage);
385 // Toolbar
386 QToolBar* bibleToolBar = new QToolBar("bibleToolBar");
387 bibleToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
388 dockLayout->addWidget(bibleToolBar);
390 m_insertIntoPlaylistAction = new KAction(KIcon("player_playlist"), i18n("Insert Into Playlist"), bibleToolBar);
391 m_insertIntoPlaylistAction->setEnabled(false);
392 connect(m_insertIntoPlaylistAction, SIGNAL(triggered(bool)),
393 this, SLOT(slotInsertIntoPlaylist()));
394 bibleToolBar->addAction(m_insertIntoPlaylistAction);
396 m_showNowAction = new KAction(KIcon("player_playlist"), i18n("Show Now"), bibleToolBar);
397 m_showNowAction->setEnabled(false);
398 connect(m_showNowAction, SIGNAL(triggered(bool)),
399 this, SLOT(slotShowNow()));
400 bibleToolBar->addAction(m_showNowAction);
402 // Fill out tabs and manager data
403 foreach (KwBibleManager* manager, managers)
405 QString name = manager->name();
406 BibleManager mgr;
407 mgr.manager = manager;
409 QWidget* tabWidget = new QWidget();
410 QHBoxLayout* layout = new QHBoxLayout(tabWidget);
412 mgr.comboBibles = new QComboBox();
413 connect(mgr.comboBibles, SIGNAL(currentIndexChanged(int)),
414 this, SLOT(slotBibleChanged()));
416 // Only fill the module list if the manager is local
417 // Otherwise we should wait until the user requests it
418 if (manager->isRemote())
420 mgr.comboBibles->setEnabled(false);
422 mgr.toolBar = new QToolBar();
423 KAction* connectToBible = new KAction(KIcon("network-connect"), i18n("Connect to %1", name), mgr.toolBar);
424 connect(connectToBible, SIGNAL(triggered(bool)),
425 this, SLOT(slotConnect()));
426 mgr.toolBar->addAction(connectToBible);
427 layout->addWidget(mgr.toolBar);
429 // Toolbar should be as small as possible
430 QSizePolicy policy;
432 policy = mgr.toolBar->sizePolicy();
433 policy.setHorizontalStretch(1);
434 mgr.toolBar->setSizePolicy(policy);
436 policy = mgr.comboBibles->sizePolicy();
437 policy.setHorizontalStretch(10);
438 mgr.comboBibles->setSizePolicy(policy);
440 else
442 mgr.toolBar = 0;
443 fillBiblesList(&mgr);
446 layout->addWidget(mgr.comboBibles);
448 m_managerTabs->addTab(tabWidget, name);
449 m_managers.push_back(mgr);
451 // Ensure widgets are apropriately modified
452 connect(m_comboBook, SIGNAL(currentIndexChanged(int)),
453 this, SLOT(slotBookChanged()));
454 connect(m_comboChapter, SIGNAL(currentIndexChanged(int)),
455 this, SLOT(slotVerseRange()));
456 connect(m_editRange, SIGNAL(textChanged(const QString&)),
457 this, SLOT(slotVerseRange()));
459 KwApplication::self()->mainWindow()->addDockWidget(Qt::LeftDockWidgetArea, m_docker);
461 slotBibleChanged();
464 void KwBiblePlugin::_unload()
466 // Clean up the bible managers.
467 /// @todo IMPLEMENT!!!
468 for (int i = 0; i < m_managers.size(); ++i)
470 BibleManager& mgr = m_managers[i];
471 delete mgr.manager;
472 mgr.manager = 0;
474 delete m_docker;
478 * Private functions
481 /// Fill up the bibles list for a manager.
482 void KwBiblePlugin::fillBiblesList(BibleManager* mgr)
484 bool ok;
485 QStringList languages = mgr->manager->languages(&ok);
486 mgr->comboBibles->setEnabled(false);
487 mgr->comboBibles->clear();
488 mgr->comboBibles->addItem(i18n("-- select a translation --"));
489 foreach (QString language, languages)
491 QStringList modules = mgr->manager->moduleNamesInLanguage(language);
492 if (!modules.isEmpty())
494 mgr->comboBibles->addItem(language, QVariant(modules.first()));
495 foreach (QString module, modules)
497 mgr->comboBibles->addItem(" " + module, QVariant(module));
501 // re-enable or clear
502 if (ok && mgr->comboBibles->count() > 1) {
503 mgr->comboBibles->setEnabled(true);
505 else {
506 mgr->comboBibles->clear();