/********* * * This file is part of BibleTime's source code, http://www.bibletime.info/. * * Copyright 1999-2006 by the BibleTime developers. * The BibleTime source code is licensed under the GNU General Public License version 2.0. * **********/ #if defined(HAVE_CONFIG_H) #include "config.h" #endif //BibleTime includes #include "cswordmoduleinfo.h" #include "cswordbackend.h" #include "cswordmodulesearch.h" #include "cswordkey.h" #include "centrydisplay.h" #include "clanguagemgr.h" #include "util/scoped_resource.h" #include "util/directoryutil.h" #include "util/cpointers.h" #include "frontend/cbtconfig.h" #include #include #include #include #include //TQt includes #include #include #include #include //TDE includes #include #include #include #include //Sword includes #include #include #include #include #include #include //Lucence includes #include #ifndef CLUCENE_V2 #include #include #include #endif // CLUCENE_V2 //Increment this, if the index format changes //Then indices on the user's systems will be rebuilt const unsigned int INDEX_VERSION = 6; //Maximum index entry size, 1MiB for now //Lucene default is too small const unsigned long BT_MAX_LUCENE_FIELD_LENGTH = 1024*1024; CSwordModuleInfo::CSwordModuleInfo(sword::SWModule * module, CSwordBackend * const usedBackend) { m_module = module; Q_ASSERT(module); m_searchResult.ClearList(); m_backend = usedBackend ? usedBackend : CPointers::backend(); m_dataCache.name = module ? TQString(module->Name()) : TQString(); m_dataCache.isUnicode = module ? module->isUnicode() : false; m_dataCache.category = UnknownCategory; m_dataCache.language = 0; m_dataCache.hasVersion = !TQString((*m_backend->getConfig())[module->Name()]["Version"]).isEmpty(); if (backend()) { if (hasVersion() && (minimumSwordVersion() > sword::SWVersion::currentVersion)) { tqWarning("The module \"%s\" requires a newer Sword library. Please update to \"Sword %s\".", name().latin1(), (const char *)minimumSwordVersion()); } } } CSwordModuleInfo::CSwordModuleInfo(const CSwordModuleInfo & m) { m_module = m.m_module; m_backend = m.m_backend; m_dataCache = m.m_dataCache; m_searchResult = m.m_searchResult; } /** No descriptions */ CSwordModuleInfo *CSwordModuleInfo::clone() { return new CSwordModuleInfo(*this); } CSwordModuleInfo::~CSwordModuleInfo() { m_searchResult.ClearList(); m_module = 0; //the Sword module object is deleted by the backend } /** Sets the unlock key of the modules and writes the key into the cofig file.*/ const bool CSwordModuleInfo::unlock(const TQString & unlockKey) { if (!isEncrypted()) { return false; } CBTConfig::setModuleEncryptionKey(name(), unlockKey); backend()->setCipherKey(m_module->Name(), unlockKey.latin1()); //TODO: write to Sword config as well return true; } /** This function returns true if this module is locked, otherwise return false. */ const bool CSwordModuleInfo::isLocked() { //still works, but the cipherkey is stored in CBTConfig. //Works because it is set in sword on program startup. if (isEncrypted()) { if (unlockKeyIsValid()) { return false; } return true; } return false; } /** This functions returns true if this module is encrypted (locked or unlocked). */ const bool CSwordModuleInfo::isEncrypted() const { /** * If we have the CipherKey entry the module * is encrypted but not necessarily locked */ //This code is still right, though we do no longer write to the module config files any more sword::ConfigEntMap config = backend()->getConfig()->Sections.find(name().latin1())->second; sword::ConfigEntMap::iterator it = config.find("CipherKey"); if (it != config.end()) { return true; } return false; } /** This function makes an estimate if a module was properly unlocked. * It returns true if the first entry of the module (parsed as Latin1 * byte sequence) is not empty and contains only printable characters. * 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. */ const bool CSwordModuleInfo::unlockKeyIsValid() { (*m_module) = sword::TOP; // This needs to use ::fromLatin1 because if the text is still locked, // a lot of garbage will show up. It will also work with properly decrypted // Unicode text, because all non-ASCII Unicode chars consist of bytes >127 // and therefore contain no control (nonprintable) characters, which are all <127. TQString test = isUnicode() ? TQString::fromUtf8(m_module->getRawEntryBuf().c_str()) : TQString::fromLatin1( m_module->getRawEntryBuf().c_str() ); if (test.isEmpty()) { tqWarning("Unlock key of module %s is NOT valid", name().latin1()); return false; } for (unsigned int i = 0; i <= test.length(); i++) { if ( !test[i].isPrint() && !test[i].isNull() ) { tqWarning("Unlock key of module %s is NOT valid", name().latin1()); return false; } } tqDebug("Unlock key of module %s is valid", name().latin1()); return true; } const TQString CSwordModuleInfo::getGlobalBaseIndexLocation() { return TDEGlobal::dirs()->saveLocation("data", "bibletime/indices"); } const TQString CSwordModuleInfo::getModuleBaseIndexLocation() const { return getGlobalBaseIndexLocation() + TQString("/") + name().ascii(); } const TQString CSwordModuleInfo::getModuleStandardIndexLocation() const { //this for now returns the location of the main index return getModuleBaseIndexLocation() + TQString("/standard"); } const bool CSwordModuleInfo::hasIndex() { //this will return true only //if the index exists and has correct version information for both index and module TQDir d; if (!d.exists( getModuleStandardIndexLocation() )) { return false; } //first check if the index version and module version are ok util::scoped_ptr indexconfig( new TDEConfig( getModuleBaseIndexLocation() + TQString("/bibletime-index.conf") ) ); if (hasVersion()) { if (indexconfig->readEntry("module-version") != TQString(config(CSwordModuleInfo::ModuleVersion)) ) { return false; } } if (indexconfig->readEntry("index-version") != TQString::number( INDEX_VERSION )) { tqDebug("%s: INDEX_VERSION is not compatible with this version of BibleTime.", name().latin1()); return false; } //then check if the index is there return lucene::index::IndexReader::indexExists(getModuleStandardIndexLocation().ascii()); } void CSwordModuleInfo::buildIndex() { wchar_t wcharBuffer[BT_MAX_LUCENE_FIELD_LENGTH + 1]; //we don't want the linked entries indexed again module()->setSkipConsecutiveLinks(true); //Without this we don't get strongs, lemmas, etc backend()->setFilterOptions ( CBTConfig::getFilterOptionDefaults() ); //make sure we reset all important filter options which influcence the plain filters. backend()->setOption( CSwordModuleInfo::strongNumbers, false ); backend()->setOption( CSwordModuleInfo::morphTags, false ); backend()->setOption( CSwordModuleInfo::morphSegmentation, false ); backend()->setOption( CSwordModuleInfo::footnotes, false ); backend()->setOption( CSwordModuleInfo::headings, false ); backend()->setOption( CSwordModuleInfo::scriptureReferences, false ); backend()->setOption( CSwordModuleInfo::redLetterWords, false ); // do not use any stop words const TCHAR* stop_words[] = { NULL }; lucene::analysis::standard::StandardAnalyzer an( stop_words ); TQString index = getModuleStandardIndexLocation(); TQDir dir; dir.mkdir( getGlobalBaseIndexLocation(), true ); dir.mkdir( getModuleBaseIndexLocation(), true ); dir.mkdir( getModuleStandardIndexLocation(), true ); if (lucene::index::IndexReader::indexExists(index.ascii())) { if (lucene::index::IndexReader::isLocked(index.ascii()) ) { lucene::index::IndexReader::unlock(index.ascii()); } } util::scoped_ptr writer( new lucene::index::IndexWriter(index.ascii(), &an, true) ); //always create a new index writer->setMaxFieldLength(BT_MAX_LUCENE_FIELD_LENGTH); writer->setUseCompoundFile(true); //merge segments into a single file #ifndef CLUCENE_V2 writer->setMinMergeDocs(1000); #endif // CLUCENE_V2 *m_module = sword::TOP; unsigned long verseLowIndex = m_module->Index(); *m_module = sword::BOTTOM; unsigned long verseHighIndex = m_module->Index(); //verseLowIndex is not 0 in all cases (i.e. NT-only modules) unsigned long verseIndex = verseLowIndex + 1; const bool isVerseModule = (type() == CSwordModuleInfo::Bible) || (type() == CSwordModuleInfo::Commentary); m_indexingProgress.setValue( TQVariant((int)0) ); m_indexingProgress.activate(); SWKey* key = m_module->getKey(); //VerseKey for bibles VerseKey* vk = dynamic_cast(key); if (vk) { // we have to be sure to insert the english key into the index, otherwise we'd be in trouble if the language changes vk->setLocale("en_US"); //If we have a verse based module, we want to include the pre-chapter etc. headings in the search vk->Headings(1); } //holds UTF-8 data and is faster than TQString TQCString textBuffer; // we start with the first module entry, key is automatically updated // because key is a pointer to the modules key for (*m_module = sword::TOP; !(key->Error()); (*key)++) { //If it is a sword-heading, store in buffer and index later in Verse X:1 if (vk) { if (vk->Verse() == 0) { //tqWarning("key is %s", key->getText()); //tqWarning("text is %s", m_module->StripText()); textBuffer.append( m_module->StripText() ); continue; } } util::scoped_ptr doc(new lucene::document::Document()); //index the key lucene_utf8towcs(wcharBuffer, key->getText(), BT_MAX_LUCENE_FIELD_LENGTH); #ifdef CLUCENE_V2 lucene::document::Field field1(_T("key"), wcharBuffer, lucene::document::Field::STORE_YES | lucene::document::Field::INDEX_NO); doc->add(field1); #else // CLUCENE_V2 doc->add(*lucene::document::Field::UnIndexed(_T("key"), wcharBuffer)); #endif // CLUCENE_V2 // 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); #ifdef CLUCENE_V2 lucene::document::Field field2(_T("key"), wcharBuffer, lucene::document::Field::STORE_NO | lucene::document::Field::INDEX_TOKENIZED); doc->add(field2); #else // CLUCENE_V2 doc->add(*lucene::document::Field::UnStored(_T("content"), wcharBuffer)); #endif // CLUCENE_V2 textBuffer.resize(0); //clean up // index attributes AttributeList::iterator attListI; 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); #ifdef CLUCENE_V2 lucene::document::Field field3(_T("footnote"), wcharBuffer, lucene::document::Field::STORE_NO | lucene::document::Field::INDEX_TOKENIZED); doc->add(field3); #else // CLUCENE_V2 doc->add(*lucene::document::Field::UnStored(_T("footnote"), wcharBuffer)); #endif // CLUCENE_V2 } // for attListI // Headings for (attValueI = m_module->getEntryAttributes()["Heading"]["Preverse"].begin(); attValueI != m_module->getEntryAttributes()["Heading"]["Preverse"].end(); attValueI++) { lucene_utf8towcs(wcharBuffer, attValueI->second, BT_MAX_LUCENE_FIELD_LENGTH); #ifdef CLUCENE_V2 lucene::document::Field field4(_T("heading"), wcharBuffer, lucene::document::Field::STORE_NO | lucene::document::Field::INDEX_TOKENIZED); doc->add(field4); #else // CLUCENE_V2 doc->add(*lucene::document::Field::UnStored(_T("heading"), wcharBuffer)); #endif // CLUCENE_V2 } // for attValueI // Strongs/Morphs for (attListI = m_module->getEntryAttributes()["Word"].begin(); attListI != m_module->getEntryAttributes()["Word"].end(); attListI++) { // for each attribute if (attListI->second["LemmaClass"] == "strong") { lucene_utf8towcs(wcharBuffer, attListI->second["Lemma"], BT_MAX_LUCENE_FIELD_LENGTH); #ifdef CLUCENE_V2 lucene::document::Field field5(_T("strong"), wcharBuffer, lucene::document::Field::STORE_NO | lucene::document::Field::INDEX_TOKENIZED); doc->add(field5); #else // CLUCENE_V2 doc->add(*lucene::document::Field::UnStored(_T("strong"), wcharBuffer)); #endif // CLUCENE_V2 //tqWarning("Adding strong %s", attListI->second["Lemma"].c_str()); } if (attListI->second.find("Morph") != attListI->second.end()) { lucene_utf8towcs(wcharBuffer, attListI->second["Morph"], BT_MAX_LUCENE_FIELD_LENGTH); #ifdef CLUCENE_V2 lucene::document::Field field6(_T("morph"), wcharBuffer, lucene::document::Field::STORE_NO | lucene::document::Field::INDEX_TOKENIZED); doc->add(field6); #else // CLUCENE_V2 doc->add(*lucene::document::Field::UnStored(_T("morph"), wcharBuffer)); #endif // CLUCENE_V2 } } // for attListI writer->addDocument(doc); verseIndex = m_module->Index(); if (verseIndex % 200 == 0) { if (verseHighIndex == verseLowIndex) { //prevent division by zero m_indexingProgress.setValue( TQVariant(0) ); } else { m_indexingProgress.setValue( TQVariant((int)((100*(verseIndex-verseLowIndex))/(verseHighIndex-verseLowIndex))) ); } m_indexingProgress.activate(); } } writer->optimize(); writer->close(); TQString configFilename = getModuleStandardIndexLocation() + TQString("/../bibletime-index.conf"); util::scoped_ptr indexconfig( new TDEConfig( configFilename ) ); if (hasVersion()) { indexconfig->writeEntry("module-version", config(CSwordModuleInfo::ModuleVersion) ); } indexconfig->writeEntry("index-version", INDEX_VERSION); } void CSwordModuleInfo::deleteIndexForModule( TQString name ) { util::filesystem::DirectoryUtil::removeRecursive( getGlobalBaseIndexLocation() + "/" + name ); } unsigned long CSwordModuleInfo::indexSize() const { return util::filesystem::DirectoryUtil::getDirSizeRecursive( getModuleBaseIndexLocation() ); } const bool CSwordModuleInfo::searchIndexed(const TQString& searchedText, sword::ListKey& scope) { char utfBuffer[BT_MAX_LUCENE_FIELD_LENGTH + 1]; wchar_t wcharBuffer[BT_MAX_LUCENE_FIELD_LENGTH + 1]; // work around Swords thread insafety for Bibles and Commentaries util::scoped_ptr < CSwordKey > key(CSwordKey::createInstance(this)); sword::SWKey* s = dynamic_cast < sword::SWKey * >(key.get()); TQPtrList list; list.setAutoDelete( true ); // the list owns the objects const bool isVerseModule = (type() == CSwordModuleInfo::Bible) || (type() == CSwordModuleInfo::Commentary); if (s) { m_module->SetKey(*s); } m_searchResult.ClearList(); try { // do not use any stop words const TCHAR* stop_words[] = { NULL }; lucene::analysis::standard::StandardAnalyzer analyzer( stop_words ); lucene::search::IndexSearcher searcher(getModuleStandardIndexLocation().ascii()); lucene_utf8towcs(wcharBuffer, searchedText.utf8(), BT_MAX_LUCENE_FIELD_LENGTH); util::scoped_ptr q( lucene::queryParser::QueryParser::parse(wcharBuffer, _T("content"), &analyzer) ); #ifdef CLUCENE_V2 util::scoped_ptr h( searcher.search(q, lucene::search::Sort::INDEXORDER()) ); #else // CLUCENE_V2 util::scoped_ptr h( searcher.search(q, lucene::search::Sort::INDEXORDER) ); #endif // CLUCENE_V2 const bool useScope = (scope.Count() > 0); // const bool isVerseModule = (type() == CSwordModuleInfo::Bible) || (type() == CSwordModuleInfo::Commentary); lucene::document::Document* doc = 0; util::scoped_ptr swKey( module()->CreateKey() ); #ifdef CLUCENE_V2 for (unsigned int i = 0; i < h->length(); ++i) { #else // CLUCENE_V2 for (int i = 0; i < h->length(); ++i) { #endif // CLUCENE_V2 doc = &h->doc(i); lucene_wcstoutf8(utfBuffer, doc->get(_T("key")), BT_MAX_LUCENE_FIELD_LENGTH); swKey->setText(utfBuffer); // limit results based on scope //if (searchOptions & CSwordModuleSearch::useScope && scope.Count() > 0){ if (useScope) { for (int j = 0; j < scope.Count(); j++) { VerseKey* vkey = dynamic_cast(scope.getElement(j)); if (vkey->LowerBound().compare(*swKey) <= 0 && vkey->UpperBound().compare(*swKey) >= 0) { m_searchResult.add(*swKey); } } } else { // no scope, give me all buffers m_searchResult.add(*swKey); } } } catch (...) { tqWarning("CLucene exception"); return false; } list.clear(); return (m_searchResult.Count() > 0); } void CSwordModuleInfo::connectIndexingFinished(TQObject* receiver, const char* slot) { m_indexingFinished.connect(receiver, slot); } void CSwordModuleInfo::connectIndexingProgress(TQObject* receiver, const char* slot) { m_indexingProgress.connect(receiver, slot); } void CSwordModuleInfo::disconnectIndexingSignals(TQObject* receiver) { m_indexingProgress.disconnect(receiver); m_indexingFinished.disconnect(receiver); } /** Returns the last search result for this module. */ sword::ListKey & CSwordModuleInfo::searchResult(const sword::ListKey * newResult) { if (newResult) { m_searchResult.copyFrom(*newResult); } return m_searchResult; } /** Clears the last search result. */ void CSwordModuleInfo::clearSearchResult() { m_searchResult.ClearList(); } /** Returns the required Sword version for this module. Returns -1 if no special Sword version is required. */ const sword::SWVersion CSwordModuleInfo::minimumSwordVersion() { return sword::SWVersion(config(CSwordModuleInfo::MinimumSwordVersion).latin1()); } const TQString CSwordModuleInfo::config(const CSwordModuleInfo::ConfigEntry entry) const { switch (entry) { case AboutInformation: { return getFormattedConfigEntry("About"); } case CipherKey: { if (CBTConfig::getModuleEncryptionKey(name()).isNull()) { //fall back! return TQString(m_module->getConfigEntry("CipherKey")); } else { return CBTConfig::getModuleEncryptionKey(name()); }; } case AbsoluteDataPath: { TQString path( getSimpleConfigEntry("AbsoluteDataPath") ); path.replace(TQRegExp("/./"), "/"); // make /abs/path/./modules/ looking better //make sure we have a trailing slash! if (path.right(1) != "/") { path.append('/'); } return path; } case DataPath: { //make sure we remove the dataFile part if it's a Lexicon TQString path(getSimpleConfigEntry("DataPath")); if ((type() == CSwordModuleInfo::GenericBook) || (type() == CSwordModuleInfo::Lexicon)) { int pos = path.findRev("/"); //last slash in the string if (pos != -1) { path = path.left(pos + 1); //include the slash } } return path; } case Description: return getFormattedConfigEntry("Description"); case ModuleVersion: { TQString version(getSimpleConfigEntry("Version")); if (version.isEmpty()) { version = "1.0"; } return version; } case MinimumSwordVersion: { const TQString minimumVersion(getSimpleConfigEntry("MinimumVersion")); return !minimumVersion.isEmpty()? minimumVersion : TQString("0.0"); } case TextDir: { const TQString dir(getSimpleConfigEntry("Direction")); return !dir.isEmpty()? dir : TQString("LtoR"); } case DisplayLevel: { const TQString level(getSimpleConfigEntry("DisplayLevel")); return !level.isEmpty()? level : TQString("1"); } case GlossaryFrom: { if (!category() == Glossary) { return TQString(); }; const TQString lang(getSimpleConfigEntry("GlossaryFrom")); return !lang.isEmpty()? lang : TQString(); } case GlossaryTo: { if (!category() == Glossary) { return TQString(); }; const TQString lang(getSimpleConfigEntry("GlossaryTo")); return !lang.isEmpty()? lang : TQString(); } case Markup: { const TQString markup(getSimpleConfigEntry("SourceType")); return !markup.isEmpty()? markup : TQString("Unknown"); } case DistributionLicense: return getSimpleConfigEntry("DistributionLicense"); case DistributionSource: return getSimpleConfigEntry("DistributionSource"); case DistributionNotes: return getSimpleConfigEntry("DistributionNotes"); case TextSource: return getSimpleConfigEntry("TextSource"); case CopyrightNotes: return getSimpleConfigEntry("CopyrightNotes"); case CopyrightHolder: return getSimpleConfigEntry("CopyrightHolder"); case CopyrightDate: return getSimpleConfigEntry("CopyrightDate"); case CopyrightContactName: return getSimpleConfigEntry("CopyrightContactName"); case CopyrightContactAddress: return getSimpleConfigEntry("CopyrightContactAddress"); case CopyrightContactEmail: return getSimpleConfigEntry("CopyrightContactEmail"); default: return TQString(); } } /** Returns true if the module supports the feature given as parameter. */ const bool CSwordModuleInfo::has(const CSwordModuleInfo::Feature feature) const { switch (feature) { // case StrongsNumbers: // return m_module->getConfig().has("Feature", "StrongsNumber"); case GreekDef: return m_module->getConfig().has("Feature", "GreekDef"); case HebrewDef: return m_module->getConfig().has("Feature", "HebrewDef"); case GreekParse: return m_module->getConfig().has("Feature", "GreekParse"); case HebrewParse: return m_module->getConfig().has("Feature", "HebrewParse"); } return false; } const bool CSwordModuleInfo::has(const CSwordModuleInfo::FilterTypes option) const { //BAD workaround to see if the filter is GBF, OSIS or ThML! const TQString name = backend()->configOptionName(option); if (m_module->getConfig().has("GlobalOptionFilter", TQString(TQString("OSIS").append(name)).latin1())) { return true; } if (m_module->getConfig().has("GlobalOptionFilter", TQString(TQString("GBF").append(name)).latin1())) { return true; } if (m_module->getConfig().has("GlobalOptionFilter", TQString(TQString("ThML").append(name)).latin1())) { return true; } if (m_module->getConfig().has("GlobalOptionFilter", TQString(TQString("UTF8").append(name)).latin1())) { return true; } if (m_module->getConfig().has("GlobalOptionFilter", name.latin1())) { return true; } return false; } /** Returns the text direction of the module's text., */ const CSwordModuleInfo::TextDirection CSwordModuleInfo::textDirection() { if (config(TextDir) == "RtoL") { return CSwordModuleInfo::RightToLeft; } else { return CSwordModuleInfo::LeftToRight; } } /** Writes the new text at the given position into the module. This does only work for writable modules. */ void CSwordModuleInfo::write(CSwordKey * key, const TQString & newText) { module()->KeyText((const char *)key->key().utf8()); //don't store a pointer to the const char* value somewhere because TQCString doesn't keep the value of it module()->setEntry(isUnicode()? (const char *)newText.utf8() : (const char *)newText.local8Bit()); } /** Deletes the current entry and removes it from the module. */ const bool CSwordModuleInfo::deleteEntry(CSwordKey * const key) { module()->KeyText(isUnicode()? (const char *)key->key().utf8() : (const char *)key->key().local8Bit()); if (module()) { module()->deleteEntry(); return true; }; return false; } /** Returns the category of this module. See CSwordModuleInfo::Category for possible values. */ const CSwordModuleInfo::Category CSwordModuleInfo::category() const { if (m_dataCache.category == CSwordModuleInfo::UnknownCategory) { const TQString cat(m_module->getConfigEntry("Category")); if (cat == "Cults / Unorthodox / Questionable Material") { m_dataCache.category = Cult; } else if (cat == "Daily Devotional" || m_module->getConfig().has("Feature", "DailyDevotion")) { m_dataCache.category = DailyDevotional; } else if (cat == "Glossaries" || m_module->getConfig().has("Feature", "Glossary")) { //alow both m_dataCache.category = Glossary; }; } return m_dataCache.category; } /** Returns the display object for this module. */ Rendering::CEntryDisplay * const CSwordModuleInfo::getDisplay() const { return dynamic_cast < Rendering::CEntryDisplay * >(m_module->Disp()); } TQString CSwordModuleInfo::aboutText() const { TQString text; text += ""; text += TQString("") .arg(i18n("Version")) .arg(hasVersion()? config(CSwordModuleInfo::ModuleVersion) : i18n("unknown")); text += TQString("") .arg(i18n("Markup")) .arg(!TQString(m_module->getConfigEntry("SourceType")).isEmpty()? m_module-> getConfigEntry("SourceType") : i18n("unknown").ascii()); text += TQString("") .arg(i18n("Location")) .arg(config(CSwordModuleInfo::AbsoluteDataPath)); text += TQString("") .arg(i18n("Language")) .arg(language()->translatedName()); if (m_module->getConfigEntry("Category")) text += TQString("") .arg(i18n("Category")) .arg(m_module->getConfigEntry("Category")); if (m_module->getConfigEntry("LCSH")) text += TQString("") .arg(i18n("LCSH")) .arg(m_module->getConfigEntry("LCSH")); text += TQString("") .arg(i18n("Writable")) .arg(isWritable()? i18n("yes") : i18n("no")); if (isEncrypted()) text += TQString("") .arg(i18n("Unlock key")) .arg(config(CSwordModuleInfo::CipherKey)); TQString options; unsigned int opts; for (opts = CSwordModuleInfo::filterTypesMIN; opts <= CSwordModuleInfo::filterTypesMAX; ++opts) { if (has(static_cast < CSwordModuleInfo::FilterTypes > (opts))) { if (!options.isEmpty()) { options += TQString::fromLatin1(", "); } options += CSwordBackend::translatedOptionName(static_cast < CSwordModuleInfo::FilterTypes > (opts)); } } if (!options.isEmpty()) { text += TQString("") .arg(i18n("Features")) .arg(options); } text += "
%1%2
%1%2
%1%2
%1%2
%1%2
%1%2
%1%2
%1%2
%1%2

