3
* This file is part of BibleTime's source code, http://www.bibletime.info/.
5
* Copyright 1999-2008 by the BibleTime developers.
6
* The BibleTime source code is licensed under the GNU General Public License version 2.0.
10
#include "creferencemanager.h"
11
#include "backend/keys/cswordversekey.h"
13
#include "backend/config/cbtconfig.h"
14
#include "util/cpointers.h"
20
#include <algorithm> // STL algorithms class library
22
/** Returns a hyperlink used to be imbedded in the display windows. At the moment the format is sword://module/key */
23
const QString CReferenceManager::encodeHyperlink( const QString moduleName, const QString key, const CReferenceManager::Type type) {
24
QString ret = QString::null;
29
ret = QString("sword://Bible/");
32
ret = QString("sword://Commentary/");
35
ret = QString("sword://Lexicon/");
38
ret = QString("sword://Book/");
41
ret = QString("morph://Hebrew/");
44
ret = QString("morph://Greek/");
47
ret = QString("strongs://Hebrew/");
50
ret = QString("strongs://Greek/");
56
if (!moduleName.isEmpty()) {
57
ret.append( moduleName ).append('/');
59
else { //if module is empty use fallback module
60
ret.append( preferredModule(type) ).append('/');
63
if (type == GenericBook) {
64
const QString s = (!key.isEmpty() ? key : QString::null);
65
QString newKey = QString::null;
66
//replace all / of the key (e.g. of a CSwordTreeKey) with
67
// the escape sequence \/ so we know it's a link internal divider (e.g. of CSwordTreeKey)!
71
for(int i = 0; i < s.length(); ++i) {
84
else { //slashes do not appear in verses and dictionary entries
88
case Bible: //bibles or commentary keys need parsing
91
/* CSwordModuleInfo* mod = CPointers::backend()->findModuleByName(moduleName);
94
options.refDestinationModule = mod->name();
96
options.sourceLanguage = mod->module()->Lang();
97
options.destinationLanguage = "en";
99
ret.append( parseVerseReference(key, options) ); //we add the english key, so drag and drop will work in all cases*/
105
ret.append( key ); //use the standard key, no parsing required
113
/** Decodes the given hyperlink to module and key. */
114
bool CReferenceManager::decodeHyperlink( const QString& hyperlink, QString& module, QString& key, CReferenceManager::Type& type ) {
116
* We have to decide between three types of URLS: sword://Type/Module/Key, morph://Testament/key and strongs://Testament/Key
118
module = QString::null;
121
type = Unknown; //not yet known
122
QString ref = hyperlink;
123
//remove the trailing slash
125
if (ref.right(1)=="/" && ref.right(2) != "\\/") //trailing slash, but not escaped
126
ref = ref.left(ref.length()-1);
128
//find out which type we have by looking at the beginning (protocoll section of URL)
129
if (ref.left(8).toLower() == "sword://") { //Bible, Commentary or Lexicon
132
if (ref.left(5).toLower() == "bible") { //a bible hyperlink
133
type = CReferenceManager::Bible;
134
ref = ref.mid(6); //inclusive trailing slash
136
else if (ref.left(10).toLower() == "commentary") { // a Commentary hyperlink
137
type = CReferenceManager::Commentary;
138
ref = ref.mid(11); //inclusive trailing slash
140
else if (ref.left(7).toLower() == "lexicon") { // a Lexicon hyperlink
141
type = CReferenceManager::Lexicon;
142
ref = ref.mid(8); //inclusive trailing slash
144
else if (ref.left(4).toLower() == "book") { // a Book hyperlink
145
type = CReferenceManager::GenericBook;
146
ref = ref.mid(5); //inclusive trailing slash
149
// string up to next slash is the modulename
150
if (ref.at(0) != '/' ) { //we have a module given
153
const int pos = ref.indexOf("/");
155
if ((pos>0) && ref.at(pos-1) != '\\') { //found a slash which is not escaped
156
module = ref.mid(0,pos);
157
ref = ref.mid(pos+1);
160
else if (pos == -1) {
165
// the rest is the key
172
//the key may be an osis key like "NASBLex:Moses", which sets the module, too
173
// const int modPos = key.find(":");
174
// if (modPos != -1 && key.at(modPos-1).isLetter() && key.at(modPos+1).isLetter()) {
175
// module = key.left(modPos);
176
// key = key.mid(modPos+1);
178
// qWarning("found the module name %s with key %s", module.latin1(), key.latin1());
181
//replace \/ escapes with /
182
key.replace(QRegExp("\\\\/"), "/");
184
else if (ref.left(8).toLower() == "morph://" || ref.left(10).toLower() == "strongs://") { //strongs or morph URL have the same format
185
enum PreType {IsMorph, IsStrongs};
186
PreType preType = IsMorph;
188
if (ref.left(8).toLower() == "morph://") { //morph code hyperlink
192
else if (ref.left(10).toLower() == "strongs://") {
197
//part up to next slash is the language
198
const int pos = ref.indexOf("/");
201
const QString language = ref.mid(0,pos);
203
if (language.toLower() == "hebrew") {
207
type = CReferenceManager::MorphHebrew;
211
type = CReferenceManager::StrongsHebrew;
215
else if (language.toLower() == "greek") {
219
type = CReferenceManager::MorphGreek;
223
type = CReferenceManager::StrongsGreek;
228
ref = ref.mid(pos+1);
229
key = ref; //the remaining part is the key
231
module = preferredModule(type);
235
if (key.isEmpty() && module.isEmpty())
241
const QString CReferenceManager::encodeReference(const QString &module, const QString &reference) {
242
//return QString("(%1)%2").arg(module).arg(reference);
243
return QString("(").append(module).append(")").append(reference);
246
void CReferenceManager::decodeReference(QString &dragreference, QString &module, QString &reference) {
247
const int pos = dragreference.indexOf(")");
248
const QString fallbackModule = dragreference.mid( 1, pos - 1);
249
dragreference = dragreference.mid(pos+1);
251
module = fallbackModule;
252
reference = dragreference;
255
/** Returns true if the parameter is a hyperlink. */
256
bool CReferenceManager::isHyperlink( const QString& hyperlink ) {
257
return ( hyperlink.left(8) == "sword://")
258
|| (hyperlink.left(10) == "strongs://")
259
|| (hyperlink.left(8) == "morph://");
262
/** Returns the preferred module name for the given type. */
263
const QString CReferenceManager::preferredModule( const CReferenceManager::Type type ) {
264
QString moduleName = QString::null;
265
CSwordModuleInfo* module = 0;
269
case CReferenceManager::Bible:
271
module = CBTConfig::get
272
( CBTConfig::standardBible );
276
case CReferenceManager::Commentary:
277
module = CBTConfig::get
278
( CBTConfig::standardCommentary );
282
case CReferenceManager::Lexicon:
283
module = CBTConfig::get
284
( CBTConfig::standardLexicon );
288
case CReferenceManager::StrongsHebrew:
289
module = CBTConfig::get
290
( CBTConfig::standardHebrewStrongsLexicon );
294
case CReferenceManager::StrongsGreek:
295
module = CBTConfig::get
296
( CBTConfig::standardGreekStrongsLexicon );
300
case CReferenceManager::MorphHebrew:
301
module = CBTConfig::get
302
( CBTConfig::standardHebrewMorphLexicon );
306
case CReferenceManager::MorphGreek:
307
module = CBTConfig::get
308
( CBTConfig::standardGreekMorphLexicon );
318
return module ? module->name() : QString::null;
321
/** No descriptions */
322
CReferenceManager::Type CReferenceManager::typeFromModule( const CSwordModuleInfo::ModuleType type) {
325
case CSwordModuleInfo::Bible:
326
return CReferenceManager::Bible;
328
case CSwordModuleInfo::Commentary:
329
return CReferenceManager::Commentary;
331
case CSwordModuleInfo::Lexicon:
332
return CReferenceManager::Lexicon;
334
case CSwordModuleInfo::GenericBook:
335
return CReferenceManager::GenericBook;
338
return CReferenceManager::Unknown;
342
/** Parses the given verse references using the given language and the module.*/
343
const QString CReferenceManager::parseVerseReference( const QString& ref, const CReferenceManager::ParseOptions& options) {
345
CSwordModuleInfo* const mod = CPointers::backend()->findModuleByName(options.refDestinationModule);
346
//Q_ASSERT(mod); tested later
349
//parsing of non-verse based references is not supported
353
if ((mod->type() != CSwordModuleInfo::Bible) && (mod->type() != CSwordModuleInfo::Commentary)) {
354
qDebug("CReferenceManager: Only verse based modules are supported as ref destination module");
355
return QString::null;
358
QString sourceLanguage = options.sourceLanguage;
359
QString destinationLanguage = options.destinationLanguage;
361
sword::StringList locales = sword::LocaleMgr::getSystemLocaleMgr()->getAvailableLocales();
362
if (/*options.sourceLanguage == "en" ||*/ std::find(locales.begin(), locales.end(), sourceLanguage.toUtf8().constData()) == locales.end()) { //sourceLanguage not available
363
sourceLanguage = "en_US";
366
if (/*options.destinationLanguage == "en" ||*/ std::find(locales.begin(), locales.end(), sourceLanguage.toUtf8().constData()) == locales.end()) { //destination not available
367
destinationLanguage = "en_US";
371
QStringList refList = ref.split(";");
373
CSwordVerseKey baseKey(0);
374
baseKey.setLocale( sourceLanguage.toUtf8().constData() );
375
baseKey.key( options.refBase ); //probably in the sourceLanguage
376
baseKey.setLocale( "en_US" ); //english works in all environments as base
378
// CSwordVerseKey dummy(0);
379
//HACK: We have to workaround a Sword bug, we have to set the default locale to the same as the sourceLanguage !
380
const QString oldLocaleName = CPointers::backend()->booknameLanguage();
381
CPointers::backend()->booknameLanguage(sourceLanguage);
383
sword::VerseKey dummy;
384
dummy.setLocale( sourceLanguage.toUtf8().constData() );
385
Q_ASSERT( !strcmp(dummy.getLocale(), sourceLanguage.toUtf8().constData()) );
387
// 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());
389
for (QStringList::iterator it = refList.begin(); it != refList.end(); it++) {
390
//The listkey may contain more than one item, because a ref lik "Gen 1:3,5" is parsed into two single refs
391
sword::ListKey lk = dummy.ParseVerseList((*it).toUtf8().constData(), baseKey.key().toUtf8().constData(), true);
392
Q_ASSERT(!dummy.Error());
394
//Q_ASSERT(lk.Count());
396
ret.append( *it ); //don't change the original
400
for (int i = 0; i < lk.Count(); ++i) {
401
if (dynamic_cast<sword::VerseKey*>(lk.getElement(i))) { // a range
402
sword::VerseKey* k = dynamic_cast<sword::VerseKey*>(lk.getElement(i));
404
k->setLocale( destinationLanguage.toUtf8().constData() );
406
ret.append( QString::fromUtf8(k->getRangeText()) ).append("; ");
408
else { // a single ref
410
vk.setLocale( sourceLanguage.toUtf8().constData() );
411
vk = lk.getElement(i)->getText();
412
vk.setLocale( destinationLanguage.toUtf8().constData() );
414
ret.append( QString::fromUtf8(vk.getText()) ).append("; ");
420
CPointers::backend()->booknameLanguage(oldLocaleName);