/********* * * 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. * **********/ //BibleTime includes #include "cswordbackend.h" #include "centrydisplay.h" #include "cbookdisplay.h" #include "cchapterdisplay.h" #include "cswordbiblemoduleinfo.h" #include "cswordcommentarymoduleinfo.h" #include "cswordlexiconmoduleinfo.h" #include "cswordbookmoduleinfo.h" #include "bt_thmlhtml.h" #include "bt_thmlplain.h" #include "bt_osishtml.h" #include "bt_gbfhtml.h" #include "bt_plainhtml.h" #include "osismorphsegmentation.h" #include "frontend/cbtconfig.h" #include #include #include //Qt includes #include #include //KDE includes #include #include //Sword includes #include #include #include #include #include #include #include using std::string; using namespace Filters; using namespace Rendering; CSwordBackend::CSwordBackend() : sword::SWMgr(0, 0, false, new sword::EncodingFilterMgr( sword::ENC_UTF8 ), true) { m_displays.entry = 0; m_displays.chapter = 0; m_displays.book = 0; m_filters.gbf = 0; m_filters.thml = 0; m_filters.osis = 0; m_filters.plain = 0; filterInit(); } CSwordBackend::CSwordBackend(const TQString& path, const bool augmentHome) : sword::SWMgr(!path.isEmpty() ? (const char*)path.local8Bit() : 0, false, new sword::EncodingFilterMgr( sword::ENC_UTF8 ), false, augmentHome) // don't allow module renaming, because we load from a path { qDebug("CSwordBackend::CSwordBackend for %s, using %s", path.latin1(), configPath); m_displays.entry = 0; m_displays.chapter = 0; m_displays.book = 0; m_filters.gbf = 0; m_filters.thml = 0; m_filters.osis = 0; m_filters.plain = 0; filterInit(); } CSwordBackend::~CSwordBackend() { shutdownModules(); delete m_filters.gbf; delete m_filters.plain; delete m_filters.thml; delete m_filters.osis; delete m_displays.book; delete m_displays.chapter; delete m_displays.entry; } /** Initializes the Sword modules. */ const CSwordBackend::LoadError CSwordBackend::initModules() { // qWarning("globalSwordConfigPath is %s", globalConfPath); LoadError ret = NoError; shutdownModules(); //remove previous modules m_moduleList.clear(); sword::ModMap::iterator end = Modules.end(); ret = LoadError( Load() ); for (sword::ModMap::iterator it = Modules.begin(); it != end; it++) { sword::SWModule* const curMod = (*it).second; CSwordModuleInfo* newModule = 0; if (!strcmp(curMod->Type(), "Biblical Texts")) { newModule = new CSwordBibleModuleInfo(curMod, this); newModule->module()->Disp( m_displays.chapter ? m_displays.chapter : (m_displays.chapter = new CChapterDisplay) ); } else if (!strcmp(curMod->Type(), "Commentaries")) { newModule = new CSwordCommentaryModuleInfo(curMod, this); newModule->module()->Disp( m_displays.entry ? m_displays.entry : (m_displays.entry = new CEntryDisplay) ); } else if (!strcmp(curMod->Type(), "Lexicons / Dictionaries")) { newModule = new CSwordLexiconModuleInfo(curMod, this); newModule->module()->Disp( m_displays.entry ? m_displays.entry : (m_displays.entry = new CEntryDisplay) ); } else if (!strcmp(curMod->Type(), "Generic Books")) { newModule = new CSwordBookModuleInfo(curMod, this); newModule->module()->Disp( m_displays.book ? m_displays.book : (m_displays.book = new CBookDisplay) ); } if (newModule) { //append the new modules to our list, but only if it's supported //the constructor of CSwordModuleInfo prints a waring on stdout if (!newModule->hasVersion() || (newModule->minimumSwordVersion() <= sword::SWVersion::currentVersion)) { m_moduleList.append( newModule ); } } } ListCSwordModuleInfo::iterator end_it = m_moduleList.end(); for (ListCSwordModuleInfo::iterator it = m_moduleList.begin() ; it != end_it; ++it) { // for (m_moduleList.first(); m_moduleList.current(); m_moduleList.next()) { m_moduleDescriptionMap.insert( (*it)->config(CSwordModuleInfo::Description), (*it)->name() ); } //unlock modules if keys are present // ListCSwordModuleInfo::iterator end_it = m_moduleList.end(); for (ListCSwordModuleInfo::iterator it = m_moduleList.begin() ; it != end_it; ++it) { // for (m_moduleList.first(); m_moduleList.current(); m_moduleList.next()) { if ( (*it)->isEncrypted() ) { const TQString unlockKey = CBTConfig::getModuleEncryptionKey( (*it)->name() ).latin1(); if (!unlockKey.isNull()) { setCipherKey( (*it)->name().latin1(), unlockKey.latin1() ); } } } 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 == "GBF") { if (!m_filters.gbf) { m_filters.gbf = new BT_GBFHTML(); } module->AddRenderFilter(m_filters.gbf); noDriver = false; } else if (sourceformat == "PLAIN") { if (!m_filters.plain) { m_filters.plain = new BT_PLAINHTML(); } module->AddRenderFilter(m_filters.plain); noDriver = false; } else if (sourceformat == "ThML") { if (!m_filters.thml) { m_filters.thml = new BT_ThMLHTML(); } module->AddRenderFilter(m_filters.thml); noDriver = false; } else if (sourceformat == "OSIS") { if (!m_filters.osis) { m_filters.osis = new BT_OSISHTML(); } module->AddRenderFilter(m_filters.osis); noDriver = false; } if (noDriver) { //no driver found if ( (moduleDriver == "RawCom") || (moduleDriver == "RawLD") ) { if (!m_filters.plain) { m_filters.plain = new BT_PLAINHTML(); } module->AddRenderFilter(m_filters.plain); noDriver = false; } } } /** This function deinitializes the modules and deletes them. */ const bool CSwordBackend::shutdownModules() { ListCSwordModuleInfo::iterator it = m_moduleList.begin(); ListCSwordModuleInfo::iterator end = m_moduleList.end(); while (it != end) { CSwordModuleInfo* current = (*it); it = m_moduleList.remove(it); delete current; } Q_ASSERT(m_moduleList.count() == 0); //BT mods are deleted now, delete Sword mods, too. DeleteMods(); return true; } /** Returns true if the given option is enabled. */ const bool CSwordBackend::isOptionEnabled( const CSwordModuleInfo::FilterTypes type) { return (getGlobalOption( optionName(type).latin1() ) == "On"); } /** Sets the given options enabled or disabled depending on the second parameter. */ void CSwordBackend::setOption( const CSwordModuleInfo::FilterTypes type, const int state ) { sword::SWBuf value; switch (type) { case CSwordModuleInfo::textualVariants: if (state == 0) { value = "Primary Reading"; } else if (state == 1) { value = "Secondary Reading"; } else { value = "All Readings"; } break; default: value = state ? "On": "Off"; break; }; if (value.length()) setGlobalOption(optionName(type).latin1(), value.c_str()); } void CSwordBackend::setFilterOptions( const CSwordBackend::FilterOptions options) { setOption( CSwordModuleInfo::footnotes, options.footnotes ); setOption( CSwordModuleInfo::strongNumbers, options.strongNumbers ); setOption( CSwordModuleInfo::headings, options.headings ); setOption( CSwordModuleInfo::morphTags, options.morphTags ); setOption( CSwordModuleInfo::lemmas, options.lemmas ); setOption( CSwordModuleInfo::hebrewPoints, options.hebrewPoints ); setOption( CSwordModuleInfo::hebrewCantillation, options.hebrewCantillation ); setOption( CSwordModuleInfo::greekAccents, options.greekAccents ); setOption( CSwordModuleInfo::redLetterWords, options.redLetterWords ); setOption( CSwordModuleInfo::textualVariants, options.textualVariants ); setOption( CSwordModuleInfo::morphSegmentation, options.morphSegmentation ); // setOption( CSwordModuleInfo::transliteration, options.transliteration ); setOption( CSwordModuleInfo::scriptureReferences, options.scriptureReferences); } void CSwordBackend::setDisplayOptions( const CSwordBackend::DisplayOptions ) { /* if (m_displays.entry) { m_displays.entry->setDisplayOptions(options); } if (m_displays.chapter) { m_displays.chapter->setDisplayOptions(options); } if (m_displays.book) { m_displays.book->setDisplayOptions(options); } */ } /** This function searches for a module with the specified description */ CSwordModuleInfo* const CSwordBackend::findModuleByDescription(const TQString& description) { CSwordModuleInfo* ret = 0; ListCSwordModuleInfo::iterator end_it = m_moduleList.end(); for (ListCSwordModuleInfo::iterator it = m_moduleList.begin() ; it != end_it; ++it) { if ( (*it)->config(CSwordModuleInfo::Description) == description ) { ret = *it; break; } } return ret; } /** This function searches for a module with the specified description */ const TQString CSwordBackend::findModuleNameByDescription(const TQString& description) { if (m_moduleDescriptionMap.contains(description)) { return m_moduleDescriptionMap[description]; } return TQString::null; } /** This function searches for a module with the specified name */ CSwordModuleInfo* const CSwordBackend::findModuleByName(const TQString& name) { CSwordModuleInfo* ret = 0; ListCSwordModuleInfo::iterator end_it = m_moduleList.end(); for (ListCSwordModuleInfo::iterator it = m_moduleList.begin() ; it != end_it; ++it) { if ( (*it)->name() == name ) { ret = *it; break; } } return ret; } CSwordModuleInfo* const CSwordBackend::findSwordModuleByPointer(const sword::SWModule* const swmodule) { CSwordModuleInfo* ret = 0; ListCSwordModuleInfo::iterator end_it = m_moduleList.end(); for (ListCSwordModuleInfo::iterator it = m_moduleList.begin() ; it != end_it; ++it) { if ( (*it)->module() == swmodule ) { ret = *it; break; } } return ret; } CSwordModuleInfo* const CSwordBackend::findModuleByPointer(const CSwordModuleInfo* const module) { CSwordModuleInfo* ret = 0; ListCSwordModuleInfo::iterator end_it = m_moduleList.end(); for (ListCSwordModuleInfo::iterator it = m_moduleList.begin() ; it != end_it; ++it) { if ( (*it) == module ) { ret = *it; break; } } return ret; } /** 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. */ const bool CSwordBackend::moduleConfig(const TQString& module, sword::SWConfig& moduleConfig) { sword::SectionMap::iterator section; DIR *dir = opendir(configPath); struct dirent *ent; bool foundConfig = false; TQString modFile; if (dir) { // find and update .conf file rewinddir(dir); while ((ent = readdir(dir)) && !foundConfig) { if ((strcmp(ent->d_name, ".")) && (strcmp(ent->d_name, ".."))) { modFile.setLatin1(configPath); modFile.append("/"); modFile.append( TQString::fromLocal8Bit(ent->d_name) ); moduleConfig = sword::SWConfig( (const char*)modFile.local8Bit() ); section = moduleConfig.Sections.find( (const char*)module.local8Bit() ); foundConfig = ( section != moduleConfig.Sections.end() ); } } closedir(dir); } else { //try to read mods.conf moduleConfig = sword::SWConfig("");//global config section = config->Sections.find( (const char*)module.local8Bit() ); foundConfig = ( section != config->Sections.end() ); sword::ConfigEntMap::iterator entry; if (foundConfig) { //copy module section for (entry = (*section).second.begin(); entry != (*section).second.end(); entry++) { moduleConfig.Sections[(*section).first].insert(sword::ConfigEntMap::value_type((*entry).first, (*entry).second)); } } } if (!foundConfig && configType != 2) { //search in $HOME/.sword/ TQString myPath(getenv("HOME")); myPath.append("/.sword/mods.d"); dir = opendir(myPath.latin1()); if (dir) { rewinddir(dir); while ((ent = readdir(dir)) && !foundConfig) { if ((strcmp(ent->d_name, ".")) && (strcmp(ent->d_name, ".."))) { modFile = myPath; modFile.append('/'); modFile.append(ent->d_name); moduleConfig = sword::SWConfig( (const char*)modFile.local8Bit() ); section = moduleConfig.Sections.find( (const char*)module.local8Bit() ); foundConfig = ( section != moduleConfig.Sections.end() ); } } closedir(dir); } } return foundConfig; } /** Returns the text used for the option given as parameter. */ const TQString CSwordBackend::optionName( const CSwordModuleInfo::FilterTypes option ) { switch (option) { case CSwordModuleInfo::footnotes: return TQString("Footnotes"); case CSwordModuleInfo::strongNumbers: return TQString("Strong's Numbers"); case CSwordModuleInfo::headings: return TQString("Headings"); case CSwordModuleInfo::morphTags: return TQString("Morphological Tags"); case CSwordModuleInfo::lemmas: return TQString("Lemmas"); case CSwordModuleInfo::hebrewPoints: return TQString("Hebrew Vowel Points"); case CSwordModuleInfo::hebrewCantillation: return TQString("Hebrew Cantillation"); case CSwordModuleInfo::greekAccents: return TQString("Greek Accents"); case CSwordModuleInfo::redLetterWords: return TQString("Words of Christ in Red"); case CSwordModuleInfo::textualVariants: return TQString("Textual Variants"); case CSwordModuleInfo::scriptureReferences: return TQString("Cross-references"); case CSwordModuleInfo::morphSegmentation: return TQString("Morph Segmentation"); // case CSwordModuleInfo::transliteration: // return TQString("Transliteration"); } return TQString::null; } /** Returns the translated name of the option given as parameter. */ const TQString CSwordBackend::translatedOptionName(const CSwordModuleInfo::FilterTypes option) { switch (option) { case CSwordModuleInfo::footnotes: return i18n("Footnotes"); case CSwordModuleInfo::strongNumbers: return i18n("Strong's numbers"); case CSwordModuleInfo::headings: return i18n("Headings"); case CSwordModuleInfo::morphTags: return i18n("Morphological tags"); case CSwordModuleInfo::lemmas: return i18n("Lemmas"); case CSwordModuleInfo::hebrewPoints: return i18n("Hebrew vowel points"); case CSwordModuleInfo::hebrewCantillation: return i18n("Hebrew cantillation marks"); case CSwordModuleInfo::greekAccents: return i18n("Greek accents"); case CSwordModuleInfo::redLetterWords: return i18n("Red letter words"); case CSwordModuleInfo::textualVariants: return i18n("Textual variants"); case CSwordModuleInfo::scriptureReferences: return i18n("Scripture cross-references"); case CSwordModuleInfo::morphSegmentation: return i18n("Morph segmentation"); // case CSwordModuleInfo::transliteration: // return i18n("Transliteration between scripts"); } return TQString::null; } const TQString CSwordBackend::configOptionName( const CSwordModuleInfo::FilterTypes option ) { switch (option) { case CSwordModuleInfo::footnotes: return TQString("Footnotes"); case CSwordModuleInfo::strongNumbers: return TQString("Strongs"); case CSwordModuleInfo::headings: return TQString("Headings"); case CSwordModuleInfo::morphTags: return TQString("Morph"); case CSwordModuleInfo::lemmas: return TQString("Lemma"); case CSwordModuleInfo::hebrewPoints: return TQString("HebrewPoints"); case CSwordModuleInfo::hebrewCantillation: return TQString("Cantillation"); case CSwordModuleInfo::greekAccents: return TQString("GreekAccents"); case CSwordModuleInfo::redLetterWords: return TQString("RedLetterWords"); case CSwordModuleInfo::textualVariants: return TQString("Variants"); case CSwordModuleInfo::scriptureReferences: return TQString("Scripref"); case CSwordModuleInfo::morphSegmentation: return TQString("MorphSegmentation"); default: return TQString::null; } return TQString::null; } const TQString CSwordBackend::booknameLanguage( const TQString& language ) { if (!language.isEmpty()) { sword::LocaleMgr::getSystemLocaleMgr()->setDefaultLocaleName( language.latin1() ); //refresh the locale of all Bible and commentary modules! const ListCSwordModuleInfo::iterator end_it = m_moduleList.end(); //use what sword returns, language may be different TQString newLocaleName( sword::LocaleMgr::getSystemLocaleMgr()->getDefaultLocaleName() ); for (ListCSwordModuleInfo::iterator it = m_moduleList.begin(); it != end_it; ++it) { if ( ((*it)->type() == CSwordModuleInfo::Bible) || ((*it)->type() == CSwordModuleInfo::Commentary) ) { //Create a new key, it will get the default bookname language ((sword::VerseKey*)((*it)->module()->getKey()))->setLocale( newLocaleName.latin1() ); } } } return TQString( sword::LocaleMgr::getSystemLocaleMgr()->getDefaultLocaleName() ); } /** Reload all Sword modules. */ void CSwordBackend::reloadModules() { shutdownModules(); //delete Sword's config to make Sword reload it! if (myconfig) { // force reload on config object because we may have changed the paths delete myconfig; config = myconfig = 0; loadConfigDir(configPath); } else if (config) { config->Load(); } initModules(); } const TQStringList CSwordBackend::swordDirList() { TQStringList ret; const TQString home = TQString(getenv("HOME")); //return a list of used Sword dirs. Useful for the installer TQString configPath = TQString("%1/.sword/sword.conf").arg(home); if (!TQFile(configPath).exists()) { configPath = globalConfPath; //e.g. /etc/sword.conf, /usr/local/etc/sword.conf } TQStringList configs = TQStringList::split(":", configPath); /*ToDo: Use the const iterator as soon as we switch to Qt > 3.1 for (TQStringList::const_iterator it = configs.constBegin(); it != configs.constEnd(); ++it) {*/ for (TQStringList::const_iterator it = configs.begin(); it != configs.end(); ++it) { if (!TQFileInfo(*it).exists()) { continue; } //get all DataPath and AugmentPath entries from the config file and add them to the list sword::SWConfig conf( (*it).latin1() ); ret << conf["Install"]["DataPath"].c_str(); sword::ConfigEntMap group = conf["Install"]; sword::ConfigEntMap::iterator start = group.equal_range("AugmentPath").first; sword::ConfigEntMap::iterator end = group.equal_range("AugmentPath").second; for (sword::ConfigEntMap::const_iterator it = start; it != end; ++it) { ret << it->second.c_str(); //added augment path } } if (!home.isEmpty()) { ret << home + "/.sword/"; } return ret; } void CSwordBackend::filterInit() { // qWarning("## INIT"); SWOptionFilter* tmpFilter = new OSISMorphSegmentation(); optionFilters.insert(OptionFilterMap::value_type("OSISMorphSegmentation", tmpFilter)); cleanupFilters.push_back(tmpFilter); //HACK: replace Sword's ThML strip filter with our own version //remove this hack as soon as Sword is fixed cleanupFilters.remove(thmlplain); delete thmlplain; thmlplain = new BT_ThMLPlain(); cleanupFilters.push_back(thmlplain); }