summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorRoberto C. Sanchez <roberto@connexer.com>2014-10-21 22:48:27 -0400
committerRoberto C. Sanchez <roberto@connexer.com>2014-10-21 22:48:27 -0400
commitdd2f7ce46df53f2c377c02d1bf4df8adcf092072 (patch)
tree51d4bd5d66a45a24784695c4e99b452b417dc3d1 /src/backend
parentb954e6dbcceaba3b50aca624e1bddc6db4830829 (diff)
Imported Upstream version 2.3
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/bookshelfmodel/btbookshelfmodel.cpp184
-rw-r--r--src/backend/bookshelfmodel/btbookshelfmodel.h67
-rw-r--r--src/backend/bookshelfmodel/btbookshelftreemodel.cpp474
-rw-r--r--src/backend/bookshelfmodel/btbookshelftreemodel.h114
-rw-r--r--src/backend/bookshelfmodel/btcheckstatefilterproxymodel.cpp70
-rw-r--r--src/backend/bookshelfmodel/btcheckstatefilterproxymodel.h47
-rw-r--r--src/backend/bookshelfmodel/btmodulenamefilterproxymodel.cpp43
-rw-r--r--src/backend/bookshelfmodel/btmodulenamefilterproxymodel.h34
-rw-r--r--src/backend/bookshelfmodel/categoryitem.cpp23
-rw-r--r--src/backend/bookshelfmodel/categoryitem.h54
-rw-r--r--src/backend/bookshelfmodel/distributionitem.cpp23
-rw-r--r--src/backend/bookshelfmodel/distributionitem.h43
-rw-r--r--src/backend/bookshelfmodel/item.cpp57
-rw-r--r--src/backend/bookshelfmodel/item.h170
-rw-r--r--src/backend/bookshelfmodel/languageitem.cpp23
-rw-r--r--src/backend/bookshelfmodel/languageitem.h50
-rw-r--r--src/backend/bookshelfmodel/moduleitem.cpp25
-rw-r--r--src/backend/bookshelfmodel/moduleitem.h41
-rw-r--r--src/backend/keys/cswordversekey.cpp7
-rw-r--r--src/backend/rendering/cdisplayrendering.cpp5
20 files changed, 1551 insertions, 3 deletions
diff --git a/src/backend/bookshelfmodel/btbookshelfmodel.cpp b/src/backend/bookshelfmodel/btbookshelfmodel.cpp
new file mode 100644
index 0000000..6764a88
--- /dev/null
+++ b/src/backend/bookshelfmodel/btbookshelfmodel.cpp
@@ -0,0 +1,184 @@
+/*********
+*
+* In the name of the Father, and of the Son, and of the Holy Spirit.
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License
+* version 2.0.
+*
+**********/
+
+#include "backend/bookshelfmodel/btbookshelfmodel.h"
+
+#include <QSet>
+#include "util/cresmgr.h"
+#include "util/directoryutil.h"
+
+BtBookshelfModel::BtBookshelfModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+ // Intentionally empty
+}
+
+BtBookshelfModel::~BtBookshelfModel() {
+ // Intentionally empty
+}
+
+int BtBookshelfModel::rowCount(const QModelIndex &parent) const {
+ return m_data.size();
+}
+
+QVariant BtBookshelfModel::data(const QModelIndex &index, int role) const {
+ if (!index.isValid() || index.column() != 0 || index.parent().isValid()) {
+ return QVariant();
+ }
+ int row(index.row());
+ if (row >= m_data.size()) return QVariant();
+
+ switch (role) {
+ case ModuleNameRole: // Qt::DisplayRole
+ return m_data.at(row)->name();
+ case ModuleIconRole: // Qt::DecorationRole
+ return categoryIcon(m_data.at(row)->category());
+ case ModulePointerRole:
+ return qVariantFromValue((void*) m_data.at(row));
+ default:
+ return QVariant();
+ }
+}
+
+QVariant BtBookshelfModel::headerData(int section, Qt::Orientation orientation,
+ int role) const
+{
+ if (role == Qt::DisplayRole && orientation == Qt::Horizontal &&
+ section == 0)
+ {
+ return tr("Module");
+ }
+
+ return QVariant();
+}
+
+QIcon BtBookshelfModel::categoryIcon(const CSwordModuleInfo::Category &category)
+{
+ typedef util::filesystem::DirectoryUtil DU;
+
+ switch (category) {
+ case CSwordModuleInfo::Bibles:
+ return DU::getIcon(CResMgr::categories::bibles::icon);
+ case CSwordModuleInfo::Commentaries:
+ return DU::getIcon(CResMgr::categories::commentaries::icon);
+ case CSwordModuleInfo::Books:
+ return DU::getIcon(CResMgr::categories::books::icon);
+ case CSwordModuleInfo::Cult:
+ return DU::getIcon(CResMgr::categories::cults::icon);
+ case CSwordModuleInfo::Images:
+ return DU::getIcon(CResMgr::categories::images::icon);
+ case CSwordModuleInfo::DailyDevotional:
+ return DU::getIcon(CResMgr::categories::dailydevotional::icon);
+ case CSwordModuleInfo::Lexicons:
+ return DU::getIcon(CResMgr::categories::lexicons::icon);
+ case CSwordModuleInfo::Glossary:
+ return DU::getIcon(CResMgr::categories::glossary::icon);
+ case CSwordModuleInfo::UnknownCategory:
+ default:
+ return QIcon();
+ }
+}
+
+QString BtBookshelfModel::categoryName(
+ const CSwordModuleInfo::Category &category)
+{
+ switch (category) {
+ case CSwordModuleInfo::Bibles:
+ return tr("Bibles");
+ case CSwordModuleInfo::Commentaries:
+ return tr("Commentaries");
+ case CSwordModuleInfo::Books:
+ return tr("Books");
+ case CSwordModuleInfo::Cult:
+ return tr("Cults/Unorthodox");
+ case CSwordModuleInfo::Images:
+ return tr("Maps and Images");
+ case CSwordModuleInfo::DailyDevotional:
+ return tr("Daily Devotionals");
+ case CSwordModuleInfo::Lexicons:
+ return tr("Lexicons and Dictionaries");
+ case CSwordModuleInfo::Glossary:
+ return tr("Glossaries");
+ default:
+ return tr("Unknown");
+ }
+}
+
+QString BtBookshelfModel::languageName(
+ const CLanguageMgr::Language *language)
+{
+ return language->translatedName();
+}
+
+void BtBookshelfModel::clear() {
+ beginRemoveRows(QModelIndex(), 0, m_data.size() - 1);
+ m_data.clear();
+ endRemoveRows();
+}
+
+void BtBookshelfModel::addModule(CSwordModuleInfo * const module) {
+ Q_ASSERT(module != 0);
+
+ if (m_data.contains(module)) return;
+
+ const int index(m_data.size());
+ beginInsertRows(QModelIndex(), index, index);
+ m_data.append(module);
+ endInsertRows();
+}
+
+void BtBookshelfModel::addModules(const QList<CSwordModuleInfo *> &modules) {
+ addModules(modules.toSet());
+}
+
+void BtBookshelfModel::addModules(const QSet<CSwordModuleInfo *> &modules) {
+ QList<CSwordModuleInfo *> newModules;
+ Q_FOREACH(CSwordModuleInfo *module, modules) {
+ if (!m_data.contains(module)) {
+ newModules.append(module);
+ }
+ }
+
+ if (newModules.isEmpty()) return;
+
+ beginInsertRows(QModelIndex(), m_data.size(),
+ m_data.size() + newModules.size() - 1);
+ m_data.append(newModules);
+ endInsertRows();
+}
+
+void BtBookshelfModel::removeModule(CSwordModuleInfo * const module) {
+ const int index(m_data.indexOf(module));
+ if (index == -1) return;
+
+ beginRemoveRows(QModelIndex(), index, index);
+ m_data.removeAt(index);
+ endRemoveRows();
+}
+
+void BtBookshelfModel::removeModules(const QList<CSwordModuleInfo *> &modules) {
+ removeModules(modules.toSet());
+}
+
+void BtBookshelfModel::removeModules(const QSet<CSwordModuleInfo *> &modules) {
+ // This is inefficient, since signals are emitted for each removed module:
+ Q_FOREACH(CSwordModuleInfo *module, modules) {
+ removeModule(module);
+ }
+}
+
+CSwordModuleInfo* BtBookshelfModel::getModule(const QString &name) const {
+ Q_FOREACH(CSwordModuleInfo *module, m_data) {
+ if (module->name() == name) return module;
+ }
+ return 0;
+}
diff --git a/src/backend/bookshelfmodel/btbookshelfmodel.h b/src/backend/bookshelfmodel/btbookshelfmodel.h
new file mode 100644
index 0000000..c268d2c
--- /dev/null
+++ b/src/backend/bookshelfmodel/btbookshelfmodel.h
@@ -0,0 +1,67 @@
+/*********
+*
+* In the name of the Father, and of the Son, and of the Holy Spirit.
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License
+* version 2.0.
+*
+**********/
+
+#ifndef BTBOOKSHELFMODEL_H
+#define BTBOOKSHELFMODEL_H
+
+#include <QAbstractListModel>
+
+#include "backend/drivers/cswordmoduleinfo.h"
+
+class BtBookshelfModel: public QAbstractListModel {
+ Q_OBJECT
+ public:
+ enum ModuleRole {
+ ModuleNameRole = Qt::DisplayRole,
+ ModuleIconRole = Qt::DecorationRole,
+ ModulePointerRole = Qt::UserRole,
+ ModuleCategoryRole = Qt::UserRole + 1,
+ ModuleLanguageRole = Qt::UserRole + 2,
+ UserRole = Qt::UserRole + 100
+ };
+
+ BtBookshelfModel(QObject *parent = 0);
+ virtual ~BtBookshelfModel();
+
+ virtual int rowCount(const QModelIndex &parent) const;
+ virtual QVariant data(const QModelIndex &index, int role) const;
+ virtual QVariant headerData(int section, Qt::Orientation orientation,
+ int role = Qt::DisplayRole) const;
+
+ inline CSwordModuleInfo *module(const QModelIndex &index) const {
+ return (CSwordModuleInfo *)
+ data(index, BtBookshelfModel::ModulePointerRole)
+ .value<void *>();
+ }
+
+ static QIcon categoryIcon(const CSwordModuleInfo::Category &category);
+ static QString categoryName(const CSwordModuleInfo::Category &category);
+ static QString languageName(const CLanguageMgr::Language *language);
+
+ void clear();
+ void addModule(CSwordModuleInfo * const module);
+ void addModules(const QSet<CSwordModuleInfo *> &modules);
+ void addModules(const QList<CSwordModuleInfo *> &modules);
+ void removeModule(CSwordModuleInfo * const module);
+ void removeModules(const QSet<CSwordModuleInfo *> &modules);
+ void removeModules(const QList<CSwordModuleInfo *> &modules);
+
+ CSwordModuleInfo* getModule(const QString &name) const;
+ inline const QList<CSwordModuleInfo *> &modules() const {
+ return m_data;
+ }
+
+ protected:
+ QList<CSwordModuleInfo *> m_data;
+};
+
+#endif // BTBOOKSHELFMODEL_H
diff --git a/src/backend/bookshelfmodel/btbookshelftreemodel.cpp b/src/backend/bookshelfmodel/btbookshelftreemodel.cpp
new file mode 100644
index 0000000..47526e9
--- /dev/null
+++ b/src/backend/bookshelfmodel/btbookshelftreemodel.cpp
@@ -0,0 +1,474 @@
+/*********
+*
+* In the name of the Father, and of the Son, and of the Holy Spirit.
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License
+* version 2.0.
+*
+**********/
+
+#include "backend/bookshelfmodel/btbookshelftreemodel.h"
+
+#include <QQueue>
+#include <QSet>
+#include "backend/bookshelfmodel/categoryitem.h"
+#include "backend/bookshelfmodel/distributionitem.h"
+#include "backend/bookshelfmodel/languageitem.h"
+#include "backend/bookshelfmodel/moduleitem.h"
+
+using namespace BookshelfModel;
+
+BtBookshelfTreeModel::BtBookshelfTreeModel(QObject *parent)
+ : QAbstractItemModel(parent), m_sourceModel(0), m_rootItem(new RootItem),
+ m_checkable(false), m_defaultChecked(false)
+{
+ m_groupingOrder.push_back(GROUP_CATEGORY);
+ m_groupingOrder.push_back(GROUP_LANGUAGE);
+}
+
+BtBookshelfTreeModel::~BtBookshelfTreeModel() {
+ delete m_rootItem;
+}
+
+int BtBookshelfTreeModel::rowCount(const QModelIndex &parent) const {
+ return getItem(parent)->children().size();
+}
+
+int BtBookshelfTreeModel::columnCount(const QModelIndex &parent) const {
+ return 1;
+}
+
+bool BtBookshelfTreeModel::hasChildren(const QModelIndex &parent) const {
+ return !getItem(parent)->children().isEmpty();
+}
+
+QModelIndex BtBookshelfTreeModel::index(int row, int column,
+ const QModelIndex &parent) const
+{
+ if (!hasIndex(row, column, parent)) return QModelIndex();
+
+ Item *parentItem(getItem(parent));
+ Item *childItem(parentItem->childAt(row));
+ if (childItem != 0) {
+ return createIndex(row, column, childItem);
+ } else {
+ return QModelIndex();
+ }
+}
+
+QModelIndex BtBookshelfTreeModel::parent(const QModelIndex &index) const {
+ if (!index.isValid()) return QModelIndex();
+
+ Item *childItem(static_cast<Item*>(index.internalPointer()));
+ Q_ASSERT(childItem != 0);
+ Item *parentItem(childItem->parent());
+ Q_ASSERT(parentItem != 0);
+
+ if (parentItem == m_rootItem) {
+ return QModelIndex();
+ }
+ return createIndex(parentItem->childIndex(), 0, parentItem);
+}
+
+QVariant BtBookshelfTreeModel::data(const QModelIndex &index, int role) const {
+ typedef util::filesystem::DirectoryUtil DU;
+
+ if (!index.isValid() || index.column() != 0) {
+ return QVariant();
+ }
+
+ Item *i(static_cast<Item*>(index.internalPointer()));
+ Q_ASSERT(i != 0);
+ switch (role) {
+ case Qt::DisplayRole:
+ return i->name();
+ case Qt::CheckStateRole:
+ if (!m_checkable) break;
+ case BtBookshelfTreeModel::CheckStateRole:
+ return i->checkState();
+ case Qt::DecorationRole:
+ return i->icon();
+ case BtBookshelfModel::ModulePointerRole:
+ if (i->type() == Item::ITEM_MODULE) {
+ ModuleItem *mi(dynamic_cast<ModuleItem *>(i));
+ if (mi != 0) {
+ return qVariantFromValue((void*) mi->moduleInfo());
+ }
+ }
+ return 0;
+ default:
+ break;
+ }
+ return QVariant();
+}
+
+bool BtBookshelfTreeModel::setData(const QModelIndex &itemIndex,
+ const QVariant &value,
+ int role)
+{
+ typedef QPair<Item *, QModelIndex> IP;
+
+ if (role == Qt::CheckStateRole) {
+ bool ok;
+ Qt::CheckState newState((Qt::CheckState) value.toInt(&ok));
+ if (ok && newState != Qt::PartiallyChecked) {
+ Item *i(static_cast<Item*>(itemIndex.internalPointer()));
+ Q_ASSERT(i != 0);
+ // Recursively (un)check all children:
+ QList<IP> q;
+ q.append(IP(i, itemIndex));
+ while (!q.isEmpty()) {
+ const IP p(q.takeFirst());
+ Item *item(p.first);
+ item->setCheckState(newState);
+ emit dataChanged(p.second, p.second);
+ const QList<Item*> &children(item->children());
+ for (int i(0); i < children.size(); i++) {
+ q.append(IP(children.at(i), index(i, 0, p.second)));
+ }
+ }
+
+ // Change check state of the item itself
+ i->setCheckState(newState);
+ emit dataChanged(itemIndex, itemIndex);
+
+ // Recursively change parent check states.
+ resetParentCheckStates(itemIndex.parent());
+
+ return true;
+ } // if (ok && newState != Qt::PartiallyChecked)
+ } // if (role == Qt::CheckStateRole)
+ return false;
+}
+
+Qt::ItemFlags BtBookshelfTreeModel::flags(const QModelIndex &index) const {
+ if (!index.isValid()) return 0;
+
+ Qt::ItemFlags f(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
+
+ if (m_checkable) {
+ f |= Qt::ItemIsUserCheckable;
+
+ Item *i(static_cast<Item*>(index.internalPointer()));
+ Q_ASSERT(i != 0);
+
+ if (i->type() != Item::ITEM_MODULE) {
+ f |= Qt::ItemIsTristate;
+ }
+ }
+
+ return f;
+}
+
+QVariant BtBookshelfTreeModel::headerData(int section,
+ Qt::Orientation orientation,
+ int role) const
+{
+ if (orientation == Qt::Horizontal) {
+ return m_sourceModel->headerData(section, orientation, role);
+ }
+ return QVariant();
+}
+
+void BtBookshelfTreeModel::setSourceModel(QAbstractListModel *sourceModel) {
+ if (m_sourceModel == sourceModel) return;
+
+ if (m_sourceModel != 0) {
+ disconnect(this, SLOT(moduleInserted(QModelIndex,int,int)));
+ disconnect(this, SLOT(moduleRemoved(QModelIndex,int,int)));
+ disconnect(this, SLOT(moduleDataChanged(QModelIndex,QModelIndex)));
+ beginRemoveRows(QModelIndex(), 0, m_rootItem->children().size() - 1);
+ delete m_rootItem;
+ m_modules.clear();
+ m_rootItem = new RootItem;
+ endRemoveRows();
+ }
+
+ m_sourceModel = sourceModel;
+
+ if (sourceModel != 0) {
+ connect(sourceModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
+ this, SLOT(moduleRemoved(QModelIndex,int,int)));
+ connect(sourceModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(moduleInserted(QModelIndex,int,int)));
+ connect(sourceModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)),
+ this, SLOT(moduleDataChanged(QModelIndex, QModelIndex)));
+
+ BtBookshelfModel *m(dynamic_cast<BtBookshelfModel*>(sourceModel));
+ if (m != 0) {
+ Q_FOREACH(CSwordModuleInfo *module, m->modules()) {
+ addModule(module, m_defaultChecked);
+ }
+ } else {
+ for (int i(0); i < sourceModel->rowCount(); i++) {
+ CSwordModuleInfo *module(
+ static_cast<CSwordModuleInfo *>(
+ sourceModel->data(
+ sourceModel->index(i),
+ BtBookshelfModel::ModulePointerRole
+ ).value<void*>()
+ )
+ );
+ Q_ASSERT(module != 0);
+ addModule(
+ module,
+ m_defaultChecked
+ );
+ }
+ }
+ }
+}
+
+void BtBookshelfTreeModel::setGroupingOrder(const Grouping &groupingOrder) {
+ if (m_groupingOrder == groupingOrder) return;
+ m_groupingOrder = groupingOrder;
+
+ if (m_sourceModel != 0) {
+ QSet<CSwordModuleInfo*> checked(checkedModules().toSet());
+ beginRemoveRows(QModelIndex(), 0, m_rootItem->children().size() - 1);
+ delete m_rootItem;
+ m_modules.clear();
+ m_rootItem = new RootItem;
+ endRemoveRows();
+
+ BtBookshelfModel *m(dynamic_cast<BtBookshelfModel*>(m_sourceModel));
+ if (m != 0) {
+ Q_FOREACH(CSwordModuleInfo *module, m->modules()) {
+ addModule(module, checked.contains(module));
+ }
+ } else {
+ for (int i(0); i < m_sourceModel->rowCount(); i++) {
+ CSwordModuleInfo *module(
+ static_cast<CSwordModuleInfo *>(
+ m_sourceModel->data(
+ m_sourceModel->index(i),
+ BtBookshelfModel::ModulePointerRole
+ ).value<void*>()
+ )
+ );
+ Q_ASSERT(module != 0);
+ addModule(module, checked.contains(module));
+ }
+ }
+ }
+}
+
+void BtBookshelfTreeModel::setCheckable(bool checkable) {
+ if (m_checkable == checkable) return;
+ m_checkable = checkable;
+ if (m_sourceModel != 0) {
+ QModelIndexList queue;
+ queue.append(QModelIndex());
+ do {
+ QModelIndex parent(queue.takeFirst());
+ int numChildren(rowCount(parent));
+ emit dataChanged(index(0, 0, parent),
+ index(numChildren - 1, 0, parent));
+ for (int i(0); i < numChildren; i++) {
+ QModelIndex childIndex(index(i, 0, parent));
+ if (rowCount(childIndex) > 0) {
+ queue.append(childIndex);
+ }
+ }
+ } while (!queue.isEmpty());
+ }
+}
+
+QList<CSwordModuleInfo*> BtBookshelfTreeModel::checkedModules() const {
+ typedef ModuleItemMap::const_iterator MMCI;
+
+ QList<CSwordModuleInfo*> modules;
+ for (MMCI it(m_modules.constBegin()); it != m_modules.constEnd(); it++) {
+ if (it.value()->checkState() == Qt::Checked) {
+ modules.append(it.key());
+ }
+ }
+ return modules;
+}
+
+void BtBookshelfTreeModel::addModule(CSwordModuleInfo *module, bool checked) {
+ if (m_modules.contains(module)) return;
+ Grouping g(m_groupingOrder);
+ addModule(module, QModelIndex(), g, checked);
+
+ /**
+ \bug Calling reset() shouldn't be necessary here, but omitting it will
+ will break things like switching to a grouped layout or installing
+ new modules. As a side effect, all attached views will also reset
+ themselves.
+ */
+ reset();
+}
+
+void BtBookshelfTreeModel::addModule(CSwordModuleInfo *module,
+ QModelIndex parentIndex,
+ Grouping &intermediateGrouping,
+ bool checked)
+{
+ Q_ASSERT(module != 0);
+
+ if (!intermediateGrouping.empty()) {
+ QModelIndex newIndex;
+ switch (intermediateGrouping.front()) {
+ case GROUP_DISTRIBUTION:
+ newIndex = getGroup<DistributionItem>(module, parentIndex);
+ break;
+ case GROUP_CATEGORY:
+ newIndex = getGroup<CategoryItem>(module, parentIndex);
+ break;
+ case GROUP_LANGUAGE:
+ newIndex = getGroup<LanguageItem>(module, parentIndex);
+ break;
+ }
+ intermediateGrouping.pop_front();
+ addModule(module, newIndex, intermediateGrouping, checked);
+ } else {
+ Item *parentItem(getItem(parentIndex));
+ ModuleItem *newItem(new ModuleItem(module));
+ newItem->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
+ const int newIndex(parentItem->indexFor(newItem));
+ beginInsertRows(parentIndex, newIndex, newIndex);
+ parentItem->insertChild(newIndex, newItem);
+ m_modules.insert(module, newItem);
+ endInsertRows();
+ resetParentCheckStates(parentIndex);
+ }
+}
+
+void BtBookshelfTreeModel::removeModule(CSwordModuleInfo *module) {
+ Item *i(m_modules.value(module, 0));
+ if (i == 0) return;
+
+ // Set i to be the lowest item (including empty groups) to remove:
+ Q_ASSERT(i->parent() != 0);
+ while (i->parent() != m_rootItem && i->parent()->children().size() <= 1) {
+ i = i->parent();
+ }
+ Q_ASSERT(i != 0);
+
+ // Calculate index of parent item:
+ QModelIndex parentIndex;
+ {
+ QList<int> indexes;
+ for (Item *j(i->parent()); j != m_rootItem; j = j->parent()) {
+ Q_ASSERT(j != 0);
+ indexes.push_back(j->childIndex());
+ }
+ while (!indexes.isEmpty()) {
+ parentIndex = index(indexes.takeLast(), 0, parentIndex);
+ }
+ }
+
+ // Remove item:
+ int index(i->childIndex());
+ beginRemoveRows(parentIndex, index, index);
+ i->parent()->deleteChildAt(index);
+ m_modules.remove(module);
+ endRemoveRows();
+ resetParentCheckStates(parentIndex);
+}
+
+Item *BtBookshelfTreeModel::getItem(const QModelIndex &index) const {
+ if (index.isValid()) {
+ Item *item(static_cast<Item*>(index.internalPointer()));
+ Q_ASSERT(item != 0);
+ return item;
+ } else {
+ return m_rootItem;
+ }
+}
+
+void BtBookshelfTreeModel::resetParentCheckStates(QModelIndex parentIndex) {
+ for ( ; parentIndex.isValid(); parentIndex = parentIndex.parent()) {
+ Item *parentItem(static_cast<Item*>(parentIndex.internalPointer()));
+ Q_ASSERT(parentItem != 0);
+
+ Qt::CheckState oldState(parentItem->checkState());
+ bool haveCheckedChildren(false);
+ bool haveUncheckedChildren(false);
+ for (int i(0); i < parentItem->children().size(); i++) {
+ Qt::CheckState state(parentItem->childAt(i)->checkState());
+ if (state == Qt::PartiallyChecked) {
+ haveCheckedChildren = true;
+ haveUncheckedChildren = true;
+ break;
+ } else if (state == Qt::Checked) {
+ haveCheckedChildren = true;
+ if (haveUncheckedChildren) break;
+ } else if (state == Qt::Unchecked) {
+ haveUncheckedChildren = true;
+ if (haveCheckedChildren) break;
+ }
+ }
+
+ Qt::CheckState newState;
+ if (haveCheckedChildren) {
+ if (haveUncheckedChildren) {
+ newState = Qt::PartiallyChecked;
+ } else {
+ newState = Qt::Checked;
+ }
+ } else {
+ newState = Qt::Unchecked;
+ }
+ if (newState == oldState) break;
+
+ parentItem->setCheckState(newState);
+ emit dataChanged(parentIndex, parentIndex);
+ } // for ( ; parentIndex.isValid(); parentIndex = parentIndex.parent())
+}
+
+void BtBookshelfTreeModel::moduleDataChanged(const QModelIndex &topLeft,
+ const QModelIndex &bottomRight)
+{
+ typedef BtBookshelfModel BM;
+ static const BM::ModuleRole PR(BM::ModulePointerRole);
+
+ Q_ASSERT(!topLeft.parent().isValid());
+ Q_ASSERT(!bottomRight.parent().isValid());
+ Q_ASSERT(topLeft.column() == 0 && bottomRight.column() == 0);
+
+ for (int i(topLeft.row()); i <= bottomRight.row(); i++) {
+ QModelIndex moduleIndex(m_sourceModel->index(i, 0, topLeft.parent()));
+ QVariant data(m_sourceModel->data(moduleIndex, PR));
+ CSwordModuleInfo *module((CSwordModuleInfo *) (data.value<void*>()));
+
+ /// \todo There might be a better way to do this.
+ bool checked(m_modules.value(module)->checkState() == Qt::Checked);
+ removeModule(module);
+ addModule(module, checked);
+ }
+}
+
+void BtBookshelfTreeModel::moduleInserted(const QModelIndex &parent, int start,
+ int end)
+{
+ typedef BtBookshelfModel BM;
+ static const BM::ModuleRole PR(BM::ModulePointerRole);
+
+ for (int i(start); i <= end; i++) {
+ QModelIndex moduleIndex(m_sourceModel->index(i, 0, parent));
+ QVariant data(m_sourceModel->data(moduleIndex, PR));
+ CSwordModuleInfo *module((CSwordModuleInfo *) (data.value<void*>()));
+
+ addModule(module, m_defaultChecked);
+ }
+}
+
+void BtBookshelfTreeModel::moduleRemoved(const QModelIndex &parent, int start,
+ int end)
+{
+ typedef BtBookshelfModel BM;
+ static const BM::ModuleRole PR(BM::ModulePointerRole);
+
+ for (int i(start); i <= end; i++) {
+ QModelIndex moduleIndex(m_sourceModel->index(i, 0, parent));
+ QVariant data(m_sourceModel->data(moduleIndex, PR));
+ CSwordModuleInfo *module((CSwordModuleInfo *) (data.value<void*>()));
+
+ removeModule(module);
+ }
+}
diff --git a/src/backend/bookshelfmodel/btbookshelftreemodel.h b/src/backend/bookshelfmodel/btbookshelftreemodel.h
new file mode 100644
index 0000000..0a84ac3
--- /dev/null
+++ b/src/backend/bookshelfmodel/btbookshelftreemodel.h
@@ -0,0 +1,114 @@
+/*********
+*
+* In the name of the Father, and of the Son, and of the Holy Spirit.
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License
+* version 2.0.
+*
+**********/
+
+#ifndef BTBOOKSHELFTREEMODEL_H
+#define BTBOOKSHELFTREEMODEL_H
+
+#include <QAbstractItemModel>
+
+#include <QMap>
+#include "backend/bookshelfmodel/btbookshelfmodel.h"
+#include "backend/bookshelfmodel/item.h"
+
+namespace BookshelfModel {
+ class ModuleItem;
+}
+class CSwordModuleInfo;
+
+class BtBookshelfTreeModel: public QAbstractItemModel {
+ Q_OBJECT
+
+ typedef QMap<CSwordModuleInfo*, BookshelfModel::ModuleItem*> ModuleItemMap;
+
+ public:
+ enum ModuleRole {
+ CheckStateRole = BtBookshelfModel::UserRole,
+ UserRole = BtBookshelfModel::UserRole + 100
+ };
+ enum Group { GROUP_CATEGORY, GROUP_LANGUAGE, GROUP_DISTRIBUTION };
+ typedef QList<Group> Grouping;
+
+ BtBookshelfTreeModel(QObject *parent = 0);
+ virtual ~BtBookshelfTreeModel();
+
+ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ virtual int columnCount(const QModelIndex &parent = QModelIndex())
+ const;
+ virtual bool hasChildren(const QModelIndex &parent = QModelIndex())
+ const;
+ virtual QModelIndex index(int row, int column,
+ const QModelIndex &parent = QModelIndex())
+ const;
+ virtual QModelIndex parent(const QModelIndex &index) const;
+ virtual QVariant data(const QModelIndex &index, int role) const;
+ virtual Qt::ItemFlags flags(const QModelIndex &index) const;
+ virtual QVariant headerData(int section, Qt::Orientation orientation,
+ int role = Qt::DisplayRole) const;
+ virtual bool setData(const QModelIndex &index, const QVariant &value,
+ int role);
+
+ void setSourceModel(QAbstractListModel *sourceModel);
+ inline QAbstractListModel *sourceModel() const { return m_sourceModel; }
+ void setGroupingOrder(const Grouping &groupingOrder);
+ inline Grouping groupingOrder() const { return m_groupingOrder; }
+ void setCheckable(bool checkable);
+ inline bool checkable() const { return m_checkable; }
+ inline void setDefaultChecked(bool defaultChecked) {
+ m_defaultChecked = defaultChecked;
+ }
+ inline bool defaultChecked() const { return m_defaultChecked; }
+
+ QList<CSwordModuleInfo*> checkedModules() const;
+
+ protected:
+ void addModule(CSwordModuleInfo *module, bool checked);
+ void addModule(CSwordModuleInfo *module, QModelIndex parentIndex,
+ Grouping &intermediateGrouping, bool checked);
+ void removeModule(CSwordModuleInfo *module);
+
+ BookshelfModel::Item *getItem(const QModelIndex &index) const;
+ void resetParentCheckStates(QModelIndex parentIndex);
+
+ template <class T>
+ QModelIndex getGroup(CSwordModuleInfo *module,
+ QModelIndex parentIndex)
+ {
+ BookshelfModel::Item *parentItem(getItem(parentIndex));
+ int groupIndex;
+ T *groupItem(parentItem->getGroupItem<T>(module, &groupIndex));
+
+ if (groupItem == 0) {
+ groupItem = new T(module);
+ groupIndex = parentItem->indexFor(groupItem);
+ beginInsertRows(parentIndex, groupIndex, groupIndex);
+ parentItem->insertChild(groupIndex, groupItem);
+ endInsertRows();
+ }
+ return index(groupIndex, 0, parentIndex);
+ }
+
+ protected slots:
+ void moduleDataChanged(const QModelIndex &topLeft,
+ const QModelIndex &bottomRight);
+ void moduleInserted(const QModelIndex &parent, int start, int end);
+ void moduleRemoved(const QModelIndex &parent, int start, int end);
+
+ protected:
+ QAbstractListModel *m_sourceModel;
+ BookshelfModel::Item *m_rootItem;
+ ModuleItemMap m_modules;
+ Grouping m_groupingOrder;
+ bool m_checkable;
+ bool m_defaultChecked;
+};
+
+#endif // BTBOOKSHELFTREEMODEL_H
diff --git a/src/backend/bookshelfmodel/btcheckstatefilterproxymodel.cpp b/src/backend/bookshelfmodel/btcheckstatefilterproxymodel.cpp
new file mode 100644
index 0000000..4d9cfd6
--- /dev/null
+++ b/src/backend/bookshelfmodel/btcheckstatefilterproxymodel.cpp
@@ -0,0 +1,70 @@
+/*********
+*
+* In the name of the Father, and of the Son, and of the Holy Spirit.
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License
+* version 2.0.
+*
+**********/
+
+#include "backend/bookshelfmodel/btcheckstatefilterproxymodel.h"
+
+BtCheckStateFilterProxyModel::BtCheckStateFilterProxyModel(QObject *parent)
+ : QSortFilterProxyModel(parent), m_enabled(true), m_showChecked(true),
+ m_showUnchecked(false), m_showPartiallyChecked(true)
+{
+ setFilterRole(Qt::CheckStateRole);
+}
+
+BtCheckStateFilterProxyModel::~BtCheckStateFilterProxyModel() {
+ // Intentionally empty
+}
+
+void BtCheckStateFilterProxyModel::setEnabled(bool enable) {
+ if (enable == m_enabled) return;
+ m_enabled = enable;
+ invalidateFilter();
+}
+
+void BtCheckStateFilterProxyModel::setShowChecked(bool show) {
+ if (m_showChecked == show) return;
+ m_showChecked = show;
+ invalidateFilter();
+}
+
+void BtCheckStateFilterProxyModel::setShowUnchecked(bool show) {
+ if (m_showUnchecked == show) return;
+ m_showUnchecked = show;
+ invalidateFilter();
+}
+
+void BtCheckStateFilterProxyModel::setShowPartiallyChecked(bool show) {
+ if (m_showPartiallyChecked == show) return;
+ m_showPartiallyChecked = show;
+ invalidateFilter();
+}
+
+bool BtCheckStateFilterProxyModel::filterAcceptsRow(int row,
+ const QModelIndex &parent) const
+{
+ typedef Qt::CheckState CS;
+
+ if (!m_enabled) return true;
+
+ QAbstractItemModel *m(sourceModel());
+
+ QModelIndex i(m->index(row, filterKeyColumn(), parent));
+ CS state((CS) m->data(i, filterRole()).toInt());
+ Q_ASSERT(state == Qt::Checked || state == Qt::Unchecked ||
+ state == Qt::PartiallyChecked);
+ if (state == Qt::Unchecked) {
+ return m_showUnchecked;
+ } else if (state == Qt::Checked) {
+ return m_showChecked;
+ } else {
+ return m_showPartiallyChecked;
+ }
+}
diff --git a/src/backend/bookshelfmodel/btcheckstatefilterproxymodel.h b/src/backend/bookshelfmodel/btcheckstatefilterproxymodel.h
new file mode 100644
index 0000000..b2081f1
--- /dev/null
+++ b/src/backend/bookshelfmodel/btcheckstatefilterproxymodel.h
@@ -0,0 +1,47 @@
+/*********
+*
+* In the name of the Father, and of the Son, and of the Holy Spirit.
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License
+* version 2.0.
+*
+**********/
+
+#ifndef BTCHECKSTATEFILTERPROXYMODEL_H
+#define BTCHECKSTATEFILTERPROXYMODEL_H
+
+#include <QSortFilterProxyModel>
+
+class BtCheckStateFilterProxyModel: public QSortFilterProxyModel {
+ Q_OBJECT
+ public:
+ BtCheckStateFilterProxyModel(QObject *parent = 0);
+ virtual ~BtCheckStateFilterProxyModel();
+
+ inline bool enabled() const { return m_enabled; }
+ void setEnabled(bool enable);
+
+ inline bool showChecked() const { return m_showChecked; }
+ void setShowChecked(bool show);
+
+ inline bool showUnchecked() const { return m_showUnchecked; }
+ void setShowUnchecked(bool show);
+
+ inline bool showPartiallyChecked() const {
+ return m_showPartiallyChecked;
+ }
+ void setShowPartiallyChecked(bool show);
+
+ virtual bool filterAcceptsRow(int row, const QModelIndex &parent) const;
+
+ protected:
+ bool m_enabled;
+ bool m_showChecked;
+ bool m_showUnchecked;
+ bool m_showPartiallyChecked;
+};
+
+#endif // BTSELECTEDMODULESBOOKSHELFPROXYMODEL_H
diff --git a/src/backend/bookshelfmodel/btmodulenamefilterproxymodel.cpp b/src/backend/bookshelfmodel/btmodulenamefilterproxymodel.cpp
new file mode 100644
index 0000000..f416175
--- /dev/null
+++ b/src/backend/bookshelfmodel/btmodulenamefilterproxymodel.cpp
@@ -0,0 +1,43 @@
+/*********
+*
+* In the name of the Father, and of the Son, and of the Holy Spirit.
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License
+* version 2.0.
+*
+**********/
+
+#include "backend/bookshelfmodel/btmodulenamefilterproxymodel.h"
+
+BtModuleNameFilterProxyModel::BtModuleNameFilterProxyModel(QObject *parent)
+ : QSortFilterProxyModel(parent), m_enabled(true)
+{
+ setFilterCaseSensitivity(Qt::CaseInsensitive);
+}
+
+BtModuleNameFilterProxyModel::~BtModuleNameFilterProxyModel() {
+ // Intentionally empty
+}
+
+bool BtModuleNameFilterProxyModel::filterAcceptsRow(int row,
+ const QModelIndex &p) const
+{
+ if (!m_enabled) return true;
+
+ const QAbstractItemModel *m(sourceModel());
+ Q_ASSERT(m != 0);
+
+ QModelIndex itemIndex(m->index(row, 0, p));
+ int numChildren(m->rowCount(itemIndex));
+ if (numChildren == 0) {
+ return QSortFilterProxyModel::filterAcceptsRow(row, p);
+ } else {
+ for (int i(0); i < numChildren; i++) {
+ if (filterAcceptsRow(i, itemIndex)) return true;
+ }
+ return false;
+ }
+}
diff --git a/src/backend/bookshelfmodel/btmodulenamefilterproxymodel.h b/src/backend/bookshelfmodel/btmodulenamefilterproxymodel.h
new file mode 100644
index 0000000..dd6f652
--- /dev/null
+++ b/src/backend/bookshelfmodel/btmodulenamefilterproxymodel.h
@@ -0,0 +1,34 @@
+/*********
+*
+* In the name of the Father, and of the Son, and of the Holy Spirit.
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License
+* version 2.0.
+*
+**********/
+
+#ifndef BTMODULENAMEFILTERPROXYMODEL_H
+#define BTMODULENAMEFILTERPROXYMODEL_H
+
+#include <QSortFilterProxyModel>
+
+class BtModuleNameFilterProxyModel: public QSortFilterProxyModel {
+ Q_OBJECT
+ public:
+ BtModuleNameFilterProxyModel(QObject *parent = 0);
+ virtual ~BtModuleNameFilterProxyModel();
+
+ inline bool enabled() const { return m_enabled; }
+ void setEnabled(bool enable);
+
+ virtual bool filterAcceptsRow(int row, const QModelIndex &parent) const;
+
+ protected:
+ QString m_filter;
+ bool m_enabled;
+};
+
+#endif // BTMODULENAMEFILTERPROXYMODEL_H
diff --git a/src/backend/bookshelfmodel/categoryitem.cpp b/src/backend/bookshelfmodel/categoryitem.cpp
new file mode 100644
index 0000000..0d4b853
--- /dev/null
+++ b/src/backend/bookshelfmodel/categoryitem.cpp
@@ -0,0 +1,23 @@
+/*********
+*
+* In the name of the Father, and of the Son, and of the Holy Spirit.
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License
+* version 2.0.
+*
+**********/
+
+#include "categoryitem.h"
+
+namespace BookshelfModel {
+
+CategoryItem::CategoryItem(CSwordModuleInfo *module)
+ : Item(ITEM_CATEGORY), m_category(module->category())
+{
+ // Intentionally empty
+}
+
+} // namespace BookshelfModel
diff --git a/src/backend/bookshelfmodel/categoryitem.h b/src/backend/bookshelfmodel/categoryitem.h
new file mode 100644
index 0000000..3cf7996
--- /dev/null
+++ b/src/backend/bookshelfmodel/categoryitem.h
@@ -0,0 +1,54 @@
+/*********
+*
+* In the name of the Father, and of the Son, and of the Holy Spirit.
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License
+* version 2.0.
+*
+**********/
+
+#ifndef CATEGORYITEM_H
+#define CATEGORYITEM_H
+
+#include "backend/bookshelfmodel/item.h"
+
+#include <QCoreApplication>
+#include "backend/bookshelfmodel/btbookshelfmodel.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+
+namespace BookshelfModel {
+
+class CategoryItem: public Item {
+ Q_DECLARE_TR_FUNCTIONS(CategoryItem);
+
+ public:
+ static const Item::Type GROUP_TYPE = Item::ITEM_CATEGORY;
+
+ CategoryItem(CSwordModuleInfo *module);
+
+ inline const CSwordModuleInfo::Category &category() const {
+ return m_category;
+ }
+
+ inline QString name() const {
+ return BtBookshelfModel::categoryName(m_category);
+ }
+
+ inline QIcon icon() const {
+ return BtBookshelfModel::categoryIcon(m_category);
+ }
+
+ inline bool fitFor(CSwordModuleInfo *module) {
+ return module->category() == m_category;
+ }
+
+ protected:
+ CSwordModuleInfo::Category m_category;
+};
+
+} // namespace BookshelfModel
+
+#endif // CATEGORYITEM_H
diff --git a/src/backend/bookshelfmodel/distributionitem.cpp b/src/backend/bookshelfmodel/distributionitem.cpp
new file mode 100644
index 0000000..411e236
--- /dev/null
+++ b/src/backend/bookshelfmodel/distributionitem.cpp
@@ -0,0 +1,23 @@
+/*********
+*
+* In the name of the Father, and of the Son, and of the Holy Spirit.
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License
+* version 2.0.
+*
+**********/
+
+#include "backend/bookshelfmodel/distributionitem.h"
+
+namespace BookshelfModel {
+
+DistributionItem::DistributionItem(CSwordModuleInfo *module)
+ : Item(ITEM_DISTRIBUTION)
+{
+ m_distribution = module->config(CSwordModuleInfo::DistributionSource);
+}
+
+} // namespace BookshelfModel
diff --git a/src/backend/bookshelfmodel/distributionitem.h b/src/backend/bookshelfmodel/distributionitem.h
new file mode 100644
index 0000000..ac3912d
--- /dev/null
+++ b/src/backend/bookshelfmodel/distributionitem.h
@@ -0,0 +1,43 @@
+/*********
+*
+* In the name of the Father, and of the Son, and of the Holy Spirit.
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License
+* version 2.0.
+*
+**********/
+
+#ifndef DISTRIBUTIONITEM_H
+#define DISTRIBUTIONITEM_H
+
+#include "backend/bookshelfmodel/item.h"
+
+#include "backend/drivers/cswordmoduleinfo.h"
+
+namespace BookshelfModel {
+
+class DistributionItem: public Item {
+ public:
+ static const Item::Type GROUP_TYPE = Item::ITEM_DISTRIBUTION;
+
+ DistributionItem(CSwordModuleInfo *module);
+
+ inline QString distribution() const { return m_distribution; }
+
+ inline QString name() const { return m_distribution; }
+
+ inline bool fitFor(CSwordModuleInfo *module) {
+ return module->config(CSwordModuleInfo::DistributionSource)
+ == m_distribution;
+ }
+
+ protected:
+ QString m_distribution;
+};
+
+} // namespace BookshelfModel
+
+#endif // DISTRIBUTIONITEM_H
diff --git a/src/backend/bookshelfmodel/item.cpp b/src/backend/bookshelfmodel/item.cpp
new file mode 100644
index 0000000..22bed91
--- /dev/null
+++ b/src/backend/bookshelfmodel/item.cpp
@@ -0,0 +1,57 @@
+/*********
+*
+* In the name of the Father, and of the Son, and of the Holy Spirit.
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License
+* version 2.0.
+*
+**********/
+
+#include "backend/bookshelfmodel/item.h"
+
+#include "backend/bookshelfmodel/categoryitem.h"
+#include "backend/bookshelfmodel/distributionitem.h"
+#include "backend/bookshelfmodel/languageitem.h"
+
+namespace BookshelfModel {
+
+Item::Item(Type type)
+ : m_type(type), m_parent(0), m_checkState(Qt::Unchecked)
+{
+ // Intentionally empty
+}
+
+Item::~Item() {
+ qDeleteAll(m_children);
+}
+
+int Item::indexFor(Item *newItem) {
+ Q_ASSERT(newItem != 0);
+
+ if (m_children.empty()) return 0;
+
+ int i(0);
+ for (;;) {
+ Item *nextItem(m_children.at(i));
+ Q_ASSERT(nextItem->type() == newItem->type());
+ if (*newItem < *nextItem) {
+ return i;
+ }
+ i++;
+ if (i >= m_children.size()) {
+ return i;
+ }
+ }
+}
+
+bool Item::operator<(const Item &other) const {
+ if (m_type != other.type()) {
+ return m_type < other.type();
+ }
+ return name().localeAwareCompare(other.name()) < 0;
+}
+
+} // namespace BookshelfModel
diff --git a/src/backend/bookshelfmodel/item.h b/src/backend/bookshelfmodel/item.h
new file mode 100644
index 0000000..cb2e6d9
--- /dev/null
+++ b/src/backend/bookshelfmodel/item.h
@@ -0,0 +1,170 @@
+/*********
+*
+* In the name of the Father, and of the Son, and of the Holy Spirit.
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License
+* version 2.0.
+*
+**********/
+
+#ifndef ITEM_H
+#define ITEM_H
+
+#include <QIcon>
+#include <QList>
+#include <QString>
+#include <QtGlobal>
+
+class CSwordModuleInfo;
+
+namespace BookshelfModel {
+
+class Item {
+ public:
+ enum Type {
+ ITEM_ROOT = 0,
+ ITEM_CATEGORY = 1,
+ ITEM_LANGUAGE = 2,
+ ITEM_MODULE = 3,
+ ITEM_DISTRIBUTION = 4
+ };
+
+ Item(Type type);
+ virtual ~Item();
+
+ /**
+ \brief Returns the type of this item.
+ */
+ inline Type type() const { return m_type; }
+
+ /**
+ \brief Returns a pointer to the parent item of this item.
+ \retval 0 if this item has no parent.
+ */
+ inline Item *parent() const { return m_parent; }
+
+ /**
+ \brief Returns the list of child items of this node.
+ */
+ inline const QList<Item*> &children() const { return m_children; }
+
+ /**
+ \brief Returns a pointer to the child item at the given index.
+ \pre The given index is valid
+ \param[in] index Index of child item to return.
+ */
+ Item *childAt(int index) const {
+ Q_ASSERT(index >= 0 && index < m_children.size());
+ return m_children.at(index);
+ }
+
+ /**
+ \brief Returns the index of this item under its parent.
+ \retval -1 if this item has no parent.
+ */
+ inline int childIndex() {
+ if (m_parent == 0) return -1;
+ return m_parent->m_children.indexOf(this);
+ }
+
+ /**
+ \brief Returns the position for where the given child item would be
+ inserted.
+ \param[in] newItem Pointer to the item that would be inserted.
+ */
+ int indexFor(Item *newItem);
+
+ /**
+ \brief Inserts the given item as a child at the given index.
+ \pre The given index is a valid position for the item.
+ \param[in] index The child index to insert the item at.
+ \param[in] newItem The item to insert.
+ */
+ inline void insertChild(int index, Item *newItem) {
+ Q_ASSERT(newItem != 0);
+ Q_ASSERT(index >= 0 && index <= m_children.size());
+ m_children.insert(index, newItem);
+ newItem->setParent(this);
+ }
+
+ inline void deleteChildAt(int index) {
+ Q_ASSERT(index >= 0 && index <= m_children.size());
+ delete m_children.takeAt(index);
+ }
+
+ template <class T>
+ T *getGroupItem(CSwordModuleInfo *module, int *index) {
+ for (int i(0); i < m_children.size(); i++) {
+ Q_ASSERT(m_children.at(i)->type() == T::GROUP_TYPE);
+ T *item(static_cast<T*>(m_children.at(i)));
+ if (item->fitFor(module)) {
+ if (index != 0) *index = i;
+ return item;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ \brief Returns the visible name of the item.
+ */
+ inline virtual QString name() const { return QString::null; }
+
+ /**
+ \brief Returns the visible icon of the item.
+ */
+ inline virtual QIcon icon() const { return QIcon(); }
+
+ /**
+ \brief Returns the check state of this item.
+ */
+ inline const Qt::CheckState checkState() const { return m_checkState; }
+
+ /**
+ \brief Sets the check state of this item.
+ \param[in] state new check state.
+ */
+ inline void setCheckState(const Qt::CheckState state) {
+ m_checkState = state;
+ }
+
+ /**
+ \brief Returns whether this item is fit to contain the given module.
+ \param[in] module The module to check with.
+ \retval true If this item is a group and can contain the given module.
+ \retval false This item is not a group or a wrong group.
+ */
+ inline virtual bool fitFor(CSwordModuleInfo *module) {
+ Q_UNUSED(module);
+ return false;
+ }
+
+ /**
+ \brief Comparsion operator used sorting child items.
+ */
+ bool operator<(const Item &other) const;
+
+ protected:
+ inline void setParent(Item *parent) {
+ Q_ASSERT(parent != 0);
+ m_parent = parent;
+ }
+
+ protected:
+ Type m_type;
+ Item *m_parent;
+ QList<Item*> m_children;
+ Qt::CheckState m_checkState;
+};
+
+class RootItem: public Item {
+ public:
+ inline RootItem() : Item(Item::ITEM_ROOT) {}
+};
+
+} // Namespace BookshelfModel
+
+#endif // ITEM_H
diff --git a/src/backend/bookshelfmodel/languageitem.cpp b/src/backend/bookshelfmodel/languageitem.cpp
new file mode 100644
index 0000000..6c2af30
--- /dev/null
+++ b/src/backend/bookshelfmodel/languageitem.cpp
@@ -0,0 +1,23 @@
+/*********
+*
+* In the name of the Father, and of the Son, and of the Holy Spirit.
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License
+* version 2.0.
+*
+**********/
+
+#include "languageitem.h"
+
+namespace BookshelfModel {
+
+LanguageItem::LanguageItem(CSwordModuleInfo *module)
+ : Item(ITEM_LANGUAGE), m_language(module->language())
+{
+ // Intentionally empty
+}
+
+} // namespace BookshelfModel
diff --git a/src/backend/bookshelfmodel/languageitem.h b/src/backend/bookshelfmodel/languageitem.h
new file mode 100644
index 0000000..3b329f1
--- /dev/null
+++ b/src/backend/bookshelfmodel/languageitem.h
@@ -0,0 +1,50 @@
+/*********
+*
+* In the name of the Father, and of the Son, and of the Holy Spirit.
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License
+* version 2.0.
+*
+**********/
+
+#ifndef LANGUAGEITEM_H
+#define LANGUAGEITEM_H
+
+#include "backend/bookshelfmodel/item.h"
+
+#include "backend/bookshelfmodel/btbookshelfmodel.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+#include "util/directoryutil.h"
+
+namespace BookshelfModel {
+
+class LanguageItem: public Item {
+ public:
+ static const Item::Type GROUP_TYPE = Item::ITEM_LANGUAGE;
+
+ LanguageItem(CSwordModuleInfo *module);
+
+ inline const CLanguageMgr::Language *language() const { return m_language; }
+
+ inline QString name() const {
+ return BtBookshelfModel::languageName(m_language);
+ }
+
+ inline QIcon icon() const {
+ return util::filesystem::DirectoryUtil::getIcon("flag.svg");
+ }
+
+ inline bool fitFor(CSwordModuleInfo *module) {
+ return module->language() == m_language;
+ }
+
+ protected:
+ const CLanguageMgr::Language *m_language;
+};
+
+} // namespace BookshelfModel
+
+#endif // LANGUAGEITEM_H
diff --git a/src/backend/bookshelfmodel/moduleitem.cpp b/src/backend/bookshelfmodel/moduleitem.cpp
new file mode 100644
index 0000000..6a543bc
--- /dev/null
+++ b/src/backend/bookshelfmodel/moduleitem.cpp
@@ -0,0 +1,25 @@
+/*********
+*
+* In the name of the Father, and of the Son, and of the Holy Spirit.
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License
+* version 2.0.
+*
+**********/
+
+#include "moduleitem.h"
+
+#include "util/cresmgr.h"
+
+namespace BookshelfModel {
+
+ModuleItem::ModuleItem(CSwordModuleInfo *module)
+ : Item(ITEM_MODULE), m_moduleInfo(module)
+{
+ Q_ASSERT(module != 0);
+}
+
+} // namespace BookshelfModel
diff --git a/src/backend/bookshelfmodel/moduleitem.h b/src/backend/bookshelfmodel/moduleitem.h
new file mode 100644
index 0000000..7bafc1f
--- /dev/null
+++ b/src/backend/bookshelfmodel/moduleitem.h
@@ -0,0 +1,41 @@
+/*********
+*
+* In the name of the Father, and of the Son, and of the Holy Spirit.
+*
+* This file is part of BibleTime's source code, http://www.bibletime.info/.
+*
+* Copyright 1999-2009 by the BibleTime developers.
+* The BibleTime source code is licensed under the GNU General Public License
+* version 2.0.
+*
+**********/
+
+#ifndef MODULEITEM_H
+#define MODULEITEM_H
+
+#include "backend/bookshelfmodel/item.h"
+
+#include "backend/bookshelfmodel/btbookshelfmodel.h"
+#include "backend/drivers/cswordmoduleinfo.h"
+
+namespace BookshelfModel {
+
+class ModuleItem: public Item {
+ public:
+ ModuleItem(CSwordModuleInfo *module);
+
+ CSwordModuleInfo *moduleInfo() const { return m_moduleInfo; }
+
+ inline QString name() const { return m_moduleInfo->name(); }
+
+ inline QIcon icon() const {
+ return BtBookshelfModel::categoryIcon(m_moduleInfo->category());
+ }
+
+ protected:
+ CSwordModuleInfo *m_moduleInfo;
+};
+
+} // namespace BookshelfModel
+
+#endif // MODULEITEM_H
diff --git a/src/backend/keys/cswordversekey.cpp b/src/backend/keys/cswordversekey.cpp
index 8db5d74..8008a7f 100644
--- a/src/backend/keys/cswordversekey.cpp
+++ b/src/backend/keys/cswordversekey.cpp
@@ -18,8 +18,13 @@
#include <swmodule.h>
#include <localemgr.h>
-CSwordVerseKey::CSwordVerseKey( CSwordModuleInfo* const module ) : CSwordKey(module) {
+CSwordVerseKey::CSwordVerseKey( CSwordModuleInfo* const module ) :
+ CSwordKey(module)
+{
if ( CSwordBibleModuleInfo* bible = dynamic_cast<CSwordBibleModuleInfo*>(module) ) {
+ // Copy important settings like versification system
+ copyFrom((sword::VerseKey*) bible->module()->getKey());
+
key( bible->lowerBound().key() );
}
}
diff --git a/src/backend/rendering/cdisplayrendering.cpp b/src/backend/rendering/cdisplayrendering.cpp
index 50d5b18..32444b4 100644
--- a/src/backend/rendering/cdisplayrendering.cpp
+++ b/src/backend/rendering/cdisplayrendering.cpp
@@ -99,8 +99,9 @@ namespace Rendering {
const QString CDisplayRendering::keyToHTMLAnchor(const QString& key) {
QString ret = key;
- ret = ret.trimmed().remove(QRegExp("[^A-Za-z0-9]+"));
- ret = ret.remove(QRegExp("^\\d+|"));
+ // Be careful not to remove non-ASCII characters, this causes problems
+ // with many languages.
+ ret = ret.trimmed().remove(QRegExp("\\s")).replace(QString(":"), QString("_"));
return ret;
}