diff options
Diffstat (limited to 'src/backend/drivers/cswordmoduleinfo.cpp')
-rw-r--r-- | src/backend/drivers/cswordmoduleinfo.cpp | 924 |
1 files changed, 454 insertions, 470 deletions
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; } - |