You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
435 lines
12 KiB
435 lines
12 KiB
/*********
|
|
*
|
|
* 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.
|
|
*
|
|
**********/
|
|
|
|
|
|
|
|
#include "creferencemanager.h"
|
|
#include "cswordversekey.h"
|
|
|
|
#include "../frontend/cbtconfig.h"
|
|
|
|
//TQt includes
|
|
#include <tqregexp.h>
|
|
|
|
//stl includes
|
|
#include <algorithm> // STL algorithms class library
|
|
|
|
/** Returns a hyperlink used to be imbedded in the display windows. At the moment the format is sword://module/key */
|
|
const TQString CReferenceManager::encodeHyperlink( const TQString moduleName, const TQString key, const CReferenceManager::Type type) {
|
|
TQString ret = TQString();
|
|
|
|
switch (type) {
|
|
|
|
case Bible:
|
|
ret.setLatin1("sword://Bible/");
|
|
break;
|
|
|
|
case Commentary:
|
|
ret.setLatin1("sword://Commentary/");
|
|
break;
|
|
|
|
case Lexicon:
|
|
ret.setLatin1("sword://Lexicon/");
|
|
break;
|
|
|
|
case GenericBook:
|
|
ret.setLatin1("sword://Book/");
|
|
break;
|
|
|
|
case MorphHebrew:
|
|
ret.setLatin1("morph://Hebrew/");
|
|
break;
|
|
|
|
case MorphGreek:
|
|
ret.setLatin1("morph://Greek/");
|
|
break;
|
|
|
|
case StrongsHebrew:
|
|
ret.setLatin1("strongs://Hebrew/");
|
|
break;
|
|
|
|
case StrongsGreek:
|
|
ret.setLatin1("strongs://Greek/");
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!moduleName.isEmpty()) {
|
|
ret.append( moduleName ).append('/');
|
|
}
|
|
else { //if module is empty use fallback module
|
|
ret.append( preferredModule(type) ).append('/');
|
|
}
|
|
|
|
if (type == GenericBook) {
|
|
const TQString s = (!key.isEmpty() ? key : TQString());
|
|
TQString newKey = TQString();
|
|
//replace all / of the key (e.g. of a CSwordTreeKey) with
|
|
// the escape sequence \/ so we know it's a link internal divider (e.g. of CSwordTreeKey)!
|
|
|
|
TQChar c;
|
|
|
|
for(unsigned int i = 0; i < s.length(); ++i) {
|
|
c = s.at(i);
|
|
|
|
if (c == '/') {
|
|
newKey.append("\\/");
|
|
}
|
|
else {
|
|
newKey.append(c);
|
|
}
|
|
}
|
|
|
|
ret.append( newKey );
|
|
}
|
|
else { //slashes do not appear in verses and dictionary entries
|
|
|
|
switch (type) {
|
|
|
|
case Bible: //bibles or commentary keys need parsing
|
|
|
|
case Commentary: {
|
|
/* CSwordModuleInfo* mod = CPointers::backend()->findModuleByName(moduleName);
|
|
|
|
ParseOptions options;
|
|
options.refDestinationModule = mod->name();
|
|
options.refBase =
|
|
options.sourceLanguage = mod->module()->Lang();
|
|
options.destinationLanguage = "en";
|
|
|
|
ret.append( parseVerseReference(key, options) ); //we add the english key, so drag and drop will work in all cases*/
|
|
ret.append(key);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
ret.append( key ); //use the standard key, no parsing required
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/** Decodes the given hyperlink to module and key. */
|
|
const bool CReferenceManager::decodeHyperlink( const TQString& hyperlink, TQString& module, TQString& key, CReferenceManager::Type& type ) {
|
|
/**
|
|
* We have to decide between three types of URLS: sword://Type/Module/Key, morph://Testament/key and strongs://Testament/Key
|
|
*/
|
|
module = TQString();
|
|
key = TQString();
|
|
|
|
type = Unknown; //not yet known
|
|
TQString ref = hyperlink;
|
|
//remove the trailing slash
|
|
|
|
if (ref.right(1)=="/" && ref.right(2) != "\\/") //trailing slash, but not escaped
|
|
ref = ref.left(ref.length()-1);
|
|
|
|
//find out which type we have by looking at the beginning (protocoll section of URL)
|
|
if (ref.left(8).lower() == "sword://") { //Bible, Commentary or Lexicon
|
|
ref = ref.mid(8);
|
|
|
|
if (ref.left(5).lower() == "bible") { //a bible hyperlink
|
|
type = CReferenceManager::Bible;
|
|
ref = ref.mid(6); //inclusive trailing slash
|
|
}
|
|
else if (ref.left(10).lower() == "commentary") { // a Commentary hyperlink
|
|
type = CReferenceManager::Commentary;
|
|
ref = ref.mid(11); //inclusive trailing slash
|
|
}
|
|
else if (ref.left(7).lower() == "lexicon") { // a Lexicon hyperlink
|
|
type = CReferenceManager::Lexicon;
|
|
ref = ref.mid(8); //inclusive trailing slash
|
|
}
|
|
else if (ref.left(4).lower() == "book") { // a Book hyperlink
|
|
type = CReferenceManager::GenericBook;
|
|
ref = ref.mid(5); //inclusive trailing slash
|
|
}
|
|
|
|
// string up to next slash is the modulename
|
|
if (ref.at(0) != '/' ) { //we have a module given
|
|
|
|
while (true) {
|
|
const int pos = ref.find("/");
|
|
|
|
if ((pos>0) && ref.at(pos-1) != '\\') { //found a slash which is not escaped
|
|
module = ref.mid(0,pos);
|
|
ref = ref.mid(pos+1);
|
|
break;
|
|
}
|
|
else if (pos == -1) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// the rest is the key
|
|
key = ref;
|
|
}
|
|
else {
|
|
key = ref.mid(1);
|
|
}
|
|
|
|
//the key may be an osis key like "NASBLex:Moses", which sets the module, too
|
|
// const int modPos = key.find(":");
|
|
// if (modPos != -1 && key.at(modPos-1).isLetter() && key.at(modPos+1).isLetter()) {
|
|
// module = key.left(modPos);
|
|
// key = key.mid(modPos+1);
|
|
//
|
|
// tqWarning("found the module name %s with key %s", module.latin1(), key.latin1());
|
|
// }
|
|
|
|
//replace \/ escapes with /
|
|
key.replace(TQRegExp("\\\\/"), "/");
|
|
}
|
|
else if (ref.left(8).lower() == "morph://" || ref.left(10).lower() == "strongs://") { //strongs or morph URL have the same format
|
|
enum PreType {IsMorph, IsStrongs};
|
|
PreType preType = IsMorph;
|
|
|
|
if (ref.left(8).lower() == "morph://") { //morph code hyperlink
|
|
ref = ref.mid(8);
|
|
preType = IsMorph;
|
|
}
|
|
else if (ref.left(10).lower() == "strongs://") {
|
|
ref = ref.mid(10);
|
|
preType = IsStrongs;
|
|
}
|
|
|
|
//part up to next slash is the language
|
|
const int pos = ref.find("/");
|
|
|
|
if (pos>0) { //found
|
|
const TQString language = ref.mid(0,pos);
|
|
|
|
if (language.lower() == "hebrew") {
|
|
switch (preType) {
|
|
|
|
case IsMorph:
|
|
type = CReferenceManager::MorphHebrew;
|
|
break;
|
|
|
|
case IsStrongs:
|
|
type = CReferenceManager::StrongsHebrew;
|
|
break;
|
|
}
|
|
}
|
|
else if (language.lower() == "greek") {
|
|
switch (preType) {
|
|
|
|
case IsMorph:
|
|
type = CReferenceManager::MorphGreek;
|
|
break;
|
|
|
|
case IsStrongs:
|
|
type = CReferenceManager::StrongsGreek;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ref = ref.mid(pos+1);
|
|
key = ref; //the remaining part is the key
|
|
|
|
module = preferredModule(type);
|
|
}
|
|
}
|
|
|
|
if (key.isEmpty() && module.isEmpty())
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
const TQString CReferenceManager::encodeReference(const TQString &module, const TQString &reference) {
|
|
//return TQString("(%1)%2").arg(module).arg(reference);
|
|
return TQString("(").append(module).append(")").append(reference);
|
|
}
|
|
|
|
void CReferenceManager::decodeReference(TQString &dragreference, TQString &module, TQString &reference) {
|
|
const int pos = dragreference.find(")");
|
|
const TQString fallbackModule = dragreference.mid( 1, pos - 1);
|
|
dragreference = dragreference.mid(pos+1);
|
|
|
|
module = fallbackModule;
|
|
reference = dragreference;
|
|
}
|
|
|
|
/** Returns true if the parameter is a hyperlink. */
|
|
const bool CReferenceManager::isHyperlink( const TQString& hyperlink ) {
|
|
return ( hyperlink.left(8) == "sword://")
|
|
|| (hyperlink.left(10) == "strongs://")
|
|
|| (hyperlink.left(8) == "morph://");
|
|
}
|
|
|
|
/** Returns the preferred module name for the given type. */
|
|
const TQString CReferenceManager::preferredModule( const CReferenceManager::Type type ) {
|
|
TQString moduleName = TQString();
|
|
CSwordModuleInfo* module = 0;
|
|
|
|
switch (type) {
|
|
|
|
case CReferenceManager::Bible:
|
|
|
|
module = CBTConfig::get
|
|
( CBTConfig::standardBible );
|
|
|
|
break;
|
|
|
|
case CReferenceManager::Commentary:
|
|
module = CBTConfig::get
|
|
( CBTConfig::standardCommentary );
|
|
|
|
break;
|
|
|
|
case CReferenceManager::Lexicon:
|
|
module = CBTConfig::get
|
|
( CBTConfig::standardLexicon );
|
|
|
|
break;
|
|
|
|
case CReferenceManager::StrongsHebrew:
|
|
module = CBTConfig::get
|
|
( CBTConfig::standardHebrewStrongsLexicon );
|
|
|
|
break;
|
|
|
|
case CReferenceManager::StrongsGreek:
|
|
module = CBTConfig::get
|
|
( CBTConfig::standardGreekStrongsLexicon );
|
|
|
|
break;
|
|
|
|
case CReferenceManager::MorphHebrew:
|
|
module = CBTConfig::get
|
|
( CBTConfig::standardHebrewMorphLexicon );
|
|
|
|
break;
|
|
|
|
case CReferenceManager::MorphGreek:
|
|
module = CBTConfig::get
|
|
( CBTConfig::standardGreekMorphLexicon );
|
|
|
|
break;
|
|
|
|
default:
|
|
module = 0;
|
|
|
|
break;
|
|
}
|
|
|
|
return module ? module->name() : TQString();
|
|
}
|
|
|
|
/** No descriptions */
|
|
CReferenceManager::Type CReferenceManager::typeFromModule( const CSwordModuleInfo::ModuleType type) {
|
|
switch (type) {
|
|
|
|
case CSwordModuleInfo::Bible:
|
|
return CReferenceManager::Bible;
|
|
|
|
case CSwordModuleInfo::Commentary:
|
|
return CReferenceManager::Commentary;
|
|
|
|
case CSwordModuleInfo::Lexicon:
|
|
return CReferenceManager::Lexicon;
|
|
|
|
case CSwordModuleInfo::GenericBook:
|
|
return CReferenceManager::GenericBook;
|
|
|
|
default:
|
|
return CReferenceManager::Unknown;
|
|
}
|
|
}
|
|
|
|
/** Parses the given verse references using the given language and the module.*/
|
|
const TQString CReferenceManager::parseVerseReference( const TQString& ref, const CReferenceManager::ParseOptions& options) {
|
|
|
|
CSwordModuleInfo* const mod = CPointers::backend()->findModuleByName(options.refDestinationModule);
|
|
Q_ASSERT(mod);
|
|
|
|
if (!mod) {
|
|
//parsing of non-verse based references is not supported
|
|
return ref;
|
|
}
|
|
|
|
if ((mod->type() != CSwordModuleInfo::Bible) && (mod->type() != CSwordModuleInfo::Commentary)) {
|
|
tqDebug("CReferenceManager: Only verse based modules are supported as ref destination module");
|
|
return TQString();
|
|
}
|
|
|
|
TQString sourceLanguage = options.sourceLanguage;
|
|
TQString destinationLanguage = options.destinationLanguage;
|
|
|
|
StringList locales = sword::LocaleMgr::getSystemLocaleMgr()->getAvailableLocales();
|
|
if (/*options.sourceLanguage == "en" ||*/ std::find(locales.begin(), locales.end(), sourceLanguage.ascii()) == locales.end()) { //sourceLanguage not available
|
|
sourceLanguage = "en_US";
|
|
}
|
|
|
|
if (/*options.destinationLanguage == "en" ||*/ std::find(locales.begin(), locales.end(), sourceLanguage.ascii()) == locales.end()) { //destination not available
|
|
destinationLanguage = "en_US";
|
|
}
|
|
|
|
|
|
TQString ret;
|
|
TQStringList refList = TQStringList::split(";", ref);
|
|
|
|
CSwordVerseKey baseKey(0);
|
|
baseKey.setLocale( sourceLanguage.latin1() );
|
|
baseKey.key( options.refBase ); //probably in the sourceLanguage
|
|
baseKey.setLocale( "en_US" ); //english works in all environments as base
|
|
|
|
// CSwordVerseKey dummy(0);
|
|
//HACK: We have to workaround a Sword bug, we have to set the default locale to the same as the sourceLanguage !
|
|
const TQString oldLocaleName = CPointers::backend()->booknameLanguage();
|
|
CPointers::backend()->booknameLanguage(sourceLanguage);
|
|
|
|
VerseKey dummy;
|
|
dummy.setLocale( sourceLanguage.latin1() );
|
|
Q_ASSERT( !strcmp(dummy.getLocale(), sourceLanguage.latin1()) );
|
|
|
|
// tqDebug("Parsing '%s' in '%s' using '%s' as base, source lang '%s', dest lang '%s'", ref.latin1(), options.refDestinationModule.latin1(), baseKey.key().latin1(), sourceLanguage.latin1(), destinationLanguage.latin1());
|
|
|
|
for (TQStringList::iterator it = refList.begin(); it != refList.end(); it++) {
|
|
//The listkey may contain more than one item, because a ref lik "Gen 1:3,5" is parsed into two single refs
|
|
ListKey lk = dummy.ParseVerseList((const char*)(*it).utf8(), (const char*)baseKey.key().utf8(), true);
|
|
Q_ASSERT(!dummy.Error());
|
|
|
|
Q_ASSERT(lk.Count());
|
|
if (!lk.Count()) {
|
|
ret.append( *it ); //don't change the original
|
|
continue;
|
|
}
|
|
|
|
for (int i = 0; i < lk.Count(); ++i) {
|
|
if (dynamic_cast<VerseKey*>(lk.getElement(i))) { // a range
|
|
VerseKey* k = dynamic_cast<VerseKey*>(lk.getElement(i));
|
|
Q_ASSERT(k);
|
|
k->setLocale( destinationLanguage.latin1() );
|
|
|
|
ret.append( TQString::fromUtf8(k->getRangeText()) ).append("; ");
|
|
}
|
|
else { // a single ref
|
|
VerseKey vk;
|
|
vk.setLocale( sourceLanguage.latin1() );
|
|
vk = lk.getElement(i)->getText();
|
|
vk.setLocale( destinationLanguage.latin1() );
|
|
|
|
ret.append( TQString::fromUtf8(vk.getText()) ).append("; ");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
CPointers::backend()->booknameLanguage(oldLocaleName);
|
|
// tqDebug(" %s", ret.latin1());
|
|
|
|
return ret;
|
|
}
|