summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/btmoduletreeitem.cpp272
-rw-r--r--src/backend/btmoduletreeitem.h166
-rw-r--r--src/backend/config/cbtconfig.cpp720
-rw-r--r--src/backend/config/cbtconfig.h197
-rw-r--r--src/backend/cswordmodulesearch.cpp123
-rw-r--r--src/backend/cswordmodulesearch.h98
-rw-r--r--src/backend/drivers/cswordbiblemoduleinfo.cpp261
-rw-r--r--src/backend/drivers/cswordbiblemoduleinfo.h126
-rw-r--r--src/backend/drivers/cswordbookmoduleinfo.cpp68
-rw-r--r--src/backend/drivers/cswordbookmoduleinfo.h64
-rw-r--r--src/backend/drivers/cswordcommentarymoduleinfo.cpp32
-rw-r--r--src/backend/drivers/cswordcommentarymoduleinfo.h43
-rw-r--r--src/backend/drivers/cswordlexiconmoduleinfo.cpp170
-rw-r--r--src/backend/drivers/cswordlexiconmoduleinfo.h71
-rw-r--r--src/backend/drivers/cswordmoduleinfo.cpp955
-rw-r--r--src/backend/drivers/cswordmoduleinfo.h384
-rw-r--r--src/backend/filters/bt_gbfhtml.cpp296
-rw-r--r--src/backend/filters/bt_gbfhtml.h55
-rw-r--r--src/backend/filters/bt_osishtml.cpp619
-rw-r--r--src/backend/filters/bt_osishtml.h67
-rw-r--r--src/backend/filters/bt_plainhtml.cpp72
-rw-r--r--src/backend/filters/bt_plainhtml.h33
-rw-r--r--src/backend/filters/bt_thmlhtml.cpp385
-rw-r--r--src/backend/filters/bt_thmlhtml.h53
-rw-r--r--src/backend/filters/bt_thmlplain.cpp221
-rw-r--r--src/backend/filters/bt_thmlplain.h28
-rw-r--r--src/backend/filters/osismorphsegmentation.cpp83
-rw-r--r--src/backend/filters/osismorphsegmentation.h36
-rw-r--r--src/backend/keys/cswordkey.cpp185
-rw-r--r--src/backend/keys/cswordkey.h111
-rw-r--r--src/backend/keys/cswordldkey.cpp118
-rw-r--r--src/backend/keys/cswordldkey.h110
-rw-r--r--src/backend/keys/cswordtreekey.cpp93
-rw-r--r--src/backend/keys/cswordtreekey.h79
-rw-r--r--src/backend/keys/cswordversekey.cpp303
-rw-r--r--src/backend/keys/cswordversekey.h122
-rw-r--r--src/backend/managers/btstringmgr.cpp139
-rw-r--r--src/backend/managers/btstringmgr.h53
-rw-r--r--src/backend/managers/cdisplaytemplatemgr.cpp170
-rw-r--r--src/backend/managers/cdisplaytemplatemgr.h91
-rw-r--r--src/backend/managers/clanguagemgr.cpp546
-rw-r--r--src/backend/managers/clanguagemgr.h151
-rw-r--r--src/backend/managers/creferencemanager.cpp422
-rw-r--r--src/backend/managers/creferencemanager.h110
-rw-r--r--src/backend/managers/cswordbackend.cpp555
-rw-r--r--src/backend/managers/cswordbackend.h273
-rw-r--r--src/backend/rendering/cbookdisplay.cpp136
-rw-r--r--src/backend/rendering/cbookdisplay.h45
-rw-r--r--src/backend/rendering/cchapterdisplay.cpp59
-rw-r--r--src/backend/rendering/cchapterdisplay.h37
-rw-r--r--src/backend/rendering/cdisplayrendering.cpp158
-rw-r--r--src/backend/rendering/cdisplayrendering.h38
-rw-r--r--src/backend/rendering/centrydisplay.cpp63
-rw-r--r--src/backend/rendering/centrydisplay.h51
-rw-r--r--src/backend/rendering/chtmlexportrendering.cpp234
-rw-r--r--src/backend/rendering/chtmlexportrendering.h58
-rw-r--r--src/backend/rendering/cplaintextexportrendering.cpp53
-rw-r--r--src/backend/rendering/cplaintextexportrendering.h40
-rw-r--r--src/backend/rendering/ctextrendering.cpp263
-rw-r--r--src/backend/rendering/ctextrendering.h128
60 files changed, 10692 insertions, 0 deletions
diff --git a/src/backend/btmoduletreeitem.cpp b/src/backend/btmoduletreeitem.cpp
new file mode 100644
index 0000000..275c841
--- /dev/null
+++ b/src/backend/btmoduletreeitem.cpp
@@ -0,0 +1,272 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btmoduletreeitem.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "util/cpointers.h"
+#include "backend/managers/cswordbackend.h"
+#include "util/cresmgr.h"
+#include "util/ctoolclass.h"
+
+#include <QString>
+#include <QList>
+
+#include <QDebug>
+
+
+
+//This ctor creates the root item and the tree.
+BTModuleTreeItem::BTModuleTreeItem(QList<BTModuleTreeItem::Filter*>& filters, BTModuleTreeItem::Grouping grouping, QList<CSwordModuleInfo*>* modules)
+ : m_moduleInfo(0),
+ m_firstChild(0),
+ m_next(0),
+ m_type(BTModuleTreeItem::Root),
+ m_category(CSwordModuleInfo::UnknownCategory)
+{
+ if (modules) {
+ m_originalModuleList = *modules;
+ } else {
+ m_originalModuleList = CPointers::backend()->moduleList();
+ }
+ //populate the tree with groups/modules
+ create_tree(filters, grouping);
+}
+
+/**
+* Private constructor which sets the members of the non-root item. This will be the first child of the
+* parent, the previous firstChild will be the next sibling of this.
+*/
+BTModuleTreeItem::BTModuleTreeItem(BTModuleTreeItem* parentItem, const QString& text, BTModuleTreeItem::Type type, CSwordModuleInfo* info, CSwordModuleInfo::Category category)
+ : m_moduleInfo(info),
+ m_text(text),
+ m_firstChild(0),
+ m_next(0),
+ m_type(type),
+ m_category(category)
+{
+ if (info) {
+ m_text = info->name();
+ m_type = BTModuleTreeItem::Module;
+ }
+ BTModuleTreeItem* tmp = parentItem->m_firstChild;
+ parentItem->m_firstChild = this;
+ if (tmp) this->m_next = tmp;
+}
+
+
+BTModuleTreeItem::~BTModuleTreeItem()
+{
+ // this works recursively
+ foreach(BTModuleTreeItem* i, children()) {
+ delete i;
+ }
+}
+
+QList<BTModuleTreeItem*> BTModuleTreeItem::children() const
+{
+ //qDebug("BTModuleTreeItem::children");
+ QList<BTModuleTreeItem*> childList;
+ if (m_firstChild) {
+ BTModuleTreeItem* child = m_firstChild;
+ while (child) {
+ //qDebug() << "child:" << child->text();
+ childList.append(child);
+ child = child->m_next;
+ }
+ }
+ return childList;
+}
+
+//TODO
+QString BTModuleTreeItem::iconName() const
+{
+ if (m_type == Category) {
+ switch ( m_category) {
+ case CSwordModuleInfo::Bibles:
+ return CResMgr::categories::bibles::icon;
+ break;
+ case CSwordModuleInfo::Commentaries:
+ return CResMgr::categories::commentaries::icon;
+ break;
+ case CSwordModuleInfo::Books:
+ return CResMgr::categories::books::icon;
+ break;
+ case CSwordModuleInfo::Cult:
+ return CResMgr::categories::cults::icon;
+ break;
+ case CSwordModuleInfo::Images:
+ return CResMgr::categories::images::icon;
+ break;
+ case CSwordModuleInfo::DailyDevotional:
+ return CResMgr::categories::dailydevotional::icon;
+ break;
+ case CSwordModuleInfo::Lexicons:
+ return CResMgr::categories::lexicons::icon;
+ break;
+ case CSwordModuleInfo::Glossary:
+ return CResMgr::categories::glossary::icon;
+ break;
+ default: break;
+ }
+ }
+ else if (m_type == Module) {
+ return CToolClass::getIconNameForModule(m_moduleInfo);
+ }
+ else if (m_type == Language) {
+ //TODO: don't hardcode here
+ return "flag.svg";
+ }
+
+ return QString::null;
+}
+
+
+void BTModuleTreeItem::create_tree(QList<BTModuleTreeItem::Filter*>& filters, BTModuleTreeItem::Grouping grouping)
+{
+ qDebug("BTModuleTreeItem::create_tree");
+ static bool map_initialized = false;
+ static QMap<CSwordModuleInfo::Category, QString> CategoryNamesMap;
+ if (!map_initialized) {
+ CategoryNamesMap.insert(CSwordModuleInfo::Commentaries, QObject::tr("Commentaries"));
+ CategoryNamesMap.insert(CSwordModuleInfo::Cult, QObject::tr("Cults/Unorthodox"));
+ CategoryNamesMap.insert(CSwordModuleInfo::Images, QObject::tr("Maps and Images"));
+ CategoryNamesMap.insert(CSwordModuleInfo::DailyDevotional, QObject::tr("Daily Devotionals"));
+ CategoryNamesMap.insert(CSwordModuleInfo::Lexicons, QObject::tr("Lexicons and Dictionaries"));
+ CategoryNamesMap.insert(CSwordModuleInfo::Bibles, QObject::tr("Bibles"));
+ CategoryNamesMap.insert(CSwordModuleInfo::Glossary, QObject::tr("Glossaries"));
+ CategoryNamesMap.insert(CSwordModuleInfo::Books, QObject::tr("Books"));
+
+ map_initialized = true;
+ }
+
+ //QList<CSwordModuleInfo*> originalInfoList = CPointers::backend()->moduleList();
+
+ foreach (CSwordModuleInfo* info, m_originalModuleList) {
+ bool included;
+ included = true;
+ foreach (BTModuleTreeItem::Filter* f, filters) {
+ if (!f->filter(info)) {
+ included = false;
+ break;
+ }
+ }
+ if (included) {
+ //qDebug() << "a module will be included: " << info->name();
+
+ BTModuleTreeItem* parentGroupForModule = this;
+ BTModuleTreeItem* parentGroupForLanguage = this;
+ BTModuleTreeItem* parentGroupForCategory = this;
+
+ //the order of if(grouping...) clauses is important
+ if (grouping == BTModuleTreeItem::LangMod || grouping == BTModuleTreeItem::LangCatMod) {
+ BTModuleTreeItem* langItem = create_parent_item(parentGroupForLanguage, info->language()->translatedName(), BTModuleTreeItem::Language);
+
+ if (grouping == BTModuleTreeItem::LangMod)
+ parentGroupForModule = langItem;
+ else
+ parentGroupForCategory = langItem;
+ }
+
+ if (grouping == BTModuleTreeItem::CatMod || grouping == BTModuleTreeItem::CatLangMod) {
+ BTModuleTreeItem* catItem = create_parent_item(parentGroupForCategory, CategoryNamesMap.value(info->category()), BTModuleTreeItem::Category, info->category());
+
+ if (grouping == BTModuleTreeItem::CatMod)
+ parentGroupForModule = catItem;
+ else
+ parentGroupForLanguage = catItem;
+ }
+
+ if (grouping == BTModuleTreeItem::CatLangMod) {
+ // category is there already, create language and make it the parent for the module
+ parentGroupForModule = create_parent_item(parentGroupForLanguage, info->language()->translatedName(), BTModuleTreeItem::Language);
+ }
+
+ if (grouping == BTModuleTreeItem::LangCatMod) {
+ //language is there already, create category and make it the parent for the module
+ parentGroupForModule = create_parent_item(parentGroupForCategory, CategoryNamesMap.value(info->category()), BTModuleTreeItem::Category, info->category());
+ }
+
+ // the parent group for module has been set above, now just add the module to it
+ new BTModuleTreeItem(parentGroupForModule, QString::null, BTModuleTreeItem::Module, info);
+
+ } // end: if (included)
+ }
+
+ // Finally sort the items
+ sort_children(this);
+}
+
+BTModuleTreeItem* BTModuleTreeItem::create_parent_item(
+ BTModuleTreeItem* parentGroup,
+ const QString& itemText,
+ BTModuleTreeItem::Type type,
+ CSwordModuleInfo::Category category)
+{
+ BTModuleTreeItem* item = 0;
+ foreach(BTModuleTreeItem* it, parentGroup->children()) {
+ if (it->text() == itemText) {
+ item = it;
+ break;
+ }
+ }
+ if (!item)
+ item = new BTModuleTreeItem(parentGroup, itemText, type, 0, category);
+
+ return item;
+}
+
+void BTModuleTreeItem::sort_children(BTModuleTreeItem* parent)
+{
+ //qDebug("BTModuleTreeItem::sort_children");
+
+ // sort each child recursively depth-first
+ foreach(BTModuleTreeItem* item, parent->children()) {
+ sort_children(item);
+ }
+
+ QList<BTModuleTreeItem*> items = parent->children();
+ if (items.size() > 0) {
+ // Sort the list of the children according to each item's text
+ qSort(items.begin(), items.end(), BTModuleTreeItem::localeAwareLessThan);
+ //put the children back to tree in sorted order
+ BTModuleTreeItem* first = items.at(0);
+ BTModuleTreeItem* prev = first;
+ foreach (BTModuleTreeItem* item2, items) {
+ prev->m_next = item2;
+ prev = item2;
+ }
+ prev->m_next = 0;
+ parent->m_firstChild = first; // attach the partial tree to the parent
+ }
+}
+
+bool BTModuleTreeItem::localeAwareLessThan(BTModuleTreeItem* first, BTModuleTreeItem* second)
+{
+ static bool map_initialized = false;
+ static QMap<QString, int> CategoryNameValueMap;
+ if (!map_initialized) {
+ //this is the sorting order for categories
+ CategoryNameValueMap.insert(QObject::tr("Bibles"), 1);
+ CategoryNameValueMap.insert(QObject::tr("Commentaries"), 2);
+ CategoryNameValueMap.insert(QObject::tr("Books"), 3);
+ CategoryNameValueMap.insert(QObject::tr("Lexicons and Dictionaries"), 4);
+ CategoryNameValueMap.insert(QObject::tr("Glossaries"), 5);
+ CategoryNameValueMap.insert(QObject::tr("Daily Devotionals"), 6);
+ CategoryNameValueMap.insert(QObject::tr("Maps and Images"), 7);
+ CategoryNameValueMap.insert(QObject::tr("Cults/Unorthodox"), 8);
+ map_initialized = true;
+ }
+
+ //Categories are always in the same order, not alphabetically
+ if (first->type() == BTModuleTreeItem::Category) {
+ return (CategoryNameValueMap.value(first->text()) < CategoryNameValueMap.value(second->text()));
+ }
+ return (QString::localeAwareCompare(first->text(), second->text()) < 0 );
+}
diff --git a/src/backend/btmoduletreeitem.h b/src/backend/btmoduletreeitem.h
new file mode 100644
index 0000000..abdfdb7
--- /dev/null
+++ b/src/backend/btmoduletreeitem.h
@@ -0,0 +1,166 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTMODULETREEITEM_H
+#define BTMODULETREEITEM_H
+
+#include "backend/drivers/cswordmoduleinfo.h"
+
+#include <QString>
+
+
+/**
+Item of a tree which represents Sword modules categorized and filtered.
+Can be used when building trees for different views.
+
+The tree will be created with the public constructor. It creates the root item and
+populates it with the rest of the tree. The root item is the handle to the tree.
+Users can get the list of the children and operate on it recursively.
+
+The tree is meant to be created, read and then deleted. If you need to apply for example
+different set of filters you have to create a new tree - it's not possible to modify the tree.
+
+Example:
+
+ ...
+ QList<BTModuleTreeItem::Filter*> noFilters
+ BTModuleTreeItem root(noFilters, BTModuleTreeItem::CatLangMod);
+ add_to_view(&root, qtreewidget->invisibleRootItem());
+ ...
+ void add_to_view(BTModuleTreeItem* item, QTreeWidgetItem* widgetItem) {
+ foreach (BTModuleTreeItem* i, item->children()) {
+ add_to_view(i, new QTreeWidgetItem(widgetItem));
+ }
+ if (item->type() == BTModuleTreeItem::Category) prepare_category_item(widgetItem, item);
+ ...
+ }
+
+
+ @author The BibleTime team <info@bibletime.info>
+*/
+class BTModuleTreeItem
+{
+public:
+
+ /**
+ * A filter which is given to the root constructor. It filters some modules
+ * out from the tree. If it returns true when the filter() is called the module will be added,
+ * if it returns false the module will be left out.
+ *
+ * If you want for example to get only unindexed modules in the list you should
+ * write a class (possibly a small inner class inside the calling class) which
+ * inherits Filter and write the operator() function which returns true if the
+ * module is unindexed and false if it's indexed.
+ *
+ * It's also possible to do arbitrary tasks to modules by using more complex subclasses.
+ *
+ * The filters will be applied in the order in which they are in the list.
+ * A module will be filtered out if even one filter rejects it and testing
+ * will stop with the first negative.
+ *
+ * Example:
+ * QList<BTModuleTreeItem::Filter*> filters;
+ * MyFilter filter; BTModuleTreeItem::HiddenOff hideFilter;
+ * filters.append(&hideFilter); filters.append(&filter);
+ * BTModuleTreeItem root(filters, BTModuleTreeItem::CatLangMod);
+ */
+ struct Filter {
+ virtual bool filter(CSwordModuleInfo*) = 0;
+ inline virtual ~Filter() {};
+ };
+
+ /**
+ * One example of a filter which can be used with any view. If the module has been
+ * set "hidden" it will be filtered out.
+ */
+ struct HiddenOff : public Filter {
+ inline bool filter(CSwordModuleInfo* mi) { return !mi->isHidden(); }
+ inline virtual ~HiddenOff() {};
+ };
+
+ /**
+ * Type of the item: root item, category (Bibles, Commentaries etc.), language or module.
+ */
+ enum Type {Root, Category, Language, Module};
+
+ /**
+ * Tells how to group the modules. For example:
+ * CatLangMod: first category, second language, third module. Mod: don't use
+ * Category or Language at all, Module is toplevel and tree is flat.
+ */
+ enum Grouping {CatLangMod, CatMod, LangCatMod, LangMod, Mod};
+
+
+ /**
+ * This constructor creates a root item. Create it for example with scoped_ptr or in stack.
+ * The root item is populated with the item tree.
+ * The constructor takes a list of filters (see Filter), grouping indicator (see Grouping)
+ * and optionally the module list from which the tree is constructed
+ * (by default CPointers::backend()->moduleList() is used).
+ */
+ BTModuleTreeItem(QList<BTModuleTreeItem::Filter*>& filters,
+ BTModuleTreeItem::Grouping grouping, QList<CSwordModuleInfo*>* modules = 0);
+
+ /** When the root item is deleted the whole tree is deleted. */
+ ~BTModuleTreeItem();
+
+ /**
+ * Returns the item type.
+ */
+ inline BTModuleTreeItem::Type type() const {return m_type;}
+ /**
+ * Returns the item text (category name, language name or module name).
+ */
+ inline QString text() const {return m_text;}
+ /**
+ * Returns the path to the icon which is appropriate for this type of item, or QString::null.
+ */
+ QString iconName() const;
+ /**
+ * If the type is Module returns a pointer to the corresponding CSwordModuleInfo object,
+ * otherwise returns 0.
+ */
+ inline CSwordModuleInfo* moduleInfo() const {return m_moduleInfo;}
+ /**
+ * Returns a list of the direct children of this item.
+ */
+ QList<BTModuleTreeItem*> children() const;
+
+ /**
+ * For alphabetical sorting which uses text(). See QString::localeAwareCompare().
+ * Categories will always be in the same order regardless of the i18n.
+ */
+ static bool localeAwareLessThan(BTModuleTreeItem* first, BTModuleTreeItem* second);
+
+
+private:
+ /**
+ * Private constructor which sets the members.
+ */
+ BTModuleTreeItem(BTModuleTreeItem* parentItem, const QString& text, Type type, CSwordModuleInfo* info=0, CSwordModuleInfo::Category category=CSwordModuleInfo::UnknownCategory);
+ /** Default ctor is private because it is not to be called.*/
+ BTModuleTreeItem();
+
+ /** Creates the tree under this root item (called only from root ctor). */
+ void create_tree(QList<BTModuleTreeItem::Filter*>& filters, BTModuleTreeItem::Grouping grouping);
+ /** Sorts recursively the children of of the given item. */
+ void sort_children(BTModuleTreeItem* parent);
+ /** Helper function for creating a group item while creating the tree. */
+ BTModuleTreeItem* create_parent_item(BTModuleTreeItem* parent, const QString& text, BTModuleTreeItem::Type type, CSwordModuleInfo::Category category=CSwordModuleInfo::UnknownCategory);
+
+ CSwordModuleInfo* m_moduleInfo;
+ QString m_text;
+ BTModuleTreeItem* m_firstChild;
+ BTModuleTreeItem* m_next;
+ Type m_type;
+ CSwordModuleInfo::Category m_category;
+ QList<CSwordModuleInfo*> m_originalModuleList;
+};
+
+#endif
diff --git a/src/backend/config/cbtconfig.cpp b/src/backend/config/cbtconfig.cpp
new file mode 100644
index 0000000..a0fb4f2
--- /dev/null
+++ b/src/backend/config/cbtconfig.cpp
@@ -0,0 +1,720 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+//BibleTime includes
+#include "cbtconfig.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/managers/clanguagemgr.h"
+#include "backend/managers/cdisplaytemplatemgr.h"
+#include "backend/btmoduletreeitem.h"
+#include "util/cpointers.h"
+#include "util/directoryutil.h"
+#include "frontend/searchdialog/btsearchoptionsarea.h"
+
+//Qt includes
+#include <QApplication>
+#include <QString>
+#include <QStringList>
+#include <QMap>
+#include <QList>
+#include <QDebug>
+#include <QSettings>
+#include <QLocale>
+#include <QWebSettings>
+
+//Sword includes
+#include <versekey.h> //for range configuration
+
+//init statics
+QFont* CBTConfig::m_defaultFont = 0;
+CBTConfig::FontCache CBTConfig::fontConfigMap;
+
+/* No constructor and destructor, because this class only contains static methods.
+ It won't be instantiated. */
+
+QString CBTConfig::getKey( const CBTConfig::strings ID) {
+ switch ( ID ) {
+ case bibletimeVersion: return "bibletimeVersion";
+ case language: return "language";
+ case displayStyle: return "displayStyle";
+ case bookshelfCurrentItem: return "bookshelfCurrentItem";
+ }
+ Q_ASSERT(false);
+ return QString::null;
+}
+
+QString CBTConfig::getDefault( const CBTConfig::strings ID) {
+ switch ( ID ) {
+ case bibletimeVersion: return "0.0"; // main() will realize this and set the value to VERSION
+ case language: return QLocale::system().name();
+ case displayStyle: return CDisplayTemplateMgr::defaultTemplate();
+ case bookshelfCurrentItem: return QString();
+ }
+ return QString::null;
+}
+
+QString CBTConfig::getKey( const CBTConfig::modules ID) {
+ switch ( ID ) {
+ case standardBible: return "standardBible";
+ case standardCommentary: return "standardCommentary";
+ case standardLexicon: return "standardLexicon";
+ case standardDailyDevotional: return "standardDailyDevotional";
+ case standardHebrewStrongsLexicon: return "standardHebrewLexicon";
+ case standardGreekStrongsLexicon: return "standardGreekLexicon";
+ case standardHebrewMorphLexicon: return "standardHebrewMorphLexicon";
+ case standardGreekMorphLexicon: return "standardGreekMorphLexicon";
+ }
+ Q_ASSERT(false);
+ return QString::null;
+}
+
+QString CBTConfig::getDefault( const CBTConfig::modules ID) {
+ // CSwordBackend* b = CPointers::backend();
+ switch ( ID ) {
+ case standardBible: return "KJV";
+ case standardCommentary: return "MHC";
+ case standardLexicon: return "ISBE";
+ case standardDailyDevotional: return ""; //no default
+
+ case standardHebrewStrongsLexicon: return "StrongsHebrew";
+ case standardGreekStrongsLexicon: return "StrongsGreek";
+ case standardHebrewMorphLexicon: return "StrongsHebrew";
+ case standardGreekMorphLexicon: return "StrongsGreek";
+ }
+
+ return QString::null;
+}
+
+QString CBTConfig::getKey( const CBTConfig::bools ID) {
+ switch ( ID ) {
+ case firstSearchDialog: return "firstSearchDialog";
+ case readOldBookmarks: return "readOldBookmarks";
+
+ case toolbar: return "toolbar";
+ case mainIndex: return "mainIndex";
+ case infoDisplay: return "infoDisplay";
+
+ case autoTileVertical: return "autoTileVertical";
+ case autoTileHorizontal: return "autoTileHorizontal";
+ case autoCascade: return "autoCascade";
+
+ case lineBreaks: return "lineBreaks";
+ case verseNumbers: return "verseNumbers";
+
+ case logo: return "logo";
+ case autoDeleteOrphanedIndices: return "autoDeleteOrphanedIndices";
+ case crashedLastTime: return "crashedLastTime";
+ case crashedTwoTimes: return "crashedTwoTimes";
+
+ case bookshelfShowHidden: return "bookshelfShowHidden";
+ case allowNetworkConnection: return "allowNetworkConnection";
+ }
+ Q_ASSERT(false);
+ return false;
+}
+
+QString CBTConfig::getKey( const CBTConfig::ints ID) {
+ switch ( ID ) {
+ case footnotes: return "footnotes";
+ case strongNumbers: return "strongNumbers";
+ case headings: return "headings";
+ case morphTags: return "morphTags";
+ case lemmas: return "lemmas";
+ case hebrewPoints: return "hebrewPoints";
+ case hebrewCantillation: return "hebrewCantillation";
+ case greekAccents: return "greekAccents";
+ case textualVariants: return "textualVariants";
+ case scriptureReferences: return "scriptureReferences";
+ case morphSegmentation: return "morphSegmentation";
+ case bookshelfContentsX: return "bookshelfContentsX";
+ case bookshelfContentsY: return "bookshelfContentsY";
+ case magDelay: return "magDelay";
+ case bookshelfGrouping: return "bookshelfGrouping";
+ case mainindexActiveTab: return "mainindexActiveTab";
+ case searchDialogWidth: return "searchDialogWidth";
+ case searchDialogHeight: return "searchDialogHeight";
+ case searchDialogX: return "searchDialogX";
+ case searchDialogY: return "searchDialogY";
+ case searchType: return "searchType";
+ case installPathIndex: return "installPathIndex";
+ }
+ Q_ASSERT(false);
+ return QString::null;
+}
+
+bool CBTConfig::getDefault( const CBTConfig::bools ID) {
+ switch ( ID ) {
+ case firstSearchDialog: return true;
+ case readOldBookmarks: return false;
+
+ case toolbar: return true;
+ case mainIndex: return true;
+ case infoDisplay: return true;
+
+ case autoTileVertical: return true;
+ case autoTileHorizontal: return false;
+ case autoCascade: return false;
+
+ case lineBreaks: return false;
+ case verseNumbers: return true;
+
+ case logo: return true;
+ case autoDeleteOrphanedIndices: return true;
+ case crashedLastTime: return false;
+ case crashedTwoTimes: return false;
+ case bookshelfShowHidden: return false;
+ case allowNetworkConnection: return false;
+ }
+ return false;
+}
+
+int CBTConfig::getDefault( const CBTConfig::ints ID) {
+ switch ( ID ) {
+ case footnotes: return int(true);
+ case strongNumbers: return int(true);
+ case headings: return int(true);
+ case morphTags: return int(true);
+ case lemmas: return int(true);
+ case hebrewPoints: return int(true);
+ case hebrewCantillation: return int(true);
+ case greekAccents: return int(true);
+ case textualVariants: return int(false);
+ case scriptureReferences: return int(true);
+ case morphSegmentation: return int(true);
+ case bookshelfContentsX: return 0;
+ case bookshelfContentsY: return 0;
+ case magDelay: return 400;
+ case bookshelfGrouping: return BTModuleTreeItem::CatLangMod;
+ case searchDialogWidth: return 200;
+ case searchDialogHeight: return 400;
+ case searchDialogX: return 200;
+ case searchDialogY: return 200;
+ case searchType: return Search::BtSearchOptionsArea::AndType;
+ case mainindexActiveTab: return 0;
+ case installPathIndex: return 0;
+ }
+ return 0;
+}
+
+QString CBTConfig::getKey( const CBTConfig::intLists ID) {
+ switch ( ID ) {
+ case leftPaneSplitterSizes: return "leftPaneSplitterSizes";
+ case mainSplitterSizes: return "mainSplitterSizes";
+ case searchMainSplitterSizes: return "searchMainSplitterSizes";
+ case searchResultSplitterSizes: return "searchResultSplitterSizes";
+ }
+ Q_ASSERT(false);
+ return QString::null;
+}
+
+QList<int> CBTConfig::getDefault( const CBTConfig::intLists /*ID*/) {
+ QList<int> result;
+ /*switch ( ID ) {
+ case leftPaneSplitterSizes: break;
+ case mainSplitterSizes: break;
+ case searchMainSplitterSizes: break;
+ case searchResultSplitterSizes: break;*/
+ return result;
+}
+
+QString CBTConfig::getKey( const CBTConfig::stringLists ID) {
+ switch ( ID ) {
+ case searchCompletionTexts: return QString("searchCompletionTexts");
+ case searchTexts: return QString("searchTexts");
+ case searchModulesHistory: return QString("searchModulesHistory");
+ case bookshelfOpenGroups: return QString("bookshelfOpenGroups");
+ case hiddenModules: return QString("hiddenModules");
+ }
+ Q_ASSERT(false);
+ return QString::null;
+}
+
+QStringList CBTConfig::getDefault( const CBTConfig::stringLists ID) {
+ switch ( ID ) {
+ case searchTexts: {
+ QStringList list;
+ list.append(QString::null);
+ return list;
+ }
+ case searchCompletionTexts: return QStringList();
+ case bookshelfOpenGroups: return QStringList();
+ case hiddenModules: return QStringList();
+ case searchModulesHistory: return QStringList();
+ }
+ return QStringList();
+}
+
+QString CBTConfig::getKey( const CBTConfig::stringMaps ID) {
+ switch (ID) {
+ case searchScopes:
+ return QString("SearchScopes");
+ };
+ Q_ASSERT(false);
+ return QString::null;
+}
+
+CBTConfig::StringMap CBTConfig::getDefault( const CBTConfig::stringMaps ID) {
+ switch ( ID ) {
+ case searchScopes: {
+ CBTConfig::StringMap map;
+ map.insert(QObject::tr("Old testament"), QString("Gen - Mal"));
+ map.insert(QObject::tr("Moses/Pentateuch/Torah"),QString("Gen - Deut"));
+ map.insert(QObject::tr("History"), QString("Jos - Est"));
+ map.insert(QObject::tr("Prophets"), QString("Isa - Mal"));
+ map.insert(QObject::tr("New testament"), QString("Mat - Rev"));
+ map.insert(QObject::tr("Gospels"), QString("Mat - Joh"));
+ map.insert(QObject::tr("Letters/Epistles"), QString("Rom - Jude"));
+ map.insert(QObject::tr("Paul's Epistles"), QString("Rom - Phile"));
+
+ //make the list to the current bookname language!
+ CBTConfig::StringMap::Iterator it;
+ sword::VerseKey vk;
+ vk.setLocale("en_US");
+
+ for (it = map.begin(); it != map.end(); ++it) {
+ sword::ListKey list = vk.ParseVerseList(it.value().toLocal8Bit(), "Genesis 1:1", true);
+ QString data;
+ for (int i = 0; i < list.Count(); ++i) {
+ data += QString::fromUtf8(list.GetElement(i)->getRangeText()) + "; ";
+ }
+ map[it.key()] = data; //set the new data
+ };
+
+ return map;
+ };
+ default:
+ return CBTConfig::StringMap();
+ }
+
+ return CBTConfig::StringMap();
+}
+
+
+QString CBTConfig::getKey( const CLanguageMgr::Language* const language ) {
+ Q_ASSERT(!language->name().isEmpty());
+ return language->name();
+}
+
+QFont& CBTConfig::getDefault( const CLanguageMgr::Language* const)
+{
+ //language specific lookup of the font name
+ if (m_defaultFont)
+ {
+ return *m_defaultFont;
+ }
+
+// TODO - make the font name and size a configuration option
+ //int fontSize = QWebSettings::globalSettings()->fontSize(QWebSettings::DefaultFontSize);
+ int fontSize = 12;
+ QString fontName = QWebSettings::globalSettings()->fontFamily(QWebSettings::StandardFont);
+
+ m_defaultFont = new QFont(fontName, fontSize); //TODO: there may be a mem leak here!
+ return *m_defaultFont;
+}
+
+QString CBTConfig::get( const CBTConfig::strings ID)
+{
+ QString result;
+ getConfig()->beginGroup("strings");
+ result = getConfig()->value(getKey(ID), getDefault(ID)).toString();
+ getConfig()->endGroup();
+ return result;
+
+}
+
+CSwordModuleInfo* CBTConfig::get( const CBTConfig::modules ID)
+{
+ CSwordModuleInfo* result;
+ getConfig()->beginGroup("modules");
+ result = CPointers::backend()->findModuleByName( getConfig()->value(getKey(ID), getDefault(ID)).toString() );
+ getConfig()->endGroup();
+ return result;
+}
+
+bool CBTConfig::get( const CBTConfig::bools ID)
+{
+ bool result;
+ getConfig()->beginGroup("bools");
+ result = getConfig()->value(getKey(ID), getDefault(ID)).toBool();
+ getConfig()->endGroup();
+ return result;
+}
+
+int CBTConfig::get( const CBTConfig::ints ID)
+{
+ int result;
+ getConfig()->beginGroup("ints");
+ result = getConfig()->value(getKey(ID), getDefault(ID)).toInt();
+ getConfig()->endGroup();
+ return result;
+}
+
+QList<int> CBTConfig::get( const CBTConfig::intLists ID )
+{
+ QList<int> result;
+ getConfig()->beginGroup("intlists");
+ result = StringToIntList( getConfig()->value(getKey(ID), IntListToString( getDefault(ID) )).toString() );
+ getConfig()->endGroup();
+ return result;
+}
+
+QStringList CBTConfig::get( const CBTConfig::stringLists ID )
+{
+ QStringList result;
+ getConfig()->beginGroup("stringlists");
+ result = getConfig()->value(getKey(ID), getDefault(ID)).toStringList();
+ getConfig()->endGroup();
+ return result;
+}
+
+CBTConfig::StringMap CBTConfig::get( const CBTConfig::stringMaps ID )
+{
+ getConfig()->beginGroup(getKey(ID));
+ CBTConfig::StringMap map;
+
+ QStringList keys(getConfig()->childKeys());
+ if (!keys.isEmpty()) {
+ switch (ID) {
+ case searchScopes: { //make sure we return the scopes in the chosen language. saved keys are in english
+ sword::VerseKey vk;
+ foreach (QString key, keys) {
+ Q_ASSERT(!key.isEmpty());
+ sword::ListKey list = vk.ParseVerseList(getConfig()->value(key).toString().toUtf8(), "Genesis 1:1", true);
+ QString data;
+ for (int i = 0; i < list.Count(); ++i) {
+ data += QString::fromUtf8(list.GetElement(i)->getRangeText()) + "; ";
+ }
+ map[key] = data; //set the new data
+ }
+ }
+ default: break;
+ }
+ }
+ else
+ {
+ map = getDefault(ID);
+ }
+ getConfig()->endGroup();
+ return map;
+}
+
+CBTConfig::FontSettingsPair CBTConfig::get( const CLanguageMgr::Language* const language )
+{
+ if (fontConfigMap.contains(language)) {
+ return fontConfigMap.find(language).value();
+ }
+
+ FontSettingsPair settings;
+
+ getConfig()->beginGroup("font standard settings");
+ settings.first = getConfig()->value(getKey(language), QVariant(false)).toBool();
+ getConfig()->endGroup();
+ getConfig()->beginGroup("fonts");
+
+ QFont font;
+ if (settings.first)
+ font.fromString(getConfig()->value(getKey(language), getDefault(language)).toString());
+ else
+ font = getDefault(language);
+
+ settings.second = font;
+ getConfig()->endGroup();
+
+ fontConfigMap.insert(language, settings); //cache the value
+ return settings;
+}
+
+void CBTConfig::set( const CBTConfig::strings ID, const QString value )
+{
+// KConfigGroup cg = CBTConfig::getConfig()->group("strings");
+// cg.writeEntry(getKey(ID), value);
+ getConfig()->beginGroup("strings");
+ getConfig()->setValue(getKey(ID), value);
+ getConfig()->endGroup();
+}
+
+void CBTConfig::set( const CBTConfig::modules ID, CSwordModuleInfo* const value )
+{
+// KConfigGroup cg = CBTConfig::getConfig()->group("modules");
+// cg.writeEntry(getKey(ID), value ? value->name() : QString::null);
+ getConfig()->beginGroup("modules");
+ getConfig()->setValue(getKey(ID), value ? value->name() : QString::null);
+ getConfig()->endGroup();
+}
+
+void CBTConfig::set( const CBTConfig::modules ID, const QString& value )
+{
+ CSwordModuleInfo* module = CPointers::backend()->findModuleByName(value);
+ if (module) {
+ CBTConfig::set(ID, module);
+ }
+}
+
+void CBTConfig::set(const CBTConfig::bools ID,const bool value )
+{
+ getConfig()->beginGroup("bools");
+ getConfig()->setValue(getKey(ID), value);
+ getConfig()->endGroup();
+}
+
+void CBTConfig::set(const CBTConfig::ints ID, const int value )
+{
+ getConfig()->beginGroup("ints");
+ getConfig()->setValue(getKey(ID), value);
+ getConfig()->endGroup();
+}
+
+void CBTConfig::set( const CBTConfig::intLists ID, const QList<int> value )
+{
+ getConfig()->beginGroup("intlists");
+ getConfig()->setValue(getKey(ID), IntListToString(value));
+ getConfig()->endGroup();
+}
+
+void CBTConfig::set( const CBTConfig::stringLists ID, const QStringList value )
+{
+ getConfig()->beginGroup("stringlists");
+ getConfig()->setValue(getKey(ID), value);
+ getConfig()->endGroup();
+}
+
+void CBTConfig::set( const CBTConfig::stringMaps ID, const CBTConfig::StringMap value )
+{
+ getConfig()->beginGroup(getKey(ID));
+ getConfig()->remove(""); //clear all entries of this group to make sure old stuff gets removed
+
+ switch (ID) {
+ case searchScopes: {
+ /**
+ * We want to make sure that the search scopes are saved with english key names so loading them
+ * will always work with each locale set.
+ */
+ CBTConfig::StringMap::ConstIterator it;
+ QString data;// = QString::null;
+
+ sword::VerseKey vk;
+ for (it = value.begin(); it != value.end(); ++it) {
+ sword::ListKey list = vk.ParseVerseList(it.value().toUtf8(), "Genesis 1:1", true);
+ data = QString::null;
+ for (int i = 0; i < list.Count(); ++i) {
+ if ( sword::VerseKey* range = dynamic_cast<sword::VerseKey*>(list.GetElement(i)) ) {
+ range->setLocale("en");
+ data += QString::fromUtf8( range->getRangeText() ) + ";";
+ }
+ }
+ getConfig()->setValue(it.key(), data);
+ }
+ break;
+ }
+ default: {
+ for (CBTConfig::StringMap::ConstIterator it = value.begin(); it != value.end(); ++it) {
+ getConfig()->setValue(it.key(), it.value());
+ }
+ break;
+ }
+ }
+ getConfig()->endGroup();
+}
+
+
+void CBTConfig::set( const CLanguageMgr::Language* const language, const FontSettingsPair& value )
+{
+ getConfig()->beginGroup("fonts");
+ getConfig()->setValue(getKey(language), value.second.toString());
+ getConfig()->endGroup();
+ getConfig()->beginGroup("font standard settings");
+ getConfig()->setValue(getKey(language), value.first);
+ getConfig()->endGroup();
+
+ if (fontConfigMap.contains(language)) {
+ fontConfigMap.remove
+ (language); //remove it from the cache
+ }
+}
+
+CSwordBackend::DisplayOptions CBTConfig::getDisplayOptionDefaults()
+{
+ CSwordBackend::DisplayOptions options;
+ options.lineBreaks = get(CBTConfig::lineBreaks);
+ options.verseNumbers = get(CBTConfig::verseNumbers);
+
+ return options;
+}
+
+CSwordBackend::FilterOptions CBTConfig::getFilterOptionDefaults()
+{
+ CSwordBackend::FilterOptions options;
+
+ options.footnotes = true; //required for the info display
+ options.strongNumbers = true; //get(CBTConfig::strongNumbers);
+ options.headings = get(CBTConfig::headings);
+ options.morphTags = true;//required for the info display
+ options.lemmas = true;//required for the info display
+ options.redLetterWords = true;
+ options.hebrewPoints = get(CBTConfig::hebrewPoints);
+ options.hebrewCantillation = get(CBTConfig::hebrewCantillation);
+ options.greekAccents = get(CBTConfig::greekAccents);
+ options.textualVariants = get(CBTConfig::textualVariants);
+ options.scriptureReferences = get(CBTConfig::scriptureReferences);
+ options.morphSegmentation = get(CBTConfig::morphSegmentation);
+
+ return options;
+}
+
+//void CBTConfig::setupAccelSettings(const CBTConfig::keys /*type*/, KActionCollection* const /*actionCollection*/)
+//{
+// qDebug("CBTConfig::setupAccelSettings");
+// QString groupName;
+// switch (type) {
+// case allWindows : {
+// groupName = "Displaywindow shortcuts";
+// break;
+// };
+// case writeWindow : {
+// groupName = "Writewindow shortcuts";
+// break;
+// };
+// case readWindow : {
+// groupName = "Readwindow shortcuts";
+// break;
+// };
+// case bookWindow : {
+// groupName = "Book shortcuts";
+// break;
+// };
+// case bibleWindow : {
+// groupName = "Bible shortcuts";
+// break;
+// };
+// case commentaryWindow : {
+// groupName = "Commentary shortcuts";
+// break;
+// };
+// case lexiconWindow : {
+// groupName = "Lexicon shortcuts";
+// break;
+// };
+// case application : {
+// groupName = "Application shortcuts";
+// break;
+// };
+// };
+// qDebug() << groupName;
+// Q_ASSERT(CBTConfig::getConfig());
+// //buggy???
+// KConfigGroup* cg = &(CBTConfig::getConfig()->group(groupName));
+// //KConfigGroup* cg;
+//
+// Q_ASSERT(cg);
+// Q_ASSERT(actionCollection);
+// //actionCollection->readSettings(cg);
+// actionCollection->setConfigGroup(groupName);
+//
+// actionCollection->readSettings();
+// qDebug("CBTConfig::setupAccelSettings end");
+//}
+
+//void CBTConfig::saveAccelSettings(const CBTConfig::keys /*type*/, KActionCollection* const /*actionCollection*/)
+//{
+// qDebug("CBTConfig::saveAccelSettings");
+// QString groupName;
+// switch (type) {
+// case allWindows : {
+// groupName = "Displaywindow shortcuts";
+// break;
+// };
+// case writeWindow : {
+// groupName = "Writewindow shortcuts";
+// break;
+// };
+// case readWindow : {
+// groupName = "Readwindow shortcuts";
+// break;
+// };
+// case bookWindow : {
+// groupName = "Book shortcuts";
+// break;
+// };
+// case bibleWindow : {
+// groupName = "Bible shortcuts";
+// break;
+// };
+// case commentaryWindow : {
+// groupName = "Commentary shortcuts";
+// break;
+// };
+// case lexiconWindow : {
+// groupName = "Lexicon shortcuts";
+// break;
+// };
+// case application : {
+// groupName = "Application shortcuts";
+// break;
+// };
+// };
+//
+// // KConfigGroup* cg = &(CBTConfig::getConfig()->group(groupName));
+//
+// qDebug("NOT saving accelerators!");
+// //actionCollection->writeSettings(cg);
+// qDebug("CBTConfig::saveAccelSettings end");
+//}
+
+
+QString CBTConfig::getModuleEncryptionKey( const QString& module )
+{
+ Q_ASSERT(!module.isEmpty());
+ QString result;
+ getConfig()->beginGroup("Module keys");
+ result = getConfig()->value(module, QVariant(QString::null)).toString();
+ getConfig()->endGroup();
+ return result;
+}
+
+void CBTConfig::setModuleEncryptionKey( const QString& module, const QString& key )
+{
+ getConfig()->beginGroup("Module keys");
+ getConfig()->setValue(module, key);
+ getConfig()->endGroup();
+}
+
+QSettings* CBTConfig::getConfig()
+{
+ static QSettings config(util::filesystem::DirectoryUtil::getUserBaseDir().absolutePath() + "/bibletimerc", QSettings::IniFormat);
+ return &config;
+}
+
+void CBTConfig::syncConfig()
+{
+ CBTConfig::getConfig()->sync();
+}
+
+QString CBTConfig::IntListToString( const QList<int> intList )
+{
+ QStringList intStrings;
+ foreach(int i, intList)
+ {
+ intStrings << QString::number(i);
+ }
+ return intStrings.join(",");
+}
+
+QList<int> CBTConfig::StringToIntList( const QString intListString )
+{
+ QList<int> intList;
+ if (!intListString.isEmpty() && intListString.contains(','))
+ {
+ foreach(QString intString, intListString.split(","))
+ {
+ intList << intString.trimmed().toInt();
+ }
+ }
+ return intList;
+}
diff --git a/src/backend/config/cbtconfig.h b/src/backend/config/cbtconfig.h
new file mode 100644
index 0000000..0ded865
--- /dev/null
+++ b/src/backend/config/cbtconfig.h
@@ -0,0 +1,197 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CBTCONFIG_H
+#define CBTCONFIG_H
+
+#include "backend/managers/cswordbackend.h"
+
+//Qt includes
+#include <QString>
+#include <QFont>
+#include <QList>
+#include <QMap>
+
+//Forward declarations
+class QSettings;
+//class CLanguageMgr::Language;
+
+/**
+ * This class is the interface to the config object of BibleTime
+ * @author The BibleTime team
+ */
+class CBTConfig {
+public:
+ typedef QMap<QString, QString> StringMap;
+
+ enum strings {
+ bibletimeVersion,
+ language,
+ displayStyle,
+ bookshelfCurrentItem
+ };
+ enum modules {
+ standardBible = 0, //just to make sure, default is IMHO 0, so that's redundant here
+ standardCommentary,
+ standardLexicon,
+ standardDailyDevotional,
+ standardHebrewStrongsLexicon,
+ standardGreekStrongsLexicon,
+ standardHebrewMorphLexicon,
+ standardGreekMorphLexicon,
+ lastModuleType = standardGreekMorphLexicon
+ };
+ enum bools {
+ firstSearchDialog,
+ readOldBookmarks,
+
+ toolbar,
+ mainIndex,
+ infoDisplay,
+
+ autoTileVertical,
+ autoTileHorizontal,
+ autoCascade,
+
+ lineBreaks,
+ verseNumbers,
+
+ logo,
+ autoDeleteOrphanedIndices,
+ crashedLastTime,
+ crashedTwoTimes,
+
+ bookshelfShowHidden,
+
+ allowNetworkConnection
+ };
+ enum ints {
+ footnotes,
+ strongNumbers,
+ headings,
+ morphTags,
+ lemmas,
+ hebrewPoints,
+ hebrewCantillation,
+ greekAccents,
+ textualVariants,
+ scriptureReferences,
+ morphSegmentation,
+
+ bookshelfContentsX,
+ bookshelfContentsY,
+ magDelay, /* The delay until a mouse move makes the content appear in the mag */
+ bookshelfGrouping,
+ mainindexActiveTab,
+
+ searchDialogWidth,
+ searchDialogHeight,
+ searchDialogX,
+ searchDialogY,
+ searchType,
+
+ installPathIndex
+ };
+ enum intLists {
+ leftPaneSplitterSizes,
+ mainSplitterSizes,
+ searchMainSplitterSizes,
+ searchResultSplitterSizes
+ };
+ enum stringLists {
+ searchCompletionTexts,
+ searchTexts,
+ searchModulesHistory,
+ bookshelfOpenGroups,
+ hiddenModules
+ };
+ enum keys {
+ allWindows,
+ readWindow,
+ writeWindow,
+ bookWindow,
+ bibleWindow,
+ commentaryWindow,
+ lexiconWindow,
+ application
+ };
+ enum stringMaps {
+ searchScopes
+ };
+ typedef std::pair<bool, QFont> FontSettingsPair;
+
+ static QString get( const CBTConfig::strings );
+ static CSwordModuleInfo* get( const CBTConfig::modules );
+ static bool get( const CBTConfig::bools );
+ static int get( const CBTConfig::ints );
+ static QList<int> get( const CBTConfig::intLists );
+ static QStringList get( const CBTConfig::stringLists );
+ static CBTConfig::StringMap get( const CBTConfig::stringMaps );
+
+ static FontSettingsPair get( const CLanguageMgr::Language* const );
+
+ static QString getDefault( const CBTConfig::strings );
+ static QString getDefault( const CBTConfig::modules );
+ static bool getDefault( const CBTConfig::bools );
+ static int getDefault( const CBTConfig::ints );
+ static QList<int> getDefault( const CBTConfig::intLists );
+ static QStringList getDefault( const CBTConfig::stringLists );
+ static CBTConfig::StringMap getDefault( const CBTConfig::stringMaps );
+ static QFont& getDefault( const CLanguageMgr::Language* const );
+
+ static void set( const CBTConfig::strings, const QString value );
+ static void set( const CBTConfig::modules, CSwordModuleInfo* const module );
+ static void set( const CBTConfig::modules, const QString& moduleName );
+ static void set( const CBTConfig::bools, const bool value );
+ static void set( const CBTConfig::ints, const int value );
+ static void set( const CBTConfig::intLists, const QList<int> value );
+ static void set( const CBTConfig::stringLists, const QStringList value);
+ static void set( const CBTConfig::stringMaps, const CBTConfig::StringMap value);
+ static void set( const CLanguageMgr::Language* const language, const FontSettingsPair& fontSettings );
+
+ static CSwordBackend::FilterOptions getFilterOptionDefaults();
+ static CSwordBackend::DisplayOptions getDisplayOptionDefaults();
+
+// static void setupAccelSettings(const CBTConfig::keys type, KActionCollection* const actionCollection);
+// static void saveAccelSettings(const CBTConfig::keys type, KActionCollection* const actionCollection);
+
+ static QString getModuleEncryptionKey( const QString& name );
+ static void setModuleEncryptionKey( const QString& name, const QString& key );
+
+ /** Re-reads the config from disk */
+ static void syncConfig();
+
+private:
+ friend class BibleTimeTest;
+ /** The config object.
+ * @return A config object which is used currently, may be the global config or the session config
+ */
+ static QSettings* getConfig();
+
+ static QString getKey( const CBTConfig::strings );
+ static QString getKey( const CBTConfig::modules );
+ static QString getKey( const CBTConfig::bools );
+ static QString getKey( const CBTConfig::ints );
+ static QString getKey( const CBTConfig::intLists );
+ static QString getKey( const CBTConfig::stringLists );
+ static QString getKey( const CBTConfig::stringMaps );
+ static QString getKey( const CLanguageMgr::Language* const );
+
+ static QString IntListToString( const QList<int> );
+ static QList<int> StringToIntList( const QString );
+
+ //static caches
+ static QFont* m_defaultFont;
+
+ typedef QMap<const CLanguageMgr::Language*, CBTConfig::FontSettingsPair> FontCache;
+ static QMap<const CLanguageMgr::Language*, CBTConfig::FontSettingsPair> fontConfigMap;
+};
+
+
+#endif
diff --git a/src/backend/cswordmodulesearch.cpp b/src/backend/cswordmodulesearch.cpp
new file mode 100644
index 0000000..f57a87a
--- /dev/null
+++ b/src/backend/cswordmodulesearch.cpp
@@ -0,0 +1,123 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+//BibleTime includes
+#include "cswordmodulesearch.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/managers/cswordbackend.h"
+#include "backend/config/cbtconfig.h"
+
+//Sword includes
+#include <swmodule.h>
+#include <swkey.h>
+#include <listkey.h>
+
+
+CSwordModuleSearch* CSwordModuleSearch::searcher = 0;
+
+CSwordModuleSearch::CSwordModuleSearch()
+ : m_searchedText(QString::null),
+ m_searchOptions(0),
+ m_foundItems(false)
+{
+ searcher = this;
+}
+
+CSwordModuleSearch::~CSwordModuleSearch() {
+ searcher = 0;
+}
+
+/** This function sets the modules which should be searched. */
+void CSwordModuleSearch::setModules( const QList<CSwordModuleInfo*>& list ) {
+ m_moduleList = list;
+}
+
+/** Starts the search for the search text. */
+bool CSwordModuleSearch::startSearch() {
+ backend()->setFilterOptions ( CBTConfig::getFilterOptionDefaults() );
+ m_foundItems = false;
+
+ bool foundItems = false;
+
+ // for (m_moduleList.first(); m_moduleList.current() && !m_terminateSearch; m_moduleList.next()) {
+ QList<CSwordModuleInfo*>::iterator end_it = m_moduleList.end();
+
+ for (QList<CSwordModuleInfo*>::iterator it = m_moduleList.begin(); it != end_it; ++it) {
+ if ( (*it)->searchIndexed(m_searchedText/*, m_searchOptions*/, m_searchScope) ) {
+ foundItems = true;
+ }
+ }
+
+ m_foundItems = foundItems;
+
+ //m_finishedSig.activate();
+ emit finished();
+ return true;
+}
+
+/** Sets the text which should be search in the modules. */
+void CSwordModuleSearch::setSearchedText( const QString& text ) {
+ m_searchedText = text;
+}
+
+/** Sets the search scope. */
+void CSwordModuleSearch::setSearchScope( const sword::ListKey& scope ) {
+ m_searchScope.copyFrom( scope );
+
+ if (!strlen(scope.getRangeText())) { //we can't search with an empty search scope, would crash
+ //reset the scope
+ resetSearchScope();
+
+ //disable searching with a scope!
+ // if (m_searchOptions | useScope) {
+ // qWarning("using the scope!");
+ //set back the scope flag
+ // }
+ }
+}
+
+/** Sets the search scope back. */
+void CSwordModuleSearch::resetSearchScope() {
+ m_searchScope.ClearList();
+}
+
+/** Returns true if in the last search the searcher found items, if no items were found return false. */
+bool CSwordModuleSearch::foundItems() const {
+ return m_foundItems;
+}
+
+/** Returns a copy of the used search scope. */
+const sword::ListKey& CSwordModuleSearch::searchScope() const {
+ return m_searchScope;
+}
+
+void CSwordModuleSearch::connectFinished( QObject *receiver, const char *member ) {
+ //m_finishedSig.connect(receiver, member);
+ QObject::connect(this, SIGNAL(finished()), receiver, member);
+}
+
+/** Should be called when the search finished. */
+void CSwordModuleSearch::searchFinished() {
+ //m_finishedSig.activate();
+ emit finished();
+}
+
+bool CSwordModuleSearch::modulesHaveIndices( const QList<CSwordModuleInfo*>& modules )
+{
+ bool hasIndices = true;
+ QList<CSwordModuleInfo*>::const_iterator end_it = modules.end();
+ for( QList<CSwordModuleInfo*>::const_iterator it = modules.begin(); it != end_it; ++it) {
+ if (!(*it)->hasIndex()) {
+ hasIndices = false;
+ break;
+ }
+ }
+ return hasIndices;
+}
diff --git a/src/backend/cswordmodulesearch.h b/src/backend/cswordmodulesearch.h
new file mode 100644
index 0000000..7ba6a6f
--- /dev/null
+++ b/src/backend/cswordmodulesearch.h
@@ -0,0 +1,98 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+#ifndef CSWORDMODULESEARCH_H
+#define CSWORDMODULESEARCH_H
+
+//BibleTime - backend
+class CSwordModuleInfo;
+
+//BibleTime - utils
+#include "util/cpointers.h"
+
+//Qt includes
+#include <QObject>
+#include <QString>
+
+//Sword includes
+#include <listkey.h>
+
+/**
+ * CSwordModuleSearch manages the search on Sword modules. It manages the thread(s)
+ * and manages the different modules.
+ *
+ * @author The BibleTime team
+ * @version $Id: cswordmodulesearch.h,v 1.34 2006/08/08 19:32:48 joachim Exp $
+ */
+
+class CSwordModuleSearch: public QObject, CPointers {
+ Q_OBJECT
+
+public:
+ CSwordModuleSearch();
+ /**
+ * The destructor of this class. It cleans uop memory before it's deleted.
+ */
+ virtual ~CSwordModuleSearch();
+ /**
+ * Sets the text which should be search in the modules.
+ */
+ void setSearchedText( const QString& );
+ /**
+ * Starts the search for the search text.
+ */
+ bool startSearch();
+ /**
+ * This function sets the modules which should be searched.
+ */
+ void setModules( const QList<CSwordModuleInfo*>& );
+ /**
+ * Sets the search scope.
+ */
+ void setSearchScope( const sword::ListKey& scope );
+ /**
+ * Sets the seaech scope back.
+ */
+ void resetSearchScope();
+ /**
+ * @return "true" if in the last search the searcher found items, if no items were found return "false"
+ */
+ bool foundItems() const;
+ /**
+ * Returns a copy of the used search scope.
+ */
+ const sword::ListKey& searchScope() const;
+
+ void connectFinished( QObject * receiver, const char * member );
+ void searchFinished();
+
+ /**
+ * Returns true if all of the specified modules have indices already built.
+ */
+ bool modulesHaveIndices( const QList<CSwordModuleInfo*>& );
+
+protected:
+ QString m_searchedText;
+ sword::ListKey m_searchScope;
+ QList<CSwordModuleInfo*> m_moduleList;
+
+ int m_searchOptions;
+
+ bool m_foundItems;
+
+signals:
+ void finished();
+
+private:
+ static CSwordModuleSearch* searcher;
+};
+
+#endif
diff --git a/src/backend/drivers/cswordbiblemoduleinfo.cpp b/src/backend/drivers/cswordbiblemoduleinfo.cpp
new file mode 100644
index 0000000..921157b
--- /dev/null
+++ b/src/backend/drivers/cswordbiblemoduleinfo.cpp
@@ -0,0 +1,261 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+//BibleTime includes
+#include "cswordbiblemoduleinfo.h"
+#include "backend/managers/cswordbackend.h"
+#include "backend/keys/cswordversekey.h"
+
+//Qt
+#include <QFile>
+
+//Sword
+#include <versekey.h>
+
+#include <boost/scoped_ptr.hpp>
+
+
+CSwordBibleModuleInfo::CSwordBibleModuleInfo( sword::SWModule* module, CSwordBackend* const usedBackend )
+: CSwordModuleInfo(module, usedBackend),
+m_lowerBound(0),
+m_upperBound(0),
+m_bookList(0),
+m_cachedLocale("unknown"),
+m_hasOT(-1),
+m_hasNT(-1) {}
+
+CSwordBibleModuleInfo::CSwordBibleModuleInfo( const CSwordBibleModuleInfo& m ) :
+CSwordModuleInfo(m),
+m_lowerBound(0),
+m_upperBound(0),
+m_bookList(0) {
+ if (m.m_bookList) {
+ m_bookList = new QStringList();
+ *m_bookList = *m.m_bookList;
+ }
+
+ m_hasOT = m.m_hasOT;
+ m_hasNT = m.m_hasNT;
+ m_cachedLocale = m.m_cachedLocale;
+}
+
+CSwordModuleInfo* CSwordBibleModuleInfo::clone() {
+ return new CSwordBibleModuleInfo(*this);
+}
+
+CSwordBibleModuleInfo::~CSwordBibleModuleInfo() {
+ delete m_bookList;
+}
+
+void CSwordBibleModuleInfo::initBounds() {
+ if (m_hasOT == -1) {
+ m_hasOT = hasTestament(OldTestament);
+ }
+
+ if (m_hasNT == -1) {
+ m_hasNT = hasTestament(NewTestament);
+ }
+
+ if (m_hasOT) {
+ m_lowerBound.key("Genesis 1:1");
+ }
+ else {
+ m_lowerBound.key("Matthew 1:1");
+ }
+
+ if (!m_hasNT) {
+ m_upperBound.key("Malachi 4:6");
+ }
+ else {
+ m_upperBound.key("Revelation of John 22:21");
+ }
+}
+
+
+/** Returns the books available in this module */
+QStringList* CSwordBibleModuleInfo::books() {
+ if (m_cachedLocale != backend()->booknameLanguage()) { //if the locale has changed
+ delete m_bookList;
+ m_bookList = 0;
+ }
+
+ if (!m_bookList) {
+ m_bookList = new QStringList();
+
+ initBounds();
+ int min = 0;
+ int max = 1;
+
+ //find out if we have ot and nt, only ot or only nt
+
+ if (m_hasOT>0 && m_hasNT>0) { //both
+ min = 0;
+ max = 1;
+ }
+ else if (m_hasOT>0 && !m_hasNT) { //only OT
+ min = 0;
+ max = 0;
+ }
+ else if (!m_hasOT && m_hasNT>0) { //only NT
+ min = 1;
+ max = 1;
+ }
+ else if (!m_hasOT && !m_hasNT) { //somethings wrong here! - no OT and no NT
+ qWarning("CSwordBibleModuleInfo (%s) no OT and not NT! Check your config!", module()->Name());
+ min = 0;
+ max = -1;
+ }
+
+ boost::scoped_ptr<sword::VerseKey> key((sword::VerseKey *)module()->CreateKey());
+ (*key) = sword::TOP;
+
+ for (key->Testament(min+1); !key->Error() && (key->Testament()-1) <= max; key->Book(key->Book()+1)) {
+ m_bookList->append( QString::fromUtf8(key->getBookName()) );
+ }
+
+ m_cachedLocale = backend()->booknameLanguage();
+ }
+
+ return m_bookList;
+}
+
+/** Returns the number of chapters for the given book. */
+unsigned int CSwordBibleModuleInfo::chapterCount(const unsigned int book) {
+ int result = 0;
+
+ boost::scoped_ptr<sword::VerseKey> key((sword::VerseKey *)module()->CreateKey());
+ (*key) = sword::TOP;
+
+ // works for old and new versions
+ key->Book(book);
+ (*key) = sword::MAXCHAPTER;
+ result = key->Chapter();
+
+ return result;
+}
+
+unsigned int CSwordBibleModuleInfo::chapterCount(const QString& book) {
+ return chapterCount( bookNumber(book) );
+}
+
+/** Returns the number of verses for the given chapter. */
+
+unsigned int CSwordBibleModuleInfo::verseCount( const unsigned int book, const unsigned int chapter ) {
+ unsigned int result = 0;
+
+ boost::scoped_ptr<sword::VerseKey> key((sword::VerseKey *)module()->CreateKey());
+ (*key) = sword::TOP;
+
+ // works for old and new versions
+ key->Book(book);
+ key->Chapter(chapter);
+ (*key) = sword::MAXVERSE;
+ result = key->Verse();
+
+ return result;
+}
+
+unsigned int CSwordBibleModuleInfo::verseCount( const QString& book, const unsigned int chapter ) {
+ return verseCount( bookNumber(book), chapter );
+}
+
+unsigned int CSwordBibleModuleInfo::bookNumber(const QString &book) {
+ unsigned int bookNumber = 0;
+ bool found = false;
+ int min = 0;
+ int max = 1;
+
+ //find out if we have ot and nt, only ot or only nt
+ initBounds();
+
+ boost::scoped_ptr<sword::VerseKey> key((sword::VerseKey *)module()->CreateKey());
+ (*key) = sword::TOP;
+
+#ifdef SWORD_MULTIVERSE
+ key->setBookName(book.toUtf8().constData());
+
+ bookNumber = ((key->Testament() > 1) ? key->BMAX[0] : 0) + key->Book();
+#else
+
+ if ((m_hasOT>0 && m_hasNT>0) || (m_hasOT == -1 && m_hasNT == -1)) {
+ min = 0;
+ max = 1;
+ bookNumber = 0;
+ }
+ else if (m_hasOT>0 && !m_hasNT) {
+ min = 0;
+ max = 0;
+ bookNumber = 0;
+ }
+ else if (!m_hasOT && m_hasNT>0) {
+ min = 1;
+ max = 1;
+ bookNumber = key->BMAX[0];
+ }
+ else if (!m_hasOT && !m_hasNT) {
+ min = 0;
+ max = -1; //no loop
+ bookNumber = 0;
+ }
+
+ for (int i = min; i <= max && !found; ++i) {
+ for ( int j = 0; j < key->BMAX[i] && !found; ++j) {
+ ++bookNumber;
+
+ if (book == QString::fromUtf8( key->books[i][j].name) )
+ found = true;
+ }
+ }
+#endif
+
+ return bookNumber;
+}
+
+/** Returns true if his module has the text of desired type of testament */
+bool CSwordBibleModuleInfo::hasTestament( CSwordBibleModuleInfo::Testament type ) {
+ if (m_hasOT == -1 || m_hasNT == -1) {
+ const bool oldStatus = module()->getSkipConsecutiveLinks();
+ module()->setSkipConsecutiveLinks(true);
+
+ *module() = sword::TOP; //position to first entry
+ sword::VerseKey key( module()->KeyText() );
+
+ if (key.Testament() == 1) { // OT && NT
+ m_hasOT = 1;
+ }
+ else if (key.Testament() == 2) { //no OT
+ m_hasOT = 0;
+ }
+
+ *module() = sword::BOTTOM;
+ key = module()->KeyText();
+
+ if (key.Testament() == 1) { // only OT, no NT
+ m_hasNT = 0;
+ }
+ else if (key.Testament() == 2) { //has NT
+ m_hasNT = 1;
+ }
+
+ module()->setSkipConsecutiveLinks(oldStatus);
+ }
+
+ switch (type) {
+
+ case OldTestament:
+ return m_hasOT>0;
+
+ case NewTestament:
+ return m_hasNT>0;
+
+ default:
+ return false;
+ }
+}
+
diff --git a/src/backend/drivers/cswordbiblemoduleinfo.h b/src/backend/drivers/cswordbiblemoduleinfo.h
new file mode 100644
index 0000000..c25eb37
--- /dev/null
+++ b/src/backend/drivers/cswordbiblemoduleinfo.h
@@ -0,0 +1,126 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CSWORDBIBLEMODULEINFO_H
+#define CSWORDBIBLEMODULEINFO_H
+
+#include "cswordmoduleinfo.h"
+#include "backend/keys/cswordversekey.h"
+
+//Qt
+#include <QStringList>
+
+/**
+ * This is the CModuleInfo imlementation for Bible modules managed by Sword.
+ *
+ * @short Implementation for Sword Bibles
+ * @author The BibleTime team
+ * @version $Id: cswordbiblemoduleinfo.h,v 1.18 2006/02/25 11:38:15 joachim Exp $
+ */
+
+class CSwordBibleModuleInfo : public CSwordModuleInfo {
+
+public:
+ enum Testament {
+ OldTestament = 1,
+ NewTestament = 2
+ };
+
+ /**
+ * The constructor of this class
+ */
+ CSwordBibleModuleInfo( sword::SWModule* module, CSwordBackend* const );
+ /** The copy constructor for this Bible module.
+ */
+ CSwordBibleModuleInfo( const CSwordBibleModuleInfo& m );
+ /**
+ * The destructor of this class
+ */
+ ~CSwordBibleModuleInfo();
+ /**
+ * Returns the number of avalable verses for the given chapter and book.
+ *
+ * @param book The number book we should use
+ * @param chapter The chapter we should use
+ * @return The number of verses for the given book and chapter
+ */
+ virtual unsigned int verseCount( const unsigned int book, const unsigned int chapter );
+ /**
+ * Returns the number of avalable verses for the given chapter and book.
+ *
+ * @param book The name of the book we use
+ * @param chapter The number of the chapter we use
+ * @return The number of verses for the given book and chapter
+ */
+ virtual unsigned int verseCount( const QString& book, const unsigned int chapter );
+ /** Information about the chapters in a book.
+ * @return The number of available chapters of the given book.
+ * @return The number of chapters for the given book
+ */
+ virtual unsigned int chapterCount( const unsigned int book );
+ /** Information about the chapters in a book.
+ * @return The number of available chapters of the given book.
+ */
+ virtual unsigned int chapterCount( const QString& book );
+ /** Return all book of this module.
+ * @return A QStringList containing the books which are available in this module.
+ */
+ virtual QStringList* books();
+ /**
+ * Reimplementation, Returns the type
+ */
+ virtual CSwordModuleInfo::ModuleType type() const;
+ /**
+ * @return the book number, values starting with 1; 0 if not found
+ */
+ unsigned int bookNumber(const QString &book);
+ /**
+ * Returns true if his module has the text of desired type of testament
+ */
+ bool hasTestament( CSwordBibleModuleInfo::Testament );
+ /** Reimplementation to clone this object. */
+ virtual CSwordModuleInfo* clone();
+ /**
+ * Returns the key which represents the lower bound of this module.
+ */
+ inline const CSwordVerseKey& lowerBound();
+ /**
+ * Returns the key which represents the upper bound of this module.
+ */
+ inline const CSwordVerseKey& upperBound();
+
+private:
+ void initBounds();
+
+ CSwordVerseKey m_lowerBound;
+ CSwordVerseKey m_upperBound;
+
+ QStringList* m_bookList; //This booklist is cached
+ QString m_cachedLocale;
+ short int m_hasOT;
+ short int m_hasNT;
+};
+
+inline CSwordModuleInfo::ModuleType CSwordBibleModuleInfo::type() const {
+ return CSwordModuleInfo::Bible;
+}
+
+/** Returns the key which represents the lower bound of this module. */
+inline const CSwordVerseKey& CSwordBibleModuleInfo::lowerBound() {
+ initBounds();
+ return m_lowerBound;
+}
+
+/** Returns the key which represents the lower bound of this module. */
+inline const CSwordVerseKey& CSwordBibleModuleInfo::upperBound() {
+ initBounds();
+ return m_upperBound;
+}
+
+#endif
diff --git a/src/backend/drivers/cswordbookmoduleinfo.cpp b/src/backend/drivers/cswordbookmoduleinfo.cpp
new file mode 100644
index 0000000..0a8c1e6
--- /dev/null
+++ b/src/backend/drivers/cswordbookmoduleinfo.cpp
@@ -0,0 +1,68 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+//BibleTime includes
+#include "cswordbookmoduleinfo.h"
+#include "backend/keys/cswordtreekey.h"
+
+//Sword includes
+#include <treekeyidx.h>
+#include <treekey.h>
+
+CSwordBookModuleInfo::CSwordBookModuleInfo( sword::SWModule* module, CSwordBackend* const usedBackend )
+: CSwordModuleInfo(module, usedBackend),
+m_depth(-1) {}
+
+CSwordBookModuleInfo::CSwordBookModuleInfo( const CSwordBookModuleInfo& module )
+: CSwordModuleInfo(module) {
+ m_depth = module.m_depth;
+}
+
+CSwordBookModuleInfo::~CSwordBookModuleInfo() {}
+
+int CSwordBookModuleInfo::depth() {
+ if (m_depth == -1) {
+ sword::TreeKeyIdx* key = tree();
+
+ if (key) {
+ key->root();
+ computeDepth(key, 0);
+ }
+ }
+
+ return m_depth;
+}
+
+void CSwordBookModuleInfo::computeDepth(sword::TreeKeyIdx* key, int level ) {
+ std::string savedKey;
+ // savedKey = key->getFullName(); //sword 1.5.8
+ savedKey = key->getText();
+
+ if (level > m_depth) {
+ m_depth = level;
+ }
+
+ if (key->hasChildren()) {
+ key->firstChild();
+ computeDepth(key, level+1);
+
+ key->setText( savedKey.c_str() );//return to the initial value
+ }
+
+ if (key->nextSibling()) {
+ computeDepth(key, level);
+ }
+}
+
+/** Returns a treekey filled with the structure of this module */
+sword::TreeKeyIdx* CSwordBookModuleInfo::tree() const {
+ sword::TreeKeyIdx* treeKey = dynamic_cast<sword::TreeKeyIdx*>((sword::SWKey*)*(module()));
+ Q_ASSERT(treeKey);
+ return treeKey;
+}
diff --git a/src/backend/drivers/cswordbookmoduleinfo.h b/src/backend/drivers/cswordbookmoduleinfo.h
new file mode 100644
index 0000000..f471d61
--- /dev/null
+++ b/src/backend/drivers/cswordbookmoduleinfo.h
@@ -0,0 +1,64 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CSWORDGENBOOKMODULEINFO_H
+#define CSWORDGENBOOKMODULEINFO_H
+
+#include "cswordmoduleinfo.h"
+
+//Sword
+#include <treekeyidx.h>
+
+/** Class for generic book support
+ * @author The BibleTime team
+ */
+
+class CSwordBookModuleInfo : public CSwordModuleInfo {
+
+public:
+ /** Constructor.
+ * @param module The module which belongs to this object
+ * @param backend The parent backend for this book module.
+ */
+ CSwordBookModuleInfo( sword::SWModule* module, CSwordBackend* const backend );
+ /** Copy constructor.
+ * Copy constructor to copy the passed parameter.
+ * @param module The module which should be copied.
+ */
+ CSwordBookModuleInfo( const CSwordBookModuleInfo& module );
+ /** Destructor.
+ */
+ ~CSwordBookModuleInfo();
+ /**
+ * Returns the type of the module.
+ */
+ virtual CSwordModuleInfo::ModuleType type() const;
+ /**
+ * Returns the maximal depth of sections and subsections.
+ */
+ int depth();
+ /**
+ * @return A treekey filled with the structure of this module. Don't delete the returned key because it's casted from the module object.
+ */
+ sword::TreeKeyIdx* tree() const;
+
+private:
+ /**
+ * A recursive helper function to help computng the module depth!
+ */
+ void computeDepth(sword::TreeKeyIdx* key, int level = 0 );
+ int m_depth;
+};
+
+inline CSwordBookModuleInfo::ModuleType CSwordBookModuleInfo::type() const {
+ return CSwordModuleInfo::GenericBook;
+}
+
+
+#endif
diff --git a/src/backend/drivers/cswordcommentarymoduleinfo.cpp b/src/backend/drivers/cswordcommentarymoduleinfo.cpp
new file mode 100644
index 0000000..b09e2f3
--- /dev/null
+++ b/src/backend/drivers/cswordcommentarymoduleinfo.cpp
@@ -0,0 +1,32 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cswordcommentarymoduleinfo.h"
+
+CSwordCommentaryModuleInfo::CSwordCommentaryModuleInfo( sword::SWModule* module, CSwordBackend* const usedBackend)
+: CSwordBibleModuleInfo(module, usedBackend) {}
+
+CSwordCommentaryModuleInfo::~CSwordCommentaryModuleInfo() {}
+
+/** No descriptions */
+CSwordModuleInfo* CSwordCommentaryModuleInfo::clone() {
+ return new CSwordCommentaryModuleInfo(*this);
+}
+
+/** Returns true if this module may be written by the write display windows. */
+bool CSwordCommentaryModuleInfo::isWritable() const {
+ // qWarning(module()->getConfigEntry("ModDrv"));
+ //a module is only writable if it's a RawFiles module with writable returning true
+
+ if ( (std::string(module()->getConfigEntry("ModDrv")) == std::string("RawFiles")) && module()->isWritable()) {
+ return true;
+ };
+
+ return false;
+}
diff --git a/src/backend/drivers/cswordcommentarymoduleinfo.h b/src/backend/drivers/cswordcommentarymoduleinfo.h
new file mode 100644
index 0000000..7ebf23f
--- /dev/null
+++ b/src/backend/drivers/cswordcommentarymoduleinfo.h
@@ -0,0 +1,43 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CSWORDCOMMENTARYMODULEINFO_H
+#define CSWORDCOMMENTARYMODULEINFO_H
+
+//own includes
+#include "cswordbiblemoduleinfo.h"
+
+/** Commentary module implementation.
+ * This CSwordModule implementation provides access to Sword's commentary modules.
+ * @author The BibleTime team
+ * @version $Id: cswordcommentarymoduleinfo.h,v 1.13 2006/02/25 11:38:15 joachim Exp $
+ */
+
+class CSwordCommentaryModuleInfo : public CSwordBibleModuleInfo {
+
+public:
+ CSwordCommentaryModuleInfo( sword::SWModule* module, CSwordBackend* const );
+ ~CSwordCommentaryModuleInfo();
+ /** Reimplementation to return the commentary type.
+ */
+ virtual CSwordModuleInfo::ModuleType type() const;
+ /** Reimplementation to clone the current object.
+ */
+ virtual CSwordModuleInfo* clone();
+ /**
+ * Returns true if this module may be written by the write display windows.
+ */
+ virtual bool isWritable() const;
+};
+
+inline CSwordModuleInfo::ModuleType CSwordCommentaryModuleInfo::type() const {
+ return CSwordModuleInfo::Commentary;
+}
+
+#endif
diff --git a/src/backend/drivers/cswordlexiconmoduleinfo.cpp b/src/backend/drivers/cswordlexiconmoduleinfo.cpp
new file mode 100644
index 0000000..a8b81e4
--- /dev/null
+++ b/src/backend/drivers/cswordlexiconmoduleinfo.cpp
@@ -0,0 +1,170 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cswordlexiconmoduleinfo.h"
+#include "util/directoryutil.h"
+
+//Qt
+#include <QFile>
+#include <QDataStream>
+#include <QTextCodec>
+
+//Sword
+#include <swmodule.h>
+
+//STL includes
+#include <algorithm>
+
+//Change it once the format changed to make all systems rebuild their caches
+#define CACHE_FORMAT "2"
+
+CSwordLexiconModuleInfo::CSwordLexiconModuleInfo( sword::SWModule* module, CSwordBackend* const backend ) : CSwordModuleInfo(module, backend) {
+ m_entryList = 0;
+}
+
+CSwordLexiconModuleInfo::CSwordLexiconModuleInfo( const CSwordLexiconModuleInfo& m ) : CSwordModuleInfo(m) {
+ delete m_entryList;
+ m_entryList = 0;
+
+ if (m.m_entryList) {
+ m_entryList = new QStringList();
+ *m_entryList = *m.m_entryList;//copy list items
+ }
+}
+
+CSwordLexiconModuleInfo::~CSwordLexiconModuleInfo() {
+ delete m_entryList;
+ m_entryList = 0;
+}
+
+/** Returns the entries of the module. */
+QStringList* CSwordLexiconModuleInfo::entries() {
+ if (!module()) {
+ return 0;
+ }
+
+ sword::SWModule* my_module = module();
+ bool is_unicode = isUnicode();
+
+ if (!m_entryList) {
+ m_entryList = new QStringList();
+ bool read = false;
+
+ //Check for buggy modules! They will not be loaded any more.
+
+ if ( name() == QString("ZhEnglish")) {
+ qWarning("Module ZhEnglish is buggy and will not be loaded.");
+ return m_entryList;
+ }
+
+ QString dir(util::filesystem::DirectoryUtil::getUserCacheDir().absolutePath());
+ QFile f1(
+ QString(dir)
+ .append("/")
+ .append(name())
+ );
+
+ if ( f1.open( QIODevice::ReadOnly ) ) {
+ QDataStream s( &f1 );
+ QString mod_ver, prog_ver;
+ s >> mod_ver;
+ s >> prog_ver;
+
+ if ((mod_ver == config(ModuleVersion)) && (prog_ver == CACHE_FORMAT)) {
+ s >> *m_entryList;
+ read = true;
+ }
+
+ f1.close();
+ // qWarning("read entries %d",m_entryList->count());
+ }
+
+ // Q_ASSERT(read);
+ // Q_ASSERT(m_entryList->count());
+ if (!read || !m_entryList->count()) {
+ my_module->setSkipConsecutiveLinks(true);
+ (*my_module) = sword::TOP;
+ snap(); //snap to top entry
+
+ // qWarning("Reading in module" );
+ int i = 0;
+
+ do {
+ if ( is_unicode ) {
+ m_entryList->append(QString::fromUtf8(my_module->KeyText()));
+ // qWarning("Entry: %s", my_module->KeyText() );
+ }
+ else { //for latin1 modules use fromLatin1 because of speed
+ // m_entryList->append(QString::fromLatin1(my_module->KeyText()));
+ QTextCodec* codec = QTextCodec::codecForName("Windows-1252");
+ m_entryList->append(codec->toUnicode(my_module->KeyText()));
+ }
+
+ (*my_module)++;
+ i++;
+ }
+ while ( !my_module->Error() );
+
+ // qWarning("Reading finished. Module has %d entries.", i );
+
+ (*my_module) = sword::TOP; //back to the first entry
+
+ my_module->setSkipConsecutiveLinks(false);
+
+ if (m_entryList->count()) {
+ m_entryList->first().simplified();
+
+ if (m_entryList->first().trimmed().isEmpty()) {
+ m_entryList->erase( m_entryList->begin() );
+ }
+
+ //now sort the list, this is necesssary because Sword doesn't do Unicode ordering
+ // qWarning("sorting");
+ // QStringList::iterator start(m_entryList->begin());
+ // QStringList::iterator end(m_entryList->end());
+ // std::sort( start, end, myLocaleAwareCompare() ); //stl sort
+ // m_entryList->sort(); //make sure the module is sorted by utf-8
+ }
+
+ qWarning("Writing cache file.");
+
+ if (m_entryList->count()) {
+ //create cache
+ QString dir = util::filesystem::DirectoryUtil::getUserCacheDir().absolutePath();
+ //QFile f2( QString::fromLatin1("%1/%2").arg(dir).arg( name() ) );
+ QFile f2( QString(dir).append("/").append(name()) );
+
+
+ if (f2.open( QIODevice::WriteOnly )) {
+ QDataStream s( &f2 );
+ s << config(CSwordModuleInfo::ModuleVersion); //store module version
+ s << QString(CACHE_FORMAT); //store BT version -- format may change
+ s << *m_entryList;
+ f2.close();
+ }
+ }
+ }
+ }
+
+ return m_entryList;
+}
+
+/** Jumps to the closest entry in the module. */
+bool CSwordLexiconModuleInfo::snap() {
+ if(module()->getRawEntry()) { // Snap to the current entry
+ return true;
+ }
+
+ return false;
+}
+
+/** No descriptions */
+CSwordModuleInfo* CSwordLexiconModuleInfo::clone() {
+ return new CSwordLexiconModuleInfo(*this);
+}
diff --git a/src/backend/drivers/cswordlexiconmoduleinfo.h b/src/backend/drivers/cswordlexiconmoduleinfo.h
new file mode 100644
index 0000000..13f72e4
--- /dev/null
+++ b/src/backend/drivers/cswordlexiconmoduleinfo.h
@@ -0,0 +1,71 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CSWORDLEXICONMODULEINFO_H
+#define CSWORDLEXICONMODULEINFO_H
+
+//own includes
+#include "cswordmoduleinfo.h"
+
+//Qt includes
+#include <QStringList>
+
+/**
+ * The implementation of CModuleInfo for the Sword lexiccons and citionaries.
+ * @author The BibleTime team
+ * @version $Id: cswordlexiconmoduleinfo.h,v 1.12 2006/02/25 11:38:15 joachim Exp $
+ */
+
+class CSwordLexiconModuleInfo : public CSwordModuleInfo {
+
+public:
+ /**
+ * The standard constructor fot this object.
+ * A default constructor doesn't exist. Use this one.
+ */
+ CSwordLexiconModuleInfo( sword::SWModule* module, CSwordBackend* const );
+ /**
+ * The copy constructor
+ */
+ CSwordLexiconModuleInfo( const CSwordLexiconModuleInfo& m );
+ /** Reimplementation to return a valid clone.
+ */
+ virtual CSwordModuleInfo* clone();
+ /** Destructor.
+ */
+ virtual ~CSwordLexiconModuleInfo();
+ /**
+ * Returns the entries of the module.
+ * This function returns the entries of the modules represented by this object.
+ * If this function is called for the first time the list is load from disk and stored in a list which cahes it.
+ * If the function is called again, the cached list is returned so we have a major speed improvement.
+ * @return The list of lexicon entries
+ */
+ QStringList* entries();
+ /**
+ * Reimplementation, to return the right type for this lexicon.
+ */
+ virtual CSwordModuleInfo::ModuleType type() const;
+ /**
+ * Jumps to the closest entry in the module.
+ */
+ bool snap();
+
+private:
+ /**
+ * This is the list which caches the entres of the module.
+ */
+ QStringList* m_entryList;
+};
+
+inline CSwordModuleInfo::ModuleType CSwordLexiconModuleInfo::type() const {
+ return CSwordModuleInfo::Lexicon;
+}
+
+#endif
diff --git a/src/backend/drivers/cswordmoduleinfo.cpp b/src/backend/drivers/cswordmoduleinfo.cpp
new file mode 100644
index 0000000..c76f5ef
--- /dev/null
+++ b/src/backend/drivers/cswordmoduleinfo.cpp
@@ -0,0 +1,955 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+//BibleTime includes
+#include "cswordmoduleinfo.h"
+#include "cswordlexiconmoduleinfo.h"
+
+#include "backend/managers/cswordbackend.h"
+#include "backend/cswordmodulesearch.h"
+#include "backend/keys/cswordkey.h"
+#include "backend/rendering/centrydisplay.h"
+#include "backend/managers/clanguagemgr.h"
+
+#include "util/directoryutil.h"
+#include "util/cpointers.h"
+#include "util/exceptions.h"
+#include "backend/config/cbtconfig.h"
+
+
+#include <boost/scoped_ptr.hpp>
+
+//Qt includes
+#include <QRegExp>
+#include <QDir>
+#include <QFileInfo>
+#include <QList>
+#include <QByteArray>
+#include <QDebug>
+#include <QSettings>
+#include <QMessageBox>
+#include <QCoreApplication>
+
+//Sword includes
+#include <swbuf.h>
+#include <swkey.h>
+#include <listkey.h>
+#include <versekey.h>
+#include <swconfig.h>
+#include <rtfhtml.h>
+
+//Lucence includes
+#include <CLucene.h>
+#include <CLucene/util/Reader.h>
+#include <CLucene/util/Misc.h>
+#include <CLucene/util/dirent.h>
+
+
+//Increment this, if the index format changes
+//Then indices on the user's systems will be rebuilt
+const unsigned int INDEX_VERSION = 6;
+
+//Maximum index entry size, 1MiB for now
+//Lucene default is too small
+const unsigned long BT_MAX_LUCENE_FIELD_LENGTH = 1024*1024;
+
+CSwordModuleInfo::CSwordModuleInfo(sword::SWModule * module, CSwordBackend * const usedBackend) {
+ m_module = module;
+ Q_ASSERT(module);
+
+ m_hidden = false;
+ m_cancelIndexing = false;
+ m_searchResult.ClearList();
+ m_backend = usedBackend ? usedBackend : CPointers::backend();
+ m_dataCache.name = module ? QString(module->Name()) : QString::null;
+ m_dataCache.isUnicode = module ? module->isUnicode() : false;
+ m_dataCache.category = UnknownCategory;
+ m_dataCache.language = 0;
+ m_dataCache.hasVersion = !QString((*m_backend->getConfig())[module->Name()]["Version"]).isEmpty();
+
+ if (backend()) {
+ if (hasVersion() && (minimumSwordVersion() > sword::SWVersion::currentVersion)) {
+ qWarning("The module \"%s\" requires a newer Sword library. Please update to \"Sword %s\".",
+ name().toUtf8().constData(), (const char *)minimumSwordVersion());
+ }
+ }
+}
+
+CSwordModuleInfo::CSwordModuleInfo(const CSwordModuleInfo & m) : QObject(){
+ m_module = m.m_module;
+ m_backend = m.m_backend;
+ m_dataCache = m.m_dataCache;
+ m_searchResult = m.m_searchResult;
+ m_hidden = m.m_hidden;
+ m_cancelIndexing = m.m_cancelIndexing;
+}
+
+/** No descriptions */
+CSwordModuleInfo *CSwordModuleInfo::clone() {
+ return new CSwordModuleInfo(*this);
+}
+
+CSwordModuleInfo::~CSwordModuleInfo() {
+ m_searchResult.ClearList();
+ m_module = 0; //the Sword module object is deleted by the backend
+}
+
+/** Sets the unlock key of the modules and writes the key into the cofig file.*/
+bool CSwordModuleInfo::unlock(const QString & unlockKey) {
+ if (!isEncrypted()) {
+ return false;
+ }
+
+ CBTConfig::setModuleEncryptionKey(name(), unlockKey);
+ backend()->setCipherKey(m_module->Name(), unlockKey.toUtf8().constData());
+ //TODO: write to Sword config as well
+
+ return true;
+}
+
+/** This function returns true if this module is locked, otherwise return false. */
+bool CSwordModuleInfo::isLocked() {
+ //still works, but the cipherkey is stored in CBTConfig.
+ //Works because it is set in sword on program startup.
+
+ if (isEncrypted()) {
+ if (unlockKeyIsValid()) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+/** This functions returns true if this module is encrypted (locked or unlocked). */
+bool CSwordModuleInfo::isEncrypted() const {
+ /**
+ * If we have the CipherKey entry the module
+ * is encrypted but not necessarily locked
+ */
+
+ //This code is still right, though we do no longer write to the module config files any more
+ sword::ConfigEntMap config = backend()->getConfig()->Sections.find(name().toUtf8().constData())->second;
+ sword::ConfigEntMap::iterator it = config.find("CipherKey");
+
+ if (it != config.end()) {
+ return true;
+ }
+
+ return false;
+}
+
+/** This function makes an estimate if a module was properly unlocked.
+* It returns true if the first entry of the module is not empty and
+* contains only printable characters (for the first 100 chars or so).
+* If that is the case, we can safely assume that a) the module was properly
+* unlocked and b) no buffer overflows will occur, which can happen when
+* Sword filters process garbage text which was not properly decrypted.
+*/
+bool CSwordModuleInfo::unlockKeyIsValid() {
+
+ (*m_module) = sword::TOP;
+
+ // This needs to use ::fromLatin1 because if the text is still locked,
+ // a lot of garbage will show up. It will also work with properly decrypted
+ // Unicode text, because all non-ASCII Unicode chars consist of bytes >127
+ // and therefore contain no control (nonprintable) characters, which are all <127.
+ QString test = isUnicode()
+ ? QString::fromUtf8(m_module->getRawEntryBuf().c_str())
+ : QString::fromLatin1( m_module->getRawEntryBuf().c_str() );
+
+ if (test.isEmpty()) {
+ qWarning() << "Unlock key of module" << name() << "is NOT valid!";
+ return false;
+ }
+
+ for (int i = 0; i <= test.length() && i < 100; i++) {
+ if ( !test[i].isPrint() && !test[i].isNull() ) {
+ qWarning() << "Unlock key of module" << name() << "is NOT valid!";
+ return false;
+ }
+ }
+
+ qDebug() << "Unlock key of module" << name() << "is valid";
+ return true;
+}
+
+QString CSwordModuleInfo::getGlobalBaseIndexLocation() {
+ return util::filesystem::DirectoryUtil::getUserIndexDir().absolutePath();
+}
+
+QString CSwordModuleInfo::getModuleBaseIndexLocation() const {
+ return getGlobalBaseIndexLocation() + QString("/") + name().toLocal8Bit();
+}
+
+QString CSwordModuleInfo::getModuleStandardIndexLocation() const { //this for now returns the location of the main index
+ return getModuleBaseIndexLocation() + QString("/standard");
+}
+
+bool CSwordModuleInfo::hasIndex() {
+ //this will return true only
+ //if the index exists and has correct version information for both index and module
+ QDir d;
+ if (!d.exists( getModuleStandardIndexLocation() )) {
+ return false;
+ }
+
+ //first check if the index version and module version are ok
+ QSettings module_config(getModuleBaseIndexLocation() + QString("/bibletime-index.conf"), QSettings::IniFormat);
+
+ if (hasVersion()) {
+ if (module_config.value("module-version") != QString(config(CSwordModuleInfo::ModuleVersion)) ) {
+ return false;
+ }
+ }
+ if (module_config.value("index-version") != QString::number( INDEX_VERSION )) {
+ qDebug("%s: INDEX_VERSION is not compatible with this version of BibleTime.", name().toUtf8().constData());
+ return false;
+ }
+
+ //then check if the index is there
+ return lucene::index::IndexReader::indexExists(getModuleStandardIndexLocation().toAscii().constData());
+}
+
+
+void CSwordModuleInfo::buildIndex() {
+
+ m_cancelIndexing = false;
+
+ try
+ {
+ //Without this we don't get strongs, lemmas, etc
+ backend()->setFilterOptions ( CBTConfig::getFilterOptionDefaults() );
+ //make sure we reset all important filter options which influcence the plain filters.
+ backend()->setOption( CSwordModuleInfo::strongNumbers, false );
+ backend()->setOption( CSwordModuleInfo::morphTags, false );
+ backend()->setOption( CSwordModuleInfo::morphSegmentation, false );
+ backend()->setOption( CSwordModuleInfo::footnotes, false );
+ backend()->setOption( CSwordModuleInfo::headings, false );
+ backend()->setOption( CSwordModuleInfo::scriptureReferences, false );
+ backend()->setOption( CSwordModuleInfo::redLetterWords, false );
+
+ // do not use any stop words
+ const TCHAR* stop_words[] = { NULL };
+ lucene::analysis::standard::StandardAnalyzer an( (const TCHAR**)stop_words );
+ QString index = getModuleStandardIndexLocation();
+
+ QDir dir("/");
+ dir.mkpath( getGlobalBaseIndexLocation() );
+ dir.mkpath( getModuleBaseIndexLocation() );
+ dir.mkpath( getModuleStandardIndexLocation() );
+
+ if (lucene::index::IndexReader::indexExists(index.toAscii().constData())) {
+ if (lucene::index::IndexReader::isLocked(index.toAscii().constData()) ) {
+ lucene::index::IndexReader::unlock(index.toAscii().constData());
+ }
+ }
+
+ boost::scoped_ptr<lucene::index::IndexWriter> writer( new lucene::index::IndexWriter(index.toAscii().constData(), &an, true) ); //always create a new index
+ writer->setMaxFieldLength(BT_MAX_LUCENE_FIELD_LENGTH);
+ writer->setUseCompoundFile(true); //merge segments into a single file
+ writer->setMinMergeDocs(1000);
+
+ *m_module = sword::TOP;
+ unsigned long verseLowIndex = m_module->Index();
+ *m_module = sword::BOTTOM;
+ unsigned long verseHighIndex = m_module->Index();
+
+ //verseLowIndex is not 0 in all cases (i.e. NT-only modules)
+ unsigned long verseIndex = verseLowIndex + 1;
+ unsigned long verseSpan = verseHighIndex - verseLowIndex;
+
+ //Index() is not implemented properly for lexicons, so we use a
+ //workaround.
+ if (type() == CSwordModuleInfo::Lexicon){
+ verseIndex = 0;
+ verseLowIndex = 0;
+ verseSpan = ((CSwordLexiconModuleInfo*)this)->entries()->size();
+ }
+
+ emit indexingProgress(0);
+
+ sword::SWKey* key = m_module->getKey();
+ //VerseKey for bibles
+ sword::VerseKey* vk = dynamic_cast<sword::VerseKey*>(key);
+
+ if (vk) {
+ // we have to be sure to insert the english key into the index, otherwise we'd be in trouble if the language changes
+ vk->setLocale("en_US");
+ //If we have a verse based module, we want to include the pre-chapter etc. headings in the search
+ vk->Headings(1);
+ }
+
+ //holds UTF-8 data and is faster than QString.
+ QByteArray textBuffer;
+
+ // we start with the first module entry, key is automatically updated
+ // because key is a pointer to the modules key
+ m_module->setSkipConsecutiveLinks(true);
+
+ wchar_t wcharBuffer[BT_MAX_LUCENE_FIELD_LENGTH + 1];
+
+ for (*m_module = sword::TOP; !(m_module->Error()) && !m_cancelIndexing; (*m_module)++) {
+
+ //If it is a sword-heading, store in buffer and index later in Verse X:1
+ if (vk) {
+ if (vk->Verse() == 0) {
+ textBuffer.append( m_module->StripText() );
+ continue;
+ }
+ }
+
+ boost::scoped_ptr<lucene::document::Document> doc(new lucene::document::Document());
+
+ //index the key
+ lucene_utf8towcs(wcharBuffer, key->getText(), BT_MAX_LUCENE_FIELD_LENGTH);
+ //doc->add(*lucene::document::Field::UnIndexed((const TCHAR*)_T("key"), (const TCHAR*)wcharBuffer));
+ doc->add(*(new lucene::document::Field((const TCHAR*)_T("key"), (const TCHAR*)wcharBuffer, lucene::document::Field::STORE_YES | lucene::document::Field::INDEX_NO)));
+ // index the main text
+ //at this point we have to make sure we disabled the strongs and the other options
+ //so the plain filters won't include the numbers somehow.
+ lucene_utf8towcs(wcharBuffer, (const char*) textBuffer.append(m_module->StripText()), BT_MAX_LUCENE_FIELD_LENGTH);
+ //doc->add(*lucene::document::Field::UnStored((const TCHAR*)_T("content"), (const TCHAR*)wcharBuffer));
+ doc->add(*(new lucene::document::Field((const TCHAR*)_T("content"), (const TCHAR*)wcharBuffer, lucene::document::Field::STORE_NO | lucene::document::Field::INDEX_TOKENIZED)));
+ textBuffer.resize(0); //clean up
+
+ // index attributes
+ sword::AttributeList::iterator attListI;
+ sword::AttributeValue::iterator attValueI;
+ // Footnotes
+ for (attListI = m_module->getEntryAttributes()["Footnote"].begin();
+ attListI != m_module->getEntryAttributes()["Footnote"].end();
+ attListI++) {
+ lucene_utf8towcs(wcharBuffer, attListI->second["body"], BT_MAX_LUCENE_FIELD_LENGTH);
+ //doc->add(*lucene::document::Field::UnStored((const TCHAR*)_T("footnote"), wcharBuffer));
+ doc->add(*(new lucene::document::Field((const TCHAR*)_T("footnote"), (const TCHAR*)wcharBuffer, lucene::document::Field::STORE_NO | lucene::document::Field::INDEX_TOKENIZED)));
+ } // for attListI
+
+ // Headings
+ for (attValueI = m_module->getEntryAttributes()["Heading"]["Preverse"].begin();
+ attValueI != m_module->getEntryAttributes()["Heading"]["Preverse"].end();
+ attValueI++) {
+ lucene_utf8towcs(wcharBuffer, attValueI->second, BT_MAX_LUCENE_FIELD_LENGTH);
+ //doc->add(*lucene::document::Field::UnStored((const TCHAR*)_T("heading"), wcharBuffer));
+ doc->add(*(new lucene::document::Field((const TCHAR*)_T("heading"), (const TCHAR*)wcharBuffer, lucene::document::Field::STORE_NO | lucene::document::Field::INDEX_TOKENIZED)));
+ } // for attValueI
+
+ // Strongs/Morphs
+ for (attListI = m_module->getEntryAttributes()["Word"].begin();
+ attListI != m_module->getEntryAttributes()["Word"].end();
+ attListI++) {
+ // for each attribute
+ if (attListI->second["LemmaClass"] == "strong") {
+ lucene_utf8towcs(wcharBuffer, attListI->second["Lemma"], BT_MAX_LUCENE_FIELD_LENGTH);
+ //doc->add(*lucene::document::Field::UnStored((const TCHAR*)_T("strong"), wcharBuffer));
+ doc->add(*(new lucene::document::Field((const TCHAR*)_T("strong"), (const TCHAR*)wcharBuffer, lucene::document::Field::STORE_NO | lucene::document::Field::INDEX_TOKENIZED)));
+ //qWarning("Adding strong %s", attListI->second["Lemma"].c_str());
+ }
+ if (attListI->second.find("Morph") != attListI->second.end()) {
+ lucene_utf8towcs(wcharBuffer, attListI->second["Morph"], BT_MAX_LUCENE_FIELD_LENGTH);
+ //doc->add(*lucene::document::Field::UnStored((const TCHAR*)_T("morph"), wcharBuffer));
+ doc->add(*(new lucene::document::Field((const TCHAR*)_T("morph"), (const TCHAR*)wcharBuffer, lucene::document::Field::STORE_NO | lucene::document::Field::INDEX_TOKENIZED)));
+ }
+ } // for attListI
+
+ writer->addDocument(doc.get());
+ //Index() is not implemented properly for lexicons, so we use a
+ //workaround.
+ if (type() == CSwordModuleInfo::Lexicon){
+ verseIndex++;
+ }
+ else{
+ verseIndex = m_module->Index();
+ }
+
+ if (verseIndex % 200 == 0) {
+ int indexingProgressValue;
+ if (verseSpan == 0) { //prevent division by zero
+ //m_indexingProgress.setValue( QVariant(0) );
+ indexingProgressValue = 0;
+ } else {
+ //m_indexingProgress.setValue( QVariant((int)((100*(verseIndex-verseLowIndex))/(verseHighIndex-verseLowIndex))) );
+ indexingProgressValue = (int)((100*(verseIndex-verseLowIndex)) / (verseSpan));
+ }
+ //m_indexingProgress.activate();
+ emit indexingProgress(indexingProgressValue);
+ }
+ }
+
+ if (!m_cancelIndexing)
+ {
+ writer->optimize();
+ }
+ writer->close();
+
+ if (m_cancelIndexing){
+ deleteIndexForModule(name());
+ m_cancelIndexing = false;
+ }
+ else
+ {
+ QSettings module_config(getModuleBaseIndexLocation() + QString("/bibletime-index.conf"), QSettings::IniFormat);
+ if (hasVersion()) module_config.setValue("module-version", config(CSwordModuleInfo::ModuleVersion) );
+ module_config.setValue("index-version", INDEX_VERSION );
+ }
+ }
+ catch(...)
+ {
+ qWarning("CLucene exception occurred while indexing");
+ QMessageBox::warning(0, QCoreApplication::tr("Indexing aborted"), QCoreApplication::tr("An internal error occurred while building the index."));
+ deleteIndexForModule(name());
+ m_cancelIndexing = false;
+ }
+}
+
+void CSwordModuleInfo::deleteIndexForModule( QString name ) {
+ util::filesystem::DirectoryUtil::removeRecursive( getGlobalBaseIndexLocation() + "/" + name );
+}
+
+unsigned long CSwordModuleInfo::indexSize() const {
+ return util::filesystem::DirectoryUtil::getDirSizeRecursive( getModuleBaseIndexLocation() );
+}
+
+
+bool CSwordModuleInfo::searchIndexed(const QString& searchedText, sword::ListKey& scope) {
+ char utfBuffer[BT_MAX_LUCENE_FIELD_LENGTH + 1];
+ wchar_t wcharBuffer[BT_MAX_LUCENE_FIELD_LENGTH + 1];
+
+ // work around Swords thread insafety for Bibles and Commentaries
+ boost::scoped_ptr < CSwordKey > key(CSwordKey::createInstance(this));
+ sword::SWKey* s = dynamic_cast < sword::SWKey * >(key.get());
+ QList<sword::VerseKey*> list;
+
+ if (s) {
+ m_module->SetKey(*s);
+ }
+
+ m_searchResult.ClearList();
+
+ try {
+ // do not use any stop words
+ const TCHAR* stop_words[] = { NULL };
+ lucene::analysis::standard::StandardAnalyzer analyzer( stop_words );
+ lucene::search::IndexSearcher searcher(getModuleStandardIndexLocation().toAscii().constData());
+ lucene_utf8towcs(wcharBuffer, searchedText.toUtf8().constData(), BT_MAX_LUCENE_FIELD_LENGTH);
+ boost::scoped_ptr<lucene::search::Query> q( lucene::queryParser::QueryParser::parse((const TCHAR*)wcharBuffer, (const TCHAR*)_T("content"), &analyzer) );
+
+ boost::scoped_ptr<lucene::search::Hits> h( searcher.search(q.get(), lucene::search::Sort::INDEXORDER) );
+
+ const bool useScope = (scope.Count() > 0);
+// const bool isVerseModule = (type() == CSwordModuleInfo::Bible) || (type() == CSwordModuleInfo::Commentary);
+
+ lucene::document::Document* doc = 0;
+ boost::scoped_ptr<sword::SWKey> swKey( module()->CreateKey() );
+
+
+ for (int i = 0; i < h->length(); ++i) {
+ doc = &h->doc(i);
+ lucene_wcstoutf8(utfBuffer, (const wchar_t*)doc->get((const TCHAR*)_T("key")), BT_MAX_LUCENE_FIELD_LENGTH);
+
+ swKey->setText(utfBuffer);
+
+ // limit results based on scope
+ //if (searchOptions & CSwordModuleSearch::useScope && scope.Count() > 0){
+ if (useScope) {
+ for (int j = 0; j < scope.Count(); j++) {
+ sword::VerseKey* vkey = dynamic_cast<sword::VerseKey*>(scope.getElement(j));
+ if (vkey->LowerBound().compare(*swKey) <= 0 && vkey->UpperBound().compare(*swKey) >= 0) {
+ m_searchResult.add(*swKey);
+ }
+ }
+ } else { // no scope, give me all buffers
+ m_searchResult.add(*swKey);
+ }
+ }
+ }
+ catch (...) {
+ qWarning("CLucene exception occurred");
+ QMessageBox::warning(0, QCoreApplication::tr("Search aborted"), QCoreApplication::tr("An internal error occurred while executing your search."));
+ return false;
+ }
+
+ qDeleteAll(list);
+ list.clear();
+
+ return (m_searchResult.Count() > 0);
+}
+
+/** Returns the last search result for this module. */
+sword::ListKey & CSwordModuleInfo::searchResult(const sword::ListKey * newResult) {
+ if (newResult) {
+ m_searchResult.copyFrom(*newResult);
+ }
+
+ return m_searchResult;
+}
+
+/** Clears the last search result. */
+void CSwordModuleInfo::clearSearchResult() {
+ m_searchResult.ClearList();
+}
+
+/** Returns the required Sword version for this module. Returns -1 if no special Sword version is required. */
+sword::SWVersion CSwordModuleInfo::minimumSwordVersion() {
+ return sword::SWVersion(config(CSwordModuleInfo::MinimumSwordVersion).toUtf8().constData());
+}
+
+QString CSwordModuleInfo::config(const CSwordModuleInfo::ConfigEntry entry) const {
+ switch (entry) {
+
+ case AboutInformation:
+ return getFormattedConfigEntry("About");
+
+ case CipherKey: {
+ if (CBTConfig::getModuleEncryptionKey(name()).isNull()) { //fall back!
+ return QString(m_module->getConfigEntry("CipherKey"));
+ }
+ else {
+ return CBTConfig::getModuleEncryptionKey(name());
+ }
+ }
+
+ case AbsoluteDataPath: {
+ QString path( getSimpleConfigEntry("AbsoluteDataPath") );
+ path.replace(QRegExp("/./"), "/"); // make /abs/path/./modules/ looking better
+ //make sure we have a trailing slash!
+
+ if (path.right(1) != "/") {
+ path.append('/');
+ }
+
+ return path;
+ }
+
+ case DataPath: { //make sure we remove the dataFile part if it's a Lexicon
+ QString path(getSimpleConfigEntry("DataPath"));
+
+ if ((type() == CSwordModuleInfo::GenericBook) || (type() == CSwordModuleInfo::Lexicon)) {
+ int pos = path.lastIndexOf("/"); //last slash in the string
+
+ if (pos != -1) {
+ path = path.left(pos + 1); //include the slash
+ }
+ }
+
+ return path;
+ }
+
+ case Description:
+ return getFormattedConfigEntry("Description");
+
+ case ModuleVersion: {
+ QString version(getSimpleConfigEntry("Version"));
+
+ if (version.isEmpty()) {
+ version = "1.0";
+ }
+
+ return version;
+ }
+
+ case MinimumSwordVersion: {
+ const QString minimumVersion(getSimpleConfigEntry("MinimumVersion"));
+ return !minimumVersion.isEmpty()? minimumVersion : QString("0.0");
+ }
+
+ case TextDir: {
+ const QString dir(getSimpleConfigEntry("Direction"));
+ return !dir.isEmpty()? dir : QString("LtoR");
+ }
+
+ case DisplayLevel: {
+ const QString level(getSimpleConfigEntry("DisplayLevel"));
+ return !level.isEmpty()? level : QString("1");
+ }
+
+ case GlossaryFrom: {
+ if (!category() == Glossary) {
+ return QString::null;
+ };
+
+ const QString lang(getSimpleConfigEntry("GlossaryFrom"));
+
+ return !lang.isEmpty()? lang : QString::null;
+ }
+
+ case GlossaryTo: {
+ if (!category() == Glossary) {
+ return QString::null;
+ };
+
+ const QString lang(getSimpleConfigEntry("GlossaryTo"));
+
+ return !lang.isEmpty()? lang : QString::null;
+ }
+
+ case Markup: {
+ const QString markup(getSimpleConfigEntry("SourceType"));
+ return !markup.isEmpty()? markup : QString("Unknown");
+ }
+
+ case DistributionLicense:
+ return getSimpleConfigEntry("DistributionLicense");
+
+ case DistributionSource:
+ return getSimpleConfigEntry("DistributionSource");
+
+ case DistributionNotes:
+ return getSimpleConfigEntry("DistributionNotes");
+
+ case TextSource:
+ return getSimpleConfigEntry("TextSource");
+
+ case CopyrightNotes:
+ return getSimpleConfigEntry("CopyrightNotes");
+
+ case CopyrightHolder:
+ return getSimpleConfigEntry("CopyrightHolder");
+
+ case CopyrightDate:
+ return getSimpleConfigEntry("CopyrightDate");
+
+ case CopyrightContactName:
+ return getSimpleConfigEntry("CopyrightContactName");
+
+ case CopyrightContactAddress:
+ return getSimpleConfigEntry("CopyrightContactAddress");
+
+ case CopyrightContactEmail:
+ return getSimpleConfigEntry("CopyrightContactEmail");
+
+ default:
+ return QString::null;
+ }
+}
+
+/** Returns true if the module supports the feature given as parameter. */
+bool CSwordModuleInfo::has(const CSwordModuleInfo::Feature feature) const {
+ switch (feature) {
+
+ // case StrongsNumbers:
+ // return m_module->getConfig().has("Feature", "StrongsNumber");
+
+ case GreekDef:
+ return m_module->getConfig().has("Feature", "GreekDef");
+
+ case HebrewDef:
+ return m_module->getConfig().has("Feature", "HebrewDef");
+
+ case GreekParse:
+ return m_module->getConfig().has("Feature", "GreekParse");
+
+ case HebrewParse:
+ return m_module->getConfig().has("Feature", "HebrewParse");
+ }
+
+ return false;
+}
+
+bool CSwordModuleInfo::has(const CSwordModuleInfo::FilterTypes option) const {
+ //BAD workaround to see if the filter is GBF, OSIS or ThML!
+ const QString name = backend()->configOptionName(option);
+
+ if (m_module->getConfig().has("GlobalOptionFilter", QString("OSIS").append(name).toUtf8().constData())) {
+ return true;
+ }
+
+ if (m_module->getConfig().has("GlobalOptionFilter", QString("GBF").append(name).toUtf8().constData())) {
+ return true;
+ }
+
+ if (m_module->getConfig().has("GlobalOptionFilter", QString("ThML").append(name).toUtf8().constData())) {
+ return true;
+ }
+
+ if (m_module->getConfig().has("GlobalOptionFilter", QString("UTF8").append(name).toUtf8().constData())) {
+ return true;
+ }
+
+ if (m_module->getConfig().has("GlobalOptionFilter", name.toUtf8().constData())) {
+ return true;
+ }
+
+ return false;
+}
+
+/** Returns the text direction of the module's text., */
+CSwordModuleInfo::TextDirection CSwordModuleInfo::textDirection() {
+ if (config(TextDir) == "RtoL") {
+ return CSwordModuleInfo::RightToLeft;
+ }
+ else {
+ return CSwordModuleInfo::LeftToRight;
+ }
+}
+
+/** Writes the new text at the given position into the module. This does only work for writable modules. */
+void CSwordModuleInfo::write(CSwordKey * key, const QString & newText) {
+ module()->KeyText(key->key().toUtf8().constData());
+
+ //don't store a pointer to the const char* value somewhere because QCString doesn't keep the value of it
+ module()->setEntry(isUnicode()? newText.toUtf8().constData() : newText.toLocal8Bit().constData());
+}
+
+/** Deletes the current entry and removes it from the module. */
+bool CSwordModuleInfo::deleteEntry(CSwordKey * const key) {
+ module()->KeyText(isUnicode()? key->key().toUtf8().constData() : key->key().toLocal8Bit().constData());
+
+ if (module()) {
+ module()->deleteEntry();
+ return true;
+ }
+
+ return false;
+}
+
+/** Returns the category of this module. See CSwordModuleInfo::Category for possible values. */
+CSwordModuleInfo::Category CSwordModuleInfo::category() const {
+ //qDebug("CSwordModuleInfo::category");
+ if (m_dataCache.category == CSwordModuleInfo::UnknownCategory) {
+ const QString cat(m_module->getConfigEntry("Category"));
+ //qDebug() << "the category was unknown, add a category "<< cat << "for module" << m_module->Name();
+
+ if (cat == "Cults / Unorthodox / Questionable Material") {
+ m_dataCache.category = Cult;
+ }
+ else if (cat == "Daily Devotional" || m_module->getConfig().has("Feature", "DailyDevotion")) {
+ m_dataCache.category = DailyDevotional;
+ }
+ else if (cat == "Glossaries" || m_module->getConfig().has("Feature", "Glossary")) { //allow both
+ m_dataCache.category = Glossary;
+ }
+ else if (cat == "Images" || cat == "Maps") {
+ m_dataCache.category = Images;
+ }
+ else if (type() == Commentary) {
+ m_dataCache.category = Commentaries;
+ }
+ else if (type() == Bible) {
+ m_dataCache.category = Bibles;
+ }
+ else if (type() == Lexicon) {
+ m_dataCache.category = Lexicons;
+ }
+ else if (type() == GenericBook) {
+ m_dataCache.category = Books;
+ }
+ }
+ //qDebug() << "assigned category: " << m_dataCache.category;
+ return m_dataCache.category;
+}
+
+/** Returns the display object for this module. */
+Rendering::CEntryDisplay * CSwordModuleInfo::getDisplay() const {
+ return dynamic_cast < Rendering::CEntryDisplay * >(m_module->Disp());
+}
+
+QString CSwordModuleInfo::aboutText() const {
+ QString text;
+ text += "<table>";
+
+ text += QString("<tr><td><b>%1</b></td><td>%2</td><tr>")
+ .arg(tr("Version"))
+ .arg(hasVersion()? config(CSwordModuleInfo::ModuleVersion) : tr("unknown"));
+
+ text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>")
+ .arg(tr("Markup"))
+ .arg(!QString(m_module->getConfigEntry("SourceType")).isEmpty()? QString(m_module->
+ getConfigEntry("SourceType")) : tr("unknown"));
+
+ text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>")
+ .arg(tr("Location"))
+ .arg(config(CSwordModuleInfo::AbsoluteDataPath));
+
+ text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>")
+ .arg(tr("Language"))
+ .arg(language()->translatedName());
+
+ if (m_module->getConfigEntry("Category"))
+ text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>")
+ .arg(tr("Category"))
+ .arg(m_module->getConfigEntry("Category"));
+
+ if (m_module->getConfigEntry("LCSH"))
+ text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>")
+ .arg(tr("LCSH"))
+ .arg(m_module->getConfigEntry("LCSH"));
+
+ text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>")
+ .arg(tr("Writable"))
+ .arg(isWritable()? tr("yes") : tr("no"));
+
+ if (isEncrypted())
+ text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>")
+ .arg(tr("Unlock key"))
+ .arg(config(CSwordModuleInfo::CipherKey));
+
+ QString options;
+
+ unsigned int opts;
+
+ for (opts = CSwordModuleInfo::filterTypesMIN; opts <= CSwordModuleInfo::filterTypesMAX; ++opts) {
+ if (has(static_cast < CSwordModuleInfo::FilterTypes > (opts))) {
+ if (!options.isEmpty()) {
+ options += QString::fromLatin1(", ");
+ }
+
+ options += CSwordBackend::translatedOptionName(static_cast < CSwordModuleInfo::FilterTypes > (opts));
+ }
+ }
+
+ if (!options.isEmpty()) {
+ text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>")
+ .arg(tr("Features"))
+ .arg(options);
+ }
+
+ text += "</table><hr>";
+
+ if (category() == Cult) //clearly say the module contains cult/questionable materials
+ text += QString("<br/><b>%1</b><br/><br/>")
+ .arg(tr("Take care, this work contains cult / questionable material!"));
+
+ text += QString("<b>%1:</b><br>%2</font>")
+ .arg(tr("About"))
+ .arg(config(AboutInformation));
+
+ typedef QList<CSwordModuleInfo::ConfigEntry> ListConfigEntry;
+
+ ListConfigEntry entries;
+
+ entries.append(DistributionLicense);
+
+ entries.append(DistributionSource);
+
+ entries.append(DistributionNotes);
+
+ entries.append(TextSource);
+
+ entries.append(CopyrightNotes);
+
+ entries.append(CopyrightHolder);
+
+ entries.append(CopyrightDate);
+
+ entries.append(CopyrightContactName);
+
+ entries.append(CopyrightContactAddress);
+
+ entries.append(CopyrightContactEmail);
+
+ typedef QMap<CSwordModuleInfo::ConfigEntry, QString> MapConfigEntry;
+
+ MapConfigEntry entryMap;
+
+ entryMap[DistributionLicense] = tr("Distribution license");
+
+ entryMap[DistributionSource] = tr("Distribution source");
+
+ entryMap[DistributionNotes] = tr("Distribution notes");
+
+ entryMap[TextSource] = tr("Text source");
+
+ entryMap[CopyrightNotes] = tr("Copyright notes");
+
+ entryMap[CopyrightHolder] = tr("Copyright holder");
+
+ entryMap[CopyrightDate] = tr("Copyright date");
+
+ entryMap[CopyrightContactName] = tr("Copyright contact name");
+
+ entryMap[CopyrightContactAddress] = tr("Copyright contact address");
+
+ entryMap[CopyrightContactEmail] = tr("Copyright contact email");
+
+ text += ("<hr><table>");
+
+ for (ListConfigEntry::iterator it(entries.begin()); it != entries.end(); ++it) {
+ QString t( config(*it) );
+
+ if (!t.isEmpty()) {
+ text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>")
+ .arg(entryMap[*it])
+ .arg(config(*it));
+ }
+
+ }
+
+
+ text += "</table></font>";
+
+ return text;
+}
+
+/** Returns the language of the module. */
+const CLanguageMgr::Language* CSwordModuleInfo::language() const {
+ if (!m_dataCache.language) {
+ if (module()) {
+ if (category() == Glossary) {
+ //special handling for glossaries, we use the "from language" as language for the module
+ m_dataCache.language = (CPointers::languageMgr())->languageForAbbrev(config(GlossaryFrom));
+ }
+ else {
+ m_dataCache.language = (CPointers::languageMgr())->languageForAbbrev(module()->Lang());
+ }
+ }
+ else {
+ m_dataCache.language = (CPointers::languageMgr())->defaultLanguage(); //default language
+ }
+ }
+
+ return m_dataCache.language;
+}
+
+
+/*!
+ \fn CSwordModuleInfo::getSimpleConfigEntry(char* name)
+*/
+QString CSwordModuleInfo::getSimpleConfigEntry(const QString& name) const {
+ QString ret = isUnicode()
+ ? QString::fromUtf8(m_module->getConfigEntry(name.toUtf8().constData()))
+ : QString::fromLatin1(m_module->getConfigEntry(name.toUtf8().constData()));
+
+ return ret.isEmpty() ? QString::null : ret;
+}
+
+QString CSwordModuleInfo::getFormattedConfigEntry(const QString& name) const {
+ sword::SWBuf RTF_Buffer(m_module->getConfigEntry(name.toUtf8().constData()));
+ sword::RTFHTML RTF_Filter;
+ RTF_Filter.processText(RTF_Buffer, 0, 0);
+ QString ret = isUnicode()
+ ? QString::fromUtf8(RTF_Buffer.c_str())
+ : QString::fromLatin1(RTF_Buffer.c_str());
+
+ return ret.isEmpty() ? QString::null : ret;
+}
+
+void CSwordModuleInfo::setHidden(bool hidden)
+{
+ //qDebug("CSwordModuleInfo::setHidden");
+ QStringList hiddenModules = CBTConfig::get(CBTConfig::hiddenModules);
+ if (hidden && !hiddenModules.contains(this->name())) {
+ hiddenModules.append(this->name());
+ CBTConfig::set(CBTConfig::hiddenModules, hiddenModules);
+ }
+ if (!hidden && hiddenModules.contains(this->name()) ) {
+ hiddenModules.removeAll(this->name());
+ CBTConfig::set(CBTConfig::hiddenModules, hiddenModules);
+ }
+}
+
+bool CSwordModuleInfo::isHidden() const
+{
+ //qDebug("CSwordModuleInfo::isHidden");
+ QStringList hiddenModules = CBTConfig::get(CBTConfig::hiddenModules);
+ if (hiddenModules.contains(this->name())) {
+ return true;
+ }
+ return false;
+}
diff --git a/src/backend/drivers/cswordmoduleinfo.h b/src/backend/drivers/cswordmoduleinfo.h
new file mode 100644
index 0000000..0f612f9
--- /dev/null
+++ b/src/backend/drivers/cswordmoduleinfo.h
@@ -0,0 +1,384 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CSWORDMODULEINFO_H
+#define CSWORDMODULEINFO_H
+
+#include "backend/managers/clanguagemgr.h"
+
+//Qt
+#include <QString>
+#include <QList>
+
+//Sword
+#include <listkey.h>
+#include <swsearchable.h>
+#include <swmodule.h>
+#include <swversion.h>
+#include <swdisp.h>
+
+class CSwordBackend;
+class CSwordKey;
+
+namespace Rendering {
+
+ class CEntryDisplay;
+}
+
+/**
+ * Base class for Sword modules.
+ * This is the base class for all Sword modules. Every class handling a special Sword module type
+ * does inherit from this class.
+ *
+ * @author The BibleTime team
+ * @version $Id: cswordmoduleinfo.h,v 1.83 2007/02/04 23:12:32 joachim Exp $
+ */
+
+class CSwordModuleInfo: public QObject
+{
+ Q_OBJECT
+
+public:
+ /**
+ * These are the options which could be supported by modules and by this backend.
+ * It's used in @ref CSwordBackend::setOption.
+ */
+ enum FilterTypes {
+ footnotes, /**< Footnotes embedded in the module's text */
+ strongNumbers, /**< strong numbers, usually in the text for the info display */
+ headings, /**< additional section headings */
+ morphTags, /**< morphology */
+ lemmas, /**< lemma tags */
+ hebrewPoints,/**< Hebrew vowel points */
+ hebrewCantillation, /**<Hewbrew caantillation points */
+ greekAccents, /**< Greek accents may be switched on and off */
+ scriptureReferences, /**< scripture references may be switched on and off, just makes sense in Bibles */
+ redLetterWords, /**< Jesus words in red, color is template specific */
+ textualVariants, /**< variants */
+ morphSegmentation, /**< morph word segmentation, supported by OSIS */
+ filterTypesMIN = footnotes, /**< first entry of this enum */
+ filterTypesMAX = morphSegmentation /**< last item in this enum */
+ // transliteration /* The following are handled in a special way */
+ };
+ /** The text direction of a module */
+ enum TextDirection { /* The text direction of the modules's text */
+ LeftToRight, /**< Left to right text direction, the default setting */
+ RightToLeft /**< Right to left text directin, e.g. for hebrew */
+ };
+ /** The module type.
+ */
+ enum ModuleType {
+ Bible, /**< Bible module */
+ Commentary, /**< Commentary module */
+ Lexicon, /**< Lexicon module */
+ GenericBook, /**< Generic book module */
+ Unknown /**< Fall back type for unknown modules */
+ };
+ /**
+ * This enum is used to give
+ * back an error code after unlocking the module
+ * BibleTime stores the unlock key not in the module's config file but in BibleTime's
+ * configuration file.
+ */
+ enum UnlockErrorCode {
+ noError, /**< No error occured, everything worked ok. The key was written to the BibleTime config */
+ wrongUnlockKey, /**< The wrong key was used. Module is not unlocked */
+ notLocked, /**< The module was not locked so it can't be unlocked */
+ noPermission /**< The key was not written to config because we have no permissions */
+ };
+ enum ConfigEntry {
+ AboutInformation, /**< The about information of a module which is stored in the config file*/
+ AbsoluteDataPath, /**< The absolute data path stored in the config object */
+ CipherKey, /**< The cipher key which was used to unlock the module. Not necessarily set.*/
+ DataPath, /**< The relative path. See AbsoluteDataPath*/
+ Description, /**< The module description stored in the config file */
+ ModuleVersion, /**< The module's version.*/
+ MinimumSwordVersion, /**< The required Sword Version of this module. Otherwise some things may not work (compression etc.).*/
+ TextDir, /**< The text direction */
+ DisplayLevel, /**< Mostly used for books. Gives the level which should contain the connected entries.*/
+ GlossaryFrom, /**< lamguage from which the Glosaary tramslates */
+ GlossaryTo, /**< lamguages to which the glossary maps to */
+ DistributionLicense,
+ DistributionSource,
+ DistributionNotes,
+ TextSource,
+ CopyrightNotes,
+ CopyrightHolder,
+ CopyrightDate,
+ CopyrightContactName,
+ CopyrightContactAddress,
+ CopyrightContactEmail,
+ Markup /**< The markup of this module */
+ };
+ enum Feature {
+ //StrongsNumbers, /**< Use for Bibles which have embedded strong numbers */ BT does not use this as a user option
+ GreekDef,
+ HebrewDef,
+ GreekParse,
+ HebrewParse,
+ featureMin = GreekDef,
+ featureMax = HebrewParse
+ };
+ enum Category {
+ UnknownCategory = 0, /**< The category wasn't set or has an unknwon value */
+ Bibles,
+ Commentaries,
+ Books,
+ Lexicons,
+ Glossary,
+ DailyDevotional,
+ Images,
+ Cult /**< The module is a cult / sect / questionable module */
+ };
+
+ /**
+ * Returns the base directory for search indices
+ */
+ static QString getGlobalBaseIndexLocation();
+ /**
+ * Removes search index for this module, even if the module is not there any more
+ */
+ static void deleteIndexForModule( QString name );
+
+
+ /**
+ * Returns the config entry which is pecified by the parameter.
+ */
+ QString config( const CSwordModuleInfo::ConfigEntry entry ) const;
+
+ CSwordModuleInfo( sword::SWModule* module, CSwordBackend* const = 0 );
+ /** Copy constructor to copy the passed parameter.
+ * @param m The module to be copied
+ */
+ CSwordModuleInfo( const CSwordModuleInfo& m );
+ /** Reimplementation to return a valid clone.
+ */
+ virtual CSwordModuleInfo* clone();
+ /** Destructor.
+ */
+ virtual ~CSwordModuleInfo();
+
+ /**
+ * Returns the module object so all objects can access the original Sword module.
+ */
+ sword::SWModule* module() const;
+ /**
+ * Sets the unlock key of the modules and writes the key into the cofig file.
+ * @return True if the unlock process was succesful, if the key was wrong, or if the config file was write protected return false.
+ */
+ bool unlock( const QString& unlockKey );
+ /**
+ * Returns the display object for this module. Normally every module should have a Display object.
+ * Please don't use module()->Display() because this function does return the Sword display and does
+ * render the text, too.
+ * This function performs some casts to return the correct display. If it returns 0 there's no valid
+ * display object.
+ */
+ Rendering::CEntryDisplay* getDisplay() const;
+ /**
+ * This function does return true if the data files of the module are encrypted by the module author
+ * (the on who made the module) no matter if it's locked or not.
+ * @return True if this module is encryped
+ */
+ bool isEncrypted() const;
+ /**
+ * This function returns true if this module is locked (encrypted + correct cipher key),
+ * otherwise return false.
+ * @return True if this module is locked, i.e. encrypted but without a key set
+ */
+ bool isLocked();
+
+ bool unlockKeyIsValid();
+
+ /** The module version.
+ * @return true if this module has a version number and false if it doesn't have one.
+ */
+ inline bool hasVersion() const;
+
+ /**
+ * Returns true if the module's index has been built.
+ */
+ virtual bool hasIndex();
+ /**
+ * Returns the path to this module's index base dir
+ */
+ virtual QString getModuleBaseIndexLocation() const;
+ /**
+ * Returns the path to this module's standard index
+ */
+ virtual QString getModuleStandardIndexLocation() const;
+ /**
+ * Builds a search index for this module
+ */
+ virtual void buildIndex();
+ /**
+ * Returns index size
+ */
+ virtual unsigned long indexSize() const;
+ /**
+ * Returns true if something was found, otherwise return false.
+ * This function uses CLucene to perform and index based search. It also
+ * overwrites the variable containing the last search result.
+ */
+ virtual bool searchIndexed(const QString& searchedText, sword::ListKey& scope);
+ /**
+ * Returns the last search result for this module.
+ * The last result is cleared by @ref search
+ */
+ virtual sword::ListKey& searchResult( const sword::ListKey* newResult = 0 );
+ /**
+ * Clears the last search result.
+ * This does immediately clean the last search result,
+ * no matter if search is in progress or not.
+ */
+ void clearSearchResult();
+ /**
+ * Returns the type of the module.
+ */
+ virtual CSwordModuleInfo::ModuleType type() const;
+ /**
+ * Returns the required Sword version for this module.
+ * Returns -1 if no special Sword version is required.
+ */
+ sword::SWVersion minimumSwordVersion();
+ /**
+ * Returns the name of the module.
+ * @return The name of this module.
+ */
+ QString name() const;
+ /**
+ * Snaps to the closest entry in the module if the current key is
+ * not present in the data files.
+ */
+ virtual bool snap() {
+ return false;
+ };
+
+ bool has( const CSwordModuleInfo::Feature ) const;
+ bool has( const CSwordModuleInfo::FilterTypes ) const;
+ /**
+ * Returns the text direction of the module's text.,
+ */
+ virtual CSwordModuleInfo::TextDirection textDirection();
+ /**
+ * Writes the new text at the given position into the module. This does only work for writabe modules.
+ */
+ virtual void write( CSwordKey* key, const QString& newText );
+ /**
+ * Deletes the current entry and removes it from the module.
+ */
+ bool deleteEntry( CSwordKey* const key );
+ /**
+ * Returns the language of the module.
+ */
+ const CLanguageMgr::Language* language() const;
+ /**
+ * Returns true if this module may be written by the write display windows.
+ */
+ inline virtual bool isWritable() const;
+ /**
+ * Returns true if this module is hidden (not to be shown with other modules in certain views).
+ */
+ bool isHidden() const;
+
+ void setHidden(bool hidden);
+
+ /**
+ * Returns the category of this module. See CSwordModuleInfo::Category for possible values.
+ */
+ CSwordModuleInfo::Category category() const;
+ /**
+ * The about text which belongs to this module.
+ */
+ QString aboutText() const;
+ /**
+ * Returns true if this module is Unicode encoded. False if the charset is iso8859-1.
+ * Protected because it should not be used outside of the CSword*ModuleInfo classes.
+ */
+ inline bool isUnicode() const {
+ return m_dataCache.isUnicode;
+ }
+
+public slots:
+ inline void cancelIndexing() { m_cancelIndexing = true; };
+
+protected:
+ friend class CSwordBackend;
+
+ inline CSwordBackend* backend() const {
+ return m_backend;
+ }
+
+ inline void backend( CSwordBackend* newBackend ) {
+ if (newBackend) {
+ m_backend = newBackend;
+ }
+ }
+
+ QString getSimpleConfigEntry(const QString& name) const;
+ QString getFormattedConfigEntry(const QString& name) const;
+
+signals:
+ void indexingFinished();
+ void indexingProgress(int);
+
+private:
+ sword::SWModule* m_module;
+ sword::ListKey m_searchResult;
+
+ mutable struct DataCache {
+ DataCache() {
+ language = 0;
+ }
+
+ QString name;
+ bool isUnicode;
+ CSwordModuleInfo::Category category;
+ const CLanguageMgr::Language* language;
+ bool hasVersion;
+ }
+
+ m_dataCache;
+
+ CSwordBackend* m_backend;
+
+ bool m_hidden;
+
+ bool m_cancelIndexing;
+};
+
+inline CSwordModuleInfo::ModuleType CSwordModuleInfo::type() const {
+ return CSwordModuleInfo::Unknown;
+}
+
+inline sword::SWModule* CSwordModuleInfo::module() const {
+ return m_module;
+}
+
+inline bool CSwordModuleInfo::hasVersion() const {
+ return m_dataCache.hasVersion;
+}
+
+
+/**
+* Returns the name of the module.
+* The Sword library takes care of the duplicate names: _n is added after each duplicate.
+*/
+inline QString CSwordModuleInfo::name() const {
+ return m_dataCache.name;
+}
+
+/** Returns true if this module may be written by the write display windows. */
+inline bool CSwordModuleInfo::isWritable() const {
+ return false;
+}
+
+//#include "util/cpointers.h"
+
+#endif
diff --git a/src/backend/filters/bt_gbfhtml.cpp b/src/backend/filters/bt_gbfhtml.cpp
new file mode 100644
index 0000000..0627cee
--- /dev/null
+++ b/src/backend/filters/bt_gbfhtml.cpp
@@ -0,0 +1,296 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+//BibleTime includes
+#include "bt_gbfhtml.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/managers/cswordbackend.h"
+#include "util/cpointers.h"
+
+//Sword includes
+#include <utilxml.h>
+
+//Qt includes
+#include <QRegExp>
+#include <QString>
+
+Filters::BT_GBFHTML::BT_GBFHTML() : sword::GBFHTML() {
+
+ setEscapeStringCaseSensitive(true);
+ setPassThruUnknownEscapeString(true); //the HTML widget will render the HTML escape codes
+
+ removeTokenSubstitute("Rf");
+ // addTokenSubstitute("RB", "<span>"); //start of a footnote with embedded text
+
+ addTokenSubstitute("FI", "<span class=\"italic\">"); // italics begin
+ addTokenSubstitute("Fi", "</span>");
+
+ addTokenSubstitute("FB", "<span class=\"bold\">"); // bold begin
+ addTokenSubstitute("Fb", "</span>");
+
+ addTokenSubstitute("FR", "<span class=\"jesuswords\">");
+ addTokenSubstitute("Fr", "</span>");
+
+ addTokenSubstitute("FU", "<u>"); // underline begin
+ addTokenSubstitute("Fu", "</u>");
+
+ addTokenSubstitute("FO", "<span class=\"quotation\">"); // Old Testament quote begin
+ addTokenSubstitute("Fo", "</span>");
+
+
+ addTokenSubstitute("FS", "<span class=\"sup\">"); // Superscript begin// Subscript begin
+ addTokenSubstitute("Fs", "</span>");
+
+ addTokenSubstitute("FV", "<span class=\"sub\">"); // Subscript begin
+ addTokenSubstitute("Fv", "</span>");
+
+ addTokenSubstitute("TT", "<div class=\"booktitle\">");
+ addTokenSubstitute("Tt", "</div>");
+
+ addTokenSubstitute("TS", "<div class=\"sectiontitle\">");
+ addTokenSubstitute("Ts", "</div>");
+
+ //addTokenSubstitute("PP", "<span class=\"poetry\">"); // poetry begin
+ //addTokenSubstitute("Pp", "</span>");
+
+
+ addTokenSubstitute("Fn", "</font>"); // font end
+ addTokenSubstitute("CL", "<br/>"); // new line
+ addTokenSubstitute("CM", "<br/>"); // paragraph <!P> is a non showing comment that can be changed in the front end to <P> if desired
+
+ addTokenSubstitute("CG", "&gt;"); // literal greater-than sign
+ addTokenSubstitute("CT", "&lt;"); // literal less-than sign
+
+ addTokenSubstitute("JR", "<span class=\"right\">"); // right align begin
+ addTokenSubstitute("JC", "<span class=\"center\">"); // center align begin
+ addTokenSubstitute("JL", "</span>"); // align end
+}
+
+/** No descriptions */
+char Filters::BT_GBFHTML::processText(sword::SWBuf& buf, const sword::SWKey * key, const sword::SWModule * module) {
+ GBFHTML::processText(buf, key, module);
+
+ if (!module->isProcessEntryAttributes()) {
+ return 1; //no processing should be done, may happen in a search
+ }
+
+ CSwordModuleInfo* m = CPointers::backend()->findModuleByName( module->Name() );
+
+ if (m && !(m->has(CSwordModuleInfo::lemmas) || m->has(CSwordModuleInfo::morphTags) || m->has(CSwordModuleInfo::strongNumbers))) { //only parse if the module has strongs or lemmas
+ return 1; //WARNING: Return alread here
+ }
+
+ //Am Anfang<WH07225> schuf<WH01254><WTH8804> Gott<WH0430> Himmel<WH08064> und<WT> Erde<WH0776>.
+ //A simple word<WT> means: No entry for this word "word"
+ QString result;
+
+ QString t = QString::fromUtf8(buf.c_str());
+
+ QRegExp tag("([.,;:]?<W[HGT][^>]*>\\s*)+");
+
+ QStringList list;
+
+ int lastMatchEnd = 0;
+
+ int pos = tag.indexIn(t,0);
+
+ if (pos == -1) { //no strong or morph code found in this text
+ return 1; //WARNING: Return already here
+ }
+
+ //split the text into parts which end with the GBF tag marker for strongs/lemmas
+ while (pos != -1) {
+ list.append(t.mid(lastMatchEnd, pos+tag.matchedLength()-lastMatchEnd));
+
+ lastMatchEnd = pos + tag.matchedLength();
+ pos = tag.indexIn(t, pos + tag.matchedLength());
+ }
+
+ //append the trailing text to the list.
+ if (!t.right(t.length() - lastMatchEnd).isEmpty()) {
+ list.append(t.right(t.length() - lastMatchEnd));
+ }
+
+ //list is now a list of words with 1-n Strongs at the end, which belong to this word.
+
+ //now create the necessary HTML in list entries and concat them to the result
+ tag = QRegExp("<W([HGT])([^>]*)>");
+ tag.setMinimal(true);
+
+ for (QStringList::iterator it = list.begin(); it != list.end(); ++it) {
+ QString e = (*it); //current entry to process
+ //qWarning(e.latin1());
+
+ //check if there is a word to which the strongs info belongs to.
+ //If yes, wrap that word with the strongs info
+ //If not, leave out the strongs info, because it can't be tight to a text
+ //Comparing the first char with < is not enough, because the tokenReplace is done already
+ //so there might be html tags already.
+ const bool textPresent = (e.trimmed().remove(QRegExp("[.,;:]")).left(2) != "<W");
+
+ if (!textPresent) {
+ result += (*it);
+ continue;
+ }
+
+ int pos = tag.indexIn(e, 0); //try to find a strong number marker
+ bool insertedTag = false;
+ bool hasLemmaAttr = false;
+ bool hasMorphAttr = false;
+
+ QString value = QString::null;
+ int tagAttributeStart = -1;
+
+ while (pos != -1) { //work on all strong/lemma tags in this section, should be between 1-3 loops
+ const bool isMorph = (tag.cap(1) == "T");
+ value = isMorph ? tag.cap(2) : tag.cap(2).prepend( tag.cap(1) );
+
+ if (value.isEmpty()) {
+ break;
+ }
+
+ //insert the span
+ if (!insertedTag) { //we have to insert a new tag end and beginning, i.e. our first loop
+ e.replace(pos, tag.matchedLength(), "</span>");
+ pos += 7;
+
+ //skip blanks, commas, dots and stuff at the beginning, it doesn't belong to the morph code
+ QString rep("<span ");
+ rep.append(isMorph ? "morph" : "lemma").append("=\"").append(value).append("\">");
+
+ hasMorphAttr = isMorph;
+ hasLemmaAttr = !isMorph;
+
+ int startPos = 0;
+ QChar c = e[startPos];
+
+ while ((startPos < pos) && (c.isSpace() || c.isPunct())) {
+ ++startPos;
+
+ c = e[startPos];
+ }
+
+ e.insert( startPos, rep );
+ tagAttributeStart = startPos + 6; //to point to the start of the attributes
+ pos += rep.length();
+ }
+ else { //add the attribute to the existing tag
+ e.remove(pos, tag.matchedLength());
+
+ if (tagAttributeStart == -1) {
+ continue; //nothing valid found
+ }
+
+ if ((!isMorph && hasLemmaAttr) || (isMorph && hasMorphAttr)) { //we append another attribute value, e.g. 3000 gets 3000|5000
+ //search the existing attribute start
+ QRegExp attrRegExp( isMorph ? "morph=\".+(?=\")" : "lemma=\".+(?=\")" );
+ attrRegExp.setMinimal(true);
+ const int foundPos = e.indexOf(attrRegExp, tagAttributeStart);
+
+ if (foundPos != -1) {
+ e.insert(foundPos + attrRegExp.matchedLength(), QString("|").append(value));
+ pos += value.length() + 1;
+
+ hasLemmaAttr = !isMorph;
+ hasMorphAttr = isMorph;
+ }
+ }
+ else { //attribute was not yet inserted
+ QString attr = QString(isMorph ? "morph" : "lemma").append("=\"").append(value).append("\" ");
+
+ e.insert(tagAttributeStart, attr);
+ pos += attr.length();
+
+ hasMorphAttr = isMorph;
+ hasLemmaAttr = !isMorph;
+ }
+
+ //tagAttributeStart remains the same
+ }
+
+ insertedTag = true;
+ pos = tag.indexIn(e, pos);
+ }
+
+ result += e;
+ }
+
+ if (list.count()) {
+ buf = (const char*)result.toUtf8().constData();
+ }
+
+ return 1;
+}
+
+bool Filters::BT_GBFHTML::handleToken(sword::SWBuf &buf, const char *token, sword::BasicFilterUserData *userData) {
+ if (!substituteToken(buf, token)) { //more than a simple replace
+ const unsigned int tokenLength = strlen(token);
+ unsigned long i;
+ sword::SWBuf value;
+
+ BT_UserData* myUserData = dynamic_cast<BT_UserData*>(userData);
+ sword::SWModule* myModule = const_cast<sword::SWModule*>(myUserData->module); //hack to be able to call stuff like Lang()
+
+ if ( !strncmp(token, "WG", 2)
+ || !strncmp(token, "WH", 2)
+ || !strncmp(token, "WT", 2) ) {
+ buf.append('<');
+ buf.append(token);
+ buf.append('>');
+ }
+ else if (!strncmp(token, "RB", 2)) {
+ myUserData->hasFootnotePreTag = true;
+ buf.append("<span class=\"footnotepre\">");
+ }
+ else if (!strncmp(token, "RF", 2)) {
+ //we use several append calls because appendFormatted slows down filtering, which should be fast
+
+ if (myUserData->hasFootnotePreTag) {
+ // qWarning("inserted footnotepre end");
+ buf.append("</span>");
+ myUserData->hasFootnotePreTag = false;
+ }
+
+ buf.append(" <span class=\"footnote\" note=\"");
+ buf.append(myModule->Name());
+ buf.append('/');
+ buf.append(myUserData->key->getShortText());
+ buf.append('/');
+ buf.append( QString::number(myUserData->swordFootnote++).toUtf8().constData() );
+ buf.append("\">*</span> ");
+
+ userData->suspendTextPassThru = true;
+ }
+ else if (!strncmp(token, "Rf", 2)) { //end of footnote
+ userData->suspendTextPassThru = false;
+ }
+ else if (!strncmp(token, "FN", 2)) { //the end </font> tag is inserted in addTokenSubsitute
+ buf.append("<font face=\"");
+
+ for (i = 2; i < tokenLength; i++) {
+ if(token[i] != '\"') {
+ buf.append( token[i] );
+ }
+ }
+
+ buf.append("\">");
+ }
+ else if (!strncmp(token, "CA", 2)) { // ASCII value
+ buf.append( (char)atoi(&token[2]) );
+ }
+ else {
+ return GBFHTML::handleToken(buf, token, userData);
+ }
+ }
+
+ return true;
+}
diff --git a/src/backend/filters/bt_gbfhtml.h b/src/backend/filters/bt_gbfhtml.h
new file mode 100644
index 0000000..b9118aa
--- /dev/null
+++ b/src/backend/filters/bt_gbfhtml.h
@@ -0,0 +1,55 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+
+
+/* $Header: /cvsroot/bibletime/bibletime/bibletime/backend/filters/bt_gbfhtml.h,v 1.24 2006/02/25 11:38:15 joachim Exp $ */
+/* $Revision: 1.24 $ */
+
+#ifndef BT_GBFHTML_H
+#define BT_GBFHTML_H
+
+//Sword includes
+#include <gbfhtml.h>
+
+namespace Filters {
+
+ /** GBF to HTML filter,
+ * This filter converts GBF Text into HTML
+ */
+
+class BT_GBFHTML : public sword::GBFHTML/*, protected CFilterTool */
+ {
+
+protected:
+
+class BT_UserData : public sword::GBFHTML::MyUserData {
+
+public:
+BT_UserData(const sword::SWModule *module, const sword::SWKey *key) : sword::GBFHTML::MyUserData(module, key) {
+ swordFootnote = 1;
+ hasFootnotePreTag = false;
+ }
+
+ short unsigned int swordFootnote;
+ };
+
+ virtual sword::BasicFilterUserData *createUserData(const sword::SWModule* module, const sword::SWKey* key) {
+ return new BT_UserData(module, key);
+ }
+
+public:
+ BT_GBFHTML();
+ virtual bool handleToken(sword::SWBuf &buf, const char *token, sword::BasicFilterUserData *userData);
+ virtual char processText(sword::SWBuf& buf, const sword::SWKey*, const sword::SWModule * = 0);
+ };
+
+}
+
+#endif
diff --git a/src/backend/filters/bt_osishtml.cpp b/src/backend/filters/bt_osishtml.cpp
new file mode 100644
index 0000000..b9c9746
--- /dev/null
+++ b/src/backend/filters/bt_osishtml.cpp
@@ -0,0 +1,619 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+//BibleTime includes
+#include "bt_osishtml.h"
+#include "backend/managers/clanguagemgr.h"
+#include "backend/managers/creferencemanager.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+
+#include "backend/config/cbtconfig.h"
+#include "util/cpointers.h"
+
+//Sword
+#include <swmodule.h>
+#include <swbuf.h>
+#include <utilxml.h>
+
+//Qt
+#include <QString>
+
+//KDE
+
+
+Filters::BT_OSISHTML::BT_OSISHTML() : sword::OSISHTMLHREF() {
+ setPassThruUnknownEscapeString(true); //the HTML widget will render the HTML escape codes
+
+ addTokenSubstitute("inscription", "<span class=\"inscription\">");
+ addTokenSubstitute("/inscription","</span>");
+
+ addTokenSubstitute("mentioned", "<span class=\"mentioned\">");
+ addTokenSubstitute("/mentioned", "</span>");
+
+// addTokenSubstitute("divineName", "<span class=\"name\"><span class=\"divine\">");
+// addTokenSubstitute("/divineName", "</span></span>");
+
+ //TODO Move that down to the real tag handling, segs without the type morph would generate incorrect markup, as the end span is always inserted
+// addTokenSubstitute("seg type=\"morph\"", "<span class=\"morphSegmentation\">");
+// addTokenSubstitute("/seg", "</span>");
+
+ // OSIS tables
+ addTokenSubstitute("table", "<table>");
+ addTokenSubstitute("/table", "</table>");
+ addTokenSubstitute("row", "<tr>");
+ addTokenSubstitute("/row", "</tr>");
+ addTokenSubstitute("cell", "<td>");
+ addTokenSubstitute("/cell", "</td>");
+
+}
+
+bool Filters::BT_OSISHTML::handleToken(sword::SWBuf &buf, const char *token, sword::BasicFilterUserData *userData) {
+ // manually process if it wasn't a simple substitution
+
+ if (!substituteToken(buf, token)) {
+ BT_UserData* myUserData = dynamic_cast<BT_UserData*>(userData);
+ sword::SWModule* myModule = const_cast<sword::SWModule*>(myUserData->module); //hack
+
+ sword::XMLTag tag(token);
+ // qWarning("found %s", token);
+ const bool osisQToTick = ((!userData->module->getConfigEntry("OSISqToTick")) || (strcmp(userData->module->getConfigEntry("OSISqToTick"), "false")));
+
+ if (!tag.getName()) {
+ return false;
+ }
+
+ // <div> tag
+ if (!strcmp(tag.getName(), "div")) {
+ //handle intro
+
+ if ((!tag.isEmpty()) && (!tag.isEndTag())) { //start tag
+ sword::SWBuf type( tag.getAttribute("type") );
+
+ if (type == "introduction") {
+ buf.append("<div class=\"introduction\">");
+ }
+ else if (type == "chapter") {
+ buf.append("<div class=\"chapter\" />"); //don't open a div here, that would lead to a broken XML structure
+ }
+ else {
+ buf.append("<div>");
+ }
+ }
+ else if (tag.isEndTag()) { //end tag
+ buf.append("</div>");
+ }
+ }
+ else if (!strcmp(tag.getName(), "w")) {
+ if ((!tag.isEmpty()) && (!tag.isEndTag())) { //start tag
+ const char *attrib;
+ const char *val;
+
+ sword::XMLTag outTag("span");
+ sword::SWBuf attrValue;
+
+ if ((attrib = tag.getAttribute("xlit"))) {
+ val = strchr(attrib, ':');
+ val = (val) ? (val + 1) : attrib;
+ outTag.setAttribute("xlit", val);
+ }
+
+ if ((attrib = tag.getAttribute("gloss"))) {
+ val = strchr(attrib, ':');
+ val = (val) ? (val + 1) : attrib;
+ outTag.setAttribute("gloss", val);
+ }
+
+ if ((attrib = tag.getAttribute("lemma"))) {
+ char splitChar = '|';
+ const int countSplit1 = tag.getAttributePartCount("lemma", '|');
+ const int countSplit2 = tag.getAttributePartCount("lemma", ' '); //TODO: not allowed, remove soon
+ int count = 0;
+
+ if (countSplit1 > countSplit2) { //| split char
+ splitChar = '|'; //TODO: not allowed, remove soon
+ count = countSplit1;
+ }
+ else {
+ splitChar = ' ';
+ count = countSplit2;
+ }
+
+ int i = (count > 1) ? 0 : -1; // -1 for whole value cuz it's faster, but does the same thing as 0
+ attrValue = "";
+
+ do {
+ if (attrValue.length()) {
+ attrValue.append( '|' );
+ }
+
+ attrib = tag.getAttribute("lemma", i, splitChar);
+
+ if (i < 0) { // to handle our -1 condition
+ i = 0;
+ }
+
+ val = strchr(attrib, ':');
+ val = (val) ? (val + 1) : attrib;
+
+ attrValue.append(val);
+ }
+ while (++i < count);
+
+ if (attrValue.length()) {
+ outTag.setAttribute("lemma", attrValue.c_str());
+ }
+ }
+
+ if ((attrib = tag.getAttribute("morph"))) {
+ char splitChar = '|';
+ const int countSplit1 = tag.getAttributePartCount("morph", '|');
+ const int countSplit2 = tag.getAttributePartCount("morph", ' '); //TODO: not allowed, remove soon
+ int count = 0;
+
+ if (countSplit1 > countSplit2) { //| split char
+ splitChar = '|';
+ count = countSplit1;
+ }
+ else {
+ splitChar = ' ';
+ count = countSplit2;
+ }
+
+ int i = (count > 1) ? 0 : -1; // -1 for whole value cuz it's faster, but does the same thing as 0
+
+ attrValue = "";
+
+ do {
+ if (attrValue.length()) {
+ attrValue.append('|');
+ }
+
+ attrib = tag.getAttribute("morph", i, splitChar);
+
+ if (i < 0) {
+ i = 0; // to handle our -1 condition
+ }
+
+ val = strchr(attrib, ':');
+
+ if (val) { //the prefix gives the modulename
+ //check the prefix
+ if (!strncmp("robinson:", attrib, 9)) { //robinson
+ attrValue.append( "Robinson:" ); //work is not the same as Sword's module name
+ attrValue.append( val+1 );
+ }
+ //strongs is handled by BibleTime
+ /*else if (!strncmp("strongs", attrib, val-atrrib)) {
+ attrValue.append( !strncmp(attrib, "x-", 2) ? attrib+2 : attrib );
+ }*/
+ else {
+ attrValue.append( !strncmp(attrib, "x-", 2) ? attrib+2 : attrib );
+ }
+ }
+ else { //no prefix given
+ val = attrib;
+ const bool skipFirst = ((val[0] == 'T') && ((val[1] == 'H') || (val[1] == 'H')));
+ attrValue.append( skipFirst ? val+1 : val );
+ }
+ }
+ while (++i < count);
+
+ if (attrValue.length()) {
+ outTag.setAttribute("morph", attrValue.c_str());
+ }
+ }
+
+ if ((attrib = tag.getAttribute("POS"))) {
+ val = strchr(attrib, ':');
+ val = (val) ? (val + 1) : attrib;
+ outTag.setAttribute("pos", val);
+ }
+
+ buf.append( outTag.toString() );
+ }
+ else if (tag.isEndTag()) { // end or empty <w> tag
+ buf.append("</span>");
+ }
+ }
+
+ // <note> tag
+ else if (!strcmp(tag.getName(), "note")) {
+ if (!tag.isEndTag()) { //start tag
+ const sword::SWBuf type( tag.getAttribute("type") );
+
+ if (type == "crossReference") { //note containing cross references
+ myUserData->inCrossrefNote = true;
+ myUserData->noteType = BT_UserData::CrossReference;
+ myUserData->swordFootnote++; // cross refs count as notes, too
+
+ /* //get the refList value of the right entry attribute
+ AttributeList notes = myModule->getEntryAttributes()["Footnote"];
+ bool foundNote = false;
+
+ SWBuf id( tag.getAttribute("osisID") );
+ SWBuf refList;
+
+ for (AttributeList::iterator list_it = notes.begin(); (list_it != notes.end()) && !foundNote; ++list_it ) {
+ for (AttributeValue::iterator val_it = list_it->second.begin(); (val_it != list_it->second.end()) && !foundNote; ++val_it ) {
+ if ((val_it->first == "osisID") && (val_it->second == id)) {
+ foundNote = true; //this break the loop
+ refList = list_it->second["refList"];
+ }
+ }
+ }
+
+ if (refList.length()) {
+ buf.append(" <span class=\"crossreference\" crossrefs=\"");
+ buf.append(refList.c_str());
+ buf.append("\"> ");
+
+ myUserData->noteType = BT_UserData::CrossReference;
+ }
+ else {
+ myUserData->noteType = BT_UserData::Unknown;
+ }*/
+
+ buf.append("<span class=\"crossreference\">");
+#ifdef SWORD_SIMPLERENDER
+ sword::SWBuf footnoteNumber = tag.getAttribute("swordFootnote");
+ sword::SWBuf footnoteBody = myModule->getEntryAttributes()["Footnote"][footnoteNumber]["body"];
+ buf += myModule->RenderText(footnoteBody);
+#endif
+ }
+
+ /* else if (type == "explanation") {
+ }
+ */
+ else if ((type == "strongsMarkup") || (type == "x-strongsMarkup")) {
+ /**
+ * leave strong's markup notes out, in the future we'll probably have
+ * different option filters to turn different note types on or off
+ */
+
+ myUserData->suspendTextPassThru = true;
+ myUserData->noteType = BT_UserData::StrongsMarkup;
+ }
+
+ else {
+ // qWarning("found note in %s", myUserData->key->getShortText());
+ buf.append(" <span class=\"footnote\" note=\"");
+ buf.append(myModule->Name());
+ buf.append('/');
+ buf.append(myUserData->key->getShortText());
+ buf.append('/');
+ buf.append( QString::number(myUserData->swordFootnote++).toUtf8().constData() ); //inefficient
+
+ const sword::SWBuf n = tag.getAttribute("n");
+
+ buf.append("\">");
+ buf.append( (n.length() > 0) ? n.c_str() : "*" );
+ buf.append("</span> ");
+
+ myUserData->noteType = BT_UserData::Footnote;
+ myUserData->suspendTextPassThru = true;
+ }
+ }
+ else { //if (tag.isEndTag()) {
+ Q_ASSERT(myUserData->noteType != BT_UserData::Unknown);
+
+ if (myUserData->noteType == BT_UserData::CrossReference) {
+ buf.append("</span> ");
+// myUserData->suspendTextPassThru = false;
+ myUserData->inCrossrefNote = false;
+ }
+
+ myUserData->noteType = BT_UserData::Unknown;
+ myUserData->suspendTextPassThru = false;
+ }
+ }
+ // The <p> paragraph tag is handled by OSISHTMLHref
+ else if (!strcmp(tag.getName(), "reference")) { // <reference> tag
+ if (!tag.isEndTag() && !tag.isEmpty()) {
+
+ renderReference(tag.getAttribute("osisRef"), buf, myModule, myUserData);
+
+ }
+ else if (tag.isEndTag()) {
+ buf.append("</a>");
+ }
+ else { // empty reference marker
+ // -- what should we do? nothing for now.
+ }
+ }
+
+ // <l> is handled by OSISHTMLHref
+ // <title>
+ else if (!strcmp(tag.getName(), "title")) {
+ if (!tag.isEndTag() && !tag.isEmpty()) {
+ buf.append("<div class=\"sectiontitle\">");
+ }
+ else if (tag.isEndTag()) {
+ buf.append("</div>");
+ }
+ else { // empty title marker
+ // what to do? is this even valid?
+ buf.append("<br/>");
+ }
+ }
+
+ // <hi> highlighted text
+ else if (!strcmp(tag.getName(), "hi")) {
+ const sword::SWBuf type = tag.getAttribute("type");
+
+ if ((!tag.isEndTag()) && (!tag.isEmpty())) {
+ if (type == "bold") {
+ buf.append("<span class=\"bold\">");
+ }
+ else if (type == "illuminated") {
+ buf.append("<span class=\"illuminated\">");
+ }
+ else if (type == "italic") {
+ buf.append("<span class=\"italic\">");
+ }
+ else if (type == "line-through") {
+ buf.append("<span class=\"line-through\">");
+ }
+ else if (type == "normal") {
+ buf.append("<span class=\"normal\">");
+ }
+ else if (type == "small-caps") {
+ buf.append("<span class=\"small-caps\">");
+ }
+ else if (type == "underline") {
+ buf.append("<span class=\"underline\">");
+ }
+ else {
+ buf.append("<span>"); //don't break markup, </span> is inserted later
+ }
+ }
+ else if (tag.isEndTag()) { //all hi replacements are html spans
+ buf.append("</span>");
+ }
+ }
+
+ //name
+ else if (!strcmp(tag.getName(), "name")) {
+ const sword::SWBuf type = tag.getAttribute("type");
+
+ if ((!tag.isEndTag()) && (!tag.isEmpty())) {
+ if (type == "geographic") {
+ buf.append("<span class=\"name\"><span class=\"geographic\">");
+ }
+ else if (type == "holiday") {
+ buf.append("<span class=\"name\"><span class=\"holiday\">");
+ }
+ else if (type == "nonhuman") {
+ buf.append("<span class=\"name\"><span class=\"nonhuman\">");
+ }
+ else if (type == "person") {
+ buf.append("<span class=\"name\"><span class=\"person\">");
+ }
+ else if (type == "ritual") {
+ buf.append("<span class=\"name\"><span class=\"ritual\">");
+ }
+ else {
+ buf.append("<span class=\"name\"><span>");
+ }
+ }
+ else if (tag.isEndTag()) { //all hi replacements are html spans
+ buf.append("</span></span> ");
+ }
+ }
+ else if (!strcmp(tag.getName(), "transChange")) {
+ sword::SWBuf type( tag.getAttribute("type") );
+
+ if ( !type.length() ) {
+ type = tag.getAttribute("changeType");
+ }
+
+ if ((!tag.isEndTag()) && (!tag.isEmpty())) {
+ if (type == "added") {
+ buf.append("<span class=\"transchange\" title=\"");
+ buf.append(QObject::tr("Added text").toUtf8().constData());
+ buf.append("\"><span class=\"added\">");
+ }
+ else if (type == "amplified") {
+ buf.append("<span class=\"transchange\"><span class=\"amplified\">");
+ }
+ else if (type == "changed") {
+ buf.append("<span class=\"transchange\"><span class=\"changed\">");
+ }
+ else if (type == "deleted") {
+ buf.append("<span class=\"transchange\"><span class=\"deleted\">");
+ }
+ else if (type == "moved") {
+ buf.append("<span class=\"transchange\"><span class=\"moved\">");
+ }
+ else if (type == "tenseChange") {
+ buf.append("<span class=\"transchange\" title=\"");
+ buf.append(QObject::tr("Verb tense changed").toUtf8().constData());
+ buf.append("\"><span class=\"tenseChange\">");
+ }
+ else {
+ buf.append("<span class=\"transchange\"><span>");
+ }
+ }
+ else if (tag.isEndTag()) { //all hi replacements are html spans
+ buf.append("</span></span>");
+ }
+ }
+ else if (!strcmp(tag.getName(), "p")) {
+ if (tag.isEmpty()) {
+ buf.append("<p/>");
+ }
+ }
+
+ // <q> quote
+ else if (!strcmp(tag.getName(), "q")) {
+ sword::SWBuf type = tag.getAttribute("type");
+ sword::SWBuf who = tag.getAttribute("who");
+ const char *lev = tag.getAttribute("level");
+ int level = (lev) ? atoi(lev) : 1;
+ const char* quoteMarker = tag.getAttribute("marker");
+
+ if ((!tag.isEndTag())) {
+ myUserData->quote.who = who;
+ if (quoteMarker) {
+ buf.append(quoteMarker);
+ }
+ else if(osisQToTick) //alternate " and '
+ buf.append((level % 2) ? '\"' : '\'');
+
+ if (who == "Jesus") {
+ buf.append("<span class=\"jesuswords\">");
+ }
+ }
+ else if (tag.isEndTag()) {
+ if (myUserData->quote.who == "Jesus") {
+ buf.append("</span>");
+ }
+ if (quoteMarker) {
+ buf.append(quoteMarker);
+ }
+ else if (osisQToTick) { //alternate " and '
+ buf.append((level % 2) ? '\"' : '\'');
+ }
+
+ myUserData->quote.who = "";
+ }
+ }
+
+ // abbr tag
+ else if (!strcmp(tag.getName(), "abbr")) {
+ if (!tag.isEndTag() && !tag.isEmpty()) {
+ const sword::SWBuf expansion = tag.getAttribute("expansion");
+
+ buf.append("<span class=\"abbreviation\" expansion=\"");
+ buf.append(expansion);
+ buf.append("\">");
+ }
+ else if (tag.isEndTag()) {
+ buf.append("</span>");
+ }
+ }
+
+ // <milestone> tag
+ else if (!strcmp(tag.getName(), "milestone")) {
+ const sword::SWBuf type = tag.getAttribute("type");
+
+ if ((type == "screen") || (type == "line")) {//line break
+ buf.append("<br/>");
+ userData->supressAdjacentWhitespace = true;
+ }
+ else if (type == "x-p") { //e.g. occurs in the KJV2006 module
+ //buf.append("<br/>");
+ const sword::SWBuf marker = tag.getAttribute("marker");
+ if (marker.length() > 0) {
+ buf.append(marker);
+ }
+ }
+ }
+ //seg tag
+ else if (!strcmp(tag.getName(), "seg")) {
+ if (!tag.isEndTag() && !tag.isEmpty()) {
+
+ const sword::SWBuf type = tag.getAttribute("type");
+
+ if (type == "morph") {//line break
+ //This code is for WLC and MORPH (WHI)
+ sword::XMLTag outTag("span");
+ outTag.setAttribute("class", "morphSegmentation");
+ const char* attrValue;
+ //Transfer the values to the span
+ //Problem: the data is in hebrew/aramaic, how to encode in HTML/BibleTime?
+ if ((attrValue = tag.getAttribute("lemma"))) outTag.setAttribute("lemma", attrValue);
+ if ((attrValue = tag.getAttribute("morph"))) outTag.setAttribute("morph", attrValue);
+ if ((attrValue = tag.getAttribute("homonym"))) outTag.setAttribute("homonym", attrValue);
+
+ buf.append(outTag.toString());
+ //buf.append("<span class=\"morphSegmentation\">");
+ }
+ else{
+ buf.append("<span>");
+ }
+ }
+ else { // seg end tag
+ buf.append("</span>");
+ }
+ //qWarning(QString("handled <seg> token. result: %1").arg(buf.c_str()).latin1());
+ }
+
+ //divine name, don't use simple tag replacing because it may have attributes
+ else if (!strcmp(tag.getName(), "divineName")) {
+ if (!tag.isEndTag()) {
+ buf.append("<span class=\"name\"><span class=\"divine\">");
+ }
+ else { //all hi replacements are html spans
+ buf.append("</span></span>");
+ }
+ }
+
+ else { //all tokens handled by OSISHTMLHref will run through the filter now
+ return sword::OSISHTMLHREF::handleToken(buf, token, userData);
+ }
+ }
+
+ return false;
+}
+
+void Filters::BT_OSISHTML::renderReference(const char *osisRef, sword::SWBuf &buf, sword::SWModule *myModule, BT_UserData *myUserData) {
+ QString ref( osisRef );
+ QString hrefRef( ref );
+ //Q_ASSERT(!ref.isEmpty()); checked later
+
+ if (!ref.isEmpty()) {
+ //find out the mod, using the current module makes sense if it's a bible or commentary because the refs link into a bible by default.
+ //If the osisRef is something like "ModuleID:key comes here" then the
+ // modulename is given, so we'll use that one
+
+ CSwordModuleInfo* mod = CPointers::backend()->findSwordModuleByPointer(myModule);
+ //Q_ASSERT(mod); checked later
+ if (!mod || (mod->type() != CSwordModuleInfo::Bible
+ && mod->type() != CSwordModuleInfo::Commentary)) {
+
+ mod = CBTConfig::get( CBTConfig::standardBible );
+ }
+
+ // Q_ASSERT(mod); There's no necessarily a module or standard Bible
+
+ //if the osisRef like "GerLut:key" contains a module, use that
+ int pos = ref.indexOf(":");
+
+ if ((pos >= 0) && ref.at(pos-1).isLetter() && ref.at(pos+1).isLetter()) {
+ QString newModuleName = ref.left(pos);
+ hrefRef = ref.mid(pos+1);
+
+ if (CPointers::backend()->findModuleByName(newModuleName)) {
+ mod = CPointers::backend()->findModuleByName(newModuleName);
+ }
+ }
+
+ if (mod) {
+ CReferenceManager::ParseOptions options;
+ options.refBase = QString::fromUtf8(myUserData->key->getText());
+ options.refDestinationModule = QString(mod->name());
+ options.sourceLanguage = QString(myModule->Lang());
+ options.destinationLanguage = QString("en");
+
+ buf.append("<a href=\"");
+ buf.append( //create the hyperlink with key and mod
+ CReferenceManager::encodeHyperlink(
+ mod->name(),
+ CReferenceManager::parseVerseReference(hrefRef, options),
+ CReferenceManager::typeFromModule(mod->type())
+ ).toUtf8().constData()
+ );
+ buf.append("\" crossrefs=\"");
+ buf.append((const char*)CReferenceManager::parseVerseReference(ref, options).toUtf8().constData()); //ref must contain the osisRef module marker if there was any
+ buf.append("\">");
+ }
+ // should we add something if there were no referenced module available?
+ }
+}
+
diff --git a/src/backend/filters/bt_osishtml.h b/src/backend/filters/bt_osishtml.h
new file mode 100644
index 0000000..7ae5e6d
--- /dev/null
+++ b/src/backend/filters/bt_osishtml.h
@@ -0,0 +1,67 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BT_OSISHTML_H
+#define BT_OSISHTML_H
+
+//Sword includes
+#include <swbuf.h>
+#include <osishtmlhref.h>
+
+namespace Filters {
+
+ /** BibleTime's OSIS to HTMl filter.
+ * This filter works on OSIS tags and outputs HTML in the structure supported by BibleTime.
+ */
+
+class BT_OSISHTML : public sword::OSISHTMLHREF {
+
+protected:
+
+class BT_UserData : public sword::OSISHTMLHREF::MyUserData {
+
+public:
+BT_UserData(const sword::SWModule *module, const sword::SWKey *key) : sword::OSISHTMLHREF::MyUserData(module, key) {
+ noteType = Unknown;
+ swordFootnote = 1;
+ inCrossrefNote = false;
+ }
+
+ unsigned short int swordFootnote;
+ bool inCrossrefNote;
+
+ enum NoteType {
+ Unknown,
+ Alternative,
+ CrossReference,
+ Footnote,
+ StrongsMarkup
+ } noteType;
+
+ struct {
+ sword::SWBuf who;
+ }
+
+ quote;
+ };
+
+ virtual sword::BasicFilterUserData *createUserData(const sword::SWModule* module, const sword::SWKey* key) {
+ return new BT_UserData(module, key);
+ }
+
+public:
+ BT_OSISHTML();
+ virtual bool handleToken(sword::SWBuf &buf, const char *token, sword::BasicFilterUserData *userData);
+private:
+ void renderReference(const char *osisRef, sword::SWBuf &buf, sword::SWModule *myModule, BT_UserData *myUserData);
+ };
+
+} //end of Filters namespace
+
+#endif
diff --git a/src/backend/filters/bt_plainhtml.cpp b/src/backend/filters/bt_plainhtml.cpp
new file mode 100644
index 0000000..67557cc
--- /dev/null
+++ b/src/backend/filters/bt_plainhtml.cpp
@@ -0,0 +1,72 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "bt_plainhtml.h"
+
+Filters::BT_PLAINHTML::BT_PLAINHTML() : sword::SWFilter() {
+}
+
+/** No descriptions */
+char Filters::BT_PLAINHTML::processText(sword::SWBuf& text, const sword::SWKey* /*key*/, const sword::SWModule* /*module*/) {
+ int count = 0;
+
+ sword::SWBuf orig = text;
+ const char *from = orig.c_str();
+ for (text = ""; *from; from++)
+ {
+ if ((*from == '\n') && (from[1] == '\n')) // two newlinea are a paragraph
+ {
+ text += "<P>";
+ from++;
+ continue;
+ }
+ //This is a special case: Newlines in the plaintext editor are stored as <br />, not as \n
+ //we need to let them through
+ else if ((*from == '<') && (from[1] == 'b') && (from[2] == 'r') && (from[3] == ' ') && (from[4] == '/') && (from[5] == '>')){
+ text += "<br />";
+ from += 5;
+ continue;
+ }
+ else if ((*from == '\n')){ // only one new line
+ text += "<BR>";
+ continue;
+ }
+ else if (*from == '<') {
+ text += "&lt;";
+ continue;
+ }
+ else if (*from == '>') {
+ text += "&gt;";
+ continue;
+ }
+ else if (*from == '&'){
+ text += "&amp;";
+ continue;
+ }
+ else if (*from == '{') { //footnote start
+ text += "<FONT COLOR=\"#80000\"><SMALL> (";
+ continue;
+ }
+ else if (*from == '}') //footnote end
+ {
+ text += ") </SMALL></FONT>";
+ continue;
+ }
+ else if ((*from == ' ') && (count > 5000))
+ {
+ text += "<WBR>";
+ count = 0;
+ continue;
+ }
+
+ text += *from;
+ count++;
+ }
+ return 0;
+}
diff --git a/src/backend/filters/bt_plainhtml.h b/src/backend/filters/bt_plainhtml.h
new file mode 100644
index 0000000..ce1ef36
--- /dev/null
+++ b/src/backend/filters/bt_plainhtml.h
@@ -0,0 +1,33 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BT_PLAINHTML_H
+#define BT_PLAINHTML_H
+
+//Sword includes
+#include <swfilter.h>
+#include <swbuf.h>
+
+class SWKey;
+class SWModule;
+
+namespace Filters {
+
+ /** Plain to HTML filter,
+ * This filter converts Plain Text into HTML
+ */
+class BT_PLAINHTML : public sword::SWFilter{
+protected:
+ virtual char processText(sword::SWBuf& buf, const sword::SWKey*, const sword::SWModule * = 0);
+public:
+ BT_PLAINHTML();
+ };
+}
+
+#endif
diff --git a/src/backend/filters/bt_thmlhtml.cpp b/src/backend/filters/bt_thmlhtml.cpp
new file mode 100644
index 0000000..a5f17d2
--- /dev/null
+++ b/src/backend/filters/bt_thmlhtml.cpp
@@ -0,0 +1,385 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+//BibleTime includes
+#include "bt_thmlhtml.h"
+#include "backend/managers/clanguagemgr.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/managers/creferencemanager.h"
+
+#include "backend/config/cbtconfig.h"
+#include "util/cpointers.h"
+#include <boost/scoped_ptr.hpp>
+
+//Sword includes
+#include <swmodule.h>
+#include <utilxml.h>
+#include <versekey.h>
+#include <utilstr.h>
+
+//Qt includes
+#include <QString>
+#include <QRegExp>
+
+Filters::BT_ThMLHTML::BT_ThMLHTML() {
+ setEscapeStringCaseSensitive(true);
+ setPassThruUnknownEscapeString(true); //the HTML widget will render the HTML escape codes
+
+ setTokenStart("<");
+ setTokenEnd(">");
+ setTokenCaseSensitive(true);
+
+ addTokenSubstitute("/foreign", "</span>");
+
+ removeTokenSubstitute("note");
+ removeTokenSubstitute("/note");
+}
+
+char Filters::BT_ThMLHTML::processText(sword::SWBuf& buf, const sword::SWKey* key, const sword::SWModule* module) {
+ sword::ThMLHTML::processText(buf, key, module);
+
+ CSwordModuleInfo* m = CPointers::backend()->findModuleByName( module->Name() );
+
+ if (m && !(m->has(CSwordModuleInfo::lemmas) || m->has(CSwordModuleInfo::strongNumbers))) { //only parse if the module has strongs or lemmas
+ return 1;
+ }
+
+ QString result;
+
+ QString t = QString::fromUtf8(buf.c_str());
+ QRegExp tag("([.,;]?<sync[^>]+(type|value)=\"([^\"]+)\"[^>]+(type|value)=\"([^\"]+)\"([^<]*)>)+");
+
+ QStringList list;
+ int lastMatchEnd = 0;
+ int pos = tag.indexIn(t,0);
+
+ if (pos == -1) { //no strong or morph code found in this text
+ return 1; //WARNING: Return alread here
+ }
+
+ while (pos != -1) {
+ list.append(t.mid(lastMatchEnd, pos+tag.matchedLength()-lastMatchEnd));
+
+ lastMatchEnd = pos+tag.matchedLength();
+ pos = tag.indexIn(t,pos+tag.matchedLength());
+ }
+
+ if (!t.right(t.length() - lastMatchEnd).isEmpty()) {
+ list.append(t.right(t.length() - lastMatchEnd));
+ }
+
+ tag = QRegExp("<sync[^>]+(type|value|class)=\"([^\"]+)\"[^>]+(type|value|class)=\"([^\"]+)\"[^>]+((type|value|class)=\"([^\"]+)\")*([^<]*)>");
+
+ for (QStringList::iterator it = list.begin(); it != list.end(); ++it) {
+ QString e( *it );
+
+ const bool textPresent = (e.trimmed().remove(QRegExp("[.,;:]")).left(1) != "<");
+
+ if (!textPresent) {
+ continue;
+ }
+
+
+ bool hasLemmaAttr = false;
+ bool hasMorphAttr = false;
+
+ int pos = tag.indexIn(e, 0);
+ bool insertedTag = false;
+ QString value;
+ QString valueClass;
+
+ while (pos != -1) {
+ bool isMorph = false;
+ bool isStrongs = false;
+ value = QString::null;
+ valueClass = QString::null;
+
+ // check 3 attribute/value pairs
+
+ for (int i = 1; i < 6; i += 2) {
+ if (i > 4)
+ i++;
+
+ if (tag.cap(i) == "type") {
+ isMorph = (tag.cap(i+1) == "morph");
+ isStrongs = (tag.cap(i+1) == "Strongs");
+ }
+ else if (tag.cap(i) == "value") {
+ value = tag.cap(i+1);
+ }
+ else if (tag.cap(i) == "class") {
+ valueClass = tag.cap(i+1);
+ }
+ }
+
+ // prepend the class qualifier to the value
+ if (!valueClass.isEmpty()) {
+ value = valueClass + ":" + value;
+ // value.append(":").append(value);
+ }
+
+ if (value.isEmpty()) {
+ break;
+ }
+
+ //insert the span
+ if (!insertedTag) {
+ e.replace(pos, tag.matchedLength(), "</span>");
+ pos += 7;
+
+ QString rep = QString("<span lemma=\"").append(value).append("\">");
+ int startPos = 0;
+ QChar c = e[startPos];
+
+ while ((startPos < pos) && (c.isSpace() || c.isPunct())) {
+ ++startPos;
+ c = e[startPos];
+ }
+
+ hasLemmaAttr = isStrongs;
+ hasMorphAttr = isMorph;
+
+ e.insert( startPos, rep );
+ pos += rep.length();
+ }
+ else { //add the attribute to the existing tag
+ e.remove(pos, tag.matchedLength());
+
+ if ((!isMorph && hasLemmaAttr) || (isMorph && hasMorphAttr)) { //we append another attribute value, e.g. 3000 gets 3000|5000
+ //search the existing attribute start
+ QRegExp attrRegExp( isMorph ? "morph=\".+(?=\")" : "lemma=\".+(?=\")" );
+ attrRegExp.setMinimal(true);
+ const int foundAttrPos = e.indexOf(attrRegExp, pos);
+
+ if (foundAttrPos != -1) {
+ e.insert(foundAttrPos + attrRegExp.matchedLength(), QString("|").append(value));
+ pos += value.length() + 1;
+
+ hasLemmaAttr = !isMorph;
+ hasMorphAttr = isMorph;
+ }
+ }
+ else { //attribute was not yet inserted
+ const int attrPos = e.indexOf(QRegExp("morph=|lemma="), 0);
+
+ if (attrPos >= 0) {
+ QString attr;
+ attr.append(isMorph ? "morph" : "lemma").append("=\"").append(value).append("\" ");
+ e.insert(attrPos, attr);
+
+ hasMorphAttr = isMorph;
+ hasLemmaAttr = !isMorph;
+
+ pos += attr.length();
+ }
+ }
+ }
+
+ insertedTag = true;
+ pos = tag.indexIn(e, pos);
+ }
+
+ result.append( e );
+ }
+
+ if (list.count()) {
+ buf = (const char*)result.toUtf8();
+ }
+
+ return 1;
+}
+
+
+bool Filters::BT_ThMLHTML::handleToken(sword::SWBuf &buf, const char *token, sword::BasicFilterUserData *userData) {
+ if (!substituteToken(buf, token) && !substituteEscapeString(buf, token)) {
+ sword::XMLTag tag(token);
+ BT_UserData* myUserData = dynamic_cast<BT_UserData*>(userData);
+ sword::SWModule* myModule = const_cast<sword::SWModule*>(myUserData->module); //hack to be able to call stuff like Lang()
+
+ if ( tag.getName() && !sword::stricmp(tag.getName(), "foreign") ) { // a text part in another language, we have to set the right font
+
+ if (tag.getAttribute("lang")) {
+ const char* abbrev = tag.getAttribute("lang");
+ //const CLanguageMgr::Language* const language = CPointers::languageMgr()->languageForAbbrev( QString::fromLatin1(abbrev) );
+
+ buf.append("<span class=\"foreign\" lang=\"");
+ buf.append(abbrev);
+ buf.append("\">");
+ }
+ }
+ else if (tag.getName() && !sword::stricmp(tag.getName(), "sync")) { //lemmas, morph codes or strongs
+
+ if (tag.getAttribute("type") && (!sword::stricmp(tag.getAttribute("type"), "morph") || !sword::stricmp(tag.getAttribute("type"), "Strongs") || !sword::stricmp(tag.getAttribute("type"), "lemma"))) { // Morph or Strong
+ buf.append('<');
+ buf.append(token);
+ buf.append('>');
+ }
+ }
+ else if (tag.getName() && !sword::stricmp(tag.getName(), "note")) { // <note> tag
+
+ if (!tag.isEndTag() && !tag.isEmpty()) {
+ //appending is faster than appendFormatted
+ buf.append(" <span class=\"footnote\" note=\"");
+ buf.append(myModule->Name());
+ buf.append('/');
+ buf.append(myUserData->key->getShortText());
+ buf.append('/');
+ buf.append( QString::number(myUserData->swordFootnote++).toUtf8().constData() );
+ buf.append("\">*</span> ");
+
+ myUserData->suspendTextPassThru = true;
+ myUserData->inFootnoteTag = true;
+ }
+ else if (tag.isEndTag() && !tag.isEmpty()) { //end tag
+ //buf += ")</span>";
+ myUserData->suspendTextPassThru = false;
+ myUserData->inFootnoteTag = false;
+ }
+ }
+ else if (tag.getName() && !sword::stricmp(tag.getName(), "scripRef")) { // a scripRef
+ //scrip refs which are embeded in footnotes may not be displayed!
+
+ if (!myUserData->inFootnoteTag) {
+ if (tag.isEndTag()) {
+ if (myUserData->inscriptRef) { // like "<scripRef passage="John 3:16">See John 3:16</scripRef>"
+ buf.append("</a></span>");
+
+ myUserData->inscriptRef = false;
+ myUserData->suspendTextPassThru = false;
+ }
+ else { // like "<scripRef>John 3:16</scripRef>"
+
+ CSwordModuleInfo* mod = CBTConfig::get(CBTConfig::standardBible);
+ //Q_ASSERT(mod); tested later
+ if (mod) {
+ CReferenceManager::ParseOptions options;
+ options.refBase = QString::fromUtf8(myUserData->key->getText()); //current module key
+ options.refDestinationModule = QString(mod->name());
+ options.sourceLanguage = QString(myModule->Lang());
+ options.destinationLanguage = QString("en");
+
+ //it's ok to split the reference, because to descriptive text is given
+ bool insertSemicolon = false;
+ buf.append("<span class=\"crossreference\">");
+ QStringList refs = QString::fromUtf8(myUserData->lastTextNode.c_str()).split(";");
+ QString oldRef; //the previous reference to use as a base for the next refs
+ for (QStringList::iterator it(refs.begin()); it != refs.end(); ++it) {
+
+ if (! oldRef.isEmpty() ){
+ options.refBase = oldRef; //use the last ref as a base, e.g. Rom 1,2-3, when the next ref is only 3:3-10
+ }
+ const QString completeRef( CReferenceManager::parseVerseReference((*it), options) );
+
+ oldRef = completeRef; //use the parsed result as the base for the next ref.
+
+ if (insertSemicolon) { //prepend a ref divider if we're after the first one
+ buf.append("; ");
+ }
+
+ buf.append("<a href=\"");
+ buf.append(
+ CReferenceManager::encodeHyperlink(
+ mod->name(),
+ completeRef,
+ CReferenceManager::typeFromModule(mod->type())
+ ).toUtf8().constData()
+ );
+
+ buf.append("\" crossrefs=\"");
+ buf.append((const char*)completeRef.toUtf8());
+ buf.append("\">");
+
+ buf.append((const char*)(*it).toUtf8());
+
+ buf.append("</a>");
+
+ insertSemicolon = true;
+ }
+ buf.append("</span>"); //crossref end
+ }
+
+ myUserData->suspendTextPassThru = false;
+ }
+ }
+ else if (tag.getAttribute("passage") ) { //the passage was given as a parameter value
+ myUserData->inscriptRef = true;
+ myUserData->suspendTextPassThru = false;
+
+ const char* ref = tag.getAttribute("passage");
+ Q_ASSERT(ref);
+
+ CSwordModuleInfo* mod = CBTConfig::get(CBTConfig::standardBible);
+ //Q_ASSERT(mod); tested later
+
+ CReferenceManager::ParseOptions options;
+ options.refBase = QString::fromUtf8(myUserData->key->getText());
+
+ options.sourceLanguage = myModule->Lang();
+ options.destinationLanguage = QString("en");
+
+ const QString completeRef = CReferenceManager::parseVerseReference(QString::fromUtf8(ref), options);
+
+ if (mod) {
+ options.refDestinationModule = QString(mod->name());
+ buf.append("<span class=\"crossreference\">");
+ buf.append("<a href=\"");
+ buf.append(
+ CReferenceManager::encodeHyperlink(
+ mod->name(),
+ completeRef,
+ CReferenceManager::typeFromModule(mod->type())
+ ).toUtf8().constData()
+ );
+ buf.append("\" crossrefs=\"");
+ buf.append((const char*)completeRef.toUtf8());
+ buf.append("\">");
+ }
+ else {
+ buf.append("<span><a>");
+ }
+ }
+ else if ( !tag.getAttribute("passage") ) { // we're starting a scripRef like "<scripRef>John 3:16</scripRef>"
+ myUserData->inscriptRef = false;
+
+ // let's stop text from going to output, the text get's added in the -tag handler
+ myUserData->suspendTextPassThru = true;
+ }
+ }
+ }
+ else if (tag.getName() && !sword::stricmp(tag.getName(), "div")) {
+ if (tag.isEndTag()) {
+ buf.append("</div>");
+ }
+ else if ( tag.getAttribute("class") && !sword::stricmp(tag.getAttribute("class"),"sechead") ) {
+ buf.append("<div class=\"sectiontitle\">");
+ }
+ else if (tag.getAttribute("class") && !sword::stricmp(tag.getAttribute("class"), "title")) {
+ buf.append("<div class=\"booktitle\">");
+ }
+ }
+ else if (tag.getName() && !sword::stricmp(tag.getName(), "img") && tag.getAttribute("src")) {
+ const char* value = tag.getAttribute("src");
+
+ if (value[0] == '/') {
+ value++; //strip the first /
+ }
+
+ buf.append("<img src=\"file:");
+ buf.append(myUserData->module->getConfigEntry("AbsoluteDataPath"));
+ buf.append('/');
+ buf.append(value);
+ buf.append("\" />");
+ }
+ else { // let unknown token pass thru
+ return sword::ThMLHTML::handleToken(buf, token, userData);
+ }
+ }
+
+ return true;
+}
diff --git a/src/backend/filters/bt_thmlhtml.h b/src/backend/filters/bt_thmlhtml.h
new file mode 100644
index 0000000..df20472
--- /dev/null
+++ b/src/backend/filters/bt_thmlhtml.h
@@ -0,0 +1,53 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BT_THMLHTML_H
+#define BT_THMLHTML_H
+
+//Sword
+#include <swbuf.h>
+#include <thmlhtml.h>
+
+namespace Filters {
+
+ /** ThML to HTML filter.
+ * This filter converts ThML text to HTML text
+ */
+
+class BT_ThMLHTML : public sword::ThMLHTML {
+
+protected:
+
+class BT_UserData : public sword::ThMLHTML::MyUserData {
+
+public:
+BT_UserData(const sword::SWModule *module, const sword::SWKey *key) : sword::ThMLHTML::MyUserData(module, key) {
+ inscriptRef = false;
+ swordFootnote = 1;
+ inFootnoteTag = false;
+ }
+
+ bool inscriptRef;
+ bool inFootnoteTag;
+ unsigned short int swordFootnote;
+ };
+
+ virtual sword::BasicFilterUserData *createUserData(const sword::SWModule* module, const sword::SWKey* key) {
+ return new BT_UserData(module, key);
+ }
+
+public:
+ BT_ThMLHTML ();
+ virtual bool handleToken(sword::SWBuf& buf, const char *token, sword::BasicFilterUserData *userData);
+ virtual char processText(sword::SWBuf& buf, const sword::SWKey*, const sword::SWModule* = 0);
+ };
+
+}
+
+#endif
diff --git a/src/backend/filters/bt_thmlplain.cpp b/src/backend/filters/bt_thmlplain.cpp
new file mode 100644
index 0000000..e08afb7
--- /dev/null
+++ b/src/backend/filters/bt_thmlplain.cpp
@@ -0,0 +1,221 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+/******************************************************************************
+ *
+ * thmlplain - SWFilter descendant to strip out all ThML tags or convert to
+ * ASCII rendered symbols.
+ */
+
+#include "bt_thmlplain.h"
+
+Filters::BT_ThMLPlain::BT_ThMLPlain() {
+}
+
+char Filters::BT_ThMLPlain::processText(sword::SWBuf &text, const sword::SWKey* /*key*/, const sword::SWModule* /*module*/)
+{
+ char token[2048];
+ int tokpos = 0;
+ bool intoken = false;
+ bool ampersand = false;
+
+ const char *from;
+ sword::SWBuf orig = text;
+ from = orig.c_str();
+ for (text = ""; *from; from++)
+ {
+ if (*from == 10 || *from == 13)
+ from++;
+ if (*from == '<') {
+ intoken = true;
+ tokpos = 0;
+ token[0] = 0;
+ token[1] = 0;
+ token[2] = 0;
+ ampersand = false;
+ continue;
+ }
+ else if (*from == '&') {
+ intoken = true;
+ tokpos = 0;
+ token[0] = 0;
+ token[1] = 0;
+ token[2] = 0;
+ ampersand = true;
+ continue;
+ }
+ if (*from == ';' && ampersand) {
+ intoken = false;
+ ampersand = false;
+
+ if (!strncmp("nbsp", token, 4)) text += " ";
+ else if (!strncmp("quot", token, 4)) text += "\"";
+ else if (!strncmp("amp", token, 3)) text += "&";
+ else if (!strncmp("lt", token, 2)) text += "<";
+ else if (!strncmp("gt", token, 2)) text += ">";
+ else if (!strncmp("brvbar", token, 6)) text += "¦";
+ else if (!strncmp("sect", token, 4)) text += "§";
+ else if (!strncmp("copy", token, 4)) text += "©";
+ else if (!strncmp("laquo", token, 5)) text += "«";
+ else if (!strncmp("reg", token, 3)) text += "®";
+ else if (!strncmp("acute", token, 5)) text += "´";
+ else if (!strncmp("para", token, 4)) text += "¶";
+ else if (!strncmp("raquo", token, 5)) text += "»";
+
+ else if (!strncmp("Aacute", token, 6)) text += "Á";
+ else if (!strncmp("Agrave", token, 6)) text += "À";
+ else if (!strncmp("Acirc", token, 5)) text += "Â";
+ else if (!strncmp("Auml", token, 4)) text += "Ä";
+ else if (!strncmp("Atilde", token, 6)) text += "Ã";
+ else if (!strncmp("Aring", token, 5)) text += "Å";
+ else if (!strncmp("aacute", token, 6)) text += "á";
+ else if (!strncmp("agrave", token, 6)) text += "à";
+ else if (!strncmp("acirc", token, 5)) text += "â";
+ else if (!strncmp("auml", token, 4)) text += "ä";
+ else if (!strncmp("atilde", token, 6)) text += "ã";
+ else if (!strncmp("aring", token, 5)) text += "å";
+ else if (!strncmp("Eacute", token, 6)) text += "É";
+ else if (!strncmp("Egrave", token, 6)) text += "È";
+ else if (!strncmp("Ecirc", token, 5)) text += "Ê";
+ else if (!strncmp("Euml", token, 4)) text += "Ë";
+ else if (!strncmp("eacute", token, 6)) text += "é";
+ else if (!strncmp("egrave", token, 6)) text += "è";
+ else if (!strncmp("ecirc", token, 5)) text += "ê";
+ else if (!strncmp("euml", token, 4)) text += "ë";
+ else if (!strncmp("Iacute", token, 6)) text += "Í";
+ else if (!strncmp("Igrave", token, 6)) text += "Ì";
+ else if (!strncmp("Icirc", token, 5)) text += "Î";
+ else if (!strncmp("Iuml", token, 4)) text += "Ï";
+ else if (!strncmp("iacute", token, 6)) text += "í";
+ else if (!strncmp("igrave", token, 6)) text += "ì";
+ else if (!strncmp("icirc", token, 5)) text += "î";
+ else if (!strncmp("iuml", token, 4)) text += "ï";
+ else if (!strncmp("Oacute", token, 6)) text += "Ó";
+ else if (!strncmp("Ograve", token, 6)) text += "Ò";
+ else if (!strncmp("Ocirc", token, 5)) text += "Ô";
+ else if (!strncmp("Ouml", token, 4)) text += "Ö";
+ else if (!strncmp("Otilde", token, 6)) text += "Õ";
+ else if (!strncmp("oacute", token, 6)) text += "ó";
+ else if (!strncmp("ograve", token, 6)) text += "ò";
+ else if (!strncmp("ocirc", token, 5)) text += "ô";
+ else if (!strncmp("ouml", token, 4)) text += "ö";
+ else if (!strncmp("otilde", token, 6)) text += "õ";
+ else if (!strncmp("Uacute", token, 6)) text += "Ú";
+ else if (!strncmp("Ugrave", token, 6)) text += "Ù";
+ else if (!strncmp("Ucirc", token, 5)) text += "Û";
+ else if (!strncmp("Uuml", token, 4)) text += "Ü";
+ else if (!strncmp("uacute", token, 6)) text += "ú";
+ else if (!strncmp("ugrave", token, 6)) text += "ù";
+ else if (!strncmp("ucirc", token, 5)) text += "û";
+ else if (!strncmp("uuml", token, 4)) text += "ü";
+ else if (!strncmp("Yacute", token, 6)) text += "Ý";
+ else if (!strncmp("yacute", token, 6)) text += "ý";
+ else if (!strncmp("yuml", token, 4)) text += "ÿ";
+
+ else if (!strncmp("deg", token, 3)) text += "°";
+ else if (!strncmp("plusmn", token, 6)) text += "±";
+ else if (!strncmp("sup2", token, 4)) text += "²";
+ else if (!strncmp("sup3", token, 4)) text += "³";
+ else if (!strncmp("sup1", token, 4)) text += "¹";
+ else if (!strncmp("nbsp", token, 4)) text += "º";
+ else if (!strncmp("pound", token, 5)) text += "£";
+ else if (!strncmp("cent", token, 4)) text += "¢";
+ else if (!strncmp("frac14", token, 6)) text += "¼";
+ else if (!strncmp("frac12", token, 6)) text += "½";
+ else if (!strncmp("frac34", token, 6)) text += "¾";
+ else if (!strncmp("iquest", token, 6)) text += "¿";
+ else if (!strncmp("iexcl", token, 5)) text += "¡";
+ else if (!strncmp("ETH", token, 3)) text += "Ð";
+ else if (!strncmp("eth", token, 3)) text += "ð";
+ else if (!strncmp("THORN", token, 5)) text += "Þ";
+ else if (!strncmp("thorn", token, 5)) text += "þ";
+ else if (!strncmp("AElig", token, 5)) text += "Æ";
+ else if (!strncmp("aelig", token, 5)) text += "æ";
+ else if (!strncmp("Oslash", token, 6)) text += "Ø";
+ else if (!strncmp("curren", token, 6)) text += "¤";
+ else if (!strncmp("Ccedil", token, 6)) text += "Ç";
+ else if (!strncmp("ccedil", token, 6)) text += "ç";
+ else if (!strncmp("szlig", token, 5)) text += "ß";
+ else if (!strncmp("Ntilde", token, 6)) text += "Ñ";
+ else if (!strncmp("ntilde", token, 6)) text += "ñ";
+ else if (!strncmp("yen", token, 3)) text += "¥";
+ else if (!strncmp("not", token, 3)) text += "¬";
+ else if (!strncmp("ordf", token, 4)) text += "ª";
+ else if (!strncmp("uml", token, 3)) text += "¨";
+ else if (!strncmp("shy", token, 3)) text += "­";
+ else if (!strncmp("macr", token, 4)) text += "¯";
+ else if (!strncmp("micro", token, 5)) text += "µ";
+ else if (!strncmp("middot", token, 6)) text +="·";
+ else if (!strncmp("cedil", token, 5)) text += "¸";
+ else if (!strncmp("ordm", token, 4)) text += "º";
+ else if (!strncmp("times", token, 5)) text += "×";
+ else if (!strncmp("divide", token, 6)) text +="÷";
+ else if (!strncmp("oslash", token, 6)) text +="ø";
+ continue;
+
+ }
+ else if (*from == '>' && !ampersand) {
+ intoken = false;
+ // process desired tokens
+ if (!strncmp(token, "sync type=\"Strongs\" value=\"", 27)) {
+ text += ' ';
+ text += '<';
+ for (unsigned int i = 27; token[i] != '\"'; i++)
+ text += token[i];
+ text += '>';
+ continue;
+ }
+ if (!strncmp(token, "sync type=\"morph\" value=\"", 25)) {
+ text += ' ';
+ text += '(';
+ for (unsigned int i = 25; token[i] != '\"'; i++)
+ text += token[i];
+ text += ')';
+ continue;
+ }
+ if (!strncmp("note", token, 4)) {
+ text += ' ';
+ text += '(';
+ }
+ else if (!strncmp("br", token, 2))
+ text += '\n';
+ else if (!strncmp("/p", token, 2))
+ text += '\n';
+ else if (!strncmp("/note", token, 5)) {
+ text += ')';
+ text += ' ';
+ }
+ continue;
+ }
+ if (intoken) {
+ if (tokpos < 2045)
+ token[tokpos++] = *from;
+ token[tokpos+2] = 0;
+ }
+ else text += *from;
+ }
+
+ orig = text;
+ from = orig.c_str();
+ for (text = ""; *from; from++) { //loop to remove extra spaces
+ if ((strchr(" \t\n\r", *from))) {
+ while (*(from+1) && (strchr(" \t\n\r", *(from+1)))) {
+ from++;
+ }
+ text += " ";
+ }
+ else {
+ text += *from;
+ }
+ }
+ text += (char)0;
+
+ return 0;
+}
+
diff --git a/src/backend/filters/bt_thmlplain.h b/src/backend/filters/bt_thmlplain.h
new file mode 100644
index 0000000..9d0a0c5
--- /dev/null
+++ b/src/backend/filters/bt_thmlplain.h
@@ -0,0 +1,28 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BT_THMLPLAIN_H
+#define BT_THMLPLAIN_H
+
+#include <swbuf.h>
+#include <swfilter.h>
+
+namespace Filters {
+
+ /** This filter converts ThML text to plain text
+ */
+class BT_ThMLPlain : public sword::SWFilter {
+protected:
+ virtual char processText(sword::SWBuf &text, const sword::SWKey *key = 0, const sword::SWModule *module = 0);
+public:
+ BT_ThMLPlain();
+};
+
+}
+#endif
diff --git a/src/backend/filters/osismorphsegmentation.cpp b/src/backend/filters/osismorphsegmentation.cpp
new file mode 100644
index 0000000..9ec00f7
--- /dev/null
+++ b/src/backend/filters/osismorphsegmentation.cpp
@@ -0,0 +1,83 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+#include "osismorphsegmentation.h"
+
+//Sword
+#include <utilxml.h>
+
+const char Filters::OSISMorphSegmentation::oName[] = "Morph segmentation";
+const char Filters::OSISMorphSegmentation::oTip[] = "Toggles morph segmentation On and Off if they exist";
+
+const sword::SWBuf Filters::OSISMorphSegmentation::choices[3] = {"Off", "On", ""};
+
+const sword::StringList Filters::OSISMorphSegmentation::oValues(&choices[0], &choices[2]);
+
+Filters::OSISMorphSegmentation::OSISMorphSegmentation() : sword::SWOptionFilter(oName, oTip, &oValues) {
+ setOptionValue("Off");
+ }
+
+Filters::OSISMorphSegmentation::~OSISMorphSegmentation() {}
+
+char Filters::OSISMorphSegmentation::processText(sword::SWBuf &text, const sword::SWKey */*key*/, const sword::SWModule */*module*/) {
+ sword::SWBuf token;
+ bool intoken = false;
+ bool hide = false;
+
+ sword::SWBuf orig( text );
+ const char *from = orig.c_str();
+
+ sword::XMLTag tag;
+
+ for (text = ""; *from; ++from) {
+ if (*from == '<') {
+ intoken = true;
+ token = "";
+ continue;
+ }
+
+ if (*from == '>') { // process tokens
+ intoken = false;
+
+ if (!strncmp(token.c_str(), "seg ", 4) || !strncmp(token.c_str(), "/seg", 4)) {
+ tag = token;
+
+ if (!tag.isEndTag() && tag.getAttribute("type") && !strcmp("morph", tag.getAttribute("type"))) { //<seg type="morph"> start tag
+ hide = (option == 0); //only hide if option is Off
+ }
+
+ if (hide) { //hides start and end tags as long as hide is set
+
+ if (tag.isEndTag()) { //</seg>
+ hide = false;
+ }
+
+ continue; //leave out the current token
+ }
+ } //end of seg tag handling
+
+ text.append('<');
+ text.append(token);
+ text.append('>');
+
+ // hide = false; //not right, because there may be child tags in seg. Only /seg may disable the seg hiding.
+
+ continue;
+ } //end of intoken part
+
+ if (intoken) { //copy token
+ token.append(*from);
+ }
+ else { //copy text which is not inside of a tag
+ text.append(*from);
+ }
+ }
+
+ return 0;
+}
+
diff --git a/src/backend/filters/osismorphsegmentation.h b/src/backend/filters/osismorphsegmentation.h
new file mode 100644
index 0000000..e419fe2
--- /dev/null
+++ b/src/backend/filters/osismorphsegmentation.h
@@ -0,0 +1,36 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef OSISMORPHSEGMENTATION_H
+#define OSISMORPHSEGMENTATION_H
+
+#include <swbuf.h>
+#include <swoptfilter.h>
+
+namespace Filters {
+
+/** This Filter shows/hides headings in a OSIS text.
+ * @author Martin Gruner
+ */
+class OSISMorphSegmentation : public sword::SWOptionFilter {
+ static const char oName[];
+ static const char oTip[];
+ static const sword::SWBuf choices[3];
+ static const sword::StringList oValues;
+
+public:
+ OSISMorphSegmentation();
+ virtual ~OSISMorphSegmentation();
+
+ virtual char processText(sword::SWBuf &text, const sword::SWKey *key = 0, const sword::SWModule *module = 0);
+};
+
+}
+
+#endif
diff --git a/src/backend/keys/cswordkey.cpp b/src/backend/keys/cswordkey.cpp
new file mode 100644
index 0000000..acb6da9
--- /dev/null
+++ b/src/backend/keys/cswordkey.cpp
@@ -0,0 +1,185 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cswordkey.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "cswordversekey.h"
+#include "cswordldkey.h"
+#include "cswordtreekey.h"
+
+#include "util/ctoolclass.h"
+
+//Sword
+#include <swmodule.h>
+#include <swkey.h>
+#include <versekey.h>
+#include <treekey.h>
+#include <treekeyidx.h>
+#include <utilstr.h>
+
+//Qt
+#include <QRegExp>
+#include <QString>
+#include <QTextCodec>
+
+CSwordKey::CSwordKey(CSwordModuleInfo* const module) : m_module(module) {}
+
+CSwordKey::CSwordKey(const CSwordKey& k) {
+ m_module = k.m_module;
+}
+
+QString CSwordKey::rawText() {
+ if (!m_module) return QString::null;
+
+ if (dynamic_cast<sword::SWKey*>(this)) {
+ char * buffer = new char[strlen(rawKey()) + 1];
+ strcpy(buffer, rawKey());
+ m_module->module()->getKey()->setText( buffer );
+ delete [] buffer;
+ }
+
+ if (key().isNull()) return QString::null;
+
+ return QString::fromUtf8( m_module->module()->getRawEntry() );
+}
+
+QString CSwordKey::renderedText( const CSwordKey::TextRenderType mode ) {
+ Q_ASSERT(m_module);
+ if (!m_module) {
+ return QString::null;
+ }
+
+ sword::SWKey* const k = dynamic_cast<sword::SWKey*>(this);
+
+ if (k) {
+ char * keyBuffer = new char[strlen(rawKey()) + 1];
+ strcpy(keyBuffer, rawKey());
+ sword::VerseKey* vk_mod = dynamic_cast<sword::VerseKey*>(m_module->module()->getKey());
+
+ if (vk_mod) {
+ vk_mod->Headings(1);
+ }
+
+ m_module->module()->getKey()->setText( keyBuffer );
+
+ if (m_module->type() == CSwordModuleInfo::Lexicon) {
+ m_module->snap();
+ /* In lexicons make sure that our key (e.g. 123) was successfully set to the module,
+ i.e. the module key contains this key (e.g. 0123 contains 123) */
+
+ if ( sword::stricmp(m_module->module()->getKey()->getText(), keyBuffer)
+ && !strstr(m_module->module()->getKey()->getText(), keyBuffer)
+ ) {
+ qDebug("return an empty key for %s", m_module->module()->getKey()->getText());
+ return QString::null;
+ }
+ }
+ delete [] keyBuffer;
+ }
+
+ //Q_ASSERT(!key().isNull());
+ if (!key().isNull()) { //we have valid text
+ QString text = QString::fromUtf8( m_module->module()->RenderText() );
+
+ // This is yucky, but if we want strong lexicon refs we have to do it here.
+ if (m_module->type() == CSwordModuleInfo::Lexicon) {
+ QString t(text);
+ QRegExp rx("(GREEK|HEBREW) for 0*([1-9]\\d*)"); // ignore 0's before number
+ int pos = 0;
+ while( (pos = rx.indexIn(t, pos)) != -1 ) {
+ QString language = rx.cap(1);
+ QString langcode = QString(language.at(0)); // "G" or "H"
+ QString number = rx.cap(2);
+ QString paddednumber = number.rightJustified(5, '0'); // Form 00123
+
+ text.replace(
+ QRegExp( QString(
+ "(>[^<>]+)" // Avoid replacing inside tags
+ "\\b(0*%1)\\b").arg(number) ), // And span around 0's
+ QString("\\1<span lemma=\"%1%2\"><a href=\"strongs://%3/%4\">\\2</a></span>")
+ .arg(langcode, paddednumber, language, paddednumber)
+ );
+ pos += rx.matchedLength();
+ }
+ }
+
+ if (mode == HTMLEscaped) {
+ //we have to encode all UTF-8 in HTML escapes
+ // go though every character and write down the escaped HTML unicode entity
+ // form is &#<decimal unicode value here>;
+ QString ret;
+ QChar c;
+ const unsigned int length = text.length();
+
+ for (unsigned int i = 0; i < length; ++i) {
+ c = text.at(i);
+
+ if (c.toLatin1()) { //normal latin1 character
+ ret.append(c);
+ }
+ else {//unicode character, needs to be escaped
+ ret.append("&#")
+ .append(c.unicode())
+ .append(";");
+ }
+ }
+
+ return ret;
+ }
+ else {
+ return text;
+ }
+ }
+
+ return QString::null;
+}
+
+QString CSwordKey::strippedText() {
+ if (!m_module) return QString::null;
+
+ if (dynamic_cast<sword::SWKey*>(this)) {
+ char * buffer = new char[strlen(rawKey()) + 1];
+ strcpy(buffer, rawKey());
+ m_module->module()->getKey()->setText( buffer );
+ delete [] buffer;
+ }
+
+ return QString::fromUtf8( m_module->module()->StripText() );
+}
+
+const QTextCodec* CSwordKey::cp1252Codec() {
+ static QTextCodec * codec = QTextCodec::codecForName("Windows-1252");
+ return codec;
+}
+
+
+/** This will create a proper key object from a given module */
+CSwordKey* CSwordKey::createInstance( CSwordModuleInfo* const module ) {
+ if (!module) {
+ return 0;
+ }
+
+ switch( module->type() ) {
+
+ case CSwordModuleInfo::Bible://fall through
+
+ case CSwordModuleInfo::Commentary:
+ return new CSwordVerseKey( (sword::VerseKey *) ( (sword::SWKey *)(*module->module()) ), module );
+
+ case CSwordModuleInfo::Lexicon:
+ return new CSwordLDKey( (sword::SWKey *)(*module->module()), module);
+
+ case CSwordModuleInfo::GenericBook:
+ return new CSwordTreeKey( (sword::TreeKeyIdx*)((sword::SWKey *)(*module->module())), module );
+
+ default:
+ return 0;
+ }
+}
diff --git a/src/backend/keys/cswordkey.h b/src/backend/keys/cswordkey.h
new file mode 100644
index 0000000..e0e6300
--- /dev/null
+++ b/src/backend/keys/cswordkey.h
@@ -0,0 +1,111 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CSWORDKEY_H
+#define CSWORDKEY_H
+
+//Qt
+#include <QString>
+
+class CSwordModuleInfo;
+class QTextCodec;
+
+/** Base class for all keys.
+ * The base class for all Sword based keys.
+ * @author The BibleTime team
+ * @version $Id: cswordkey.h,v 1.27 2006/10/30 19:53:32 mgruner Exp $
+ */
+
+class CSwordKey {
+
+protected:
+ /** Constructor. May only be called from sublasses because this class contains pure virtual methods.
+ * @param module The module which belongs to this key, may be NULL
+ */
+ CSwordKey(CSwordModuleInfo* const module = 0); //protected constructor, because CSwordKey shouldn't be used (it's an abstract base class).
+ /** Copy constructor.
+ */
+ CSwordKey(const CSwordKey&); //copy constructor
+
+public:
+ enum TextRenderType {
+ Normal = 0,
+ HTMLEscaped
+ };
+ /** Destructor.
+ * Public, not protected like the constructor, because CSwordKey pointers may be deleted by all others.
+ */
+ virtual ~CSwordKey() {};
+
+ //pure virtual functions
+ /** Returns the current key.
+ * @return The current key which belongs to the current object.
+ */
+ virtual QString key() const = 0;
+ /** Sets the current key. Sets the key using a utf8 enabled QString.
+ * @param key The key which should be used to set the current one
+ */
+ virtual bool key(const QString& key) = 0;
+ /** Set the key using a utf8-decoded c-string
+ * @param key The key which should be used to set the current one
+ */
+ virtual bool key(const char* key) = 0;
+ /** Clone this object. Clone this current object and return it.
+ * @return A clone of the current object.
+ */
+ virtual CSwordKey* copy() const = 0;
+
+ //implemented functions
+ /** Set/get the module. Set and get the module which belongs to this key.
+ * @return The module which belongs to this key.
+ */
+ inline virtual CSwordModuleInfo* module(CSwordModuleInfo* const newModule = 0);
+ /** Returns the raw, unchanged text. Returns the text without any filter modifications,
+ * just in the way it comes out of the module.
+ */
+ virtual QString rawText();
+ /** Returns the rendered text. Returns the text of the current key after passign it through the
+ * modules filters.
+ */
+ virtual QString renderedText( const CSwordKey::TextRenderType mode = CSwordKey::Normal );
+ /** Stripped down text. Returns the text after removing all markup tags from it.
+ */
+ virtual QString strippedText();
+ /**
+ * This returns a new object of the right CSwordKey* implementation
+ * (e.g. CSwordVerseKey or CSwordLDKey)
+ * The type is determined by the type of the module.
+ * @see CSwordModuleInfo, CSwordBibleModuleInfo, CSwordCommentaryModuleInfo, CSwordLexiconModukleInfo
+ */
+ static CSwordKey* createInstance(CSwordModuleInfo * const module);
+
+protected:
+ /**
+ * Returns the encoded key appropriate for use directly with Sword.
+ */
+ virtual const char * rawKey() const = 0;
+ static const QTextCodec* cp1252Codec();
+ CSwordModuleInfo* m_module; //module pointer used by all keys
+
+private:
+ /**
+ * Disable the assignment operator
+ */
+ CSwordKey& operator= ( const CSwordKey & );
+
+};
+
+inline CSwordModuleInfo* CSwordKey::module(CSwordModuleInfo* const newModule) {
+ if (newModule) {
+ m_module = newModule;
+ }
+ return m_module;
+}
+
+#endif
diff --git a/src/backend/keys/cswordldkey.cpp b/src/backend/keys/cswordldkey.cpp
new file mode 100644
index 0000000..3205827
--- /dev/null
+++ b/src/backend/keys/cswordldkey.cpp
@@ -0,0 +1,118 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cswordldkey.h"
+#include "backend/drivers/cswordlexiconmoduleinfo.h"
+
+//Sword includes
+#include <swmodule.h>
+#include <swld.h>
+#include <utilstr.h>
+
+//Qt includes
+#include <QTextCodec>
+
+CSwordLDKey::CSwordLDKey( CSwordModuleInfo* module ) {
+ if ((m_module = dynamic_cast<CSwordLexiconModuleInfo*>(module))) {
+ // *(m_module->module()) = TOP;
+ }
+
+ SWKey::operator= (" ");
+}
+
+/** No descriptions */
+CSwordLDKey::CSwordLDKey( const CSwordLDKey &k ) : CSwordKey(k), SWKey((const char*)k) {}
+
+/** No descriptions */
+CSwordLDKey::CSwordLDKey( const SWKey *k, CSwordModuleInfo* module) : CSwordKey(module), SWKey(*k) {}
+
+/** Clones this object by copying the members. */
+CSwordLDKey* CSwordLDKey::copy() const {
+ return new CSwordLDKey(*this);
+}
+
+/** Sets the module of this key. */
+CSwordModuleInfo* CSwordLDKey::module(CSwordModuleInfo* const newModule) {
+ if (newModule && newModule->type() == CSwordModuleInfo::Lexicon) {
+ const QString oldKey = key();
+ m_module = newModule;
+ key(oldKey);
+ }
+
+ return m_module;
+}
+
+QString CSwordLDKey::key() const {
+ //return QString::fromUtf8((const char*)*this);
+ Q_ASSERT(m_module);
+
+ if (m_module->isUnicode()) {
+ return QString::fromUtf8((const char*)*this);
+ } else {
+ return cp1252Codec()->toUnicode((const char*)*this);
+ }
+}
+
+const char * CSwordLDKey::rawKey() const {
+ return (const char*)*this;
+}
+
+bool CSwordLDKey::key( const QString& newKey ) {
+ Q_ASSERT(m_module);
+
+ if (m_module->isUnicode()) {
+ return key(newKey.toUtf8().constData());
+ } else {
+ return key((const char*)cp1252Codec()->fromUnicode(newKey));
+ }
+}
+
+
+/** Sets the key of this instance */
+bool CSwordLDKey::key( const char* newKey ) {
+ Q_ASSERT(newKey);
+
+ if (newKey) {
+ SWKey::operator = (newKey); //set the key
+ m_module->module()->SetKey(this);
+ m_module->snap();
+ }
+
+ return !Error();
+}
+
+/** Uses the parameter to returns the next entry afer this key. */
+CSwordLDKey* CSwordLDKey::NextEntry() {
+ m_module->module()->SetKey(this); //use this key as base for the next one!
+ // m_module->module()->getKey()->setText( (const char*)key().utf8() );
+
+ m_module->module()->setSkipConsecutiveLinks(true);
+ ( *( m_module->module() ) )++;
+ m_module->module()->setSkipConsecutiveLinks(false);
+
+ key(m_module->module()->KeyText());
+ SWKey::operator = (m_module->module()->KeyText());
+
+ return this;
+}
+
+/** Uses the parameter to returns the next entry afer this key. */
+CSwordLDKey* CSwordLDKey::PreviousEntry() {
+ m_module->module()->SetKey(this); //use this key as base for the next one!
+ // m_module->module()->getKey()->setText( (const char*)key().utf8() );
+
+ m_module->module()->setSkipConsecutiveLinks(true);
+ ( *( m_module->module() ) )--;
+ m_module->module()->setSkipConsecutiveLinks(false);
+
+ SWKey::operator = (m_module->module()->KeyText());
+
+ return this;
+}
+
diff --git a/src/backend/keys/cswordldkey.h b/src/backend/keys/cswordldkey.h
new file mode 100644
index 0000000..0349597
--- /dev/null
+++ b/src/backend/keys/cswordldkey.h
@@ -0,0 +1,110 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CSWORDLDKEY_H
+#define CSWORDLDKEY_H
+
+#include "cswordkey.h"
+class CSwordModuleInfo;
+
+//Qt
+#include <QString>
+
+//Sword includes
+#include <swkey.h>
+
+/**
+ * This class is the implementation of CSwordKey used for dictionaries and lexicons.
+ *
+ * CSwordLDKey is the implementation of CKey for Lexicons and dictionaries.
+ * It provides a simple interface to set the current key,
+ * to get the text for the key and functions to get the next and previous items
+ * of the used module in comparision to the current key.<BR>
+ * Here's an example how to use this class:<BR>
+ * @code
+ * CSwordLexiconModuleInfo* m_module = backend()->findModuleByName("ISBE");
+ * CSwordLDKey ldKey(m_module);
+ * ldKey.key("Adam");
+ * ldKey.nextEntry();
+ * qDebug( QString("The current key is: %1").arg(ldKey.key()));
+ * @endcode
+ *
+ * Please not, that the result will be invalid if use the operator const char*
+ * on the adress of the object, use something like this
+ *
+ * @code
+ * CSwordLDKey* key = new CSwordLDKey( lexicon_module );
+ * const QString keyname = key->getKey();
+ * @endcode
+ *
+ * @author The BibleTime team
+ * @version $Id: cswordldkey.h,v 1.24 2006/02/25 11:38:15 joachim Exp $
+ */
+
+class CSwordLDKey : public CSwordKey, public sword::SWKey {
+
+public:
+ /**
+ * Constructor of CSwordLDKey
+ */
+ CSwordLDKey( CSwordModuleInfo* module );
+ /**
+ * Copy constructor for this key class.
+ */
+ CSwordLDKey( const CSwordLDKey &k );
+ /**
+ * Copy constructor for this key class.
+ */
+ CSwordLDKey( const sword::SWKey *k, CSwordModuleInfo* module);
+ /**
+ * Clones this object by copying the members.
+ */
+ virtual CSwordLDKey* copy() const;
+ /**
+ * Uses the parameter to returns the next entry afer this key.
+ */
+ CSwordLDKey* NextEntry( void );
+ /**
+ * Uses the parameter to returns the previous entry afer this key.
+ */
+ CSwordLDKey* PreviousEntry( void );
+ /**
+ * Sets the module of this key.
+ */
+ virtual CSwordModuleInfo* module( CSwordModuleInfo* const module = 0 );
+ /**
+ * Returns the current key as a QString
+ */
+ virtual QString key() const;
+ /**
+ * Set the current key using unicode decoded QString.
+ */
+ virtual bool key( const QString& newKey );
+ /**
+ * Set the current key from char*. To avoid encoding problems use key(QString) instead.
+ */
+ virtual bool key( const char* );
+
+protected:
+ /**
+ * Returns the raw key appropriate for use directly with Sword.
+ */
+ virtual const char* rawKey() const;
+
+private:
+ /**
+ * Disable assignment operator
+ */
+ CSwordLDKey& operator= (const CSwordLDKey& );
+
+};
+
+
+#endif
+
diff --git a/src/backend/keys/cswordtreekey.cpp b/src/backend/keys/cswordtreekey.cpp
new file mode 100644
index 0000000..6e02806
--- /dev/null
+++ b/src/backend/keys/cswordtreekey.cpp
@@ -0,0 +1,93 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cswordtreekey.h"
+#include "backend/drivers/cswordbookmoduleinfo.h"
+
+#include <QTextCodec>
+
+#include <QDebug>
+
+CSwordTreeKey::CSwordTreeKey( const CSwordTreeKey& k ) : CSwordKey(k), TreeKeyIdx(k) {}
+
+CSwordTreeKey::CSwordTreeKey( const TreeKeyIdx *k, CSwordModuleInfo* module ) : CSwordKey(module), TreeKeyIdx(*k) {}
+
+CSwordTreeKey* CSwordTreeKey::copy() const {
+ return new CSwordTreeKey(*this);
+}
+
+/** Sets the key of this instance */
+QString CSwordTreeKey::key() const {
+ //return getTextUnicode();
+ Q_ASSERT(m_module);
+ if (m_module->isUnicode()) {
+ return QString::fromUtf8(getText());
+ } else {
+ return cp1252Codec()->toUnicode(getText());
+ }
+}
+
+const char * CSwordTreeKey::rawKey() const {
+ return getText();
+}
+
+bool CSwordTreeKey::key( const QString& newKey ) {
+ //return key( newKey.toLocal8Bit().constData() );
+ //return key(m_module->getTextCodec()->fromUnicode(newKey).constData());
+ Q_ASSERT(m_module);
+ if (m_module->isUnicode()) {
+ return key(newKey.toUtf8().constData());
+ } else {
+ return key((const char*)cp1252Codec()->fromUnicode(newKey));
+ }
+}
+
+bool CSwordTreeKey::key( const char* newKey ) {
+ Q_ASSERT(newKey);
+
+ if (newKey) {
+ TreeKeyIdx::operator = (newKey);
+ }
+ else {
+ root();
+ }
+
+ return !Error();
+}
+
+QString CSwordTreeKey::getLocalNameUnicode()
+{
+ //return m_module->getTextCodec()->toUnicode(getLocalName());
+ //Only UTF-8 and latin1 are legal Sword module encodings
+ Q_ASSERT(m_module);
+ if (m_module->isUnicode()) {
+ return QString::fromUtf8(getLocalName());
+ } else {
+ return cp1252Codec()->toUnicode(getLocalName());
+ }
+}
+
+CSwordModuleInfo* CSwordTreeKey::module( CSwordModuleInfo* const newModule ) {
+ if (newModule && (newModule != m_module) && (newModule->type() == CSwordModuleInfo::GenericBook) ) {
+ m_module = newModule;
+
+ const QString oldKey = key();
+
+ CSwordBookModuleInfo* newBook = dynamic_cast<CSwordBookModuleInfo*>(newModule);
+ copyFrom( *(newBook->tree()) );
+
+ key(oldKey); //try to restore our old key
+
+ //set the key to the root node
+ root();
+ firstChild();
+ }
+
+ return m_module;
+}
diff --git a/src/backend/keys/cswordtreekey.h b/src/backend/keys/cswordtreekey.h
new file mode 100644
index 0000000..4114652
--- /dev/null
+++ b/src/backend/keys/cswordtreekey.h
@@ -0,0 +1,79 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CSWORDTREEKEYIDX_H
+#define CSWORDTREEKEYIDX_H
+
+//BibleTime
+#include "cswordkey.h"
+
+//Sword
+#include <treekeyidx.h>
+
+class CSwordModuleInfo;
+
+/** BibleTime's implementation of Sword's TreeKeyIdx class.
+ * @short CSwordKey implementation for Sword's TreeKey
+ * @author The BibleTime team
+ */
+
+class CSwordTreeKey : public CSwordKey, public sword::TreeKeyIdx {
+
+public:
+ /** Constructor of this CSwordKey implementation.
+ * @param k The Sword tree key which belongs to this key
+ * @param module The module which belongs to this key
+ */
+ CSwordTreeKey( const sword::TreeKeyIdx *k, CSwordModuleInfo* module );
+ /** Copy constructor.
+ */
+ CSwordTreeKey( const CSwordTreeKey& k );
+ /** The module which belongs to this key.
+ * @return The module.
+ */
+ virtual CSwordModuleInfo* module( CSwordModuleInfo* const newModule );
+ /** Copy method.
+ * @return A new copy of this object.
+ */
+ virtual CSwordTreeKey* copy() const;
+
+ /**
+ * Returns the TreeKeyIdx::getLocalKey value in unicode.
+ * Local key is the last part of the tree key, for example "Subsection1" from "/Section1/Subsection1".
+ * Use this instead of getLocalKey() to avoid encoding problems.
+ */
+ QString getLocalNameUnicode();
+ /**
+ * Returns the current key as unicode decoded QString.
+ */
+ virtual QString key() const;
+ /**
+ * Set the key. If the parameter is empty or null, the key will be set to "/"
+ */
+ virtual bool key( const QString& key );
+ /**
+ * Set the key from char* To avoid encoding problems use key(QString instead),
+ * otherwise it is caller's responsibility to ensure the correct encoding (utf8/latin1).
+ */
+ virtual bool key( const char* key );
+
+protected:
+ /**
+ * Returns the raw key appropriate for use directly with Sword.
+ */
+ virtual const char * rawKey() const;
+
+private:
+ /** Disable assignment operator */
+ CSwordTreeKey& operator= (const CSwordTreeKey&);
+ /** Disable from base class to prevent compiler warnings */
+ inline virtual CSwordTreeKey& operator= (const sword::TreeKeyIdx&) { return (*this); };
+};
+
+#endif
diff --git a/src/backend/keys/cswordversekey.cpp b/src/backend/keys/cswordversekey.cpp
new file mode 100644
index 0000000..424b268
--- /dev/null
+++ b/src/backend/keys/cswordversekey.cpp
@@ -0,0 +1,303 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cswordversekey.h"
+#include "backend/drivers/cswordbiblemoduleinfo.h"
+#include "backend/drivers/cswordcommentarymoduleinfo.h"
+
+//Qt
+#include <QStringList>
+
+//Sword
+#include <swmodule.h>
+#include <localemgr.h>
+
+CSwordVerseKey::CSwordVerseKey( CSwordModuleInfo* const module ) : CSwordKey(module) {
+ if ( CSwordBibleModuleInfo* bible = dynamic_cast<CSwordBibleModuleInfo*>(module) ) {
+ key( bible->lowerBound().key() );
+ }
+}
+
+CSwordVerseKey::CSwordVerseKey( const CSwordVerseKey& k ) : CSwordKey(k), VerseKey(k) {}
+
+CSwordVerseKey::CSwordVerseKey( const VerseKey* const k, CSwordModuleInfo* const module ) : CSwordKey(module), VerseKey(*k) {}
+
+/** Clones this object. */
+CSwordKey* CSwordVerseKey::copy() const {
+ return new CSwordVerseKey(*this);
+}
+
+/** Sets the module for this key */
+CSwordModuleInfo* CSwordVerseKey::module( CSwordModuleInfo* const newModule ) {
+ if (newModule && ((newModule->type() == CSwordModuleInfo::Bible) || (newModule->type() == CSwordModuleInfo::Commentary) ) ) {
+ m_module = newModule;
+
+ //check if the module contains the key we present
+ CSwordBibleModuleInfo* bible = dynamic_cast<CSwordBibleModuleInfo*>(newModule);
+
+ if (_compare(bible->lowerBound()) < 0) {
+ key( bible->lowerBound() );
+ }
+
+ if (_compare(bible->upperBound()) > 0) {
+ key( bible->upperBound() );
+ }
+ }
+
+ return dynamic_cast<CSwordBibleModuleInfo*>(m_module);
+}
+
+/** Returns the current book as Text, not as integer. */
+QString CSwordVerseKey::book( const QString& newBook ) {
+ int min = 0;
+ int max = 1;
+
+ if (CSwordBibleModuleInfo* bible = dynamic_cast<CSwordBibleModuleInfo*>(module())) {
+ const bool hasOT = bible->hasTestament(CSwordBibleModuleInfo::OldTestament);
+ const bool hasNT = bible->hasTestament(CSwordBibleModuleInfo::NewTestament);
+
+ if (hasOT && hasNT) {
+ min = 0;
+ max = 1;
+ }
+ else if (hasOT && !hasNT) {
+ min = 0;
+ max = 0;
+ }
+ else if (!hasOT && hasNT) {
+ min = 1;
+ max = 1;
+ }
+ else if (!hasOT && !hasNT) {
+ min = 0;
+ max = -1; //no loop
+ }
+ }
+
+ if (!newBook.isEmpty()) {
+
+#ifdef SWORD_MULTIVERSE
+ setBookName(newBook.toUtf8().constData());
+#else
+
+ bool finished = false;
+
+ for (int testament = min; testament <= max && !finished; ++testament) {
+ for (int book = 0; book < BMAX[testament] && !finished; ++book) {
+ if ( !strcmp(newBook.toUtf8().constData(), books[testament][book].name ) ) {
+ Testament(testament+1);
+ Book(book+1);
+ finished = true;
+ }
+ }
+ }
+#endif
+ }
+
+ if ( (Testament() >= min+1) && (Testament() <= max+1) && (Book() <= BMAX[min]) ) {
+ return QString::fromUtf8( getBookName() );
+ }
+
+ //return QString::fromUtf8( books[min][0].name ); //return the first book, i.e. Genesis
+ return QString::null;
+}
+
+/** Sets the key we use to the parameter. */
+QString CSwordVerseKey::key() const {
+ return QString::fromUtf8(getText());
+}
+
+const char * CSwordVerseKey::rawKey() const {
+ return getText();
+}
+
+bool CSwordVerseKey::key( const QString& newKey ) {
+ return key( newKey.toUtf8().constData() );
+}
+
+bool CSwordVerseKey::key( const char* newKey ) {
+ if (newKey && (strlen(newKey)>0) ) {
+ VerseKey::operator = (newKey);
+ }
+ else if (newKey && !strlen(newKey)) {
+ CSwordBibleModuleInfo* bible = dynamic_cast<CSwordBibleModuleInfo*>(module());
+
+ if ( bible ) {
+ VerseKey::operator = (bible->lowerBound().key().toUtf8().constData());
+ }
+ }
+
+ return !Error();
+}
+
+bool CSwordVerseKey::next( const JumpType type ) {
+ Error(); //clear Error status
+ bool ret = true;
+
+ switch (type) {
+
+ case UseBook: {
+ const int currentTestament = Testament();
+ const int currentBook = Book();
+
+ if ((currentTestament == 2) && (currentBook >= BMAX[currentTestament-1])) { //Revelation, i.e. end of navigation
+ return false;
+ }
+ else if ((currentTestament == 1) && (currentBook >= BMAX[currentTestament-1])) { //Malachi, switch to the NT
+ Testament(currentTestament+1);
+ Book(1);
+ }
+ else {
+ Book(Book()+1);
+ }
+ break;
+ }
+
+ case UseChapter: {
+ Chapter(Chapter()+1);
+ break;
+ }
+
+ case UseVerse: {
+ if (m_module && m_module->module()) {
+ const bool oldStatus = m_module->module()->getSkipConsecutiveLinks();
+ m_module->module()->setSkipConsecutiveLinks(true);
+
+ //disable headings for next verse
+ const bool useHeaders = (Verse() == 0);
+ const bool oldHeadingsStatus = ((VerseKey*)(m_module->module()->getKey()))->Headings( useHeaders );
+ //don't use setKey(), that would create a new key without Headings set
+ m_module->module()->getKey()->setText( key().toUtf8().constData() );
+
+ (*(m_module->module()) )++;
+
+ ((VerseKey*)(m_module->module()->getKey()))->Headings(oldHeadingsStatus);
+ m_module->module()->setSkipConsecutiveLinks(oldStatus);
+
+ if (!m_module->module()->Error()) {
+ key( QString::fromUtf8(m_module->module()->KeyText()) );
+ }
+ else {
+ // Verse(Verse()+1);
+ //don't change the key, restore the module's position
+ m_module->module()->getKey()->setText( key().toUtf8().constData() );
+ ret = false;
+ break;
+ }
+
+ }
+ else {
+ Verse(Verse()+1);
+ }
+
+ break;
+ }
+
+ default:
+ return false;
+ }
+
+ if ( CSwordBibleModuleInfo* bible = dynamic_cast<CSwordBibleModuleInfo*>(module()) ) {
+ if (_compare(bible->lowerBound()) < 0 ) {
+ key( bible->lowerBound() );
+ ret = false;
+ }
+
+ if (_compare(bible->upperBound()) > 0 ) {
+ key( bible->upperBound() );
+ ret = false;
+ }
+
+ return ret;
+ }
+ else if (Error()) { //we have no module, so take care of VerseKey::Error()
+ return false;
+ }
+
+ return ret;
+}
+
+bool CSwordVerseKey::previous( const JumpType type ) {
+ bool ret = true;
+
+ switch (type) {
+
+ case UseBook: {
+ if ( (Book() == 1) && (Testament() == 1) ) { //Genesis
+ return false;
+ }
+ else if ( (Book() == 1) && (Testament() == 2) ){ //Matthew
+ Testament(1);
+ Book(BMAX[0]);
+ }
+ else{
+ Book( Book()-1 );
+ }
+
+ break;
+ }
+
+ case UseChapter: {
+ Chapter(Chapter()-1);
+ break;
+ }
+
+ case UseVerse: {
+ if (m_module && m_module->module()) {
+ const bool useHeaders = (Verse() == 0);
+ const bool oldHeadingsStatus = ((VerseKey*)(m_module->module()->getKey()))->Headings( useHeaders );
+
+ m_module->module()->getKey()->setText( key().toUtf8().constData() );
+
+ const bool oldStatus = m_module->module()->getSkipConsecutiveLinks();
+ m_module->module()->setSkipConsecutiveLinks(true);
+ ( *( m_module->module() ) )--;
+
+ ((VerseKey*)(m_module->module()->getKey()))->Headings( oldHeadingsStatus );
+ m_module->module()->setSkipConsecutiveLinks(oldStatus);
+
+ if (!m_module->module()->Error()) {
+ key( QString::fromUtf8(m_module->module()->KeyText()) );//don't use fromUtf8
+ }
+ else {
+ ret = false;
+ // Verse(Verse()-1);
+ m_module->module()->getKey()->setText( key().toUtf8().constData() ); //restore module's key
+ }
+ }
+ else {
+ Verse(Verse()-1);
+ }
+
+ break;
+ }
+
+ default:
+ return false;
+ }
+
+ if ( CSwordBibleModuleInfo* bible = dynamic_cast<CSwordBibleModuleInfo*>(module()) ) {
+ if (_compare(bible->lowerBound()) < 0 ) {
+ key( bible->lowerBound() );
+ ret = false;
+ }
+
+ if (_compare(bible->upperBound()) > 0 ) {
+ key( bible->upperBound() );
+ ret = false;
+ }
+
+ return ret;
+ }
+ else if (Error()) {
+ return false;
+ }
+
+ return ret;
+}
diff --git a/src/backend/keys/cswordversekey.h b/src/backend/keys/cswordversekey.h
new file mode 100644
index 0000000..e421b6c
--- /dev/null
+++ b/src/backend/keys/cswordversekey.h
@@ -0,0 +1,122 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CSWORDVERSEKEY_H
+#define CSWORDVERSEKEY_H
+
+#include "cswordkey.h"
+class CSwordModuleInfo;
+
+//Qt
+#include <QString>
+
+//Sword
+#include <versekey.h>
+
+/**
+ * The CSwordKey implementation for verse based modules (Bibles and Commentaries)
+ *
+ * This class is the implementation of CKey for verse based modules like
+ * Bibles and commentaries.
+ * This class provides the special functions to work with the verse based modules.
+ *
+ * Useful functions are
+ * @see NextBook()
+ * @see PreviousBook()
+ * @see NextChapter()
+ * @see PreviousChapter()
+ * @see NextVerse()
+ * @see PreviousVerse().
+ *
+ * Call the constructor only with a valid verse based modules, otherwise this key will be invalid
+ * and the application will probably crash.
+ *
+ * @version $Id: cswordversekey.h,v 1.26 2006/02/25 11:38:15 joachim Exp $
+ * @short CSwordKey implementation for Sword's VerseKey.
+ * @author The BibleTime team
+ */
+
+class CSwordVerseKey : public CSwordKey, public sword::VerseKey {
+
+public:
+ enum JumpType {
+ UseBook,
+ UseChapter,
+ UseVerse
+ };
+
+ /**
+ * Constructor of this class.
+ *
+ * This function will construct a versekey with the current module position
+ * and it will setup the m_module members.
+ *
+ */
+ CSwordVerseKey( CSwordModuleInfo* const module );
+ /**
+ * Copy constructor.
+ */
+ CSwordVerseKey( const CSwordVerseKey& k );
+ /**
+ * VerseKey based constructor.
+ */
+ CSwordVerseKey( const sword::VerseKey* const k, CSwordModuleInfo* const module );
+ /**
+ * Clones this object.
+ */
+ virtual CSwordKey* copy() const;
+ /**
+ * Set/get the key. If the parameter is not set (means equal to QString::null)
+ * the used key is returned. Otherwise the key is set and the new on ei returned.
+ */
+ virtual QString key() const;
+ /**
+ * Set the current key.
+ */
+ virtual bool key( const QString& );
+ /**
+ * Set/get the key. If the parameter is not set (means equal to QString::null)
+ * the used key is returned. Otherwise the key is set and the new on ei returned.
+ */
+ virtual bool key( const char* key );
+
+ /**
+ * Jumps to the next entry of the given type
+ */
+ bool next( const JumpType type );
+ /**
+ * Jumps to the previous entry of the given type
+ */
+ bool previous ( const JumpType type );
+ /**
+ * This functions returns the current book as localised text, not as book numer.
+ *
+ * Use "char Book()" to retrieve the book number of the current book.
+ * @return The name of the current book
+ */
+ QString book(const QString& newBook = QString::null);
+ /**
+ * Sets the module for this key
+ */
+ virtual CSwordModuleInfo* module( CSwordModuleInfo* const newModule = 0 );
+
+protected:
+ /**
+ * Returns the raw key appropriate for use directly with Sword.
+ */
+ virtual const char * rawKey() const;
+
+private:
+ /** Disable assignment operator */
+ CSwordVerseKey& operator= (const CSwordVerseKey&);
+ /** Disable from base class to prevent compiler warnings */
+ inline virtual CSwordVerseKey& operator= (const sword::VerseKey&) { return (*this); };
+};
+
+#endif
diff --git a/src/backend/managers/btstringmgr.cpp b/src/backend/managers/btstringmgr.cpp
new file mode 100644
index 0000000..9f57258
--- /dev/null
+++ b/src/backend/managers/btstringmgr.cpp
@@ -0,0 +1,139 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "btstringmgr.h"
+
+char* BTStringMgr::upperUTF8(char* text, unsigned int maxlen) const {
+ const int max = (maxlen>0) ? maxlen : strlen(text);
+
+ if (isUtf8(text)) {
+ strncpy(text, (const char*)QString::fromUtf8(text).toUpper().toUtf8(), max);
+
+ return text;
+ }
+ else {
+ char* ret = text;
+
+ while (*text) {
+ *text = toupper(*text);
+ text++;
+ }
+
+ return ret;
+ }
+
+ return text;
+}
+
+char* BTStringMgr::upperLatin1(char* text, unsigned int /*max*/) const {
+ char* ret = text;
+
+ while (*text) {
+ *text = toupper(*text);
+ text++;
+ }
+
+ return ret;
+}
+
+bool BTStringMgr::supportsUnicode() const {
+ return true;
+}
+
+bool BTStringMgr::isUtf8(const char *buf) const {
+ int i, n;
+ register unsigned char c;
+ bool gotone = false;
+
+ #define F 0 /* character never appears in text */
+ #define T 1 /* character appears in plain ASCII text */
+ #define I 2 /* character appears in ISO-8859 text */
+ #define X 3 /* character appears in non-ISO extended ASCII (Mac, IBM PC) */
+
+ static const unsigned char text_chars[256] = {
+ /* BEL BS HT LF FF CR */
+ F, F, F, F, F, F, F, T, T, T, T, F, T, T, F, F, /* 0x0X */
+ /* ESC */
+ F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F, /* 0x1X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x2X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x3X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x4X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x5X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x6X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F, /* 0x7X */
+ /* NEL */
+ X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X, /* 0x8X */
+ X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, /* 0x9X */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xaX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xbX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xcX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xdX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xeX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I /* 0xfX */
+ };
+
+ /* *ulen = 0; */
+
+ for (i = 0; (c = buf[i]); i++) {
+ if ((c & 0x80) == 0) { /* 0xxxxxxx is plain ASCII */
+ /*
+ * Even if the whole file is valid UTF-8 sequences,
+ * still reject it if it uses weird control characters.
+ */
+
+ if (text_chars[c] != T)
+ return false;
+
+ }
+ else if ((c & 0x40) == 0) { /* 10xxxxxx never 1st byte */
+ return false;
+ }
+ else { /* 11xxxxxx begins UTF-8 */
+ int following;
+
+ if ((c & 0x20) == 0) { /* 110xxxxx */
+ following = 1;
+ }
+ else if ((c & 0x10) == 0) { /* 1110xxxx */
+ following = 2;
+ }
+ else if ((c & 0x08) == 0) { /* 11110xxx */
+ following = 3;
+ }
+ else if ((c & 0x04) == 0) { /* 111110xx */
+ following = 4;
+ }
+ else if ((c & 0x02) == 0) { /* 1111110x */
+ following = 5;
+ }
+ else
+ return false;
+
+ for (n = 0; n < following; n++) {
+ i++;
+
+ if (!(c = buf[i]))
+ goto done;
+
+ if ((c & 0x80) == 0 || (c & 0x40))
+ return false;
+ }
+
+ gotone = true;
+ }
+ }
+
+done:
+ return gotone; /* don't claim it's UTF-8 if it's all 7-bit */
+}
+
+#undef F
+#undef T
+#undef I
+#undef X
diff --git a/src/backend/managers/btstringmgr.h b/src/backend/managers/btstringmgr.h
new file mode 100644
index 0000000..d202c7f
--- /dev/null
+++ b/src/backend/managers/btstringmgr.h
@@ -0,0 +1,53 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef BTSTRINGMGR_H
+#define BTSTRINGMGR_H
+
+//Sword includes
+#include <stringmgr.h>
+
+//Qt includes
+#include <QString>
+
+/** Unicode string manager implementation.
+ * This is the StringManager implementation which works with QString.
+ * @author The BibleTime developers
+ */
+
+class BTStringMgr : public sword::StringMgr {
+
+public:
+ /** Converts the param to an upper case Utf8 string
+ * @param The text encoded in utf8 which should be turned into an upper case string
+ */
+ virtual char *upperUTF8(char *text, unsigned int max = 0) const;
+
+ /** Converts the param to an uppercase latin1 string
+ * @param The text encoded in latin1 which should be turned into an upper case string
+ */
+ virtual char *upperLatin1(char *text, unsigned int max = 0) const;
+
+protected:
+ /** Enable Unicode support.
+ * Reimplementation to show unicode support.
+ */
+ virtual bool supportsUnicode() const;
+
+ /** CODE TAKEN FROM KDELIBS 3.2, which is licensed under the LGPL 2.
+ *
+ * This code was taken from KStringHandler, which is part of the KDE libraries.
+ *
+ * This function checks whether a string is utf8 or not.
+ * It was taken from kdelibs so we do not depend on KDE 3.2.
+ */
+ bool isUtf8(const char *buf) const;
+};
+
+#endif
diff --git a/src/backend/managers/cdisplaytemplatemgr.cpp b/src/backend/managers/cdisplaytemplatemgr.cpp
new file mode 100644
index 0000000..6ddd6b7
--- /dev/null
+++ b/src/backend/managers/cdisplaytemplatemgr.cpp
@@ -0,0 +1,170 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cdisplaytemplatemgr.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/managers/clanguagemgr.h"
+#include "backend/config/cbtconfig.h"
+#include "util/cpointers.h"
+#include "util/directoryutil.h"
+
+//Qt
+#include <QStringList>
+#include <QFile>
+#include <QFileInfo>
+#include <QTextStream>
+#include <QDebug>
+
+CDisplayTemplateMgr::CDisplayTemplateMgr() {
+ loadTemplates();
+}
+
+CDisplayTemplateMgr::~CDisplayTemplateMgr() {
+}
+
+const QString CDisplayTemplateMgr::fillTemplate( const QString& name, const QString& content, Settings& settings )
+{
+ qDebug() << "CDisplayTemplateMgr::fillTemplate";
+
+ const QString templateName = m_templateMap.contains(name) ? name : defaultTemplate();
+
+ QString displayTypeString;
+
+ if (!settings.pageCSS_ID.isEmpty()) {
+ displayTypeString = settings.pageCSS_ID;
+ }
+ else {
+ if (settings.modules.count()) {
+ switch (settings.modules.first()->type()) {
+
+ case CSwordModuleInfo::Bible:
+ displayTypeString = "bible";
+ break;
+
+ case CSwordModuleInfo::GenericBook:
+ displayTypeString = "book";
+ break;
+
+ case CSwordModuleInfo::Commentary:
+ case CSwordModuleInfo::Lexicon:
+ default:
+ displayTypeString = "singleentry";
+ break;
+ };
+ }
+ else { //use bible as default type if no modules are set
+ displayTypeString = "bible";
+ };
+ }
+
+ QString newContent = content;
+ const int moduleCount = settings.modules.count();
+
+ if (moduleCount >= 2) {
+ //create header for the modules
+ qDebug("There were more than 1 module, create headers");
+ QString header;
+
+ QList<CSwordModuleInfo*>::iterator end_it = settings.modules.end();
+
+ for (QList<CSwordModuleInfo*>::iterator it(settings.modules.begin()); it != end_it; ++it) {
+ header.append("<th style=\"width:")
+ .append(QString::number(int( 100.0 / (float)moduleCount )))
+ .append("%;\">")
+ .append((*it)->name())
+ .append("</th>");
+ }
+
+ newContent = QString("<table><tr>")
+ .append(header)
+ .append("</tr>")
+ .append(content)
+ .append("</table>");
+ }
+
+ QString langCSS;
+ CLanguageMgr::LangMap langMap = CPointers::languageMgr()->availableLanguages();
+
+ qDebug() << "langMap length:" << langMap.count();
+ qDebug("loop through langMap");
+ foreach(const CLanguageMgr::Language* lang, langMap) {
+ //const CLanguageMgr::Language* lang = *it;
+ //qDebug() << "foreach, lang: ";
+ //qDebug() << lang;
+
+ //if (lang->isValid() && CBTConfig::get(lang).first) {
+ if (!lang->abbrev().isEmpty() && CBTConfig::get(lang).first) {
+ const QFont f = CBTConfig::get(lang).second;
+
+ //don't use important, because it would reset the title formatting, etc. to the setup font
+ QString css("{ ");
+ css.append("font-family:").append(f.family())/*.append(" !important")*/;
+ css.append("; font-size:").append(QString::number(f.pointSize())).append("pt /*!important*/");
+ css.append("; font-weight:").append(f.bold() ? "bold" : "normal /*!important*/");
+ css.append("; font-style:").append(f.italic() ? "italic" : "normal /*!important*/");
+ css.append("; }\n");
+
+ langCSS +=
+ QString("\n*[lang=%1] %2")
+ .arg(lang->abbrev())
+ .arg(css);
+ }
+ }
+
+ //at first append the font standard settings for all languages without configured font
+ // Create a dummy language (the langmap may be empty)
+ CLanguageMgr::Language lang_v(QString("en"), QString("English"), QString());
+ CLanguageMgr::Language* lang = &lang_v;
+
+ if (lang && !lang->abbrev().isEmpty()/*&& lang->isValid()*/) {
+ const QFont standardFont = CBTConfig::getDefault(lang); //we just need a dummy lang param
+ langCSS.prepend(
+ QString("\n#content {font-family:%1; font-size:%2pt; font-weight:%3; font-style: %4;}\n")
+ .arg(standardFont.family())
+ .arg(standardFont.pointSize())
+ .arg(standardFont.bold() ? "bold" : "normal")
+ .arg(standardFont.italic() ? "italic" : "normal")
+ );
+ }
+
+// qWarning("Outputing unformated text");
+ const QString t = QString(m_templateMap[ templateName ]) //don't change the map's content directly, use a copy
+ .replace("#TITLE#", settings.title)
+ .replace("#LANG_ABBREV#", settings.langAbbrev.isEmpty() ? QString("en") : settings.langAbbrev)
+ .replace("#DISPLAYTYPE#", displayTypeString)
+ .replace("#LANG_CSS#", langCSS)
+ .replace("#PAGE_DIRECTION#", settings.pageDirection)
+ .replace("#CONTENT#", newContent);
+
+ return t;
+}
+
+void CDisplayTemplateMgr::loadTemplates() {
+ QStringList files;
+ foreach (QString file, util::filesystem::DirectoryUtil::getDisplayTemplatesDir().entryList(QStringList("*.tmpl")))
+ {
+ files += util::filesystem::DirectoryUtil::getDisplayTemplatesDir().canonicalPath() + "/" + file;
+ }
+ foreach (QString file, util::filesystem::DirectoryUtil::getUserDisplayTemplatesDir().entryList(QStringList("*.tmpl")))
+ {
+ files += util::filesystem::DirectoryUtil::getUserDisplayTemplatesDir().canonicalPath() + "/" + file;
+ }
+
+ foreach (QString file, files) {
+ QFile f(file);
+ if (f.exists() && f.open( QIODevice::ReadOnly )) {
+ QString fileContent = QTextStream( &f ).readAll();
+
+ if (!fileContent.isEmpty()) {
+ m_templateMap[ QFileInfo(file).fileName() ] = fileContent;
+ }
+ }
+ }
+}
diff --git a/src/backend/managers/cdisplaytemplatemgr.h b/src/backend/managers/cdisplaytemplatemgr.h
new file mode 100644
index 0000000..c791e16
--- /dev/null
+++ b/src/backend/managers/cdisplaytemplatemgr.h
@@ -0,0 +1,91 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CDISPLAYTEMPLATEMGR_H
+#define CDISPLAYTEMPLATEMGR_H
+
+//BibleTime include
+class CSwordModuleInfo;
+
+//Qt includes
+#include <QMap>
+#include <QString>
+#include <QStringList>
+
+/**
+ * Manages the display templates used in the filters and display classes.
+ * @author The BibleTime team
+*/
+
+class CDisplayTemplateMgr {
+
+public:
+ /** Settings which are used to fill the content into the template.
+ */
+
+ struct Settings {
+ /** Constructor. Constructs the new settings object. The default values are empty.
+ */
+ Settings() {
+ title = QString::null;
+ langAbbrev = QString::null;
+ pageCSS_ID = QString::null;
+ pageDirection = QString("ltr");
+ };
+
+ QList<CSwordModuleInfo*> modules; /**< the list of modules */
+ QString title; /**< the title which is used for the new processed HTML page */
+ QString langAbbrev; /**< the language for the HTML page. */
+ QString pageDirection; /**< the language for the HTML page. */
+ QString pageCSS_ID; /**< the CSS ID which is used in the content part of the page */
+ };
+
+ /** Available templates.
+ * @return The list of templates, which are available.
+ */
+ inline const QStringList availableTemplates();
+ /** Fill template. Fill rendered content into the template given by the name.
+ * @param name The name of the template
+ * @param content The content which should be filled into the template
+ * @param settings The settings which are used to process the templating process
+ * @return The full HTML template HTML code including the CSS data.
+ */
+ const QString fillTemplate( const QString& name, const QString& content, Settings& settings);
+ /** Default template.
+ * @return The i18n'ed name of the default template
+ */
+ inline static const QString defaultTemplate();
+
+protected:
+ friend class CPointers;
+ /** Display template manager constructor. Protected to just allow CPointers to create objects. */
+ CDisplayTemplateMgr();
+ /** Destructor. */
+ ~CDisplayTemplateMgr();
+ /** Does the actual work of loading templates from disk */
+ void loadTemplates();
+
+private:
+ QMap<QString, QString> m_templateMap;
+};
+
+inline const QString CDisplayTemplateMgr::defaultTemplate() {
+ return QString("Blue.tmpl");
+}
+
+/**
+ * CDisplayTemplateMgr::availableTemplates()
+ */
+inline const QStringList CDisplayTemplateMgr::availableTemplates() {
+ return m_templateMap.keys();
+}
+
+
+
+#endif
diff --git a/src/backend/managers/clanguagemgr.cpp b/src/backend/managers/clanguagemgr.cpp
new file mode 100644
index 0000000..4dcc411
--- /dev/null
+++ b/src/backend/managers/clanguagemgr.cpp
@@ -0,0 +1,546 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "clanguagemgr.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "cswordbackend.h"
+
+#include "util/cpointers.h"
+
+//KDE
+
+
+CLanguageMgr::Language::Language() {}
+
+CLanguageMgr::Language::Language(const Language& l) {
+ m_abbrev = l.m_abbrev;
+ m_englishName = l.m_englishName;
+ m_translatedName = l.m_translatedName;
+ m_altAbbrevs = l.m_altAbbrevs;
+}
+
+CLanguageMgr::Language::Language( const QString& abbrev, const QString& name, const QString& translatedName, const QStringList& altAbbrevs ) {
+ m_abbrev = abbrev;
+ m_englishName = name;
+ m_translatedName = translatedName;
+ m_altAbbrevs = altAbbrevs;
+}
+
+CLanguageMgr::Language::~Language() {
+}
+
+
+/****************************************************/
+/******************** CLanguageMgr ******************/
+/****************************************************/
+CLanguageMgr::CLanguageMgr() : m_langMap() {
+ m_availableModulesCache.moduleCount = 0;
+ init();
+}
+
+CLanguageMgr::~CLanguageMgr() {
+ qDeleteAll(m_cleanupLangPtrs);
+ m_cleanupLangPtrs.clear();
+ qDeleteAll(m_langList);
+ m_langList.clear();
+}
+
+const CLanguageMgr::LangMap& CLanguageMgr::availableLanguages() {
+ QList<CSwordModuleInfo*> mods = CPointers::backend()->moduleList();
+
+ if ( m_availableModulesCache.moduleCount != (unsigned int)mods.count() ) { //we have to refill the cached map
+ m_availableModulesCache.availableLanguages.clear();
+ m_availableModulesCache.moduleCount = mods.count();
+
+ //collect the languages abbrevs of all modules
+ QStringList abbrevs;
+
+ foreach (const CSwordModuleInfo* mod, mods) {
+ if (!abbrevs.contains(mod->module()->Lang())){
+ abbrevs.append(mod->module()->Lang());
+ }
+ }
+
+ //now create a map of available langs
+ foreach ( QString abbrev, abbrevs ) {
+ const Language* const lang = languageForAbbrev(abbrev);
+
+ if (lang->isValid()) {
+ m_availableModulesCache.availableLanguages.insert( abbrev, lang );
+ }
+ else { //invalid lang used by a module, create a new language using the abbrev
+ Language* newLang = new Language(abbrev, abbrev, abbrev);
+ m_cleanupLangPtrs.append(newLang);
+ m_availableModulesCache.availableLanguages.insert( abbrev, newLang );
+ }
+ }
+ }
+ return m_availableModulesCache.availableLanguages;
+}
+
+const CLanguageMgr::Language* CLanguageMgr::languageForAbbrev( const QString& abbrev ) const {
+ LangMapIterator it = m_langMap.find(abbrev);
+ if (it != m_langMap.constEnd()) return *it; //Language is already here
+
+ //try to search in the alternative abbrevs
+ foreach (const Language* lang, m_langList ) {
+ if (lang->alternativeAbbrevs().contains(abbrev)) return lang;
+ }
+
+ // Invalid lang used by a modules, create a new language using the abbrev
+ Language* newLang = new Language(abbrev, abbrev, abbrev); //return a language which holds the valid abbrev
+ m_cleanupLangPtrs.append(newLang);
+
+ return newLang;
+}
+
+const CLanguageMgr::Language* CLanguageMgr::languageForName( const QString& name ) const {
+ foreach ( const Language* lang, m_langList ) {
+ if (lang->name() == name) return lang;
+ }
+ return &m_defaultLanguage;//invalid language
+}
+
+const CLanguageMgr::Language* CLanguageMgr::languageForTranslatedName( const QString& name ) const {
+ foreach ( const Language* lang, m_langList ) {
+ if (lang->translatedName() == name) return lang;
+ }
+ return &m_defaultLanguage; //invalid language
+}
+
+void CLanguageMgr::init() {
+
+ // The main() sets string literal codec to utf8:
+ // QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
+ // The language names include escape sequences \uxxxx
+
+ //if we've already inserted all items we do not proceed
+ if (m_langMap.count() > 0) return;
+
+ // Developers: It's easy to get a list of used language codes from all modules:
+ // Refresh all sources; go to .sword/InstallMgr/; run:
+ // grep -R -hs Lang= *|cut -c 6-|sort|uniq
+ // Don't remove unused languages from the source code unless you know it won't be used
+ // anymore.in any module ever.
+
+ /*:
+ The string "Names of languages" doesn't actually need translation.
+ It is put here to help translators notice this help text.
+ -------
+ The names of the languages should follow the conventions of your
+ language. You can write the names with a capital first letter even if your language
+ uses non-capitalized language names (they look better with capital
+ first letter when they are listed).
+ -------
+ To find the names of all languages from internet try searching for
+ "names of languages in language_x" but in your own language, e.g.
+ "kielten nimet suomeksi" in Finnish or "names of languages in english"
+ in English.
+ -------
+ You can find the language codes and names by googling for the standards
+ mentioned below.
+ -------
+ Preference order for locale codes are:
+ -------
+ ISO 639-1 -------
+ ISO 639-2 -------
+ ISO 639-3
+ -------
+ x-E-XXX form is deprecated and no modules in repositories use it.
+ If you find a module with x-E-XXX language, update the module.
+ */
+ QObject::tr("Names of languages", "No need to translate - see the longer comment (If there is no longer comment, it doesn't work yet :)) ------ ");
+ // m_langList.append( new Language("aa", "Afar", QObject::tr("Afar")) );
+ // m_langList.append( new Language("ab", "Abkhazian", QObject::tr("Abkhazian")) );
+ // m_langList.append( new Language("ae", "Avestan", QObject::tr("Avestan")) );
+ //: Language name af
+ m_langList.append( new Language("af", "Afrikaans", QObject::tr("Afrikaans")) );
+ // m_langList.append( new Language("am", "Amharic", QObject::tr("Amharic")) );
+ //: Language name amu
+ m_langList.append( new Language("amu", "Amuzgo, Guerrero", QObject::tr("Amuzgo, Guerrero")) );
+ //: Language name ang
+ m_langList.append( new Language("ang", "English, Old (ca.450-1100)", QObject::tr("English, Old (ca.450-1100)")) );
+ //: Language name ar
+ m_langList.append( new Language("ar", "Arabic", QObject::tr("Arabic")) );
+ // m_langList.append( new Language("as", "Assamese", QObject::tr("Assamese")) );
+ //: Language name az
+ m_langList.append( new Language("az", "Azerbaijani", QObject::tr("Azerbaijani")) );
+ //: Language name azb
+ m_langList.append( new Language("azb", "Azerbaijani, South", QObject::tr("Azerbaijani, South")) );
+ // m_langList.append( new Language("ba", "Bashkir", QObject::tr("Bashkir")) );
+ //: Language name bar
+ m_langList.append( new Language("bar", "Bavarian", QObject::tr("Bavarian")) );
+ //: Language name be
+ m_langList.append( new Language("be", "Belarusian", QObject::tr("Belarusian")) );
+ //: Language name bg
+ m_langList.append( new Language("bg", "Bulgarian", QObject::tr("Bulgarian")) );
+ // m_langList.append( new Language("bh", "Bihari", QObject::tr("Bihari")) );
+ // m_langList.append( new Language("bi", "Bislama", QObject::tr("Bislama")) );
+ // m_langList.append( new Language("bn", "Bengali", QObject::tr("Bengali")) );
+ // m_langList.append( new Language("bo", "Tibetan", QObject::tr("Tibetan")) );
+ //: Language name br
+ m_langList.append( new Language("br", "Breton", QObject::tr("Breton")) );
+ //: Language name bs
+ m_langList.append( new Language("bs", "Bosnian", QObject::tr("Bosnian")) );
+ //: Language name ca
+ m_langList.append( new Language("ca", "Catalan", QObject::tr("Catalan")) );
+ // m_langList.append( new Language("ce", "Chechen", QObject::tr("Chechen")) );
+ //: Language name cco
+ m_langList.append( new Language("cco", "Chinantec, Comaltepec", QObject::tr("Chinantec, Comaltepec")) );
+ //: Language name ceb
+ m_langList.append( new Language("ceb", "Cebuano", QObject::tr("Cebuano")) );
+ //: Language name ch
+ m_langList.append( new Language("ch", "Chamorro", QObject::tr("Chamorro")) );
+ //: Language name chd
+ m_langList.append( new Language("chd", "Chontal, Highland Oaxaca", QObject::tr("Chontal, Highland Oaxaca")) );
+ //: Language name chq
+ m_langList.append( new Language("chq", "Chinantec, Quiotepec", QObject::tr("Chinantec, Quiotepec")) );
+ //: Language name chz
+ m_langList.append( new Language("chz", "Chinantec, Ozumac\u00edn", QObject::tr("Chinantec, Ozumac\u00edn")) );
+ // m_langList.append( new Language("co", "Corsican", QObject::tr("Corsican")) );
+ //: Language name ckw
+ m_langList.append( new Language("ckw", "Cakchiquel, Western", QObject::tr("Cakchiquel, Western")) );
+ //: Language name cnl
+ m_langList.append( new Language("cnl", "Chinantec, Lalana", QObject::tr("Chinantec, Lalana")) );
+ //: Language name cnt
+ m_langList.append( new Language("cnt", "Chinantec, Tepetotutla", QObject::tr("Chinantec, Tepetotutla")) );
+ //: Language name cop
+ m_langList.append( new Language("cop", "Coptic", QObject::tr("Coptic")) );
+ //: Language name cs
+ m_langList.append( new Language("cs", "Czech", QObject::tr("Czech")) );
+ //: Language name cso
+ m_langList.append( new Language("cso", "Chinantec, Sochiapan", QObject::tr("Chinantec, Sochiapan")) );
+ //: Language name cti
+ m_langList.append( new Language("cti", "Chol, Tila", QObject::tr("Chol, Tila")) );
+ //: Language name ctp
+ m_langList.append( new Language("ctp", "Chatino, Western Highland", QObject::tr("Chatino, Western Highland")) );
+ //: Language name cu
+ m_langList.append( new Language("cu", "Church Slavic", QObject::tr("Church Slavic")) );
+ // m_langList.append( new Language("cv", "Chuvash", QObject::tr("Chuvash")) );
+ //: Language name cy
+ m_langList.append( new Language("cy", "Welsh", QObject::tr("Welsh")) );
+ //: Language name da
+ m_langList.append( new Language("da", "Danish", QObject::tr("Danish")) );
+ //: Language name de
+ m_langList.append( new Language("de", "German", QObject::tr("German")) );
+ //: Language name dug
+ m_langList.append( new Language("dug", "Duruma", QObject::tr("Duruma")) );
+ // m_langList.append( new Language("dz", "Dzongkha", QObject::tr("Dzongkha")) );
+ //: Language name el
+ m_langList.append( new Language("el", "Greek, Modern (1453-)", QObject::tr("Greek, Modern (1453-)"), makeStringList("gre;ell")) );
+ //: Language name en
+ m_langList.append( new Language("en", "English", QObject::tr("English")) );
+ //: Language name en_US
+ m_langList.append( new Language("en_US","American English", QObject::tr("American English")) );
+ //: Language name enm
+ m_langList.append( new Language("enm", "English, Middle (1100-1500)", QObject::tr("English, Middle (1100-1500)")) );
+ //: Language name eo
+ m_langList.append( new Language("eo", "Esperanto", QObject::tr("Esperanto")) );
+ //: Language name es
+ m_langList.append( new Language("es", "Spanish", QObject::tr("Spanish")) );
+ //: Language name et
+ m_langList.append( new Language("et", "Estonian", QObject::tr("Estonian")) );
+ //: Language name eu
+ m_langList.append( new Language("eu", "Basque", QObject::tr("Basque")) );
+ //: Language name fa
+ m_langList.append( new Language("fa", "Persian", QObject::tr("Persian")) );
+ //: Language name fi
+ m_langList.append( new Language("fi", "Finnish", QObject::tr("Finnish")) );
+ // m_langList.append( new Language("fj", "Fijian", QObject::tr("Fijian")) );
+ // m_langList.append( new Language("fo", "Faroese", QObject::tr("Faroese")) );
+ //: Language name fr
+ m_langList.append( new Language("fr", "French", QObject::tr("French")) );
+ //: Language name fy
+ m_langList.append( new Language("fy", "Frisian", QObject::tr("Frisian")) );
+ //: Language name ga
+ m_langList.append( new Language("ga", "Irish", QObject::tr("Irish")) );
+ //: Language name gd
+ m_langList.append( new Language("gd", "Gaelic (Scots)", QObject::tr("Gaelic (Scots)")) );
+ //: Language name gez
+ m_langList.append( new Language("gez", "Geez", QObject::tr("Geez")) );
+ // m_langList.append( new Language("gl", "Gallegan", QObject::tr("Gallegan")) );
+ // m_langList.append( new Language("gn", "Guarani", QObject::tr("Guarani")) );
+ // m_langList.append( new Language("gn", "Gujarati", QObject::tr("Gujarati")) );
+ //: Language name got
+ m_langList.append( new Language("got", "Gothic", QObject::tr("Gothic")) );
+ //: Language name gv
+ m_langList.append( new Language("gv", "Manx", QObject::tr("Manx")) );
+ //: Language name grc
+ m_langList.append( new Language("grc", "Greek, Ancient (to 1453)", QObject::tr("Greek, Ancient (to 1453)")) );
+ //: Language name he
+ m_langList.append( new Language("he", "Hebrew", QObject::tr("Hebrew")) );
+ //: Language name hau
+ m_langList.append( new Language("hau", "Hausa", QObject::tr("Hausa")) );
+ //: Language name haw
+ m_langList.append( new Language("haw", "Hawaiian", QObject::tr("Hawaiian")) );
+ //: Language name hi
+ m_langList.append( new Language("hi", "Hindi", QObject::tr("Hindi")) );
+ // m_langList.append( new Language("ho", "Hiri Motu", QObject::tr("Hiri Motu")) );
+ //: Language name hr
+ m_langList.append( new Language("hr", "Croatian", QObject::tr("Croatian")) );
+ //: Language name ht
+ m_langList.append( new Language("ht", "Haitian Creole", QObject::tr("Haitian Creole")) );
+ //: Language name hu
+ m_langList.append( new Language("hu", "Hungarian", QObject::tr("Hungarian")) );
+ //: Language name huv
+ m_langList.append( new Language("huv", "Huave, San Mateo Del Mar", QObject::tr("Huave, San Mateo Del Mar")) );
+ //: Language name hy
+ m_langList.append( new Language("hy", "Armenian", QObject::tr("Armenian")) );
+ // m_langList.append( new Language("hz", "Herero", QObject::tr("Herero")) );
+ // m_langList.append( new Language("ia", "Interlingua", QObject::tr("Interlingua")) );
+ //: Language name id
+ m_langList.append( new Language("id", "Indonesian", QObject::tr("Indonesian")) );
+ // m_langList.append( new Language("ie", "Interlingue", QObject::tr("Interlingue")) );
+ // m_langList.append( new Language("ik", "Inupiaq", QObject::tr("Inupiaq")) );
+ //: Language name is
+ m_langList.append( new Language("is", "Icelandic", QObject::tr("Icelandic")) );
+ //: Language name it
+ m_langList.append( new Language("it", "Italian", QObject::tr("Italian")) );
+ //: Language name itz
+ m_langList.append( new Language("itz", "Itz\u00e1", QObject::tr("Itz\u00e1")) );
+ //: Language name ixl
+ m_langList.append( new Language("ixl", "Ixil, San Juan Cotzal", QObject::tr("Ixil, San Juan Cotzal")) );
+ // m_langList.append( new Language("iu", "Inuktitut", QObject::tr("Inuktitut")) );
+ //: Language name ja
+ m_langList.append( new Language("ja", "Japanese", QObject::tr("Japanese")) );
+ //: Language name jac
+ m_langList.append( new Language("jac", "Jacalteco, Eastern", QObject::tr("Jacalteco, Eastern")) );
+ //: Language name jvn
+ m_langList.append( new Language("jvn", "Javanese, Caribbean", QObject::tr("Javanese, Caribbean")) );
+ //: Language name ka
+ m_langList.append( new Language("ka", "Georgian", QObject::tr("Georgian")) );
+ //: Language name kek
+ m_langList.append( new Language("kek", "Kekch\u00ed", QObject::tr("Kekch\u00ed", "kek")) );
+ // m_langList.append( new Language("ki", "Kikuyu", QObject::tr("Kikuyu")) );
+ // m_langList.append( new Language("kj", "Kuanyama", QObject::tr("Kuanyama")) );
+ // m_langList.append( new Language("kk", "Kazakh", QObject::tr("Kazakh")) );
+ // m_langList.append( new Language("kl", "Kalaallisut", QObject::tr("Kalaallisut")) );
+ // m_langList.append( new Language("km", "Khmer", QObject::tr("Khmer")) );
+ // m_langList.append( new Language("kn", "Kannada", QObject::tr("Kannada")) );
+ //: Language name ko
+ m_langList.append( new Language("ko", "Korean", QObject::tr("Korean")) );
+ // m_langList.append( new Language("ks", "Kashmiri", QObject::tr("Kashmiri")) );
+ //: Language name ku
+ m_langList.append( new Language("ku", "Kurdish", QObject::tr("Kurdish")) );
+ // m_langList.append( new Language("kv", "Komi", QObject::tr("Komi")) );
+ // m_langList.append( new Language("kw", "Cornish", QObject::tr("Cornish")) );
+ //: Language name ky
+ m_langList.append( new Language("ky", "Kirghiz", QObject::tr("Kirghiz")) );
+ //: Language name la
+ m_langList.append( new Language("la", "Latin", QObject::tr("Latin")) );
+ //: Language name lac
+ m_langList.append( new Language("lac", "Lacandon", QObject::tr("Lacandon")) );
+ // m_langList.append( new Language("lb", "Letzeburgesch", QObject::tr("Letzeburgesch")) );
+ //: Language name lmo
+ m_langList.append( new Language("lmo", "Lombard", QObject::tr("Lombard")) );
+ // m_langList.append( new Language("ln", "Lingala", QObject::tr("Lingala")) );
+ // m_langList.append( new Language("lo", "Lao", QObject::tr("Lao")) );
+ //: Language name lt
+ m_langList.append( new Language("lt", "Lithuanian", QObject::tr("Lithuanian")) );
+ //: Language name lv
+ m_langList.append( new Language("lv", "Latvian", QObject::tr("Latvian")) );
+ //: Language name mg
+ m_langList.append( new Language("mg", "Malagasy", QObject::tr("Malagasy")) );
+ // m_langList.append( new Language("mh", "Marshall", QObject::tr("Marshall")) );
+ //: Language name mi
+ m_langList.append( new Language("mi", "Maori", QObject::tr("Maori")) );
+ //: Language name mir
+ m_langList.append( new Language("mir", "Mixe, Isthmus", QObject::tr("Mixe, Isthmus")) );
+ //: Language name miz
+ m_langList.append( new Language("miz", "Mixtec, Coatzospan", QObject::tr("Mixtec, Coatzospan")) );
+ //: Language name mk
+ m_langList.append( new Language("mk", "Macedonian", QObject::tr("Macedonian")) );
+ //: Language name mks
+ m_langList.append( new Language("mks", "Mixtec, Silacayoapan", QObject::tr("Mixtec, Silacayoapan")) );
+ // m_langList.append( new Language("ml", "Malayalam", QObject::tr("Malayalam")) );
+ // m_langList.append( new Language("mn", "Mongolian", QObject::tr("Mongolian")) );
+ // m_langList.append( new Language("mo", "Moldavian", QObject::tr("Moldavian")) );
+ //: Language name mos
+ m_langList.append( new Language("mos", "More", QObject::tr("More")) );
+ // m_langList.append( new Language("mr", "Marathi", QObject::tr("Marathi")) );
+ //: Language name ms
+ m_langList.append( new Language("ms", "Malay", QObject::tr("Malay")) );
+ //: Language name mt
+ m_langList.append( new Language("mt", "Maltese", QObject::tr("Maltese")) );
+ //: Language name mul (meaning that the work has multiple languages)
+ m_langList.append( new Language("mul", "(Multiple languages)", QObject::tr("(Multiple languages)")) );
+ //: Language name mvc
+ m_langList.append( new Language("mvc", "Mam, Central", QObject::tr("Mam, Central")) );
+ //: Language name mvj
+ m_langList.append( new Language("mvj", "Mam, Todos Santos Cuchumat\u00e1n", QObject::tr("Mam, Todos Santos Cuchumat\u00e1n")) );
+ //: Language name mxq
+ m_langList.append( new Language("mxq", "Mixe, Juquila", QObject::tr("Mixe, Juquila")) );
+ //: Language name mxt
+ m_langList.append( new Language("mxt", "Mixtec, Jamiltepec", QObject::tr("Mixtec, Jamiltepec")) );
+ //: Language name my
+ m_langList.append( new Language("my", "Burmese", QObject::tr("Burmese")) );
+ // m_langList.append( new Language("na", "Nauru", QObject::tr("Nauru")) );
+ //: Language name nb
+ m_langList.append( new Language("nb", "Norwegian Bokm\u00e5l", QObject::tr("Norwegian Bokm\u00e5l")) );
+ //: Language name ncl
+ m_langList.append( new Language("ncl", "Nahuatl, Michoac\u00e1n", QObject::tr("Nahuatl, Michoac\u00e1n")) );
+ // m_langList.append( new Language("nd", "Ndebele, North", QObject::tr("Ndebele, North")) );
+ //: Language name nds
+ m_langList.append( new Language("nds", "Low German; Low Saxon", QObject::tr("Low German; Low Saxon")) );
+ //: Language name ne
+ m_langList.append( new Language("ne", "Nepali", QObject::tr("Nepali")) );
+ //: Language name ngu
+ m_langList.append( new Language("ngu", "Nahuatl, Guerrero", QObject::tr("Nahuatl, Guerrero")) );
+ //: Language name nhy
+ m_langList.append( new Language("nhy", "Nahuatl, Northern Oaxaca", QObject::tr("Nahuatl, Northern Oaxaca")) );
+ // m_langList.append( new Language("ng", "Ndonga", QObject::tr("Ndonga")) );
+ //: Language name nl
+ m_langList.append( new Language("nl", "Dutch", QObject::tr("Dutch")) );
+ //: Language name nn
+ m_langList.append( new Language("nn", "Norwegian Nynorsk", QObject::tr("Norwegian Nynorsk")) );
+ //: Language name no
+ m_langList.append( new Language("no", "Norwegian", QObject::tr("Norwegian")) );
+ // m_langList.append( new Language("nr", "Ndebele, South", QObject::tr("Ndebele, South")) );
+ // m_langList.append( new Language("nv", "Navajo", QObject::tr("Navajo")) );
+ // m_langList.append( new Language("ny", "Chichewa; Nyanja", QObject::tr("Chichewa; Nyanja")) );
+ // m_langList.append( new Language("oc", "Occitan (post 1500); Provençal", QObject::tr("Occitan (post 1500); Provençal")) );
+ // m_langList.append( new Language("om", "Oromo", QObject::tr("Oromo")) );
+ // m_langList.append( new Language("or", "Oriya", QObject::tr("Oriya")) );
+ // m_langList.append( new Language("os", "Ossetian; Ossetic", QObject::tr("Ossetian; Ossetic")) );
+ //: Language name otq
+ m_langList.append( new Language("otq", "Otomi, Quer\u00e9taro", QObject::tr("Otomi, Quer\u00e9taro")) );
+ // m_langList.append( new Language("pa", "Panjabi", QObject::tr("Panjabi")) );
+ //: Language name pap
+ m_langList.append( new Language("pap", "Papiamento", QObject::tr("Papiamento")) );
+ // m_langList.append( new Language("pi", "Pali", QObject::tr("Pali")) );
+ //: Language name ppk
+ m_langList.append( new Language("ppk", "Uma", QObject::tr("Uma")) );
+ //: Language name pl
+ m_langList.append( new Language("pl", "Polish", QObject::tr("Polish")) );
+ //: Language name pot
+ m_langList.append( new Language("pot", "Potawatomi", QObject::tr("Potawatomi")) );
+ //: Language name ppk
+ m_langList.append( new Language("ppk", "Uma", QObject::tr("Uma")) );
+ //: Language name prs
+ m_langList.append( new Language("prs", "Persian (Dari)", QObject::tr("Persian (Dari)")) );
+
+ // m_langList.append( new Language("ps", "Pushto", QObject::tr("Pushto")) );
+ //: Language name pt
+ m_langList.append( new Language("pt", "Portuguese", QObject::tr("Portuguese")) );
+ //: Language name pt_BR
+ m_langList.append( new Language("pt_BR", "Brasilian Portuguese", QObject::tr("Brasilian Portuguese")) );//added by ourself
+ // m_langList.append( new Language("qu", "Quechua", QObject::tr("Quechua")) );
+ //: Language name qut
+ m_langList.append( new Language("qut", "Quich\u00e9, West Central", QObject::tr("Quich\u00e9, West Central")) );
+ // m_langList.append( new Language("rm", "Raeto-Romance", QObject::tr("Raeto-Romance")) );
+ // m_langList.append( new Language("rn", "Rundi", QObject::tr("Rundi")) );
+ //: Language name ro
+ m_langList.append( new Language("ro", "Romanian", QObject::tr("Romanian")) );
+ //: Language name ru
+ m_langList.append( new Language("ru", "Russian", QObject::tr("Russian")) );
+ // m_langList.append( new Language("rw", "Kinyarwanda", QObject::tr("Kinyarwanda")) );
+ // m_langList.append( new Language("sa", "Sanskrit", QObject::tr("Sanskrit")) );
+ // m_langList.append( new Language("sc", "Sardinian", QObject::tr("Sardinian")) );
+ //: Language name sco
+ m_langList.append( new Language("sco", "Scots", QObject::tr("Scots")) );
+ // m_langList.append( new Language("sd", "Sindhi", QObject::tr("Sindhi")) );
+ // m_langList.append( new Language("se", "Northern Sami", QObject::tr("Northern Sami")) );
+ // m_langList.append( new Language("sg", "Sango", QObject::tr("Sango")) );
+ // m_langList.append( new Language("si", "Sinhalese", QObject::tr("Sinhalese")) );
+ //: Language name sk
+ m_langList.append( new Language("sk", "Slovak", QObject::tr("Slovak")) );
+ //: Language name sl
+ m_langList.append( new Language("sl", "Slovenian", QObject::tr("Slovenian")) );
+ // m_langList.append( new Language("sm", "Samoan", QObject::tr("Samoan")) );
+ // m_langList.append( new Language("sn", "Shona", QObject::tr("Shona")) );
+ //: Language name so
+ m_langList.append( new Language("so", "Somali", QObject::tr("Somali")) );
+ //: Language name sq
+ m_langList.append( new Language("sq", "Albanian", QObject::tr("Albanian")) );
+ // m_langList.append( new Language("sr", "Serbian", QObject::tr("Serbian")) );
+ //: Language name srn
+ m_langList.append( new Language("srn", "Sranan", QObject::tr("Sranan")) );
+ // m_langList.append( new Language("ss", "Swati", QObject::tr("Swati")) );
+ // m_langList.append( new Language("st", "Sotho, Southern", QObject::tr("Sotho, Southern")) );
+ // m_langList.append( new Language("su", "Sundanese", QObject::tr("Sundanese")) );
+ //: Language name sv
+ m_langList.append( new Language("sv", "Swedish", QObject::tr("Swedish")) );
+ //: Language name sw
+ m_langList.append( new Language("sw", "Swahili", QObject::tr("Swahili")) );
+ //: Language name syr
+ m_langList.append( new Language("syr", "Syriac", QObject::tr("Syriac")) );
+ //: Language name ta
+ m_langList.append( new Language("ta", "Tamil", QObject::tr("Tamil")) );
+ // m_langList.append( new Language("te", "Telugu", QObject::tr("Telugu")) );
+ // m_langList.append( new Language("tg", "Tajik", QObject::tr("Tajik")) );
+ //: Language name th
+ m_langList.append( new Language("th", "Thai", QObject::tr("Thai")) );
+ // m_langList.append( new Language("tk", "Turkmen", QObject::tr("Turkmen")) );
+ //: Language name tl
+ m_langList.append( new Language("tl", "Tagalog", QObject::tr("Tagalog")) );
+ //: Language name tlh
+ m_langList.append( new Language("tlh", "Klingon", QObject::tr("Klingon")) );
+ //: Language name tn
+ m_langList.append( new Language("tn", "Tswana", QObject::tr("Tswana")) );
+ //: Language name tr
+ m_langList.append( new Language("tr", "Turkish", QObject::tr("Turkish")) );
+ // m_langList.append( new Language("ts", "Tsonga", QObject::tr("Tsonga")) );
+ // m_langList.append( new Language("tt", "Tatar", QObject::tr("Tatar")) );
+ //: Language name ttc
+ m_langList.append( new Language("ttc", "Tektiteko", QObject::tr("Tektiteko")) );
+ // m_langList.append( new Language("tw", "Twi", QObject::tr("Twi")) );
+ //: Language name ty
+ m_langList.append( new Language("ty", "Tahitian", QObject::tr("Tahitian")) );
+ //: Language name tzz
+ m_langList.append( new Language("tzz", "Tzotzil, Zinacant\u00e1n", QObject::tr("Tzotzil, Zinacant\u00e1n")) );
+ // m_langList.append( new Language("ug", "Uighur", QObject::tr("Uighur")) );
+ //: Language name uk
+ m_langList.append( new Language("uk", "Ukrainian", QObject::tr("Ukrainian")) );
+ // m_langList.append( new Language("ur", "Urdu", QObject::tr("Urdu")) );
+ //: Language name ury
+ m_langList.append( new Language("ury", "Orya", QObject::tr("Orya")) );
+ //: Language name usp
+ m_langList.append( new Language("usp", "Uspanteco", QObject::tr("Uspanteco")) );
+ // m_langList.append( new Language("uz", "Uzbek", QObject::tr("Uzbek")) );
+ //: Language name vi
+ m_langList.append( new Language("vi", "Vietnamese", QObject::tr("Vietnamese")) );
+ // m_langList.append( new Language("vo", "Volapük", QObject::tr("Volapük")) );
+ // m_langList.append( new Language("wo", "Wolof", QObject::tr("Wolof")) );
+ //: Language name xh
+ m_langList.append( new Language("xh", "Xhosa", QObject::tr("Xhosa")) );
+ //: Language name xtd
+ m_langList.append( new Language("xtd", "Mixtec, Diuxi-Tilantongo", QObject::tr("Mixtec, Diuxi-Tilantongo")) );
+ //: Language name yi
+ m_langList.append( new Language("yi", "Yiddish", QObject::tr("Yiddish")) );
+ //: Language name yo
+ m_langList.append( new Language("yo", "Yoruba", QObject::tr("Yoryba")) );
+ // m_langList.append( new Language("za", "Zhuang", QObject::tr("Zhuang")) );
+ //: Language name zab
+ m_langList.append( new Language("zab", "Zapotec, San Juan Guelav\u00eda", QObject::tr("Zapotec, San Juan Guelav\u00eda")) );
+ //: Language name zaw
+ m_langList.append( new Language("zaw", "Zapotec, Mitla", QObject::tr("Zapotec, Mitla")) );
+ //: Language name zh
+ m_langList.append( new Language("zh", "Chinese", QObject::tr("Chinese")) );
+ //: Language name zpo
+ m_langList.append( new Language("zpo", "Zapotec, Amatl\u00e1n", QObject::tr("Zapotec, Amatl\u00e1n")) );
+ //: Language name zpq
+ m_langList.append( new Language("zpq", "Zapotec, Zoogocho", QObject::tr("Zapotec, Zoogocho")) );
+ //: Language name zpu
+ m_langList.append( new Language("zpu", "Zapotec, Yal\u00e1lag", QObject::tr("Zapotec, Yal\u00e1lag")) );
+ //: Language name zpv
+ m_langList.append( new Language("zpv", "Zapotec, Chichicapan", QObject::tr("Zapotec, Chichicapan")) );
+ //: Language name zsr
+ m_langList.append( new Language("zsr", "Zapotec, Southern Rincon", QObject::tr("Zapotec, Southern Rincon")) );
+ //: Language name ztq
+ m_langList.append( new Language("ztq", "Zapotec, Quioquitani-Quier\u00ed", QObject::tr("Zapotec, Quioquitani-Quier\u00ed")) );
+ //: Language name zty
+ m_langList.append( new Language("zty", "Zapotec, Yatee", QObject::tr("Zapotec, Yatee")) );
+ //: Language name zu
+ m_langList.append( new Language("zu", "Zulu", QObject::tr("Zulu")) );
+
+ foreach (Language* lang, m_langList) {
+ m_langMap.insert( lang->abbrev(), lang);
+ }
+}
diff --git a/src/backend/managers/clanguagemgr.h b/src/backend/managers/clanguagemgr.h
new file mode 100644
index 0000000..f421e62
--- /dev/null
+++ b/src/backend/managers/clanguagemgr.h
@@ -0,0 +1,151 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CLANGUAGEMGR_H
+#define CLANGUAGEMGR_H
+
+//Qt includes
+#include <QString>
+#include <QStringList>
+#include <QList>
+#include <QHash>
+
+/** Manages the languages of BibleTime and provides functions to work with them.
+ * @author The BibleTime team
+ */
+
+class CLanguageMgr {
+
+public:
+ /** Language container.
+ * This class (Language) contains the information about the chosen language.
+ */
+ class Language {
+ public:
+ /** Default constructor of a language object.
+ * Uses the abbreviation parameter to lookup the
+ * language name and to be able to return the name, flag etc.
+ * Possible values for abbrev are de, en, fr, it etc.
+ */
+ Language();
+ /** Copy constructor.
+ */
+ Language(const Language&);
+ /** Constructor which takes all necessary data.
+ */
+ Language(const QString& abbrev, const QString& englishName, const QString& translatedName, const QStringList& altAbbrevs = QStringList());
+ /** Destructor.
+ */
+ ~Language();
+ /** Returns the abbreviation.
+ * @return The abbreviation of the chosen language.
+ */
+ inline const QString& abbrev() const {
+ if (m_abbrev.isEmpty() && m_altAbbrevs.count()) { //no standard abbrev but alternative ones
+ return m_altAbbrevs.first();
+ }
+ return m_abbrev;
+ }
+ /** Returns the translated name.
+ * @return The translated name of the language.
+ */
+ inline const QString& translatedName() const {
+ return m_translatedName;
+ }
+ /** The english name of the language.
+ * @return The english name of the chosen language.
+ */
+ inline const QString& name() const {
+ return m_englishName;
+ }
+ /** The alternative abbreviations which are avalable for this language.
+ * @return The List of alternate abbreviations
+ */
+ inline const QStringList alternativeAbbrevs() const {
+ return m_altAbbrevs;
+ }
+ /**
+ * Returns true if this language object is valid, i.e. has an abbrev and name.
+ * @return True if the data is valid for this language.
+ */
+ inline bool isValid() const {
+ return (!abbrev().isEmpty() && !name().isEmpty());
+ }
+
+ private:
+ QString m_abbrev;
+ QString m_englishName;
+ QString m_translatedName;
+ QStringList m_altAbbrevs;
+ };
+
+ typedef QList<Language*> LanguageList;
+ typedef QHash<QString, const Language*> LangMap;
+ typedef QHash<QString, const Language*>::const_iterator LangMapIterator;
+
+ /** Constructor.
+ */
+ CLanguageMgr();
+ /** Destructor
+ */
+ virtual ~CLanguageMgr();
+ /**
+ * Returns the standard languages available as standard. Does nothing for Sword.
+ * @return A LangMap map which contains all known languages
+ */
+ inline const CLanguageMgr::LangMap* languages() const {
+ return &m_langMap;
+ }
+ /**
+ * Returns the languages which are available. The languages cover all available modules, but nothing more.
+ * @return A map of all languages with modules available for them
+ */
+ const CLanguageMgr::LangMap& availableLanguages();
+ /** Language for abbreviation.
+ * @param abbrev The language abbreviation
+ * @return Pointer to a language for the given string abbreviation.
+ */
+ const CLanguageMgr::Language* languageForAbbrev( const QString& abbrev ) const;
+ /** Language for english name.
+ * @param abbrev The english language name.
+ * @return Pointer to a language for the given name
+ */
+ const CLanguageMgr::Language* languageForName( const QString& language ) const;
+ /** Language for translated language name.
+ * @param abbrev The translated language name
+ * @return Pointer to a language for the given translated language name
+ */
+ const CLanguageMgr::Language* languageForTranslatedName( const QString& language ) const;
+ /** Default language so we don't return NULL pointers.
+ * @return Pointer to the default language
+ */
+ inline const CLanguageMgr::Language* defaultLanguage() const {
+ return &m_defaultLanguage;
+ }
+
+private:
+ void init();
+ inline const QStringList makeStringList(const QString& abbrevs) {
+ return abbrevs.split( ";", QString::KeepEmptyParts, Qt::CaseSensitive );
+ }
+
+ Language m_defaultLanguage;
+ mutable LanguageList m_langList;
+ mutable LangMap m_langMap;
+ mutable LanguageList m_cleanupLangPtrs;
+
+ struct ModuleCache {
+ unsigned int moduleCount;
+ LangMap availableLanguages;
+ }
+ m_availableModulesCache;
+};
+
+#endif
+
diff --git a/src/backend/managers/creferencemanager.cpp b/src/backend/managers/creferencemanager.cpp
new file mode 100644
index 0000000..adae180
--- /dev/null
+++ b/src/backend/managers/creferencemanager.cpp
@@ -0,0 +1,422 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "creferencemanager.h"
+#include "backend/keys/cswordversekey.h"
+
+#include "backend/config/cbtconfig.h"
+#include "util/cpointers.h"
+
+//QT
+#include <QRegExp>
+
+//stl
+#include <algorithm> // STL algorithms class library
+
+/** Returns a hyperlink used to be imbedded in the display windows. At the moment the format is sword://module/key */
+const QString CReferenceManager::encodeHyperlink( const QString moduleName, const QString key, const CReferenceManager::Type type) {
+ QString ret = QString::null;
+
+ switch (type) {
+
+ case Bible:
+ ret = QString("sword://Bible/");
+ break;
+ case Commentary:
+ ret = QString("sword://Commentary/");
+ break;
+ case Lexicon:
+ ret = QString("sword://Lexicon/");
+ break;
+ case GenericBook:
+ ret = QString("sword://Book/");
+ break;
+ case MorphHebrew:
+ ret = QString("morph://Hebrew/");
+ break;
+ case MorphGreek:
+ ret = QString("morph://Greek/");
+ break;
+ case StrongsHebrew:
+ ret = QString("strongs://Hebrew/");
+ break;
+ case StrongsGreek:
+ ret = QString("strongs://Greek/");
+ break;
+ default:
+ break;
+ }
+
+ if (!moduleName.isEmpty()) {
+ ret.append( moduleName ).append('/');
+ }
+ else { //if module is empty use fallback module
+ ret.append( preferredModule(type) ).append('/');
+ }
+
+ if (type == GenericBook) {
+ const QString s = (!key.isEmpty() ? key : QString::null);
+ QString newKey = QString::null;
+ //replace all / of the key (e.g. of a CSwordTreeKey) with
+ // the escape sequence \/ so we know it's a link internal divider (e.g. of CSwordTreeKey)!
+
+ QChar c;
+
+ for(int i = 0; i < s.length(); ++i) {
+ c = s.at(i);
+
+ if (c == '/') {
+ newKey.append("\\/");
+ }
+ else {
+ newKey.append(c);
+ }
+ }
+
+ ret.append( newKey );
+ }
+ else { //slashes do not appear in verses and dictionary entries
+
+ switch (type) {
+
+ case Bible: //bibles or commentary keys need parsing
+
+ case Commentary: {
+/* CSwordModuleInfo* mod = CPointers::backend()->findModuleByName(moduleName);
+
+ ParseOptions options;
+ options.refDestinationModule = mod->name();
+ options.refBase =
+ options.sourceLanguage = mod->module()->Lang();
+ options.destinationLanguage = "en";
+
+ ret.append( parseVerseReference(key, options) ); //we add the english key, so drag and drop will work in all cases*/
+ ret.append(key);
+ break;
+ }
+
+ default:
+ ret.append( key ); //use the standard key, no parsing required
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/** Decodes the given hyperlink to module and key. */
+bool CReferenceManager::decodeHyperlink( const QString& hyperlink, QString& module, QString& key, CReferenceManager::Type& type ) {
+ /**
+ * We have to decide between three types of URLS: sword://Type/Module/Key, morph://Testament/key and strongs://Testament/Key
+ */
+ module = QString::null;
+ key = QString::null;
+
+ type = Unknown; //not yet known
+ QString ref = hyperlink;
+ //remove the trailing slash
+
+ if (ref.right(1)=="/" && ref.right(2) != "\\/") //trailing slash, but not escaped
+ ref = ref.left(ref.length()-1);
+
+ //find out which type we have by looking at the beginning (protocoll section of URL)
+ if (ref.left(8).toLower() == "sword://") { //Bible, Commentary or Lexicon
+ ref = ref.mid(8);
+
+ if (ref.left(5).toLower() == "bible") { //a bible hyperlink
+ type = CReferenceManager::Bible;
+ ref = ref.mid(6); //inclusive trailing slash
+ }
+ else if (ref.left(10).toLower() == "commentary") { // a Commentary hyperlink
+ type = CReferenceManager::Commentary;
+ ref = ref.mid(11); //inclusive trailing slash
+ }
+ else if (ref.left(7).toLower() == "lexicon") { // a Lexicon hyperlink
+ type = CReferenceManager::Lexicon;
+ ref = ref.mid(8); //inclusive trailing slash
+ }
+ else if (ref.left(4).toLower() == "book") { // a Book hyperlink
+ type = CReferenceManager::GenericBook;
+ ref = ref.mid(5); //inclusive trailing slash
+ }
+
+ // string up to next slash is the modulename
+ if (ref.at(0) != '/' ) { //we have a module given
+
+ while (true) {
+ const int pos = ref.indexOf("/");
+
+ if ((pos>0) && ref.at(pos-1) != '\\') { //found a slash which is not escaped
+ module = ref.mid(0,pos);
+ ref = ref.mid(pos+1);
+ break;
+ }
+ else if (pos == -1) {
+ break;
+ }
+ }
+
+ // the rest is the key
+ key = ref;
+ }
+ else {
+ key = ref.mid(1);
+ }
+
+ //the key may be an osis key like "NASBLex:Moses", which sets the module, too
+ // const int modPos = key.find(":");
+ // if (modPos != -1 && key.at(modPos-1).isLetter() && key.at(modPos+1).isLetter()) {
+ // module = key.left(modPos);
+ // key = key.mid(modPos+1);
+ //
+ // qWarning("found the module name %s with key %s", module.latin1(), key.latin1());
+ // }
+
+ //replace \/ escapes with /
+ key.replace(QRegExp("\\\\/"), "/");
+ }
+ else if (ref.left(8).toLower() == "morph://" || ref.left(10).toLower() == "strongs://") { //strongs or morph URL have the same format
+ enum PreType {IsMorph, IsStrongs};
+ PreType preType = IsMorph;
+
+ if (ref.left(8).toLower() == "morph://") { //morph code hyperlink
+ ref = ref.mid(8);
+ preType = IsMorph;
+ }
+ else if (ref.left(10).toLower() == "strongs://") {
+ ref = ref.mid(10);
+ preType = IsStrongs;
+ }
+
+ //part up to next slash is the language
+ const int pos = ref.indexOf("/");
+
+ if (pos>0) { //found
+ const QString language = ref.mid(0,pos);
+
+ if (language.toLower() == "hebrew") {
+ switch (preType) {
+
+ case IsMorph:
+ type = CReferenceManager::MorphHebrew;
+ break;
+
+ case IsStrongs:
+ type = CReferenceManager::StrongsHebrew;
+ break;
+ }
+ }
+ else if (language.toLower() == "greek") {
+ switch (preType) {
+
+ case IsMorph:
+ type = CReferenceManager::MorphGreek;
+ break;
+
+ case IsStrongs:
+ type = CReferenceManager::StrongsGreek;
+ break;
+ }
+ }
+
+ ref = ref.mid(pos+1);
+ key = ref; //the remaining part is the key
+
+ module = preferredModule(type);
+ }
+ }
+
+ if (key.isEmpty() && module.isEmpty())
+ return false;
+
+ return true;
+}
+
+const QString CReferenceManager::encodeReference(const QString &module, const QString &reference) {
+ //return QString("(%1)%2").arg(module).arg(reference);
+ return QString("(").append(module).append(")").append(reference);
+}
+
+void CReferenceManager::decodeReference(QString &dragreference, QString &module, QString &reference) {
+ const int pos = dragreference.indexOf(")");
+ const QString fallbackModule = dragreference.mid( 1, pos - 1);
+ dragreference = dragreference.mid(pos+1);
+
+ module = fallbackModule;
+ reference = dragreference;
+}
+
+/** Returns true if the parameter is a hyperlink. */
+bool CReferenceManager::isHyperlink( const QString& hyperlink ) {
+ return ( hyperlink.left(8) == "sword://")
+ || (hyperlink.left(10) == "strongs://")
+ || (hyperlink.left(8) == "morph://");
+}
+
+/** Returns the preferred module name for the given type. */
+const QString CReferenceManager::preferredModule( const CReferenceManager::Type type ) {
+ QString moduleName = QString::null;
+ CSwordModuleInfo* module = 0;
+
+ switch (type) {
+
+ case CReferenceManager::Bible:
+
+ module = CBTConfig::get
+ ( CBTConfig::standardBible );
+
+ break;
+
+ case CReferenceManager::Commentary:
+ module = CBTConfig::get
+ ( CBTConfig::standardCommentary );
+
+ break;
+
+ case CReferenceManager::Lexicon:
+ module = CBTConfig::get
+ ( CBTConfig::standardLexicon );
+
+ break;
+
+ case CReferenceManager::StrongsHebrew:
+ module = CBTConfig::get
+ ( CBTConfig::standardHebrewStrongsLexicon );
+
+ break;
+
+ case CReferenceManager::StrongsGreek:
+ module = CBTConfig::get
+ ( CBTConfig::standardGreekStrongsLexicon );
+
+ break;
+
+ case CReferenceManager::MorphHebrew:
+ module = CBTConfig::get
+ ( CBTConfig::standardHebrewMorphLexicon );
+
+ break;
+
+ case CReferenceManager::MorphGreek:
+ module = CBTConfig::get
+ ( CBTConfig::standardGreekMorphLexicon );
+
+ break;
+
+ default:
+ module = 0;
+
+ break;
+ }
+
+ return module ? module->name() : QString::null;
+}
+
+/** No descriptions */
+CReferenceManager::Type CReferenceManager::typeFromModule( const CSwordModuleInfo::ModuleType type) {
+ switch (type) {
+
+ case CSwordModuleInfo::Bible:
+ return CReferenceManager::Bible;
+
+ case CSwordModuleInfo::Commentary:
+ return CReferenceManager::Commentary;
+
+ case CSwordModuleInfo::Lexicon:
+ return CReferenceManager::Lexicon;
+
+ case CSwordModuleInfo::GenericBook:
+ return CReferenceManager::GenericBook;
+
+ default:
+ return CReferenceManager::Unknown;
+ }
+}
+
+/** Parses the given verse references using the given language and the module.*/
+const QString CReferenceManager::parseVerseReference( const QString& ref, const CReferenceManager::ParseOptions& options) {
+
+ CSwordModuleInfo* const mod = CPointers::backend()->findModuleByName(options.refDestinationModule);
+ //Q_ASSERT(mod); tested later
+
+ if (!mod) {
+ //parsing of non-verse based references is not supported
+ return ref;
+ }
+
+ if ((mod->type() != CSwordModuleInfo::Bible) && (mod->type() != CSwordModuleInfo::Commentary)) {
+ qDebug("CReferenceManager: Only verse based modules are supported as ref destination module");
+ return QString::null;
+ }
+
+ QString sourceLanguage = options.sourceLanguage;
+ QString destinationLanguage = options.destinationLanguage;
+
+ sword::StringList locales = sword::LocaleMgr::getSystemLocaleMgr()->getAvailableLocales();
+ if (/*options.sourceLanguage == "en" ||*/ std::find(locales.begin(), locales.end(), sourceLanguage.toUtf8().constData()) == locales.end()) { //sourceLanguage not available
+ sourceLanguage = "en_US";
+ }
+
+ if (/*options.destinationLanguage == "en" ||*/ std::find(locales.begin(), locales.end(), sourceLanguage.toUtf8().constData()) == locales.end()) { //destination not available
+ destinationLanguage = "en_US";
+ }
+
+ QString ret;
+ QStringList refList = ref.split(";");
+
+ CSwordVerseKey baseKey(0);
+ baseKey.setLocale( sourceLanguage.toUtf8().constData() );
+ baseKey.key( options.refBase ); //probably in the sourceLanguage
+ baseKey.setLocale( "en_US" ); //english works in all environments as base
+
+// CSwordVerseKey dummy(0);
+ //HACK: We have to workaround a Sword bug, we have to set the default locale to the same as the sourceLanguage !
+ const QString oldLocaleName = CPointers::backend()->booknameLanguage();
+ CPointers::backend()->booknameLanguage(sourceLanguage);
+
+ sword::VerseKey dummy;
+ dummy.setLocale( sourceLanguage.toUtf8().constData() );
+ Q_ASSERT( !strcmp(dummy.getLocale(), sourceLanguage.toUtf8().constData()) );
+
+// qDebug("Parsing '%s' in '%s' using '%s' as base, source lang '%s', dest lang '%s'", ref.latin1(), options.refDestinationModule.latin1(), baseKey.key().latin1(), sourceLanguage.latin1(), destinationLanguage.latin1());
+
+ for (QStringList::iterator it = refList.begin(); it != refList.end(); it++) {
+ //The listkey may contain more than one item, because a ref lik "Gen 1:3,5" is parsed into two single refs
+ sword::ListKey lk = dummy.ParseVerseList((*it).toUtf8().constData(), baseKey.key().toUtf8().constData(), true);
+ Q_ASSERT(!dummy.Error());
+
+ //Q_ASSERT(lk.Count());
+ if (!lk.Count()) {
+ ret.append( *it ); //don't change the original
+ continue;
+ }
+
+ for (int i = 0; i < lk.Count(); ++i) {
+ if (dynamic_cast<sword::VerseKey*>(lk.getElement(i))) { // a range
+ sword::VerseKey* k = dynamic_cast<sword::VerseKey*>(lk.getElement(i));
+ Q_ASSERT(k);
+ k->setLocale( destinationLanguage.toUtf8().constData() );
+
+ ret.append( QString::fromUtf8(k->getRangeText()) ).append("; ");
+ }
+ else { // a single ref
+ sword::VerseKey vk;
+ vk.setLocale( sourceLanguage.toUtf8().constData() );
+ vk = lk.getElement(i)->getText();
+ vk.setLocale( destinationLanguage.toUtf8().constData() );
+
+ ret.append( QString::fromUtf8(vk.getText()) ).append("; ");
+ }
+ }
+
+ }
+
+ CPointers::backend()->booknameLanguage(oldLocaleName);
+ return ret;
+}
diff --git a/src/backend/managers/creferencemanager.h b/src/backend/managers/creferencemanager.h
new file mode 100644
index 0000000..19baae7
--- /dev/null
+++ b/src/backend/managers/creferencemanager.h
@@ -0,0 +1,110 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CREFERENCEMANAGER_H
+#define CREFERENCEMANAGER_H
+
+#include "backend/drivers/cswordmoduleinfo.h"
+
+//Qt includes
+#include <QString>
+
+/** Contains static functions to work with references used for Drag & Drop and for hyperlinks used in our
+ * rendered HTML code.
+ * @author The BibleTime team
+ */
+
+class CReferenceManager {
+
+public:
+ enum Type {
+ Bible, /**< Bibles */
+ Commentary, /**< Commentary */
+ Lexicon, /**< Lexicon */
+ GenericBook, /**< Generic Book */
+ MorphHebrew, /**< Module for hebrew morphology*/
+ MorphGreek, /**< Module for greek morphology */
+ StrongsHebrew, /**< Module for hebrew strongs */
+ StrongsGreek, /**< Module for greek strongs */
+ Unknown /**< Unknown */
+ };
+
+ /** Turn a hyperlink into module, key and type.
+ * Decodes the given hyperlink into module, key and type.
+ * @param hyperlink The hyperlink to decode
+ * @param module The string which will contain the module name after decoding
+ * @param key The string which will contain the key after decoding
+ * @param type The type param will contain the reference type after decoding
+ */
+ static bool decodeHyperlink( const QString& hyperlink, QString& module, QString& key, Type& type);
+ /**
+ * Returns a hyperlink used to be embedded in the display windows.
+ * At the moment the format is sword://module/key
+ * @param module The module which is used to encode the hyperlink
+ * @param key The key which is used to encode the hyperlink
+ * @param type The type which is used to encode the hyperlink
+ * @return The encoded hyperlink
+ */
+ static const QString encodeHyperlink( const QString module, const QString key, const Type type);
+ /**
+ * Puts a module Name and a Reference together in the 'draggable' form
+ * (module)reference
+ * @param module The name of the module
+ * @param reference The key reference as text
+ * @return The encoded reference using module and reference
+ * @author Martin Gruner
+ */
+ static const QString encodeReference(const QString &module, const QString &reference);
+ /**
+ * decodes a 'draggable' reference into a modulename and a reference
+ * @author Martin Gruner
+ */
+ static void decodeReference(QString &dragreference, QString &module, QString &reference);
+ /**
+ * Returns true if the parameter is a hyperlink.
+ * @param hyperlink The string which is tested
+ * @return True if the passed string is a hyperlink
+ */
+ static bool isHyperlink( const QString& hyperlink );
+ /**
+ * Returns the preferred module name for the given type.
+ * @param type The type which is used to find the module
+ * @return The default module name for the passed type
+ */
+ static const QString preferredModule( const Type type );
+ /**
+ * Returns the type of the passed module type
+ * @param type The CSwordModuleInfo module typpe
+ * @return The ReferenceManager type
+ */
+ static CReferenceManager::Type typeFromModule( const CSwordModuleInfo::ModuleType type );
+
+
+ struct ParseOptions {
+ QString refDestinationModule;
+ QString refBase; /* only valid for verse based destination modules*/
+ QString sourceLanguage; /* only valid for verse based destination modules*/
+ QString destinationLanguage; /* only valid for verse based destination modules*/
+
+ ParseOptions() {
+ destinationLanguage = "en";
+ };
+ };
+
+ /** Parses the given verse references using the given language and the module.
+ * @param moduleName The name of the module to use. Required for the language checking before parsing the key.
+ * @param ref The verse reference.
+ * @param lang The language of the verse reference
+ * @param newLang The language of the reference, which will be returned. For example: If BibleTime using an english environment parses a spanish ref (lang=es) the returned ref should be in english (newLang=en), because his english standard module only understands en.
+ */
+ static const QString parseVerseReference( const QString& ref, const ParseOptions& options);
+};
+
+#endif
+
diff --git a/src/backend/managers/cswordbackend.cpp b/src/backend/managers/cswordbackend.cpp
new file mode 100644
index 0000000..0afe467
--- /dev/null
+++ b/src/backend/managers/cswordbackend.cpp
@@ -0,0 +1,555 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cswordbackend.h"
+
+#include "backend/rendering/centrydisplay.h"
+#include "backend/rendering/cbookdisplay.h"
+#include "backend/rendering/cchapterdisplay.h"
+#include "backend/drivers/cswordbiblemoduleinfo.h"
+#include "backend/drivers/cswordcommentarymoduleinfo.h"
+#include "backend/drivers/cswordlexiconmoduleinfo.h"
+#include "backend/drivers/cswordbookmoduleinfo.h"
+#include "backend/filters/bt_thmlhtml.h"
+#include "backend/filters/bt_thmlplain.h"
+#include "backend/filters/bt_osishtml.h"
+#include "backend/filters/bt_gbfhtml.h"
+#include "backend/filters/bt_plainhtml.h"
+#include "backend/filters/osismorphsegmentation.h"
+
+#include "backend/config/cbtconfig.h"
+
+#include "util/directoryutil.h"
+
+#include <dirent.h>
+
+//Qt
+#include <QString>
+#include <QDir>
+#include <QFileInfo>
+#include <QSet>
+#include <QDebug>
+
+//Sword
+#include <swdisp.h>
+#include <swfiltermgr.h>
+#include <encfiltmgr.h>
+#include <rtfhtml.h>
+#include <filemgr.h>
+#include <utilstr.h>
+#include <swfilter.h>
+
+using namespace Filters;
+using namespace Rendering;
+
+CSwordBackend::CSwordBackend()
+ : sword::SWMgr(0, 0, false, new sword::EncodingFilterMgr( sword::ENC_UTF8 ), true)
+{
+ m_filters.gbf = new BT_GBFHTML();
+ m_filters.plain = new BT_PLAINHTML();
+ m_filters.thml = new BT_ThMLHTML();
+ m_filters.osis = new BT_OSISHTML();
+
+ m_displays.entry = new CEntryDisplay();
+ m_displays.chapter = new CChapterDisplay();
+ m_displays.book = new CBookDisplay();
+
+ filterInit();
+}
+
+CSwordBackend::CSwordBackend(const QString& path, const bool augmentHome)
+ : sword::SWMgr(!path.isEmpty() ? path.toLocal8Bit().constData() : 0, false, new sword::EncodingFilterMgr( sword::ENC_UTF8 ), false, augmentHome) // don't allow module renaming, because we load from a path
+{
+ m_filters.gbf = new BT_GBFHTML();
+ m_filters.plain = new BT_PLAINHTML();
+ m_filters.thml = new BT_ThMLHTML();
+ m_filters.osis = new BT_OSISHTML();
+
+ m_displays.entry = new CEntryDisplay();
+ m_displays.chapter = new CChapterDisplay();
+ m_displays.book = new CBookDisplay();
+
+ filterInit();
+}
+
+CSwordBackend::~CSwordBackend() {
+ shutdownModules();
+
+ delete m_filters.gbf;
+ delete m_filters.plain;
+ delete m_filters.thml;
+ delete m_filters.osis;
+
+ delete m_displays.book;
+ delete m_displays.chapter;
+ delete m_displays.entry;
+}
+
+void CSwordBackend::filterInit() {
+ //HACK: replace Sword's OSISMorphSegmentation filter, seems to be buggy, ours works
+ if (sword::SWOptionFilter* filter = optionFilters["OSISMorphSegmentation"])
+ {
+ cleanupFilters.remove(filter);
+ optionFilters.erase("OSISMorphSegmentation");
+ delete filter;
+ }
+ sword::SWOptionFilter* tmpFilter = new OSISMorphSegmentation();
+ optionFilters.insert(sword::OptionFilterMap::value_type("OSISMorphSegmentation", tmpFilter));
+ cleanupFilters.push_back(tmpFilter);
+
+ //HACK: replace Sword's ThML strip filter with our own version
+ //remove this hack as soon as Sword is fixed
+ cleanupFilters.remove(thmlplain);
+ delete thmlplain;
+ thmlplain = new BT_ThMLPlain();
+ cleanupFilters.push_back(thmlplain);
+}
+
+QList<CSwordModuleInfo*> CSwordBackend::takeModulesFromList(QStringList names)
+{
+ int numberOfRemoved = 0;
+ QList<CSwordModuleInfo*> list;
+ foreach(QString name, names) {
+ CSwordModuleInfo* mInfo = findModuleByName(name);
+ if (mInfo) {
+ m_moduleList.removeAll(mInfo);
+ ++numberOfRemoved;
+ list.append(mInfo);
+ }
+ }
+ if (numberOfRemoved > 0)
+ emit sigSwordSetupChanged(RemovedModules);
+ return list;
+}
+
+/** Initializes the Sword modules. */
+CSwordBackend::LoadError CSwordBackend::initModules(SetupChangedReason reason) {
+ // qWarning("globalSwordConfigPath is %s", globalConfPath);
+ LoadError ret = NoError;
+
+ shutdownModules(); //remove previous modules
+ m_moduleList.clear();
+
+ sword::ModMap::iterator end = Modules.end();
+ ret = LoadError( Load() );
+
+ for (sword::ModMap::iterator it = Modules.begin(); it != end; it++) {
+ sword::SWModule* const curMod = (*it).second;
+ CSwordModuleInfo* newModule = 0;
+
+ if (!strcmp(curMod->Type(), "Biblical Texts")) {
+ newModule = new CSwordBibleModuleInfo(curMod, this);
+ newModule->module()->Disp(m_displays.chapter);
+ }
+ else if (!strcmp(curMod->Type(), "Commentaries")) {
+ newModule = new CSwordCommentaryModuleInfo(curMod, this);
+ newModule->module()->Disp(m_displays.entry);
+ }
+ else if (!strcmp(curMod->Type(), "Lexicons / Dictionaries")) {
+ newModule = new CSwordLexiconModuleInfo(curMod, this);
+ newModule->module()->Disp(m_displays.entry);
+ }
+ else if (!strcmp(curMod->Type(), "Generic Books")) {
+ newModule = new CSwordBookModuleInfo(curMod, this);
+ newModule->module()->Disp(m_displays.book);
+ }
+
+ if (newModule) {
+ //Append the new modules to our list, but only if it's supported
+ //The constructor of CSwordModuleInfo prints a warning on stdout
+ if (!newModule->hasVersion() || (newModule->minimumSwordVersion() <= sword::SWVersion::currentVersion)) {
+ m_moduleList.append( newModule );
+ }
+ else
+ {
+ delete newModule;
+ }
+ }
+ }
+
+ QList<CSwordModuleInfo*>::iterator end_it = m_moduleList.end();
+
+ foreach (CSwordModuleInfo* mod, m_moduleList) {
+ m_moduleDescriptionMap.insert( mod->config(CSwordModuleInfo::Description), mod->name() );
+ //unlock modules if keys are present
+ if ( mod->isEncrypted() ) {
+ const QString unlockKey = CBTConfig::getModuleEncryptionKey( mod->name() );
+ if (!unlockKey.isNull()) {
+ setCipherKey( mod->name().toUtf8().constData(), unlockKey.toUtf8().constData() );
+ }
+ }
+ }
+
+ emit sigSwordSetupChanged(reason);
+ return ret;
+}
+
+void CSwordBackend::AddRenderFilters(sword::SWModule *module, sword::ConfigEntMap &section) {
+ sword::SWBuf moduleDriver;
+ sword::SWBuf sourceformat;
+ sword::ConfigEntMap::iterator entry;
+ bool noDriver = true;
+
+ sourceformat = ((entry = section.find("SourceType")) != section.end()) ? (*entry).second : (sword::SWBuf) "";
+ moduleDriver = ((entry = section.find("ModDrv")) != section.end()) ? (*entry).second : (sword::SWBuf) "";
+
+ if (sourceformat == "GBF") {
+ module->AddRenderFilter(m_filters.gbf);
+ noDriver = false;
+ }
+ else if (sourceformat == "PLAIN") {
+ module->AddRenderFilter(m_filters.plain);
+ noDriver = false;
+ }
+ else if (sourceformat == "ThML") {
+ module->AddRenderFilter(m_filters.thml);
+ noDriver = false;
+ }
+ else if (sourceformat == "OSIS") {
+ module->AddRenderFilter(m_filters.osis);
+ noDriver = false;
+ }
+
+ if (noDriver) { //no driver found
+ if ( (moduleDriver == "RawCom") || (moduleDriver == "RawLD") ) {
+ module->AddRenderFilter(m_filters.plain);
+ noDriver = false;
+ }
+ }
+}
+
+/** This function deinitializes the modules and deletes them. */
+bool CSwordBackend::shutdownModules() {
+ QList<CSwordModuleInfo*>::iterator it = m_moduleList.begin();
+ QList<CSwordModuleInfo*>::iterator end = m_moduleList.end();
+
+ while (it != end) {
+ CSwordModuleInfo* current = (*it);
+ it = m_moduleList.erase(it);
+ delete current;
+ }
+
+ Q_ASSERT(m_moduleList.count() == 0);
+ //BT mods are deleted now, delete Sword mods, too.
+ DeleteMods();
+
+ /* Cipher filters must be handled specially, because SWMgr creates them,
+ * stores them in cipherFilters and cleanupFilters and attaches them to locked
+ * modules. If these modules are removed, the filters need to be removed as well,
+ * so that they are re-created for the new module objects.
+ */
+ sword::FilterMap::iterator cipher_it;
+ for (cipher_it = cipherFilters.begin(); cipher_it != cipherFilters.end(); cipher_it++)
+ {
+ //Delete the Filter and remove it from the cleanup list
+ cleanupFilters.remove(cipher_it->second);
+ delete cipher_it->second;
+ }
+ cipherFilters.clear();
+
+ return true;
+}
+
+void CSwordBackend::setOption( const CSwordModuleInfo::FilterTypes type, const int state ) {
+ sword::SWBuf value;
+
+ switch (type) {
+
+ case CSwordModuleInfo::textualVariants:
+
+ if (state == 0) {
+ value = "Primary Reading";
+ }
+ else if (state == 1) {
+ value = "Secondary Reading";
+ }
+ else {
+ value = "All Readings";
+ }
+
+ break;
+
+ default:
+ value = state ? "On": "Off";
+ break;
+ };
+
+ if (value.length())
+ setGlobalOption(optionName(type).toUtf8().constData(), value.c_str());
+}
+
+void CSwordBackend::setFilterOptions( const CSwordBackend::FilterOptions options) {
+ setOption( CSwordModuleInfo::footnotes, options.footnotes );
+ setOption( CSwordModuleInfo::strongNumbers, options.strongNumbers );
+ setOption( CSwordModuleInfo::headings, options.headings );
+ setOption( CSwordModuleInfo::morphTags, options.morphTags );
+ setOption( CSwordModuleInfo::lemmas, options.lemmas );
+ setOption( CSwordModuleInfo::hebrewPoints, options.hebrewPoints );
+ setOption( CSwordModuleInfo::hebrewCantillation, options.hebrewCantillation );
+ setOption( CSwordModuleInfo::greekAccents, options.greekAccents );
+ setOption( CSwordModuleInfo::redLetterWords, options.redLetterWords );
+ setOption( CSwordModuleInfo::textualVariants, options.textualVariants );
+ setOption( CSwordModuleInfo::morphSegmentation, options.morphSegmentation );
+ // setOption( CSwordModuleInfo::transliteration, options.transliteration );
+ setOption( CSwordModuleInfo::scriptureReferences, options.scriptureReferences);
+}
+
+/** This function searches for a module with the specified description */
+CSwordModuleInfo* CSwordBackend::findModuleByDescription(const QString& description) {
+ foreach(CSwordModuleInfo* mod, m_moduleList) {
+ if (mod->config(CSwordModuleInfo::Description) == description) return mod;
+ }
+ return 0;
+}
+
+/** This function searches for a module with the specified description */
+const QString CSwordBackend::findModuleNameByDescription(const QString& description) {
+ if (m_moduleDescriptionMap.contains(description)) {
+ return m_moduleDescriptionMap[description];
+ }
+ return QString::null;
+}
+
+/** This function searches for a module with the specified name */
+CSwordModuleInfo* CSwordBackend::findModuleByName(const QString& name) {
+ foreach(CSwordModuleInfo* mod, m_moduleList) {
+ if (mod->name() == name) return mod;
+ }
+ return 0;
+}
+
+CSwordModuleInfo* CSwordBackend::findSwordModuleByPointer(const sword::SWModule* const swmodule) {
+ foreach(CSwordModuleInfo* mod, m_moduleList) {
+ if (mod->module() == swmodule ) return mod;
+ }
+ return 0;
+}
+
+CSwordModuleInfo* CSwordBackend::findModuleByPointer(const CSwordModuleInfo* const module) {
+ foreach(CSwordModuleInfo* mod, m_moduleList) {
+ if (mod == module) return mod;
+ }
+ return 0;
+}
+
+/** Returns our local config object to store the cipher keys etc. locally for each user. The values of the config are merged with the global config. */
+bool CSwordBackend::moduleConfig(const QString& module, sword::SWConfig& moduleConfig) {
+ sword::SectionMap::iterator section;
+ DIR *dir = opendir(configPath);
+
+ struct dirent *ent;
+
+ bool foundConfig = false;
+ QString modFile;
+
+ if (dir) { // find and update .conf file
+ rewinddir(dir);
+
+ while ((ent = readdir(dir)) && !foundConfig) {
+ if ((strcmp(ent->d_name, ".")) && (strcmp(ent->d_name, ".."))) {
+ modFile = QString(configPath);
+ modFile.append("/");
+ modFile.append( QString::fromLocal8Bit(ent->d_name) );
+
+ moduleConfig = sword::SWConfig( modFile.toLocal8Bit().constData() );
+ section = moduleConfig.Sections.find( module.toLocal8Bit().constData() );
+ foundConfig = ( section != moduleConfig.Sections.end() );
+ }
+ }
+
+ closedir(dir);
+ }
+ else { //try to read mods.conf
+ moduleConfig = sword::SWConfig("");//global config
+ section = config->Sections.find( module.toLocal8Bit().constData() );
+ foundConfig = ( section != config->Sections.end() );
+
+ sword::ConfigEntMap::iterator entry;
+
+ if (foundConfig) { //copy module section
+
+ for (entry = section->second.begin(); entry != section->second.end(); entry++) {
+ moduleConfig.Sections[section->first].insert(sword::ConfigEntMap::value_type(entry->first, entry->second));
+ }
+ }
+ }
+
+ if (!foundConfig && configType != 2) { //search in $HOME/.sword/
+
+ QString myPath = util::filesystem::DirectoryUtil::getUserHomeDir().absolutePath();
+ myPath.append("/.sword/mods.d");
+ dir = opendir(myPath.toUtf8().constData());
+
+ if (dir) {
+ rewinddir(dir);
+
+ while ((ent = readdir(dir)) && !foundConfig) {
+ if ((strcmp(ent->d_name, ".")) && (strcmp(ent->d_name, ".."))) {
+ modFile = myPath;
+ modFile.append('/');
+ modFile.append(ent->d_name);
+ moduleConfig = sword::SWConfig( modFile.toLocal8Bit().constData() );
+ section = moduleConfig.Sections.find( module.toLocal8Bit().constData() );
+ foundConfig = ( section != moduleConfig.Sections.end() );
+ }
+ }
+
+ closedir(dir);
+ }
+ }
+
+ return foundConfig;
+}
+
+/** Returns the text used for the option given as parameter. */
+const QString CSwordBackend::optionName( const CSwordModuleInfo::FilterTypes option ) {
+ switch (option) {
+ case CSwordModuleInfo::footnotes: return QString("Footnotes");
+ case CSwordModuleInfo::strongNumbers: return QString("Strong's Numbers");
+ case CSwordModuleInfo::headings: return QString("Headings");
+ case CSwordModuleInfo::morphTags: return QString("Morphological Tags");
+ case CSwordModuleInfo::lemmas: return QString("Lemmas");
+ case CSwordModuleInfo::hebrewPoints: return QString("Hebrew Vowel Points");
+ case CSwordModuleInfo::hebrewCantillation: return QString("Hebrew Cantillation");
+ case CSwordModuleInfo::greekAccents: return QString("Greek Accents");
+ case CSwordModuleInfo::redLetterWords: return QString("Words of Christ in Red");
+ case CSwordModuleInfo::textualVariants: return QString("Textual Variants");
+ case CSwordModuleInfo::scriptureReferences: return QString("Cross-references");
+ case CSwordModuleInfo::morphSegmentation: return QString("Morph Segmentation");
+ }
+ return QString::null;
+}
+
+/** Returns the translated name of the option given as parameter. */
+const QString CSwordBackend::translatedOptionName(const CSwordModuleInfo::FilterTypes option) {
+ switch (option) {
+ case CSwordModuleInfo::footnotes: return QObject::tr("Footnotes");
+ case CSwordModuleInfo::strongNumbers: return QObject::tr("Strong's numbers");
+ case CSwordModuleInfo::headings: return QObject::tr("Headings");
+ case CSwordModuleInfo::morphTags: return QObject::tr("Morphological tags");
+ case CSwordModuleInfo::lemmas: return QObject::tr("Lemmas");
+ case CSwordModuleInfo::hebrewPoints: return QObject::tr("Hebrew vowel points");
+ case CSwordModuleInfo::hebrewCantillation: return QObject::tr("Hebrew cantillation marks");
+ case CSwordModuleInfo::greekAccents: return QObject::tr("Greek accents");
+ case CSwordModuleInfo::redLetterWords: return QObject::tr("Red letter words");
+ case CSwordModuleInfo::textualVariants: return QObject::tr("Textual variants");
+ case CSwordModuleInfo::scriptureReferences: return QObject::tr("Scripture cross-references");
+ case CSwordModuleInfo::morphSegmentation: return QObject::tr("Morph segmentation");
+ }
+ return QString::null;
+}
+
+
+const QString CSwordBackend::configOptionName( const CSwordModuleInfo::FilterTypes option ) {
+ switch (option) {
+ case CSwordModuleInfo::footnotes: return QString("Footnotes");
+ case CSwordModuleInfo::strongNumbers: return QString("Strongs");
+ case CSwordModuleInfo::headings: return QString("Headings");
+ case CSwordModuleInfo::morphTags: return QString("Morph");
+ case CSwordModuleInfo::lemmas: return QString("Lemma");
+ case CSwordModuleInfo::hebrewPoints: return QString("HebrewPoints");
+ case CSwordModuleInfo::hebrewCantillation: return QString("Cantillation");
+ case CSwordModuleInfo::greekAccents: return QString("GreekAccents");
+ case CSwordModuleInfo::redLetterWords: return QString("RedLetterWords");
+ case CSwordModuleInfo::textualVariants: return QString("Variants");
+ case CSwordModuleInfo::scriptureReferences: return QString("Scripref");
+ case CSwordModuleInfo::morphSegmentation: return QString("MorphSegmentation");
+ }
+ return QString::null;
+}
+
+const QString CSwordBackend::booknameLanguage( const QString& language ) {
+ if (!language.isEmpty()) {
+ sword::LocaleMgr::getSystemLocaleMgr()->setDefaultLocaleName( language.toUtf8().constData() );
+
+ //refresh the locale of all Bible and commentary modules!
+ //use what sword returns, language may be different
+ QString newLocaleName( sword::LocaleMgr::getSystemLocaleMgr()->getDefaultLocaleName() );
+
+ foreach(CSwordModuleInfo* mod, m_moduleList) {
+ if ( (mod->type() == CSwordModuleInfo::Bible) || (mod->type() == CSwordModuleInfo::Commentary) ) {
+ //Create a new key, it will get the default bookname language
+ ((sword::VerseKey*)(mod->module()->getKey()))->setLocale( newLocaleName.toUtf8().constData() );
+ }
+ }
+
+ }
+ return QString( sword::LocaleMgr::getSystemLocaleMgr()->getDefaultLocaleName() );
+}
+
+
+/** Reload all Sword modules. */
+void CSwordBackend::reloadModules(SetupChangedReason reason) {
+ shutdownModules();
+
+ //delete Sword's config to make Sword reload it!
+
+ if (myconfig) { // force reload on config object because we may have changed the paths
+ delete myconfig;
+ config = myconfig = 0;
+ // we need to call findConfig to make sure that augPaths are reloaded
+#ifdef SWORD_SYSCONF_CHANGED
+ findConfig(&configType, &prefixPath, &configPath, &augPaths, &sysConfig);
+#else
+ findConfig(&configType, &prefixPath, &configPath, &augPaths, sysconfig);
+#endif
+ // now re-read module configuration files
+ loadConfigDir(configPath);
+ }
+ else if (config) {
+ config->Load();
+ }
+
+ initModules(reason);
+}
+
+const QStringList CSwordBackend::swordDirList() {
+ QSet<QString> ret;
+ const QString home = util::filesystem::DirectoryUtil::getUserHomeDir().absolutePath();
+
+ //return a list of used Sword dirs. Useful for the installer
+ QString configPath = QString("%1/.sword/sword.conf").arg(home);
+
+ if (!QFile(configPath).exists()) {
+ configPath = globalConfPath; //e.g. /etc/sword.conf, /usr/local/etc/sword.conf
+ }
+
+ QStringList configs = configPath.split(":");
+
+ for (QStringList::const_iterator it = configs.begin(); it != configs.end(); ++it) {
+ if (!QFileInfo(*it).exists()) {
+ continue;
+ }
+
+ //get all DataPath and AugmentPath entries from the config file and add them to the list
+ sword::SWConfig conf( (*it).toUtf8().constData() );
+ ret << conf["Install"]["DataPath"].c_str();
+ sword::ConfigEntMap group = conf["Install"];
+ sword::ConfigEntMap::iterator start = group.equal_range("AugmentPath").first;
+ sword::ConfigEntMap::iterator end = group.equal_range("AugmentPath").second;
+
+ for (sword::ConfigEntMap::const_iterator it = start; it != end; ++it) {
+ ret << QDir(it->second.c_str()).absolutePath(); //added augment path
+ }
+ }
+
+ if (!home.isEmpty()) {
+ // This is added to the set if not there already. Notice that
+ // this prevents duplication only if the QDir::absolutePath() returns
+ // string without the prepended "/".
+ ret << home + "/.sword";
+ }
+
+ return ret.values();
+}
+
+void CSwordBackend::notifyChange(SetupChangedReason reason)
+{
+ emit sigSwordSetupChanged(reason);
+}
diff --git a/src/backend/managers/cswordbackend.h b/src/backend/managers/cswordbackend.h
new file mode 100644
index 0000000..0ffb484
--- /dev/null
+++ b/src/backend/managers/cswordbackend.h
@@ -0,0 +1,273 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CSWORDBACKEND_H
+#define CSWORDBACKEND_H
+
+//BibleTime includes
+#include "backend/drivers/cswordmoduleinfo.h"
+
+//Qt includes
+#include <QObject>
+#include <QMap>
+#include <QString>
+#include <QStringList>
+
+//Sword includes
+#include <swmgr.h>
+#include <swbuf.h>
+#include <swmodule.h>
+#include <swversion.h>
+#include <localemgr.h>
+#include <utilstr.h>
+
+//forward declarations
+namespace Rendering {
+ class CEntryDisplay;
+ class CChapterDisplay;
+ class CBookDisplay;
+}
+
+/** The backend layer main class.
+ * This is the implementation of CBackend for Sword. It's additionally derived from SWMgr
+ * to provide functions of Sword.
+ *
+ * @short The backend implementation of Sword
+ * @author The BibleTime team
+ * @version $Id: cswordbackend.h,v 1.58 2007/03/14 21:32:47 joachim Exp $
+ */
+
+class CSwordBackend : public QObject, public sword::SWMgr
+{
+ Q_OBJECT
+public:
+
+ /** The reason for the sigSwordSetupChanged signal, i.e. why the module list has changed. */
+ enum SetupChangedReason {
+ AddedModules = 1,
+ RemovedModules = 2,
+ HidedModules = 4,
+ PathChanged = 8,
+ OtherChange = 16
+ };
+
+ /** Filter options. Filter options to
+ * control the text display of modules. Uses int and not bool because not all
+ * options have just two toggle values.
+ */
+ struct FilterOptions {
+ int footnotes; /**< 0 for disabled, 1 for enabled */
+ int strongNumbers; /**< 0 for disabled, 1 for enabled */
+ int headings; /**< 0 for disabled, 1 for enabled */
+ int morphTags; /**< 0 for disabled, 1 for enabled */
+ int lemmas; /**< 0 for disabled, 1 for enabled */
+ int hebrewPoints; /**< 0 for disabled, 1 for enabled */
+ int hebrewCantillation; /**< 0 for disabled, 1 for enabled */
+ int greekAccents; /**< 0 for disabled, 1 for enabled */
+ int textualVariants; /**< Number n to enabled the n-th variant */
+ int redLetterWords; /**< 0 for disabled, 1 for enabled */
+ int scriptureReferences; /**< 0 for disabled, 1 for enabled */
+ int morphSegmentation; /**< 0 for disabled, 1 for enabled */
+ };
+
+ /** Control the display of a text.
+ */
+ struct DisplayOptions {
+ int lineBreaks;
+ int verseNumbers;
+ };
+
+ /** The error codes which may be returned by the @ref Load() call.
+ */
+ enum LoadError { // the values exist to cast from the char return of SWMgr::Load
+ NoSwordConfig = -1,
+ NoError = 0,
+ NoModules = 1
+ };
+ /**
+ * The constructor of the Sword backend.
+ * It creates the SWModule objects using SWMgr's methods, it adds the necessary
+ * filters for the module format.
+ */
+ CSwordBackend();
+ /**
+ * The constructor of the Sword backend. This is actually used nowhere.
+ * Notice that using augmentHome=false can mess up the system because it is true elsewhere.
+ * @param path The path which is used to load modules
+ * @param augmentHome True if the $HOME/.sword/ modules should be augmented with the other modules
+ */
+ CSwordBackend( const QString& path, const bool augmentHome = true );
+
+ /**
+ * The destrctor of this backend. This function shuts the modules down using @ref shutdownModules.
+ */
+ virtual ~CSwordBackend();
+
+ /**
+ * This function returns the list of available modules managed by this backend.
+ * You have to call initModules() first;
+ *
+ * @return The list of modules managed by this backend
+ */
+ inline virtual QList<CSwordModuleInfo*>& moduleList();
+ /**
+ * Initializes the Sword modules.
+ *
+ * @return True if the initializiation was succesful, otherwise return false.
+ */
+ virtual CSwordBackend::LoadError initModules(SetupChangedReason reason);
+ /**
+ * This function deinitializes the modules and deletes them.
+ *
+ * @return True if it was succesful, otherwise return false
+ */
+ virtual bool shutdownModules();
+ /**
+ * Sets the given options enabled or disabled depending on the second parameter.
+ *
+ * @param type This is the type this function should set enabled or disabled
+ * @param enable If this is true the option will be enabled, otherwise it will be disabled.
+ */
+ void setOption( const CSwordModuleInfo::FilterTypes type, const int state );
+ /** */
+ void setFilterOptions( const CSwordBackend::FilterOptions options );
+ /**
+ * Sets the language for the international booknames of Sword.
+ * @param langName The abbreviation string which should be used for the Sword backend
+ */
+ const QString booknameLanguage( const QString& langName = QString::null );
+ /**
+ * This function searches for a module with the specified description
+ * @param description The description of the desired module
+ * @return pointer to the desired module; null if no module has the specified description
+ */
+ virtual CSwordModuleInfo* findModuleByDescription(const QString& description);
+ /**
+ * This function searches for a module with the specified description
+ * @param description The description of the desired module
+ * @return pointer to the desired module; null if no module has the specified description
+ */
+ const QString findModuleNameByDescription(const QString& description);
+ /**
+ * This function searches for a module with the specified name
+ * @param name The name of the desired module
+ * @return Pointer to the desired module; null if no module has the specified name
+ */
+ CSwordModuleInfo* findModuleByName(const QString& name);
+ /**
+ * This function searches for a module with the specified sword module as module() object!
+ * @param swmodule to a Sword module
+ * @return pointer to the desired module; null if no module has the specified name
+ */
+ CSwordModuleInfo* findSwordModuleByPointer(const sword::SWModule* const swmodule);
+ /**
+ * This function searches for a module which is the same as the passed module.
+ * @param module The module which should be used for searching the new one. May be child of a different backend.
+ * @return Pointer to the desired module; null if no module has the specified name
+ */
+ CSwordModuleInfo* findModuleByPointer(const CSwordModuleInfo* const module);
+ /**
+ * @return Our global config object which contains the configs of all modules merged together.
+ */
+ inline sword::SWConfig* getConfig() const;
+ /**
+ * Tries to find the config object for the module. The second paramter will be the found config.
+ * @return True if the config was found, false if not. If false is returned the moduleConfig object is in undefined/unknwon state.
+ */
+ bool moduleConfig(const QString& module, sword::SWConfig& moduleConfig );
+ /**
+ * Returns the text used for the option given as parameter.
+ * @param The paramter enum
+ * @return The name of the option given by the parameter
+ */
+ static const QString optionName( const CSwordModuleInfo::FilterTypes option );
+ /**
+ * Returns the text used for the option given as parameter.
+ */
+ static const QString configOptionName( const CSwordModuleInfo::FilterTypes option );
+ /**
+ * Returns the translated name of the option given as parameter.
+ * @param The translated option name
+ */
+ static const QString translatedOptionName(const CSwordModuleInfo::FilterTypes option );
+ /**
+ * Returns the version of the Sword library.
+ * @return The version used by this backend
+ */
+ inline virtual const sword::SWVersion Version();
+ /**
+ * Reload all Sword modules.
+ */
+ void reloadModules(SetupChangedReason reason);
+
+ /**
+ * Takes off the given modules from the list and returns them.
+ * User must take care of the deletion of the returned CSwordModuleInfo pointers.
+ */
+ QList<CSwordModuleInfo*> takeModulesFromList(QStringList names);
+
+ /** Sword prefix list.
+ * @return A list of all known Sword prefix dirs
+ */
+ const QStringList swordDirList();
+
+ /** Emits the sigSwordSetupChanged signal.
+ * This can be called directly from outside if there is no need to reload the backend.
+ */
+ void notifyChange(SetupChangedReason reason);
+
+signals:
+ void sigSwordSetupChanged(CSwordBackend::SetupChangedReason reason);
+
+protected:
+ /**
+ * Adds a render filter to the module.
+ * This is used to apply our own render filters to our modules instead of the sword filters
+ */
+ virtual void AddRenderFilters(sword::SWModule *module, sword::ConfigEntMap &section);
+ /**
+ * Overrides Sword filters which appear to be buggy.
+ */
+ virtual void filterInit();
+
+private:
+ // Filters
+ struct Filters {
+ sword::SWFilter* gbf;
+ sword::SWFilter* plain;
+ sword::SWFilter* thml;
+ sword::SWFilter* osis;
+ } m_filters;
+
+ struct Displays {
+ Rendering::CChapterDisplay* chapter;
+ Rendering::CEntryDisplay* entry;
+ Rendering::CBookDisplay* book;
+ } m_displays;
+
+ QList<CSwordModuleInfo*> m_moduleList;
+ QMap<QString, QString> m_moduleDescriptionMap;
+};
+
+/**Returns The list of modules managed by this backend*/
+inline QList<CSwordModuleInfo*>& CSwordBackend::moduleList() {
+ return m_moduleList;
+}
+
+/** Returns our local config object to store the cipher keys etc. locally for each user. The values of the config are merged with the global config. */
+inline sword::SWConfig* CSwordBackend::getConfig() const {
+ return config;
+}
+
+/** Returns the version of the Sword library. */
+inline const sword::SWVersion CSwordBackend::Version() {
+ return sword::SWVersion::currentVersion;
+}
+
+#endif
diff --git a/src/backend/rendering/cbookdisplay.cpp b/src/backend/rendering/cbookdisplay.cpp
new file mode 100644
index 0000000..fd57034
--- /dev/null
+++ b/src/backend/rendering/cbookdisplay.cpp
@@ -0,0 +1,136 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+//Backend
+#include "cbookdisplay.h"
+#include "cdisplayrendering.h"
+#include "backend/drivers/cswordbookmoduleinfo.h"
+#include "backend/keys/cswordtreekey.h"
+
+//Util
+#include <boost/scoped_ptr.hpp>
+
+/** Returns the rendered text using the modules in the list and using the key parameter. The displayoptions and filter options are used, too. */
+const QString Rendering::CBookDisplay::text( const QList<CSwordModuleInfo*>& modules, const QString& keyName, const CSwordBackend::DisplayOptions displayOptions, const CSwordBackend::FilterOptions filterOptions ) {
+ CSwordBookModuleInfo* book = dynamic_cast<CSwordBookModuleInfo*>(modules.first());
+ Q_ASSERT(book);
+
+ CSwordBackend::DisplayOptions dOpts = displayOptions;
+ dOpts.lineBreaks = true; //books should render with blocks, not with inlined sections
+
+ CDisplayRendering render(dOpts, filterOptions);
+ CDisplayRendering::KeyTree tree;
+ CDisplayRendering::KeyTreeItem::Settings itemSettings;
+
+ // the number of levels which should be display together, 1 means display no entries together
+ int displayLevel = book->config( CSwordModuleInfo::DisplayLevel ).toInt();
+
+ boost::scoped_ptr<CSwordTreeKey> key (
+ dynamic_cast<CSwordTreeKey*>( CSwordKey::createInstance(book) )
+ );
+ key->key(keyName); //set the key to position we'd like to get
+
+ const unsigned long offset = key->getOffset();
+
+ // standard of DisplayLevel, display nothing together
+ // if the current key is the root entry don't display anything together!
+
+ if ((displayLevel <= 1) || (key->key().isEmpty() || (key->key() == "/") )) {
+ tree.append( new CDisplayRendering::KeyTreeItem( key->key(), modules, itemSettings ) );
+
+ const QString renderedText = render.renderKeyTree(tree);
+ key->setOffset( offset );
+ return renderedText;
+ };
+
+ /**
+ * Check whether displaying displayLevel levels together is possible.
+ * For this count the childs and parents
+ * of the required position
+ */
+
+ int possibleLevels = 1; //we start with the default value of displayLevel, which means no entries together
+
+ while( key->parent() && (key->key() != "/") && !key->key().isEmpty() ) {//add parents
+ ++possibleLevels;
+ };
+
+ // key->key(keyName); //set the key to the start position
+
+ key->setOffset( offset );
+
+ while( key->firstChild( )) { //add childs
+ ++possibleLevels;
+ };
+
+ if (possibleLevels < displayLevel) { //too few levels available!
+ //display current level, we could also decide to display the available levels together
+ tree.append( new CDisplayRendering::KeyTreeItem( key->key(), modules, itemSettings ) );
+
+ const QString renderedText = render.renderKeyTree(tree);
+ key->setOffset( offset );
+ return renderedText;
+ };
+
+ if ((displayLevel > 2) && (displayLevel == possibleLevels)) { //fix not to diplay the whole module
+ --displayLevel;
+ }
+
+ // at this point we're sure that we can display the required levels toogether
+ // at the moment we're at the lowest level, so we only have to go up!
+ for (int currentLevel = 1; currentLevel < displayLevel; ++currentLevel) { //we start again with 1 == standard of displayLevel
+
+ if ( !key->parent() ) { //something went wrong although we checked before! Be safe and return entry's text
+ tree.append( new CDisplayRendering::KeyTreeItem( key->key(), modules, itemSettings ) );
+
+ const QString renderedText = render.renderKeyTree(tree);
+ key->setOffset( offset );
+ return renderedText;
+ };
+ };
+
+ // no we can display all sub levels together! We checked before that this is possible!
+ itemSettings.highlight = (key->key() == keyName);
+
+ tree.append( new CDisplayRendering::KeyTreeItem( key->key(), modules, itemSettings ) );
+
+ //const bool hasToplevelText = !key->strippedText().isEmpty();
+ key->firstChild(); //go to the first sibling on the same level
+
+ setupRenderTree(key.get(), &tree, keyName);
+
+ const QString renderedText = render.renderKeyTree(tree);
+
+ key->setOffset( offset ); //restore key
+
+ return renderedText;
+}
+
+void Rendering::CBookDisplay::setupRenderTree(CSwordTreeKey * swordTree, CTextRendering::KeyTree * renderTree, const QString& highlightKey) {
+
+ const QString key = swordTree->key();
+ const unsigned long offset = swordTree->getOffset();
+
+ CTextRendering::KeyTreeItem::Settings settings;
+ settings.highlight = (key == highlightKey);
+
+ CTextRendering::KeyTreeItem* item = new CTextRendering::KeyTreeItem(key, swordTree->module(0), settings );
+ renderTree->append( item );
+
+ if (swordTree->hasChildren()) { //print tree for the child items
+ swordTree->firstChild();
+ setupRenderTree(swordTree, item->childList(), highlightKey);
+ swordTree->setOffset( offset ); //go back where we came from
+ }
+
+ if (swordTree->nextSibling()) { //print tree for next entry on the same depth
+ setupRenderTree(swordTree, renderTree, highlightKey);
+ swordTree->setOffset( offset ); //return to the value we had at the beginning of this block!
+ }
+}
diff --git a/src/backend/rendering/cbookdisplay.h b/src/backend/rendering/cbookdisplay.h
new file mode 100644
index 0000000..6f0b031
--- /dev/null
+++ b/src/backend/rendering/cbookdisplay.h
@@ -0,0 +1,45 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef RENDERINGCBOOKDISPLAY_H
+#define RENDERINGCBOOKDISPLAY_H
+
+#include "centrydisplay.h"
+#include "ctextrendering.h"
+//TODO: It would be sufficient to forward declare CTextRendering and CTextRendering::KeyTree
+//but I don't know how :(
+
+class CSwordTreeKey;
+
+namespace Rendering {
+
+ /**
+ * A CEntryDisplay implementation which works on tree-based GenBook modules
+ * of Sword.
+ * @short CEntryDisplay implementation for GenBook modules,
+ * @author The BibleTime team
+ */
+
+class CBookDisplay : public CEntryDisplay {
+public: // Public methods
+ virtual ~CBookDisplay() {}
+
+ /**
+ * Returns the rendered text using the modules in the list and using the key parameter.
+ * The displayoptions and filter options are used, too.
+ */
+ virtual const QString text( const QList<CSwordModuleInfo*>& modules, const QString& key, const CSwordBackend::DisplayOptions displayOptions, const CSwordBackend::FilterOptions filterOptions);
+
+protected:
+ void setupRenderTree(CSwordTreeKey* swordTree, CTextRendering::KeyTree* renderTree, const QString& highlightKey);
+};
+
+}
+
+#endif
diff --git a/src/backend/rendering/cchapterdisplay.cpp b/src/backend/rendering/cchapterdisplay.cpp
new file mode 100644
index 0000000..921ed78
--- /dev/null
+++ b/src/backend/rendering/cchapterdisplay.cpp
@@ -0,0 +1,59 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+//Backend
+#include "cchapterdisplay.h"
+#include "cdisplayrendering.h"
+#include "backend/keys/cswordversekey.h"
+#include "backend/drivers/cswordbiblemoduleinfo.h"
+
+const QString Rendering::CChapterDisplay::text( const QList<CSwordModuleInfo*>& modules, const QString& keyName, const CSwordBackend::DisplayOptions displayOptions, const CSwordBackend::FilterOptions filterOptions ) {
+ Q_ASSERT( modules.count() >= 1 );
+ Q_ASSERT( !keyName.isEmpty() );
+
+ CSwordModuleInfo* module = modules.first();
+
+ if (modules.count() == 1) module->module()->setSkipConsecutiveLinks( true ); //skip empty, linked verses
+
+ CTextRendering::KeyTreeItem::Settings settings;
+ settings.keyRenderingFace =
+ displayOptions.verseNumbers
+ ? CTextRendering::KeyTreeItem::Settings::SimpleKey
+ : CTextRendering::KeyTreeItem::Settings::NoKey;
+
+ QString startKey = keyName;
+ QString endKey = startKey;
+
+ //check whether there's an intro we have to include
+ Q_ASSERT((module->type() == CSwordModuleInfo::Bible));
+
+ if (module->type() == CSwordModuleInfo::Bible) {
+ ((sword::VerseKey*)(module->module()->getKey()))->Headings(1); //HACK: enable headings for VerseKeys
+
+ CSwordBibleModuleInfo* bible = dynamic_cast<CSwordBibleModuleInfo*>(module);
+ Q_ASSERT(bible);
+
+ CSwordVerseKey k1(module);
+ k1.Headings(1);
+ k1.key(keyName);
+
+ if (k1.Chapter() == 1) k1.Chapter(0); //Chapter 1, start with 0:0, otherwise X:0
+
+ k1.Verse(0);
+
+ startKey = k1.key();
+
+ if (k1.Chapter() == 0) k1.Chapter(1);
+ k1.Verse(bible->verseCount(k1.book(), k1.Chapter()));
+ endKey = k1.key();
+ }
+
+ CDisplayRendering render(displayOptions, filterOptions);
+ return render.renderKeyRange( startKey, endKey, modules, keyName, settings );
+}
diff --git a/src/backend/rendering/cchapterdisplay.h b/src/backend/rendering/cchapterdisplay.h
new file mode 100644
index 0000000..cf00adf
--- /dev/null
+++ b/src/backend/rendering/cchapterdisplay.h
@@ -0,0 +1,37 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef RENDERINGCCHAPTERDISPLAY_H
+#define RENDERINGCCHAPTERDISPLAY_H
+
+#include "centrydisplay.h"
+
+namespace Rendering {
+
+/** Chapter rendering.
+* A CEntryDisplay implementation mde for Bibles to display whole chapters
+* at once.
+* @author The BibleTime team
+*/
+
+class CChapterDisplay : public CEntryDisplay {
+
+public: // Public methods
+ virtual ~CChapterDisplay() {}
+
+ /**
+ * Returns the rendered text using the modules in the list and using the key parameter.
+ * The displayoptions and filter options are used, too.
+ */
+ virtual const QString text( const QList<CSwordModuleInfo*>& modules, const QString& key, const CSwordBackend::DisplayOptions displayOptions, const CSwordBackend::FilterOptions filterOptions);
+};
+
+}
+
+#endif
diff --git a/src/backend/rendering/cdisplayrendering.cpp b/src/backend/rendering/cdisplayrendering.cpp
new file mode 100644
index 0000000..8c6c525
--- /dev/null
+++ b/src/backend/rendering/cdisplayrendering.cpp
@@ -0,0 +1,158 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "cdisplayrendering.h"
+
+#include "backend/managers/cdisplaytemplatemgr.h"
+#include "backend/managers/creferencemanager.h"
+#include "backend/keys/cswordkey.h"
+#include "backend/keys/cswordversekey.h"
+
+#include "util/cpointers.h"
+
+//Qt
+#include <QString>
+#include <QRegExp>
+
+namespace Rendering {
+
+ CDisplayRendering::CDisplayRendering(CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions)
+: CHTMLExportRendering(CHTMLExportRendering::Settings(true), displayOptions, filterOptions) {}
+
+ const QString CDisplayRendering::entryLink( const KeyTreeItem& item, CSwordModuleInfo* module ) {
+ QString linkText;
+
+ const bool isBible = module && (module->type() == CSwordModuleInfo::Bible);
+ CSwordVerseKey vk(module); //only valid for bible modules, i.e. isBible == true
+ vk.Headings(true);
+
+ if (isBible) {
+ vk.key(item.key());
+ }
+
+ if (isBible && (vk.Verse() == 0)) {
+ return QString::null; //Warning: return already here
+ }
+
+ switch (item.settings().keyRenderingFace) {
+
+ case KeyTreeItem::Settings::NoKey: {
+ linkText = QString::null;
+ break; //no key is valid for all modules
+ }
+
+ case KeyTreeItem::Settings::CompleteShort: {
+ if (isBible) {
+ linkText = QString::fromUtf8(vk.getShortText());
+ break;
+ }
+
+ //fall through for non-Bible modules
+ }
+
+ case KeyTreeItem::Settings::CompleteLong: {
+ if (isBible) {
+ linkText = vk.key();
+ break;
+ }
+
+ //fall through for non-Bible modules
+ }
+
+ case KeyTreeItem::Settings::SimpleKey: {
+ if (isBible) {
+ linkText = QString::number(vk.Verse());
+ break;
+ }
+
+ //fall through for non-Bible modules
+ }
+
+ default: { //default behaviour to return the passed key
+ linkText = item.key();
+ break;
+ }
+ }
+
+ if (linkText.isEmpty()) {
+ return QString("<a name=\"").append(keyToHTMLAnchor(item.key())).append("\" />");
+ }
+ else {
+ return QString("<a name=\"").append(keyToHTMLAnchor(item.key())).append("\" ")
+ .append("href=\"")
+ .append(CReferenceManager::encodeHyperlink(
+ module->name(), item.key(), CReferenceManager::typeFromModule(module->type()))
+ )
+ .append("\">").append(linkText).append("</a>\n");
+ }
+
+ return QString::null;
+ }
+
+ const QString CDisplayRendering::keyToHTMLAnchor(const QString& key) {
+ QString ret = key;
+ ret = ret.trimmed().remove(QRegExp("[^A-Za-z0-9]+"));
+ ret = ret.remove(QRegExp("^\\d+|"));
+
+ return ret;
+ }
+
+ const QString CDisplayRendering::finishText( const QString& oldText, KeyTree& tree ) {
+ QList<CSwordModuleInfo*> modules = collectModules(&tree);
+ qDebug("CDisplayRendering::finishText");
+
+ //marking words is very slow, we have to find a better solution
+
+ /*
+ //mark all words by spans
+
+ QString text = oldText;
+
+ QRegExp re("(\\b)(?=\\w)"); //word begin marker
+ int pos = text.find(re, 0);
+
+ while (pos != -1) { //word begin found
+ //qWarning("found word at %i in %i", pos, text.length());
+ int endPos = pos + 1;
+ if (!CToolClass::inHTMLTag(pos+1, text)) { //the re has a positive look ahead which matches one char before the word start
+ //qWarning("matched %s", text.mid(pos+1, 4).latin1());
+
+ //find end of word and put a marker around it
+ endPos = text.find(QRegExp("\\b|[,.:]"), pos+1);
+ if ((endPos != -1) && !CToolClass::inHTMLTag(endPos, text) && (endPos - pos >= 3)) { //reuire wordslonger than 3 chars
+ text.insert(endPos, "</span>");
+ text.insert(pos, "<span class=\"word\">");
+
+ endPos += 26;
+ }
+ }
+ pos = text.find(re, endPos);
+ }
+ */
+ const CLanguageMgr::Language* const lang =
+ (modules.count() >= 1)
+ ? modules.first()->language()
+ : CPointers::languageMgr()->defaultLanguage();
+
+ CDisplayTemplateMgr* tMgr = CPointers::displayTemplateManager();
+
+ //Q_ASSERT(modules.count() >= 1);
+
+ CDisplayTemplateMgr::Settings settings;
+ settings.modules = modules;
+ settings.langAbbrev = ((modules.count() == 1) && lang->isValid()) ? lang->abbrev() : QString::null;
+
+ if (modules.count() == 1)
+ settings.pageDirection = (modules.first()->textDirection() == CSwordModuleInfo::LeftToRight) ? "ltr" : "rtl";
+ else
+ settings.pageDirection = QString::null;
+
+ return tMgr->fillTemplate(CBTConfig::get(CBTConfig::displayStyle), oldText, settings);
+ }
+}
diff --git a/src/backend/rendering/cdisplayrendering.h b/src/backend/rendering/cdisplayrendering.h
new file mode 100644
index 0000000..9c4451b
--- /dev/null
+++ b/src/backend/rendering/cdisplayrendering.h
@@ -0,0 +1,38 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef RENDERINGCDISPLAYRENDERING_H
+#define RENDERINGCDISPLAYRENDERING_H
+
+#include "chtmlexportrendering.h"
+
+namespace Rendering {
+
+/** HTML rendering for the text display widgets.
+ * @short Rendering for the html display widget.
+ * @author The BibleTime team
+ */
+
+class CDisplayRendering : public CHTMLExportRendering {
+public:
+ static const QString keyToHTMLAnchor(const QString& key);
+
+ CDisplayRendering(
+ CSwordBackend::DisplayOptions displayOptions = CBTConfig::getDisplayOptionDefaults(),
+ CSwordBackend::FilterOptions filterOptions = CBTConfig::getFilterOptionDefaults()
+ );
+
+protected:
+ virtual const QString entryLink( const KeyTreeItem& item, CSwordModuleInfo* const module );
+ virtual const QString finishText( const QString&, KeyTree& tree );
+};
+
+}
+
+#endif
diff --git a/src/backend/rendering/centrydisplay.cpp b/src/backend/rendering/centrydisplay.cpp
new file mode 100644
index 0000000..7a4626c
--- /dev/null
+++ b/src/backend/rendering/centrydisplay.cpp
@@ -0,0 +1,63 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+//BibleTime includes
+#include "centrydisplay.h"
+
+#include "backend/keys/cswordkey.h"
+#include "backend/keys/cswordversekey.h"
+#include "backend/drivers/cswordbookmoduleinfo.h"
+#include "backend/managers/creferencemanager.h"
+#include "backend/managers/cdisplaytemplatemgr.h"
+#include "cdisplayrendering.h"
+
+#include "backend/config/cbtconfig.h"
+#include <boost/scoped_ptr.hpp>
+
+//Qt includes
+#include <QApplication>
+#include <QRegExp>
+
+using namespace Rendering;
+
+/** Returns the rendered text using the modules in the list and using the key parameter.
+ * The displayoptions and filter options are used, too.
+ */
+const QString CEntryDisplay::text( const QList<CSwordModuleInfo*>& modules, const QString& keyName, const CSwordBackend::DisplayOptions displayOptions, const CSwordBackend::FilterOptions filterOptions ) {
+ CDisplayRendering render(displayOptions, filterOptions);
+
+ //no highlighted key and no extra key link in the text
+ CTextRendering::KeyTreeItem::Settings normal_settings(false, CTextRendering::KeyTreeItem::Settings::CompleteShort);
+ CSwordModuleInfo* module = modules.first();
+ QString result;
+
+ //in Bibles and Commentaries we need to check if 0:0 and X:0 contain something
+ if (module->type() == CSwordModuleInfo::Bible || module->type() == CSwordModuleInfo::Commentary) {
+ ((sword::VerseKey*)(module->module()->getKey()))->Headings(1); //HACK: enable headings for VerseKeys
+
+ CSwordVerseKey k1(module);
+ k1.Headings(1);
+ k1.key(keyName);
+
+ // don't print the key
+ CTextRendering::KeyTreeItem::Settings preverse_settings(false, CTextRendering::KeyTreeItem::Settings::NoKey);
+
+ if (k1.Verse() == 1){ //X:1, prepend X:0
+ if (k1.Chapter() == 1){ //1:1, also prepend 0:0 before that
+ k1.Chapter(0);
+ k1.Verse(0);
+ if ( k1.rawText().length() > 0 ) result.append( render.renderSingleKey(k1.key(), modules, preverse_settings ) );
+ k1.Chapter(1);
+ }
+ k1.Verse(0);
+ if ( k1.rawText().length() > 0 ) result.append( render.renderSingleKey(k1.key(), modules, preverse_settings ) );
+ }
+ }
+ return result.append( render.renderSingleKey(keyName, modules, normal_settings) );
+}
diff --git a/src/backend/rendering/centrydisplay.h b/src/backend/rendering/centrydisplay.h
new file mode 100644
index 0000000..96f0dba
--- /dev/null
+++ b/src/backend/rendering/centrydisplay.h
@@ -0,0 +1,51 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CENTRYDISPLAY_H
+#define CENTRYDISPLAY_H
+
+//BibleTime
+//#include "ctextrendering.h"
+class CSwordModuleInfo;
+#include "backend/managers/cswordbackend.h"
+
+#include "util/cpointers.h"
+
+//Sword
+#include <swdisp.h>
+
+//Qt
+#include <QString>
+
+class CSwordModuleInfo;
+
+namespace Rendering {
+
+/**
+* The reimplementation of SWDisplay to fit our needs.
+* @short Display implementation
+* @author The BibleTime team
+*/
+
+class CEntryDisplay : public sword::SWDisplay, public CPointers {
+
+public:
+ virtual ~CEntryDisplay() {}
+
+ /**
+ * Returns the rendered text using the modules in the list and using the key parameter.
+ * The displayoptions and filter options are used, too.
+ */
+ virtual const QString text( const QList<CSwordModuleInfo*>& modules, const QString& key, const CSwordBackend::DisplayOptions displayOptions, const CSwordBackend::FilterOptions filterOptions);
+};
+
+
+}
+
+#endif
diff --git a/src/backend/rendering/chtmlexportrendering.cpp b/src/backend/rendering/chtmlexportrendering.cpp
new file mode 100644
index 0000000..38a83d3
--- /dev/null
+++ b/src/backend/rendering/chtmlexportrendering.cpp
@@ -0,0 +1,234 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "chtmlexportrendering.h"
+
+#include "backend/managers/cdisplaytemplatemgr.h"
+#include "backend/managers/clanguagemgr.h"
+#include "backend/keys/cswordkey.h"
+#include "backend/keys/cswordversekey.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+
+#include "util/cpointers.h"
+#include <boost/scoped_ptr.hpp>
+
+#include <iostream>
+
+namespace {
+
+/*
+ * Helper function to dump a verse with all its enty attributes
+ */
+
+void dumpEntryAttributes(sword::SWModule *module) {
+ std::cout << "Attributes for key: " << module->getKeyText() << std::endl;
+ sword::AttributeTypeList::iterator i1;
+ sword::AttributeList::iterator i2;
+ sword::AttributeValue::iterator i3;
+ for (i1 = module->getEntryAttributes().begin(); i1 != module->getEntryAttributes().end(); i1++) {
+ std::cout << "[ " << i1->first << " ]\n";
+ for (i2 = i1->second.begin(); i2 != i1->second.end(); i2++) {
+ std::cout << "\t[ " << i2->first << " ]\n";
+ for (i3 = i2->second.begin(); i3 != i2->second.end(); i3++) {
+ std::cout << "\t\t" << i3->first << " = " << i3->second << "\n";
+ }
+ }
+ }
+ std::cout << std::endl;
+}
+
+}
+
+namespace Rendering {
+
+ CHTMLExportRendering::CHTMLExportRendering(const CHTMLExportRendering::Settings& settings, CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions)
+: m_displayOptions(displayOptions),
+ m_filterOptions(filterOptions),
+ m_settings(settings) {}
+
+ CHTMLExportRendering::~CHTMLExportRendering() {}
+
+ const QString CHTMLExportRendering::renderEntry( const KeyTreeItem& i, CSwordKey* k) {
+
+ if (i.hasAlternativeContent()) {
+ QString ret = QString(i.settings().highlight ? "<div class=\"currententry\">" : "<div class=\"entry\">");
+ ret.append(i.getAlternativeContent());
+
+ // Q_ASSERT(i.hasChildItems());
+
+ if (!i.childList()->isEmpty()) {
+ KeyTree * const tree = i.childList();
+
+ const QList<CSwordModuleInfo*> modules = collectModules(tree);
+
+ if (modules.count() == 1) { //insert the direction into the sorrounding div
+ ret.insert( 5, QString("dir=\"%1\" ").arg((modules.first()->textDirection() == CSwordModuleInfo::LeftToRight) ? "ltr" : "rtl" ));
+ }
+
+ foreach ( KeyTreeItem* c, (*tree) ) {
+ ret.append( renderEntry( *c ) );
+ }
+ }
+
+ ret.append("</div>");
+ return ret; //WARNING: Return already here!
+ }
+
+
+ const QList<CSwordModuleInfo*>& modules( i.modules() );
+ if (modules.count() == 0) {
+ return QString(""); //no module present for rendering
+ }
+
+ boost::scoped_ptr<CSwordKey> scoped_key( !k ? CSwordKey::createInstance(modules.first()) : 0 );
+ CSwordKey* key = k ? k : scoped_key.get();
+ Q_ASSERT(key);
+
+ CSwordVerseKey* myVK = dynamic_cast<CSwordVerseKey*>(key);
+
+ if ( myVK ) myVK->Headings(1);
+
+ QString renderedText( (modules.count() > 1) ? "\n\t\t<tr>\n" : "\n" );
+ // Only insert the table stuff if we are displaying parallel.
+
+ //declarations out of the loop for optimization
+ QString entry;
+ QString keyText;
+ bool isRTL;
+ QString preverseHeading;
+ QString langAttr;
+ QString key_renderedText;
+
+ QList<CSwordModuleInfo*>::const_iterator end_modItr = modules.end();
+
+ for (QList<CSwordModuleInfo*>::const_iterator mod_Itr(modules.begin()); mod_Itr != end_modItr; ++mod_Itr) {
+ key->module(*mod_Itr);
+ key->key( i.key() );
+
+ keyText = key->key();
+ isRTL = ((*mod_Itr)->textDirection() == CSwordModuleInfo::RightToLeft);
+ entry = QString::null;
+
+ if ((*mod_Itr)->language()->isValid()) {
+ langAttr = QString("xml:lang=\"")
+ .append((*mod_Itr)->language()->abbrev())
+ .append("\" lang=\"")
+ .append((*mod_Itr)->language()->abbrev())
+ .append("\"");
+ }
+ else {
+ langAttr = QString("xml:lang=\"")
+ .append((*mod_Itr)->module()->Lang())
+ .append("\" lang=\"")
+ .append((*mod_Itr)->module()->Lang())
+ .append("\"");
+ }
+
+ key_renderedText = key->renderedText();
+
+ if (m_filterOptions.headings) {
+ (*mod_Itr)->module()->RenderText();
+ sword::AttributeValue::const_iterator it =
+ (*mod_Itr)->module()->getEntryAttributes()["Heading"]["Preverse"].begin();
+ const sword::AttributeValue::const_iterator end =
+ (*mod_Itr)->module()->getEntryAttributes()["Heading"]["Preverse"].end();
+
+ for (; it != end; ++it) {
+ preverseHeading = QString::fromUtf8(it->second.c_str());
+ //TODO: Take care of the heading type!
+ if (!preverseHeading.isEmpty()) {
+ entry.append("<div ")
+ .append(langAttr)
+ .append(" class=\"sectiontitle\">")
+ .append(preverseHeading)
+ .append("</div>");
+ }
+ }
+ }
+
+ entry.append(m_displayOptions.lineBreaks ? "<div " : "<div style=\"display: inline;\" ");
+
+ if (modules.count() == 1) { //insert only the class if we're not in a td
+ entry.append( i.settings().highlight ? "class=\"currententry\" " : "class=\"entry\" " );
+ }
+
+ entry.append(langAttr).append(isRTL ? " dir=\"rtl\"" : " dir=\"ltr\"").append(">");
+
+ //keys should normally be left-to-right, but this doesn't apply in all cases
+ entry.append("<span class=\"entryname\" dir=\"ltr\">").append(entryLink(i, *mod_Itr)).append("</span>");
+
+ if (m_settings.addText) {
+ //entry.append( QString::fromLatin1("<span %1>%2</span>").arg(langAttr).arg(key_renderedText) );
+ entry.append( key_renderedText );
+ }
+
+ if (!i.childList()->isEmpty()) {
+ KeyTree* tree(i.childList());
+
+ foreach (KeyTreeItem* c, (*tree)) {
+ entry.append( renderEntry(*c) );
+ }
+ }
+
+ entry.append("</div>");
+
+ if (modules.count() == 1) {
+ renderedText.append( "\t\t" ).append( entry ).append("\n");
+ }
+ else {
+ renderedText.append("\t\t<td class=\"")
+ .append(i.settings().highlight ? "currententry" : "entry")
+ .append("\" ")
+ .append(langAttr)
+ .append(" dir=\"")
+ .append(isRTL ? "rtl" : "ltr")
+ .append("\">\n")
+ .append( "\t\t\t" ).append( entry ).append("\n")
+ .append("\t\t</td>\n");
+ }
+ }
+
+ if (modules.count() > 1) {
+ renderedText.append("\t\t</tr>\n");
+ }
+
+ // qDebug("CHTMLExportRendering: %s", renderedText.latin1());
+ return renderedText;
+}
+
+void CHTMLExportRendering::initRendering() {
+ //CPointers::backend()->setDisplayOptions( m_displayOptions );
+ CPointers::backend()->setFilterOptions( m_filterOptions );
+}
+
+const QString CHTMLExportRendering::finishText( const QString& text, KeyTree& tree ) {
+ const QList<CSwordModuleInfo*> modules = collectModules(&tree);
+
+ const CLanguageMgr::Language* const lang = modules.first()->language();
+
+ CDisplayTemplateMgr* tMgr = CPointers::displayTemplateManager();
+ CDisplayTemplateMgr::Settings settings;
+ settings.modules = modules;
+ settings.langAbbrev = ((modules.count() == 1) && lang->isValid()) ? lang->abbrev() : "unknown";
+ if (modules.count() == 1)
+ settings.pageDirection = ((modules.first()->textDirection() == CSwordModuleInfo::LeftToRight) ? "ltr" : "rtl");
+ else
+ settings.pageDirection = QString::null;
+
+ return tMgr->fillTemplate(QObject::tr("Export"), text, settings);
+}
+
+/*!
+ \fn CHTMLExportRendering::entryLink( KeyTreeItem& item )
+ */
+const QString CHTMLExportRendering::entryLink( const KeyTreeItem& item, CSwordModuleInfo* ) {
+ return item.key();
+}
+
+}//end of namespace "Rendering"
diff --git a/src/backend/rendering/chtmlexportrendering.h b/src/backend/rendering/chtmlexportrendering.h
new file mode 100644
index 0000000..6a8153e
--- /dev/null
+++ b/src/backend/rendering/chtmlexportrendering.h
@@ -0,0 +1,58 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef RENDERINGCHTMLEXPORTRENDERING_H
+#define RENDERINGCHTMLEXPORTRENDERING_H
+
+#include "backend/managers/cswordbackend.h"
+#include "ctextrendering.h"
+
+#include "backend/config/cbtconfig.h"
+
+namespace Rendering {
+
+ /**
+ * This CTextRenerding implementation
+ * creates HTML specially made for export as HTML files.
+ * @short HTML rendering for export.
+ * @author The BibleTime team
+ */
+
+class CHTMLExportRendering : public CTextRendering {
+
+public:
+ struct Settings {
+ Settings(const bool text = true) {
+ addText = text;
+ };
+
+ bool addText;
+ };
+
+ CHTMLExportRendering(
+ const Settings& settings,
+ CSwordBackend::DisplayOptions displayOptions = CBTConfig::getDisplayOptionDefaults(),
+ CSwordBackend::FilterOptions filterOptions = CBTConfig::getFilterOptionDefaults()
+ );
+ virtual ~CHTMLExportRendering();
+
+protected:
+ virtual const QString renderEntry( const KeyTreeItem&, CSwordKey* = 0 );
+ virtual const QString finishText( const QString&, KeyTree& tree );
+ virtual const QString entryLink( const KeyTreeItem& item, CSwordModuleInfo* module );
+ virtual void initRendering();
+
+ CSwordBackend::DisplayOptions m_displayOptions;
+ CSwordBackend::FilterOptions m_filterOptions;
+ Settings m_settings;
+};
+
+}
+
+#endif
diff --git a/src/backend/rendering/cplaintextexportrendering.cpp b/src/backend/rendering/cplaintextexportrendering.cpp
new file mode 100644
index 0000000..d99cff3
--- /dev/null
+++ b/src/backend/rendering/cplaintextexportrendering.cpp
@@ -0,0 +1,53 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+//Backend includes
+#include "cplaintextexportrendering.h"
+#include "backend/keys/cswordkey.h"
+
+//Util
+#include <boost/scoped_ptr.hpp>
+
+namespace Rendering {
+
+CPlainTextExportRendering::CPlainTextExportRendering(const CPlainTextExportRendering::Settings& settings, CSwordBackend::DisplayOptions displayOptions, CSwordBackend::FilterOptions filterOptions)
+ : CHTMLExportRendering(settings, displayOptions, filterOptions) {}
+
+CPlainTextExportRendering::~CPlainTextExportRendering() {}
+
+const QString CPlainTextExportRendering::renderEntry( const KeyTreeItem& i, CSwordKey* ) {
+ if (!m_settings.addText) {
+ return QString(i.key()).append("\n");
+ }
+
+ QList<CSwordModuleInfo*> modules = i.modules();
+ boost::scoped_ptr<CSwordKey> key( CSwordKey::createInstance(modules.first()) );
+ QString renderedText = QString(i.key()).append(":\n");
+
+ QString entry;
+ // for (CSwordModuleInfo* m = modules.first(); m; m = modules.next()) {
+ QList<CSwordModuleInfo*>::iterator end_it = modules.end();
+
+ for (QList<CSwordModuleInfo*>::iterator it(modules.begin()); it != end_it; ++it) {
+ key->module(*it);
+ key->key( i.key() );
+
+ //ToDo: Check this code
+ entry.append(key->strippedText()).append("\n");
+ renderedText.append( entry );
+ }
+
+ return renderedText;
+}
+
+const QString CPlainTextExportRendering::finishText( const QString& oldText, KeyTree& ) {
+ return oldText;
+}
+
+}
diff --git a/src/backend/rendering/cplaintextexportrendering.h b/src/backend/rendering/cplaintextexportrendering.h
new file mode 100644
index 0000000..9ec388b
--- /dev/null
+++ b/src/backend/rendering/cplaintextexportrendering.h
@@ -0,0 +1,40 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef RENDERINGCPLAINTEXTEXPORTRENDERING_H
+#define RENDERINGCPLAINTEXTEXPORTRENDERING_H
+
+#include "chtmlexportrendering.h"
+
+namespace Rendering {
+
+ /**
+ * This implementation can be used to export content as plain text.
+ * @short Text rendering as plain text.
+ * @author The BibleTime team
+ */
+
+class CPlainTextExportRendering : public CHTMLExportRendering {
+
+public:
+ CPlainTextExportRendering(
+ const Settings& settings,
+ CSwordBackend::DisplayOptions displayOptions = CBTConfig::getDisplayOptionDefaults(),
+ CSwordBackend::FilterOptions filterOptions = CBTConfig::getFilterOptionDefaults()
+ );
+ virtual ~CPlainTextExportRendering();
+
+protected:
+ virtual const QString renderEntry( const KeyTreeItem&, CSwordKey* = 0 );
+ virtual const QString finishText( const QString&, KeyTree& tree );
+};
+
+}
+
+#endif
diff --git a/src/backend/rendering/ctextrendering.cpp b/src/backend/rendering/ctextrendering.cpp
new file mode 100644
index 0000000..c7ac0bd
--- /dev/null
+++ b/src/backend/rendering/ctextrendering.cpp
@@ -0,0 +1,263 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#include "ctextrendering.h"
+
+//BibleTime
+#include "backend/keys/cswordkey.h"
+#include "backend/keys/cswordversekey.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "backend/managers/cdisplaytemplatemgr.h"
+#include "backend/managers/creferencemanager.h"
+
+#include <boost/scoped_ptr.hpp>
+#include "util/ctoolclass.h"
+
+//Sword
+#include <swkey.h>
+
+//Qt
+#include <QRegExp>
+
+
+using namespace Rendering;
+
+CTextRendering::KeyTreeItem::KeyTreeItem(const QString& key, CSwordModuleInfo const * mod, const Settings settings )
+ : m_settings( settings ),
+ m_moduleList(),
+ m_key( key ),
+ m_childList(),
+ m_stopKey( QString::null ),
+ m_alternativeContent( QString::null )
+{
+ m_moduleList.append( const_cast<CSwordModuleInfo*>(mod) ); //BAD CODE
+}
+
+CTextRendering::KeyTreeItem::KeyTreeItem(const QString& content, const Settings settings )
+ : m_settings( settings ),
+ m_moduleList(),
+ m_key( QString::null ),
+ m_childList(),
+ m_stopKey( QString::null ),
+ m_alternativeContent( content )
+{
+}
+
+CTextRendering::KeyTreeItem::KeyTreeItem(const QString& key, const QList<CSwordModuleInfo*>& mods, const Settings settings )
+ : m_settings( settings ),
+ m_moduleList( mods ),
+ m_key( key ),
+ m_childList(),
+ m_stopKey( QString::null ),
+ m_alternativeContent( QString::null )
+{
+}
+
+CTextRendering::KeyTreeItem::KeyTreeItem()
+ : m_settings(),
+ m_moduleList(),
+ m_key(QString::null),
+ m_childList(),
+ m_stopKey(QString::null),
+ m_alternativeContent(QString::null)
+{
+}
+
+CTextRendering::KeyTreeItem::KeyTreeItem(const KeyTreeItem& i)
+ : m_settings( i.m_settings ),
+ m_moduleList( i.m_moduleList ),
+ m_key( i.m_key ),
+ m_childList(),
+ m_stopKey( i.m_stopKey ),
+ m_alternativeContent( i.m_alternativeContent )
+{
+ foreach(KeyTreeItem* item, (*i.childList())){
+ m_childList.append(new KeyTreeItem((*item))); //deep copy
+ }
+
+}
+
+CTextRendering::KeyTreeItem::~KeyTreeItem() {
+ qDeleteAll(m_childList);
+}
+
+CTextRendering::KeyTreeItem::KeyTreeItem(const QString& startKey, const QString& stopKey, CSwordModuleInfo* module, const Settings settings)
+: m_settings( settings ),
+m_moduleList(),
+m_key( startKey ),
+m_childList(),
+m_stopKey( stopKey ),
+m_alternativeContent( QString::null ) {
+ Q_ASSERT(module);
+ m_moduleList.append(module);
+
+ //use the start and stop key to ceate our child items
+
+ if (module->type() == CSwordModuleInfo::Bible) {
+ CSwordVerseKey start(module);
+ start.key(startKey);
+
+ CSwordVerseKey stop(module);
+ stop.key(stopKey);
+
+ if (!m_key.isEmpty() && !m_stopKey.isEmpty()) { //we have a range of keys
+ bool ok = true;
+
+ while (ok && ((start < stop) || (start == stop)) ) { //range
+ m_childList.append(
+ new KeyTreeItem(start.key(), module, KeyTreeItem::Settings(false, settings.keyRenderingFace))
+ );
+
+
+ ok = start.next(CSwordVerseKey::UseVerse);
+ }
+ }
+ else if (m_key.isEmpty()) {
+ m_childList.append( new KeyTreeItem(startKey, module, KeyTreeItem::Settings(false, settings.keyRenderingFace)) );
+ }
+ }
+ else if ((module->type() == CSwordModuleInfo::Lexicon) || (module->type() == CSwordModuleInfo::Commentary) ) {
+ m_childList.append( new KeyTreeItem(startKey, module, KeyTreeItem::Settings(false, KeyTreeItem::Settings::NoKey)) );
+ }
+ else if (module->type() == CSwordModuleInfo::GenericBook) {
+ m_childList.append( new KeyTreeItem(startKey, module, KeyTreeItem::Settings(false, KeyTreeItem::Settings::NoKey)) );
+ }
+
+ //make it into "<simple|range> (modulename)"
+
+ if (startKey == stopKey) {
+ m_alternativeContent = startKey;
+ }
+ else {
+ sword::VerseKey vk(startKey.toUtf8().constData(), stopKey.toUtf8().constData());
+
+ if (vk.LowerBound().Book() != vk.UpperBound().Book()) {
+ m_alternativeContent = QString::fromUtf8(vk.getRangeText());
+ }
+ else if (vk.LowerBound().Chapter() != vk.UpperBound().Chapter()) {
+ m_alternativeContent = QString("%1 - %2:%3")
+ .arg(QString::fromUtf8(vk.LowerBound().getText()))
+ .arg(vk.UpperBound().Chapter())
+ .arg(vk.UpperBound().Verse());
+ }
+ else { //only verses differ (same book, same chapter)
+ m_alternativeContent = QString("%1 - %2")
+ .arg(QString::fromUtf8(vk.LowerBound().getText()))
+ .arg(vk.UpperBound().Verse());
+ }
+ }
+
+ m_alternativeContent.append(" (").append(module->name()).append(")");
+ m_alternativeContent.prepend("<div class=\"rangeheading\" dir=\"ltr\">").append("</div>"); //insert the right tags
+}
+
+const QString& CTextRendering::KeyTreeItem::getAlternativeContent() const {
+ return m_alternativeContent;
+}
+
+const QList<CSwordModuleInfo*> CTextRendering::collectModules(KeyTree* const tree) const {
+ //collect all modules which are available and used by child items
+ QList<CSwordModuleInfo*> modules;
+
+ foreach (KeyTreeItem* c, (*tree)) {
+ Q_ASSERT(c);
+ foreach (CSwordModuleInfo* mod, c->modules()) {
+ if (!modules.contains(mod)) {
+ modules.append(mod);
+ }
+ }
+ }
+ return modules;
+}
+
+const QString CTextRendering::renderKeyTree( KeyTree& tree ) {
+ initRendering();
+
+ QList<CSwordModuleInfo*> modules = collectModules(&tree);
+ QString t;
+
+ //optimization for entries with the same key
+ boost::scoped_ptr<CSwordKey> key(
+ (modules.count() == 1) ? CSwordKey::createInstance(modules.first()) : 0
+ );
+
+ foreach (KeyTreeItem* c, tree) {
+ if (modules.count() == 1) { //this optimizes the rendering, only one key created for all items
+ key->key( c->key() );
+ t.append( renderEntry( *c, key.get()) );
+ }
+ else {
+ t.append( renderEntry( *c ) );
+ }
+ }
+
+ return finishText(t, tree);
+}
+
+const QString CTextRendering::renderKeyRange( const QString& start, const QString& stop, const QList<CSwordModuleInfo*>& modules, const QString& highlightKey, const KeyTreeItem::Settings& keySettings ) {
+
+ CSwordModuleInfo* module = modules.first();
+ //qWarning( "renderKeyRange start %s stop %s \n", start.latin1(), stop.latin1() );
+
+ boost::scoped_ptr<CSwordKey> lowerBound( CSwordKey::createInstance(module) );
+ lowerBound->key(start);
+
+ boost::scoped_ptr<CSwordKey> upperBound( CSwordKey::createInstance(module) );
+ upperBound->key(stop);
+
+ sword::SWKey* sw_start = dynamic_cast<sword::SWKey*>(lowerBound.get());
+ sword::SWKey* sw_stop = dynamic_cast<sword::SWKey*>(upperBound.get());
+
+ Q_ASSERT((*sw_start == *sw_stop) || (*sw_start < *sw_stop));
+
+ if (*sw_start == *sw_stop) { //same key, render single key
+ return renderSingleKey(lowerBound->key(), modules);
+ }
+ else if (*sw_start < *sw_stop) { // Render range
+ KeyTree tree;
+ KeyTreeItem::Settings settings = keySettings;
+
+ CSwordVerseKey* vk_start = dynamic_cast<CSwordVerseKey*>(lowerBound.get());
+ Q_ASSERT(vk_start);
+
+ CSwordVerseKey* vk_stop = dynamic_cast<CSwordVerseKey*>(upperBound.get());
+ Q_ASSERT(vk_stop);
+
+ bool ok = true;
+ while (ok && ((*vk_start < *vk_stop) || (*vk_start == *vk_stop))) {
+ //make sure the key given by highlightKey gets marked as current key
+ settings.highlight = (!highlightKey.isEmpty() ? (vk_start->key() == highlightKey) : false);
+
+ /*TODO: We need to take care of linked verses if we render one or (esp) more modules
+ If the verses 2,3,4,5 are linked to 1, it should be displayed as one entry with the caption 1-5 */
+
+ if (vk_start->Chapter() == 0){ //range was 0:0-1:x, render 0:0 first and jump to 1:0
+ vk_start->Verse(0);
+ tree.append( new KeyTreeItem(vk_start->key(), modules, settings) );
+ vk_start->Chapter(1);
+ vk_start->Verse(0);
+ }
+ tree.append( new KeyTreeItem(vk_start->key(), modules, settings) );
+ ok = vk_start->next(CSwordVerseKey::UseVerse);
+ }
+
+ return renderKeyTree(tree);
+ }
+
+ return QString::null;
+}
+
+const QString CTextRendering::renderSingleKey( const QString& key, const QList<CSwordModuleInfo*>& moduleList, const KeyTreeItem::Settings& settings ) {
+ KeyTree tree;
+ tree.append( new KeyTreeItem(key, moduleList, settings) );
+
+ return renderKeyTree(tree);
+}
+
+
diff --git a/src/backend/rendering/ctextrendering.h b/src/backend/rendering/ctextrendering.h
new file mode 100644
index 0000000..403962b
--- /dev/null
+++ b/src/backend/rendering/ctextrendering.h
@@ -0,0 +1,128 @@
+/*********
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2008 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License version 2.0.
+*
+**********/
+
+#ifndef CTEXTRENDERING_H
+#define CTEXTRENDERING_H
+
+//BT includes
+class CSwordModuleInfo;
+//#include "util/autoptrvector.h"
+
+//QT includes
+#include <QString>
+#include <QList>
+
+class CSwordKey;
+
+/**
+ * CTextRendering is BibleTime's place where the actual rendering takes place.
+ * It provides several methods to convert an abstract tree of items
+ * into a string of html.
+ *
+ * See the implementations @ref CHTMLExportRendering and especially @ref CDisplayRendering.
+ * @short Text rendering based on trees
+ * @author The BibleTime team
+*/
+
+namespace Rendering {
+
+class CTextRendering {
+
+public:
+
+ class KeyTreeItem;
+ typedef QList<KeyTreeItem*> KeyTree;
+
+ class KeyTreeItem {
+ public:
+
+ struct Settings {
+ enum KeyRenderingFace {
+ NoKey, //< means no key shown at all
+ SimpleKey, //< means only versenumber or only lexicon entry name
+ CompleteShort, //< means key like "Gen 1:1"
+ CompleteLong //< means "Genesis 1:1"
+ };
+
+ Settings(const bool highlight = false, KeyRenderingFace keyRendering = SimpleKey) : highlight(highlight), keyRenderingFace(keyRendering) {}
+
+ bool highlight;
+ KeyRenderingFace keyRenderingFace;
+ };
+
+ KeyTreeItem(const QString& key, CSwordModuleInfo const * module, const Settings settings);
+ KeyTreeItem(const QString& key, const QList<CSwordModuleInfo*>& modules, const Settings settings);
+ KeyTreeItem(const QString& startKey, const QString& stopKey, CSwordModuleInfo* module, const Settings settings);
+ KeyTreeItem(const QString& content, const Settings settings);
+ KeyTreeItem(const KeyTreeItem& i);
+
+ virtual ~KeyTreeItem();
+
+ const QString& getAlternativeContent() const;
+ inline void setAlternativeContent(const QString& newContent) {
+ m_alternativeContent = newContent;
+ };
+
+ inline bool hasAlternativeContent() const {
+ return !m_alternativeContent.isNull();
+ };
+
+ inline const QList<CSwordModuleInfo*>& modules() const {
+ return m_moduleList;
+ };
+
+ inline const QString& key() const {
+ return m_key;
+ };
+
+ inline const Settings& settings() const {
+ return m_settings;
+ };
+
+ inline KeyTree* childList() const;
+// inline const bool hasChildItems() const;
+
+ protected:
+ KeyTreeItem();
+
+ Settings m_settings;
+ QList<CSwordModuleInfo*> m_moduleList;
+ QString m_key;
+ mutable KeyTree m_childList;
+
+ QString m_stopKey;
+ QString m_alternativeContent;
+ };
+
+ virtual ~CTextRendering() {}
+
+ const QString renderKeyTree( KeyTree& );
+
+ const QString renderKeyRange( const QString& start, const QString& stop, const QList<CSwordModuleInfo*>& modules, const QString& hightlightKey = QString::null, const KeyTreeItem::Settings& settings = KeyTreeItem::Settings() );
+
+ const QString renderSingleKey( const QString& key, const QList<CSwordModuleInfo*>&, const KeyTreeItem::Settings& settings = KeyTreeItem::Settings() );
+
+protected:
+ const QList<CSwordModuleInfo*> collectModules(KeyTree* const tree) const;
+ virtual const QString renderEntry( const KeyTreeItem&, CSwordKey* = 0 ) = 0;
+ virtual const QString finishText( const QString&, KeyTree& tree ) = 0;
+ virtual void initRendering() = 0;
+};
+
+inline CTextRendering::KeyTree* CTextRendering::KeyTreeItem::childList() const{
+ return &m_childList;
+}
+//
+//inline const bool CTextRendering::KeyTreeItem::hasChildItems() const {
+// return !m_childList.isEmpty();
+//}
+
+}
+
+#endif