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 "backend/managers/referencemanager.h"
16
#include "backend/config/cbtconfig.h"
17
#include "backend/keys/cswordversekey.h"
18
#include "util/cpointers.h"
21
/** Returns a hyperlink used to be imbedded in the display windows. At the moment the format is sword://module/key */
22
const QString ReferenceManager::encodeHyperlink( const QString moduleName, const QString key, const ReferenceManager::Type type) {
23
QString ret = QString::null;
28
ret = QString("sword://Bible/");
31
ret = QString("sword://Commentary/");
34
ret = QString("sword://Lexicon/");
37
ret = QString("sword://Book/");
40
ret = QString("morph://Hebrew/");
43
ret = QString("morph://Greek/");
46
ret = QString("strongs://Hebrew/");
49
ret = QString("strongs://Greek/");
55
if (!moduleName.isEmpty()) {
56
ret.append( moduleName ).append('/');
58
else { //if module is empty use fallback module
59
ret.append( preferredModule(type) ).append('/');
62
if (type == GenericBook) {
63
const QString s = (!key.isEmpty() ? key : QString::null);
64
QString newKey = QString::null;
65
//replace all / of the key (e.g. of a CSwordTreeKey) with
66
// the escape sequence \/ so we know it's a link internal divider (e.g. of CSwordTreeKey)!
70
for (int i = 0; i < s.length(); ++i) {
83
else { //slashes do not appear in verses and dictionary entries
87
case Bible: //bibles or commentary keys need parsing
90
/* CSwordModuleInfo* mod = CPointers::backend()->findModuleByName(moduleName);
93
options.refDestinationModule = mod->name();
95
options.sourceLanguage = mod->module()->Lang();
96
options.destinationLanguage = "en";
98
ret.append( parseVerseReference(key, options) ); //we add the english key, so drag and drop will work in all cases*/
104
ret.append( key ); //use the standard key, no parsing required
112
/** Decodes the given hyperlink to module and key. */
113
bool ReferenceManager::decodeHyperlink( const QString& hyperlink, QString& module, QString& key, ReferenceManager::Type& type ) {
115
* We have to decide between three types of URLS: sword://Type/Module/Key, morph://Testament/key and strongs://Testament/Key
117
module = QString::null;
120
type = Unknown; //not yet known
121
QString ref = hyperlink;
122
//remove the trailing slash
124
if (ref.right(1) == "/" && ref.right(2) != "\\/") //trailing slash, but not escaped
125
ref = ref.left(ref.length() - 1);
127
//find out which type we have by looking at the beginning (protocoll section of URL)
128
if (ref.left(8).toLower() == "sword://") { //Bible, Commentary or Lexicon
131
if (ref.left(5).toLower() == "bible") { //a bible hyperlink
132
type = ReferenceManager::Bible;
133
ref = ref.mid(6); //inclusive trailing slash
135
else if (ref.left(10).toLower() == "commentary") { // a Commentary hyperlink
136
type = ReferenceManager::Commentary;
137
ref = ref.mid(11); //inclusive trailing slash
139
else if (ref.left(7).toLower() == "lexicon") { // a Lexicon hyperlink
140
type = ReferenceManager::Lexicon;
141
ref = ref.mid(8); //inclusive trailing slash
143
else if (ref.left(4).toLower() == "book") { // a Book hyperlink
144
type = ReferenceManager::GenericBook;
145
ref = ref.mid(5); //inclusive trailing slash
148
// string up to next slash is the modulename
149
if (ref.at(0) != '/' ) { //we have a module given
152
const int pos = ref.indexOf("/");
154
if ((pos > 0) && ref.at(pos - 1) != '\\') { //found a slash which is not escaped
155
module = ref.mid(0, pos);
156
ref = ref.mid(pos + 1);
159
else if (pos == -1) {
164
// the rest is the key
171
//the key may be an osis key like "NASBLex:Moses", which sets the module, too
172
// const int modPos = key.find(":");
173
// if (modPos != -1 && key.at(modPos-1).isLetter() && key.at(modPos+1).isLetter()) {
174
// module = key.left(modPos);
175
// key = key.mid(modPos+1);
177
// qWarning("found the module name %s with key %s", module.latin1(), key.latin1());
180
//replace \/ escapes with /
181
key.replace(QRegExp("\\\\/"), "/");
183
else if (ref.left(8).toLower() == "morph://" || ref.left(10).toLower() == "strongs://") { //strongs or morph URL have the same format
184
enum PreType {IsMorph, IsStrongs};
185
PreType preType = IsMorph;
187
if (ref.left(8).toLower() == "morph://") { //morph code hyperlink
191
else if (ref.left(10).toLower() == "strongs://") {
196
//part up to next slash is the language
197
const int pos = ref.indexOf("/");
199
if (pos > 0) { //found
200
const QString language = ref.mid(0, pos);
202
if (language.toLower() == "hebrew") {
206
type = ReferenceManager::MorphHebrew;
210
type = ReferenceManager::StrongsHebrew;
214
else if (language.toLower() == "greek") {
218
type = ReferenceManager::MorphGreek;
222
type = ReferenceManager::StrongsGreek;
227
ref = ref.mid(pos + 1);
228
key = ref; //the remaining part is the key
230
module = preferredModule(type);
234
if (key.isEmpty() && module.isEmpty())
240
const QString ReferenceManager::encodeReference(const QString &module, const QString &reference) {
241
//return QString("(%1)%2").arg(module).arg(reference);
242
return QString("(").append(module).append(")").append(reference);
245
void ReferenceManager::decodeReference(QString &dragreference, QString &module, QString &reference) {
246
const int pos = dragreference.indexOf(")");
247
const QString fallbackModule = dragreference.mid( 1, pos - 1);
248
dragreference = dragreference.mid(pos + 1);
250
module = fallbackModule;
251
reference = dragreference;
254
/** Returns true if the parameter is a hyperlink. */
255
bool ReferenceManager::isHyperlink( const QString& hyperlink ) {
256
return ( hyperlink.left(8) == "sword://")
257
|| (hyperlink.left(10) == "strongs://")
258
|| (hyperlink.left(8) == "morph://");
261
/** Returns the preferred module name for the given type. */
262
const QString ReferenceManager::preferredModule( const ReferenceManager::Type type ) {
263
QString moduleName = QString::null;
264
CSwordModuleInfo* module = 0;
268
case ReferenceManager::Bible:
270
module = CBTConfig::get
271
( CBTConfig::standardBible );
275
case ReferenceManager::Commentary:
276
module = CBTConfig::get
277
( CBTConfig::standardCommentary );
281
case ReferenceManager::Lexicon:
282
module = CBTConfig::get
283
( CBTConfig::standardLexicon );
287
case ReferenceManager::StrongsHebrew:
288
module = CBTConfig::get
289
( CBTConfig::standardHebrewStrongsLexicon );
293
case ReferenceManager::StrongsGreek:
294
module = CBTConfig::get
295
( CBTConfig::standardGreekStrongsLexicon );
299
case ReferenceManager::MorphHebrew:
300
module = CBTConfig::get
301
( CBTConfig::standardHebrewMorphLexicon );
305
case ReferenceManager::MorphGreek:
306
module = CBTConfig::get
307
( CBTConfig::standardGreekMorphLexicon );
317
return module ? module->name() : QString::null;
320
/** No descriptions */
321
ReferenceManager::Type ReferenceManager::typeFromModule( const CSwordModuleInfo::ModuleType type) {
324
case CSwordModuleInfo::Bible:
325
return ReferenceManager::Bible;
327
case CSwordModuleInfo::Commentary:
328
return ReferenceManager::Commentary;
330
case CSwordModuleInfo::Lexicon:
331
return ReferenceManager::Lexicon;
333
case CSwordModuleInfo::GenericBook:
334
return ReferenceManager::GenericBook;
337
return ReferenceManager::Unknown;
341
/** Parses the given verse references using the given language and the module.*/
342
const QString ReferenceManager::parseVerseReference( const QString& ref, const ReferenceManager::ParseOptions& options) {
344
CSwordModuleInfo* const mod = CPointers::backend()->findModuleByName(options.refDestinationModule);
345
//Q_ASSERT(mod); tested later
348
//parsing of non-verse based references is not supported
352
if ((mod->type() != CSwordModuleInfo::Bible) && (mod->type() != CSwordModuleInfo::Commentary)) {
353
qDebug() << "CReferenceManager: Only verse based modules are supported as ref destination module";
354
return QString::null;
357
QString sourceLanguage = options.sourceLanguage;
358
QString destinationLanguage = options.destinationLanguage;
360
sword::StringList locales = sword::LocaleMgr::getSystemLocaleMgr()->getAvailableLocales();
361
if (/*options.sourceLanguage == "en" ||*/ std::find(locales.begin(), locales.end(), sourceLanguage.toUtf8().constData()) == locales.end()) { //sourceLanguage not available
362
sourceLanguage = "en_US";
365
if (/*options.destinationLanguage == "en" ||*/ std::find(locales.begin(), locales.end(), sourceLanguage.toUtf8().constData()) == locales.end()) { //destination not available
366
destinationLanguage = "en_US";
370
QStringList refList = ref.split(";");
372
CSwordVerseKey baseKey(0);
373
baseKey.setLocale( sourceLanguage.toUtf8().constData() );
374
baseKey.key( options.refBase ); //probably in the sourceLanguage
375
baseKey.setLocale( "en_US" ); //english works in all environments as base
377
// CSwordVerseKey dummy(0);
378
//HACK: We have to workaround a Sword bug, we have to set the default locale to the same as the sourceLanguage !
379
const QString oldLocaleName = CPointers::backend()->booknameLanguage();
380
CPointers::backend()->booknameLanguage(sourceLanguage);
382
sword::VerseKey dummy;
383
dummy.setLocale( sourceLanguage.toUtf8().constData() );
384
Q_ASSERT( !strcmp(dummy.getLocale(), sourceLanguage.toUtf8().constData()) );
386
// 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());
388
for (QStringList::iterator it = refList.begin(); it != refList.end(); it++) {
389
//The listkey may contain more than one item, because a ref lik "Gen 1:3,5" is parsed into two single refs
390
sword::ListKey lk = dummy.ParseVerseList((*it).toUtf8().constData(), baseKey.key().toUtf8().constData(), true);
391
Q_ASSERT(!dummy.Error());
393
//Q_ASSERT(lk.Count());
395
ret.append( *it ); //don't change the original
399
for (int i = 0; i < lk.Count(); ++i) {
400
if (dynamic_cast<sword::VerseKey*>(lk.getElement(i))) { // a range
401
sword::VerseKey* k = dynamic_cast<sword::VerseKey*>(lk.getElement(i));
403
k->setLocale( destinationLanguage.toUtf8().constData() );
405
ret.append( QString::fromUtf8(k->getRangeText()) ).append("; ");
407
else { // a single ref
409
vk.setLocale( sourceLanguage.toUtf8().constData() );
410
vk = lk.getElement(i)->getText();
411
vk.setLocale( destinationLanguage.toUtf8().constData() );
413
ret.append( QString::fromUtf8(vk.getText()) ).append("; ");
419
CPointers::backend()->booknameLanguage(oldLocaleName);