/*********
*
* 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 ;
}