diff options
Diffstat (limited to 'src/backend')
90 files changed, 5122 insertions, 4051 deletions
diff --git a/src/backend/bookshelfmodel/btbookshelffiltermodel.cpp b/src/backend/bookshelfmodel/btbookshelffiltermodel.cpp index 182d337..320d693 100644 --- a/src/backend/bookshelfmodel/btbookshelffiltermodel.cpp +++ b/src/backend/bookshelfmodel/btbookshelffiltermodel.cpp @@ -4,7 +4,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License * version 2.0. * @@ -15,25 +15,26 @@ #include "backend/bookshelfmodel/btbookshelfmodel.h" -BtBookshelfFilterModel::BtBookshelfFilterModel(QObject *parent) - : QSortFilterProxyModel(parent), m_enabled(true), - m_nameFilterRole(BtBookshelfModel::ModuleNameRole), m_nameFilterColumn(0), - m_nameFilterCase(Qt::CaseInsensitive), - m_hiddenFilterRole(BtBookshelfModel::ModuleHiddenRole), - m_hiddenFilterColumn(0), m_showHidden(false), m_showShown(true), - m_categoryFilter(CSwordModuleInfo::AllCategories), - m_categoryFilterRole(BtBookshelfModel::ModuleCategoryRole), - m_categoryFilterColumn(0) +BtBookshelfFilterModel::BtBookshelfFilterModel(QObject * parent) + : QSortFilterProxyModel(parent) + , m_enabled(true) + , m_nameFilterRole(BtBookshelfModel::ModuleNameRole) + , m_nameFilterColumn(0) + , m_nameFilterCase(Qt::CaseInsensitive) + , m_hiddenFilterRole(BtBookshelfModel::ModuleHiddenRole) + , m_hiddenFilterColumn(0) + , m_showHidden(false) + , m_showShown(true) + , m_categoryFilter(CSwordModuleInfo::AllCategories) + , m_categoryFilterRole(BtBookshelfModel::ModuleCategoryRole) + , m_categoryFilterColumn(0) { setDynamicSortFilter(true); } -BtBookshelfFilterModel::~BtBookshelfFilterModel() { - // Intentionally empty -} - void BtBookshelfFilterModel::setEnabled(bool enable) { - if (enable == m_enabled) return; + if (enable == m_enabled) + return; m_enabled = enable; invalidateFilter(); } @@ -41,25 +42,29 @@ void BtBookshelfFilterModel::setEnabled(bool enable) { // Name filter: void BtBookshelfFilterModel::setNameFilterRole(int role) { - if (m_nameFilterRole == role) return; + if (m_nameFilterRole == role) + return; m_nameFilterRole = role; invalidateFilter(); } void BtBookshelfFilterModel::setNameFilterKeyColumn(int column) { - if (m_nameFilterColumn == column) return; + if (m_nameFilterColumn == column) + return; m_nameFilterColumn = column; invalidateFilter(); } void BtBookshelfFilterModel::setNameFilterFixedString(const QString &filter) { - if (m_nameFilter == filter) return; + if (m_nameFilter == filter) + return; m_nameFilter = filter; invalidateFilter(); } void BtBookshelfFilterModel::setNameFilterCase(Qt::CaseSensitivity value) { - if (m_nameFilterCase == value) return; + if (m_nameFilterCase == value) + return; m_nameFilterCase = value; invalidateFilter(); } @@ -67,25 +72,29 @@ void BtBookshelfFilterModel::setNameFilterCase(Qt::CaseSensitivity value) { // Hidden filter: void BtBookshelfFilterModel::setHiddenFilterRole(int role) { - if (m_hiddenFilterRole == role) return; + if (m_hiddenFilterRole == role) + return; m_hiddenFilterRole = role; invalidateFilter(); } void BtBookshelfFilterModel::setHiddenFilterKeyColumn(int column) { - if (m_hiddenFilterColumn == column) return; + if (m_hiddenFilterColumn == column) + return; m_hiddenFilterColumn = column; invalidateFilter(); } void BtBookshelfFilterModel::setShowHidden(bool show) { - if (m_showHidden == show) return; + if (m_showHidden == show) + return; m_showHidden = show; invalidateFilter(); } void BtBookshelfFilterModel::setShowShown(bool show) { - if (m_showShown == show) return; + if (m_showShown == show) + return; m_showShown = show; invalidateFilter(); } @@ -93,21 +102,24 @@ void BtBookshelfFilterModel::setShowShown(bool show) { // Category filter: void BtBookshelfFilterModel::setCategoryFilterRole(int role) { - if (m_categoryFilterRole == role) return; + if (m_categoryFilterRole == role) + return; m_categoryFilterRole = role; invalidateFilter(); } void BtBookshelfFilterModel::setCategoryFilterKeyColumn(int column) { - if (m_categoryFilterColumn == column) return; + if (m_categoryFilterColumn == column) + return; m_categoryFilterColumn = column; invalidateFilter(); } void BtBookshelfFilterModel::setShownCategories( - const CSwordModuleInfo::Categories &categories) + const CSwordModuleInfo::Categories & categories) { - if (m_categoryFilter == categories) return; + if (m_categoryFilter == categories) + return; m_categoryFilter = categories; invalidateFilter(); } @@ -115,20 +127,27 @@ void BtBookshelfFilterModel::setShownCategories( // Filtering: bool BtBookshelfFilterModel::filterAcceptsRow(int row, - const QModelIndex &parent) const + const QModelIndex & parent) const { - if (!m_enabled) return true; + if (!m_enabled) + return true; - if (!hiddenFilterAcceptsRow(row, parent)) return false; - if (!nameFilterAcceptsRow(row, parent)) return false; - if (!categoryFilterAcceptsRow(row, parent)) return false; + if (!hiddenFilterAcceptsRow(row, parent)) + return false; + if (!nameFilterAcceptsRow(row, parent)) + return false; + if (!categoryFilterAcceptsRow(row, parent)) + return false; return true; } -bool BtBookshelfFilterModel::nameFilterAcceptsRow(int row, const QModelIndex &parent) const { - if (m_nameFilter.isEmpty()) return true; +bool BtBookshelfFilterModel::nameFilterAcceptsRow(int row, + const QModelIndex & parent) const +{ + if (m_nameFilter.isEmpty()) + return true; - const QAbstractItemModel *m(sourceModel()); + const QAbstractItemModel * const m = sourceModel(); Q_ASSERT(m != 0); QModelIndex itemIndex(m->index(row, m_nameFilterColumn, parent)); @@ -137,59 +156,54 @@ bool BtBookshelfFilterModel::nameFilterAcceptsRow(int row, const QModelIndex &pa QVariant data(m->data(itemIndex, m_nameFilterRole)); return data.toString().contains(m_nameFilter, m_nameFilterCase); } - else { - for (int i(0); i < numChildren; i++) { - if (filterAcceptsRow(i, itemIndex)) return true; - } - return false; - } + + for (int i = 0; i < numChildren; i++) + if (filterAcceptsRow(i, itemIndex)) + return true; + return false; } -bool BtBookshelfFilterModel::hiddenFilterAcceptsRow(int row, const QModelIndex &parent) const +bool BtBookshelfFilterModel::hiddenFilterAcceptsRow(int row, + const QModelIndex & parent) const { - if (m_showHidden && m_showShown) return true; + if (m_showHidden && m_showShown) + return true; - typedef Qt::CheckState CS; - - QAbstractItemModel *m(sourceModel()); + const QAbstractItemModel * const m = sourceModel(); Q_ASSERT(m != 0); - QModelIndex itemIndex(m->index(row, m_hiddenFilterColumn, parent)); - int numChildren(m->rowCount(itemIndex)); + const QModelIndex itemIndex = m->index(row, m_hiddenFilterColumn, parent); + const int numChildren = m->rowCount(itemIndex); if (numChildren == 0) { - if ((CS) m->data(itemIndex, m_hiddenFilterRole).toBool()) { + if (static_cast<Qt::CheckState>(m->data(itemIndex, m_hiddenFilterRole).toBool())) return m_showHidden; - } - else { - return m_showShown; - } - } - else { - for (int i(0); i < numChildren; i++) { - if (filterAcceptsRow(i, itemIndex)) return true; - } - return false; + return m_showShown; } + + for (int i = 0; i < numChildren; i++) + if (filterAcceptsRow(i, itemIndex)) + return true; + return false; } bool BtBookshelfFilterModel::categoryFilterAcceptsRow(int row, - const QModelIndex &parent) const + const QModelIndex & parent) const { - if (m_categoryFilter == CSwordModuleInfo::AllCategories) return true; + if (m_categoryFilter == CSwordModuleInfo::AllCategories) + return true; - QAbstractItemModel *m(sourceModel()); + const QAbstractItemModel * const m = sourceModel(); Q_ASSERT(m != 0); - QModelIndex itemIndex(m->index(row, m_categoryFilterColumn, parent)); - int numChildren(m->rowCount(itemIndex)); + const QModelIndex itemIndex(m->index(row, m_categoryFilterColumn, parent)); + const int numChildren(m->rowCount(itemIndex)); if (numChildren == 0) { - int cat = m->data(itemIndex, m_categoryFilterRole).toInt(); - return m_categoryFilter.testFlag((CSwordModuleInfo::Category) cat); - } - else { - for (int i(0); i < numChildren; i++) { - if (filterAcceptsRow(i, itemIndex)) return true; - } - return false; + const int cat = m->data(itemIndex, m_categoryFilterRole).toInt(); + return m_categoryFilter.testFlag(static_cast<CSwordModuleInfo::Category>(cat)); } + + for (int i = 0; i < numChildren; i++) + if (filterAcceptsRow(i, itemIndex)) + return true; + return false; } diff --git a/src/backend/bookshelfmodel/btbookshelffiltermodel.h b/src/backend/bookshelfmodel/btbookshelffiltermodel.h index 55322ed..b1b22e6 100644 --- a/src/backend/bookshelfmodel/btbookshelffiltermodel.h +++ b/src/backend/bookshelfmodel/btbookshelffiltermodel.h @@ -4,7 +4,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License * version 2.0. * @@ -19,109 +19,113 @@ class BtBookshelfFilterModel: public QSortFilterProxyModel { + Q_OBJECT - public: - BtBookshelfFilterModel(QObject *parent = 0); - virtual ~BtBookshelfFilterModel(); - - // Common methods: - inline bool enabled() const { - return m_enabled; - } - - virtual bool filterAcceptsRow(int row, const QModelIndex &parent) const; - - // Name filter: - inline int nameFilterRole() const { - return m_nameFilterRole; - } - - inline int nameFilterKeyColumn() const { - return m_nameFilterColumn; - } - - inline const QString &nameFilter() const { - return m_nameFilter; - } - - inline const Qt::CaseSensitivity nameFilterCase() const { - return m_nameFilterCase; - } - - // Hidden filter: - int hiddenFilterRole() const { - return m_hiddenFilterRole; - } - - int hiddenFilterKeyColumn() const { - return m_hiddenFilterColumn; - } - - inline bool showHidden() const { - return m_showHidden; - } - - inline bool showShown() const { - return m_showShown; - } - - // Category filter: - int categoryFilterRole() const { - return m_categoryFilterRole; - } - - int categoryFilterKeyColumn() const { - return m_categoryFilterColumn; - } - - inline CSwordModuleInfo::Categories shownCategories() const { - return m_categoryFilter; - } - - public slots: - void setEnabled(bool enable); - - // Name filter: - void setNameFilterRole(int role); - void setNameFilterKeyColumn(int column); - void setNameFilterFixedString(const QString &nameFilter); - void setNameFilterCase(Qt::CaseSensitivity value); - - // Hidden filter: - void setHiddenFilterRole(int role); - void setHiddenFilterKeyColumn(int column); - void setShowHidden(bool show); - void setShowShown(bool show); - - // Category filter: - void setCategoryFilterRole(int role); - void setCategoryFilterKeyColumn(int column); - void setShownCategories(const CSwordModuleInfo::Categories &categories); - - protected: - bool nameFilterAcceptsRow(int row, const QModelIndex &parent) const; - bool hiddenFilterAcceptsRow(int row, const QModelIndex &parent) const; - bool categoryFilterAcceptsRow(int row, const QModelIndex &parent) const; - - protected: - bool m_enabled; - - // Name filter: - QString m_nameFilter; - int m_nameFilterRole; - int m_nameFilterColumn; - Qt::CaseSensitivity m_nameFilterCase; - - // Hidden filter: - int m_hiddenFilterRole; - int m_hiddenFilterColumn; - bool m_showHidden; - bool m_showShown; - - // Categories filter: - CSwordModuleInfo::Categories m_categoryFilter; - int m_categoryFilterRole; - int m_categoryFilterColumn; + +public: /* Methods: */ + + BtBookshelfFilterModel(QObject * parent = 0); + + inline bool enabled() const { + return m_enabled; + } + + virtual bool filterAcceptsRow(int row, const QModelIndex & parent) const; + + // Name filter: + inline int nameFilterRole() const { + return m_nameFilterRole; + } + + inline int nameFilterKeyColumn() const { + return m_nameFilterColumn; + } + + inline const QString &nameFilter() const { + return m_nameFilter; + } + + inline Qt::CaseSensitivity nameFilterCase() const { + return m_nameFilterCase; + } + + // Hidden filter: + int hiddenFilterRole() const { + return m_hiddenFilterRole; + } + + int hiddenFilterKeyColumn() const { + return m_hiddenFilterColumn; + } + + inline bool showHidden() const { + return m_showHidden; + } + + inline bool showShown() const { + return m_showShown; + } + + // Category filter: + int categoryFilterRole() const { + return m_categoryFilterRole; + } + + int categoryFilterKeyColumn() const { + return m_categoryFilterColumn; + } + + inline CSwordModuleInfo::Categories shownCategories() const { + return m_categoryFilter; + } + +public slots: + void setEnabled(bool enable); + + // Name filter: + void setNameFilterRole(int role); + void setNameFilterKeyColumn(int column); + void setNameFilterFixedString(const QString & nameFilter); + void setNameFilterCase(Qt::CaseSensitivity value); + + // Hidden filter: + void setHiddenFilterRole(int role); + void setHiddenFilterKeyColumn(int column); + void setShowHidden(bool show); + void setShowShown(bool show); + + // Category filter: + void setCategoryFilterRole(int role); + void setCategoryFilterKeyColumn(int column); + void setShownCategories(const CSwordModuleInfo::Categories & categories); + +private: /* Methods: */ + + bool nameFilterAcceptsRow(int row, const QModelIndex & parent) const; + bool hiddenFilterAcceptsRow(int row, const QModelIndex & parent) const; + bool categoryFilterAcceptsRow(int row, const QModelIndex & parent) const; + +private: /* Fields: */ + + bool m_enabled; + + // Name filter: + QString m_nameFilter; + int m_nameFilterRole; + int m_nameFilterColumn; + Qt::CaseSensitivity m_nameFilterCase; + + // Hidden filter: + int m_hiddenFilterRole; + int m_hiddenFilterColumn; + bool m_showHidden; + bool m_showShown; + + // Categories filter: + CSwordModuleInfo::Categories m_categoryFilter; + int m_categoryFilterRole; + int m_categoryFilterColumn; + }; #endif // BTBOOKSHELFFILTERMODEL_H diff --git a/src/backend/bookshelfmodel/btbookshelfmodel.cpp b/src/backend/bookshelfmodel/btbookshelfmodel.cpp index 322b22a..c19e429 100644 --- a/src/backend/bookshelfmodel/btbookshelfmodel.cpp +++ b/src/backend/bookshelfmodel/btbookshelfmodel.cpp @@ -4,7 +4,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License * version 2.0. * @@ -17,29 +17,22 @@ #include "util/macros.h" -BtBookshelfModel::BtBookshelfModel(QObject *parent) - : QAbstractListModel(parent) { - // Intentionally empty -} - -BtBookshelfModel::~BtBookshelfModel() { - // Intentionally empty -} - -int BtBookshelfModel::rowCount(const QModelIndex &parent) const { - if (parent.isValid()) return 0; +int BtBookshelfModel::rowCount(const QModelIndex & parent) const { + if (parent.isValid()) + return 0; return m_data.size(); } -QVariant BtBookshelfModel::data(CSwordModuleInfo *module, int role) const { +QVariant BtBookshelfModel::data(CSwordModuleInfo * module, int role) const { + Q_ASSERT(module); switch (role) { case ModuleNameRole: // Qt::DisplayRole return module->name(); case ModuleIconRole: // Qt::DecorationRole - return CSwordModuleInfo::moduleIcon(module); + return CSwordModuleInfo::moduleIcon(*module); case ModulePointerRole: - return qVariantFromValue((void*) module); + return qVariantFromValue(static_cast<void *>(module)); case ModuleCategoryRole: return QVariant::fromValue(module->category()); case ModuleLanguageRole: @@ -64,30 +57,40 @@ QVariant BtBookshelfModel::data(CSwordModuleInfo *module, int role) const { } QVariant BtBookshelfModel::data(const QModelIndex &index, int role) const { - if (!index.isValid() || index.column() != 0 || index.parent().isValid()) { + if (!index.isValid() || index.column() != 0 || index.parent().isValid()) + return QVariant(); + + int row = index.row(); + if (row >= m_data.size()) return QVariant(); - } - int row(index.row()); - if (row >= m_data.size()) return QVariant(); return data(m_data.at(row), role); } -QVariant BtBookshelfModel::headerData(int section, Qt::Orientation orientation, - int role) const { - if (role == Qt::DisplayRole && orientation == Qt::Horizontal && - section == 0) { +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(); } -bool BtBookshelfModel::setData(const QModelIndex &index, const QVariant &value, - int role) { - int row(index.row()); - if (role == ModuleHiddenRole && row >= 0 && row < m_data.size() - && index.column() == 0) { +bool BtBookshelfModel::setData(const QModelIndex & index, + const QVariant & value, + int role) +{ + int row = index.row(); + if (role == ModuleHiddenRole + && row >= 0 + && row < m_data.size() + && index.column() == 0) + { /* Emitting dataChanged here is actually mandatory, but were not doing it directly. Since we're connected to the module, changing its hidden @@ -100,12 +103,12 @@ bool BtBookshelfModel::setData(const QModelIndex &index, const QVariant &value, } void BtBookshelfModel::clear(bool destroy) { - if (m_data.size() <= 0) return; + if (m_data.size() <= 0) + return; beginRemoveRows(QModelIndex(), 0, m_data.size() - 1); - if (destroy) { + if (destroy) qDeleteAll(m_data); - } m_data.clear(); endRemoveRows(); } @@ -113,7 +116,8 @@ void BtBookshelfModel::clear(bool destroy) { void BtBookshelfModel::addModule(CSwordModuleInfo * const module) { Q_ASSERT(module != 0); - if (m_data.contains(module)) return; + if (m_data.contains(module)) + return; const int index(m_data.size()); beginInsertRows(QModelIndex(), index, index); @@ -127,23 +131,23 @@ void BtBookshelfModel::addModule(CSwordModuleInfo * const module) { endInsertRows(); } -void BtBookshelfModel::addModules(const QList<CSwordModuleInfo *> &modules) { +void BtBookshelfModel::addModules(const QList<CSwordModuleInfo *> & modules) { addModules(modules.toSet()); } -void BtBookshelfModel::addModules(const QSet<CSwordModuleInfo *> &modules) { +void BtBookshelfModel::addModules(const QSet<CSwordModuleInfo *> & modules) { QList<CSwordModuleInfo *> newModules; - Q_FOREACH(CSwordModuleInfo *module, modules) { - if (!m_data.contains(module)) { + Q_FOREACH (CSwordModuleInfo * module, modules) + if (!m_data.contains(module)) newModules.append(module); - } - } - if (newModules.isEmpty()) return; + if (newModules.isEmpty()) + return; - beginInsertRows(QModelIndex(), m_data.size(), + beginInsertRows(QModelIndex(), + m_data.size(), m_data.size() + newModules.size() - 1); - Q_FOREACH(CSwordModuleInfo *module, newModules) { + Q_FOREACH (CSwordModuleInfo * module, newModules) { m_data.append(module); connect(module, SIGNAL(hiddenChanged(bool)), this, SLOT(moduleHidden(bool))); @@ -157,8 +161,9 @@ void BtBookshelfModel::addModules(const QSet<CSwordModuleInfo *> &modules) { void BtBookshelfModel::removeModule(CSwordModuleInfo * const module, bool destroy) { - const int index(m_data.indexOf(module)); - if (index == -1) return; + const int index = m_data.indexOf(module); + if (index == -1) + return; beginRemoveRows(QModelIndex(), index, index); disconnect(module, SIGNAL(hiddenChanged(bool)), @@ -169,48 +174,51 @@ void BtBookshelfModel::removeModule(CSwordModuleInfo * const module, this, SLOT(moduleUnlocked(bool))); m_data.removeAt(index); endRemoveRows(); - if (destroy) delete module; + if (destroy) + delete module; } -void BtBookshelfModel::removeModules(const QList<CSwordModuleInfo *> &modules, - bool destroy) { +void BtBookshelfModel::removeModules(const QList<CSwordModuleInfo *> & modules, + bool destroy) +{ removeModules(modules.toSet(), destroy); } -void BtBookshelfModel::removeModules(const QSet<CSwordModuleInfo *> &modules, - bool destroy) { +void BtBookshelfModel::removeModules(const QSet<CSwordModuleInfo *> & modules, + bool destroy) +{ // This is inefficient, since signals are emitted for each removed module: - Q_FOREACH(CSwordModuleInfo *module, modules) { + Q_FOREACH (CSwordModuleInfo * module, modules) removeModule(module, destroy); - } } -CSwordModuleInfo* BtBookshelfModel::getModule(const QString &name) const { - Q_FOREACH(CSwordModuleInfo *module, m_data) { - if (UNLIKELY(module->name() == name)) return module; - } +CSwordModuleInfo * BtBookshelfModel::getModule(const QString & name) const { + Q_FOREACH (CSwordModuleInfo * module, m_data) + if (UNLIKELY(module->name() == name)) + return module; + return 0; } void BtBookshelfModel::moduleHidden(bool) { - Q_ASSERT(qobject_cast<CSwordModuleInfo*>(sender()) != 0); + Q_ASSERT(qobject_cast<CSwordModuleInfo *>(sender()) != 0); - moduleDataChanged(static_cast<CSwordModuleInfo*>(sender())); + moduleDataChanged(static_cast<CSwordModuleInfo *>(sender())); } void BtBookshelfModel::moduleIndexed(bool) { - Q_ASSERT(qobject_cast<CSwordModuleInfo*>(sender()) != 0); + Q_ASSERT(qobject_cast<CSwordModuleInfo *>(sender()) != 0); - moduleDataChanged(static_cast<CSwordModuleInfo*>(sender())); + moduleDataChanged(static_cast<CSwordModuleInfo *>(sender())); } void BtBookshelfModel::moduleUnlocked(bool) { - Q_ASSERT(qobject_cast<CSwordModuleInfo*>(sender()) != 0); + Q_ASSERT(qobject_cast<CSwordModuleInfo *>(sender()) != 0); - moduleDataChanged(static_cast<CSwordModuleInfo*>(sender())); + moduleDataChanged(static_cast<CSwordModuleInfo *>(sender())); } -void BtBookshelfModel::moduleDataChanged(CSwordModuleInfo *module) { +void BtBookshelfModel::moduleDataChanged(CSwordModuleInfo * module) { Q_ASSERT(m_data.count(module) == 1); QModelIndex i(index(m_data.indexOf(module), 0)); diff --git a/src/backend/bookshelfmodel/btbookshelfmodel.h b/src/backend/bookshelfmodel/btbookshelfmodel.h index 20f2b3d..0884b4c 100644 --- a/src/backend/bookshelfmodel/btbookshelfmodel.h +++ b/src/backend/bookshelfmodel/btbookshelfmodel.h @@ -4,7 +4,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License * version 2.0. * @@ -25,148 +25,157 @@ BtBookshelfTreeModel might be a better choice, since it also provides sorting and grouping. */ 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, - ModuleHiddenRole = Qt::UserRole + 3, - ModuleInstallPathRole = Qt::UserRole + 4, - ModuleHasIndexRole = Qt::UserRole + 5, - ModuleIndexSizeRole = Qt::UserRole + 6, - ModuleDescriptionRole = Qt::UserRole + 7, - UserRole = Qt::UserRole + 100 - }; - - public: - BtBookshelfModel(QObject *parent = 0); - ~BtBookshelfModel(); - - // Virtual methods implemented from QAbstractListModel: - int rowCount(const QModelIndex &parent = QModelIndex()) const; - QVariant data(CSwordModuleInfo *module, int role) const; - QVariant data(const QModelIndex &index, int role) const; - QVariant headerData(int section, Qt::Orientation orientation, - int role = Qt::DisplayRole) const; - bool setData(const QModelIndex &index, const QVariant &value, - int role = ModuleHiddenRole); - - /** - Given an index of this model, this method returns a pointer to the underlying - CSwordModuleInfo instance corresponding to the given index. - \param[in] index An index to this model. - */ - inline CSwordModuleInfo *module(const QModelIndex &index) const { - return (CSwordModuleInfo *) - data(index, BtBookshelfModel::ModulePointerRole) - .value<void *>(); - } - - /** - Clears the data of the whole model by removing all items. - \param[in] destroy If true, all CSwordModuleInfo instances in this model are also - destroyed. - */ - void clear(bool destroy = false); - - /** - Appends the given module to this model. - \param[in] module Module to add. - */ - void addModule(CSwordModuleInfo * const module); - - /** - Appends the all the modules in the given set to this model. - \param[in] modules Set of modules to add. - */ - void addModules(const QSet<CSwordModuleInfo *> &modules); - - /** - Appends the all the modules in the given list to this model. - \param[in] modules Set of modules to add. - */ - void addModules(const QList<CSwordModuleInfo *> &modules); - - /** - Removes the given module from this model and optionally destroys it. - \param[in] module The module to remove from this model. - \param[in] destroy If true, the given CSwordModuleInfo instance is destroyed. - */ - void removeModule(CSwordModuleInfo * const module, - bool destroy = false); - - /** - Removes all modules from the given set from this model and optionally destroys - them. - \param[in] modules The set of modules to remove from this model. - \param[in] destroy If true, the given CSwordModuleInfo instances are destroyed. - */ - void removeModules(const QSet<CSwordModuleInfo *> &modules, - bool destroy = false); - - /** - Removes all modules from the given list from this model and optionally destroys - them. - \param[in] modules The list of modules to remove from this model. - \param[in] destroy If true, the given CSwordModuleInfo instances are destroyed. - */ - void removeModules(const QList<CSwordModuleInfo *> &modules, - bool destroy = false); - - /** - Returns the first module found with the given name. - \param[in] name Name of the module to find. - */ - CSwordModuleInfo* getModule(const QString &name) const; - - /** - Returns the list of handled modules as a list of CSwordModuleInfo* pointers. - */ - inline const QList<CSwordModuleInfo *> &moduleList() const { - return m_data; - } - - protected slots: - /** - Slot DIRECTLY called by CSwordModuleInfo when the hidden status of the respective - module changes. - \param[in] hidden True, if the module was hidden; false, if the module was shown. - */ - void moduleHidden(bool hidden); - - /** - Slot DIRECTLY called by CSwordModuleInfo when the indexed status of the respective - module changes. - \param[in] indexed True, if the module was indexed; false if the index was deleted. - */ - void moduleIndexed(bool indexed); - - /** - Slot DIRECTLY called by CSwordModuleInfo when the locked status of the respective - module changes. - \param[in] unlocked True, if the module was unlocked; false if the module was - locked. - */ - void moduleUnlocked(bool unlocked); - - protected: - /** - Called internally when module data changes. This method emits any neccessary - signals for this model. - \pre The givem module is handled by this model. - \param[in] module The module that changed status. - */ - void moduleDataChanged(CSwordModuleInfo *module); - - protected: - /** - The underlying data as a list of pointers to the respective CSwordModuleInfo - instances. - */ - QList<CSwordModuleInfo *> m_data; + + Q_OBJECT + +public: /* Types: */ + + enum ModuleRole { + ModuleNameRole = Qt::DisplayRole, + ModuleIconRole = Qt::DecorationRole, + ModulePointerRole = Qt::UserRole, + ModuleCategoryRole = Qt::UserRole + 1, + ModuleLanguageRole = Qt::UserRole + 2, + ModuleHiddenRole = Qt::UserRole + 3, + ModuleInstallPathRole = Qt::UserRole + 4, + ModuleHasIndexRole = Qt::UserRole + 5, + ModuleIndexSizeRole = Qt::UserRole + 6, + ModuleDescriptionRole = Qt::UserRole + 7, + UserRole = Qt::UserRole + 100 + }; + +public: /* Methods: */ + + inline BtBookshelfModel(QObject * const parent = 0) + : QAbstractListModel(parent) {} + + // Virtual methods implemented from QAbstractListModel: + int rowCount(const QModelIndex & parent = QModelIndex()) const; + QVariant data(CSwordModuleInfo * module, int role) const; + QVariant data(const QModelIndex & index, int role) const; + QVariant headerData(int section, + Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + bool setData(const QModelIndex & index, + const QVariant & value, + int role = ModuleHiddenRole); + + /** + Given an index of this model, this method returns a pointer to the underlying + CSwordModuleInfo instance corresponding to the given index. + \param[in] index An index to this model. + */ + inline CSwordModuleInfo * module(const QModelIndex & index) const { + return static_cast<CSwordModuleInfo *>( + data(index, BtBookshelfModel::ModulePointerRole).value<void *>()); + } + + /** + Clears the data of the whole model by removing all items. + \param[in] destroy If true, all CSwordModuleInfo instances in this model are also + destroyed. + */ + void clear(bool destroy = false); + + /** + Appends the given module to this model. + \param[in] module Module to add. + */ + void addModule(CSwordModuleInfo * const module); + + /** + Appends the all the modules in the given set to this model. + \param[in] modules Set of modules to add. + */ + void addModules(const QSet<CSwordModuleInfo *> & modules); + + /** + Appends the all the modules in the given list to this model. + \param[in] modules Set of modules to add. + */ + void addModules(const QList<CSwordModuleInfo *> & modules); + + /** + Removes the given module from this model and optionally destroys it. + \param[in] module The module to remove from this model. + \param[in] destroy If true, the given CSwordModuleInfo instance is destroyed. + */ + void removeModule(CSwordModuleInfo * const module, + bool destroy = false); + + /** + Removes all modules from the given set from this model and optionally destroys + them. + \param[in] modules The set of modules to remove from this model. + \param[in] destroy If true, the given CSwordModuleInfo instances are destroyed. + */ + void removeModules(const QSet<CSwordModuleInfo *> & modules, + bool destroy = false); + + /** + Removes all modules from the given list from this model and optionally destroys + them. + \param[in] modules The list of modules to remove from this model. + \param[in] destroy If true, the given CSwordModuleInfo instances are destroyed. + */ + void removeModules(const QList<CSwordModuleInfo *> & modules, + bool destroy = false); + + /** + Returns the first module found with the given name. + \param[in] name Name of the module to find. + */ + CSwordModuleInfo* getModule(const QString & name) const; + + /** + Returns the list of handled modules as a list of CSwordModuleInfo* pointers. + */ + inline const QList<CSwordModuleInfo *> & moduleList() const { + return m_data; + } + +protected slots: + + /** + Slot DIRECTLY called by CSwordModuleInfo when the hidden status of the respective + module changes. + \param[in] hidden True, if the module was hidden; false, if the module was shown. + */ + void moduleHidden(bool hidden); + + /** + Slot DIRECTLY called by CSwordModuleInfo when the indexed status of the respective + module changes. + \param[in] indexed True, if the module was indexed; false if the index was deleted. + */ + void moduleIndexed(bool indexed); + + /** + Slot DIRECTLY called by CSwordModuleInfo when the locked status of the respective + module changes. + \param[in] unlocked True, if the module was unlocked; false if the module was + locked. + */ + void moduleUnlocked(bool unlocked); + +private: /* Methods: */ + + /** + Called internally when module data changes. This method emits any neccessary + signals for this model. + \pre The givem module is handled by this model. + \param[in] module The module that changed status. + */ + void moduleDataChanged(CSwordModuleInfo * module); + +private: /* Fields: */ + + /** + The underlying data as a list of pointers to the respective CSwordModuleInfo + instances. + */ + QList<CSwordModuleInfo *> m_data; + }; #endif // BTBOOKSHELFMODEL_H diff --git a/src/backend/bookshelfmodel/btbookshelftreemodel.cpp b/src/backend/bookshelfmodel/btbookshelftreemodel.cpp index 0fcd14e..f3dbc4a 100644 --- a/src/backend/bookshelfmodel/btbookshelftreemodel.cpp +++ b/src/backend/bookshelfmodel/btbookshelftreemodel.cpp @@ -4,7 +4,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License * version 2.0. * @@ -13,20 +13,19 @@ #include "backend/bookshelfmodel/btbookshelftreemodel.h" #include <QSet> -#include <QSettings> #include "backend/bookshelfmodel/categoryitem.h" #include "backend/bookshelfmodel/indexingitem.h" #include "backend/bookshelfmodel/languageitem.h" #include "backend/bookshelfmodel/moduleitem.h" -#include "backend/config/cbtconfig.h" +#include "backend/config/btconfig.h" #include "util/macros.h" using namespace BookshelfModel; -bool BtBookshelfTreeModel::Grouping::loadFrom(const QString &configKey) { +bool BtBookshelfTreeModel::Grouping::loadFrom(const QString & configKey) { Q_ASSERT(!configKey.isNull()); - QVariant v = CBTConfig::getConfig()->value(configKey); + QVariant v = btConfig().qVariantValue(configKey, QVariant()); if (!v.canConvert<Grouping>()) return false; @@ -34,141 +33,142 @@ bool BtBookshelfTreeModel::Grouping::loadFrom(const QString &configKey) { return true; } -void BtBookshelfTreeModel::Grouping::saveTo(const QString &configKey) const { +void BtBookshelfTreeModel::Grouping::saveTo(const QString & configKey) const { Q_ASSERT(!configKey.isNull()); - CBTConfig::getConfig()->setValue(configKey, QVariant::fromValue(*this)); -} - - -BtBookshelfTreeModel::BtBookshelfTreeModel(QObject *parent) - : QAbstractItemModel(parent), m_sourceModel(0), m_rootItem(new RootItem), - m_defaultChecked(MODULE_HIDDEN), m_checkable(false) -{ - // Intentionally empty -} - -BtBookshelfTreeModel::BtBookshelfTreeModel(const QString &configKey, - QObject *parent) - : QAbstractItemModel(parent), m_sourceModel(0), m_rootItem(new RootItem), - m_groupingOrder(configKey), m_defaultChecked(MODULE_HIDDEN), - m_checkable(false) -{ - // Intentionally empty -} - -BtBookshelfTreeModel::BtBookshelfTreeModel(const Grouping &g, QObject *parent) - : QAbstractItemModel(parent), m_sourceModel(0), m_rootItem(new RootItem), - m_groupingOrder(g), m_defaultChecked(MODULE_HIDDEN), m_checkable(false) -{ - // Intentionally empty -} + btConfig().setValue(configKey, QVariant::fromValue(*this)); +} + +BtBookshelfTreeModel::BtBookshelfTreeModel(QObject * parent) + : QAbstractItemModel(parent) + , m_sourceModel(0) + , m_rootItem(new RootItem) + , m_defaultChecked(MODULE_HIDDEN) + , m_checkable(false) {} + +BtBookshelfTreeModel::BtBookshelfTreeModel(const QString & configKey, + QObject * parent) + : QAbstractItemModel(parent) + , m_sourceModel(0) + , m_rootItem(new RootItem) + , m_groupingOrder(configKey) + , m_defaultChecked(MODULE_HIDDEN) + , m_checkable(false) {} + +BtBookshelfTreeModel::BtBookshelfTreeModel(const Grouping & grouping, + QObject * parent) + : QAbstractItemModel(parent) + , m_sourceModel(0) + , m_rootItem(new RootItem) + , m_groupingOrder(grouping) + , m_defaultChecked(MODULE_HIDDEN) + , m_checkable(false) {} BtBookshelfTreeModel::~BtBookshelfTreeModel() { delete m_rootItem; } -int BtBookshelfTreeModel::rowCount(const QModelIndex &parent) const { - return getItem(parent)->children().size(); +int BtBookshelfTreeModel::rowCount(const QModelIndex & parent) const { + return getItem(parent).children().size(); } -int BtBookshelfTreeModel::columnCount(const QModelIndex &parent) const { +int BtBookshelfTreeModel::columnCount(const QModelIndex & parent) const { Q_UNUSED(parent); return 1; } -bool BtBookshelfTreeModel::hasChildren(const QModelIndex &parent) const { - return !getItem(parent)->children().isEmpty(); +bool BtBookshelfTreeModel::hasChildren(const QModelIndex & parent) const { + return !getItem(parent).children().isEmpty(); } QModelIndex BtBookshelfTreeModel::index(int row, int column, - const QModelIndex &parent) const { + const QModelIndex & parent) const +{ if (!hasIndex(row, column, parent)) return QModelIndex(); - Item *parentItem(getItem(parent)); - Item *childItem(parentItem->children().at(row)); - if (childItem != 0) { - return createIndex(row, column, childItem); - } - else { + Item & parentItem = getItem(parent); + Item * const childItem = parentItem.children().at(row); + if (!childItem) return QModelIndex(); - } + + return createIndex(row, column, childItem); } -QModelIndex BtBookshelfTreeModel::parent(const QModelIndex &index) const { - if (!index.isValid()) return QModelIndex(); +QModelIndex BtBookshelfTreeModel::parent(const QModelIndex & index) const { + if (!index.isValid()) + return QModelIndex(); - Item *childItem(static_cast<Item*>(index.internalPointer())); + Item * childItem(static_cast<Item*>(index.internalPointer())); Q_ASSERT(childItem != 0); - Item *parentItem(childItem->parent()); + Item * parentItem(childItem->parent()); Q_ASSERT(parentItem != 0); - if (parentItem == m_rootItem) { + if (parentItem == m_rootItem) return QModelIndex(); - } + return createIndex(parentItem->childIndex(), 0, parentItem); } -QVariant BtBookshelfTreeModel::data(const QModelIndex &index, int role) const { - if (!index.isValid() || index.column() != 0) { +QVariant BtBookshelfTreeModel::data(const QModelIndex & index, int role) const { + if (!index.isValid() || index.column() != 0) return QVariant(); - } - Item *i(static_cast<Item*>(index.internalPointer())); + const Item * const i = static_cast<Item*>(index.internalPointer()); Q_ASSERT(i != 0); switch (role) { + case Qt::CheckStateRole: - if (!m_checkable) break; + if (!m_checkable) + break; + case BtBookshelfTreeModel::CheckStateRole: return i->checkState(); + case BtBookshelfModel::ModulePointerRole: /* This case is just an optimization. */ if (i->type() == Item::ITEM_MODULE) { - ModuleItem *mi(static_cast<ModuleItem *>(i)); - return qVariantFromValue((void*) mi->moduleInfo()); + const ModuleItem & mi = *static_cast<const ModuleItem *>(i); + return qVariantFromValue(static_cast<void *>(&mi.moduleInfo())); } return 0; + case Qt::DisplayRole: case Qt::DecorationRole: case BtBookshelfModel::ModuleHiddenRole: default: - if (i->type() == Item::ITEM_MODULE) { - ModuleItem *item(static_cast<ModuleItem *>(i)); - CSwordModuleInfo* m(item->moduleInfo()); - return data(m, role); - } - else { - return i->data(role); - } + if (i->type() == Item::ITEM_MODULE) + return data(static_cast<const ModuleItem *>(i)->moduleInfo(), role); + + return i->data(role); + } return QVariant(); } -QVariant BtBookshelfTreeModel::data(CSwordModuleInfo *module, int role) const { - Q_ASSERT(m_sourceIndexMap.contains(module)); - return m_sourceModel->data(m_sourceIndexMap.value(module), role); +QVariant BtBookshelfTreeModel::data(CSwordModuleInfo & module, int role) const { + Q_ASSERT(m_sourceIndexMap.contains(&module)); + return m_sourceModel->data(m_sourceIndexMap.value(&module), role); } -bool BtBookshelfTreeModel::setData(const QModelIndex &itemIndex, - const QVariant &value, +bool BtBookshelfTreeModel::setData(const QModelIndex & itemIndex, + const QVariant & value, int role) { Q_ASSERT(itemIndex.isValid()); typedef QPair<Item *, QModelIndex> IP; - Qt::CheckState newState; - if (LIKELY(role == Qt::CheckStateRole)) { - bool ok; - newState = (Qt::CheckState) value.toInt(&ok); - if (UNLIKELY(!ok)) return false; - } - else { + if (UNLIKELY(role != Qt::CheckStateRole)) + return false; + + bool ok; + Qt::CheckState newState = static_cast<Qt::CheckState>(value.toInt(&ok)); + if (UNLIKELY(!ok)) return false; - } // Handle partially checked as checked here in setData(): - if (newState == Qt::PartiallyChecked) newState = Qt::Checked; + if (newState == Qt::PartiallyChecked) + newState = Qt::Checked; - Item *item(static_cast<Item*>(itemIndex.internalPointer())); + Item * item = static_cast<Item *>(itemIndex.internalPointer()); Q_ASSERT(item != 0); if (item->checkState() == newState) return false; @@ -180,25 +180,23 @@ bool BtBookshelfTreeModel::setData(const QModelIndex &itemIndex, item->setCheckState(newState); emit dataChanged(p.second, p.second); if (item->type() == Item::ITEM_MODULE) { - ModuleItem *mItem(static_cast<ModuleItem*>(item)); - CSwordModuleInfo *mInfo(mItem->moduleInfo()); + ModuleItem & mItem = *static_cast<ModuleItem *>(item); + CSwordModuleInfo & mInfo = mItem.moduleInfo(); if (newState == Qt::Checked) { - m_checkedModulesCache.insert(mInfo); - emit moduleChecked(mInfo, true); - } - else { - m_checkedModulesCache.remove(mInfo); - emit moduleChecked(mInfo, false); + m_checkedModulesCache.insert(&mInfo); + emit moduleChecked(&mInfo, true); + } else { + m_checkedModulesCache.remove(&mInfo); + emit moduleChecked(&mInfo, false); } - } - else { - const QList<Item*> &children(item->children()); - for (int i(0); i < children.size(); i++) { + } else { + 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))); - } } } - if (q.empty()) break; + if (q.empty()) + break; p = q.takeFirst(); item = p.first; } @@ -209,36 +207,36 @@ bool BtBookshelfTreeModel::setData(const QModelIndex &itemIndex, return true; } -Qt::ItemFlags BtBookshelfTreeModel::flags(const QModelIndex &index) const { - if (!index.isValid()) return 0; +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) { + const Item & i = *static_cast<Item*>(index.internalPointer()); + 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) { + Qt::Orientation orientation, + int role) const +{ + if (orientation == Qt::Horizontal) return m_sourceModel->headerData(section, orientation, role); - } + return QVariant(); } -void BtBookshelfTreeModel::setSourceModel(QAbstractItemModel *sourceModel) { - if (m_sourceModel == sourceModel) return; +void BtBookshelfTreeModel::setSourceModel(QAbstractItemModel * sourceModel) { + if (m_sourceModel == sourceModel) + return; if (m_sourceModel != 0) { disconnect(this, SLOT(moduleInserted(QModelIndex, int, int))); @@ -263,43 +261,38 @@ void BtBookshelfTreeModel::setSourceModel(QAbstractItemModel *sourceModel) { connect(sourceModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(moduleDataChanged(QModelIndex, QModelIndex))); - for (int i(0); i < sourceModel->rowCount(); i++) { - typedef BtBookshelfModel::ModuleRole MRole; - static const MRole HR(BtBookshelfModel::ModuleHiddenRole); - static const MRole PR(BtBookshelfModel::ModulePointerRole); - static const MRole IR(BtBookshelfModel::ModuleHasIndexRole); - - QModelIndex moduleIndex(sourceModel->index(i, 0)); - CSwordModuleInfo *module( - static_cast<CSwordModuleInfo *>( - sourceModel->data(moduleIndex, PR).value<void*>() - ) - ); - Q_ASSERT(module != 0); + for (int i = 0; i < sourceModel->rowCount(); i++) { + const QModelIndex moduleIndex(sourceModel->index(i, 0)); + CSwordModuleInfo & module = *static_cast<CSwordModuleInfo *>( + sourceModel->data(moduleIndex, + BtBookshelfModel::ModulePointerRole).value<void*>()); + bool checked; if (m_defaultChecked == MODULE_HIDDEN) { - checked = !sourceModel->data(moduleIndex, HR).toBool(); - } - else if (m_defaultChecked == MODULE_INDEXED) { - checked = !sourceModel->data(moduleIndex, IR).toBool(); - } - else { + checked = !sourceModel->data(moduleIndex, + BtBookshelfModel::ModuleHiddenRole).toBool(); + } else if (m_defaultChecked == MODULE_INDEXED) { + checked = !sourceModel->data(moduleIndex, + BtBookshelfModel::ModuleHasIndexRole).toBool(); + } else { checked = (m_defaultChecked == CHECKED); } - m_sourceIndexMap[module] = moduleIndex; + m_sourceIndexMap[&module] = moduleIndex; addModule(module, checked); } } } -void BtBookshelfTreeModel::setGroupingOrder(const Grouping &groupingOrder, +void BtBookshelfTreeModel::setGroupingOrder(const Grouping & groupingOrder, bool emitSignal) { - if (m_groupingOrder == groupingOrder) return; + if (m_groupingOrder == groupingOrder) + return; + m_groupingOrder = groupingOrder; if (m_sourceModel != 0) { - QSet<CSwordModuleInfo*> checked(m_checkedModulesCache); + const QSet<CSwordModuleInfo *> checked(m_checkedModulesCache); m_checkedModulesCache.clear(); beginRemoveRows(QModelIndex(), 0, m_rootItem->children().size() - 1); @@ -308,42 +301,39 @@ void BtBookshelfTreeModel::setGroupingOrder(const Grouping &groupingOrder, m_rootItem = new RootItem; endRemoveRows(); - for (int i(0); i < m_sourceModel->rowCount(); i++) { - QModelIndex sourceIndex(m_sourceModel->index(i, 0)); - CSwordModuleInfo *module( - static_cast<CSwordModuleInfo *>( - m_sourceModel->data( - sourceIndex, - BtBookshelfModel::ModulePointerRole - ).value<void*>() - ) - ); - Q_ASSERT(module != 0); - m_sourceIndexMap[module] = sourceIndex; - addModule(module, checked.contains(module)); + for (int i = 0; i < m_sourceModel->rowCount(); i++) { + const QModelIndex sourceIndex(m_sourceModel->index(i, 0)); + CSwordModuleInfo & module = *static_cast<CSwordModuleInfo *>( + m_sourceModel->data(sourceIndex, + BtBookshelfModel::ModulePointerRole).value<void *>()); + m_sourceIndexMap[&module] = sourceIndex; + addModule(module, checked.contains(&module)); } } - if (emitSignal) emit groupingOrderChanged(groupingOrder); + if (emitSignal) + emit groupingOrderChanged(groupingOrder); } void BtBookshelfTreeModel::setCheckable(bool checkable) { - if (m_checkable == checkable) return; + if (m_checkable == checkable) + return; m_checkable = checkable; - if (m_sourceModel == 0) return; + if (m_sourceModel == 0) + return; // Notify views that flags changed for all items: resetData(); } -void BtBookshelfTreeModel::setCheckedModules(const QSet<CSwordModuleInfo*> &modules) { +void BtBookshelfTreeModel::setCheckedModules(const QSet<CSwordModuleInfo *> & modules) { typedef ModuleItemMap::const_iterator MIMCI; - for (MIMCI it(m_modules.constBegin()); it != m_modules.constEnd(); it++) { + for (MIMCI it = m_modules.constBegin(); it != m_modules.constEnd(); ++it) { if (modules.contains(it.key())) { - setData(getIndex(it.value()), Qt::Checked, Qt::CheckStateRole); + setData(getIndex(*it.value()), Qt::Checked, Qt::CheckStateRole); } else { - setData(getIndex(it.value()), Qt::Unchecked, Qt::CheckStateRole); + setData(getIndex(*it.value()), Qt::Unchecked, Qt::CheckStateRole); } } } @@ -355,18 +345,17 @@ void BtBookshelfTreeModel::resetData() { QModelIndex parent(queue.takeFirst()); emit dataChanged(index(0, 0, parent), index(rowCount(parent) - 1, columnCount() - 1, parent)); - for (int i(0); i < rowCount(parent); i++) { - QModelIndex childIndex(index(i, 0, parent)); - if (rowCount(childIndex) > 0) { + for (int i = 0; i < rowCount(parent); i++) { + const QModelIndex childIndex(index(i, 0, parent)); + if (rowCount(childIndex) > 0) queue.append(childIndex); - } } - } - while (!queue.isEmpty()); + } while (!queue.isEmpty()); } -void BtBookshelfTreeModel::addModule(CSwordModuleInfo *module, bool checked) { - if (m_modules.contains(module)) return; +void BtBookshelfTreeModel::addModule(CSwordModuleInfo & module, bool checked) { + if (m_modules.contains(&module)) + return; #if QT_VERSION >= 0x040600 beginResetModel(); @@ -388,42 +377,43 @@ void BtBookshelfTreeModel::addModule(CSwordModuleInfo *module, bool checked) { #endif } -void BtBookshelfTreeModel::addModule(CSwordModuleInfo *module, +void BtBookshelfTreeModel::addModule(CSwordModuleInfo & module, QModelIndex parentIndex, - Grouping &intermediateGrouping, - bool checked) { - Q_ASSERT(module != 0); - + Grouping & intermediateGrouping, + bool checked) +{ if (!intermediateGrouping.empty()) { QModelIndex newIndex; switch (intermediateGrouping.front()) { + case GROUP_CATEGORY: newIndex = getGroup<CategoryItem>(module, parentIndex); break; + case GROUP_LANGUAGE: newIndex = getGroup<LanguageItem>(module, parentIndex); break; + case GROUP_INDEXING: newIndex = getGroup<IndexingItem>(module, parentIndex); break; + } intermediateGrouping.pop_front(); addModule(module, newIndex, intermediateGrouping, checked); - } - else { - Item *parentItem(getItem(parentIndex)); - ModuleItem *newItem(new ModuleItem(module, this)); + } else { + Item & parentItem = getItem(parentIndex); + ModuleItem * const newItem = new ModuleItem(module, *this); newItem->setCheckState(checked ? Qt::Checked : Qt::Unchecked); - const int newIndex(parentItem->indexFor(newItem)); + const int newIndex(parentItem.indexFor(newItem)); // Actually do the insertion: beginInsertRows(parentIndex, newIndex, newIndex); - parentItem->insertChild(newIndex, newItem); - m_modules.insert(module, newItem); - if (checked) { - // Add to checked modules cache - m_checkedModulesCache.insert(module); - } + parentItem.insertChild(newIndex, newItem); + m_modules.insert(&module, newItem); + if (checked) // Add to checked modules cache + m_checkedModulesCache.insert(&module); + endInsertRows(); // Reset parent item check states, if needed: @@ -431,85 +421,84 @@ void BtBookshelfTreeModel::addModule(CSwordModuleInfo *module, } } -void BtBookshelfTreeModel::removeModule(CSwordModuleInfo *module) { - if (!m_modules.contains(module)) return; +void BtBookshelfTreeModel::removeModule(CSwordModuleInfo & module) { + typedef ModuleItemMap::iterator MIMI; + const MIMI it = m_modules.find(&module); + if (it == m_modules.end()) + return; - Item *i(m_modules[module]); + Item * i = it.value(); // 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) { + Q_ASSERT(i->parent()); + while (i->parent() != m_rootItem && i->parent()->children().size() <= 1) i = i->parent(); - } - Q_ASSERT(i != 0); - Q_ASSERT(i->parent() != 0); + Q_ASSERT(i); + Q_ASSERT(i->parent()); // Calculate item indexes: - int index(i->childIndex()); - QModelIndex parentIndex(getIndex(i->parent())); + const int index = i->childIndex(); + const QModelIndex parentIndex(getIndex(*i->parent())); // Actually remove the item: beginRemoveRows(parentIndex, index, index); delete i->parent()->children().takeAt(index); - m_modules.remove(module); - m_checkedModulesCache.remove(module); + m_modules.erase(it); + m_checkedModulesCache.remove(&module); endRemoveRows(); // Reset parent item check states, if needed: resetParentCheckStates(parentIndex); } -Item *BtBookshelfTreeModel::getItem(const QModelIndex &index) const { - if (LIKELY(index.isValid())) { - Item *item(static_cast<Item*>(index.internalPointer())); - Q_ASSERT(item != 0); - return item; - } - else { - return m_rootItem; - } -} +Item & BtBookshelfTreeModel::getItem(const QModelIndex & index) const { + if (UNLIKELY(!index.isValid())) + return *m_rootItem; -QModelIndex BtBookshelfTreeModel::getIndex(const BookshelfModel::Item *item) { - Q_ASSERT(item != 0); + Item * const item = static_cast<Item *>(index.internalPointer()); + Q_ASSERT(item); + return *item; +} +QModelIndex BtBookshelfTreeModel::getIndex(const BookshelfModel::Item & item) { + const BookshelfModel::Item * it = &item; QList<int> indexes; for (;;) { - int i(item->childIndex()); - if (i < 0) break; + const int i = it->childIndex(); + if (i < 0) + break; indexes.append(i); - item = item->parent(); + it = it->parent(); } QModelIndex i; - while (!indexes.isEmpty()) { + while (!indexes.isEmpty()) i = index(indexes.takeLast(), 0, i); - } return i; } 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->children().at(i)->checkState()); + Item & parentItem = *static_cast<Item *>(parentIndex.internalPointer()); + + const Qt::CheckState oldState = parentItem.checkState(); + bool haveCheckedChildren = false; + bool haveUncheckedChildren = false; + for (int i = 0; i < parentItem.children().size(); i++) { + const Qt::CheckState state = parentItem.children().at(i)->checkState(); if (state == Qt::PartiallyChecked) { haveCheckedChildren = true; haveUncheckedChildren = true; break; - } - else if (state == Qt::Checked) { + } else if (state == Qt::Checked) { haveCheckedChildren = true; - if (haveUncheckedChildren) break; - } - else if (state == Qt::Unchecked) { + if (haveUncheckedChildren) + break; + } else { + Q_ASSERT(state == Qt::Unchecked); haveUncheckedChildren = true; - if (haveCheckedChildren) break; + if (haveCheckedChildren) + break; } } @@ -517,35 +506,34 @@ void BtBookshelfTreeModel::resetParentCheckStates(QModelIndex parentIndex) { if (haveCheckedChildren) { if (haveUncheckedChildren) { newState = Qt::PartiallyChecked; - } - else { + } else { newState = Qt::Checked; } - } - else { + } else { newState = Qt::Unchecked; } - if (newState == oldState) break; + if (newState == oldState) + break; - parentItem->setCheckState(newState); + 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); - +void BtBookshelfTreeModel::moduleDataChanged(const QModelIndex & topLeft, + const QModelIndex & bottomRight) +{ 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*>())); - QModelIndex itemIndex(getIndex(m_modules[module])); + Q_ASSERT(topLeft.column() == 0); + Q_ASSERT(bottomRight.column() == 0); + + for (int i = topLeft.row(); i <= bottomRight.row(); i++) { + const QModelIndex moduleIndex(m_sourceModel->index(i, 0, topLeft.parent())); + const QVariant data(m_sourceModel->data(moduleIndex, + BtBookshelfModel::ModulePointerRole)); + CSwordModuleInfo & module = *static_cast<CSwordModuleInfo *>(data.value<void *>()); + QModelIndex itemIndex(getIndex(*m_modules[&module])); Q_ASSERT(itemIndex.isValid()); emit dataChanged(itemIndex, itemIndex); @@ -557,67 +545,73 @@ void BtBookshelfTreeModel::moduleDataChanged(const QModelIndex &topLeft, do { itemIndex = itemIndex.parent(); emit dataChanged(itemIndex, itemIndex); - } - while (itemIndex.isValid()); + } while (itemIndex.isValid()); } } -void BtBookshelfTreeModel::moduleInserted(const QModelIndex &parent, int start, int end) { - typedef BtBookshelfModel BM; - static const BM::ModuleRole PR(BM::ModulePointerRole); - static const BM::ModuleRole HR(BM::ModuleHiddenRole); - static const BM::ModuleRole IR(BM::ModuleHasIndexRole); +void BtBookshelfTreeModel::moduleInserted(const QModelIndex & parent, + int start, + int end) +{ + Q_ASSERT(start <= end); - 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*>())); + for (int i = start; i <= end; i++) { + const QModelIndex moduleIndex(m_sourceModel->index(i, 0, parent)); + const QVariant data(m_sourceModel->data(moduleIndex, + BtBookshelfModel::ModulePointerRole)); + CSwordModuleInfo & module = *static_cast<CSwordModuleInfo *>(data.value<void *>()); bool checked; if (m_defaultChecked == MODULE_HIDDEN) { - checked = !m_sourceModel->data(moduleIndex, HR).toBool(); - } - else if (m_defaultChecked == MODULE_INDEXED) { - checked = !m_sourceModel->data(moduleIndex, IR).toBool(); - } - else { + checked = !m_sourceModel->data(moduleIndex, + BtBookshelfModel::ModuleHiddenRole).toBool(); + } else if (m_defaultChecked == MODULE_INDEXED) { + checked = !m_sourceModel->data(moduleIndex, + BtBookshelfModel::ModuleHasIndexRole).toBool(); + } else { + Q_ASSERT(m_defaultChecked == CHECKED || m_defaultChecked == UNCHECKED); checked = (m_defaultChecked == CHECKED); } - m_sourceIndexMap[module] = moduleIndex; + m_sourceIndexMap[&module] = moduleIndex; addModule(module, checked); } } -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*>())); +void BtBookshelfTreeModel::moduleRemoved(const QModelIndex & parent, + int start, + int end) +{ + Q_ASSERT(start <= end); + for (int i = start; i <= end; i++) { + const QModelIndex moduleIndex(m_sourceModel->index(i, 0, parent)); + const QVariant data(m_sourceModel->data(moduleIndex, + BtBookshelfModel::ModulePointerRole)); + CSwordModuleInfo & module = *static_cast<CSwordModuleInfo *>(data.value<void*>()); removeModule(module); - m_sourceIndexMap.remove(module); + m_sourceIndexMap.remove(&module); } } -QDataStream &operator<<(QDataStream &os, const BtBookshelfTreeModel::Grouping &o) { +QDataStream & operator <<(QDataStream & os, + const BtBookshelfTreeModel::Grouping & o) +{ os << o.size(); - Q_FOREACH(BtBookshelfTreeModel::Group g, o) { - os << (int) g; - } + Q_FOREACH(BtBookshelfTreeModel::Group g, o) + os << static_cast<int>(g); return os; } -QDataStream &operator>>(QDataStream &is, BtBookshelfTreeModel::Grouping &o) { +QDataStream & operator >>(QDataStream & is, + BtBookshelfTreeModel::Grouping & o) +{ int s; is >> s; o.clear(); - for (int i(0); i < s; i++) { + for (int i = 0; i < s; i++) { int g; is >> g; - o.append((BtBookshelfTreeModel::Group) g); + o.append(static_cast<BtBookshelfTreeModel::Group>(g)); } return is; } diff --git a/src/backend/bookshelfmodel/btbookshelftreemodel.h b/src/backend/bookshelfmodel/btbookshelftreemodel.h index 085095d..14c3289 100644 --- a/src/backend/bookshelfmodel/btbookshelftreemodel.h +++ b/src/backend/bookshelfmodel/btbookshelftreemodel.h @@ -4,7 +4,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License * version 2.0. * @@ -23,157 +23,181 @@ #include "backend/bookshelfmodel/item.h" -namespace BookshelfModel { -class ModuleItem; -} +namespace BookshelfModel { class ModuleItem; } class CSwordModuleInfo; class QDataStream; class BtBookshelfTreeModel: public QAbstractItemModel { - Q_OBJECT - Q_ENUMS(Group) - - typedef QMap<CSwordModuleInfo*, BookshelfModel::ModuleItem*> ModuleItemMap; - typedef QMap<CSwordModuleInfo*, QPersistentModelIndex> SourceIndexMap; - - public: /* Types: */ - enum ModuleRole { - CheckStateRole = BtBookshelfModel::UserRole, - UserRole = BtBookshelfModel::UserRole + 100 - }; - enum Group { - GROUP_CATEGORY = 0, - GROUP_LANGUAGE = 1, - GROUP_INDEXING - }; - enum CheckedBehavior { - CHECKED, /**< Check all added modules by default. */ - UNCHECKED, /**< Uncheck all added modules by default. */ - MODULE_HIDDEN, /**< By default, check only added modules that are not hidden. */ - MODULE_INDEXED /**< By default, check only added modules that are indexed. */ - }; - - class Grouping: public QList<Group> { - public: - /** - \warning Be careful using this constructor! - */ - explicit inline Grouping(bool empty = false) { - if (empty) - return; - push_back(GROUP_CATEGORY); - push_back(GROUP_LANGUAGE); - } - explicit inline Grouping(Group group) { push_back(group); } - explicit inline Grouping(const QString &configKey) { - if (loadFrom(configKey)) - return; - push_back(GROUP_CATEGORY); - push_back(GROUP_LANGUAGE); - } - inline Grouping(const Grouping ©) - : QList<Group>(copy) {} - - bool loadFrom(const QString &configKey); - void saveTo(const QString &configKey) const; - }; - - public: /* Methods: */ - BtBookshelfTreeModel(QObject *parent = 0); - BtBookshelfTreeModel(const QString &configKey, QObject *parent = 0); - BtBookshelfTreeModel(const Grouping &grouping, 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 = Qt::DisplayRole) const; - QVariant data(CSwordModuleInfo *module, int role = Qt::DisplayRole) 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); - - inline QAbstractItemModel *sourceModel() const { return m_sourceModel; } - inline const Grouping &groupingOrder() const { return m_groupingOrder; } - inline bool checkable() const { return m_checkable; } - inline CheckedBehavior defaultChecked() const { return m_defaultChecked; } - inline QList<CSwordModuleInfo*> modules() const { return m_modules.keys(); } - inline const QSet<CSwordModuleInfo*> &checkedModules() const { - return m_checkedModulesCache; - } - public slots: - void setSourceModel(QAbstractItemModel *sourceModel); - void setGroupingOrder(const BtBookshelfTreeModel::Grouping &groupingOrder, - bool emitSignal = true); - void setCheckable(bool checkable); - inline void setDefaultChecked(CheckedBehavior b) { - m_defaultChecked = b; - } - void setCheckedModules(const QSet<CSwordModuleInfo*> &modules); - - signals: - void groupingOrderChanged(BtBookshelfTreeModel::Grouping newGrouping); - void moduleChecked(CSwordModuleInfo *module, bool checked); - - protected: - void resetData(); - QVariant parentData(BookshelfModel::ModuleItem *item, int role) const; - 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; - QModelIndex getIndex(const BookshelfModel::Item *item); - 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(); + Q_OBJECT + Q_ENUMS(Group) + +private: /* Types: */ + + typedef QMap<CSwordModuleInfo *, BookshelfModel::ModuleItem *> ModuleItemMap; + typedef QMap<CSwordModuleInfo *, QPersistentModelIndex> SourceIndexMap; + +public: /* Types: */ + + enum ModuleRole { + CheckStateRole = BtBookshelfModel::UserRole, + UserRole = BtBookshelfModel::UserRole + 100 + }; + + enum Group { + GROUP_CATEGORY = 0, + GROUP_LANGUAGE = 1, + GROUP_INDEXING + }; + + enum CheckedBehavior { + CHECKED, /**< Check all added modules by default. */ + UNCHECKED, /**< Uncheck all added modules by default. */ + MODULE_HIDDEN, /**< By default, check only added modules that are not hidden. */ + MODULE_INDEXED /**< By default, check only added modules that are indexed. */ + }; + + class Grouping: public QList<Group> { + + public: /* Methods: */ + + /** + \warning Be careful using this constructor! + */ + explicit inline Grouping(bool empty = false) { + if (empty) + return; + push_back(GROUP_CATEGORY); + push_back(GROUP_LANGUAGE); + } + + explicit inline Grouping(Group group) { push_back(group); } + + explicit inline Grouping(const QString & configKey) { + if (loadFrom(configKey)) + return; + push_back(GROUP_CATEGORY); + push_back(GROUP_LANGUAGE); } - return index(groupIndex, 0, parentIndex); + + inline Grouping(const Grouping & copy) + : QList<Group>(copy) {} + + bool loadFrom(const QString & configKey); + void saveTo(const QString & configKey) const; + + }; + +public: /* Methods: */ + + BtBookshelfTreeModel(QObject * parent = 0); + BtBookshelfTreeModel(const QString & configKey, QObject * parent = 0); + BtBookshelfTreeModel(const Grouping & grouping, 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 = Qt::DisplayRole) const; + QVariant data(CSwordModuleInfo & module, int role = Qt::DisplayRole) 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); + + inline QAbstractItemModel * sourceModel() const { return m_sourceModel; } + inline const Grouping & groupingOrder() const { return m_groupingOrder; } + inline bool checkable() const { return m_checkable; } + inline CheckedBehavior defaultChecked() const { return m_defaultChecked; } + inline QList<CSwordModuleInfo *> modules() const { return m_modules.keys(); } + inline const QSet<CSwordModuleInfo *> & checkedModules() const { + return m_checkedModulesCache; + } + +public slots: + + void setSourceModel(QAbstractItemModel * sourceModel); + void setGroupingOrder(const BtBookshelfTreeModel::Grouping & groupingOrder, + bool emitSignal = true); + void setCheckable(bool checkable); + inline void setDefaultChecked(CheckedBehavior b) { + m_defaultChecked = b; + } + void setCheckedModules(const QSet<CSwordModuleInfo *> & modules); + +signals: + + void groupingOrderChanged(BtBookshelfTreeModel::Grouping newGrouping); + void moduleChecked(CSwordModuleInfo * module, bool checked); + +protected: /* Methods: */ + + void resetData(); + +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); + +private: /* Methods: */ + + 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; + QModelIndex getIndex(const BookshelfModel::Item & item); + 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) { + groupItem = new T(module); + groupIndex = parentItem.indexFor(groupItem); + beginInsertRows(parentIndex, groupIndex, groupIndex); + parentItem.insertChild(groupIndex, groupItem); + endInsertRows(); } + return index(groupIndex, 0, parentIndex); + } + +private: /* Fields: */ + + QAbstractItemModel * m_sourceModel; + BookshelfModel::Item * m_rootItem; + ModuleItemMap m_modules; + SourceIndexMap m_sourceIndexMap; + Grouping m_groupingOrder; + CheckedBehavior m_defaultChecked; + bool m_checkable; + + QSet<CSwordModuleInfo *> m_checkedModulesCache; - 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: - QAbstractItemModel *m_sourceModel; - BookshelfModel::Item *m_rootItem; - ModuleItemMap m_modules; - SourceIndexMap m_sourceIndexMap; - Grouping m_groupingOrder; - CheckedBehavior m_defaultChecked; - bool m_checkable; - - QSet<CSwordModuleInfo*> m_checkedModulesCache; }; -QDataStream &operator<<(QDataStream &os, const BtBookshelfTreeModel::Grouping &o); -QDataStream &operator>>(QDataStream &is, BtBookshelfTreeModel::Grouping &o); +QDataStream & operator <<(QDataStream & os, const BtBookshelfTreeModel::Grouping & o); +QDataStream & operator >>(QDataStream & is, BtBookshelfTreeModel::Grouping & o); -Q_DECLARE_METATYPE(BtBookshelfTreeModel::Grouping); +Q_DECLARE_METATYPE(BtBookshelfTreeModel::Grouping) #endif // BTBOOKSHELFTREEMODEL_H diff --git a/src/backend/bookshelfmodel/categoryitem.cpp b/src/backend/bookshelfmodel/categoryitem.cpp index aaf5566..20ba8e4 100644 --- a/src/backend/bookshelfmodel/categoryitem.cpp +++ b/src/backend/bookshelfmodel/categoryitem.cpp @@ -4,7 +4,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License * version 2.0. * @@ -15,29 +15,31 @@ namespace BookshelfModel { -CategoryItem::CategoryItem(CSwordModuleInfo *module) - : Item(ITEM_CATEGORY), m_category(module->category()) { - // Intentionally empty -} QVariant CategoryItem::data(int role) const { switch (role) { + case Qt::DisplayRole: return CSwordModuleInfo::categoryName(m_category); + case Qt::DecorationRole: return CSwordModuleInfo::categoryIcon(m_category); + default: return Item::data(role); + } } -bool CategoryItem::operator<(const Item &other) const { - if (other.type() != ITEM_CATEGORY) { +bool CategoryItem::operator<(const Item & other) const { + if (other.type() != ITEM_CATEGORY) return ITEM_CATEGORY < other.type(); - } - const CategoryItem &o(static_cast<const CategoryItem &>(other)); - if (m_category == CSwordModuleInfo::UnknownCategory) return false; - if (o.m_category == CSwordModuleInfo::UnknownCategory) return true; + + const CategoryItem & o = static_cast<const CategoryItem &>(other); + if (m_category == CSwordModuleInfo::UnknownCategory) + return false; + if (o.m_category == CSwordModuleInfo::UnknownCategory) + return true; return m_category < o.m_category; } diff --git a/src/backend/bookshelfmodel/categoryitem.h b/src/backend/bookshelfmodel/categoryitem.h index 75d5a7c..135f337 100644 --- a/src/backend/bookshelfmodel/categoryitem.h +++ b/src/backend/bookshelfmodel/categoryitem.h @@ -4,7 +4,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License * version 2.0. * @@ -22,28 +22,29 @@ namespace BookshelfModel { -class CategoryItem: public Item { - Q_DECLARE_TR_FUNCTIONS(CategoryItem); +class CategoryItem: public GroupItem<Item::ITEM_CATEGORY> { - public: - static const Item::Type GROUP_TYPE = Item::ITEM_CATEGORY; +public: /* Methods: */ - CategoryItem(CSwordModuleInfo *module); + inline CategoryItem(const CSwordModuleInfo & module) + : m_category(module.category()) {} - inline const CSwordModuleInfo::Category &category() const { - return m_category; - } + inline const CSwordModuleInfo::Category & category() const { + return m_category; + } - QVariant data(int role = Qt::DisplayRole) const; + QVariant data(int role = Qt::DisplayRole) const; - inline bool fitFor(CSwordModuleInfo *module) const { - return module->category() == m_category; - } + inline bool fitFor(const CSwordModuleInfo & module) const { + return module.category() == m_category; + } - bool operator<(const Item &other) const; + bool operator<(const Item & other) const; + +private: /* Fields: */ + + const CSwordModuleInfo::Category m_category; - protected: - CSwordModuleInfo::Category m_category; }; } // namespace BookshelfModel diff --git a/src/backend/bookshelfmodel/indexingitem.cpp b/src/backend/bookshelfmodel/indexingitem.cpp index 5491ca5..46488a4 100644 --- a/src/backend/bookshelfmodel/indexingitem.cpp +++ b/src/backend/bookshelfmodel/indexingitem.cpp @@ -4,7 +4,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License * version 2.0. * @@ -15,23 +15,13 @@ namespace BookshelfModel { -IndexingItem::IndexingItem(CSwordModuleInfo *module) - : Item(Item::ITEM_INDEXING), m_indexed(module->hasIndex()) { - // Intentionally empty -} - QVariant IndexingItem::data(int role) const { - switch (role) { - case Qt::DisplayRole: - if (m_indexed) { - return QObject::tr("Indexed works"); - } - else { - return QObject::tr("Unindexed works"); - } - default: - return Item::data(role); - } + if (role != Qt::DisplayRole) + return Item::data(role); + + return m_indexed + ? QObject::tr("Indexed works") + : QObject::tr("Unindexed works"); } } // namespace BookshelfModel diff --git a/src/backend/bookshelfmodel/indexingitem.h b/src/backend/bookshelfmodel/indexingitem.h index a1eb812..3e1e0cd 100644 --- a/src/backend/bookshelfmodel/indexingitem.h +++ b/src/backend/bookshelfmodel/indexingitem.h @@ -4,7 +4,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License * version 2.0. * @@ -20,20 +20,23 @@ namespace BookshelfModel { -class IndexingItem: public Item { - public: - static const Item::Type GROUP_TYPE = Item::ITEM_INDEXING; +class IndexingItem: public GroupItem<Item::ITEM_INDEXING> { - IndexingItem(CSwordModuleInfo *module); +public: /* Methods: */ - QVariant data(int role = Qt::DisplayRole) const; + inline IndexingItem(const CSwordModuleInfo & module) + : m_indexed(module.hasIndex()) {} - inline bool fitFor(CSwordModuleInfo *module) const { - return module->hasIndex() == m_indexed; - } + QVariant data(int role = Qt::DisplayRole) const; + + inline bool fitFor(const CSwordModuleInfo & module) const { + return module.hasIndex() == m_indexed; + } + +private: /* Fields: */ + + bool m_indexed; - protected: - bool m_indexed; }; } // namespace BookshelfModel diff --git a/src/backend/bookshelfmodel/item.cpp b/src/backend/bookshelfmodel/item.cpp index 02cd991..9d6e5af 100644 --- a/src/backend/bookshelfmodel/item.cpp +++ b/src/backend/bookshelfmodel/item.cpp @@ -4,7 +4,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License * version 2.0. * @@ -17,56 +17,56 @@ 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); +int Item::indexFor(Item * newItem) { + Q_ASSERT(newItem); - if (m_children.empty()) return 0; + if (m_children.empty()) + return 0; - int i(0); + int i = 0; for (;;) { - Item *nextItem(m_children.at(i)); + Item * const nextItem(m_children.at(i)); Q_ASSERT(nextItem->type() == newItem->type()); - if (*newItem < *nextItem) { + if (*newItem < *nextItem) return i; - } + i++; - if (i >= m_children.size()) { + if (i >= m_children.size()) return i; - } } } QVariant Item::data(int role) const { switch (role) { + case Qt::CheckStateRole: return m_checkState; + case BtBookshelfModel::ModuleHiddenRole: - if (m_children.empty()) return true; + if (m_children.empty()) + return true; - foreach (Item *child, m_children) { - if (!child->data(role).toBool()) return false; - } + Q_FOREACH (Item * child, m_children) + if (!child->data(role).toBool()) + return false; return true; + default: return QVariant(); + } } -bool Item::operator<(const Item &other) const { - if (m_type != other.type()) { +bool Item::operator<(const Item & other) const { + if (m_type != other.type()) return m_type < other.type(); - } - QString first(data(Qt::DisplayRole).toString().toLower()); - QString second(other.data(Qt::DisplayRole).toString().toLower()); + + const QString first(data(Qt::DisplayRole).toString().toLower()); + const QString second(other.data(Qt::DisplayRole).toString().toLower()); return first.localeAwareCompare(second) < 0; } diff --git a/src/backend/bookshelfmodel/item.h b/src/backend/bookshelfmodel/item.h index 652120b..712d4a2 100644 --- a/src/backend/bookshelfmodel/item.h +++ b/src/backend/bookshelfmodel/item.h @@ -4,7 +4,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License * version 2.0. * @@ -13,10 +13,7 @@ #ifndef ITEM_H #define ITEM_H -#include <QIcon> #include <QList> -#include <QString> -#include <QtGlobal> #include <QVariant> @@ -25,134 +22,165 @@ class CSwordModuleInfo; namespace BookshelfModel { class Item { - public: - enum Type { - ITEM_ROOT = 0, - ITEM_CATEGORY = 1, - ITEM_LANGUAGE = 2, - ITEM_MODULE = 3, - ITEM_INDEXING = 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; +public: /* Types: */ + + enum Type { + ITEM_ROOT = 0, + ITEM_CATEGORY = 1, + ITEM_LANGUAGE = 2, + ITEM_MODULE = 3, + ITEM_INDEXING = 4 + }; + +public: /* Methods: */ + + inline Item(Type type) + : m_type(type) + , m_parent(0) + , m_checkState(Qt::Unchecked) {} + + 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 QList<Item *> & children() { + return m_children; + } + + /** + \brief Returns the index of this item under its parent. + \retval -1 if this item has no parent. + */ + inline int childIndex() const { + return m_parent == 0 + ? -1 + : m_parent->m_children.indexOf(const_cast<Item *>(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); + } + + template <class T> + inline T * getGroupItem(CSwordModuleInfo & module, int & outIndex) { + for (int i = 0; i < m_children.size(); i++) { + Q_ASSERT(m_children.at(i)->type() == T::staticItemType()); + T * item = static_cast<T *>(m_children.at(i)); + if (item->fitFor(module)) { + outIndex = i; + return item; + } } + return 0; + } + + /** + \brief Returns data for this item. + */ + virtual QVariant data(int role = Qt::DisplayRole) const; + + /** + \brief Returns the check state of this item. + */ + inline 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 is a wrong group. + */ + inline virtual bool fitFor(const CSwordModuleInfo & module) const = 0; + + /** + \brief Comparsion operator used sorting child items. + */ + virtual bool operator<(const Item & other) const; + +private: /* Methods: */ + + inline void setParent(Item * parent) { + Q_ASSERT(parent != 0); + m_parent = parent; + } + +private: /* Fields: */ + + Type m_type; + Item * m_parent; + QList<Item *> m_children; + Qt::CheckState m_checkState; - /** - \brief Returns the list of child items of this node. - */ - inline QList<Item*> &children() { - return m_children; - } +}; - /** - \brief Returns the index of this item under its parent. - \retval -1 if this item has no parent. - */ - inline int childIndex() const { - if (m_parent == 0) return -1; - return m_parent->m_children.indexOf(const_cast<Item*>(this)); - } +class RootItem: public Item { - /** - \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); - } +public: /* Methods: */ - template <class T> - T *getGroupItem(CSwordModuleInfo *module, int &outIndex) { - 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)) { - outIndex = i; - return item; - } - } - return 0; - } + inline RootItem() + : Item(Item::ITEM_ROOT) {} - /** - \brief Returns data for this item. - */ - virtual QVariant data(int role = Qt::DisplayRole) const; + inline virtual bool fitFor(const CSwordModuleInfo &) const { + return true; + } - /** - \brief Returns the check state of this item. - */ - inline 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 is a wrong group. - */ - inline virtual bool fitFor(CSwordModuleInfo *module) const { - Q_UNUSED(module); - return false; - } +template <Item::Type TYPE> +class GroupItem: public Item { - /** - \brief Comparsion operator used sorting child items. - */ - virtual bool operator<(const Item &other) const; +public: /* Methods: */ - protected: - inline void setParent(Item *parent) { - Q_ASSERT(parent != 0); - m_parent = parent; - } + inline GroupItem() + : Item(TYPE) {} - protected: - Type m_type; - Item *m_parent; - QList<Item*> m_children; - Qt::CheckState m_checkState; -}; + inline static Item::Type staticItemType() { + return TYPE; + } -class RootItem: public Item { - public: - inline RootItem() : Item(Item::ITEM_ROOT) {} }; } // Namespace BookshelfModel diff --git a/src/backend/bookshelfmodel/languageitem.cpp b/src/backend/bookshelfmodel/languageitem.cpp index 2fdab8b..072d720 100644 --- a/src/backend/bookshelfmodel/languageitem.cpp +++ b/src/backend/bookshelfmodel/languageitem.cpp @@ -4,7 +4,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License * version 2.0. * @@ -12,22 +12,23 @@ #include "backend/bookshelfmodel/languageitem.h" +#include "util/geticon.h" -namespace BookshelfModel { -LanguageItem::LanguageItem(CSwordModuleInfo *module) - : Item(ITEM_LANGUAGE), m_language(module->language()) { - // Intentionally empty -} +namespace BookshelfModel { QVariant LanguageItem::data(int role) const { switch (role) { + case Qt::DisplayRole: return m_language->translatedName(); + case Qt::DecorationRole: - return util::directory::getIcon("flag.svg"); + return util::getIcon("flag.svg"); + default: return Item::data(role); + } } diff --git a/src/backend/bookshelfmodel/languageitem.h b/src/backend/bookshelfmodel/languageitem.h index 03a9ce3..1d1d5fa 100644 --- a/src/backend/bookshelfmodel/languageitem.h +++ b/src/backend/bookshelfmodel/languageitem.h @@ -4,7 +4,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License * version 2.0. * @@ -17,25 +17,27 @@ #include "backend/bookshelfmodel/btbookshelfmodel.h" #include "backend/drivers/cswordmoduleinfo.h" -#include "util/directory.h" namespace BookshelfModel { -class LanguageItem: public Item { - public: - static const Item::Type GROUP_TYPE = Item::ITEM_LANGUAGE; +class LanguageItem: public GroupItem<Item::ITEM_LANGUAGE> { - LanguageItem(CSwordModuleInfo *module); +public: /* Methods: */ - QVariant data(int role = Qt::DisplayRole) const; + inline LanguageItem(const CSwordModuleInfo & module) + : m_language(module.language()) {} - inline bool fitFor(CSwordModuleInfo *module) const { - return module->language() == m_language; - } + QVariant data(int role = Qt::DisplayRole) const; + + inline bool fitFor(const CSwordModuleInfo & module) const { + return module.language() == m_language; + } + +private: /* Fields: */ + + const CLanguageMgr::Language * m_language; - protected: - const CLanguageMgr::Language *m_language; }; } // namespace BookshelfModel diff --git a/src/backend/bookshelfmodel/moduleitem.cpp b/src/backend/bookshelfmodel/moduleitem.cpp index ca9c3fb..ffe8eb8 100644 --- a/src/backend/bookshelfmodel/moduleitem.cpp +++ b/src/backend/bookshelfmodel/moduleitem.cpp @@ -4,7 +4,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License * version 2.0. * @@ -18,16 +18,9 @@ namespace BookshelfModel { -ModuleItem::ModuleItem(CSwordModuleInfo *module, - BtBookshelfTreeModel *parentModel) - : Item(ITEM_MODULE), m_moduleInfo(module), m_parentModel(parentModel) { - Q_ASSERT(module != 0); - Q_ASSERT(parentModel != 0); -} - QVariant ModuleItem::data(int role) const { // Dispatch request to tree model: - return m_parentModel->data(m_moduleInfo, role); + return m_parentModel.data(m_moduleInfo, role); } } // namespace BookshelfModel diff --git a/src/backend/bookshelfmodel/moduleitem.h b/src/backend/bookshelfmodel/moduleitem.h index 5e6e1ba..071e3fe 100644 --- a/src/backend/bookshelfmodel/moduleitem.h +++ b/src/backend/bookshelfmodel/moduleitem.h @@ -4,7 +4,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License * version 2.0. * @@ -24,22 +24,34 @@ class BtBookshelfTreeModel; namespace BookshelfModel { class ModuleItem: public Item { - public: - ModuleItem(CSwordModuleInfo *module, BtBookshelfTreeModel *parentModel); - - /** - Reimplementation of Item::data() which dispatches all - requests to the parent model (BtBookshelfTreeModel). - */ - virtual QVariant data(int role = Qt::DisplayRole) const; - - inline CSwordModuleInfo *moduleInfo() const { - return m_moduleInfo; - } - - protected: - CSwordModuleInfo *m_moduleInfo; - BtBookshelfTreeModel *m_parentModel; + +public: /* Methods: */ + + ModuleItem(CSwordModuleInfo & module, + BtBookshelfTreeModel & parentModel) + : Item(ITEM_MODULE) + , m_moduleInfo(module) + , m_parentModel(parentModel) {} + + /** + Reimplementation of Item::data() which dispatches all + requests to the parent model (BtBookshelfTreeModel). + */ + virtual QVariant data(int role = Qt::DisplayRole) const; + + inline CSwordModuleInfo & moduleInfo() const { + return m_moduleInfo; + } + + inline virtual bool fitFor(const CSwordModuleInfo &) const { + return false; + } + +private: /* Fields: */ + + CSwordModuleInfo & m_moduleInfo; + BtBookshelfTreeModel & m_parentModel; + }; } // namespace BookshelfModel diff --git a/src/backend/btinstallbackend.cpp b/src/backend/btinstallbackend.cpp index c1136bf..7eb3ff4 100644 --- a/src/backend/btinstallbackend.cpp +++ b/src/backend/btinstallbackend.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -14,9 +14,9 @@ #include <QFile> #include <QFileInfo> #include "backend/managers/cswordbackend.h" -#include "frontend/bookshelfmanager/btinstallmgr.h" +#include "backend/btinstallmgr.h" #include "util/directory.h" -#include "util/dialogutil.h" +#include "frontend/messagedialog.h" // Sword includes: #include <filemgr.h> @@ -31,13 +31,22 @@ namespace BtInstallBackend { /** Adds the source described by Source to the backend. */ bool addSource(sword::InstallSource& source) { SWConfig config(configFilename().toLatin1()); - if (!strcmp(source.type, "FTP")) { - //make sure the path doesn't have a trailing slash, sword doesn't like it + if (isRemote(source)) { if (source.directory[ source.directory.length()-1 ] == '/') { - source.directory--; //make one char shorter + source.directory--; + } + if (!strcmp(source.type, "FTP")) { + config["Sources"].insert( std::make_pair(SWBuf("FTPSource"), source.getConfEnt()) ); + } + else if (!strcmp(source.type, "SFTP")) { + config["Sources"].insert( std::make_pair(SWBuf("SFTPSource"), source.getConfEnt()) ); + } + else if (!strcmp(source.type, "HTTP")) { + config["Sources"].insert( std::make_pair(SWBuf("HTTPSource"), source.getConfEnt()) ); + } + else if (!strcmp(source.type, "HTTPS")) { + config["Sources"].insert( std::make_pair(SWBuf("HTTPSSource"), source.getConfEnt()) ); } - - config["Sources"].insert( std::make_pair(SWBuf("FTPSource"), source.getConfEnt()) ); } else if (!strcmp(source.type, "DIR")) { config["Sources"].insert( std::make_pair(SWBuf("DIRSource"), source.getConfEnt()) ); @@ -68,7 +77,7 @@ sword::InstallSource source(const QString &name) { return is; } - sourceBegin++;//next source + ++sourceBegin; //next source } } } @@ -87,15 +96,10 @@ bool deleteSource(const QString &name) { SWConfig config(configFilename().toLatin1()); //this code can probably be shortened by using the stl remove_if functionality - std::pair< ConfigEntMap::iterator, ConfigEntMap::iterator > range = - isRemote(is) - ? config["Sources"].equal_range("FTPSource") - : config["Sources"].equal_range("DIRSource"); - - ConfigEntMap::iterator it = range.first; SWBuf sourceConfigEntry = is.getConfEnt(); bool notFound = true; - while (it != range.second) { + ConfigEntMap::iterator it = config["Sources"].begin(); + while (it != config["Sources"].end()) { //SWORD lib gave us a "nice" surprise: getConfEnt() adds uid, so old sources added by BT are not recognized here if (it->second == sourceConfigEntry) { config["Sources"].erase(it); @@ -111,8 +115,8 @@ bool deleteSource(const QString &name) { QStringList l = sce.split('|'); l.removeLast(); sce = l.join("|").append("|"); - it = range.first; - while (it != range.second) { + it = config["Sources"].begin(); + while (it != config["Sources"].end()) { if (it->second == sce) { config["Sources"].erase(it); break; @@ -132,7 +136,10 @@ QList<CSwordModuleInfo*> moduleList(QString /*name*/) { } bool isRemote(const sword::InstallSource& source) { - return !strcmp(source.type, "FTP"); + return !strcmp(source.type, "FTP") || + !strcmp(source.type, "SFTP") || + !strcmp(source.type, "HTTP") || + !strcmp(source.type, "HTTPS"); } QString configPath() { @@ -171,7 +178,7 @@ bool setTargetList( const QStringList& targets ) { if (!i.exists() || !i.isWritable()) { // There is no way to save to the file qWarning() << "The Sword config file is not writable!"; - util::showWarning(0, QObject::tr("Can't write file"), QObject::tr("The Sword config file can't be written!")); + message::showWarning(0, QObject::tr("Can't write file"), QObject::tr("The Sword config file can't be written!")); return false; } @@ -179,7 +186,7 @@ bool setTargetList( const QStringList& targets ) { SWConfig conf(filename.toLocal8Bit()); conf.Sections.clear(); -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN // On Windows, add the sword directory to the config file. QString swordPath = DU::convertDirSeparators( DU::getApplicationSwordDir().absolutePath()); conf["Install"].insert( @@ -190,7 +197,7 @@ bool setTargetList( const QStringList& targets ) { bool setDataPath = false; for (QStringList::const_iterator it = targets.begin(); it != targets.end(); ++it) { QString t = DU::convertDirSeparators(*it); -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN if (t.contains(DU::convertDirSeparators(DU::getUserHomeDir().canonicalPath().append("\\Sword")))) { #else if (t.contains(DU::getUserHomeDir().canonicalPath().append("/.sword"))) { @@ -217,7 +224,7 @@ QStringList sourceNameList() { QStringList names; //add Sword remote sources - for (InstallSourceMap::iterator it = mgr.sources.begin(); it != mgr.sources.end(); it++) { + for (InstallSourceMap::iterator it = mgr.sources.begin(); it != mgr.sources.end(); ++it) { names << QString::fromLocal8Bit(it->second->caption); } @@ -232,7 +239,7 @@ QStringList sourceNameList() { InstallSource is("DIR", sourceBegin->second.c_str()); names << QString::fromLatin1(is.caption.c_str()); - sourceBegin++; + ++sourceBegin; } } @@ -249,7 +256,7 @@ QString swordConfigFilename() { namespace DU = util::directory; qDebug() << "Sword config:" -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN << DU::getUserHomeDir().absolutePath().append("/Sword/sword.conf"); return DU::getUserHomeDir().absolutePath().append("/Sword/sword.conf"); // return DU::getApplicationDir().absolutePath().append("/sword.conf"); @@ -262,27 +269,20 @@ QString swordConfigFilename() { QDir swordDir() { namespace DU = util::directory; -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN return QDir(DU::getUserHomeDir().absolutePath().append("/Sword/")); #else return QDir(DU::getUserHomeDir().absolutePath().append("/.sword/")); #endif } -CSwordBackend* backend( const sword::InstallSource& is) { - CSwordBackend* ret = 0; +CSwordBackend * backend(const sword::InstallSource & is) { /// \anchor BackendNotSingleton - if (isRemote(is)) { - ret = new CSwordBackend( QString(is.localShadow.c_str()), false ); - } - else { - ret = new CSwordBackend( QString(is.directory.c_str()), false); - } - - Q_ASSERT(ret); - if (ret) { - ret->initModules(CSwordBackend::OtherChange); - } + CSwordBackend * const ret = new CSwordBackend(isRemote(is) + ? is.localShadow.c_str() + : is.directory.c_str(), + false); + ret->initModules(CSwordBackend::OtherChange); return ret; } diff --git a/src/backend/btinstallbackend.h b/src/backend/btinstallbackend.h index fc71697..1827f64 100644 --- a/src/backend/btinstallbackend.h +++ b/src/backend/btinstallbackend.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -64,7 +66,7 @@ QString swordConfigFilename(); QDir swordDir(); /** Returns backend Sword manager for the source. */ -CSwordBackend* backend( const sword::InstallSource& is); +CSwordBackend * backend(const sword::InstallSource & is); } // namespace BtInstallBackend diff --git a/src/backend/btinstallmgr.cpp b/src/backend/btinstallmgr.cpp new file mode 100644 index 0000000..2734dd3 --- /dev/null +++ b/src/backend/btinstallmgr.cpp @@ -0,0 +1,99 @@ +/********* +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License version 2.0. +* +**********/ + +#include "backend/btinstallmgr.h" + +#include "backend/btinstallbackend.h" + + +namespace { + +template <typename T> +inline T normalizeCompletionPercentage(const T value) { + if (value < 0) + return 0; + if (value > 100) + return 100; + return value; +} + +template <typename T> +inline int calculateIntPercentage(T done, T total) { + Q_ASSERT(done >= 0); + Q_ASSERT(total >= 0); + + // Special care (see warning in BtInstallMgr::statusUpdate()). + if (done > total) + done = total; + if (total == 0) + return 100; + + return normalizeCompletionPercentage<int>((done / total) * 100); +} + +} // anonymous namespace + +using namespace sword; + +BtInstallMgr::BtInstallMgr(QObject * parent) + : QObject(parent) + , InstallMgr(BtInstallBackend::configPath().toLatin1(), this) + , m_totalBytes(1) + , m_completedBytes(0) + , m_firstCallOfPreStatus(true) +{ // Use this class also as status reporter: + this->setFTPPassive(true); +} + +BtInstallMgr::~BtInstallMgr() { + //doesn't really help because it only sets a flag + this->terminate(); // make sure to close the connection +} + +bool BtInstallMgr::isUserDisclaimerConfirmed() const { + //// \todo Check from config if it's been confirmed with "don't show this anymore" checked. + // Create a dialog with the message, checkbox and Continue/Cancel, Cancel as default. + return true; +} + +void BtInstallMgr::statusUpdate(double dltotal, double dlnow) { + /** + \warning Note that these *might be* rough measures due to the double data + type being used by Sword to store the number of bytes. Special + care must be taken to work around this, since the arguments may + contain weird values which would otherwise break this logic. + */ + + if (dltotal < 0.0) // Special care (see warning above) + dltotal = 0.0; + if (dlnow < 0.0) // Special care (see warning above) + dlnow = 0.0; + + const int totalPercent = calculateIntPercentage<double>(dlnow + m_completedBytes, + m_totalBytes); + const int filePercent = calculateIntPercentage(dlnow, dltotal); + + //qApp->processEvents(); + emit percentCompleted(totalPercent, filePercent); +} + + +void BtInstallMgr::preStatus(long totalBytes, + long completedBytes, + const char * message) +{ + Q_UNUSED(message); + Q_ASSERT(completedBytes <= totalBytes); + if (m_firstCallOfPreStatus) { + m_firstCallOfPreStatus = false; + emit downloadStarted(); + } + m_completedBytes = completedBytes; + m_totalBytes = totalBytes; +} diff --git a/src/backend/btinstallmgr.h b/src/backend/btinstallmgr.h new file mode 100644 index 0000000..e82b470 --- /dev/null +++ b/src/backend/btinstallmgr.h @@ -0,0 +1,73 @@ +/********* +* +* 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-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License version 2.0. +* +**********/ + +#ifndef BTINSTALLMGR_H +#define BTINSTALLMGR_H + +#include <QObject> +// Sword includes: +#include <installmgr.h> +#include <remotetrans.h> + + +/** +* Our own reimplementation to provide installation and status bar updates. +*/ +class BtInstallMgr + : public QObject + , public sword::InstallMgr + , public sword::StatusReporter +{ + + Q_OBJECT + +public: /* Methods: */ + + BtInstallMgr(QObject * parent = 0); + ~BtInstallMgr(); + + virtual bool isUserDisclaimerConfirmed() const; + +signals: + + /** + Download status. Percent of total and file. + \warning Use these values for display only, since they might be incorrect. + */ + void percentCompleted(const int total, const int file); + + void downloadStarted(); + +protected: /* Methods: */ + + /** \note Reimplementation of sword::StatusReporter::statusUpdate(). */ + virtual void statusUpdate(double dltotal, double dlnow); + + /** + * \note Reimplementation of sword::StatusReporter::preStatus(). + * \warning This method is not always called before statusUpdate(). + * Called before starting to download each file of the module package. + * The sword message is not i18n'ed, it's in the form "Downloading (1 of 6): nt.bzs". + * This function is not utilized in the UI ATM. + */ + virtual void preStatus(long totalBytes, + long completedBytes, + const char * message); + +private: /* Fields: */ + + long m_totalBytes; + long m_completedBytes; + bool m_firstCallOfPreStatus; + +}; + +#endif /* BTINSTALLMGR_H */ diff --git a/src/backend/btinstallthread.cpp b/src/backend/btinstallthread.cpp new file mode 100644 index 0000000..69e5fb8 --- /dev/null +++ b/src/backend/btinstallthread.cpp @@ -0,0 +1,143 @@ +/********* +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License version 2.0. +* +**********/ + +#include "backend/btinstallthread.h" + +#include <QDebug> +#include <QDir> +#include <QString> +#include <QThread> +#include "backend/managers/cswordbackend.h" + +#include "backend/btinstallbackend.h" + +// Sword includes: +#include <filemgr.h> + + +namespace { + +inline bool runMkdir(QDir & dir, const QString & dirName) { + if (!dir.exists(dirName)) { + if (!dir.mkpath(dirName)) { + qDebug() << "failed to make directory" << dirName; + return false; + } + qDebug() << "made directory" << dirName; + } + return true; +} + +} + +void BtInstallThread::run() { + // Make sure target/mods.d and target/modules exist + /// \todo move this to some common precondition + QDir dir(m_destination); + if (!runMkdir(dir, m_destination) + || !runMkdir(dir, "modules") + || !runMkdir(dir, "mods.d")) + { + return; + } + + m_stopRequestedMutex.lock(); + try { + for (m_currentModuleIndex = 0; + !m_stopRequested && (m_currentModuleIndex < m_modules.size()); + m_currentModuleIndex++) + { + m_stopRequestedMutex.unlock(); + installModule(); + m_stopRequestedMutex.lock(); + } + } catch (...) { + m_stopRequestedMutex.unlock(); + throw; + } + m_stopRequestedMutex.unlock(); +} + +void BtInstallThread::installModule() { + emit preparingInstall(m_currentModuleIndex); + + const CSwordModuleInfo * const module = m_modules.at(m_currentModuleIndex); + + sword::InstallSource installSource = BtInstallBackend::source(module->property("installSourceName").toString()); + QScopedPointer<CSwordBackend> backendForSource(BtInstallBackend::backend(installSource)); + + // Check whether it's an update. If yes, remove existing module first: + /// \todo silently removing without undo if the user cancels the update is WRONG!!! + if (!removeModule()) { + QMutexLocker lock(&m_stopRequestedMutex); + if (m_stopRequested) + return; + } + + // manager for the destination path + sword::SWMgr lMgr(m_destination.toLatin1()); + if (BtInstallBackend::isRemote(installSource)) { + int status = m_iMgr.installModule(&lMgr, + 0, + module->name().toLatin1(), + &installSource); + if (status == 0) { + emit statusUpdated(m_currentModuleIndex, 100); + } else { + qWarning() << "Error with install: " << status + << "module:" << module->name(); + } + emit installCompleted(m_currentModuleIndex, status == 0); + } else { // Local source + int status = m_iMgr.installModule(&lMgr, + installSource.directory.c_str(), + module->name().toLatin1()); + if (status == 0) { + emit statusUpdated(m_currentModuleIndex, 100); + } else if (status != -1) { + qWarning() << "Error with install: " << status + << "module:" << module->name(); + } + emit installCompleted(m_currentModuleIndex, status == 0); + } +} + +void BtInstallThread::slotManagerStatusUpdated(int totalProgress, int /*fileProgress*/) { + emit statusUpdated(m_currentModuleIndex, totalProgress); +} + +void BtInstallThread::slotDownloadStarted() { + emit downloadStarted(m_currentModuleIndex); +} + +bool BtInstallThread::removeModule() { + CSwordModuleInfo * const installedModule = m_modules.at(m_currentModuleIndex); + CSwordModuleInfo * m = CSwordBackend::instance()->findModuleByName(installedModule->name()); + if (!m) + m = BtInstallBackend::backend(BtInstallBackend::source(m_destination.toLatin1()))->findModuleByName(installedModule->name()); + + if (!m) + return false; + + qDebug() << "Removing module" << installedModule->name(); + QString prefixPath = m->config(CSwordModuleInfo::AbsoluteDataPath) + "/"; + QString dataPath = m->config(CSwordModuleInfo::DataPath); + if (dataPath.left(2) == "./") + dataPath = dataPath.mid(2); + + if (prefixPath.contains(dataPath)) { + prefixPath.remove(prefixPath.indexOf(dataPath), dataPath.length()); + } else { + prefixPath = QString::fromLatin1(CSwordBackend::instance()->prefixPath); + } + + sword::SWMgr mgr(prefixPath.toLatin1()); + BtInstallMgr().removeModule(&mgr, m->name().toLatin1()); + return true; +} diff --git a/src/backend/btinstallthread.h b/src/backend/btinstallthread.h new file mode 100644 index 0000000..d4cbdc3 --- /dev/null +++ b/src/backend/btinstallthread.h @@ -0,0 +1,94 @@ +/********* +* +* 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-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License version 2.0. +* +**********/ + +#ifndef BTINSTALLTHREAD_H +#define BTINSTALLTHREAD_H + +#include <QThread> + +#include <QMutex> +#include <QMutexLocker> +#include <QSharedPointer> +#include "backend/btinstallmgr.h" + + +class BtInstallProgressDialog; +class CSwordBackend; +class CSwordModuleInfo; + + +class BtInstallThread: public QThread { + + Q_OBJECT + + public: + + BtInstallThread(const QList<CSwordModuleInfo *> & modules, + const QString & destination, + QObject * const parent = 0) + : QThread(parent) + , m_modules(modules) + , m_destination(destination) + , m_stopRequested(false) + { + connect(&m_iMgr, SIGNAL(percentCompleted(int, int)), + this, SLOT(slotManagerStatusUpdated(int, int)), + Qt::QueuedConnection); + connect(&m_iMgr, SIGNAL(downloadStarted()), + this, SLOT(slotDownloadStarted()), + Qt::QueuedConnection); + } + + void stopInstall() { + const QMutexLocker lock(&m_stopRequestedMutex); + m_stopRequested = true; + } + + signals: + + /** Emitted when starting the installation. */ + void preparingInstall(int moduleIndex); + + /** Emitted when the first file download has been started. */ + void downloadStarted(int moduleIndex); + + /** Emitted when the install progress status is updated. */ + void statusUpdated(int moduleIndex, int progressPercent); + + /** Emitted when installing is complete. */ + void installCompleted(int moduleIndex, bool success); + + protected: /* Methods: */ + + virtual void run(); + + private: /* Methods: */ + + void installModule(); + bool removeModule(); + + private slots: + + void slotDownloadStarted(); + void slotManagerStatusUpdated(int totalProgress, int fileProgress); + + private: /* Fields: */ + + const QList<CSwordModuleInfo *> & m_modules; + const QString m_destination; + BtInstallMgr m_iMgr; + int m_currentModuleIndex; + QMutex m_stopRequestedMutex; + bool m_stopRequested; + +}; + +#endif diff --git a/src/backend/btmoduletreeitem.cpp b/src/backend/btmoduletreeitem.cpp index 4c16231..7900ef0 100644 --- a/src/backend/btmoduletreeitem.cpp +++ b/src/backend/btmoduletreeitem.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ diff --git a/src/backend/btmoduletreeitem.h b/src/backend/btmoduletreeitem.h index 008bfb2..189f9b2 100644 --- a/src/backend/btmoduletreeitem.h +++ b/src/backend/btmoduletreeitem.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -115,8 +117,8 @@ class BTModuleTreeItem { /** When the root item is deleted the whole tree is deleted. */ ~BTModuleTreeItem(); - /** Adds filtered items to the tree */ - void add_items(QList<BTModuleTreeItem::Filter*>& filters); + /** Adds filtered items to the tree */ + void add_items(QList<BTModuleTreeItem::Filter*>& filters); /** * Returns the item type. @@ -168,10 +170,10 @@ class BTModuleTreeItem { /** 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); - static bool m_map_initialized; - static QMap<CSwordModuleInfo::Category, QString> m_CategoryNamesMap; - - + static bool m_map_initialized; + static QMap<CSwordModuleInfo::Category, QString> m_CategoryNamesMap; + + CSwordModuleInfo* m_moduleInfo; QString m_text; BTModuleTreeItem* m_firstChild; diff --git a/src/backend/config/btconfig.cpp b/src/backend/config/btconfig.cpp new file mode 100644 index 0000000..e76b246 --- /dev/null +++ b/src/backend/config/btconfig.cpp @@ -0,0 +1,363 @@ +/********* +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License version 2.0. +* +**********/ + +#include "btconfig.h" + +#include <QDebug> +#include <QLocale> +#include "backend/btmoduletreeitem.h" +#include "backend/managers/cdisplaytemplatemgr.h" +#include "frontend/messagedialog.h" +#include "util/directory.h" // DU::getUserBaseDir() + +// Sword includes: +#include <backend/managers/cswordbackend.h> +#include <versekey.h> // For search scope configuration + + +#define BTCONFIG_API_VERSION 1 +namespace { +const QString BTCONFIG_API_VERSION_KEY = "btconfig_api_version"; +} + + +/* + * set the instance variable initially to 0, so it can be safely checked + * whether the variable has been initialized yet. + */ +BtConfig * BtConfig::m_instance = NULL; + +BtConfig::StringMap BtConfig::m_defaultSearchScopes; + + +BtConfig::BtConfig(const QString & settingsFile) + : BtConfigCore(settingsFile) +{ + Q_ASSERT_X(!m_instance, "BtConfig", "Already initialized!"); + m_instance = this; + + if (m_defaultSearchScopes.isEmpty()) { + m_defaultSearchScopes.insert(tr("Old testament"), QString("Gen - Mal")); + m_defaultSearchScopes.insert(tr("Moses/Pentateuch/Torah"), QString("Gen - Deut")); + m_defaultSearchScopes.insert(tr("History"), QString("Jos - Est")); + m_defaultSearchScopes.insert(tr("Prophets"), QString("Isa - Mal")); + m_defaultSearchScopes.insert(tr("New testament"), QString("Mat - Rev")); + m_defaultSearchScopes.insert(tr("Gospels"), QString("Mat - Joh")); + m_defaultSearchScopes.insert(tr("Letters/Epistles"), QString("Rom - Jude")); + m_defaultSearchScopes.insert(tr("Paul's Epistles"), QString("Rom - Phile")); + } +} + +bool BtConfig::initBtConfig() { + Q_ASSERT(!m_instance); + + const QString confFileName = util::directory::getUserBaseDir().absolutePath() + + "/bibletimerc"; + bool confExisted = QFile::exists(confFileName); + m_instance = new BtConfig(confFileName); + if (!confExisted) { + m_instance->setValue<int>(BTCONFIG_API_VERSION_KEY, BTCONFIG_API_VERSION); + return true; + } + + int btConfigOldApi = m_instance->value<int>(BTCONFIG_API_VERSION_KEY, 0); + if (btConfigOldApi == BTCONFIG_API_VERSION) + return true; + + bool cont; + if (btConfigOldApi < BTCONFIG_API_VERSION) { + /// \todo Migrate from btConfigOldApi to BTCONFIG_API_VERSION + qWarning() << "BibleTime configuration migration is not yet implemented!!!"; + cont = message::showWarning( + 0, "Warning!", + "Migration to the new configuration system is not yet " + "implemented. Proceeding might result in <b>loss of data" + "</b>. Please backup your configuration files before you " + "continue!<br/><br/>Do you want to continue? Press \"No\" " + "to quit BibleTime immediately.", + QMessageBox::Yes | QMessageBox::No, + QMessageBox::No) == QMessageBox::Yes; + } else { + Q_ASSERT(btConfigOldApi > BTCONFIG_API_VERSION); + cont = message::showWarning( + 0, tr("Error loading configuration!"), + tr("Failed to load BibleTime's configuration, because it " + "appears that the configuration file corresponds to a " + "newer version of BibleTime. This is likely caused by " + "BibleTime being downgraded. Loading the new " + "configuration file may result in <b>loss of data</b>." + "<br/><br/>Do you still want to try to load the new " + "configuration file? Press \"No\" to quit BibleTime " + "immediately."), + QMessageBox::Yes | QMessageBox::No, + QMessageBox::No) == QMessageBox::Yes; + } + if (cont) + m_instance->setValue<int>(BTCONFIG_API_VERSION_KEY, BTCONFIG_API_VERSION); + return cont; +} + +BtConfig& BtConfig::getInstance() { + Q_ASSERT_X(m_instance, "BtConfig", "Not yet initialized!"); + return *m_instance; +} + +void BtConfig::destroyInstance() { + delete m_instance; + m_instance = NULL; +} + +void BtConfig::setModuleEncryptionKey(const QString & name, + const QString & key) +{ + Q_ASSERT(!name.isEmpty()); + setValue("Module keys/" + name, key); +} + +QString BtConfig::getModuleEncryptionKey(const QString & name) { + Q_ASSERT(!name.isEmpty()); + return value<QString>("Module keys/" + name, QString::null); +} + +QHash<QString, QList<QKeySequence> > BtConfig::getShortcuts(const QString & shortcutGroup) { + beginGroup(shortcutGroup); + QHash<QString, QList<QKeySequence> > allShortcuts; + Q_FOREACH (const QString & key, childKeys()) { + QVariant variant = qVariantValue(key); + + QList<QKeySequence> shortcuts; + + if (variant.type() == QVariant::List) { // For BibleTime before 2.9 + Q_FOREACH (const QVariant & shortcut, variant.toList()) + shortcuts.append(shortcut.toString()); + } else if (variant.type() == QVariant::StringList + || variant.type() == QVariant::String) + { // a StringList with one element is recognized as a QVariant::String + Q_FOREACH (const QString & shortcut, variant.toStringList()) + shortcuts.append(shortcut); + } else { // it's something we don't know, skip it + continue; + } + + allShortcuts.insert(key, shortcuts); + } + endGroup(); + return allShortcuts; +} + +void BtConfig::setShortcuts(const QString & shortcutGroup, + const QHash<QString, QList<QKeySequence> > & shortcuts) +{ + typedef QHash<QString, QList<QKeySequence> >::const_iterator SHMCI; + + beginGroup(shortcutGroup); + for (SHMCI it = shortcuts.begin(); it != shortcuts.end(); ++it) { + // Write beautiful string lists (since 2.9): + /// \note saving QKeySequences directly doesn't appear to work! + QStringList varList; + Q_FOREACH (const QKeySequence & shortcut, it.value()) + varList.append(shortcut.toString()); + + if (!varList.empty()) + setValue(it.key(), varList); + } + endGroup(); +} + +FilterOptions BtConfig::getFilterOptions() { + FilterOptions os; + beginGroup("presentation"); + os.footnotes = sessionValue<bool>("footnotes", true); + os.strongNumbers = sessionValue<bool>("strongNumbers", true); + os.headings = sessionValue<bool>("headings", true); + os.morphTags = sessionValue<bool>("morphTags", true); + os.lemmas = sessionValue<bool>("lemmas", true); + os.redLetterWords = sessionValue<bool>("redLetterWords", true); + os.hebrewPoints = sessionValue<bool>("hebrewPoints", true); + os.hebrewCantillation = sessionValue<bool>("hebrewCantillation", true); + os.greekAccents = sessionValue<bool>("greekAccents", true); + os.textualVariants = sessionValue<bool>("textualVariants", false); + os.scriptureReferences = sessionValue<bool>("scriptureReferences", true); + os.morphSegmentation = sessionValue<bool>("morphSegmentation", true); + endGroup(); + return os; +} + +void BtConfig::setFilterOptions(const FilterOptions & os) { + beginGroup("presentation"); + setSessionValue("footnotes", static_cast<bool>(os.footnotes)); + setSessionValue("strongNumbers", static_cast<bool>(os.strongNumbers)); + setSessionValue("headings", static_cast<bool>(os.headings)); + setSessionValue("morphTags", static_cast<bool>(os.morphTags)); + setSessionValue("lemmas", static_cast<bool>(os.lemmas)); + setSessionValue("redLetterWords", static_cast<bool>(os.redLetterWords)); + setSessionValue("hebrewPoints", static_cast<bool>(os.hebrewPoints)); + setSessionValue("hebrewCantillation", static_cast<bool>(os.hebrewCantillation)); + setSessionValue("greekAccents", static_cast<bool>(os.greekAccents)); + setSessionValue("textualVariants", static_cast<bool>(os.textualVariants)); + setSessionValue("scriptureReferences", static_cast<bool>(os.scriptureReferences)); + setSessionValue("morphSegmentation", static_cast<bool>(os.morphSegmentation)); + endGroup(); +} + +DisplayOptions BtConfig::getDisplayOptions() { + DisplayOptions os; + beginGroup("presentation"); + os.lineBreaks = sessionValue<bool>("lineBreaks", false); + os.verseNumbers = sessionValue<bool>("verseNumbers", false); + endGroup(); + return os; +} + +void BtConfig::setDisplayOptions(const DisplayOptions & os) { + beginGroup("presentation"); + setSessionValue("lineBreaks", static_cast<bool>(os.lineBreaks)); + setSessionValue("verseNumbers", static_cast<bool>(os.verseNumbers)); + endGroup(); +} + +void BtConfig::setFontForLanguage(const CLanguageMgr::Language & language, + const FontSettingsPair & fontSettings) +{ + const QString & englishName = language.englishName(); + Q_ASSERT(!englishName.isEmpty()); + + QMutexLocker lock(&this->m_mutex); + // write the language to the settings + setValue("fonts/" + englishName, fontSettings.second.toString()); + setValue("font standard settings/" + englishName, fontSettings.first); + + // Remove language from the cache: + m_fontCache.remove(&language); +} + +BtConfig::FontSettingsPair BtConfig::getFontForLanguage( + const CLanguageMgr::Language & language) +{ + const QString & englishName = language.englishName(); + Q_ASSERT(!englishName.isEmpty()); + + QMutexLocker lock(&this->m_mutex); + // Check the cache first: + FontCacheMap::const_iterator it(m_fontCache.find(&language)); + if (it != m_fontCache.end()) + return *it; + + // Retrieve the font from the settings + FontSettingsPair fontSettings; + + fontSettings.first = value<bool>("font standard settings/" + englishName, false); + + QFont font; + if (fontSettings.first) { + if (!font.fromString(value<QString>("fonts/" + englishName, getDefaultFont().toString()))) { + /// \todo + } + } else { + font = getDefaultFont(); + } + fontSettings.second = font; + + // Cache the value: + m_fontCache.insert(&language, fontSettings); + + return fontSettings; +} + +BtConfig::StringMap BtConfig::getSearchScopesForCurrentLocale() { + StringMap map = value<BtConfig::StringMap>("properties/searchScopes", m_defaultSearchScopes); + + // Convert map to current locale: + sword::VerseKey vk; + for (StringMap::Iterator it = map.begin(); it != map.end(); it++) { + QString &s = it.value(); + sword::ListKey list(vk.parseVerseList(QByteArray(s.toUtf8()), "Genesis 1:1", true)); + s.clear(); + for (int i = 0; i < list.getCount(); i++) { + s.append(QString::fromUtf8(list.getElement(i)->getRangeText())); + s.append("; "); + } + } + return map; +} + +void BtConfig::setSearchScopesWithCurrentLocale(StringMap 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. + */ + sword::VerseKey vk; + BtConfig::StringMap::Iterator iter = searchScopes.begin(); + while (iter != searchScopes.end()) { + QString &data = iter.value(); + bool parsingWorked = true; + sword::ListKey list(vk.parseVerseList(data.toUtf8(), "Genesis 1:1", true)); + data.clear(); + for (int i = 0; i < list.getCount(); i++) { + sword::VerseKey * verse(dynamic_cast<sword::VerseKey *>(list.getElement(i))); + + if (verse != 0) { + verse->setLocale("en"); + data.append(QString::fromUtf8(verse->getRangeText())); + data.append(";"); + } else { + parsingWorked = false; + break; + } + } + + if (parsingWorked) + iter++; + else + iter = searchScopes.erase(iter); + } + setValue("properties/searchScopes", searchScopes); +} + +void BtConfig::deleteSearchScopesWithCurrentLocale() { + remove("properties/searchScopes"); +} + +CSwordModuleInfo *BtConfig::getDefaultSwordModuleByType(const QString & moduleType) { + const QString moduleName = value<QString>("settings/defaults/" + moduleType, QString()); + if (moduleName.isEmpty()) + return 0; + + return CSwordBackend::instance()->findModuleByName(moduleName); +} + +void BtConfig::setDefaultSwordModuleByType(const QString &moduleType, + const CSwordModuleInfo * const module) +{ + setValue("settings/defaults/" + moduleType, + module != 0 ? module->name() : QString::null); +} + +/** + \todo -CDisplayWindow gets a construct method that reads from config and constructs and + returns the respective child window (check whether module is installed...) + -CDisplayWindows get a new variable "id" or something, which is a unique identifier. + The path in the configuration will use this id as name. (who gives out the IDs?) + -values are updated as they are changed, just like the rest of bibletime + -QMdiArea::subWindowActivated signal will trigger reading the window order and saving + it to the config. + Action Plan: + 1. get current code to work with old session system + 2. move complete code over to BtConfig + 3. remove CBTConfig + 4. implement BtConfig infrastructure for saving window configuration + - function to add a window + - function to remove a window + - specify how to save ordering + 5. change CDisplayWindows to write all state changes to the configuration + 6. implement BtConfig::readSession and callers + 7. make session handling code work with QSetting paths instead of properties + 8. add gui for new session handling + 9. remove old gui for session handling +*/ diff --git a/src/backend/config/btconfig.h b/src/backend/config/btconfig.h new file mode 100644 index 0000000..be19d41 --- /dev/null +++ b/src/backend/config/btconfig.h @@ -0,0 +1,248 @@ +/********* +* +* 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-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License version 2.0. +* +**********/ + +#ifndef BTCONFIG_H +#define BTCONFIG_H + +#include <QDataStream> +#include <QFont> +#include <QHash> +#include <QKeySequence> +#include <QMetaType> +#include <QSet> +#include <QSettings> +#include <QString> +#include <QStringList> +#include <QVariant> + +#include "backend/config/btconfigcore.h" + +#include "backend/btmoduletreeitem.h" // for BTModuleTreeItem::Grouping +#include "backend/drivers/cswordmoduleinfo.h" +#include "btglobal.h" + + +class BibleTimeApp; + +class BtConfig: public BtConfigCore { + + Q_DISABLE_COPY(BtConfig) + + friend class BibleTimeApp; + +public: /* Types: */ + + /*! + * The first parameter indicates whether the custom font should be used or not. + * The second parameter is the custom font that has been set. + */ + typedef QPair<bool, QFont> FontSettingsPair; + typedef QMap<QString, QString> StringMap; + +private: /* Types: */ + + typedef QHash<const CLanguageMgr::Language *, FontSettingsPair> FontCacheMap; + +public: /* Methods: */ + + static BtConfig & getInstance(); + + /*! + * \brief Function to set a module decryption key. + * + * This helper function will set a module decryption key + * in the configuration. Any previous key will be overwritten. + * + * \param[in] name Name of module to set the key for + * \param[in] key Decryption key to set as string + */ + void setModuleEncryptionKey(const QString & name, const QString & key); + + /*! + * \brief Function to get a module decryption key. + * + * This helper function will retrieve a previously set + * module decryption key from the configuration. If the key + * is not set it will return a null string. + * + * \param[in] name Name of module to retrieve the key for + * \returns Decryption key as a string + */ + QString getModuleEncryptionKey(const QString & name); + + /*! + * \brief Gets the shortcuts for the given group. + * + * Returns a hash of shortcuts for strings for the respective + * shortcut group. + * \param[in] shortcutGroup The group to retrieve shortcuts for. + * \returns Hash of strings and lists of shortcuts. + */ + QHash<QString, QList<QKeySequence> > getShortcuts(const QString & shortcutGroup); + + /*! + * \brief Sets the shortcuts for the given group. + * + * Writes a hash of shortcuts for strings for the respective + * shortcut group. + * \param[in] shortcutGroup The group to retrieve shortcuts for. + * \param[in] Hash of strings and lists of shortcuts to write. + */ + void setShortcuts(const QString & shortcutGroup, + const QHash<QString, QList<QKeySequence> > & shortcuts); + + /*! + * \brief Returns current filter options. + * + * Returns a structure containing the current + * settings to be used for filtering. + * + * \returns FilterOptions structure containing filter settings. + */ + FilterOptions getFilterOptions(); + + /*! + * \brief Saves the current filter options. + * + * \param[in] options The filter options to save. + */ + void setFilterOptions(const FilterOptions & options); + + /*! + * \brief Returns current display options. + * + * Returns a structure containing the current + * settings to be used for displaying texts. + * + * \returns DisplayOptions structure containing display settings. + */ + DisplayOptions getDisplayOptions(); + + /*! + * \brief Saves the current display options. + * + * \param[in] options The display options to save. + */ + void setDisplayOptions(const DisplayOptions & options); + + /*! + * Returns a default font that is suitable for the current language. + * \returns QFont suitable for current language. + */ + inline const QFont & getDefaultFont() const { + QMutexLocker lock(&this->m_mutex); + return m_defaultFont; + } + + /// \todo: put FontSettingsPair in QVariant directly + /*! + * \brief Set font for a language. + * + * Sets a FontSettingsPair for the language given. + * \param[in] language pointer to a language to set the font for + * \param[in] fontSettings FontSettingsPair to set + */ + void setFontForLanguage(const CLanguageMgr::Language & language, + const FontSettingsPair & fontSettings); + + /*! + * \brief Get font for a language. + * + * Gets a FontSettingsPair for the language given. If no font has been saved + * a default font is returned. + * \param[in] language pointer to a language to get the font for. + * \returns FontSettingsPair for given language + */ + FontSettingsPair getFontForLanguage(const CLanguageMgr::Language & language); + + /// \todo: unit test these functions + /*! + * Returns the searchScopes for the current locale. + * + * This function retrieves the search scopes of the + * "properties/searchScopes" property and converts them + * to the current locale. + * + * \returns Search scopes in current locale. + */ + StringMap getSearchScopesForCurrentLocale(); + + /*! + * Sets the searchScopes given in the current locale. + * + * This function sets the search scopes of the + * "properties/searchScopes" property, the scopes are + * converted to the english locale before saving them. + * + * \param[in] searchScopes Search scopes in any locale. + */ + void setSearchScopesWithCurrentLocale(StringMap searchScopes); + + /*! + * Deletes the searchScopes given in the current locale. + */ + void deleteSearchScopesWithCurrentLocale(); + + /*! + * \brief Returns default sword module info class for a given module type. + * + * This is basically a convenience function for getting the respective + * "settings/defaults/ *" variable and searching that module manually. + * If module is not installed 0 will be returned. + * \param[in] moduleType module type to return the default sword module info for + * \returns sword module info pointer or 0 + */ + CSwordModuleInfo * getDefaultSwordModuleByType(const QString & moduleType); + + /*! + * \brief Sets the default sword module for a module type. + * + * This is basically a convenience function for setting the "settings/defaults/ *" + * variables to the module->name() string manually. + * 0 is allowed as the module, then the default module will be unset. + * \param[in] moduleType module type to set + * \param[in] module the sword module info to set as default module + */ + void setDefaultSwordModuleByType(const QString & moduleType, + const CSwordModuleInfo * const module); + +private: /* Methods: */ + + explicit BtConfig(const QString & settingsFile); + + static bool initBtConfig(); + + static void destroyInstance(); + +private: /* Fields: */ + + static BtConfig * m_instance; //!< singleton instance + + QFont m_defaultFont; //!< default font used when no special one is set + FontCacheMap m_fontCache; //!< a cache for the fonts saved in the configuration file for speed + + static StringMap m_defaultSearchScopes; + +}; + +// declare types used in configuration as metatype so they can be saved directly into the configuration +Q_DECLARE_METATYPE(BtConfig::StringMap) +Q_DECLARE_METATYPE(QList<int>) + +/*! + * \brief This is a shortchand for BtConfig::getInstance(). + * \returns BtConfig singleton instance. + */ +inline BtConfig & btConfig() { + return BtConfig::getInstance(); +} + +#endif // BTCONFIG_H diff --git a/src/backend/config/btconfigcore.cpp b/src/backend/config/btconfigcore.cpp new file mode 100644 index 0000000..0914508 --- /dev/null +++ b/src/backend/config/btconfigcore.cpp @@ -0,0 +1,202 @@ +/********* +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License version 2.0. +* +**********/ + +#include "btconfigcore.h" + +#include <cstddef> +#include <limits> + + +const QString BtConfigCore::GROUP_SESSIONS = "sessions/"; +const QString BtConfigCore::KEY_CURRENT_SESSION = "sessions/currentSession"; +const QString BtConfigCore::GROUP_SESSION = "sessions/%1/"; +const QString BtConfigCore::KEY_SESSION_NAME = "sessions/%1/name"; +const QString BtConfigCore::UI_FONT_SIZE = "ui/fontSize"; + + +BtConfigCore::BtConfigCore(const QString & settingsFile) + : m_mutex(QMutex::Recursive) + , m_settings(settingsFile, QSettings::IniFormat) +{ + /** + \todo Read UI language from settings, and initialize translator for tr() + strings. + */ + + // Read all session keys and names: + m_settings.beginGroup(GROUP_SESSIONS); + const QStringList sessionKeys = m_settings.childGroups(); + m_settings.endGroup(); + Q_FOREACH (const QString & sessionKey, sessionKeys) { + // Skip empty//keys just in case: + if (sessionKey.isEmpty()) + continue; + + const QString fullKey = KEY_SESSION_NAME.arg(sessionKey); + const QString sessionName = m_settings.value(fullKey).toString(); + if (!sessionName.isEmpty()) + m_sessionNames.insert(sessionKey, sessionName); + } + + // Get current session key: + m_currentSessionKey = m_settings.value(KEY_CURRENT_SESSION).toString(); + + /* + If no session with the current session key exists, default to the first + session found. If no sessions were found, create a default session. + */ + if (m_currentSessionKey.isEmpty() + || !m_sessionNames.contains(m_currentSessionKey)) + { + if (m_sessionNames.isEmpty()) { + const QString &newSessionName = QString::number((qulonglong) 0u, 36); + m_currentSessionKey = newSessionName; + m_settings.setValue(KEY_CURRENT_SESSION, newSessionName); + m_settings.setValue(KEY_SESSION_NAME.arg(newSessionName), + tr("Default Session")); + } else { + m_currentSessionKey = m_sessionNames.keys().first(); + } + } + m_cachedCurrentSessionGroup = GROUP_SESSION.arg(m_currentSessionKey); +} + +void BtConfigCore::setCurrentSession(const QString & key) { + Q_ASSERT(!key.isEmpty()); + + QMutexLocker lock(&m_mutex); + Q_ASSERT(m_sessionNames.contains(key)); + m_currentSessionKey = key; + m_cachedCurrentSessionGroup = GROUP_SESSION.arg(key); + + m_settings.setValue(KEY_CURRENT_SESSION, key); + m_settings.sync(); +} + +QString BtConfigCore::addSession(const QString & name) { + Q_ASSERT(!name.isEmpty()); + + // Generate a new session key: + QString key = QString::number(0u, 36); + QMutexLocker lock(&m_mutex); + if (m_sessionNames.contains(key)) { + QString keyPrefix; + std::size_t i = 1u; + for (;;) { + key = QString::number(i, 36); + if (!m_sessionNames.contains(keyPrefix + key)) + break; + if (i == std::numeric_limits<std::size_t>::max()) { + i = 0u; + keyPrefix.append('_'); + } else { + i++; + } + }; + } + Q_ASSERT(!m_sessionNames.contains(key)); + m_sessionNames.insert(key, name); + + m_settings.setValue(KEY_SESSION_NAME.arg(key), name); + m_settings.sync(); + return key; +} + + +void BtConfigCore::deleteSession(const QString & key) { + QMutexLocker lock(&m_mutex); + Q_ASSERT(m_sessionNames.contains(key)); + Q_ASSERT(key != m_currentSessionKey); + m_sessionNames.remove(key); + + m_settings.remove(GROUP_SESSIONS + key); + m_settings.sync(); +} + +QStringList BtConfigCore::childKeys() { + QMutexLocker lock(&m_mutex); + return childGroups__(); +} + +QStringList BtConfigCore::childKeys__() { + if (m_groups.isEmpty()) + return m_settings.childKeys(); + + m_settings.beginGroup(group()); + const QStringList gs = m_settings.childKeys(); + m_settings.endGroup(); + return gs; +} + +QStringList BtConfigCore::childKeys(const QString & subkey) { + beginGroup(subkey); + QStringList gs = childKeys__(); + endGroup(); + return gs; +} + +QStringList BtConfigCore::childGroups() { + QMutexLocker lock(&m_mutex); + return childGroups__(); +} + +QStringList BtConfigCore::childGroups__() { + if (m_groups.isEmpty()) + return m_settings.childGroups(); + + m_settings.beginGroup(group()); + const QStringList gs = m_settings.childGroups(); + m_settings.endGroup(); + return gs; +} + +QStringList BtConfigCore::childGroups(const QString & subkey) { + beginGroup(subkey); + QStringList gs = childGroups__(); + endGroup(); + return gs; +} + +QStringList BtConfigCore::sessionChildGroups() { + QMutexLocker lock(&m_mutex); + return sessionChildGroups__(); +} + +QStringList BtConfigCore::sessionChildGroups__() { + QMutexLocker lock(&m_mutex); + m_settings.beginGroup(m_cachedCurrentSessionGroup + group()); + const QStringList gs = m_settings.childGroups(); + m_settings.endGroup(); + return gs; +} + +QStringList BtConfigCore::sessionChildGroups(const QString & subkey) { + beginGroup(subkey); + QStringList gs = sessionChildGroups__(); + endGroup(); + return gs; +} + +void BtConfigCore::remove(const QString & key) { + QMutexLocker lock(&m_mutex); + if (m_groups.isEmpty()) { + m_settings.remove(key); + } else { + m_settings.remove(m_groups.join("/") + '/' + key); + } +} + +void BtConfigCore::sessionRemove(const QString & key) { + QMutexLocker lock(&m_mutex); + if (m_groups.isEmpty()) { + m_settings.remove(m_cachedCurrentSessionGroup + key); + } else { + m_settings.remove(m_cachedCurrentSessionGroup + m_groups.join("/") + '/' + key); + } +} diff --git a/src/backend/config/btconfigcore.h b/src/backend/config/btconfigcore.h new file mode 100644 index 0000000..5c24b4f --- /dev/null +++ b/src/backend/config/btconfigcore.h @@ -0,0 +1,342 @@ +/********* +* +* 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-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License version 2.0. +* +**********/ + +#ifndef BTCONFIGCORE_H +#define BTCONFIGCORE_H + +#include <QSettings> + +#include <QCoreApplication> +#include <QHash> +#include <QMutex> +#include <QStringList> + + +/** + \note Session keys are QStrings because we even want to handle cases where the + configuration file is manually changed. When creating new sessions, they + are still generated from unsigned integers. +*/ +class BtConfigCore { + + Q_DISABLE_COPY(BtConfigCore) + Q_DECLARE_TR_FUNCTIONS(BtConfigCore) + +public: /* Types: */ + + typedef QHash<QString, QString> SessionNamesHashMap; + +public: /* Methods: */ + + /** + \param[in] settingsFile The filename of the settings file. + */ + explicit BtConfigCore(const QString & settingsFile); + + inline ~BtConfigCore() { sync(); } + + + /** + \returns the key of the current session. + */ + inline const QString & currentSessionKey() const { + QMutexLocker lock(&m_mutex); + return m_currentSessionKey; + } + + /** + \returns the name of the current session. + */ + inline const QString & currentSessionName() const { + QMutexLocker lock(&m_mutex); + typedef QHash<QString, QString>::const_iterator SSHCI; + SSHCI it = m_sessionNames.constFind(m_currentSessionKey); + Q_ASSERT(it != m_sessionNames.constEnd()); + return it.value(); + } + + /** + \returns a hashmap with the keys and printable names of the sessions. + */ + inline const SessionNamesHashMap & sessionNames() const { + QMutexLocker lock(&m_mutex); + return m_sessionNames; + } + + /** + \brief Notifies the configuration system that the session settings + should be read from and saved to the given session. + + \pre The session with the given key must exist. + \param[in] key the key of the session to switch to. + \post the sessionValue() and value() methods will work with the settings + of the given session. + */ + void setCurrentSession(const QString & key); + + /** + \brief Creates a new session with the given name. + + \pre The given name must not be an empty string. + \param[in] name the name of the session + \returns the key of the created session. + */ + QString addSession(const QString & name); + + /** + \brief Deletes the session with the given key. + + \pre The session with the given key must exist. + \pre The session with the given key must not be the current session. + \param[in] key the key of the session to delete. + \post The session with the given key and its settings are deleted. + \returns whether deleting the session was successful. + */ + void deleteSession(const QString & key); + + /** + \brief Returns the settings value for the given global key. + + \param[in] key Key to get the value for. + \param[in] defaultValue The value to return if no saved value is found. + \returns the value of type specified by the template parameter. + */ + template<typename T> + inline T value(const QString & key, const T & defaultValue = T()) { + QMutexLocker lock(&m_mutex); + return m_settings.value(group() + key, + QVariant::fromValue(defaultValue)).template value<T>(); + } + + /** + \brief Returns the settings value for the given global key as a QVariant. + + \param[in] key Key to get the value for. + \param[in] defaultValue The value to return if no saved value is found. + \returns the value. + */ + inline QVariant qVariantValue(const QString & key, + const QVariant & defaultValue = QVariant()) + { + QMutexLocker lock(&m_mutex); + return m_settings.value(group() + key, + QVariant::fromValue(defaultValue)); + } + + /** + \brief Returns the settings value for the given session key. + + \param[in] key Session key to get the value for. + \param[in] defaultValue The value to return if no saved value is found. + \returns the value of type specified by the template parameter. + */ + template<typename T> + inline T sessionValue(const QString & key, const T & defaultValue = T()) { + QMutexLocker lock(&m_mutex); + return m_settings.value(m_cachedCurrentSessionGroup + group() + key, + QVariant::fromValue(defaultValue)).template value<T>(); + } + + /** + \brief Sets a value for a global settings key. + + \param[in] key Ket to set. + \param[in] value Value to set. + */ + template<typename T> + inline void setValue(const QString & key, const T & value) { + QMutexLocker lock(&m_mutex); + m_settings.setValue(group() + key, QVariant::fromValue<T>(value)); + } + + /** + \brief Sets a value for a session settings key. + + \param[in] key Ket to set. + \param[in] value Value to set. + */ + template<typename T> + inline void setSessionValue(const QString & key, const T & value) { + QMutexLocker lock(&m_mutex); + m_settings.setValue(m_cachedCurrentSessionGroup + group() + key, + QVariant::fromValue<T>(value)); + } + + /** + \returns a list of first-level keys in the current group in global settings. + */ + QStringList childKeys(); + + /** + \pre subkey is not empty + \param[in] subkey the subkey + \returns a list of keys under the current group and subkey in global settings. + */ + QStringList childKeys(const QString & subkey); + + /** + \returns a list of first-level groups in the current group in global settings. + */ + QStringList childGroups(); + + /** + \pre subkey is not empty + \param[in] subkey the subkey + \returns a list of groups under the current group and subkey in global settings. + */ + QStringList childGroups(const QString & subkey); + + /** + \returns a list of first-level groups in the current group in session settings. + */ + QStringList sessionChildGroups(); + + /** + \pre subkey is not empty + \param[in] subkey the subkey + \returns a list of groups under the current group and subkey in session settings. + */ + QStringList sessionChildGroups(const QString & subkey); + + /** + \brief removes a key all its children from global settings. + + \param[in] key the key to remove + */ + void remove(const QString & key); + + /** + \brief removes a key all its children from session settings. + + \param[in] key the key to remove + */ + void sessionRemove(const QString & key); + + /** + \brief Synchronize the underlying QSettings. + */ + inline void sync() { + QMutexLocker lock(&m_mutex); + m_settings.sync(); + } + + /** + \brief Appends the given prefix to the current group. + + The current group is automatically prepended to all keys when reading or + writing settings values. The behaviour is similar to QSettings::beginGroup(). + + \warning Locks the object (recursively) until endGroup(). + + \param[in] prefix the prefix to append + */ + inline void beginGroup(QString prefix) { + Q_ASSERT(!prefix.isEmpty()); + while (prefix.startsWith('/')) + prefix.remove(0, 1); + Q_ASSERT(!prefix.isEmpty()); + while (prefix.endsWith('/')) + prefix.chop(1); + Q_ASSERT(!prefix.isEmpty()); + + m_mutex.lock(); + m_groups.append(prefix); + m_cachedGroup = QString(); + } + + /** + \brief Resets the current group to its previous value. + + Call this function after you are done with a started group. Every call to + beginGroup() must be matched with a call to this function in the same + thread. + + \warning Locks the object (recursively) until endGroup(). + */ + inline void endGroup() { + Q_ASSERT_X(!m_groups.isEmpty(), "BtConfig", "endGroup() called, but no beginGroup() active."); + m_groups.removeLast(); + m_cachedGroup = QString(); + m_mutex.unlock(); + } + + /** + \brief Returns the current group. + + Returns the group the BtConfig is currently set to. It will contain a + trailing / so is suitable to be preprended to a key directly. + + \returns the group string or an empty string if no group is set. + */ + inline QString group() const { + QMutexLocker lock(&m_mutex); + if (m_cachedGroup.isNull()) { + m_cachedGroup = m_groups.isEmpty() + ? "" + : m_groups.join("/") + '/'; + } + return m_cachedGroup; + } + +private: /* Methods: */ + + /** + \Brief Same childKeys(), but not thread-safe. + \returns a list of first-level keys in the current group in global settings. + */ + QStringList childKeys__(); + + /** + \Brief Same childGroups(), but not thread-safe. + \returns a list of first-level groups in the current group in global settings. + */ + QStringList childGroups__(); + + /** + \Brief Same sessionChildGroups(), but not thread-safe. + \returns a list of first-level groups in the current group in session settings. + */ + QStringList sessionChildGroups__(); + +protected: /* Fields: */ + + /** Required for asynchronous access */ + mutable QMutex m_mutex; + +private: /* Fields: */ + + /** Underlying backend */ + QSettings m_settings; + + /** List of active group prefixes */ + QStringList m_groups; + + /** Cached group() string or QString::null if not cached */ + mutable QString m_cachedGroup; + + /** Index of currently active session */ + QString m_currentSessionKey; + + /** Cached group name of the currently active session */ + mutable QString m_cachedCurrentSessionGroup; + + /** Keys and names all sessions */ + SessionNamesHashMap m_sessionNames; + + // Helper key strings: + static const QString GROUP_SESSIONS; + static const QString KEY_CURRENT_SESSION; + static const QString GROUP_SESSION; + static const QString KEY_SESSION_NAME; + static const QString UI_FONT_SIZE; +}; + +#endif // BTCONFIGCORE_H diff --git a/src/backend/config/cbtconfig.cpp b/src/backend/config/cbtconfig.cpp deleted file mode 100644 index d82fc7d..0000000 --- a/src/backend/config/cbtconfig.cpp +++ /dev/null @@ -1,776 +0,0 @@ -/********* -* -* This file is part of BibleTime's source code, http://www.bibletime.info/. -* -* Copyright 1999-2011 by the BibleTime developers. -* The BibleTime source code is licensed under the GNU General Public License version 2.0. -* -**********/ - -#include "backend/config/cbtconfig.h" - -#include <QDebug> -#include <QLocale> -#include <QSettings> -#include <QVariant> -#include <QWebSettings> -#include "backend/btmoduletreeitem.h" -#include "backend/managers/cdisplaytemplatemgr.h" -#include "btglobal.h" -#include "frontend/displaywindow/btactioncollection.h" -#include "frontend/searchdialog/btsearchoptionsarea.h" -#include "util/directory.h" - -// Sword includes: -#include <versekey.h> // For range configuration - - -namespace CBTConfig { -namespace { - -typedef QMap<const CLanguageMgr::Language*, FontSettingsPair> FontCacheMap; - -QFont *m_defaultFont = 0; -FontCacheMap m_fontCache; - -QString getKey(const strings ID) { - switch (ID) { - case bibletimeVersion: - return "bibletimeVersion"; - case language: - return "language"; - case displayStyle: - return "displayStyle"; - case bookshelfCurrentItem: - return "bookshelfCurrentItem"; - } - return QString::null; -} - -QString getKey(const 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"; - } - return QString::null; -} - -QString getKey(const bools ID) { - switch (ID) { - case firstSearchDialog: - return "firstSearchDialog"; - case readOldBookmarks: - return "readOldBookmarks"; - - case showMainWindowToolbar: - return "showMainWindowToolbar"; - case mainIndex: - return "mainIndex"; - case infoDisplay: - return "infoDisplay"; - - case autoTileVertical: - return "autoTileVertical"; - case autoTileHorizontal: - return "autoTileHorizontal"; - case autoTile: - return "autoTile"; - case autoTabbed: - return "autoTabbed"; - 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"; - - case showTextWindowHeaders: - return "showTextWindowHeaders"; - case showTextWindowNavigator: - return "showTextWindowNavigator"; - case showTextWindowModuleSelectorButtons: - return "showTextWindowModuleSelectorButtons"; - case showFormatToolbarButtons: - return "showFormatToolbarButtons"; - case showTextWindowToolButtons: - return "showTextWindowToolButtons"; - case showToolbarsInEachWindow: - return "showToolbarsInEachWindow"; - case showTipAtStartup: - return "showTipAtStartup"; - default: - Q_ASSERT(false); - return QString::null; - } -} - -QString getKey(const 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"; - case bookshelfPosX: - return "bookshelfPosX"; - case bookshelfPosY: - return "bookshelfPosY"; - case bookshelfHeight: - return "bookshelfHeight"; - case bookshelfWidth: - return "bookshelfWidth"; - case configDialogPosX: - return "configDialogPosX"; - case configDialogPosY: - return "configDialogPosY"; - case configDialogHeight: - return "configDialogHeight"; - case configDialogWidth: - return "configDialogWidth"; - case tipNumber: - return "tipNumber"; - default: - Q_ASSERT(false); - return QString::null; - } -} - -QString getKey(const intLists ID) { - switch (ID) { - case leftPaneSplitterSizes: - return "leftPaneSplitterSizes"; - case mainSplitterSizes: - return "mainSplitterSizes"; - case searchMainSplitterSizes: - return "searchMainSplitterSizes"; - case searchResultSplitterSizes: - return "searchResultSplitterSizes"; - } - return QString::null; -} - -QString getKey(const stringLists ID) { - switch (ID) { - case searchCompletionTexts: - return "searchCompletionTexts"; - case searchTexts: - return "searchTexts"; - case searchModulesHistory: - return "searchModulesHistory"; - case bookshelfOpenGroups: - return "bookshelfOpenGroups"; - case hiddenModules: - return "hiddenModules"; - default: - Q_ASSERT(false); - return QString::null; - } -} - -QString getKey(const stringMaps ID) { - Q_ASSERT(ID == searchScopes); - return "SearchScopes"; -} - -QString getKey(const CLanguageMgr::Language * const language) { - Q_ASSERT(!language->name().isEmpty()); - return language->name(); -} - -} // anonymous namespace - -QString IntListToString(const QList<int> &intList) { - QStringList intStrings; - Q_FOREACH (int i, intList) { - intStrings << QString::number(i); - } - return intStrings.join(","); -} - -QList<int> StringToIntList(const QString &intListString, - bool *ok, - QString::SplitBehavior splitBehavior) -{ - QList<int> intList; - if (ok != 0) { - *ok = true; - - if (!intListString.isEmpty()) { - Q_FOREACH (const QString &intString, intListString.split(',', splitBehavior)) { - int i = intString.trimmed().toInt(ok); - if (!(*ok)) - break; - - intList << i; - } - } - } else { - if (!intListString.isEmpty()) { - Q_FOREACH (const QString &intString, intListString.split(',', splitBehavior)) { - intList << intString.trimmed().toInt(); - } - } - } - return intList; -} - -QString getDefault(const 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::defaultTemplateName(); - case bookshelfCurrentItem: - default: - return QString::null; - } -} - -QString getDefault(const modules ID) { - 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"; - default: - return QString::null; - } -} - -bool getDefault(const bools ID) { - switch (ID) { - case firstSearchDialog: - case showMainWindowToolbar: - case mainIndex: - case infoDisplay: - case autoTileVertical: - case verseNumbers: - case logo: - case autoDeleteOrphanedIndices: - case showTextWindowHeaders: - case showTextWindowNavigator: - case showTextWindowModuleSelectorButtons: - case showTextWindowToolButtons: - case showFormatToolbarButtons: - case showToolbarsInEachWindow: - case showTipAtStartup: - return true; - case readOldBookmarks: - case autoTileHorizontal: - case autoTile: - case autoTabbed: - case autoCascade: - case lineBreaks: - case crashedLastTime: - case crashedTwoTimes: - case bookshelfShowHidden: - case allowNetworkConnection: - default: - return false; - } -} - -int getDefault(const ints ID) { - switch (ID) { - case bookshelfGrouping: - return BTModuleTreeItem::CatLangMod; - case searchType: - return Search::BtSearchOptionsArea::AndType; - case searchDialogHeight: - case magDelay: - return 400; - case searchDialogWidth: - case searchDialogX: - case searchDialogY: - return 200; - case footnotes: - case strongNumbers: - case headings: - case morphTags: - case lemmas: - case hebrewPoints: - case hebrewCantillation: - case greekAccents: - case scriptureReferences: - case morphSegmentation: - case bookshelfPosX: - case bookshelfPosY: - case bookshelfHeight: - case bookshelfWidth: - case configDialogPosX: - case configDialogPosY: - case configDialogHeight: - case configDialogWidth: - return 1; - case textualVariants: - case bookshelfContentsX: - case bookshelfContentsY: - case mainindexActiveTab: - case installPathIndex: - case tipNumber: - default: - return 0; - } -} - -QList<int> getDefault(const intLists /*ID*/) { - return QList<int>(); -} - -QStringList getDefault(const stringLists ID) { - if (ID == searchTexts) { - QStringList list; - list.append(QString::null); - return list; - } else { - return QStringList(); - } -} - -StringMap getDefault(const stringMaps ID) { - Q_ASSERT(ID == searchScopes); - - 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! - sword::VerseKey vk; - vk.setLocale("en_US"); - - for (StringMap::Iterator 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.append(QString::fromUtf8(list.getElement(i)->getRangeText())); - data.append("; "); - } - map[it.key()] = data; - }; - - return map; -} - -QFont &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 - - m_defaultFont = new QFont(); - m_defaultFont->setPointSize(12); - return *m_defaultFont; -} - -QString get(const strings ID) { - QVariant v = getConfig()->value("strings/" + getKey(ID)); - if (v.isValid()) - return v.toString(); - - return getDefault(ID); -} - -CSwordModuleInfo *get(const modules ID) { - QVariant v = getConfig()->value("modules/" + getKey(ID)); - CSwordBackend *b = CSwordBackend::instance(); - if (v.isValid()) - return b->findModuleByName(v.toString()); - - return b->findModuleByName(getDefault(ID)); -} - -bool get(const bools ID) { - QVariant v = getConfig()->value("bools/" + getKey(ID)); - if (v.isValid()) - return v.toBool(); - - return getDefault(ID); -} - -int get(const ints ID) { - QVariant v = getConfig()->value("ints/" + getKey(ID)); - if (v.isValid()) - return v.toInt(); - - return getDefault(ID); -} - -QList<int> get(const intLists ID) { - QVariant v = getConfig()->value("intlists/" + getKey(ID)); - if (v.isValid()) { - bool ok; - QList<int> r = StringToIntList(v.toString(), &ok); - if (ok) - return r; - } - return getDefault(ID); -} - -QStringList get(const stringLists ID) { - QVariant v = getConfig()->value("stringlists/" + getKey(ID)); - if (v.isValid()) - return v.toStringList(); - - return getDefault(ID); -} - -StringMap get(const stringMaps ID) { - Q_ASSERT(ID == searchScopes); - - QSettings *s = getConfig(); - s->beginGroup(getKey(ID)); - const QStringList keys = s->childKeys(); - - if (keys.isEmpty()) { - s->endGroup(); - return getDefault(ID); - } - - /** - Make sure we return the scopes in the chosen language. saved - keys are in english. - */ - StringMap map; - sword::VerseKey vk; - Q_FOREACH (const QString &key, keys) { - if (key.isEmpty()) - continue; - - QByteArray b = s->value(key).toString().toUtf8(); - sword::ListKey list(vk.ParseVerseList(b, "Genesis 1:1", true)); - QString data; - for (int i = 0; i < list.Count(); i++) { - data.append(QString::fromUtf8(list.getElement(i)->getRangeText())); - data.append("; "); - } - map[key] = data; // Set the new data - } - s->endGroup(); - return map; -} - -FontSettingsPair get(const CLanguageMgr::Language * const language) { - // Check the cache first: - FontCacheMap::const_iterator it = m_fontCache.find(language); - if (it != m_fontCache.end()) - return *it; - - QSettings *s = getConfig(); - FontSettingsPair fontSettings; - fontSettings.first = s->value("font standard settings/" + getKey(language), false).toBool(); - - if (fontSettings.first) { - QVariant v = s->value("fonts/" + getKey(language)); - if (v.isValid()) { - fontSettings.second.fromString(v.toString()); - } else { - fontSettings.second = getDefault(language); - } - } else { - fontSettings.second = getDefault(language); - } - - // Cache the value: - m_fontCache.insert(language, fontSettings); - - return fontSettings; -} - -void set(const strings ID, const QString &value) { - getConfig()->setValue("strings/" + getKey(ID), value); -} - -void set(const modules ID, CSwordModuleInfo * const value) { - getConfig()->setValue("modules/" + getKey(ID), value ? value->name() : QString::null); -} - -void set(const modules ID, const QString &value) { - CSwordModuleInfo *module(CSwordBackend::instance()->findModuleByName(value)); - if (module) { - set(ID, module); - } -} - -void set(const bools ID, const bool value) { - getConfig()->setValue("bools/" + getKey(ID), value); -} - -void set(const ints ID, const int value) { - getConfig()->setValue("ints/" + getKey(ID), value); -} - -void set(const intLists ID, const QList<int> &value) { - getConfig()->setValue("intlists/" + getKey(ID), IntListToString(value)); -} - -void set(const stringLists ID, const QStringList &value) { - getConfig()->setValue("stringlists/" + getKey(ID), value); -} - -void set(const stringMaps ID, const StringMap &value) { - typedef StringMap::ConstIterator SMCI; - using namespace sword; - - QSettings *s = getConfig(); - s->beginGroup(getKey(ID)); - - // Clear all entries of this group to make sure old stuff gets removed: - s->remove(""); - - 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. - */ - VerseKey vk; - for (SMCI it(value.begin()); it != value.end(); it++) { - QString data; - ListKey list(vk.ParseVerseList(it.value().toUtf8(), "Genesis 1:1", true)); - for (int i(0); i < list.Count(); i++) { - VerseKey *range(dynamic_cast<VerseKey*>(list.getElement(i))); - if (range) { - range->setLocale("en"); - data.append(QString::fromUtf8( range->getRangeText() )); - data.append(";"); - } - } - s->setValue(it.key(), data); - } - break; - } - default: { - for (SMCI it(value.begin()); it != value.end(); it++) { - s->setValue(it.key(), it.value()); - } - break; - } - } - s->endGroup(); -} - -void set(const CLanguageMgr::Language * const language, - const FontSettingsPair& value) -{ - QSettings *s = getConfig(); - QString lang = getKey(language); - s->setValue("fonts/" + lang, value.second.toString()); - s->setValue("font standard settings/" + lang, value.first); - - // Remove language from the cache: - m_fontCache.remove(language); -} - -DisplayOptions getDisplayOptionDefaults() { - DisplayOptions options; - options.lineBreaks = get(lineBreaks); - options.verseNumbers = get(verseNumbers); - return options; -} - -FilterOptions getFilterOptionDefaults() { - FilterOptions options; - - options.footnotes = true; // Required for the info display - options.strongNumbers = true; // get(strongNumbers); - options.headings = get(headings); - options.morphTags = true; // Required for the info display - options.lemmas = true; // Required for the info display - options.redLetterWords = true; - options.hebrewPoints = get(hebrewPoints); - options.hebrewCantillation = get(hebrewCantillation); - options.greekAccents = get(greekAccents); - options.textualVariants = get(textualVariants); - options.scriptureReferences = get(scriptureReferences); - options.morphSegmentation = get(morphSegmentation); - - return options; -} - -void setupAccelSettings(const keys type, - BtActionCollection * const actionCollection) -{ - const char *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; - } - - actionCollection->setConfigGroup(groupName); - actionCollection->readSettings(); -} - -void saveAccelSettings(const keys type, - BtActionCollection * const actionCollection) -{ - const char *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; - } - - actionCollection->setConfigGroup(groupName); - actionCollection->writeSettings(); -} - - -QString getModuleEncryptionKey(const QString &module) { - Q_ASSERT(!module.isEmpty()); - static const QString nullString; - - QVariant v = getConfig()->value("Module keys/" + module); - if (v.isValid()) - return v.toString(); - - return nullString; -} - -void setModuleEncryptionKey(const QString &module, const QString &key) { - getConfig()->setValue("Module keys/" + module, key); -} - -QSettings *getConfig() { - namespace DU = util::directory; - static QSettings config(DU::getUserBaseDir().absolutePath() + "/bibletimerc", QSettings::IniFormat); - return &config; -} - -void syncConfig() { - getConfig()->sync(); -} - -} // namespace CBTConfig diff --git a/src/backend/config/cbtconfig.h b/src/backend/config/cbtconfig.h deleted file mode 100644 index f3fa042..0000000 --- a/src/backend/config/cbtconfig.h +++ /dev/null @@ -1,204 +0,0 @@ -/********* -* -* This file is part of BibleTime's source code, http://www.bibletime.info/. -* -* Copyright 1999-2011 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 <QString> -#include <QFont> -#include <QList> -#include <QMap> -#include "backend/managers/cswordbackend.h" - -class QSettings; -class BtActionCollection; - -/** - * This class is the interface to the config object of BibleTime - * @author The BibleTime team - */ -namespace CBTConfig { - -typedef QMap<QString, QString> StringMap; -typedef std::pair<bool, QFont> FontSettingsPair; - -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, - - showMainWindowToolbar, - mainIndex, - infoDisplay, - - autoTileVertical, - autoTileHorizontal, - autoTile, - autoTabbed, - autoCascade, - - lineBreaks, - verseNumbers, - - logo, - autoDeleteOrphanedIndices, - crashedLastTime, - crashedTwoTimes, - - bookshelfShowHidden, - - allowNetworkConnection, - - showTextWindowHeaders, - showTextWindowNavigator, - showTextWindowToolButtons, - showTextWindowModuleSelectorButtons, - showFormatToolbarButtons, - showToolbarsInEachWindow, - showTipAtStartup -}; -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, - - bookshelfPosX, - bookshelfPosY, - bookshelfHeight, - bookshelfWidth, - - configDialogPosX, - configDialogPosY, - configDialogHeight, - configDialogWidth, - tipNumber -}; -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 -}; - -QString IntListToString(const QList<int> &intList); -QList<int> StringToIntList(const QString &intListString, - bool *ok = 0, - QString::SplitBehavior splitBehavior = QString::KeepEmptyParts); - -QString getDefault(const strings); -QString getDefault(const modules); -bool getDefault(const bools); -int getDefault(const ints); -QList<int> getDefault(const intLists); -QStringList getDefault(const stringLists); -StringMap getDefault(const stringMaps); -QFont &getDefault(const CLanguageMgr::Language * const); - -QString get(const strings); -CSwordModuleInfo *get(const modules); -bool get(const bools); -int get(const ints); -QList<int> get(const intLists); -QStringList get(const stringLists); -StringMap get(const stringMaps); -FontSettingsPair get(const CLanguageMgr::Language * const); - -void set(const strings, const QString &value); -void set(const modules, CSwordModuleInfo * const module); -void set(const modules, const QString &moduleName); -void set(const bools, const bool value); -void set(const ints, const int value); -void set(const intLists, const QList<int> &value); -void set(const stringLists, const QStringList &value); -void set(const stringMaps, const StringMap &value); -void set(const CLanguageMgr::Language * const language, - const FontSettingsPair &fontSettings); - -FilterOptions getFilterOptionDefaults(); -DisplayOptions getDisplayOptionDefaults(); - -void setupAccelSettings(const keys type, - BtActionCollection * const actionCollection); -void saveAccelSettings (const keys type, - BtActionCollection * const actionCollection); - -QString getModuleEncryptionKey(const QString &name); -void setModuleEncryptionKey(const QString &name, const QString &key); - -/** - Re-reads the config from disk. -*/ -void syncConfig(); - -/** - Returns the config object. -*/ -QSettings* getConfig(); - -} // namespace CBTConfig - -#endif diff --git a/src/backend/cswordmodulesearch.cpp b/src/backend/cswordmodulesearch.cpp index 694151d..799032b 100644 --- a/src/backend/cswordmodulesearch.cpp +++ b/src/backend/cswordmodulesearch.cpp @@ -2,16 +2,19 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ +#include <QDebug> + #include "backend/cswordmodulesearch.h" -#include "backend/config/cbtconfig.h" +#include "backend/config/btconfig.h" #include "backend/managers/cswordbackend.h" #include "btglobal.h" +#include "util/tool.h" void CSwordModuleSearch::startSearch() { @@ -20,7 +23,7 @@ void CSwordModuleSearch::startSearch() { m_foundItems = 0; /// \todo What is the purpose of the following statement? - CSwordBackend::instance()->setFilterOptions(CBTConfig::getFilterOptionDefaults()); + CSwordBackend::instance()->setFilterOptions(btConfig().getFilterOptions()); // Search module-by-module: Q_FOREACH(const CSwordModuleInfo *m, m_searchModules) { @@ -61,3 +64,287 @@ QList<const CSwordModuleInfo*> CSwordModuleSearch::unindexedModules( } return unindexed; } + +QString CSwordModuleSearch::highlightSearchedText(const QString& content, const QString& searchedText) { + QString ret = content; + + const Qt::CaseSensitivity cs = Qt::CaseInsensitive; + + // int index = 0; + int index = ret.indexOf("<body", 0); + int matchLen = 0; + int length = searchedText.length(); + + // Highlighting constants - + // \todo We need to make the highlight color configurable. + const QString rep1("<span style=\"background-color:#FFFF66;\">"); + const QString rep2("</span>"); + const unsigned int repLength = rep1.length() + rep1.length(); + const QString rep3("style=\"background-color:#FFFF66;\" "); + const unsigned int rep3Length = rep3.length(); + + + QString newSearchText; + + newSearchText = searchedText; + + // find the strongs search lemma and highlight it + // search the searched text for "strong:" until it is not found anymore + QStringList list; + + // split the search string - some possibilities are "\\s|\\|", "\\s|\\+", or "\\s|\\|\\+" + // \todo find all possible seperators + QString regExp = "\\s"; + list = searchedText.split(QRegExp(regExp)); + foreach (QString newSearchText, list) { + int sstIndex; // strong search text index for finding "strong:" + int idx1, idx2; + QString sNumber, lemmaText; + + sstIndex = newSearchText.indexOf("strong:"); + if (sstIndex == -1) + continue; + + // set the start index to the start of <body> + int strongIndex = index; + + // Get the strongs number from the search text. + // First, find the first space after "strong:" + sstIndex = sstIndex + 7; + // get the strongs number -> the text following "strong:" to the end of the string. + sNumber = newSearchText.mid(sstIndex, -1); + // find all the "lemma=" inside the the content + while ((strongIndex = ret.indexOf("lemma=", strongIndex, cs)) != -1) { + // get the strongs number after the lemma and compare it with the + // strongs number we are looking for + idx1 = ret.indexOf("\"", strongIndex) + 1; + idx2 = ret.indexOf("\"", idx1 + 1); + lemmaText = ret.mid(idx1, idx2 - idx1); + + // this is interesting because we could have a strongs number like: G3218|G300 + // To handle this we will use some extra cpu cycles and do a partial match against + // the lemmaText + if (lemmaText.contains(sNumber)) { + // strongs number is found now we need to highlight it + // I believe the easiest way is to insert rep3 just before "lemma=" + ret = ret.insert(strongIndex, rep3); + strongIndex += rep3Length; + } + strongIndex += 6; // 6 is the length of "lemma=" + } + } + //--------------------------------------------------------------------- + // now that the strong: stuff is out of the way continue with + // other search options + //--------------------------------------------------------------------- + + // try to figure out how to use the lucene query parser + + //using namespace lucene::queryParser; + //using namespace lucene::search; + //using namespace lucene::analysis; + //using namespace lucene::util; + + //wchar_t *buf; + //char buf8[1000]; + //standard::WhitespaceAnalyzer analyzer; + //lucene_utf8towcs(m_wcharBuffer, searchedText.utf8(), MAX_CONV_SIZE); + //QSharedPointer<Query> q( QueryParser::parse(m_wcharBuffer, _T("content"), &analyzer) ); + //StringReader reader(m_wcharBuffer); + //TokenStream* tokenStream = analyzer.tokenStream( _T("field"), &reader); + //Token token; + //while(tokenStream->next(&token) != 0) { + // lucene_wcstoutf8(buf8, token.termText(), 1000); + // printf("%s\n", buf8); + //} + + //=========================================================== + // since I could not figure out the lucene query parser, I + // made a simple parser. + //=========================================================== + QStringList words = queryParser(newSearchText); + qDebug() << "btsearchresultarea.cpp: " << __LINE__ << ": " << words << '\n'; + foreach (QString word, words) { //search for every word in the list + QRegExp findExp; + if (word.contains("*")) { + length = word.length() - 1; + word.replace('*', "\\S*"); //match within a word + findExp = QRegExp(word); + findExp.setMinimal(true); + } + else if (word.contains("?")) { + length = word.length() - 1; + word.replace('?', "\\S?"); //match within a word + findExp = QRegExp(word); + findExp.setMinimal(true); + } + else { + length = word.length(); + findExp = QRegExp("\\b" + word + "\\b"); + } + + // index = 0; //for every word start at the beginning + index = ret.indexOf("<body", 0); + findExp.setCaseSensitivity(cs); + //while ( (index = ret.find(findExp, index)) != -1 ) { //while we found the word + while ( (index = findExp.indexIn(ret, index)) != -1 ) { //while we found the word + matchLen = findExp.matchedLength(); + if (!util::tool::inHTMLTag(index, ret)) { + length = matchLen; + ret = ret.insert( index + length, rep2 ); + ret = ret.insert( index, rep1 ); + index += repLength; + } + index += length; + } + } + qDebug() << "btsearchresultarea.cpp: " << __LINE__ << ": " << words << '\n'; + //qWarning("\n\n\n%s", ret.latin1()); + return ret; +} + +QStringList CSwordModuleSearch::queryParser(const QString& queryString) { + QString token; + QStringList tokenList; + int cnt, pos; + + token = ""; + cnt = 0; + while (cnt < queryString.length()) { + // add to token + if ((queryString[cnt]).isLetterOrNumber() || (queryString[cnt] == '*')) { + token = token + queryString[cnt]; + cnt++; + } + else if ((queryString[cnt]).isLetterOrNumber() || (queryString[cnt] == '?')) { + token = token + queryString[cnt]; + cnt++; + } + // token break + else if (queryString[cnt] == ' ') { + token = token.simplified(); + if ((token != "*") && (token != "")) + tokenList.append(token); + token = ""; + cnt++; + } + // clucene appears to ignore quoted strings in the sence + // that it treats all the words within quoted strings as + // regular tokens and not as a single token. + else if (queryString[cnt] == '"') { + cnt++; + } + // wild card - treat as a special token break + //else if (queryString[cnt] == '*') { + // token = token + queryString[cnt]; + // token = token.simplified(); + // if ((token != "*") && (token != "")) + // tokenList.append(token); + // // start next token with wildcard (kin*m -> kin* *m) + // token = "*"; + // cnt++; + //} + // the ! token is also a token break + else if (queryString[cnt] == '!') { + // store away current token + token = token.simplified(); + if ((token != "*") && (token != "")) + tokenList.append(token); + // add the ! token + tokenList.append("!"); + token = ""; + cnt++; + } + // the - token is also a token break + else if (queryString[cnt] == '-') { + // store away current token + token = token.simplified(); + if ((token != "*") && (token != "")) + tokenList.append(token); + // add the ! token + tokenList.append("-"); + token = ""; + cnt++; + } + // the + token is also a token break + else if (queryString[cnt] == '+') { + // store away current token + token = token.simplified(); + if ((token != "*") && (token != "")) + tokenList.append(token); + // add the + token + tokenList.append("+"); + token = ""; + cnt++; + } + // the || token is also a token break + else if ((queryString[cnt] == '|') && (queryString[cnt+1] == '|')) { + // store away current token + token = token.simplified(); + if ((token != "*") && (token != "")) + tokenList.append(token); + // add the || token + tokenList.append("||"); + token = ""; + cnt += 2; + } + // the && token is also a token break + else if ((queryString[cnt] == '&') && (queryString[cnt+1] == '&')) { + // store away current token + token = token.simplified(); + if ((token != "*") && (token != "")) + tokenList.append(token); + // add the || token + tokenList.append("&&"); + token = ""; + cnt += 2; + } + else cnt++; + } + token = token.simplified(); + if ((token != "*") && (token != "")) + tokenList.append(token); + + cnt = 0; + QStringList::iterator it; + for (it = tokenList.begin(); it != tokenList.end(); ++it) { + //----------------------------------------------------------- + // remove all the NOT(!) tokens - these do not need to be + // highlighted in the highlighter + //----------------------------------------------------------- + if (((*it) == "!") || ((*it) == "NOT") || ((*it) == "-")) { + it = tokenList.erase(it); + if (it == tokenList.end()) + break; + it = tokenList.erase(it); + if (it == tokenList.end()) + break; + --it; + } + //----------------------------------------------------------- + // remove all the operator tokens - these do not need to be + // highlighted in the highlighter + //----------------------------------------------------------- + else if ( ((*it) == "||") || ((*it) == "OR") || ((*it) == "+") || + ((*it) == "AND") || ((*it) == "&&") ) { + it = tokenList.erase(it); + if (it == tokenList.end()) + break; + --it; + } + // if the token contains a ^ then trim the remainder of the + // token from the ^ + //What??? error: invalid conversion from ‘const void*’ to ‘int’ + // and how come "contains" returns bool but is used as int? + //else if ( (pos = (*it).contains("^")) >= 0 ) { + else if ( (pos = (*it).indexOf("^") ) >= 0 ) { + (*it) = (*it).left(pos - 1); + } + // if the token contains a ~ then trim the remainder of the + // token from the ~ + else if ( (pos = (*it).indexOf("~") ) >= 0 ) { + (*it) = (*it).left(pos - 2) + "*"; + } + } + return(tokenList); +} diff --git a/src/backend/cswordmodulesearch.h b/src/backend/cswordmodulesearch.h index aa864b0..48b66d2 100644 --- a/src/backend/cswordmodulesearch.h +++ b/src/backend/cswordmodulesearch.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -101,6 +103,17 @@ class CSwordModuleSearch: public QObject { static QList<const CSwordModuleInfo*> unindexedModules( const QList<const CSwordModuleInfo*> &modules); + /** + * This function highlights the searched text in the content using the search type given by search flags + */ + static QString highlightSearchedText(const QString& content, const QString& searchedText); + + protected: + /** + * This function breakes the queryString into clucene tokens + */ + static QStringList queryParser(const QString& queryString); + private: /* Fields: */ QString m_searchText; sword::ListKey m_searchScope; diff --git a/src/backend/drivers/cswordbiblemoduleinfo.cpp b/src/backend/drivers/cswordbiblemoduleinfo.cpp index e87fea2..1c1d124 100644 --- a/src/backend/drivers/cswordbiblemoduleinfo.cpp +++ b/src/backend/drivers/cswordbiblemoduleinfo.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -18,9 +18,9 @@ CSwordBibleModuleInfo::CSwordBibleModuleInfo(sword::SWModule *module, - CSwordBackend * const usedBackend, + CSwordBackend & backend, ModuleType type) - : CSwordModuleInfo(module, usedBackend, type) + : CSwordModuleInfo(module, backend, type) , m_boundsInitialized(false) , m_lowerBound(0) , m_upperBound(0) @@ -35,7 +35,7 @@ void CSwordBibleModuleInfo::initBounds() const { Q_ASSERT(!m_boundsInitialized); sword::SWModule *m = module(); - const bool oldStatus = m->getSkipConsecutiveLinks(); + const bool oldStatus = m->isSkipConsecutiveLinks(); m->setSkipConsecutiveLinks(true); m->setPosition(sword::TOP); // position to first entry @@ -57,11 +57,14 @@ void CSwordBibleModuleInfo::initBounds() const { /** Returns the books available in this module */ QStringList *CSwordBibleModuleInfo::books() const { - if (m_cachedLocale != backend()->booknameLanguage()) { - // Reset the booklist because the locale has changed - m_cachedLocale = backend()->booknameLanguage(); - delete m_bookList; - m_bookList = 0; + { + CSwordBackend & b = backend(); + if (m_cachedLocale != b.booknameLanguage()) { + // Reset the booklist because the locale has changed + m_cachedLocale = b.booknameLanguage(); + delete m_bookList; + m_bookList = 0; + } } if (!m_bookList) { @@ -81,12 +84,12 @@ QStringList *CSwordBibleModuleInfo::books() const { max--; // max == 1 if (min > max) { - qWarning("CSwordBibleModuleInfo (%s) no OT and not NT! Check your config!", module()->Name()); + qWarning("CSwordBibleModuleInfo (%s) no OT and not NT! Check your config!", module()->getName()); } else { - QSharedPointer<sword::VerseKey> key((sword::VerseKey *)module()->CreateKey()); + QSharedPointer<sword::VerseKey> key((sword::VerseKey *)module()->createKey()); key->setPosition(sword::TOP); - for (key->setTestament(min); !key->Error() && key->getTestament() <= max; key->setBook(key->getBook() + 1)) { + for (key->setTestament(min); !key->popError() && key->getTestament() <= max; key->setBook(key->getBook() + 1)) { m_bookList->append( QString::fromUtf8(key->getBookName()) ); } } @@ -98,7 +101,7 @@ QStringList *CSwordBibleModuleInfo::books() const { unsigned int CSwordBibleModuleInfo::chapterCount(const unsigned int book) const { int result = 0; - QSharedPointer<sword::VerseKey> key((sword::VerseKey *)module()->CreateKey()); + QSharedPointer<sword::VerseKey> key((sword::VerseKey *)module()->createKey()); key->setPosition(sword::TOP); // works for old and new versions @@ -120,7 +123,7 @@ unsigned int CSwordBibleModuleInfo::verseCount(const unsigned int book, { unsigned int result = 0; - QSharedPointer<sword::VerseKey> key((sword::VerseKey *)module()->CreateKey()); + QSharedPointer<sword::VerseKey> key((sword::VerseKey *)module()->createKey()); key->setPosition(sword::TOP); // works for old and new versions @@ -141,7 +144,7 @@ unsigned int CSwordBibleModuleInfo::verseCount(const QString &book, unsigned int CSwordBibleModuleInfo::bookNumber(const QString &book) const { unsigned int bookNumber = 0; - QSharedPointer<sword::VerseKey> key((sword::VerseKey *)module()->CreateKey()); + QSharedPointer<sword::VerseKey> key((sword::VerseKey *)module()->createKey()); key->setPosition(sword::TOP); key->setBookName(book.toUtf8().constData()); diff --git a/src/backend/drivers/cswordbiblemoduleinfo.h b/src/backend/drivers/cswordbiblemoduleinfo.h index 49606e3..fb630c3 100644 --- a/src/backend/drivers/cswordbiblemoduleinfo.h +++ b/src/backend/drivers/cswordbiblemoduleinfo.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -25,7 +27,8 @@ class CSwordBibleModuleInfo: public CSwordModuleInfo { Q_OBJECT public: /* Methods: */ - CSwordBibleModuleInfo(sword::SWModule *module, CSwordBackend * const, + CSwordBibleModuleInfo(sword::SWModule * module, + CSwordBackend & backend, ModuleType type = Bible); inline ~CSwordBibleModuleInfo() { diff --git a/src/backend/drivers/cswordbookmoduleinfo.cpp b/src/backend/drivers/cswordbookmoduleinfo.cpp index 8c6b8b1..bae54b9 100644 --- a/src/backend/drivers/cswordbookmoduleinfo.cpp +++ b/src/backend/drivers/cswordbookmoduleinfo.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -16,11 +16,10 @@ #include <treekeyidx.h> -CSwordBookModuleInfo::CSwordBookModuleInfo(sword::SWModule *module, - CSwordBackend * const usedBackend) - : CSwordModuleInfo(module, usedBackend, - CSwordModuleInfo::GenericBook), - m_depth(-1) +CSwordBookModuleInfo::CSwordBookModuleInfo(sword::SWModule * module, + CSwordBackend & backend) + : CSwordModuleInfo(module, backend, CSwordModuleInfo::GenericBook) + , m_depth(-1) { sword::TreeKeyIdx *key = tree(); if (key) { @@ -29,25 +28,21 @@ CSwordBookModuleInfo::CSwordBookModuleInfo(sword::SWModule *module, } } -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) { +void CSwordBookModuleInfo::computeDepth(sword::TreeKeyIdx * const key, + const int level) +{ + const QByteArray 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 + computeDepth(key, level + 1u); + key->setText(savedKey.constData()); // Return to the initial value } - if (key->nextSibling()) { + if (key->nextSibling()) computeDepth(key, level); - } } /** Returns a treekey filled with the structure of this module */ diff --git a/src/backend/drivers/cswordbookmoduleinfo.h b/src/backend/drivers/cswordbookmoduleinfo.h index c6b0494..d540932 100644 --- a/src/backend/drivers/cswordbookmoduleinfo.h +++ b/src/backend/drivers/cswordbookmoduleinfo.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -27,8 +29,8 @@ class CSwordBookModuleInfo: public CSwordModuleInfo { \param module The module which belongs to this object \param backend The parent backend for this book module. */ - CSwordBookModuleInfo(sword::SWModule *module, - CSwordBackend * const usedBackend); + CSwordBookModuleInfo(sword::SWModule * module, + CSwordBackend & usedBackend); inline CSwordBookModuleInfo(const CSwordBookModuleInfo ©) : CSwordModuleInfo(copy), m_depth(copy.m_depth) {} @@ -46,10 +48,11 @@ class CSwordBookModuleInfo: public CSwordModuleInfo { sword::TreeKeyIdx *tree() const; private: /* Methods: */ + /** * A recursive helper function to help computng the module depth! */ - void computeDepth(sword::TreeKeyIdx *key, int level = 0); + void computeDepth(sword::TreeKeyIdx * const key, const int level = 0); private: /* Fields: */ int m_depth; diff --git a/src/backend/drivers/cswordcommentarymoduleinfo.cpp b/src/backend/drivers/cswordcommentarymoduleinfo.cpp index 07e09d2..9baaf97 100644 --- a/src/backend/drivers/cswordcommentarymoduleinfo.cpp +++ b/src/backend/drivers/cswordcommentarymoduleinfo.cpp @@ -2,19 +2,17 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ #include "backend/drivers/cswordcommentarymoduleinfo.h" - bool CSwordCommentaryModuleInfo::isWritable() const { /* A module is only writable if it's a RawFiles module with writable returning true. */ - return std::string(module()->getConfigEntry("ModDrv")) == "RawFiles" - && module()->isWritable(); + return !qstrcmp(module()->getConfigEntry("ModDrv"), "RawFiles") && module()->isWritable(); } diff --git a/src/backend/drivers/cswordcommentarymoduleinfo.h b/src/backend/drivers/cswordcommentarymoduleinfo.h index 3c42d99..688ae53 100644 --- a/src/backend/drivers/cswordcommentarymoduleinfo.h +++ b/src/backend/drivers/cswordcommentarymoduleinfo.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -22,10 +24,12 @@ class CSwordCommentaryModuleInfo: public CSwordBibleModuleInfo { Q_OBJECT public: /* Methods: */ - inline CSwordCommentaryModuleInfo(sword::SWModule *module, - CSwordBackend * const usedBackend) - : CSwordBibleModuleInfo(module, usedBackend, - CSwordModuleInfo::Commentary) {} + + inline CSwordCommentaryModuleInfo(sword::SWModule * module, + CSwordBackend & backend) + : CSwordBibleModuleInfo(module, + backend, + CSwordModuleInfo::Commentary) {} /* Reimplementation of CSwordModuleInfo::isWritable(). */ virtual bool isWritable() const; diff --git a/src/backend/drivers/cswordlexiconmoduleinfo.cpp b/src/backend/drivers/cswordlexiconmoduleinfo.cpp index 1b976d3..350a49c 100644 --- a/src/backend/drivers/cswordlexiconmoduleinfo.cpp +++ b/src/backend/drivers/cswordlexiconmoduleinfo.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -31,17 +31,6 @@ const QStringList &CSwordLexiconModuleInfo::entries() const { return m_entries; } - // Initialize cache: - //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_entries; - } - if ( name() == QString("EReo_en")) { - qWarning() << "Module EReo_en is buggy and will not be loaded."; - return m_entries; - } - QString dir(DU::getUserCacheDir().absolutePath()); QFile f1( QString(dir).append("/").append(name())); @@ -95,11 +84,12 @@ const QStringList &CSwordLexiconModuleInfo::entries() const { } module()->increment(); - } while (!module()->Error()); + } while (!module()->popError()); module()->setPosition(sword::TOP); // back to the first entry module()->setSkipConsecutiveLinks(false); + /// \todo Document why the following code is here: if (!m_entries.empty() && m_entries.front().simplified().isEmpty()) m_entries.pop_front(); diff --git a/src/backend/drivers/cswordlexiconmoduleinfo.h b/src/backend/drivers/cswordlexiconmoduleinfo.h index 1789b9b..74fad8c 100644 --- a/src/backend/drivers/cswordlexiconmoduleinfo.h +++ b/src/backend/drivers/cswordlexiconmoduleinfo.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -22,8 +24,8 @@ class CSwordLexiconModuleInfo: public CSwordModuleInfo { Q_OBJECT public: /* Methods: */ - inline CSwordLexiconModuleInfo(sword::SWModule *module, - CSwordBackend * const backend) + inline CSwordLexiconModuleInfo(sword::SWModule * module, + CSwordBackend & backend) : CSwordModuleInfo(module, backend, Lexicon) {} inline CSwordLexiconModuleInfo(const CSwordLexiconModuleInfo ©) diff --git a/src/backend/drivers/cswordmoduleinfo.cpp b/src/backend/drivers/cswordmoduleinfo.cpp index 08721c9..f86f9ac 100644 --- a/src/backend/drivers/cswordmoduleinfo.cpp +++ b/src/backend/drivers/cswordmoduleinfo.cpp @@ -2,35 +2,37 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ #include "backend/drivers/cswordmoduleinfo.h" -#include <QSharedPointer> #include <CLucene.h> #include <QByteArray> #include <QCoreApplication> #include <QDebug> #include <QDir> #include <QFileInfo> -#include <QList> -#include <QRegExp> #include <QSettings> -#include "backend/config/cbtconfig.h" +#include <QSharedPointer> +#include <QTextDocument> +#include "backend/config/btconfig.h" #include "backend/drivers/cswordlexiconmoduleinfo.h" #include "backend/keys/cswordkey.h" #include "backend/managers/clanguagemgr.h" #include "backend/managers/cswordbackend.h" #include "backend/rendering/centrydisplay.h" #include "backend/cswordmodulesearch.h" +#include "bibletimeapp.h" #include "btglobal.h" +#include "frontend/messagedialog.h" #include "util/cresmgr.h" #include "util/directory.h" #include "util/exceptions.h" -#include "util/dialogutil.h" +#include "util/geticon.h" +#include "util/htmlescape.h" // Sword includes: #include <listkey.h> @@ -41,29 +43,6 @@ #include <versekey.h> -#if 0 -namespace { - -/** HELPER Method to dump all current EntryAttributes of a module. */ -void dumpEntryAttributes(sword::SWModule *m) { - qDebug() << "Attributes for key: " << m->getKeyText(); - sword::AttributeTypeList::iterator i1; - sword::AttributeList::iterator i2; - sword::AttributeValue::iterator i3; - for (i1 = m->getEntryAttributes().begin(); i1 != m->getEntryAttributes().end(); i1++) { - qDebug() << "[ " << i1->first << " ]"; - for (i2 = i1->second.begin(); i2 != i1->second.end(); i2++) { - qDebug() << "\t[ " << i2->first << " ]"; - for (i3 = i2->second.begin(); i3 != i2->second.end(); i3++) { - qDebug() << "\t\t" << i3->first << " = " << i3->second; - } - } - } -} - -} // anonymous namespace -#endif - //Increment this, if the index format changes //Then indices on the user's systems will be rebuilt const unsigned int INDEX_VERSION = 7; @@ -72,72 +51,74 @@ const unsigned int INDEX_VERSION = 7; //Lucene default is too small const unsigned long BT_MAX_LUCENE_FIELD_LENGTH = 1024 * 1024; -CSwordModuleInfo::CSwordModuleInfo(sword::SWModule *module, - CSwordBackend * const usedBackend, +CSwordModuleInfo::CSwordModuleInfo(sword::SWModule * module, + CSwordBackend & backend, ModuleType type) - : m_module(module), - m_backend(usedBackend ? usedBackend : CSwordBackend::instance()), + : m_module((Q_ASSERT(module), module)), + m_backend(backend), m_type(type), m_cancelIndexing(false), - m_cachedName(QString::fromUtf8(module->Name())), - m_cachedHasVersion(!QString((*m_backend->getConfig())[module->Name()]["Version"]).isEmpty()) + m_cachedName(QString::fromUtf8(module->getName())), + m_cachedHasVersion(!QString((*m_backend.getConfig())[module->getName()]["Version"]).isEmpty()) { - Q_ASSERT(module != 0); - Q_ASSERT(usedBackend != 0); - initCachedCategory(); initCachedLanguage(); - m_hidden = CBTConfig::get(CBTConfig::hiddenModules).contains(name()); - - 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()); - - /// \todo if this is the case, can we use the module at all? - } - } -} + m_hidden = btConfig().value<QStringList>("state/hiddenModules", + QStringList()).contains(m_cachedName); -CSwordModuleInfo::CSwordModuleInfo(const CSwordModuleInfo &o) - : QObject(0), m_module(o.m_module), m_backend(o.m_backend), - m_type(o.m_type), m_hidden(o.m_hidden), - m_cancelIndexing(o.m_cancelIndexing), m_cachedName(o.m_cachedName), - m_cachedCategory(o.m_cachedCategory), - m_cachedLanguage(o.m_cachedLanguage), - m_cachedHasVersion(o.m_cachedHasVersion) + if (m_cachedHasVersion + && (minimumSwordVersion() > sword::SWVersion::currentVersion)) + { + qWarning("The module \"%s\" requires a newer Sword library. Please " + "update to \"Sword %s\".", + m_cachedName.toUtf8().constData(), + minimumSwordVersion().getText()); + + /// \todo if this is the case, can we use the module at all? + } +} + +CSwordModuleInfo::CSwordModuleInfo(const CSwordModuleInfo & copy) + : QObject(NULL) + , m_module(copy.m_module) + , m_backend(copy.m_backend) + , m_type(copy.m_type) + , m_hidden(copy.m_hidden) + , m_cancelIndexing(copy.m_cancelIndexing) + , m_cachedName(copy.m_cachedName) + , m_cachedCategory(copy.m_cachedCategory) + , m_cachedLanguage(copy.m_cachedLanguage) + , m_cachedHasVersion(copy.m_cachedHasVersion) { // Intentionally empty } bool CSwordModuleInfo::unlock(const QString & unlockKey) { - if (!isEncrypted()) { + if (!isEncrypted()) return false; - } bool unlocked = unlockKeyIsValid(); - CBTConfig::setModuleEncryptionKey(name(), unlockKey); + btConfig().setModuleEncryptionKey(m_cachedName, unlockKey); /// \todo remove this comment once it is no longer needed - /* There is currently a deficiency in sword 1.6.1 in that backend->setCipherKey() does - * not work correctly for modules from which data was already fetched. Therefore we have to - * reload the modules in bibletime.cpp - */ - backend()->setCipherKey(m_module->Name(), unlockKey.toUtf8().constData()); + /* There is currently a deficiency in sword 1.6.1 in that + backend->setCipherKey() does not work correctly for modules from which + data was already fetched. Therefore we have to reload the modules in + bibletime.cpp */ + m_backend.setCipherKey(m_module->getName(), unlockKey.toUtf8().constData()); /// \todo write to Sword config as well - if (unlockKeyIsValid() != unlocked) { + if (unlockKeyIsValid() != unlocked) emit unlockedChanged(!unlocked); - } return true; } bool CSwordModuleInfo::isLocked() const { - //still works, but the cipherkey is stored in CBTConfig. - //Works because it is set in sword on program startup. + // still works, but the cipherkey is stored in BtConfig. + // Works because it is set in sword on program startup. return isEncrypted() && !unlockKeyIsValid(); } @@ -148,38 +129,35 @@ bool CSwordModuleInfo::isEncrypted() const { * is encrypted but not necessarily locked */ - //This code is still right, though we do no longer write to the module config files any more - std::map < sword::SWBuf, sword::ConfigEntMap, std::less < sword::SWBuf > >::iterator SectionMapIter; - SectionMapIter = backend()->getConfig()->Sections.find(name().toUtf8().constData()); - if (SectionMapIter == backend()->getConfig()->Sections.end()) + /* This code is still right, though we do no longer write to the module + config files any more. */ + typedef sword::SectionMap::const_iterator SMCI; + SMCI it = m_backend.getConfig()->Sections.find(m_cachedName.toUtf8().constData()); + if (it == m_backend.getConfig()->Sections.end()) return false; - sword::ConfigEntMap config = SectionMapIter->second; - sword::ConfigEntMap::iterator it = config.find("CipherKey"); - return it != config.end(); + const sword::ConfigEntMap & config = it->second; + return config.find("CipherKey") != config.end(); } bool CSwordModuleInfo::unlockKeyIsValid() const { m_module->setPosition(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() ); + /* 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. */ + const QString test(isUnicode() + ? QString::fromUtf8(m_module->getRawEntryBuf().c_str()) + : QString::fromLatin1(m_module->getRawEntryBuf().c_str())); - if (test.isEmpty()) { + if (test.isEmpty()) return false; - } - for (int i = 0; i <= test.length() && i < 100; i++) { - if ( !test[i].isPrint() && !test[i].isNull() ) { + for (int i = 0; i < test.length() && i < 100; i++) + if (!test[i].isPrint() && !test[i].isNull()) return false; - } - } - return true; } @@ -188,336 +166,374 @@ QString CSwordModuleInfo::getGlobalBaseIndexLocation() { } QString CSwordModuleInfo::getModuleBaseIndexLocation() const { - return getGlobalBaseIndexLocation() + QString("/") + name().toLocal8Bit(); + return getGlobalBaseIndexLocation() + QString("/") + m_cachedName.toLocal8Bit(); } -QString CSwordModuleInfo::getModuleStandardIndexLocation() const { //this for now returns the location of the main index +QString CSwordModuleInfo::getModuleStandardIndexLocation() const { + // This for now returns the location of the main index return getModuleBaseIndexLocation() + QString("/standard"); } bool CSwordModuleInfo::hasIndex() const { - //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; + { // Is this a directory? + QFileInfo fi(getModuleStandardIndexLocation()); + if (!fi.isDir()) + return false; } - //first check if the index version and module version are ok - QSettings module_config(getModuleBaseIndexLocation() + QString("/bibletime-index.conf"), QSettings::IniFormat); + // Are the index version and module version OK? + QSettings module_config(getModuleBaseIndexLocation() + + QString("/bibletime-index.conf"), + QSettings::IniFormat); - if (hasVersion() && - module_config.value("module-version").toString() != config(CSwordModuleInfo::ModuleVersion)) + if (m_cachedHasVersion + && module_config.value("module-version").toString() + != config(CSwordModuleInfo::ModuleVersion)) { return false; } if (module_config.value("index-version").toUInt() != INDEX_VERSION) { - qDebug("%s: INDEX_VERSION is not compatible with this version of BibleTime.", name().toUtf8().constData()); + qDebug("%s: INDEX_VERSION is not compatible with this version of " + "BibleTime.", + m_cachedName.toUtf8().constData()); return false; } - //then check if the index is there - return lucene::index::IndexReader::indexExists(getModuleStandardIndexLocation().toLatin1().constData()); + // Is the index there? + return lucene::index::IndexReader::indexExists(getModuleStandardIndexLocation() + .toLatin1().constData()); } bool 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. - // turn on these options, they are needed for the EntryAttributes population - backend()->setOption( CSwordModuleInfo::strongNumbers, true ); - backend()->setOption( CSwordModuleInfo::morphTags, true ); - backend()->setOption( CSwordModuleInfo::footnotes, true ); - backend()->setOption( CSwordModuleInfo::headings, true ); - // we don't want the following in the text, the do not carry searchable information - backend()->setOption( CSwordModuleInfo::morphSegmentation, 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(); + // Without this we don't get strongs, lemmas, etc. + m_backend.setFilterOptions(btConfig().getFilterOptions()); + /* Make sure we reset all important filter options which influcence the + plain filters. Turn on these options, they are needed for the + EntryAttributes population */ + m_backend.setOption(CSwordModuleInfo::strongNumbers, true); + m_backend.setOption(CSwordModuleInfo::morphTags, true); + m_backend.setOption(CSwordModuleInfo::footnotes, true); + m_backend.setOption(CSwordModuleInfo::headings, true); + /* We don't want the following in the text, the do not carry searchable + information. */ + m_backend.setOption(CSwordModuleInfo::morphSegmentation, false); + m_backend.setOption(CSwordModuleInfo::scriptureReferences, false); + m_backend.setOption(CSwordModuleInfo::redLetterWords, false); + + // Do not use any stop words: + static const TCHAR * stop_words[1u] = { NULL }; + lucene::analysis::standard::StandardAnalyzer an(static_cast<const TCHAR **>(stop_words)); + const QString index(getModuleStandardIndexLocation()); QDir dir("/"); - dir.mkpath( getGlobalBaseIndexLocation() ); - dir.mkpath( getModuleBaseIndexLocation() ); - dir.mkpath( getModuleStandardIndexLocation() ); + dir.mkpath(getGlobalBaseIndexLocation()); + dir.mkpath(getModuleBaseIndexLocation()); + dir.mkpath(getModuleStandardIndexLocation()); - if (lucene::index::IndexReader::indexExists(index.toLatin1().constData())) { - if (lucene::index::IndexReader::isLocked(index.toLatin1().constData()) ) { + if (lucene::index::IndexReader::indexExists(index.toLatin1().constData())) + if (lucene::index::IndexReader::isLocked(index.toLatin1().constData())) lucene::index::IndexReader::unlock(index.toLatin1().constData()); - } - } - QSharedPointer<lucene::index::IndexWriter> writer( new lucene::index::IndexWriter(index.toLatin1().constData(), &an, true) ); //always create a new index + // Always create a new index: + typedef lucene::index::IndexWriter IW; + QSharedPointer<IW> writer(new IW(index.toLatin1().constData(), &an, true)); writer->setMaxFieldLength(BT_MAX_LUCENE_FIELD_LENGTH); - writer->setUseCompoundFile(true); //merge segments into a single file + writer->setUseCompoundFile(true); // Merge segments into a single file +#ifndef CLUCENE2 + writer->setMinMergeDocs(1000); +#endif m_module->setPosition(sword::TOP); - unsigned long verseLowIndex = m_module->Index(); + unsigned long verseLowIndex = m_module->getIndex(); m_module->setPosition(sword::BOTTOM); - unsigned long verseHighIndex = m_module->Index(); + unsigned long verseHighIndex = m_module->getIndex(); - //verseLowIndex is not 0 in all cases (i.e. NT-only modules) + // 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) { + // Index() is not implemented properly for lexicons, so work around it: + if (m_type == CSwordModuleInfo::Lexicon) { verseIndex = 0; verseLowIndex = 0; - verseSpan = ((CSwordLexiconModuleInfo*)this)->entries().size(); + verseSpan = static_cast<CSwordLexiconModuleInfo *>(this)->entries().size(); } emit indexingProgress(0); - sword::SWKey* key = m_module->getKey(); - //VerseKey for bibles - sword::VerseKey* vk = dynamic_cast<sword::VerseKey*>(key); + sword::SWKey * const key = m_module->getKey(); + sword::VerseKey * const 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 + /* 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); + /* If we have a verse based module, we want to include the pre- + chapter etc. headings in the search. */ + vk->setIntros(true); } - //holds UTF-8 data and is faster than QString. - QByteArray textBuffer; + QByteArray textBuffer; // Holds UTF-8 data and is faster than QString. // 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]; + QScopedPointer<wchar_t, QScopedPointerArrayDeleter<wchar_t> > + sPwcharBuffer(new wchar_t[BT_MAX_LUCENE_FIELD_LENGTH + 1]); + wchar_t * const wcharBuffer = sPwcharBuffer.data(); + Q_ASSERT(wcharBuffer); m_module->setPosition(sword::TOP); - while (!(m_module->Error()) && !m_cancelIndexing) { + while (!(m_module->popError()) && !m_cancelIndexing) { - // Also index Chapter 0 and Verse 0, because they might have information in the entry attributes - // We used to just put their content into the textBuffer and continue to the next verse, but - // with entry attributes this doesn't work any more. - // Hits in the search dialog will show up as 1:1 (instead of 0) + /* Also index Chapter 0 and Verse 0, because they might have + information in the entry attributes. We used to just put their + content into the textBuffer and continue to the next verse, but + with entry attributes this doesn't work any more. Hits in the + search dialog will show up as 1:1 (instead of 0). */ QSharedPointer<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(*(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 + doc->add(*(new lucene::document::Field(static_cast<const TCHAR *>(_T("key")), + static_cast<const TCHAR *>(wcharBuffer), + lucene::document::Field::STORE_YES + | lucene::document::Field::INDEX_NO))); + + /* 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. */ + textBuffer.append(m_module->stripText()); + lucene_utf8towcs(wcharBuffer, + static_cast<const char *>(textBuffer), + BT_MAX_LUCENE_FIELD_LENGTH); + doc->add(*(new lucene::document::Field(static_cast<const TCHAR *>(_T("content")), + static_cast<const TCHAR *>(wcharBuffer), + lucene::document::Field::STORE_NO + | lucene::document::Field::INDEX_TOKENIZED))); + textBuffer.clear(); + + typedef sword::AttributeList::iterator ALI; + typedef sword::AttributeValue::iterator AVI; + + for (ALI it = m_module->getEntryAttributes()["Footnote"].begin(); + it != m_module->getEntryAttributes()["Footnote"].end(); + ++it) + { + lucene_utf8towcs(wcharBuffer, it->second["body"], BT_MAX_LUCENE_FIELD_LENGTH); + doc->add(*(new lucene::document::Field(static_cast<const TCHAR *>(_T("footnote")), + static_cast<const TCHAR *>(wcharBuffer), + lucene::document::Field::STORE_NO + | lucene::document::Field::INDEX_TOKENIZED))); + } // 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 + for (AVI it = m_module->getEntryAttributes()["Heading"]["Preverse"].begin(); + it != m_module->getEntryAttributes()["Heading"]["Preverse"].end(); + ++it) + { + lucene_utf8towcs(wcharBuffer, it->second, BT_MAX_LUCENE_FIELD_LENGTH); + doc->add(*(new lucene::document::Field(static_cast<const TCHAR *>(_T("heading")), + static_cast<const TCHAR *>(wcharBuffer), + lucene::document::Field::STORE_NO + | lucene::document::Field::INDEX_TOKENIZED))); + } // 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()); + for (ALI it = m_module->getEntryAttributes()["Word"].begin(); + it != m_module->getEntryAttributes()["Word"].end(); + ++it) + { + if (it->second["LemmaClass"] == "strong") { + lucene_utf8towcs(wcharBuffer, it->second["Lemma"], BT_MAX_LUCENE_FIELD_LENGTH); + doc->add(*(new lucene::document::Field(static_cast<const TCHAR *>(_T("strong")), + static_cast<const TCHAR *>(wcharBuffer), + lucene::document::Field::STORE_NO + | lucene::document::Field::INDEX_TOKENIZED))); } - 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))); + if (it->second.find("Morph") != it->second.end()) { + lucene_utf8towcs(wcharBuffer, it->second["Morph"], BT_MAX_LUCENE_FIELD_LENGTH); + doc->add(*(new lucene::document::Field(static_cast<const TCHAR *>(_T("morph")), + static_cast<const TCHAR *>(wcharBuffer), + lucene::document::Field::STORE_NO + | lucene::document::Field::INDEX_TOKENIZED))); } - } // for attListI + } writer->addDocument(doc.data()); //Index() is not implemented properly for lexicons, so we use a //workaround. - if (type() == CSwordModuleInfo::Lexicon) { + if (m_type == CSwordModuleInfo::Lexicon) { verseIndex++; - } - else { - verseIndex = m_module->Index(); + } else { + verseIndex = m_module->getIndex(); } if (verseIndex % 200 == 0) { int indexingProgressValue; - if (verseSpan == 0) { //prevent division by zero - //m_indexingProgress.setValue( QVariant(0) ); + if (verseSpan == 0) { // Prevent division by zero indexingProgressValue = 0; - } - else { - //m_indexingProgress.setValue( QVariant((int)((100*(verseIndex-verseLowIndex))/(verseHighIndex-verseLowIndex))) ); + } else { indexingProgressValue = (int)((100 * (verseIndex - verseLowIndex)) / (verseSpan)); } - //m_indexingProgress.activate(); emit indexingProgress(indexingProgressValue); } m_module->increment(); } // while (!(m_module->Error()) && !m_cancelIndexing) - if (!m_cancelIndexing) { + if (!m_cancelIndexing) writer->optimize(); - } writer->close(); if (m_cancelIndexing) { deleteIndex(); m_cancelIndexing = false; - } - else { - QSettings module_config(getModuleBaseIndexLocation() + QString("/bibletime-index.conf"), QSettings::IniFormat); - if (hasVersion()) module_config.setValue("module-version", config(CSwordModuleInfo::ModuleVersion) ); + } else { + QSettings module_config(getModuleBaseIndexLocation() + + QString("/bibletime-index.conf"), + QSettings::IniFormat); + if (m_cachedHasVersion) + module_config.setValue("module-version", + config(CSwordModuleInfo::ModuleVersion)); module_config.setValue("index-version", INDEX_VERSION); emit hasIndexChanged(true); } - } - catch (CLuceneError &e) { + } catch (CLuceneError & e) { qWarning() << "CLucene exception occurred while indexing:" << e.what(); - util::showWarning(0, QCoreApplication::tr("Indexing aborted"), QCoreApplication::tr("An internal error occurred while building the index: %1").arg(e.what())); + message::showWarning(0, + QCoreApplication::tr("Indexing aborted"), + QCoreApplication::tr("An internal error occurred " + "while building the index: %1") + .arg(e.what())); deleteIndex(); m_cancelIndexing = false; return false; - } - catch (...) { + } catch (...) { qWarning("CLucene exception occurred while indexing"); - util::showWarning(0, QCoreApplication::tr("Indexing aborted"), QCoreApplication::tr("An internal error occurred while building the index.")); + message::showWarning(0, + QCoreApplication::tr("Indexing aborted"), + QCoreApplication::tr("An internal error occurred " + "while building the index.")); deleteIndex(); m_cancelIndexing = false; return false; } - return true; } void CSwordModuleInfo::deleteIndex() { - deleteIndexForModule(name()); + deleteIndexForModule(m_cachedName); emit hasIndexChanged(false); } -void CSwordModuleInfo::deleteIndexForModule(const QString &name) { - util::directory::removeRecursive( getGlobalBaseIndexLocation() + "/" + name ); +void CSwordModuleInfo::deleteIndexForModule(const QString & name) { + util::directory::removeRecursive(getGlobalBaseIndexLocation() + "/" + name); } unsigned long CSwordModuleInfo::indexSize() const { namespace DU = util::directory; - return DU::getDirSizeRecursive( getModuleBaseIndexLocation() ); + return DU::getDirSizeRecursive(getModuleBaseIndexLocation()); } - -int CSwordModuleInfo::searchIndexed(const QString &searchedText, - const sword::ListKey &scope, - sword::ListKey &results) const +int CSwordModuleInfo::searchIndexed(const QString & searchedText, + const sword::ListKey & scope, + sword::ListKey & results) const { - char utfBuffer[BT_MAX_LUCENE_FIELD_LENGTH + 1]; - wchar_t wcharBuffer[BT_MAX_LUCENE_FIELD_LENGTH + 1]; + QScopedPointer<char, QScopedPointerArrayDeleter<char> > + sPutfBuffer(new char[BT_MAX_LUCENE_FIELD_LENGTH + 1]); + QScopedPointer<wchar_t, QScopedPointerArrayDeleter<wchar_t> > + sPwcharBuffer(new wchar_t[BT_MAX_LUCENE_FIELD_LENGTH + 1]); + char * const utfBuffer = sPutfBuffer.data(); + Q_ASSERT(utfBuffer); + wchar_t * const wcharBuffer = sPwcharBuffer.data(); + Q_ASSERT(wcharBuffer); // work around Swords thread insafety for Bibles and Commentaries - QSharedPointer < CSwordKey > key(CSwordKey::createInstance(this)); - sword::SWKey* s = dynamic_cast < sword::SWKey * >(key.data()); - QList<sword::VerseKey*> list; - - if (s) { - m_module->setKey(*s); + QSharedPointer<CSwordKey> key(CSwordKey::createInstance(this)); + { + const sword::SWKey * const s = dynamic_cast<sword::SWKey *>(key.data()); + if (s) + m_module->setKey(*s); } + QList<sword::VerseKey *> list; results.clear(); try { // do not use any stop words - const TCHAR* stop_words[] = { NULL }; - lucene::analysis::standard::StandardAnalyzer analyzer( stop_words ); + static const TCHAR * stop_words[1u] = { NULL }; + lucene::analysis::standard::StandardAnalyzer analyzer(stop_words); lucene::search::IndexSearcher searcher(getModuleStandardIndexLocation().toLatin1().constData()); lucene_utf8towcs(wcharBuffer, searchedText.toUtf8().constData(), BT_MAX_LUCENE_FIELD_LENGTH); - QSharedPointer<lucene::search::Query> q( lucene::queryParser::QueryParser::parse((const TCHAR*)wcharBuffer, (const TCHAR*)_T("content"), &analyzer) ); - -#ifdef CLUCENE2 - QSharedPointer<lucene::search::Hits> h( searcher.search(q.data(), lucene::search::Sort::INDEXORDER()) ); -#else - QSharedPointer<lucene::search::Hits> h( searcher.search(q.data(), lucene::search::Sort::INDEXORDER) ); -#endif + QSharedPointer<lucene::search::Query> q(lucene::queryParser::QueryParser::parse(static_cast<const TCHAR *>(wcharBuffer), + static_cast<const TCHAR *>(_T("content")), + &analyzer)); - /// \warning This is a workaround for Sword constness - const bool useScope = (const_cast<sword::ListKey&>(scope).Count() > 0); -// const bool isVerseModule = (type() == CSwordModuleInfo::Bible) || (type() == CSwordModuleInfo::Commentary); + QSharedPointer<lucene::search::Hits> h(searcher.search(q.data(), + #ifdef CLUCENE2 + lucene::search::Sort::INDEXORDER())); + #else + lucene::search::Sort::INDEXORDER)); + #endif - lucene::document::Document* doc = 0; - QSharedPointer<sword::SWKey> swKey( module()->CreateKey() ); + const bool useScope = (scope.getCount() > 0); + lucene::document::Document * doc = 0; + QSharedPointer<sword::SWKey> swKey(m_module->createKey()); #ifdef CLUCENE2 for (unsigned int i = 0; i < h->length(); ++i) { #else - for (int i = 0; i < h->length(); ++i) { + for (int i = 0; i < h->length(); ++i) { #endif doc = &h->doc(i); - lucene_wcstoutf8(utfBuffer, (const wchar_t*)doc->get((const TCHAR*)_T("key")), BT_MAX_LUCENE_FIELD_LENGTH); + lucene_wcstoutf8(utfBuffer, + static_cast<const wchar_t *>(doc->get(static_cast<const TCHAR *>(_T("key")))), + BT_MAX_LUCENE_FIELD_LENGTH); swKey->setText(utfBuffer); - // limit results based on scope - //if (searchOptions & CSwordModuleSearch::useScope && scope.Count() > 0){ + // Limit results based on scope: if (useScope) { - /// \warning This is a workaround for sword constness - for (int j = 0; j < const_cast<sword::ListKey&>(scope).Count(); j++) { - /// \warning This is a workaround for sword constness - sword::ListKey &scope2 = const_cast<sword::ListKey&>(scope); - sword::VerseKey* vkey = dynamic_cast<sword::VerseKey*>(scope2.getElement(j)); - if (vkey->LowerBound().compare(*swKey) <= 0 && vkey->UpperBound().compare(*swKey) >= 0) { + for (int j = 0; j < scope.getCount(); j++) { + Q_ASSERT(dynamic_cast<const sword::VerseKey *>(scope.getElement(j))); + const sword::VerseKey * const vkey = static_cast<const sword::VerseKey *>(scope.getElement(j)); + if (vkey->getLowerBound().compare(*swKey) <= 0 + && vkey->getUpperBound().compare(*swKey) >= 0) + { results.add(*swKey); } } - } - else { // no scope, give me all buffers - results.add(*swKey); + } else { + results.add(*swKey); // No scope, give me all buffers } } - } - catch (...) { + } catch (...) { qWarning("CLucene exception occurred"); - util::showWarning(0, QCoreApplication::tr("Search aborted"), QCoreApplication::tr("An internal error occurred while executing your search.")); + message::showWarning(0, + QCoreApplication::tr("Search aborted"), + QCoreApplication::tr("An internal error occurred " + "while executing your search.")); return 0; } qDeleteAll(list); list.clear(); - return results.Count(); + return results.getCount(); } sword::SWVersion CSwordModuleInfo::minimumSwordVersion() const { - return sword::SWVersion(config(CSwordModuleInfo::MinimumSwordVersion).toUtf8().constData()); + return sword::SWVersion(config(CSwordModuleInfo::MinimumSwordVersion) + .toUtf8().constData()); } QString CSwordModuleInfo::config(const CSwordModuleInfo::ConfigEntry entry) const { @@ -527,37 +543,32 @@ QString CSwordModuleInfo::config(const CSwordModuleInfo::ConfigEntry entry) cons return getFormattedConfigEntry("About"); case CipherKey: { - if (CBTConfig::getModuleEncryptionKey(name()).isNull()) { //fall back! - return QString(m_module->getConfigEntry("CipherKey")); - } - else { - return CBTConfig::getModuleEncryptionKey(name()); + if (btConfig().getModuleEncryptionKey(m_cachedName).isNull()) { + return QString(m_module->getConfigEntry("CipherKey")); // Fallback + } else { + return btConfig().getModuleEncryptionKey(m_cachedName); } } 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) != "/") { + QString path(getSimpleConfigEntry("AbsoluteDataPath")); + if (!path.endsWith('/')) /// \todo is this needed? path.append('/'); - } return path; } - case DataPath: { //make sure we remove the dataFile part if it's a Lexicon + case DataPath: { 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 - } + // Make sure we remove the dataFile part if it's a Lexicon + if (m_type == CSwordModuleInfo::GenericBook + || m_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; } @@ -565,84 +576,76 @@ QString CSwordModuleInfo::config(const CSwordModuleInfo::ConfigEntry entry) cons return getFormattedConfigEntry("Description"); case ModuleVersion: { - QString version(getSimpleConfigEntry("Version")); - - if (version.isEmpty()) { - version = "1.0"; - } - - return version; + const QString version(getSimpleConfigEntry("Version")); + return version.isEmpty() ? "1.0" : version; } case MinimumSwordVersion: { const QString minimumVersion(getSimpleConfigEntry("MinimumVersion")); - return !minimumVersion.isEmpty() ? minimumVersion : QString("0.0"); + return minimumVersion.isEmpty() ? "0.0" : minimumVersion; } case TextDir: { const QString dir(getSimpleConfigEntry("Direction")); - return !dir.isEmpty() ? dir : QString("LtoR"); + return dir.isEmpty() ? QString("LtoR") : dir; } case DisplayLevel: { const QString level(getSimpleConfigEntry("DisplayLevel")); - return !level.isEmpty() ? level : QString("1"); + return level.isEmpty() ? QString("1") : level; } case GlossaryFrom: { - if (category() != Glossary) { + if (m_cachedCategory != Glossary) return QString::null; - }; const QString lang(getSimpleConfigEntry("GlossaryFrom")); - - return !lang.isEmpty() ? lang : QString::null; + return lang.isEmpty() ? QString::null : lang; } case GlossaryTo: { - if (category() != Glossary) { + if (m_cachedCategory != Glossary) { return QString::null; }; const QString lang(getSimpleConfigEntry("GlossaryTo")); - - return !lang.isEmpty() ? lang : QString::null; + return lang.isEmpty() ? QString::null : lang; } case Markup: { const QString markup(getSimpleConfigEntry("SourceType")); - return !markup.isEmpty() ? markup : QString("Unknown"); + return markup.isEmpty() ? QString("Unknown") : markup; } case DistributionLicense: - return getSimpleConfigEntry("DistributionLicense"); + return getFormattedConfigEntry("DistributionLicense"); case DistributionSource: - return getSimpleConfigEntry("DistributionSource"); + return getFormattedConfigEntry("DistributionSource"); case DistributionNotes: - return getSimpleConfigEntry("DistributionNotes"); + return getFormattedConfigEntry("DistributionNotes"); case TextSource: - return getSimpleConfigEntry("TextSource"); + return getFormattedConfigEntry("TextSource"); case CopyrightNotes: - return getSimpleConfigEntry("CopyrightNotes"); + return getFormattedConfigEntry("CopyrightNotes"); case CopyrightHolder: - return getSimpleConfigEntry("CopyrightHolder"); + return getFormattedConfigEntry("CopyrightHolder"); case CopyrightDate: - return getSimpleConfigEntry("CopyrightDate"); + return getFormattedConfigEntry("CopyrightDate"); case CopyrightContactName: - return getSimpleConfigEntry("CopyrightContactName"); + return getFormattedConfigEntry("CopyrightContactName"); case CopyrightContactAddress: - return getSimpleConfigEntry("CopyrightContactAddress"); + return getFormattedConfigEntry("CopyrightContactAddress"); case CopyrightContactEmail: - return getSimpleConfigEntry("CopyrightContactEmail"); + return getFormattedConfigEntry("CopyrightContactEmail"); default: return QString::null; @@ -651,75 +654,54 @@ QString CSwordModuleInfo::config(const CSwordModuleInfo::ConfigEntry entry) cons 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"); + 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; + /// \todo This is a BAD workaround to see if the filter is GBF, OSIS or ThML! + const QString name = m_backend.configOptionName(option); + return m_module->getConfig().has("GlobalOptionFilter", + QString("OSIS").append(name).toUtf8().constData()) + || m_module->getConfig().has("GlobalOptionFilter", + QString("GBF").append(name).toUtf8().constData()) + || m_module->getConfig().has("GlobalOptionFilter", + QString("ThML").append(name).toUtf8().constData()) + || m_module->getConfig().has("GlobalOptionFilter", + QString("UTF8").append(name).toUtf8().constData()) + || m_module->getConfig().has("GlobalOptionFilter", + name.toUtf8().constData()); } CSwordModuleInfo::TextDirection CSwordModuleInfo::textDirection() const { - if (config(TextDir) == "RtoL") - return CSwordModuleInfo::RightToLeft; - - return CSwordModuleInfo::LeftToRight; + return (config(TextDir) == "RtoL") + ? CSwordModuleInfo::RightToLeft + : CSwordModuleInfo::LeftToRight; } -void CSwordModuleInfo::write(CSwordKey *key, const QString &newText) { - module()->setKey(key->key().toUtf8().constData()); +void CSwordModuleInfo::write(CSwordKey * key, const QString & newText) { + m_module->setKey(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()); + /* Don't store a pointer to the const char* value somewhere because QCString + doesn't keep the value of it. */ + m_module->setEntry(isUnicode() + ? newText.toUtf8().constData() + : newText.toLocal8Bit().constData()); } bool CSwordModuleInfo::deleteEntry(CSwordKey * const key) { - module()->setKey(isUnicode() ? key->key().toUtf8().constData() : key->key().toLocal8Bit().constData()); + m_module->setKey(isUnicode() + ? key->key().toUtf8().constData() + : key->key().toLocal8Bit().constData()); - if (module()) { - module()->deleteEntry(); + if (m_module) { + m_module->deleteEntry(); return true; } - return false; } @@ -727,7 +709,7 @@ void CSwordModuleInfo::initCachedCategory() { /// \todo Maybe we can use raw string comparsion instead of QString? const QString cat(m_module->getConfigEntry("Category")); - /// \warning cat has to be checked before type() !!! + /// \warning cat has to be checked before m_type !!! if (cat == "Cults / Unorthodox / Questionable Material") { m_cachedCategory = Cult; } else if (cat == "Daily Devotional" @@ -741,7 +723,7 @@ void CSwordModuleInfo::initCachedCategory() { } else if (cat == "Images" || cat == "Maps") { m_cachedCategory = Images; } else { - switch (type()) { + switch (m_type) { case Bible: m_cachedCategory = Bibles; break; case Commentary: m_cachedCategory = Commentaries; break; case Lexicon: m_cachedCategory = Lexicons; break; @@ -753,15 +735,15 @@ void CSwordModuleInfo::initCachedCategory() { } void CSwordModuleInfo::initCachedLanguage() { - CLanguageMgr *lm = CLanguageMgr::instance(); - if (category() == Glossary) { + const CLanguageMgr & lm = *CLanguageMgr::instance(); + if (m_cachedCategory == Glossary) { /* Special handling for glossaries, we use the "from language" as language for the module. */ - m_cachedLanguage = lm->languageForAbbrev(config(GlossaryFrom)); + m_cachedLanguage = lm.languageForAbbrev(config(GlossaryFrom)); } else { - m_cachedLanguage = lm->languageForAbbrev(m_module->Lang()); + m_cachedLanguage = lm.languageForAbbrev(m_module->getLanguage()); } } @@ -770,74 +752,87 @@ Rendering::CEntryDisplay * CSwordModuleInfo::getDisplay() const { } QString CSwordModuleInfo::aboutText() const { + using util::htmlEscape; + + static const QString row("<tr><td><b>%1</b></td><td>%2</td></tr>"); + QString text; text += "<table>"; - text += QString("<tr><td><b>%1</b></td><td>%2</td><tr>") + text += row .arg(tr("Version")) - .arg(hasVersion() ? config(CSwordModuleInfo::ModuleVersion) : tr("unknown")); + .arg(m_cachedHasVersion + ? htmlEscape(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")); + { + const QString sourceType(m_module->getConfigEntry("SourceType")); + text += row + .arg(tr("Markup")) + .arg(!sourceType.isEmpty() + ? htmlEscape(sourceType) + : tr("unknown")); + } - text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>") + text += row .arg(tr("Location")) - .arg(config(CSwordModuleInfo::AbsoluteDataPath)); + .arg(htmlEscape(config(CSwordModuleInfo::AbsoluteDataPath))); - text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>") + text += row .arg(tr("Language")) - .arg(language()->translatedName()); + .arg(htmlEscape(m_cachedLanguage->translatedName())); if (m_module->getConfigEntry("Category")) - text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>") + text += row .arg(tr("Category")) - .arg(m_module->getConfigEntry("Category")); + .arg(htmlEscape(m_module->getConfigEntry("Category"))); if (m_module->getConfigEntry("LCSH")) - text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>") + text += row .arg(tr("LCSH")) - .arg(m_module->getConfigEntry("LCSH")); + .arg(htmlEscape(m_module->getConfigEntry("LCSH"))); - text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>") + text += row .arg(tr("Writable")) .arg(isWritable() ? tr("yes") : tr("no")); if (isEncrypted()) - text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>") + text += row .arg(tr("Unlock key")) - .arg(config(CSwordModuleInfo::CipherKey)); + .arg(htmlEscape(config(CSwordModuleInfo::CipherKey))); QString options; unsigned int opts; - for (opts = CSwordModuleInfo::filterTypesMIN; opts <= CSwordModuleInfo::filterTypesMAX; ++opts) { + for (opts = CSwordModuleInfo::filterTypesMIN; + opts <= CSwordModuleInfo::filterTypesMAX; + ++opts) + { if (has(static_cast < CSwordModuleInfo::FilterTypes > (opts))) { - if (!options.isEmpty()) { + if (!options.isEmpty()) options += QString::fromLatin1(", "); - } - - options += CSwordBackend::translatedOptionName(static_cast < CSwordModuleInfo::FilterTypes > (opts)); + typedef CSwordModuleInfo::FilterTypes FT; + options += CSwordBackend::translatedOptionName(static_cast<FT>(opts)); } } - if (!options.isEmpty()) { - text += QString("<tr><td><b>%1</b></td><td>%2</td></tr>") + if (!options.isEmpty()) + text += row .arg(tr("Features")) - .arg(options); - } + .arg(htmlEscape(options)); text += "</table><hr>"; - if (category() == Cult) //clearly say the module contains cult/questionable materials + // Clearly say the module contains cult/questionable materials + if (m_cachedCategory == Cult) text += QString("<br/><b>%1</b><br/><br/>") - .arg(tr("Take care, this work contains cult / questionable material!")); + .arg(tr("Take care, this work contains cult / questionable " + "material!")); text += QString("<b>%1:</b><br/>%2</font>") .arg(tr("About")) - .arg(config(AboutInformation)); + .arg(config(AboutInformation)); // May contain HTML, don't escape typedef QList<CSwordModuleInfo::ConfigEntry> ListConfigEntry; @@ -871,61 +866,47 @@ QString CSwordModuleInfo::aboutText() const { 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)); - } - - } + for (ListConfigEntry::iterator it(entries.begin()); it != entries.end(); ++it) + if (!config(*it).isEmpty()) + text += row + .arg(htmlEscape(entryMap[*it])) + .arg(htmlEscape(config(*it))); text += "</table></font>"; return text; } -QIcon CSwordModuleInfo::moduleIcon(const CSwordModuleInfo *module) { - const QString &filename = moduleIconFilename(module); - if (filename.isEmpty()) return QIcon(); - return util::directory::getIcon(filename); +QIcon CSwordModuleInfo::moduleIcon(const CSwordModuleInfo & module) { + const QString & filename = moduleIconFilename(module); + if (filename.isEmpty()) + return QIcon(); + return util::getIcon(filename); } -const QString &CSwordModuleInfo::moduleIconFilename( - const CSwordModuleInfo *module) -{ - const CSwordModuleInfo::Category cat(module->category()); +const QString & CSwordModuleInfo::moduleIconFilename(const CSwordModuleInfo & module) { + const CSwordModuleInfo::Category cat(module.m_cachedCategory); switch (cat) { case CSwordModuleInfo::Bibles: - if (module->isLocked()) { - return CResMgr::modules::bible::icon_locked; - } - else { - return CResMgr::modules::bible::icon_unlocked; - } + return module.isLocked() + ? CResMgr::modules::bible::icon_locked + : CResMgr::modules::bible::icon_unlocked; + case CSwordModuleInfo::Commentaries: - if (module->isLocked()) { - return CResMgr::modules::commentary::icon_locked; - } - else { - return CResMgr::modules::commentary::icon_unlocked; - } + return module.isLocked() + ? CResMgr::modules::commentary::icon_locked + : CResMgr::modules::commentary::icon_unlocked; + case CSwordModuleInfo::Lexicons: - if (module->isLocked()) { - return CResMgr::modules::lexicon::icon_locked; - } - else { - return CResMgr::modules::lexicon::icon_unlocked; - } + return module.isLocked() + ? CResMgr::modules::lexicon::icon_locked + : CResMgr::modules::lexicon::icon_unlocked; + case CSwordModuleInfo::Books: - if (module->isLocked()) { - return CResMgr::modules::book::icon_locked; - } - else { - return CResMgr::modules::book::icon_unlocked; - } + return module.isLocked() + ? CResMgr::modules::book::icon_locked + : CResMgr::modules::book::icon_unlocked; + case CSwordModuleInfo::Cult: case CSwordModuleInfo::Images: case CSwordModuleInfo::DailyDevotional: @@ -936,16 +917,14 @@ const QString &CSwordModuleInfo::moduleIconFilename( } } -QIcon CSwordModuleInfo::categoryIcon(const CSwordModuleInfo::Category &category) -{ - QString filename = categoryIconFilename(category); - if (filename.isEmpty()) return QIcon(); - return util::directory::getIcon(filename); +QIcon CSwordModuleInfo::categoryIcon(const CSwordModuleInfo::Category & category) { + const QString filename(categoryIconFilename(category)); + if (filename.isEmpty()) + return QIcon(); + return util::getIcon(filename); } -const QString &CSwordModuleInfo::categoryIconFilename( - const CSwordModuleInfo::Category &category) -{ +const QString & CSwordModuleInfo::categoryIconFilename(const CSwordModuleInfo::Category & category) { static const QString noFilename; switch (category) { @@ -971,8 +950,7 @@ const QString &CSwordModuleInfo::categoryIconFilename( } } -QString CSwordModuleInfo::categoryName( - const CSwordModuleInfo::Category &category) { +QString CSwordModuleInfo::categoryName(const CSwordModuleInfo::Category & category) { switch (category) { case CSwordModuleInfo::Bibles: return tr("Bibles"); @@ -995,7 +973,7 @@ QString CSwordModuleInfo::categoryName( } } -QString CSwordModuleInfo::getSimpleConfigEntry(const QString& name) const { +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())); @@ -1003,32 +981,38 @@ QString CSwordModuleInfo::getSimpleConfigEntry(const QString& name) const { 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; +/// \note See http://www.crosswire.org/wiki/DevTools:conf_Files#Localization +QString CSwordModuleInfo::getFormattedConfigEntry(const QString & name) const { + const QStringList localeNames(QLocale(CSwordBackend::instance()->booknameLanguage()).uiLanguages()); + for (int i = localeNames.size() - 1; i >= -1; --i) { + sword::SWBuf RTF_Buffer = + m_module->getConfigEntry( + QString(i >= 0 ? name + "_" + localeNames[i] : name) + .toUtf8().constData()); + if (RTF_Buffer.length() > 0) { + sword::RTFHTML RTF_Filter; + RTF_Filter.processText(RTF_Buffer, 0, 0); + return isUnicode() + ? QString::fromUtf8(RTF_Buffer.c_str()) + : QString::fromLatin1(RTF_Buffer.c_str()); + } + } + return QString::null; } bool CSwordModuleInfo::setHidden(bool hide) { - if (m_hidden == hide) return false; + if (m_hidden == hide) + return false; m_hidden = hide; - QStringList hiddenModules(CBTConfig::get(CBTConfig::hiddenModules)); + QStringList hiddenModules(btConfig().value<QStringList>("state/hiddenModules")); + Q_ASSERT(hiddenModules.contains(m_cachedName) != hide); if (hide) { - Q_ASSERT(!hiddenModules.contains(name())); - hiddenModules.append(name()); - } - else { - Q_ASSERT(hiddenModules.contains(name())); - hiddenModules.removeOne(name()); + hiddenModules.append(m_cachedName); + } else { + hiddenModules.removeOne(m_cachedName); } - CBTConfig::set(CBTConfig::hiddenModules, hiddenModules); + btConfig().setValue("state/hiddenModules", hiddenModules); emit hiddenChanged(hide); return true; } - diff --git a/src/backend/drivers/cswordmoduleinfo.h b/src/backend/drivers/cswordmoduleinfo.h index 3c59f9d..c1b6c88 100644 --- a/src/backend/drivers/cswordmoduleinfo.h +++ b/src/backend/drivers/cswordmoduleinfo.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -12,6 +14,7 @@ #include "backend/managers/clanguagemgr.h" +#include <QIcon> #include <QList> #include <QMetaType> #include <QString> @@ -47,403 +50,418 @@ class CEntryDisplay; */ 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 = 0x0, /**< Unknown or unset category. */ - NoCategory = 0x0, - Bibles = 0x01, - Commentaries = 0x02, - Books = 0x04, - Lexicons = 0x08, - Glossary = 0x10, - DailyDevotional = 0x20, - Images = 0x40, - Cult = 0x80, /**< Cult / sect / questionable module. */ - AllCategories = 0xff - }; - Q_DECLARE_FLAGS(Categories, Category) - - /** - * Returns the base directory for search indices - */ - static QString getGlobalBaseIndexLocation(); - - /** - Removes the search index for this module (rm -rf). - */ - void deleteIndex(); - - /** - Removes search index for a module, even if the module is not there any more. - \param[in] name name of the module. - */ - static void deleteIndexForModule(const 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, - ModuleType type = Unknown); - - CSwordModuleInfo(const CSwordModuleInfo ©); - - /** - * Returns the module object so all objects can access the original Sword module. - */ - inline sword::SWModule *module() const { - return m_module; - } - - /** - * Sets the unlock key of the modules and writes the key into the config file. - * @return True if the unlock process was succesful, if the key was + + Q_OBJECT + +public: /* Methods: */ + + /** + * 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 = 0x0, /**< Unknown or unset category. */ + NoCategory = 0x0, + Bibles = 0x01, + Commentaries = 0x02, + Books = 0x04, + Lexicons = 0x08, + Glossary = 0x10, + DailyDevotional = 0x20, + Images = 0x40, + Cult = 0x80, /**< Cult / sect / questionable module. */ + AllCategories = 0xff + }; + Q_DECLARE_FLAGS(Categories, Category) + + /** + * Returns the base directory for search indices + */ + static QString getGlobalBaseIndexLocation(); + + /** + Removes the search index for this module (rm -rf). + */ + void deleteIndex(); + + /** + Removes search index for a module, even if the module is not there any more. + \param[in] name name of the module. + */ + static void deleteIndexForModule(const QString & name); + + /** + * Returns the config entry which is pecified by the parameter. + */ + QString config(const CSwordModuleInfo::ConfigEntry entry) const; + + /** + * Returns the module object so all objects can access the original Sword module. + */ + inline sword::SWModule * module() const { + return m_module; + } + + /** + * Sets the unlock key of the modules and writes the key into the config 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() const; - - - /** - 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 unlockKeyIsValid() const; - - /** - \retval true if this module has a version number - \retval false if it doesn't have a version number - */ - inline bool hasVersion() const { - return m_cachedHasVersion; - } - - /** - \returns true if the module's index has been built. - */ - bool hasIndex() const; - - /** - \returns the path to this module's index base dir - */ - QString getModuleBaseIndexLocation() const; - - /** - \returns the path to this module's standard index - */ - QString getModuleStandardIndexLocation() const; - - /** - Builds a search index for this module - \returns Whether indexing this module was successful. - */ - bool buildIndex(); - - /** - \returns index size - */ - unsigned long indexSize() const; - - /** - This function uses CLucene to perform and index based search. It also - overwrites the variable containing the last search result. - \returns the number of results found - */ - int searchIndexed(const QString &searchedText, - const sword::ListKey &scope, - sword::ListKey &results) const; - - /** - \returns the type of the module. - */ - inline ModuleType type() const { - return m_type; - } - - /** - * Returns the required Sword version for this module. - * Returns -1 if no special Sword version is required. - */ - sword::SWVersion minimumSwordVersion() const; - - /** - \note The Sword library takes care of the duplicate names: _n is added - after each duplicate. - \returns The name of this module. - */ - inline const QString &name() const { - return m_cachedName; - } - - /** - * Snaps to the closest entry in the module if the current key is - * not present in the data files. - */ - virtual inline bool snap() const { - return false; - } - - /** - \returns whether the module supports the feature given as parameter. - */ - bool has(const CSwordModuleInfo::Feature) const; - - bool has(const CSwordModuleInfo::FilterTypes ) const; - - /** - \returns the text direction of the module's text. - */ - CSwordModuleInfo::TextDirection textDirection() const; - - /** - Writes the new text at the given position into the module. This does - only work for writabe modules. - */ - 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. - */ - inline const CLanguageMgr::Language *language() const { - return m_cachedLanguage; - } - - /** - \returns whether this module may be written to. - */ - inline virtual bool isWritable() const { - return false; - } - - /** - * Returns true if this module is hidden (not to be shown with other modules in certain views). - */ - inline bool isHidden() const { - return m_hidden; - } - - /** - Shows or hides the module. - \param hide Whether the module should be hidden. - \returns whether the hidden state was changed. - */ - bool setHidden(bool hide); - - /** - \returns the category of this module. - */ - inline CSwordModuleInfo::Category category() const { - return m_cachedCategory; - } - - /** - * 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_module->isUnicode(); - } - - /** - Returns an icon for the given module. - \param[in] module The module whose icon to return. - */ - static QIcon moduleIcon(const CSwordModuleInfo *module); - - /** - Returns the icon filename for the given module. - \param[in] module The module whose icon filename to return. - */ - static const QString &moduleIconFilename(const CSwordModuleInfo *module); - - /** - Returns an icon for the category of given module. - \param[in] module The module whose category icon to return. - */ - static QIcon categoryIcon(const CSwordModuleInfo::Category &category); - - /** - Returns the icon filename for the category of given module. - \param[in] module The module whose category icon filename to return. - */ - static const QString &categoryIconFilename(const CSwordModuleInfo::Category &category); - - /** - Returns a translated name for the given category. - \param[in] module The category whose translated name to return. - */ - static QString categoryName(const CSwordModuleInfo::Category &category); - - public slots: - inline void cancelIndexing() { - m_cancelIndexing = true; - } - - protected: - - 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; - - private: /* Methods: */ - /** - Initializes CSwordModuleInfo::m_cachedCategory. - \pre m_module must be set - */ - void initCachedCategory(); - - /** - Initializes CSwordModuleInfo::m_cachedLanguage. - \pre CSwordModuleInfo::m_module must be set - \pre CSwordModuleInfo::m_cachedLanguage must be set - */ - void initCachedLanguage(); - - signals: - void hasIndexChanged(bool hasIndex); - void hiddenChanged(bool hidden); - void unlockedChanged(bool unlocked); - void indexingFinished(); - void indexingProgress(int); - - private: - sword::SWModule * const m_module; - CSwordBackend *m_backend; - ModuleType m_type; - bool m_hidden; - bool m_cancelIndexing; - - // Cached data: - const QString m_cachedName; - CSwordModuleInfo::Category m_cachedCategory; - const CLanguageMgr::Language *m_cachedLanguage; - bool m_cachedHasVersion; + */ + 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() const; + + /** + 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 unlockKeyIsValid() const; + + /** + \retval true if this module has a version number + \retval false if it doesn't have a version number + */ + inline bool hasVersion() const { + return m_cachedHasVersion; + } + + /** + \returns true if the module's index has been built. + */ + bool hasIndex() const; + + /** + \returns the path to this module's index base dir + */ + QString getModuleBaseIndexLocation() const; + + /** + \returns the path to this module's standard index + */ + QString getModuleStandardIndexLocation() const; + + /** + Builds a search index for this module + \returns Whether indexing this module was successful. + */ + bool buildIndex(); + + /** + \returns index size + */ + unsigned long indexSize() const; + + /** + This function uses CLucene to perform and index based search. It also + overwrites the variable containing the last search result. + \returns the number of results found + */ + int searchIndexed(const QString & searchedText, + const sword::ListKey & scope, + sword::ListKey & results) const; + + /** + \returns the type of the module. + */ + inline ModuleType type() const { + return m_type; + } + + /** + * Returns the required Sword version for this module. + * Returns -1 if no special Sword version is required. + */ + sword::SWVersion minimumSwordVersion() const; + + /** + \note The Sword library takes care of the duplicate names: _n is added + after each duplicate. + \returns The name of this module. + */ + inline const QString & name() const { + return m_cachedName; + } + + /** + * Snaps to the closest entry in the module if the current key is + * not present in the data files. + */ + virtual inline bool snap() const { + return false; + } + + /** + \returns whether the module supports the feature given as parameter. + */ + bool has(const CSwordModuleInfo::Feature) const; + + bool has(const CSwordModuleInfo::FilterTypes ) const; + + /** + \returns the text direction of the module's text. + */ + CSwordModuleInfo::TextDirection textDirection() const; + + /** + Writes the new text at the given position into the module. This does + only work for writabe modules. + */ + 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. + */ + inline const CLanguageMgr::Language * language() const { + return m_cachedLanguage; + } + + /** + \returns whether this module may be written to. + */ + inline virtual bool isWritable() const { + return false; + } + + /** + * Returns true if this module is hidden (not to be shown with other modules in certain views). + */ + inline bool isHidden() const { + return m_hidden; + } + + /** + Shows or hides the module. + \param hide Whether the module should be hidden. + \returns whether the hidden state was changed. + */ + bool setHidden(bool hide); + + /** + \returns the category of this module. + */ + inline CSwordModuleInfo::Category category() const { + return m_cachedCategory; + } + + /** + * 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_module->isUnicode(); + } + + /** + Returns an icon for this module. + */ + inline QIcon moduleIcon() const { + return CSwordModuleInfo::moduleIcon(*this); + } + + /** + Returns an icon for the given module. + \param[in] module The module whose icon to return. + */ + static QIcon moduleIcon(const CSwordModuleInfo & module); + + /** + Returns the icon filename for the given module. + \param[in] module The module whose icon filename to return. + */ + static const QString & moduleIconFilename(const CSwordModuleInfo & module); + + /** + Returns an icon for the category of given module. + \param[in] module The module whose category icon to return. + */ + static QIcon categoryIcon(const CSwordModuleInfo::Category & category); + + /** + Returns the icon filename for the category of given module. + \param[in] module The module whose category icon filename to return. + */ + static const QString & categoryIconFilename(const CSwordModuleInfo::Category & category); + + /** + Returns a translated name for the given category. + \param[in] module The category whose translated name to return. + */ + static QString categoryName(const CSwordModuleInfo::Category & category); + +public slots: + + inline void cancelIndexing() { + m_cancelIndexing = true; + } + +protected: /* Methods: */ + + CSwordModuleInfo(sword::SWModule * module, + CSwordBackend & backend, + ModuleType type); + + CSwordModuleInfo(const CSwordModuleInfo & copy); + + inline CSwordBackend & backend() const { + return m_backend; + } + + QString getSimpleConfigEntry(const QString & name) const; + QString getFormattedConfigEntry(const QString & name) const; + +private: /* Methods: */ + + /** + Initializes CSwordModuleInfo::m_cachedCategory. + \pre m_module must be set + */ + void initCachedCategory(); + + /** + Initializes CSwordModuleInfo::m_cachedLanguage. + \pre CSwordModuleInfo::m_module must be set + \pre CSwordModuleInfo::m_cachedLanguage must be set + */ + void initCachedLanguage(); + +signals: + + void hasIndexChanged(bool hasIndex); + void hiddenChanged(bool hidden); + void unlockedChanged(bool unlocked); + void indexingFinished(); + void indexingProgress(int); + +private: /* Fields: */ + + sword::SWModule * const m_module; + CSwordBackend & m_backend; + ModuleType m_type; + bool m_hidden; + bool m_cancelIndexing; + + // Cached data: + const QString m_cachedName; + CSwordModuleInfo::Category m_cachedCategory; + const CLanguageMgr::Language * m_cachedLanguage; + bool m_cachedHasVersion; + }; Q_DECLARE_METATYPE(CSwordModuleInfo::Category); diff --git a/src/backend/filters/btosismorphsegmentation.cpp b/src/backend/filters/btosismorphsegmentation.cpp new file mode 100644 index 0000000..1675476 --- /dev/null +++ b/src/backend/filters/btosismorphsegmentation.cpp @@ -0,0 +1,95 @@ +/********* +* +* This file is part of BibleTime's source code, http://www.bibletime.info/. +* +* Copyright 1999-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License version 2.0. +* +**********/ + +#include "backend/filters/btosismorphsegmentation.h" + +// Sword includes: +#include <utilxml.h> + + +const char Filters::BtOSISMorphSegmentation::oName[] = "Morph segmentation"; +const char Filters::BtOSISMorphSegmentation::oTip[] = "Toggles morph " + "segmentation On and Off " + "if they exist"; + +const sword::SWBuf Filters::BtOSISMorphSegmentation::choices[3] = { "Off", + "On", + "" }; + +const sword::StringList Filters::BtOSISMorphSegmentation::oValues(&choices[0], + &choices[2]); + +Filters::BtOSISMorphSegmentation::BtOSISMorphSegmentation() + : sword::SWOptionFilter(oName, oTip, &oValues) +{ + setOptionValue("Off"); +} + +char Filters::BtOSISMorphSegmentation::processText(sword::SWBuf & text, + const sword::SWKey * key, + const sword::SWModule * mod) +{ + (void) key; + (void) mod; + + 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) { + token.append(*from); // copy token + } else { + text.append(*from); // copy text which is not inside of a tag + } + } + + return 0; +} + diff --git a/src/backend/filters/btosismorphsegmentation.h b/src/backend/filters/btosismorphsegmentation.h new file mode 100644 index 0000000..66d4724 --- /dev/null +++ b/src/backend/filters/btosismorphsegmentation.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-2014 by the BibleTime developers. +* The BibleTime source code is licensed under the GNU General Public License version 2.0. +* +**********/ + +#ifndef BTOSISMORPHSEGMENTATION_H +#define BTOSISMORPHSEGMENTATION_H + +// Sword includes: +#include <swbuf.h> +#include <swoptfilter.h> + + +namespace Filters { + +/** + \brief This Filter shows/hides headings in a OSIS text. + \author Martin Gruner +*/ +class BtOSISMorphSegmentation: public sword::SWOptionFilter { + +public: /* Methods: */ + + BtOSISMorphSegmentation(); + + virtual char processText(sword::SWBuf & text, + const sword::SWKey * key = 0, + const sword::SWModule * module = 0); + +private: /* Fields: */ + + static const char oName[]; + static const char oTip[]; + static const sword::SWBuf choices[3]; + static const sword::StringList oValues; + +}; + +} /* namespace Filters { */ + +#endif /* BTOSISMORPHSEGMENTATION_H */ diff --git a/src/backend/filters/gbftohtml.cpp b/src/backend/filters/gbftohtml.cpp index fac70ba..8f2fcc5 100644 --- a/src/backend/filters/gbftohtml.cpp +++ b/src/backend/filters/gbftohtml.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -78,7 +78,7 @@ char Filters::GbfToHtml::processText(sword::SWBuf& buf, const sword::SWKey * key return 1; //no processing should be done, may happen in a search } - CSwordModuleInfo* m = CSwordBackend::instance()->findModuleByName( module->Name() ); + CSwordModuleInfo* m = CSwordBackend::instance()->findModuleByName( module->getName() ); 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 @@ -254,7 +254,7 @@ bool Filters::GbfToHtml::handleToken(sword::SWBuf &buf, const char *token, sword } buf.append(" <span class=\"footnote\" note=\""); - buf.append(myModule->Name()); + buf.append(myModule->getName()); buf.append('/'); buf.append(myUserData->key->getShortText()); buf.append('/'); diff --git a/src/backend/filters/gbftohtml.h b/src/backend/filters/gbftohtml.h index fbe5db2..bfe8501 100644 --- a/src/backend/filters/gbftohtml.h +++ b/src/backend/filters/gbftohtml.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ diff --git a/src/backend/filters/osismorphsegmentation.cpp b/src/backend/filters/osismorphsegmentation.cpp deleted file mode 100644 index 981ce89..0000000 --- a/src/backend/filters/osismorphsegmentation.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/********* -* -* This file is part of BibleTime's source code, http://www.bibletime.info/. -* -* Copyright 1999-2011 by the BibleTime developers. -* The BibleTime source code is licensed under the GNU General Public License version 2.0. -* -**********/ - -#include "backend/filters/osismorphsegmentation.h" - -// Sword includes: -#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"); -} - -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 deleted file mode 100644 index 8d5a4ab..0000000 --- a/src/backend/filters/osismorphsegmentation.h +++ /dev/null @@ -1,37 +0,0 @@ -/********* -* -* This file is part of BibleTime's source code, http://www.bibletime.info/. -* -* Copyright 1999-2011 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 - -// Sword includes: -#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 char processText(sword::SWBuf &text, const sword::SWKey *key = 0, const sword::SWModule *module = 0); -}; - -} - -#endif diff --git a/src/backend/filters/osistohtml.cpp b/src/backend/filters/osistohtml.cpp index c04c820..3a8d65f 100644 --- a/src/backend/filters/osistohtml.cpp +++ b/src/backend/filters/osistohtml.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -10,10 +10,11 @@ #include "backend/filters/osistohtml.h" #include <QString> -#include "backend/config/cbtconfig.h" +#include "backend/config/btconfig.h" #include "backend/drivers/cswordmoduleinfo.h" #include "backend/managers/clanguagemgr.h" #include "backend/managers/referencemanager.h" +#include "backend/managers/cswordbackend.h" // Sword includes: #include <swbuf.h> @@ -64,24 +65,22 @@ bool Filters::OsisToHtml::handleToken(sword::SWBuf &buf, const char *token, swor // <div> tag if (!strcmp(tag.getName(), "div")) { - //handle intro - - if ((!tag.isEmpty()) && (!tag.isEndTag())) { //start tag + if (tag.isEndTag()) { + buf.append("</div>"); + } else { 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 { + if (!tag.isEmpty()) + buf.append("<div class=\"introduction\">"); + } else if (type == "chapter") { + if (!tag.isEmpty()) + buf.append("<div class=\"chapter\" ></div>"); //don't open a div here, that would lead to a broken XML structure + } else if (type == "x-p") { + buf.append("<br/>"); + } 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 @@ -192,7 +191,7 @@ bool Filters::OsisToHtml::handleToken(sword::SWBuf &buf, const char *token, swor } else { //no prefix given val = attrib; - const bool skipFirst = ((val[0] == 'T') && ((val[1] == 'H') || (val[1] == 'H'))); + const bool skipFirst = ((val[0] == 'T') && ((val[1] == 'H') || (val[1] == 'G'))); attrValue.append( skipFirst ? val + 1 : val ); } } @@ -237,7 +236,7 @@ bool Filters::OsisToHtml::handleToken(sword::SWBuf &buf, const char *token, swor buf.append("<span class=\"crossreference\">"); sword::SWBuf footnoteNumber = tag.getAttribute("swordFootnote"); sword::SWBuf footnoteBody = myUserData->entryAttributes["Footnote"][footnoteNumber]["body"]; - buf += myModule->RenderText(footnoteBody); + buf += myModule->renderText(footnoteBody); } /* else if (type == "explanation") { @@ -256,7 +255,7 @@ bool Filters::OsisToHtml::handleToken(sword::SWBuf &buf, const char *token, swor else { // qWarning("found note in %s", myUserData->key->getShortText()); buf.append(" <span class=\"footnote\" note=\""); - buf.append(myModule->Name()); + buf.append(myModule->getName()); buf.append('/'); buf.append(myUserData->key->getShortText()); buf.append('/'); @@ -553,7 +552,7 @@ void Filters::OsisToHtml::renderReference(const char *osisRef, sword::SWBuf &buf if (!mod || (mod->type() != CSwordModuleInfo::Bible && mod->type() != CSwordModuleInfo::Commentary)) { - mod = CBTConfig::get( CBTConfig::standardBible ); + mod = btConfig().getDefaultSwordModuleByType("standardBible"); } // Q_ASSERT(mod); There's no necessarily a module or standard Bible @@ -574,7 +573,7 @@ void Filters::OsisToHtml::renderReference(const char *osisRef, sword::SWBuf &buf ReferenceManager::ParseOptions options; options.refBase = QString::fromUtf8(myUserData->key->getText()); options.refDestinationModule = QString(mod->name()); - options.sourceLanguage = QString(myModule->Lang()); + options.sourceLanguage = QString(myModule->getLanguage()); options.destinationLanguage = QString("en"); buf.append("<a href=\""); diff --git a/src/backend/filters/osistohtml.h b/src/backend/filters/osistohtml.h index ca36fe6..1c59ae1 100644 --- a/src/backend/filters/osistohtml.h +++ b/src/backend/filters/osistohtml.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ diff --git a/src/backend/filters/plaintohtml.cpp b/src/backend/filters/plaintohtml.cpp index 70df723..edb6208 100644 --- a/src/backend/filters/plaintohtml.cpp +++ b/src/backend/filters/plaintohtml.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ diff --git a/src/backend/filters/plaintohtml.h b/src/backend/filters/plaintohtml.h index b327ecc..e8ae570 100644 --- a/src/backend/filters/plaintohtml.h +++ b/src/backend/filters/plaintohtml.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ diff --git a/src/backend/filters/teitohtml.cpp b/src/backend/filters/teitohtml.cpp index 4b390d5..6367e22 100644 --- a/src/backend/filters/teitohtml.cpp +++ b/src/backend/filters/teitohtml.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -10,10 +10,11 @@ #include "backend/filters/teitohtml.h" #include <QString> -#include "backend/config/cbtconfig.h" +#include "backend/config/btconfig.h" #include "backend/drivers/cswordmoduleinfo.h" #include "backend/managers/clanguagemgr.h" #include "backend/managers/referencemanager.h" +#include "backend/managers/cswordbackend.h" // Sword includes: #include <swbuf.h> @@ -108,7 +109,7 @@ void TeiToHtml::renderReference(const char *osisRef, sword::SWBuf &buf, //If the osisRef is something like "ModuleID:key comes here" then the // modulename is given, so we'll use that one - CSwordModuleInfo* mod = CBTConfig::get( CBTConfig::standardBible ); + CSwordModuleInfo* mod = btConfig().getDefaultSwordModuleByType( "standardBible" ); // Q_ASSERT(mod); There's no necessarily a module or standard Bible @@ -128,7 +129,7 @@ void TeiToHtml::renderReference(const char *osisRef, sword::SWBuf &buf, ReferenceManager::ParseOptions options; options.refBase = QString::fromUtf8(myUserData->key->getText()); options.refDestinationModule = QString(mod->name()); - options.sourceLanguage = QString(mod->module()->Lang()); + options.sourceLanguage = QString(mod->module()->getLanguage()); options.destinationLanguage = QString("en"); buf.append("<a href=\""); diff --git a/src/backend/filters/teitohtml.h b/src/backend/filters/teitohtml.h index 6fcc2c6..f365616 100644 --- a/src/backend/filters/teitohtml.h +++ b/src/backend/filters/teitohtml.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ diff --git a/src/backend/filters/thmltohtml.cpp b/src/backend/filters/thmltohtml.cpp index 12f42bf..0bf6e63 100644 --- a/src/backend/filters/thmltohtml.cpp +++ b/src/backend/filters/thmltohtml.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -13,10 +13,11 @@ #include <QRegExp> #include <QUrl> #include <QTextCodec> -#include "backend/config/cbtconfig.h" +#include "backend/config/btconfig.h" #include "backend/drivers/cswordmoduleinfo.h" #include "backend/managers/clanguagemgr.h" #include "backend/managers/referencemanager.h" +#include "backend/managers/cswordbackend.h" // Sword includes: #include <swmodule.h> @@ -46,7 +47,7 @@ char ThmlToHtml::processText(sword::SWBuf &buf, const sword::SWKey *key, { sword::ThMLHTML::processText(buf, key, module); - CSwordModuleInfo* m = CSwordBackend::instance()->findModuleByName( module->Name() ); + CSwordModuleInfo* m = CSwordBackend::instance()->findModuleByName( module->getName() ); if (m && !(m->has(CSwordModuleInfo::lemmas) || m->has(CSwordModuleInfo::strongNumbers))) { //only parse if the module has strongs or lemmas return 1; @@ -230,7 +231,7 @@ bool ThmlToHtml::handleToken(sword::SWBuf &buf, const char *token, if (!tag.isEndTag() && !tag.isEmpty()) { //appending is faster than appendFormatted buf.append(" <span class=\"footnote\" note=\""); - buf.append(myModule->Name()); + buf.append(myModule->getName()); buf.append('/'); buf.append(myUserData->key->getShortText()); buf.append('/'); @@ -259,13 +260,13 @@ bool ThmlToHtml::handleToken(sword::SWBuf &buf, const char *token, } else { // like "<scripRef>John 3:16</scripRef>" - CSwordModuleInfo* mod = CBTConfig::get(CBTConfig::standardBible); + CSwordModuleInfo* mod = btConfig().getDefaultSwordModuleByType("standardBible"); //Q_ASSERT(mod); tested later if (mod) { ReferenceManager::ParseOptions options; options.refBase = QString::fromUtf8(myUserData->key->getText()); //current module key options.refDestinationModule = QString(mod->name()); - options.sourceLanguage = QString(myModule->Lang()); + options.sourceLanguage = QString(myModule->getLanguage()); options.destinationLanguage = QString("en"); //it's ok to split the reference, because to descriptive text is given @@ -318,13 +319,13 @@ bool ThmlToHtml::handleToken(sword::SWBuf &buf, const char *token, const char* ref = tag.getAttribute("passage"); Q_ASSERT(ref); - CSwordModuleInfo* mod = CBTConfig::get(CBTConfig::standardBible); + CSwordModuleInfo* mod = btConfig().getDefaultSwordModuleByType("standardBible"); //Q_ASSERT(mod); tested later ReferenceManager::ParseOptions options; options.refBase = QString::fromUtf8(myUserData->key->getText()); - options.sourceLanguage = myModule->Lang(); + options.sourceLanguage = myModule->getLanguage(); options.destinationLanguage = QString("en"); const QString completeRef = ReferenceManager::parseVerseReference(QString::fromUtf8(ref), options); diff --git a/src/backend/filters/thmltohtml.h b/src/backend/filters/thmltohtml.h index 99bbabb..ff40cf9 100644 --- a/src/backend/filters/thmltohtml.h +++ b/src/backend/filters/thmltohtml.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ diff --git a/src/backend/filters/thmltoplain.cpp b/src/backend/filters/thmltoplain.cpp index 42f383e..9f81173 100644 --- a/src/backend/filters/thmltoplain.cpp +++ b/src/backend/filters/thmltoplain.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ diff --git a/src/backend/filters/thmltoplain.h b/src/backend/filters/thmltoplain.h index 77e2a2b..68a5d95 100644 --- a/src/backend/filters/thmltoplain.h +++ b/src/backend/filters/thmltoplain.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ diff --git a/src/backend/keys/cswordkey.cpp b/src/backend/keys/cswordkey.cpp index a685b27..5fc37bd 100644 --- a/src/backend/keys/cswordkey.cpp +++ b/src/backend/keys/cswordkey.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -16,7 +16,6 @@ #include "backend/keys/cswordldkey.h" #include "backend/keys/cswordtreekey.h" #include "backend/keys/cswordversekey.h" -#include "util/btsignal.h" // Sword includes: #include <swkey.h> @@ -27,170 +26,168 @@ #include <versekey.h> -const QTextCodec *CSwordKey::m_cp1252Codec = QTextCodec::codecForName("Windows-1252"); - -CSwordKey::CSwordKey(const CSwordModuleInfo * const module) - : m_module(module), - m_signal(0) {} - -CSwordKey::CSwordKey(const CSwordKey& k) - : m_signal(0) { - m_module = k.m_module; -} - -CSwordKey::~CSwordKey() { - delete m_signal; -} +const QTextCodec * CSwordKey::m_cp1252Codec = QTextCodec::codecForName("Windows-1252"); QString CSwordKey::rawText() { - if (!m_module) return QString::null; + if (!m_module) + return QString::null; - if (dynamic_cast<sword::SWKey*>(this)) { + if (dynamic_cast<sword::SWKey*>(this)) m_module->module()->getKey()->setText( rawKey() ); - } - if (key().isNull()) return QString::null; + if (key().isNull()) + return QString::null; - return QString::fromUtf8( m_module->module()->getRawEntry() ); + return QString::fromUtf8(m_module->module()->getRawEntry()); } -QString CSwordKey::renderedText( const CSwordKey::TextRenderType mode ) { +QString CSwordKey::renderedText(const CSwordKey::TextRenderType mode) { Q_ASSERT(m_module); - sword::SWKey* const k = dynamic_cast<sword::SWKey*>(this); + sword::SWKey * const k = dynamic_cast<sword::SWKey *>(this); if (k) { - sword::VerseKey* vk_mod = dynamic_cast<sword::VerseKey*>(m_module->module()->getKey()); - if (vk_mod) { - vk_mod->Headings(1); - } + sword::VerseKey * vk_mod = dynamic_cast<sword::VerseKey *>(m_module->module()->getKey()); + if (vk_mod) + vk_mod->setIntros(true); - m_module->module()->getKey()->setText( rawKey() ); + m_module->module()->getKey()->setText(rawKey()); 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(), rawKey()) - && !strstr(m_module->module()->getKey()->getText(), rawKey()) - ) { + if (sword::stricmp(m_module->module()->getKey()->getText(), rawKey()) + && !strstr(m_module->module()->getKey()->getText(), rawKey())) + { qDebug("return an empty key for %s", m_module->module()->getKey()->getText()); return QString::null; } } } - //Q_ASSERT(!key().isNull()); - if (!key().isNull()) { //we have valid text - bool DoRender = mode != ProcessEntryAttributesOnly; - QString text = QString::fromUtf8( m_module->module()->RenderText(0,-1, DoRender)); - if (!DoRender) - return QString::null; - - // 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>") + if (key().isNull()) + return QString::null; + + bool DoRender = mode != ProcessEntryAttributesOnly; + QString text = QString::fromUtf8(m_module->module()->renderText(0, -1, DoRender)); + if (!DoRender) + return QString::null; + + // This is yucky, but if we want strong lexicon refs we have to do it here. + if (m_module->type() == CSwordModuleInfo::Lexicon) { + const QString t(text); + const QRegExp rx("(GREEK|HEBREW) for 0*([1-9]\\d*)"); // ignore 0's before number + int pos = 0; + while ((pos = rx.indexIn(t, pos)) != -1) { + const QString language = rx.cap(1); + const QString langcode = QString(language.at(0)); // "G" or "H" + const QString number = rx.cap(2); + const 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(); - } + ); + pos += rx.matchedLength(); } + } - if (mode == HTMLEscaped) { - /* - Here we encode all non-latin1 characters as HTML unicode entities - in the form &#<decimal unicode value here>; - */ - QString ret; - - // Reserve characters to reduce number of memory allocations: - ret.reserve(text.size()); - - for (int i = 0; i < text.size(); ++i) { - const QChar c = text.at(i); - - if (c.toLatin1()) { - ret.append(c); - } else { - ret.append("&#").append(c.unicode()).append(";"); - } + if (mode == HTMLEscaped) { + /* + Here we encode all non-latin1 characters as HTML unicode entities + in the form &#<decimal unicode value here>; + */ + QString ret; + + // Reserve characters to reduce number of memory allocations: + ret.reserve(text.size()); + + for (const QChar * c = text.constBegin(); c != text.constEnd(); c++) { + if (c->toLatin1()) { + ret.append(*c); + } else { + ret.append("&#").append(c->unicode()).append(";"); } - - return ret; - } - else { - return text; } - } - return QString::null; + return ret; + } + else { + return text; + } } QString CSwordKey::strippedText() { - if (!m_module) return QString::null; + 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 ); + m_module->module()->getKey()->setText(buffer); delete [] buffer; } - return QString::fromUtf8( m_module->module()->StripText() ); + return QString::fromUtf8(m_module->module()->stripText()); } void CSwordKey::emitBeforeChanged() { - if (m_signal.isNull()) - return; - m_signal->emitBeforeChanged(); + if (!m_beforeChangedSignaller.isNull()) + m_beforeChangedSignaller->emitSignal(); } -void CSwordKey::emitChanged() { - if (m_signal.isNull()) - return; - m_signal->emitChanged(); +void CSwordKey::emitAfterChanged() { + if (!m_afterChangedSignaller.isNull()) + m_afterChangedSignaller->emitSignal(); } -/** This will create a proper key object from a given module */ -CSwordKey *CSwordKey::createInstance(const CSwordModuleInfo *module) { - if (!module) { +CSwordKey * CSwordKey::createInstance(const CSwordModuleInfo * module) { + if (!module) return 0; - } - switch ( module->type() ) { + sword::SWKey * const key = module->module()->getKey(); - case CSwordModuleInfo::Bible://fall through + switch (module->type()) { + case CSwordModuleInfo::Bible: // Fall through case CSwordModuleInfo::Commentary: - return new CSwordVerseKey( (sword::VerseKey *) ( (sword::SWKey *)(*module->module()) ), module ); + + Q_ASSERT(dynamic_cast<sword::VerseKey *>(key) != 0); + return new CSwordVerseKey(static_cast<sword::VerseKey *>(key), + module); case CSwordModuleInfo::Lexicon: - return new CSwordLDKey( (sword::SWKey *)(*module->module()), module); + + return new CSwordLDKey(key, module); case CSwordModuleInfo::GenericBook: - return new CSwordTreeKey( (sword::TreeKeyIdx*)((sword::SWKey *)(*module->module())), module ); + + Q_ASSERT(dynamic_cast<sword::TreeKeyIdx *>(key) != 0); + return new CSwordTreeKey(dynamic_cast<sword::TreeKeyIdx *>(key), + module ); default: + return 0; + } } -const BtSignal* CSwordKey::signaler() { - if (m_signal.isNull()) - m_signal = new BtSignal(); - return m_signal; +const BtSignal * CSwordKey::beforeChangedSignaller() { + if (m_beforeChangedSignaller.isNull()) + m_beforeChangedSignaller = new BtSignal(); + + return m_beforeChangedSignaller; +} + +const BtSignal * CSwordKey::afterChangedSignaller() { + if (m_afterChangedSignaller.isNull()) + m_afterChangedSignaller = new BtSignal(); + + return m_afterChangedSignaller; } diff --git a/src/backend/keys/cswordkey.h b/src/backend/keys/cswordkey.h index 9b043b7..ee816a5 100644 --- a/src/backend/keys/cswordkey.h +++ b/src/backend/keys/cswordkey.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -12,120 +14,127 @@ #include <QPointer> #include <QString> +#include "util/btsignal.h" class CSwordModuleInfo; class QTextCodec; -class BtSignal; -/** 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 $ - */ +/** Base class for all Sword based keys. */ class CSwordKey { - protected: - /** - \param module The module which belongs to this key, may be NULL - */ - CSwordKey(const CSwordModuleInfo * const module = 0); - - CSwordKey(const CSwordKey ©); - - public: - enum TextRenderType { - Normal = 0, - HTMLEscaped = 1, - ProcessEntryAttributesOnly = 2 // in this case, renderText() will not return text, but only cause EntryAttribute processing - }; - - virtual ~CSwordKey(); - - /** Returns the current key. - * @return The 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 setKey(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 setKey(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; - - /** - \returns the module which belongs to this key. - */ - inline const CSwordModuleInfo *module() const { - return m_module; - } - - /** - Sets the module which belongs to this key. - \param[in] newModule the module to set. - */ - virtual inline void setModule(const CSwordModuleInfo *newModule) { - m_module = newModule; - } - - /** Returns the raw, unchanged text. Returns the text without any filter modifications, - * just in the way it comes out of the module. - */ - QString rawText(); - /** Returns the rendered text. Returns the text of the current key after passing it through the - * modules filters. - */ - QString renderedText( const CSwordKey::TextRenderType mode = CSwordKey::Normal ); - /** Stripped down text. Returns the text after removing all markup tags from it. - */ - QString strippedText(); - - const BtSignal *signaler(); - - /** - * 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(const CSwordModuleInfo *module); - - /** - * This is called before a key change to emit a signal - * */ - void emitBeforeChanged(); - /** - * This is called after a key change to emit a signal - * */ - void emitChanged(); - - protected: - /** - * Returns the encoded key appropriate for use directly with Sword. - */ - virtual const char * rawKey() const = 0; - static inline const QTextCodec *cp1252Codec() { return m_cp1252Codec; }; - - private: - /** - * Disable the assignment operator - */ - CSwordKey& operator= ( const CSwordKey & ); - - protected: - static const QTextCodec *m_cp1252Codec; - const CSwordModuleInfo *m_module; - QPointer<BtSignal> m_signal; + +public: /* Types: */ + + enum TextRenderType { + Normal = 0, + HTMLEscaped = 1, + ProcessEntryAttributesOnly = 2 // in this case, renderText() will not return text, but only cause EntryAttribute processing + }; + + virtual inline ~CSwordKey() { delete m_beforeChangedSignaller; } + + /** + \returns The key which belongs to the current object. + */ + virtual QString key() const = 0; + + /** + Sets the current key using a utf8 enabled QString. + \param[in] key The key which should be used to set the current one. + */ + virtual bool setKey(const QString & key) = 0; + + /** + Set the key using a utf8-decoded c-string. + \param[in] key The key which should be used to set the current one. + */ + virtual bool setKey(const char * key) = 0; + + /** + \returns a clone of this object. + */ + virtual CSwordKey * copy() const = 0; + + /** + \returns the module which belongs to this key. + */ + inline const CSwordModuleInfo * module() const { + return m_module; + } + + /** + Sets the module which belongs to this key. + \param[in] newModule the module to set. + */ + virtual inline void setModule(const CSwordModuleInfo * newModule) { + m_module = newModule; + } + + /** + \returns the raw, unchanged text from the module (i.e. without any filter + modifications). + */ + QString rawText(); + + /** + \returns the rendered text by passing the text under the current key + through the filters. + */ + QString renderedText(const CSwordKey::TextRenderType mode = CSwordKey::Normal); + + /** + \returns the text after removing all markup tags from it. + */ + QString strippedText(); + + const BtSignal * beforeChangedSignaller(); + const BtSignal * afterChangedSignaller(); + + /** + \returns a new CSwordkey subclass instance for the given module, depending + on the type of the module. + */ + static CSwordKey * createInstance(const CSwordModuleInfo * module); + + /** + This is called before a key change to emit a signal + */ + void emitBeforeChanged(); + + /** + This is called after a key change to emit a signal + */ + void emitAfterChanged(); + +protected: /* Methods: */ + + inline CSwordKey(const CSwordModuleInfo * const module = 0) + : m_module(module) {} + + inline CSwordKey(const CSwordKey & copy) + : m_module(copy.m_module) {} + + /** + \returns the encoded key appropriate for use directly with Sword. + */ + virtual const char * rawKey() const = 0; + + static inline const QTextCodec * cp1252Codec() { return m_cp1252Codec; } + +private: /* Methods: */ + + /** + Disable the assignment operator + */ + CSwordKey & operator=(const CSwordKey &); + +protected: /* Fields: */ + + static const QTextCodec * m_cp1252Codec; + const CSwordModuleInfo * m_module; + QPointer<BtSignal> m_beforeChangedSignaller; + QPointer<BtSignal> m_afterChangedSignaller; + }; #endif diff --git a/src/backend/keys/cswordldkey.cpp b/src/backend/keys/cswordldkey.cpp index 822da8c..f6ffb25 100644 --- a/src/backend/keys/cswordldkey.cpp +++ b/src/backend/keys/cswordldkey.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -75,7 +75,7 @@ bool CSwordLDKey::setKey(const QString &newKey) { return setKey(newKey.toUtf8().constData()); } else { - return setKey((const char*)cp1252Codec()->fromUnicode(newKey)); + return setKey(cp1252Codec()->fromUnicode(newKey).constData()); } } @@ -90,7 +90,7 @@ bool CSwordLDKey::setKey(const char *newKey) { m_module->snap(); } - return !Error(); + return !popError(); } /** Uses the parameter to returns the next entry afer this key. */ diff --git a/src/backend/keys/cswordldkey.h b/src/backend/keys/cswordldkey.h index ed43ce7..e8fba24 100644 --- a/src/backend/keys/cswordldkey.h +++ b/src/backend/keys/cswordldkey.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ diff --git a/src/backend/keys/cswordtreekey.cpp b/src/backend/keys/cswordtreekey.cpp index 4ea624f..2823e5f 100644 --- a/src/backend/keys/cswordtreekey.cpp +++ b/src/backend/keys/cswordtreekey.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -51,7 +51,7 @@ bool CSwordTreeKey::setKey(const QString &newKey) { return setKey(newKey.toUtf8().constData()); } else { - return setKey((const char*)cp1252Codec()->fromUnicode(newKey)); + return setKey(cp1252Codec()->fromUnicode(newKey).constData()); } } @@ -65,7 +65,7 @@ bool CSwordTreeKey::setKey(const char *newKey) { root(); } - return !Error(); + return !popError(); } QString CSwordTreeKey::getLocalNameUnicode() { diff --git a/src/backend/keys/cswordtreekey.h b/src/backend/keys/cswordtreekey.h index d6eb5ec..2bdfd6c 100644 --- a/src/backend/keys/cswordtreekey.h +++ b/src/backend/keys/cswordtreekey.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ diff --git a/src/backend/keys/cswordversekey.cpp b/src/backend/keys/cswordversekey.cpp index de4fd0e..3dc0c75 100644 --- a/src/backend/keys/cswordversekey.cpp +++ b/src/backend/keys/cswordversekey.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -150,14 +150,14 @@ bool CSwordVerseKey::setKey(const char *newKey) { } /// \todo Do we ALWAYS need to emit this signal and check for errors? - emitChanged(); - return !Error(); + emitAfterChanged(); + return !popError(); } bool CSwordVerseKey::next( const JumpType type ) { typedef CSwordBibleModuleInfo CSBMI; - Error(); //clear Error status + popError(); //clear Error status bool ret = true; switch (type) { @@ -186,21 +186,22 @@ bool CSwordVerseKey::next( const JumpType type ) { case UseVerse: { if (m_module && m_module->module()) { - const bool oldStatus = m_module->module()->getSkipConsecutiveLinks(); + const bool oldStatus = m_module->module()->isSkipConsecutiveLinks(); m_module->module()->setSkipConsecutiveLinks(true); //disable headings for next verse const bool useHeaders = 1; //(Verse() == 0); - const bool oldHeadingsStatus = ((VerseKey*)(m_module->module()->getKey()))->Headings( useHeaders ); + const bool oldHeadingsStatus = ((VerseKey*)(m_module->module()->getKey()))->isIntros(); + ((VerseKey*)(m_module->module()->getKey()))->setIntros( 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); + ((VerseKey*)(m_module->module()->getKey()))->setIntros(oldHeadingsStatus); m_module->module()->setSkipConsecutiveLinks(oldStatus); - if (!m_module->module()->Error()) { + if (!m_module->module()->popError()) { setKey(QString::fromUtf8(m_module->module()->getKeyText())); } else { @@ -237,14 +238,14 @@ bool CSwordVerseKey::next( const JumpType type ) { ret = false; } - emitChanged(); + emitAfterChanged(); return ret; } - else if (Error()) { //we have no module, so take care of VerseKey::Error() + else if (popError()) { //we have no module, so take care of VerseKey::Error() return false; } - emitChanged(); + emitAfterChanged(); return ret; } @@ -278,18 +279,19 @@ bool CSwordVerseKey::previous( const JumpType type ) { case UseVerse: { if (m_module && m_module->module()) { const bool useHeaders = 1; //(Verse() == 0); - const bool oldHeadingsStatus = ((VerseKey*)(m_module->module()->getKey()))->Headings( useHeaders ); + const bool oldHeadingsStatus = ((VerseKey*)(m_module->module()->getKey()))->isIntros(); + ((VerseKey*)(m_module->module()->getKey()))->setIntros( useHeaders ); m_module->module()->getKey()->setText( key().toUtf8().constData() ); - const bool oldStatus = m_module->module()->getSkipConsecutiveLinks(); + const bool oldStatus = m_module->module()->isSkipConsecutiveLinks(); m_module->module()->setSkipConsecutiveLinks(true); ( *( m_module->module() ) )--; - ((VerseKey*)(m_module->module()->getKey()))->Headings( oldHeadingsStatus ); + ((VerseKey*)(m_module->module()->getKey()))->setIntros( oldHeadingsStatus ); m_module->module()->setSkipConsecutiveLinks(oldStatus); - if (!m_module->module()->Error()) { + if (!m_module->module()->popError()) { setKey(QString::fromUtf8(m_module->module()->getKeyText())); // don't use fromUtf8 } else { @@ -323,13 +325,13 @@ bool CSwordVerseKey::previous( const JumpType type ) { ret = false; } - emitChanged(); + emitAfterChanged(); return ret; } - else if (Error()) { + else if (popError()) { return false; } - emitChanged(); + emitAfterChanged(); return ret; } diff --git a/src/backend/keys/cswordversekey.h b/src/backend/keys/cswordversekey.h index 2769cbf..4f33521 100644 --- a/src/backend/keys/cswordversekey.h +++ b/src/backend/keys/cswordversekey.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ diff --git a/src/backend/managers/btstringmgr.cpp b/src/backend/managers/btstringmgr.cpp index ad1fb3e..2e2e22a 100644 --- a/src/backend/managers/btstringmgr.cpp +++ b/src/backend/managers/btstringmgr.cpp @@ -2,52 +2,59 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ #include "backend/managers/btstringmgr.h" +#include <cstring> +#include "util/macros.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); +char * BtStringMgr::upperUTF8(char * const text, unsigned int maxlen) const { + size_t max = (maxlen > 0u) ? maxlen : strlen(text); - return text; - } - else { - char* ret = text; - - while (*text) { - *text = toupper(*text); - text++; + if (LIKELY(max > 1u)) { + max--; + if (isUtf8(text)) { + strncpy(text, QString::fromUtf8(text).toUpper().toUtf8().constData(), max); } - - return ret; + else { + strncpy(text, QString::fromLatin1(text).toUpper().toLatin1().constData(), max); + } + text[max] = '\0'; + } else if (max == 1u) { + text[0u] = '\0'; + } else { + Q_ASSERT(max == 0u); } return text; } -char* BTStringMgr::upperLatin1(char* text, unsigned int /*max*/) const { - char* ret = text; - - while (*text) { - *text = toupper(*text); - text++; +char * BtStringMgr::upperLatin1(char * const text, unsigned int maxlen) const { + size_t max = (maxlen > 0u) ? maxlen : strlen(text); + + if (LIKELY(max > 1u)) { + max--; + strncpy(text, QString::fromLatin1(text).toUpper().toLatin1().constData(), max); + text[max] = '\0'; + } else if (max == 1u) { + text[0u] = '\0'; + } else { + Q_ASSERT(max == 0u); } - return ret; + return text; } -bool BTStringMgr::supportsUnicode() const { +bool BtStringMgr::supportsUnicode() const { return true; } -bool BTStringMgr::isUtf8(const char *buf) const { +bool BtStringMgr::isUtf8(const char *buf) const { int i, n; register unsigned char c; bool gotone = false; diff --git a/src/backend/managers/btstringmgr.h b/src/backend/managers/btstringmgr.h index 1cf7170..3fd0175 100644 --- a/src/backend/managers/btstringmgr.h +++ b/src/backend/managers/btstringmgr.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -12,16 +14,20 @@ #include <QString> -// Sword includes: +/* Sword includes: */ #include <stringmgr.h> -/** Unicode string manager implementation. - * This is the StringManager implementation which works with QString. - * @author The BibleTime developers - */ +/** + Unicode string manager implementation. -class BTStringMgr : public sword::StringMgr { + A Qt-based sword::StringMgr is better than the default one in Sword, in case + Sword is not compiled against ICU regarding this. However, we have no good + means to check this, so let's use this class as default. This is currently + done in BibleTime::initBackends() as follows: + sword::StringMgr::setSystemStringMgr(new BtStringMgr()); +*/ +class BtStringMgr : public sword::StringMgr { public: /** Converts the param to an upper case Utf8 string @@ -50,4 +56,4 @@ class BTStringMgr : public sword::StringMgr { bool isUtf8(const char *buf) const; }; -#endif +#endif /* BTSTRINGMGR_H */ diff --git a/src/backend/managers/cdisplaytemplatemgr.cpp b/src/backend/managers/cdisplaytemplatemgr.cpp index fbeb921..734d912 100644 --- a/src/backend/managers/cdisplaytemplatemgr.cpp +++ b/src/backend/managers/cdisplaytemplatemgr.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -13,7 +13,7 @@ #include <QFileInfo> #include <QStringList> #include <QTextStream> -#include "backend/config/cbtconfig.h" +#include "backend/config/btconfig.h" #include "backend/drivers/cswordmoduleinfo.h" #include "backend/managers/clanguagemgr.h" #include "util/directory.h" @@ -21,6 +21,15 @@ #define CSSTEMPLATEBASE "Basic.tmpl" +namespace { + +inline QString readFileToString(const QString & filename) { + QFile f(filename); + return f.open(QIODevice::ReadOnly) ? QTextStream(&f).readAll() : QString(); +} + +} // anonymous namespace + CDisplayTemplateMgr * CDisplayTemplateMgr::m_instance = 0; CDisplayTemplateMgr::CDisplayTemplateMgr(QString & errorMessage) { @@ -57,7 +66,7 @@ CDisplayTemplateMgr::CDisplayTemplateMgr(QString & errorMessage) { loadCSSTemplate(td.canonicalPath() + "/" + file); // Load user app stylesheets Q_FOREACH(const QString & file, utd.entryList(cssfilter, readableFileFilter)) - loadCSSTemplate(td.canonicalPath() + "/" + file); + loadCSSTemplate(utd.canonicalPath() + "/" + file); } } @@ -145,12 +154,7 @@ QString CDisplayTemplateMgr::fillTemplate(const QString & name, QString langCSS; { - /* - At first append the font standard settings for all languages without - configured font. Create a dummy language (the langmap may be empty). - */ - const CLanguageMgr::Language lang(QString("en"), QString("English"), QString::null); - const QFont f = CBTConfig::getDefault(&lang); + const QFont & f = btConfig().getDefaultFont(); langCSS.append("#content{font-family:").append(f.family()) .append(";font-size:").append(QString::number(f.pointSizeF(), 'f')) .append("pt;font-weight:").append(f.bold() ? "bold" : "normal") @@ -160,8 +164,12 @@ QString CDisplayTemplateMgr::fillTemplate(const QString & name, { const CLanguageMgr::LangMap & langMap = CLanguageMgr::instance()->availableLanguages(); Q_FOREACH (const CLanguageMgr::Language * lang, langMap) { - if (!lang->abbrev().isEmpty() && CBTConfig::get(lang).first) { - const QFont f = CBTConfig::get(lang).second; + if (lang->abbrev().isEmpty()) + continue; + + BtConfig::FontSettingsPair fp = btConfig().getFontForLanguage(*lang); + if (fp.first) { + const QFont & f = fp.second; langCSS.append("*[lang=").append(lang->abbrev()).append("]{") .append("font-family:").append(f.family()) @@ -188,28 +196,26 @@ QString CDisplayTemplateMgr::fillTemplate(const QString & name, .replace("#DISPLAY_TEMPLATES_PATH#", DU::getDisplayTemplatesDir().absolutePath()); if (templateIsCss) - output.replace("#THEME_STYLE#", m_cssMap[name]); + output.replace("#THEME_STYLE#", readFileToString(m_cssMap[name])); return output; } QString CDisplayTemplateMgr::activeTemplateName() { - const QString tn = CBTConfig::get(CBTConfig::displayStyle); - if (tn.isEmpty()) - return defaultTemplateName(); - - return tn; + const QString tn = btConfig().value<QString>("GUI/activeTemplateName", + QString()); + return (tn.isEmpty() + || !instance()->m_availableTemplateNamesCache.contains(tn)) + ? defaultTemplateName() + : tn; } void CDisplayTemplateMgr::loadTemplate(const QString & filename) { Q_ASSERT(filename.endsWith(".tmpl")); Q_ASSERT(QFileInfo(filename).isFile()); - QFile f(filename); - if (f.open(QIODevice::ReadOnly)) { - const QString fileContent(QTextStream(&f).readAll()); - if (!fileContent.isEmpty()) - m_templateMap.insert(QFileInfo(f).fileName(), fileContent); - } + const QString templateString = readFileToString(filename); + if (!templateString.isEmpty()) + m_templateMap.insert(QFileInfo(filename).fileName(), templateString); } void CDisplayTemplateMgr::loadCSSTemplate(const QString & filename) { @@ -217,5 +223,5 @@ void CDisplayTemplateMgr::loadCSSTemplate(const QString & filename) { const QFileInfo fi(filename); Q_ASSERT(fi.isFile()); if (fi.isReadable()) - m_cssMap.insert(fi.fileName(), fi.absoluteFilePath()); + m_cssMap.insert(fi.fileName(), filename); } diff --git a/src/backend/managers/cdisplaytemplatemgr.h b/src/backend/managers/cdisplaytemplatemgr.h index a9e6380..823312c 100644 --- a/src/backend/managers/cdisplaytemplatemgr.h +++ b/src/backend/managers/cdisplaytemplatemgr.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ diff --git a/src/backend/managers/clanguagemgr.cpp b/src/backend/managers/clanguagemgr.cpp index a8d4e1f..49cc1a1 100644 --- a/src/backend/managers/clanguagemgr.cpp +++ b/src/backend/managers/clanguagemgr.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -13,26 +13,6 @@ #include "backend/managers/cswordbackend.h" -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 ******************/ /****************************************************/ @@ -52,7 +32,10 @@ CLanguageMgr *CLanguageMgr::instance() { return m_instance; } -CLanguageMgr::CLanguageMgr() : m_langMap() { +CLanguageMgr::CLanguageMgr() + : m_defaultLanguage("", "", QString::null) + , m_langMap() +{ m_availableModulesCache.moduleCount = 0; init(); } @@ -75,8 +58,8 @@ const CLanguageMgr::LangMap& CLanguageMgr::availableLanguages() { QStringList abbrevs; foreach (const CSwordModuleInfo* mod, mods) { - if (!abbrevs.contains(mod->module()->Lang())) { - abbrevs.append(mod->module()->Lang()); + if (!abbrevs.contains(mod->module()->getLanguage())) { + abbrevs.append(mod->module()->getLanguage()); } } @@ -122,10 +105,6 @@ const CLanguageMgr::Language* CLanguageMgr::languageForTranslatedName( const QSt 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; diff --git a/src/backend/managers/clanguagemgr.h b/src/backend/managers/clanguagemgr.h index cbe70e9..fee236f 100644 --- a/src/backend/managers/clanguagemgr.h +++ b/src/backend/managers/clanguagemgr.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -23,67 +25,94 @@ class CLanguageMgr { public: - /** Language container. - * This class (Language) contains the information about the chosen language. - */ - class Language { - public: - /** - 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(); - Language(const Language ©); + /** + \brief A language descriptor for CLanguageMgr. + + This class (Language) contains the information about the a language. + */ + class Language { - Language(const QString &abbrev, const QString &englishName, - const QString &translatedName, - const QStringList &altAbbrevs = QStringList()); + friend class CLanguageMgr; + friend class BtFontSettingsPage; - ~Language(); + public: /* Methods: */ - /** 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 + /** + \returns the abbreviation of the this 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 { + + /** + \returns the translated name of this 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 { + + /** + \returns the english name of this language. + */ + inline const QString & englishName() const { return m_englishName; } - /** The alternative abbreviations which are avalable for this language. - * @return The List of alternate abbreviations - */ - inline const QStringList alternativeAbbrevs() const { + + /** + \returns a list of alternative abbreviations for this language. + */ + 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. - */ + \returns whether this language object is valid, i.e. has an + abbreviation and an english name. + */ inline bool isValid() const { - return (!abbrev().isEmpty() && !name().isEmpty()); + return (!m_abbrev.isEmpty() && !m_englishName.isEmpty()); } - private: - QString m_abbrev; - QString m_englishName; - QString m_translatedName; - QStringList m_altAbbrevs; - }; + private: /* Methods: */ + + inline Language() {} + + inline Language(const char * abbrev, + const char * englishName, + const QString & translatedName) + : m_abbrev(abbrev) + , m_englishName(QString::fromUtf8(englishName)) + , m_translatedName(translatedName) {} + + inline Language(const QString & abbrev, + const QString & englishName, + const QString & translatedName) + : m_abbrev(abbrev) + , m_englishName(englishName) + , m_translatedName(translatedName) {} + + inline Language(const char * abbrev, + const char * englishName, + const QString & translatedName, + const QStringList & altAbbrevs) + : m_abbrev(abbrev) + , m_englishName(QString::fromUtf8(englishName)) + , m_translatedName(translatedName) + , m_altAbbrevs(altAbbrevs) {} + + private: /* Fields: */ + + const QString m_abbrev; + const QString m_englishName; + const QString m_translatedName; + const QStringList m_altAbbrevs; + + }; /* class Language { */ typedef QList<Language*> LanguageList; typedef QHash<QString, const Language*> LangMap; diff --git a/src/backend/managers/cswordbackend.cpp b/src/backend/managers/cswordbackend.cpp index b5f4bff..c126c47 100644 --- a/src/backend/managers/cswordbackend.cpp +++ b/src/backend/managers/cswordbackend.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -15,13 +15,13 @@ #include <QSet> #include <QString> #include <QTextCodec> -#include "backend/config/cbtconfig.h" +#include "backend/config/btconfig.h" #include "backend/drivers/cswordbiblemoduleinfo.h" #include "backend/drivers/cswordbookmoduleinfo.h" #include "backend/drivers/cswordcommentarymoduleinfo.h" #include "backend/drivers/cswordlexiconmoduleinfo.h" +#include "backend/filters/btosismorphsegmentation.h" #include "backend/filters/thmltoplain.h" -#include "backend/filters/osismorphsegmentation.h" #include "btglobal.h" #include "util/directory.h" @@ -37,18 +37,21 @@ using namespace Rendering; -CSwordBackend *CSwordBackend::m_instance = 0; +CSwordBackend * CSwordBackend::m_instance = 0; CSwordBackend::CSwordBackend() : sword::SWMgr(0, 0, false, - new sword::EncodingFilterMgr(sword::ENC_UTF8), true), - m_dataModel(this) + new sword::EncodingFilterMgr(sword::ENC_UTF8), true) + , m_dataModel(this) { 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 +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 filterInit(); } @@ -57,28 +60,28 @@ CSwordBackend::~CSwordBackend() { } void CSwordBackend::filterInit() { - //HACK: replace Sword's OSISMorphSegmentation filter, seems to be buggy, ours works - if (sword::SWOptionFilter* filter = optionFilters["OSISMorphSegmentation"]) { + // HACK: replace Sword's OSISMorphSegmentation filter, seems to be buggy, ours works + if (sword::SWOptionFilter * const filter = optionFilters["OSISMorphSegmentation"]) { cleanupFilters.remove(filter); optionFilters.erase("OSISMorphSegmentation"); delete filter; } - sword::SWOptionFilter *tmpFilter = new Filters::OSISMorphSegmentation(); + sword::SWOptionFilter * const tmpFilter = new Filters::BtOSISMorphSegmentation(); 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 + // 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 Filters::ThmlToPlain(); cleanupFilters.push_back(thmlplain); } -QList<CSwordModuleInfo*> CSwordBackend::takeModulesFromList(const QStringList &names) { - QList<CSwordModuleInfo*> list; - Q_FOREACH (const QString &name, names) { - CSwordModuleInfo* mInfo = findModuleByName(name); +QList<CSwordModuleInfo *> CSwordBackend::takeModulesFromList(const QStringList & names) { + QList<CSwordModuleInfo *> list; + Q_FOREACH (const QString & name, names) { + CSwordModuleInfo * const mInfo = findModuleByName(name); if (mInfo) { m_dataModel.removeModule(mInfo); list.append(mInfo); @@ -89,82 +92,76 @@ QList<CSwordModuleInfo*> CSwordBackend::takeModulesFromList(const QStringList &n return list; } -QList<CSwordModuleInfo*> CSwordBackend::getPointerList(const QStringList &names) const { - QList<CSwordModuleInfo*> list; - Q_FOREACH (const QString &name, names) { - CSwordModuleInfo *mInfo = findModuleByName(name); - if (mInfo) { +QList<CSwordModuleInfo *> CSwordBackend::getPointerList(const QStringList & names) const { + QList<CSwordModuleInfo *> list; + Q_FOREACH (const QString & name, names) { + CSwordModuleInfo * const mInfo = findModuleByName(name); + if (mInfo) list.append(mInfo); - } } return list; } -QList<const CSwordModuleInfo*> CSwordBackend::getConstPointerList( - const QStringList &names) const +QList<const CSwordModuleInfo *> CSwordBackend::getConstPointerList( + const QStringList & names) const { - QList<const CSwordModuleInfo*> list; - Q_FOREACH (const QString &name, names) { - const CSwordModuleInfo *mInfo = findModuleByName(name); - if (mInfo) { + QList<const CSwordModuleInfo *> list; + Q_FOREACH (const QString & name, names) { + const CSwordModuleInfo * const mInfo = findModuleByName(name); + if (mInfo) list.append(mInfo); - } } return list; } +CSwordBackend::LoadError CSwordBackend::initModules(const SetupChangedReason reason) { + // qWarning("globalSwordConfigPath is %s", globalConfPath); -/** Initializes the Sword modules. */ -CSwordBackend::LoadError CSwordBackend::initModules(SetupChangedReason reason) { - // qWarning("globalSwordConfigPath is %s", globalConfPath); - LoadError ret = NoError; - - shutdownModules(); //remove previous modules + shutdownModules(); // Remove previous modules m_dataModel.clear(); sword::ModMap::iterator end = Modules.end(); - ret = LoadError( Load() ); + const LoadError ret = static_cast<LoadError>(Load()); - for (sword::ModMap::iterator it = Modules.begin(); it != end; it++) { - sword::SWModule* const curMod = (*it).second; - CSwordModuleInfo* newModule = 0; + for (sword::ModMap::iterator it = Modules.begin(); it != end; ++it) { + sword::SWModule * const curMod = it->second; + CSwordModuleInfo * newModule; - if (!strcmp(curMod->Type(), "Biblical Texts")) { - newModule = new CSwordBibleModuleInfo(curMod, this); + const char * const modType = curMod->getType(); + if (!strcmp(modType, "Biblical Texts")) { + newModule = new CSwordBibleModuleInfo(curMod, *this); newModule->module()->setDisplay(&m_chapterDisplay); - } - else if (!strcmp(curMod->Type(), "Commentaries")) { - newModule = new CSwordCommentaryModuleInfo(curMod, this); + } else if (!strcmp(modType, "Commentaries")) { + newModule = new CSwordCommentaryModuleInfo(curMod, *this); newModule->module()->setDisplay(&m_entryDisplay); - } - else if (!strcmp(curMod->Type(), "Lexicons / Dictionaries")) { - newModule = new CSwordLexiconModuleInfo(curMod, this); + } else if (!strcmp(modType, "Lexicons / Dictionaries")) { + newModule = new CSwordLexiconModuleInfo(curMod, *this); newModule->module()->setDisplay(&m_entryDisplay); - } - else if (!strcmp(curMod->Type(), "Generic Books")) { - newModule = new CSwordBookModuleInfo(curMod, this); + } else if (!strcmp(modType, "Generic Books")) { + newModule = new CSwordBookModuleInfo(curMod, *this); newModule->module()->setDisplay(&m_bookDisplay); + } else { + continue; } - 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_dataModel.addModule(newModule); - } - else { - delete 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_dataModel.addModule(newModule); + } else { + delete newModule; } } - Q_FOREACH(CSwordModuleInfo* mod, m_dataModel.moduleList()) { - //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() ); - } + // Unlock modules if keys are present: + Q_FOREACH(CSwordModuleInfo * mod, m_dataModel.moduleList()) { + if (mod->isEncrypted()) { + const QString unlockKey = btConfig().getModuleEncryptionKey(mod->name()); + if (!unlockKey.isNull()) + setCipherKey(mod->name().toUtf8().constData(), + unlockKey.toUtf8().constData()); } } @@ -172,46 +169,36 @@ CSwordBackend::LoadError CSwordBackend::initModules(SetupChangedReason reason) { return ret; } -void CSwordBackend::AddRenderFilters(sword::SWModule *module, sword::ConfigEntMap §ion) { - 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 == "OSIS") { - module->AddRenderFilter(&m_osisFilter); - noDriver = false; - } - else if (sourceformat == "ThML") { - module->AddRenderFilter(&m_thmlFilter); - noDriver = false; - } - else if (sourceformat == "TEI") { - module->AddRenderFilter(&m_teiFilter); - noDriver = false; - } - else if (sourceformat == "GBF") { - module->AddRenderFilter(&m_gbfFilter); - noDriver = false; - } - else if (sourceformat == "PLAIN") { - module->AddRenderFilter(&m_plainFilter); - noDriver = false; - } - - if (noDriver) { //no driver found - if ( (moduleDriver == "RawCom") || (moduleDriver == "RawLD") ) { - module->AddRenderFilter(&m_plainFilter); - noDriver = false; +void CSwordBackend::AddRenderFilters(sword::SWModule * module, + sword::ConfigEntMap & section) +{ + sword::ConfigEntMap::const_iterator entry = section.find("SourceType"); + if (entry != section.end()) { + if (entry->second == "OSIS") { + module->addRenderFilter(&m_osisFilter); + return; + } else if (entry->second == "ThML") { + module->addRenderFilter(&m_thmlFilter); + return; + } else if (entry->second == "TEI") { + module->addRenderFilter(&m_teiFilter); + return; + } else if (entry->second == "GBF") { + module->addRenderFilter(&m_gbfFilter); + return; + } else if (entry->second == "PLAIN") { + module->addRenderFilter(&m_plainFilter); + return; } } + + // No driver found + entry = section.find("ModDrv"); + if (entry != section.end() && (entry->second == "RawCom" || entry->second == "RawLD")) + module->addRenderFilter(&m_plainFilter); } -/** This function deinitializes the modules and deletes them. */ -bool CSwordBackend::shutdownModules() { +void CSwordBackend::shutdownModules() { m_dataModel.clear(true); //BT mods are deleted now, delete Sword mods, too. DeleteMods(); @@ -221,117 +208,107 @@ bool CSwordBackend::shutdownModules() { * 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++) { + typedef sword::FilterMap::const_iterator FMCI; + for (FMCI it = cipherFilters.begin(); it != cipherFilters.end(); ++it) { //Delete the Filter and remove it from the cleanup list - cleanupFilters.remove(cipher_it->second); - delete cipher_it->second; + cleanupFilters.remove(it->second); + delete 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"; - } - +void CSwordBackend::setOption(const CSwordModuleInfo::FilterTypes type, + const int state) +{ + if (type == CSwordModuleInfo::textualVariants) { + switch (state) { + case 0: + setGlobalOption(optionName(type).toUtf8().constData(), + "Primary Reading"); + break; + case 1: + setGlobalOption(optionName(type).toUtf8().constData(), + "Secondary Reading"); break; - default: - value = state ? "On" : "Off"; + setGlobalOption(optionName(type).toUtf8().constData(), + "All Readings"); break; - }; - - if (value.length()) - setGlobalOption(optionName(type).toUtf8().constData(), value.c_str()); + } + } else { + setGlobalOption(optionName(type).toUtf8().constData(), + state ? "On" : "Off"); + } } -void CSwordBackend::setFilterOptions(const 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); +void CSwordBackend::setFilterOptions(const 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) const { - Q_FOREACH (CSwordModuleInfo *mod, m_dataModel.moduleList()) { - if (mod->config(CSwordModuleInfo::Description) == description) return mod; - } +CSwordModuleInfo * CSwordBackend::findModuleByDescription(const QString & description) const { + Q_FOREACH (CSwordModuleInfo * mod, m_dataModel.moduleList()) + if (mod->config(CSwordModuleInfo::Description) == description) + return mod; return 0; } -/** This function searches for a module with the specified name */ -CSwordModuleInfo* CSwordBackend::findModuleByName(const QString &name) const { - Q_FOREACH (CSwordModuleInfo *mod, m_dataModel.moduleList()) { - if (mod->name() == name) return mod; - } +CSwordModuleInfo * CSwordBackend::findModuleByName(const QString & name) const { + Q_FOREACH (CSwordModuleInfo * mod, m_dataModel.moduleList()) + if (mod->name() == name) + return mod; return 0; } -CSwordModuleInfo* CSwordBackend::findSwordModuleByPointer(const sword::SWModule * const swmodule) const { - Q_FOREACH (CSwordModuleInfo *mod, m_dataModel.moduleList()) { - if (mod->module() == swmodule) return mod; - } +CSwordModuleInfo * CSwordBackend::findSwordModuleByPointer(const sword::SWModule * const swmodule) const { + Q_FOREACH (CSwordModuleInfo * mod, m_dataModel.moduleList()) + if (mod->module() == swmodule) + return mod; return 0; } -/** Returns the text used for the option given as parameter. */ -const QString CSwordBackend::optionName( const CSwordModuleInfo::FilterTypes option ) { +QString CSwordBackend::optionName(const CSwordModuleInfo::FilterTypes option) { switch (option) { case CSwordModuleInfo::footnotes: - return QString("Footnotes"); + return "Footnotes"; case CSwordModuleInfo::strongNumbers: - return QString("Strong's Numbers"); + return "Strong's Numbers"; case CSwordModuleInfo::headings: - return QString("Headings"); + return "Headings"; case CSwordModuleInfo::morphTags: - return QString("Morphological Tags"); + return "Morphological Tags"; case CSwordModuleInfo::lemmas: - return QString("Lemmas"); + return "Lemmas"; case CSwordModuleInfo::hebrewPoints: - return QString("Hebrew Vowel Points"); + return "Hebrew Vowel Points"; case CSwordModuleInfo::hebrewCantillation: - return QString("Hebrew Cantillation"); + return "Hebrew Cantillation"; case CSwordModuleInfo::greekAccents: - return QString("Greek Accents"); + return "Greek Accents"; case CSwordModuleInfo::redLetterWords: - return QString("Words of Christ in Red"); + return "Words of Christ in Red"; case CSwordModuleInfo::textualVariants: - return QString("Textual Variants"); + return "Textual Variants"; case CSwordModuleInfo::scriptureReferences: - return QString("Cross-references"); + return "Cross-references"; case CSwordModuleInfo::morphSegmentation: - return QString("Morph Segmentation"); + return "Morph Segmentation"; } return QString::null; } -/** Returns the translated name of the option given as parameter. */ -const QString CSwordBackend::translatedOptionName(const CSwordModuleInfo::FilterTypes option) { +QString CSwordBackend::translatedOptionName(const CSwordModuleInfo::FilterTypes option) { switch (option) { case CSwordModuleInfo::footnotes: return QObject::tr("Footnotes"); @@ -362,58 +339,60 @@ const QString CSwordBackend::translatedOptionName(const CSwordModuleInfo::Filter } -const QString CSwordBackend::configOptionName( const CSwordModuleInfo::FilterTypes option ) { +QString CSwordBackend::configOptionName(const CSwordModuleInfo::FilterTypes option) { switch (option) { case CSwordModuleInfo::footnotes: - return QString("Footnotes"); + return "Footnotes"; case CSwordModuleInfo::strongNumbers: - return QString("Strongs"); + return "Strongs"; case CSwordModuleInfo::headings: - return QString("Headings"); + return "Headings"; case CSwordModuleInfo::morphTags: - return QString("Morph"); + return "Morph"; case CSwordModuleInfo::lemmas: - return QString("Lemma"); + return "Lemma"; case CSwordModuleInfo::hebrewPoints: - return QString("HebrewPoints"); + return "HebrewPoints"; case CSwordModuleInfo::hebrewCantillation: - return QString("Cantillation"); + return "Cantillation"; case CSwordModuleInfo::greekAccents: - return QString("GreekAccents"); + return "GreekAccents"; case CSwordModuleInfo::redLetterWords: - return QString("RedLetterWords"); + return "RedLetterWords"; case CSwordModuleInfo::textualVariants: - return QString("Variants"); + return "Variants"; case CSwordModuleInfo::scriptureReferences: - return QString("Scripref"); + return "Scripref"; case CSwordModuleInfo::morphSegmentation: - return QString("MorphSegmentation"); + return "MorphSegmentation"; } return QString::null; } -const QString CSwordBackend::booknameLanguage( const QString& language ) { +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() ); - - Q_FOREACH (CSwordModuleInfo *mod, m_dataModel.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() ); + sword::LocaleMgr::getSystemLocaleMgr()->setDefaultLocaleName(language.toUtf8().constData()); + + // Refresh the locale of all Bible and commentary modules! + // Use what sword returns, language may be different. + const QByteArray newLocaleName(QString(sword::LocaleMgr::getSystemLocaleMgr()->getDefaultLocaleName()).toUtf8()); + + Q_FOREACH (CSwordModuleInfo * mod, m_dataModel.moduleList()) { + if (mod->type() == CSwordModuleInfo::Bible + || mod->type() == CSwordModuleInfo::Commentary) + { + // Create a new key, it will get the default bookname language: + typedef sword::VerseKey VK; + VK & vk = *static_cast<VK *>(mod->module()->getKey()); + vk.setLocale(newLocaleName.constData()); } } } - return QString( sword::LocaleMgr::getSystemLocaleMgr()->getDefaultLocaleName() ); + return sword::LocaleMgr::getSystemLocaleMgr()->getDefaultLocaleName(); } - -/** Reload all Sword modules. */ -void CSwordBackend::reloadModules(SetupChangedReason reason) { +void CSwordBackend::reloadModules(const SetupChangedReason reason) { shutdownModules(); //delete Sword's config to make Sword reload it! @@ -425,8 +404,7 @@ void CSwordBackend::reloadModules(SetupChangedReason reason) { findConfig(&configType, &prefixPath, &configPath, &augPaths, &sysConfig); // now re-read module configuration files loadConfigDir(configPath); - } - else if (config) { + } else if (config) { config->Load(); } @@ -435,17 +413,13 @@ void CSwordBackend::reloadModules(SetupChangedReason reason) { // Get one or more shared sword config (sword.conf) files QStringList CSwordBackend::getSharedSwordConfigFiles() const { - QStringList configPath; -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN // %ALLUSERSPROFILE%\Sword\sword.conf - QString tmp = util::directory::getSharedSwordDir().filePath("sword.conf"); - QString globalPath = util::directory::convertDirSeparators(QString(getenv("SWORD_PATH"))); - configPath << globalPath.append("/Sword/sword.conf"); + return QStringList(util::directory::convertDirSeparators(QString(getenv("SWORD_PATH"))) += "/Sword/sword.conf"); #else // /etc/sword.conf, /usr/local/etc/sword.conf - configPath = QString(globalConfPath).split(":"); + return QString(globalConfPath).split(":"); #endif - return configPath; } // Get the private sword directory @@ -454,15 +428,13 @@ QString CSwordBackend::getPrivateSwordConfigPath() const { } QString CSwordBackend::getPrivateSwordConfigFile() const { - QString file(getPrivateSwordConfigPath() + "/sword.conf"); - return util::directory::convertDirSeparators(file); + return util::directory::convertDirSeparators(getPrivateSwordConfigPath() += "/sword.conf"); } // Return a list of used Sword dirs. Useful for the installer. QStringList CSwordBackend::swordDirList() const { namespace DU = util::directory; typedef QStringList::const_iterator SLCI; - typedef sword::ConfigEntMap::const_iterator CEMCI; // Get the set of sword directories that could contain modules: QSet<QString> swordDirSet; @@ -471,8 +443,7 @@ QStringList CSwordBackend::swordDirList() const { if (QFile(getPrivateSwordConfigFile()).exists()) { // Use the private sword.conf file: configs << getPrivateSwordConfigFile(); - } - else { + } else { /* Did not find private sword.conf, will use shared sword.conf files to build the private one. Once the private sword.conf exist, the shared @@ -480,7 +451,7 @@ QStringList CSwordBackend::swordDirList() const { */ configs = getSharedSwordConfigFiles(); -#ifdef Q_WS_WIN +#ifdef Q_OS_WIN /* On Windows, add the shared sword directory to the set so the new private sword.conf will have it. The user could decide to delete this @@ -491,53 +462,49 @@ QStringList CSwordBackend::swordDirList() const { } // Search the sword.conf file(s) for sword directories that could contain modules - for (SLCI it(configs.begin()); it != configs.end(); it++) { - if (!QFileInfo(*it).exists()) { + for (SLCI 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()); + sword::SWConfig conf(it->toUtf8().constData()); swordDirSet << QDir(QTextCodec::codecForLocale()->toUnicode(conf["Install"]["DataPath"].c_str())).absolutePath(); - sword::ConfigEntMap group(conf["Install"]); - const sword::ConfigEntMap::iterator start(group.equal_range("AugmentPath").first); - const sword::ConfigEntMap::iterator end(group.equal_range("AugmentPath").second); - - for (CEMCI it(start); it != end; it++) { - QDir(QTextCodec::codecForLocale()->toUnicode(it->second.c_str())).absolutePath(); + const sword::ConfigEntMap group(conf["Install"]); + typedef sword::ConfigEntMap::const_iterator CEMCI; + for (std::pair<CEMCI, CEMCI> its = group.equal_range("AugmentPath"); + its.first != its.second; + ++(its.first)) + { // Added augment path: - swordDirSet << QDir(QTextCodec::codecForLocale()->toUnicode(it->second.c_str())).absolutePath(); + swordDirSet << QDir(QTextCodec::codecForLocale()->toUnicode(its.first->second.c_str())).absolutePath(); } } // Add the private sword path to the set if not there already: swordDirSet << getPrivateSwordConfigPath(); - return swordDirSet.values(); + return QStringList::fromSet(swordDirSet); } void CSwordBackend::deleteOrphanedIndices() { - QDir dir(CSwordModuleInfo::getGlobalBaseIndexLocation()); - dir.setFilter(QDir::Dirs); - CSwordModuleInfo* module; - - for (unsigned int i = 0; i < dir.count(); i++) { - if (dir[i] != "." && dir[i] != "..") { - if ( (module = this->findModuleByName(dir[i])) ) { //mod exists - if (!module->hasIndex()) { //index files found, but wrong version etc. - qDebug() << "deleting outdated index for module" << dir[i]; - CSwordModuleInfo::deleteIndexForModule( dir[i] ); - } + const QStringList entries = QDir(CSwordModuleInfo::getGlobalBaseIndexLocation()).entryList(QDir::Dirs); + Q_FOREACH(const QString & entry, entries) { + if (entry == "." || entry == "..") + continue; + CSwordModuleInfo * const module = findModuleByName(entry); + if (module) { //mod exists + if (!module->hasIndex()) { //index files found, but wrong version etc. + qDebug() << "deleting outdated index for module" << entry; + CSwordModuleInfo::deleteIndexForModule(entry); } - else { //no module exists - if (CBTConfig::get( CBTConfig::autoDeleteOrphanedIndices ) ) { - qDebug() << "deleting orphaned index in directory" << dir[i]; - CSwordModuleInfo::deleteIndexForModule( dir[i] ); - } + } else { //no module exists + if (btConfig().value<bool>("settings/behaviour/autoDeleteOrphanedIndices", true)) { + qDebug() << "deleting orphaned index in directory" << entry; + CSwordModuleInfo::deleteIndexForModule(entry); } } } diff --git a/src/backend/managers/cswordbackend.h b/src/backend/managers/cswordbackend.h index 764d6d5..21da696 100644 --- a/src/backend/managers/cswordbackend.h +++ b/src/backend/managers/cswordbackend.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -10,7 +12,6 @@ #ifndef CSWORDBACKEND_H #define CSWORDBACKEND_H -#include <QMap> #include <QObject> #include <QString> #include <QStringList> @@ -44,215 +45,241 @@ BibleTimeApp::~BibleTimeApp(). Only when \ref BackendNotSingleton "managing modules" separate backends are created. */ -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 - }; - - /** 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. Used by BtInstallBackend only. - * 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. - */ - ~CSwordBackend(); - - /** Creates and returns the instance. */ - static inline CSwordBackend *createInstance() { - Q_ASSERT(m_instance == 0); - m_instance = new CSwordBackend(); - return m_instance; - } - - /** Returns the singleton instance, creating it if one does not exist. */ - static inline CSwordBackend *instance() { return m_instance; } - - /** Destroys the singleton instance, if one exists. */ - static void destroyInstance() { delete m_instance; } - - /** - * This function returns the list of available modules managed by this - * backend. You have to call initModules() first; This method is - * equivalent to model()->modules(). - * - * @return The list of modules managed by this backend - */ - inline const QList<CSwordModuleInfo*>& moduleList() const; - - inline BtBookshelfModel *model(); - - /** - * Initializes the Sword modules. - * - * @return True if the initializiation was succesful, otherwise return false. - */ - CSwordBackend::LoadError initModules(SetupChangedReason reason); - /** - * This function deinitializes the modules and deletes them. - * - * @return True if it was succesful, otherwise return false - */ - 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 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 - */ - CSwordModuleInfo* findModuleByDescription(const QString &description) const; - - /** - * 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) const; - /** - * 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) const; - - /** - * @return Our global config object which contains the configs of all modules merged together. - */ - inline sword::SWConfig* getConfig() const; - - /** - * 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 ); - - /** - * 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(const QStringList &names); - - /** - \returns a list of pointers to modules, created from a list of module - names. - */ - QList<CSwordModuleInfo*> getPointerList(const QStringList &names) const; - - /** - \returns a list of pointers to const modules, created from a list of - module names. - */ - QList<const CSwordModuleInfo*> getConstPointerList(const QStringList &names) const; - - /** Sword prefix list. - * @return A list of all known Sword prefix dirs - */ - QStringList swordDirList() const; - /** - * delete all orphaned indexes (no module present) if autoDeleteOrphanedIndices is true - * delete all indices of modules where hasIndex() returns false (because of wrong index version etc.) - */ - void deleteOrphanedIndices(); - - signals: - void sigSwordSetupChanged(CSwordBackend::SetupChangedReason reason); - - protected: - /** - Creates the SWModule objects using SWMgr's methods, it adds the - necessary filters for the module format. - */ - CSwordBackend(); - - /** - * Reimplemented from sword::SWMgr. - */ - void AddRenderFilters(sword::SWModule *module, sword::ConfigEntMap §ion); - /** - * Overrides Sword filters which appear to be buggy. - */ - void filterInit(); - - QStringList getSharedSwordConfigFiles() const; - QString getPrivateSwordConfigPath() const; - QString getPrivateSwordConfigFile() const; - - private: /* Fields: */ - // Filters: - Filters::GbfToHtml m_gbfFilter; - Filters::OsisToHtml m_osisFilter; - Filters::PlainToHtml m_plainFilter; - Filters::TeiToHtml m_teiFilter; - Filters::ThmlToHtml m_thmlFilter; - - // Displays: - Rendering::CChapterDisplay m_chapterDisplay; - Rendering::CEntryDisplay m_entryDisplay; - Rendering::CBookDisplay m_bookDisplay; - - BtBookshelfModel m_dataModel; - - static CSwordBackend *m_instance; +class CSwordBackend: public QObject, public sword::SWMgr { + + Q_OBJECT + +public: /* Types: */ + + /** + \brief 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 + }; + + /** + \brief The error codes which may be returned by the \ref Load() call. + \note These values exist to cast from the char return of SWMgr::Load(). + */ + enum LoadError { + NoSwordConfig = -1, + NoError = 0, + NoModules = 1 + }; + +public: /* Methods: */ + + /** + \note Used by BtInstallBackend only. + \note Using augmentHome=false can mess up the system because it is true + elsewhere. + \param[in] path The path which is used to load modules. + \param[in] augmentHome Whether $HOME/.sword/ modules should be augmented + with the other modules. + */ + CSwordBackend(const QString & path, const bool augmentHome = true); + + ~CSwordBackend(); + + /** \returns the CSwordBackend singleton instance (created if needed). */ + static inline CSwordBackend * createInstance() { + Q_ASSERT(!m_instance); + m_instance = new CSwordBackend(); + return m_instance; + } + + /** \returns the singleton instance, creating it if one does not exist. */ + static inline CSwordBackend * instance() { return m_instance; } + + /** \brief Destroys the singleton instance, if one exists. */ + static inline void destroyInstance() { + delete m_instance; + m_instance = NULL; + } + + /** + \warning You have to call initModules() first. + \note This method is equivalent to model()->modules(). + \returns The list of modules managed by this backend. + */ + inline const QList<CSwordModuleInfo *> & moduleList() const; + + inline BtBookshelfModel * model(); + + /** + \brief Initializes the Sword modules. + \returns whether the initializiation was successful. + */ + CSwordBackend::LoadError initModules(const SetupChangedReason reason); + + /** + \brief Deinitializes and frees the modules. + \returns whether the method succeeded. + */ + void shutdownModules(); + + /** + \brief Sets the state of the given filter option. + \param[in] type The filter type whose state to set. + \param[in] state The new filter option state. + */ + void setOption(const CSwordModuleInfo::FilterTypes type, const int state); + + void setFilterOptions(const FilterOptions & options); + + /** + \brief Sets the language for the international booknames of Sword. + \param[in] langName The abbreviation string which should be used for the + Sword backend. + */ + const QString booknameLanguage(const QString & langName = QString::null); + + /** + \brief Searches for a module with the given description. + \param[in] description The description of the desired module. + \returns a pointer to the desired module or NULL if not found. + */ + CSwordModuleInfo * findModuleByDescription(const QString & description) const; + + /** + \brief Searches for a module with the given name. + \param[in] name The name of the desired module. + \returns a pointer to the desired module or NULL if not found. + */ + CSwordModuleInfo * findModuleByName(const QString & name) const; + + /** + \brief Searches for a module with the given sword module as module(). + \param[in] swmodule The SWModule of the desired module. + \returns a pointer to the desired module or NULL if not found. + */ + CSwordModuleInfo * findSwordModuleByPointer(const sword::SWModule * const swmodule) const; + + /** + \returns The global config object containing the configs of all modules + merged together. + */ + inline sword::SWConfig * getConfig() const; + + /** + \param[in] option The option name to return. + \returns The name of the option given by the parameter. + */ + static QString optionName(const CSwordModuleInfo::FilterTypes option); + + /** + \param[in] option The configuration option name to return. + \returns the text used for the configuration option given. + */ + static QString configOptionName(const CSwordModuleInfo::FilterTypes option); + + /** + \param[in] option The translated option name. + \returns the translated name of the option given. + */ + static QString translatedOptionName(const CSwordModuleInfo::FilterTypes option); + + /** + \brief Reloads all Sword modules. + \param[in] reason The reason for the reload. + */ + void reloadModules(const SetupChangedReason reason); + + /** + \brief Takes off the given modules from the list and returns them. + \param[in] names The names of the modules to take. + \note User must take care of the deletion of the returned CSwordModuleInfo + pointers. + */ + QList<CSwordModuleInfo *> takeModulesFromList(const QStringList & names); + + /** + \param[in] names The names of the modules to return. + \returns a list of pointers to modules, created from a list of module + names. + */ + QList<CSwordModuleInfo *> getPointerList(const QStringList & names) const; + + /** + \param[in] names The names of the modules to return. + \returns a list of pointers to const modules, created from a list of + module names. + */ + QList<const CSwordModuleInfo *> getConstPointerList(const QStringList & names) const; + + /** + \brief Sword prefix list. + \returns A list of all known Sword prefix dirs + */ + QStringList swordDirList() const; + + /** + Deletes all indices of modules where hasIndex() returns false (because of + wrong index version etc.) and deletes all orphaned indexes (no module + present) if autoDeleteOrphanedIndices is true. + */ + void deleteOrphanedIndices(); + +signals: + + void sigSwordSetupChanged(CSwordBackend::SetupChangedReason reason); + +protected: /* Methods: */ + + /** + Creates the SWModule objects using SWMgr's methods, it adds the + necessary filters for the module format. + */ + CSwordBackend(); + + /** Reimplemented from sword::SWMgr. */ + void AddRenderFilters(sword::SWModule * module, + sword::ConfigEntMap & section); + + /** Overrides Sword filters which appear to be buggy. */ + void filterInit(); + + QStringList getSharedSwordConfigFiles() const; + QString getPrivateSwordConfigPath() const; + QString getPrivateSwordConfigFile() const; + +private: /* Fields: */ + + // Filters: + Filters::GbfToHtml m_gbfFilter; + Filters::OsisToHtml m_osisFilter; + Filters::PlainToHtml m_plainFilter; + Filters::TeiToHtml m_teiFilter; + Filters::ThmlToHtml m_thmlFilter; + + // Displays: + Rendering::CChapterDisplay m_chapterDisplay; + Rendering::CEntryDisplay m_entryDisplay; + Rendering::CBookDisplay m_bookDisplay; + + BtBookshelfModel m_dataModel; + + static CSwordBackend * m_instance; + }; /**Returns The list of modules managed by this backend*/ -inline const QList<CSwordModuleInfo*> &CSwordBackend::moduleList() const { +inline const QList<CSwordModuleInfo *> & CSwordBackend::moduleList() const { return m_dataModel.moduleList(); } -inline BtBookshelfModel *CSwordBackend::model() { +inline BtBookshelfModel * CSwordBackend::model() { return &m_dataModel; } /** 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 { +inline sword::SWConfig * CSwordBackend::getConfig() const { return config; } diff --git a/src/backend/managers/referencemanager.cpp b/src/backend/managers/referencemanager.cpp index 0a17645..144ad8c 100644 --- a/src/backend/managers/referencemanager.cpp +++ b/src/backend/managers/referencemanager.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -12,8 +12,10 @@ #include <algorithm> #include <QRegExp> #include <QDebug> -#include "backend/config/cbtconfig.h" +#include "backend/config/btconfig.h" #include "backend/keys/cswordversekey.h" +#include "backend/drivers/cswordmoduleinfo.h" +#include "backend/managers/cswordbackend.h" /** Returns a hyperlink used to be imbedded in the display windows. At the moment the format is sword://module/key */ @@ -250,33 +252,26 @@ const QString ReferenceManager::preferredModule( const ReferenceManager::Type ty switch (type) { case ReferenceManager::Bible: - module = CBTConfig::get(CBTConfig::standardBible); + module = btConfig().getDefaultSwordModuleByType( "standardBible" ); break; - case ReferenceManager::Commentary: - module = CBTConfig::get(CBTConfig::standardCommentary); + module = btConfig().getDefaultSwordModuleByType( "standardCommentary" ); break; - case ReferenceManager::Lexicon: - module = CBTConfig::get(CBTConfig::standardLexicon); + module = btConfig().getDefaultSwordModuleByType( "standardLexicon" ); break; - case ReferenceManager::StrongsHebrew: - module = CBTConfig::get(CBTConfig::standardHebrewStrongsLexicon); + module = btConfig().getDefaultSwordModuleByType( "standardHebrewStrongsLexicon" ); break; - case ReferenceManager::StrongsGreek: - module = CBTConfig::get(CBTConfig::standardGreekStrongsLexicon); + module = btConfig().getDefaultSwordModuleByType( "standardGreekStrongsLexicon" ); break; - case ReferenceManager::MorphHebrew: - module = CBTConfig::get(CBTConfig::standardHebrewMorphLexicon); + module = btConfig().getDefaultSwordModuleByType( "standardHebrewMorphLexicon" ); break; - case ReferenceManager::MorphGreek: - module = CBTConfig::get(CBTConfig::standardGreekMorphLexicon); + module = btConfig().getDefaultSwordModuleByType( "standardGreekMorphLexicon" ); break; - default: module = 0; break; @@ -353,18 +348,18 @@ const QString ReferenceManager::parseVerseReference( const QString& ref, const R // 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++) { + 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()); + sword::ListKey lk = dummy.parseVerseList((*it).toUtf8().constData(), baseKey.key().toUtf8().constData(), true); + Q_ASSERT(!dummy.popError()); //Q_ASSERT(lk.Count()); - if (!lk.Count()) { + if (!lk.getCount()) { ret.append( *it ); //don't change the original continue; } - for (int i = 0; i < lk.Count(); ++i) { + for (int i = 0; i < lk.getCount(); ++i) { if (dynamic_cast<sword::VerseKey*>(lk.getElement(i))) { // a range sword::VerseKey* k = dynamic_cast<sword::VerseKey*>(lk.getElement(i)); Q_ASSERT(k); diff --git a/src/backend/managers/referencemanager.h b/src/backend/managers/referencemanager.h index a07b480..80d00d6 100644 --- a/src/backend/managers/referencemanager.h +++ b/src/backend/managers/referencemanager.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ diff --git a/src/backend/rendering/cbookdisplay.cpp b/src/backend/rendering/cbookdisplay.cpp index 6589e99..e139c6f 100644 --- a/src/backend/rendering/cbookdisplay.cpp +++ b/src/backend/rendering/cbookdisplay.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ diff --git a/src/backend/rendering/cbookdisplay.h b/src/backend/rendering/cbookdisplay.h index 4bd5c22..6ed1bba 100644 --- a/src/backend/rendering/cbookdisplay.h +++ b/src/backend/rendering/cbookdisplay.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ diff --git a/src/backend/rendering/cchapterdisplay.cpp b/src/backend/rendering/cchapterdisplay.cpp index eea2a72..e4fd1a1 100644 --- a/src/backend/rendering/cchapterdisplay.cpp +++ b/src/backend/rendering/cchapterdisplay.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -42,13 +42,13 @@ const QString Rendering::CChapterDisplay::text( Q_ASSERT((module->type() == CSwordModuleInfo::Bible)); if (module->type() == CSwordModuleInfo::Bible) { - ((sword::VerseKey*)(module->module()->getKey()))->Headings(1); //HACK: enable headings for VerseKeys + ((sword::VerseKey*)(module->module()->getKey()))->setIntros(true); //HACK: enable headings for VerseKeys Q_ASSERT(dynamic_cast<const CSBMI*>(module) != 0); const CSBMI *bible = static_cast<const CSBMI*>(module); CSwordVerseKey k1(module); - k1.Headings(1); + k1.setIntros(true); k1.setKey(keyName); if (k1.getChapter() == 1) diff --git a/src/backend/rendering/cchapterdisplay.h b/src/backend/rendering/cchapterdisplay.h index c245c57..b19f103 100644 --- a/src/backend/rendering/cchapterdisplay.h +++ b/src/backend/rendering/cchapterdisplay.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ diff --git a/src/backend/rendering/cdisplayrendering.cpp b/src/backend/rendering/cdisplayrendering.cpp index bd5aa87..cbcc046 100644 --- a/src/backend/rendering/cdisplayrendering.cpp +++ b/src/backend/rendering/cdisplayrendering.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -15,6 +15,7 @@ #include "backend/keys/cswordversekey.h" #include "backend/managers/cdisplaytemplatemgr.h" #include "backend/managers/referencemanager.h" +#include "backend/config/btconfig.h" namespace Rendering { @@ -33,7 +34,7 @@ QString CDisplayRendering::entryLink(const KeyTreeItem &item, const bool isBible = module && (module->type() == CSwordModuleInfo::Bible); CSwordVerseKey vk(module); //only valid for bible modules, i.e. isBible == true - vk.Headings(true); + vk.setIntros(true); if (isBible) { vk.setKey(item.key()); diff --git a/src/backend/rendering/cdisplayrendering.h b/src/backend/rendering/cdisplayrendering.h index 362fc2a..da87b79 100644 --- a/src/backend/rendering/cdisplayrendering.h +++ b/src/backend/rendering/cdisplayrendering.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -11,6 +13,7 @@ #define RENDERINGCDISPLAYRENDERING_H #include "backend/rendering/chtmlexportrendering.h" +#include "backend/config/btconfig.h" namespace Rendering { @@ -27,8 +30,8 @@ class CDisplayRendering : public CHTMLExportRendering { static QString keyToHTMLAnchor(const QString &key); CDisplayRendering( - const DisplayOptions &displayOptions = CBTConfig::getDisplayOptionDefaults(), - const FilterOptions &filterOptions = CBTConfig::getFilterOptionDefaults()); + const DisplayOptions &displayOptions = btConfig().getDisplayOptions(), + const FilterOptions &filterOptions = btConfig().getFilterOptions()); protected: /* Methods: */ diff --git a/src/backend/rendering/centrydisplay.cpp b/src/backend/rendering/centrydisplay.cpp index 7415eda..3dbe63f 100644 --- a/src/backend/rendering/centrydisplay.cpp +++ b/src/backend/rendering/centrydisplay.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -12,7 +12,6 @@ #include <QApplication> #include <QRegExp> -#include "backend/config/cbtconfig.h" #include "backend/drivers/cswordbookmoduleinfo.h" #include "backend/keys/cswordkey.h" #include "backend/keys/cswordversekey.h" @@ -40,10 +39,10 @@ const QString CEntryDisplay::text( //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 + ((sword::VerseKey*)(module->module()->getKey()))->setIntros(true); //HACK: enable headings for VerseKeys CSwordVerseKey k1(module); - k1.Headings(1); + k1.setIntros(true); k1.setKey(keyName); // don't print the key diff --git a/src/backend/rendering/centrydisplay.h b/src/backend/rendering/centrydisplay.h index 50b6447..8773eb7 100644 --- a/src/backend/rendering/centrydisplay.h +++ b/src/backend/rendering/centrydisplay.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -14,7 +16,7 @@ // Sword includes: #include <swdisp.h> - +#include <swmodule.h> class CSwordModuleInfo; struct DisplayOptions; @@ -35,6 +37,8 @@ class CEntryDisplay: public sword::SWDisplay { const DisplayOptions &displayOptions, const FilterOptions &filterOptions); + virtual char display(sword::SWModule& mod) { (void)mod; return 'c';} + }; /* class CEntryDisplay */ } /* namespace Rendering */ diff --git a/src/backend/rendering/chtmlexportrendering.cpp b/src/backend/rendering/chtmlexportrendering.cpp index 0e19897..7c467b1 100644 --- a/src/backend/rendering/chtmlexportrendering.cpp +++ b/src/backend/rendering/chtmlexportrendering.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -65,7 +65,7 @@ QString CHTMLExportRendering::renderEntry(const KeyTreeItem& i, CSwordKey* k) { ret.append(i.getAlternativeContent()); // Q_ASSERT(i.hasChildItems()); - + if (!i.childList()->isEmpty()) { const KeyTree & tree = *i.childList(); @@ -97,7 +97,7 @@ QString CHTMLExportRendering::renderEntry(const KeyTreeItem& i, CSwordKey* k) { CSwordVerseKey* myVK = dynamic_cast<CSwordVerseKey*>(key); if (myVK) { - myVK->Headings(1); + myVK->setIntros(true); } QString renderedText( (modules.count() > 1) ? "\n\t\t<tr>\n" : "\n" ); @@ -128,9 +128,9 @@ QString CHTMLExportRendering::renderEntry(const KeyTreeItem& i, CSwordKey* k) { } else { langAttr = QString("xml:lang=\"") - .append((*mod_Itr)->module()->Lang()) + .append((*mod_Itr)->module()->getLanguage()) .append("\" lang=\"") - .append((*mod_Itr)->module()->Lang()) + .append((*mod_Itr)->module()->getLanguage()) .append("\""); } @@ -139,7 +139,7 @@ QString CHTMLExportRendering::renderEntry(const KeyTreeItem& i, CSwordKey* k) { if (m_filterOptions.headings) { // only process EntryAttributes, do not render, this might destroy the EntryAttributes again - (*mod_Itr)->module()->RenderText(0, -1, 0); + (*mod_Itr)->module()->renderText(0, -1, 0); sword::AttributeValue::const_iterator it = (*mod_Itr)->module()->getEntryAttributes()["Heading"]["Preverse"].begin(); @@ -150,12 +150,16 @@ QString CHTMLExportRendering::renderEntry(const KeyTreeItem& i, CSwordKey* k) { QString unfiltered = QString::fromUtf8(it->second.c_str()); /// \todo This is only a preliminary workaround to strip the tags: - QRegExp filter("<title>(.*)</title>"); - if (unfiltered.indexOf(filter) >= 0) { - preverseHeading = filter.cap(1); - } else { - preverseHeading = unfiltered; + QRegExp filter("(.*)<title[^>]*>(.*)</title>(.*)"); + while(filter.indexIn(unfiltered) >= 0) { + unfiltered = filter.cap(1) + filter.cap(2) + filter.cap(3); + } + // Fiter out offending self-closing div tags, which are bad HTML + QRegExp ofilter("(.*)<div[^>]*/>(.*)"); + while(ofilter.indexIn(unfiltered) >= 0) { + unfiltered = ofilter.cap(1) + ofilter.cap(2); } + preverseHeading = unfiltered; /// \todo Take care of the heading type! if (!preverseHeading.isEmpty()) { @@ -237,7 +241,9 @@ QString CHTMLExportRendering::finishText(const QString &text, const KeyTree &tre settings.langAbbrev = "unknown"; } - return CDTM::instance()->fillTemplate(QObject::tr("Export"), text, settings); + return CDTM::instance()->fillTemplate(CDisplayTemplateMgr::activeTemplateName(), + text, + settings); } /*! diff --git a/src/backend/rendering/chtmlexportrendering.h b/src/backend/rendering/chtmlexportrendering.h index db90707..51041a3 100644 --- a/src/backend/rendering/chtmlexportrendering.h +++ b/src/backend/rendering/chtmlexportrendering.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -12,7 +14,7 @@ #include "backend/rendering/ctextrendering.h" -#include "backend/config/cbtconfig.h" +#include "backend/config/btconfig.h" #include "backend/managers/cswordbackend.h" #include "btglobal.h" @@ -31,8 +33,10 @@ class CHTMLExportRendering: public CTextRendering { CHTMLExportRendering( bool addText, - const DisplayOptions &displayOptions = CBTConfig::getDisplayOptionDefaults(), - const FilterOptions &filterOptions = CBTConfig::getFilterOptionDefaults()); + const DisplayOptions &displayOptions = btConfig().getDisplayOptions(), + const FilterOptions &filterOptions = btConfig().getFilterOptions()); + + ~CHTMLExportRendering() {}; protected: /* Methods: */ diff --git a/src/backend/rendering/cplaintextexportrendering.cpp b/src/backend/rendering/cplaintextexportrendering.cpp index 4bff025..e462e53 100644 --- a/src/backend/rendering/cplaintextexportrendering.cpp +++ b/src/backend/rendering/cplaintextexportrendering.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ diff --git a/src/backend/rendering/cplaintextexportrendering.h b/src/backend/rendering/cplaintextexportrendering.h index 9360474..45ad8ac 100644 --- a/src/backend/rendering/cplaintextexportrendering.h +++ b/src/backend/rendering/cplaintextexportrendering.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -11,6 +13,7 @@ #define RENDERINGCPLAINTEXTEXPORTRENDERING_H #include "backend/rendering/chtmlexportrendering.h" +#include "backend/config/btconfig.h" namespace Rendering { @@ -26,8 +29,8 @@ class CPlainTextExportRendering: public CHTMLExportRendering { CPlainTextExportRendering( bool addText, - const DisplayOptions &displayOptions = CBTConfig::getDisplayOptionDefaults(), - const FilterOptions &filterOptions = CBTConfig::getFilterOptionDefaults()); + const DisplayOptions &displayOptions = btConfig().getDisplayOptions(), + const FilterOptions &filterOptions = btConfig().getFilterOptions()); protected: /* Methods: */ diff --git a/src/backend/rendering/ctextrendering.cpp b/src/backend/rendering/ctextrendering.cpp index 72e4e12..409a601 100644 --- a/src/backend/rendering/ctextrendering.cpp +++ b/src/backend/rendering/ctextrendering.cpp @@ -2,7 +2,7 @@ * * This file is part of BibleTime's source code, http://www.bibletime.info/. * -* Copyright 1999-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -136,19 +136,19 @@ CTextRendering::KeyTreeItem::KeyTreeItem(const QString &startKey, else { sword::VerseKey vk(startKey.toUtf8().constData(), stopKey.toUtf8().constData()); - if (vk.LowerBound().getBook() != vk.UpperBound().getBook()) { + if (vk.getLowerBound().getBook() != vk.getUpperBound().getBook()) { m_alternativeContent = QString::fromUtf8(vk.getRangeText()); } - else if (vk.LowerBound().getChapter() != vk.UpperBound().getChapter()) { + else if (vk.getLowerBound().getChapter() != vk.getUpperBound().getChapter()) { m_alternativeContent = QString("%1 - %2:%3") - .arg(QString::fromUtf8(vk.LowerBound().getText())) - .arg(vk.UpperBound().getChapter()) - .arg(vk.UpperBound().getVerse()); + .arg(QString::fromUtf8(vk.getLowerBound().getText())) + .arg(vk.getUpperBound().getChapter()) + .arg(vk.getUpperBound().getVerse()); } else { //only verses differ (same book, same chapter) m_alternativeContent = QString("%1 - %2") - .arg(QString::fromUtf8(vk.LowerBound().getText())) - .arg(vk.UpperBound().getVerse()); + .arg(QString::fromUtf8(vk.getLowerBound().getText())) + .arg(vk.getUpperBound().getVerse()); } } @@ -231,8 +231,8 @@ const QString CTextRendering::renderKeyRange( CSwordVerseKey* vk_stop = dynamic_cast<CSwordVerseKey*>(upperBound.data()); Q_ASSERT(vk_stop); - bool ok = true; - while (ok && ((*vk_start < *vk_stop) || (*vk_start == *vk_stop))) { + while ((*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); @@ -249,7 +249,10 @@ const QString CTextRendering::renderKeyRange( vk_start->setVerse(0); } tree.append( new KeyTreeItem(vk_start->key(), modules, settings) ); - ok = vk_start->next(CSwordVerseKey::UseVerse); + if (!vk_start->next(CSwordVerseKey::UseVerse)) { + /// \todo Notify the user about this failure. + break; + } } return renderKeyTree(tree); } diff --git a/src/backend/rendering/ctextrendering.h b/src/backend/rendering/ctextrendering.h index 9d467cc..c62a877 100644 --- a/src/backend/rendering/ctextrendering.h +++ b/src/backend/rendering/ctextrendering.h @@ -1,8 +1,10 @@ /********* * +* 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-2011 by the BibleTime developers. +* Copyright 1999-2014 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ @@ -134,7 +136,7 @@ class CTextRendering { public: /* Methods: */ - virtual inline ~CTextRendering() {} + virtual ~CTextRendering() {}; const QString renderKeyTree(const KeyTree &tree); |