"; if (category() == Cult) //clearly say the module contains cult/questionable materials text += TQString("
%1

") .arg(i18n("Take care, this work contains cult / questionable material!")); text += TQString("%1:
%2") .arg(i18n("About")) .arg(config(AboutInformation)); typedef TQValueList ListConfigEntry; ListConfigEntry entries; entries.append(DistributionLicense); entries.append(DistributionSource); entries.append(DistributionNotes); entries.append(TextSource); entries.append(CopyrightNotes); entries.append(CopyrightHolder); entries.append(CopyrightDate); entries.append(CopyrightContactName); entries.append(CopyrightContactAddress); entries.append(CopyrightContactEmail); typedef TQMap MapConfigEntry; MapConfigEntry entryMap; entryMap[DistributionLicense] = i18n("Distribution license"); entryMap[DistributionSource] = i18n("Distribution source"); entryMap[DistributionNotes] = i18n("Distribution notes"); entryMap[TextSource] = i18n("Text source"); entryMap[CopyrightNotes] = i18n("Copyright notes"); entryMap[CopyrightHolder] = i18n("Copyright holder"); entryMap[CopyrightDate] = i18n("Copyright date"); entryMap[CopyrightContactName] = i18n("Copyright contact name"); entryMap[CopyrightContactAddress] = i18n("Copyright contact address"); entryMap[CopyrightContactEmail] = i18n("Copyright contact email"); text += ("
"); for (ListConfigEntry::iterator it(entries.begin()); it != entries.end(); ++it) { TQString t( config(*it) ); if (!t.isEmpty()) { text += TQString("") .arg(entryMap[*it]) .arg(config(*it)); } } text += "
%1%2
"; return text; } /** Returns the language of the module. */ const CLanguageMgr::Language * const CSwordModuleInfo::language() const { if (!m_dataCache.language) { if (module()) { if (category() == Glossary) { //special handling for glossaries, we use the "from language" as language for the module m_dataCache.language = (CPointers::languageMgr())->languageForAbbrev(config(GlossaryFrom)); } else { m_dataCache.language = (CPointers::languageMgr())->languageForAbbrev(module()->Lang()); } } else { m_dataCache.language = (CPointers::languageMgr())->defaultLanguage(); //default language } } return m_dataCache.language; } /*! \fn CSwordModuleInfo::getSimpleConfigEntry(char* name) */ TQString CSwordModuleInfo::getSimpleConfigEntry(const TQString& name) const { TQString ret = isUnicode() ? TQString::fromUtf8(m_module->getConfigEntry(name.latin1())) : TQString::fromLatin1(m_module->getConfigEntry(name.latin1())); return ret.isEmpty() ? TQString() : ret; } TQString CSwordModuleInfo::getFormattedConfigEntry(const TQString& name) const { SWBuf RTF_Buffer(m_module->getConfigEntry(name.latin1())); sword::RTFHTML RTF_Filter; RTF_Filter.processText(RTF_Buffer, 0, 0); TQString ret = isUnicode() ? TQString::fromUtf8(RTF_Buffer.c_str()) : TQString::fromLatin1(RTF_Buffer.c_str()); return ret.isEmpty() ? TQString() : ret; }