Bibletime – a bible study tool
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.

creferencemanager.cpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. /*********
  2. *
  3. * This file is part of BibleTime's source code, http://www.bibletime.info/.
  4. *
  5. * Copyright 1999-2006 by the BibleTime developers.
  6. * The BibleTime source code is licensed under the GNU General Public License version 2.0.
  7. *
  8. **********/
  9. #include "creferencemanager.h"
  10. #include "cswordversekey.h"
  11. #include "../frontend/cbtconfig.h"
  12. //QT includes
  13. #include <tqregexp.h>
  14. //stl includes
  15. #include <algorithm> // STL algorithms class library
  16. /** Returns a hyperlink used to be imbedded in the display windows. At the moment the format is sword://module/key */
  17. const TQString CReferenceManager::encodeHyperlink( const TQString moduleName, const TQString key, const CReferenceManager::Type type) {
  18. TQString ret = TQString::null;
  19. switch (type) {
  20. case Bible:
  21. ret.setLatin1("sword://Bible/");
  22. break;
  23. case Commentary:
  24. ret.setLatin1("sword://Commentary/");
  25. break;
  26. case Lexicon:
  27. ret.setLatin1("sword://Lexicon/");
  28. break;
  29. case GenericBook:
  30. ret.setLatin1("sword://Book/");
  31. break;
  32. case MorphHebrew:
  33. ret.setLatin1("morph://Hebrew/");
  34. break;
  35. case MorphGreek:
  36. ret.setLatin1("morph://Greek/");
  37. break;
  38. case StrongsHebrew:
  39. ret.setLatin1("strongs://Hebrew/");
  40. break;
  41. case StrongsGreek:
  42. ret.setLatin1("strongs://Greek/");
  43. break;
  44. default:
  45. break;
  46. }
  47. if (!moduleName.isEmpty()) {
  48. ret.append( moduleName ).append('/');
  49. }
  50. else { //if module is empty use fallback module
  51. ret.append( preferredModule(type) ).append('/');
  52. }
  53. if (type == GenericBook) {
  54. const TQString s = (!key.isEmpty() ? key : TQString::null);
  55. TQString newKey = TQString::null;
  56. //replace all / of the key (e.g. of a CSwordTreeKey) with
  57. // the escape sequence \/ so we know it's a link internal divider (e.g. of CSwordTreeKey)!
  58. TQChar c;
  59. for(unsigned int i = 0; i < s.length(); ++i) {
  60. c = s.at(i);
  61. if (c == '/') {
  62. newKey.append("\\/");
  63. }
  64. else {
  65. newKey.append(c);
  66. }
  67. }
  68. ret.append( newKey );
  69. }
  70. else { //slashes do not appear in verses and dictionary entries
  71. switch (type) {
  72. case Bible: //bibles or commentary keys need parsing
  73. case Commentary: {
  74. /* CSwordModuleInfo* mod = CPointers::backend()->findModuleByName(moduleName);
  75. ParseOptions options;
  76. options.refDestinationModule = mod->name();
  77. options.refBase =
  78. options.sourceLanguage = mod->module()->Lang();
  79. options.destinationLanguage = "en";
  80. ret.append( parseVerseReference(key, options) ); //we add the english key, so drag and drop will work in all cases*/
  81. ret.append(key);
  82. break;
  83. }
  84. default:
  85. ret.append( key ); //use the standard key, no parsing required
  86. break;
  87. }
  88. }
  89. return ret;
  90. }
  91. /** Decodes the given hyperlink to module and key. */
  92. const bool CReferenceManager::decodeHyperlink( const TQString& hyperlink, TQString& module, TQString& key, CReferenceManager::Type& type ) {
  93. /**
  94. * We have to decide between three types of URLS: sword://Type/Module/Key, morph://Testament/key and strongs://Testament/Key
  95. */
  96. module = TQString::null;
  97. key = TQString::null;
  98. type = Unknown; //not yet known
  99. TQString ref = hyperlink;
  100. //remove the trailing slash
  101. if (ref.right(1)=="/" && ref.right(2) != "\\/") //trailing slash, but not escaped
  102. ref = ref.left(ref.length()-1);
  103. //find out which type we have by looking at the beginning (protocoll section of URL)
  104. if (ref.left(8).lower() == "sword://") { //Bible, Commentary or Lexicon
  105. ref = ref.mid(8);
  106. if (ref.left(5).lower() == "bible") { //a bible hyperlink
  107. type = CReferenceManager::Bible;
  108. ref = ref.mid(6); //inclusive trailing slash
  109. }
  110. else if (ref.left(10).lower() == "commentary") { // a Commentary hyperlink
  111. type = CReferenceManager::Commentary;
  112. ref = ref.mid(11); //inclusive trailing slash
  113. }
  114. else if (ref.left(7).lower() == "lexicon") { // a Lexicon hyperlink
  115. type = CReferenceManager::Lexicon;
  116. ref = ref.mid(8); //inclusive trailing slash
  117. }
  118. else if (ref.left(4).lower() == "book") { // a Book hyperlink
  119. type = CReferenceManager::GenericBook;
  120. ref = ref.mid(5); //inclusive trailing slash
  121. }
  122. // string up to next slash is the modulename
  123. if (ref.at(0) != '/' ) { //we have a module given
  124. while (true) {
  125. const int pos = ref.find("/");
  126. if ((pos>0) && ref.at(pos-1) != '\\') { //found a slash which is not escaped
  127. module = ref.mid(0,pos);
  128. ref = ref.mid(pos+1);
  129. break;
  130. }
  131. else if (pos == -1) {
  132. break;
  133. }
  134. }
  135. // the rest is the key
  136. key = ref;
  137. }
  138. else {
  139. key = ref.mid(1);
  140. }
  141. //the key may be an osis key like "NASBLex:Moses", which sets the module, too
  142. // const int modPos = key.find(":");
  143. // if (modPos != -1 && key.at(modPos-1).isLetter() && key.at(modPos+1).isLetter()) {
  144. // module = key.left(modPos);
  145. // key = key.mid(modPos+1);
  146. //
  147. // qWarning("found the module name %s with key %s", module.latin1(), key.latin1());
  148. // }
  149. //replace \/ escapes with /
  150. key.replace(TQRegExp("\\\\/"), "/");
  151. }
  152. else if (ref.left(8).lower() == "morph://" || ref.left(10).lower() == "strongs://") { //strongs or morph URL have the same format
  153. enum PreType {IsMorph, IsStrongs};
  154. PreType preType = IsMorph;
  155. if (ref.left(8).lower() == "morph://") { //morph code hyperlink
  156. ref = ref.mid(8);
  157. preType = IsMorph;
  158. }
  159. else if (ref.left(10).lower() == "strongs://") {
  160. ref = ref.mid(10);
  161. preType = IsStrongs;
  162. }
  163. //part up to next slash is the language
  164. const int pos = ref.find("/");
  165. if (pos>0) { //found
  166. const TQString language = ref.mid(0,pos);
  167. if (language.lower() == "hebrew") {
  168. switch (preType) {
  169. case IsMorph:
  170. type = CReferenceManager::MorphHebrew;
  171. break;
  172. case IsStrongs:
  173. type = CReferenceManager::StrongsHebrew;
  174. break;
  175. }
  176. }
  177. else if (language.lower() == "greek") {
  178. switch (preType) {
  179. case IsMorph:
  180. type = CReferenceManager::MorphGreek;
  181. break;
  182. case IsStrongs:
  183. type = CReferenceManager::StrongsGreek;
  184. break;
  185. }
  186. }
  187. ref = ref.mid(pos+1);
  188. key = ref; //the remaining part is the key
  189. module = preferredModule(type);
  190. }
  191. }
  192. if (key.isEmpty() && module.isEmpty())
  193. return false;
  194. return true;
  195. }
  196. const TQString CReferenceManager::encodeReference(const TQString &module, const TQString &reference) {
  197. //return TQString("(%1)%2").arg(module).arg(reference);
  198. return TQString("(").append(module).append(")").append(reference);
  199. }
  200. void CReferenceManager::decodeReference(TQString &dragreference, TQString &module, TQString &reference) {
  201. const int pos = dragreference.find(")");
  202. const TQString fallbackModule = dragreference.mid( 1, pos - 1);
  203. dragreference = dragreference.mid(pos+1);
  204. module = fallbackModule;
  205. reference = dragreference;
  206. }
  207. /** Returns true if the parameter is a hyperlink. */
  208. const bool CReferenceManager::isHyperlink( const TQString& hyperlink ) {
  209. return ( hyperlink.left(8) == "sword://")
  210. || (hyperlink.left(10) == "strongs://")
  211. || (hyperlink.left(8) == "morph://");
  212. }
  213. /** Returns the preferred module name for the given type. */
  214. const TQString CReferenceManager::preferredModule( const CReferenceManager::Type type ) {
  215. TQString moduleName = TQString::null;
  216. CSwordModuleInfo* module = 0;
  217. switch (type) {
  218. case CReferenceManager::Bible:
  219. module = CBTConfig::get
  220. ( CBTConfig::standardBible );
  221. break;
  222. case CReferenceManager::Commentary:
  223. module = CBTConfig::get
  224. ( CBTConfig::standardCommentary );
  225. break;
  226. case CReferenceManager::Lexicon:
  227. module = CBTConfig::get
  228. ( CBTConfig::standardLexicon );
  229. break;
  230. case CReferenceManager::StrongsHebrew:
  231. module = CBTConfig::get
  232. ( CBTConfig::standardHebrewStrongsLexicon );
  233. break;
  234. case CReferenceManager::StrongsGreek:
  235. module = CBTConfig::get
  236. ( CBTConfig::standardGreekStrongsLexicon );
  237. break;
  238. case CReferenceManager::MorphHebrew:
  239. module = CBTConfig::get
  240. ( CBTConfig::standardHebrewMorphLexicon );
  241. break;
  242. case CReferenceManager::MorphGreek:
  243. module = CBTConfig::get
  244. ( CBTConfig::standardGreekMorphLexicon );
  245. break;
  246. default:
  247. module = 0;
  248. break;
  249. }
  250. return module ? module->name() : TQString::null;
  251. }
  252. /** No descriptions */
  253. CReferenceManager::Type CReferenceManager::typeFromModule( const CSwordModuleInfo::ModuleType type) {
  254. switch (type) {
  255. case CSwordModuleInfo::Bible:
  256. return CReferenceManager::Bible;
  257. case CSwordModuleInfo::Commentary:
  258. return CReferenceManager::Commentary;
  259. case CSwordModuleInfo::Lexicon:
  260. return CReferenceManager::Lexicon;
  261. case CSwordModuleInfo::GenericBook:
  262. return CReferenceManager::GenericBook;
  263. default:
  264. return CReferenceManager::Unknown;
  265. }
  266. }
  267. /** Parses the given verse references using the given language and the module.*/
  268. const TQString CReferenceManager::parseVerseReference( const TQString& ref, const CReferenceManager::ParseOptions& options) {
  269. CSwordModuleInfo* const mod = CPointers::backend()->findModuleByName(options.refDestinationModule);
  270. Q_ASSERT(mod);
  271. if (!mod) {
  272. //parsing of non-verse based references is not supported
  273. return ref;
  274. }
  275. if ((mod->type() != CSwordModuleInfo::Bible) && (mod->type() != CSwordModuleInfo::Commentary)) {
  276. qDebug("CReferenceManager: Only verse based modules are supported as ref destination module");
  277. return TQString::null;
  278. }
  279. TQString sourceLanguage = options.sourceLanguage;
  280. TQString destinationLanguage = options.destinationLanguage;
  281. StringList locales = sword::LocaleMgr::getSystemLocaleMgr()->getAvailableLocales();
  282. if (/*options.sourceLanguage == "en" ||*/ std::find(locales.begin(), locales.end(), sourceLanguage) == locales.end()) { //sourceLanguage not available
  283. sourceLanguage = "en_US";
  284. }
  285. if (/*options.destinationLanguage == "en" ||*/ std::find(locales.begin(), locales.end(), sourceLanguage) == locales.end()) { //destination not available
  286. destinationLanguage = "en_US";
  287. }
  288. TQString ret;
  289. TQStringList refList = TQStringList::split(";", ref);
  290. CSwordVerseKey baseKey(0);
  291. baseKey.setLocale( sourceLanguage.latin1() );
  292. baseKey.key( options.refBase ); //probably in the sourceLanguage
  293. baseKey.setLocale( "en_US" ); //english works in all environments as base
  294. // CSwordVerseKey dummy(0);
  295. //HACK: We have to workaround a Sword bug, we have to set the default locale to the same as the sourceLanguage !
  296. const TQString oldLocaleName = CPointers::backend()->booknameLanguage();
  297. CPointers::backend()->booknameLanguage(sourceLanguage);
  298. VerseKey dummy;
  299. dummy.setLocale( sourceLanguage.latin1() );
  300. Q_ASSERT( !strcmp(dummy.getLocale(), sourceLanguage.latin1()) );
  301. // qDebug("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());
  302. for (TQStringList::iterator it = refList.begin(); it != refList.end(); it++) {
  303. //The listkey may contain more than one item, because a ref lik "Gen 1:3,5" is parsed into two single refs
  304. ListKey lk = dummy.ParseVerseList((const char*)(*it).utf8(), (const char*)baseKey.key().utf8(), true);
  305. Q_ASSERT(!dummy.Error());
  306. Q_ASSERT(lk.Count());
  307. if (!lk.Count()) {
  308. ret.append( *it ); //don't change the original
  309. continue;
  310. }
  311. for (int i = 0; i < lk.Count(); ++i) {
  312. if (dynamic_cast<VerseKey*>(lk.getElement(i))) { // a range
  313. VerseKey* k = dynamic_cast<VerseKey*>(lk.getElement(i));
  314. Q_ASSERT(k);
  315. k->setLocale( destinationLanguage.latin1() );
  316. ret.append( TQString::fromUtf8(k->getRangeText()) ).append("; ");
  317. }
  318. else { // a single ref
  319. VerseKey vk;
  320. vk.setLocale( sourceLanguage.latin1() );
  321. vk = lk.getElement(i)->getText();
  322. vk.setLocale( destinationLanguage.latin1() );
  323. ret.append( TQString::fromUtf8(vk.getText()) ).append("; ");
  324. }
  325. }
  326. }
  327. CPointers::backend()->booknameLanguage(oldLocaleName);
  328. // qDebug(" %s", ret.latin1());
  329. return ret;
  330. }