~ubuntu-branches/ubuntu/trusty/bibletime/trusty

« back to all changes in this revision

Viewing changes to src/backend/managers/creferencemanager.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Marsden
  • Date: 2009-11-18 17:30:00 UTC
  • mfrom: (1.3.4 upstream) (5.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20091118173000-endkhjz5qai88tvr
Tags: 2.4-1
* New upstream version 2.4
* debian/control: 
  - Replace incorrect bibletime-data Depends on lib4qt-gui
    with bibletime Depends on libqtgui4 (>= 4.4.0). (Closes: #556209).
  - Add Build-depends: on zlib1g-dev and libcurl4-gnutls-dev 
    (Closes: #556805).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*********
2
 
*
3
 
* This file is part of BibleTime's source code, http://www.bibletime.info/.
4
 
*
5
 
* Copyright 1999-2008 by the BibleTime developers.
6
 
* The BibleTime source code is licensed under the GNU General Public License version 2.0.
7
 
*
8
 
**********/
9
 
 
10
 
#include "creferencemanager.h"
11
 
#include "backend/keys/cswordversekey.h"
12
 
 
13
 
#include "backend/config/cbtconfig.h"
14
 
#include "util/cpointers.h"
15
 
 
16
 
//QT
17
 
#include <QRegExp>
18
 
 
19
 
//stl
20
 
#include <algorithm>       // STL algorithms class library
21
 
 
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;
25
 
 
26
 
        switch (type) {
27
 
 
28
 
                case Bible:
29
 
                        ret = QString("sword://Bible/");
30
 
                        break;
31
 
                case Commentary:
32
 
                        ret = QString("sword://Commentary/");
33
 
                        break;
34
 
                case Lexicon:
35
 
                        ret = QString("sword://Lexicon/");
36
 
                        break;
37
 
                case GenericBook:
38
 
                        ret = QString("sword://Book/");
39
 
                        break;
40
 
                case MorphHebrew:
41
 
                        ret = QString("morph://Hebrew/");
42
 
                        break;
43
 
                case MorphGreek:
44
 
                        ret = QString("morph://Greek/");
45
 
                        break;
46
 
                case StrongsHebrew:
47
 
                        ret = QString("strongs://Hebrew/");
48
 
                        break;
49
 
                case StrongsGreek:
50
 
                        ret = QString("strongs://Greek/");
51
 
                        break;
52
 
                default:
53
 
                        break;
54
 
        }
55
 
 
56
 
        if (!moduleName.isEmpty()) {
57
 
                ret.append( moduleName ).append('/');
58
 
        }
59
 
        else { //if module is empty use fallback module
60
 
                ret.append( preferredModule(type) ).append('/');
61
 
        }
62
 
 
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)!
68
 
 
69
 
                QChar c;
70
 
 
71
 
                for(int i = 0; i < s.length(); ++i) {
72
 
                        c = s.at(i);
73
 
 
74
 
                        if (c == '/') {
75
 
                                newKey.append("\\/");
76
 
                        }
77
 
                        else {
78
 
                                newKey.append(c);
79
 
                        }
80
 
                }
81
 
 
82
 
                ret.append( newKey );
83
 
        }
84
 
        else { //slashes do not appear in verses and dictionary entries
85
 
 
86
 
                switch (type) {
87
 
 
88
 
                        case Bible: //bibles or commentary keys need parsing
89
 
 
90
 
                        case Commentary: {
91
 
/*                              CSwordModuleInfo* mod = CPointers::backend()->findModuleByName(moduleName);
92
 
 
93
 
                                ParseOptions options;
94
 
                                options.refDestinationModule = mod->name();
95
 
                                options.refBase =
96
 
                                options.sourceLanguage = mod->module()->Lang();
97
 
                                options.destinationLanguage = "en";
98
 
 
99
 
                                ret.append( parseVerseReference(key, options) ); //we add the english key, so drag and drop will work in all cases*/
100
 
                                ret.append(key);
101
 
                                break;
102
 
                        }
103
 
 
104
 
                        default:
105
 
                                ret.append( key ); //use the standard key, no parsing required
106
 
                                break;
107
 
                }
108
 
        }
109
 
 
110
 
        return ret;
111
 
}
112
 
 
113
 
/** Decodes the given hyperlink to module and key. */
114
 
bool CReferenceManager::decodeHyperlink( const QString& hyperlink, QString& module, QString& key, CReferenceManager::Type& type ) {
115
 
        /**
116
 
        * We have to decide between three types of URLS: sword://Type/Module/Key, morph://Testament/key and strongs://Testament/Key
117
 
        */
118
 
        module = QString::null;
119
 
        key = QString::null;
120
 
 
121
 
        type = Unknown; //not yet known
122
 
        QString ref = hyperlink;
123
 
        //remove the trailing slash
124
 
 
125
 
        if (ref.right(1)=="/" && ref.right(2) != "\\/") //trailing slash, but not escaped
126
 
                ref = ref.left(ref.length()-1);
127
 
 
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
130
 
                ref = ref.mid(8);
131
 
 
132
 
                if (ref.left(5).toLower() == "bible") { //a bible hyperlink
133
 
                        type = CReferenceManager::Bible;
134
 
                        ref = ref.mid(6); //inclusive trailing slash
135
 
                }
136
 
                else if (ref.left(10).toLower() == "commentary") { // a Commentary hyperlink
137
 
                        type = CReferenceManager::Commentary;
138
 
                        ref = ref.mid(11); //inclusive trailing slash
139
 
                }
140
 
                else if (ref.left(7).toLower() == "lexicon") { // a Lexicon hyperlink
141
 
                        type = CReferenceManager::Lexicon;
142
 
                        ref = ref.mid(8); //inclusive trailing slash
143
 
                }
144
 
                else if (ref.left(4).toLower() == "book") { // a Book hyperlink
145
 
                        type = CReferenceManager::GenericBook;
146
 
                        ref = ref.mid(5); //inclusive trailing slash
147
 
                }
148
 
 
149
 
                // string up to next slash is the modulename
150
 
                if (ref.at(0) != '/' ) { //we have a module given
151
 
 
152
 
                        while (true) {
153
 
                                const int pos = ref.indexOf("/");
154
 
 
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);
158
 
                                        break;
159
 
                                }
160
 
                                else if (pos == -1) {
161
 
                                        break;
162
 
                                }
163
 
                        }
164
 
 
165
 
                        // the rest is the key
166
 
                        key = ref;
167
 
                }
168
 
                else {
169
 
                        key = ref.mid(1);
170
 
                }
171
 
 
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);
177
 
                //
178
 
                //    qWarning("found the module name %s with key %s", module.latin1(), key.latin1());
179
 
                //   }
180
 
 
181
 
                //replace \/ escapes with /
182
 
                key.replace(QRegExp("\\\\/"), "/");
183
 
        }
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;
187
 
 
188
 
                if (ref.left(8).toLower() == "morph://") { //morph code hyperlink
189
 
                        ref = ref.mid(8);
190
 
                        preType = IsMorph;
191
 
                }
192
 
                else if (ref.left(10).toLower() == "strongs://") {
193
 
                        ref = ref.mid(10);
194
 
                        preType = IsStrongs;
195
 
                }
196
 
 
197
 
                //part up to next slash is the language
198
 
                const int pos = ref.indexOf("/");
199
 
 
200
 
                if (pos>0) { //found
201
 
                        const QString language = ref.mid(0,pos);
202
 
 
203
 
                        if (language.toLower() == "hebrew") {
204
 
                                switch (preType) {
205
 
 
206
 
                                        case IsMorph:
207
 
                                        type = CReferenceManager::MorphHebrew;
208
 
                                        break;
209
 
 
210
 
                                        case IsStrongs:
211
 
                                        type = CReferenceManager::StrongsHebrew;
212
 
                                        break;
213
 
                                }
214
 
                        }
215
 
                        else if (language.toLower() == "greek") {
216
 
                                switch (preType) {
217
 
 
218
 
                                        case IsMorph:
219
 
                                        type = CReferenceManager::MorphGreek;
220
 
                                        break;
221
 
 
222
 
                                        case IsStrongs:
223
 
                                        type = CReferenceManager::StrongsGreek;
224
 
                                        break;
225
 
                                }
226
 
                        }
227
 
 
228
 
                        ref = ref.mid(pos+1);
229
 
                        key = ref; //the remaining part is the key
230
 
 
231
 
                        module = preferredModule(type);
232
 
                }
233
 
        }
234
 
 
235
 
        if (key.isEmpty() && module.isEmpty())
236
 
                return false;
237
 
 
238
 
        return true;
239
 
}
240
 
 
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);
244
 
}
245
 
 
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);
250
 
 
251
 
        module = fallbackModule;
252
 
        reference = dragreference;
253
 
}
254
 
 
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://");
260
 
}
261
 
 
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;
266
 
 
267
 
        switch (type) {
268
 
 
269
 
                case CReferenceManager::Bible:
270
 
 
271
 
                module = CBTConfig::get
272
 
                                         ( CBTConfig::standardBible );
273
 
 
274
 
                break;
275
 
 
276
 
                case CReferenceManager::Commentary:
277
 
                module = CBTConfig::get
278
 
                                         ( CBTConfig::standardCommentary );
279
 
 
280
 
                break;
281
 
 
282
 
                case CReferenceManager::Lexicon:
283
 
                module = CBTConfig::get
284
 
                                         ( CBTConfig::standardLexicon );
285
 
 
286
 
                break;
287
 
 
288
 
                case CReferenceManager::StrongsHebrew:
289
 
                module = CBTConfig::get
290
 
                                         ( CBTConfig::standardHebrewStrongsLexicon );
291
 
 
292
 
                break;
293
 
 
294
 
                case CReferenceManager::StrongsGreek:
295
 
                module = CBTConfig::get
296
 
                                         ( CBTConfig::standardGreekStrongsLexicon );
297
 
 
298
 
                break;
299
 
 
300
 
                case CReferenceManager::MorphHebrew:
301
 
                module = CBTConfig::get
302
 
                                         ( CBTConfig::standardHebrewMorphLexicon );
303
 
 
304
 
                break;
305
 
 
306
 
                case CReferenceManager::MorphGreek:
307
 
                module = CBTConfig::get
308
 
                                         ( CBTConfig::standardGreekMorphLexicon );
309
 
 
310
 
                break;
311
 
 
312
 
                default:
313
 
                module = 0;
314
 
 
315
 
                break;
316
 
        }
317
 
 
318
 
        return module ? module->name() : QString::null;
319
 
}
320
 
 
321
 
/** No descriptions */
322
 
CReferenceManager::Type CReferenceManager::typeFromModule( const CSwordModuleInfo::ModuleType type) {
323
 
        switch (type) {
324
 
 
325
 
                case CSwordModuleInfo::Bible:
326
 
                return CReferenceManager::Bible;
327
 
 
328
 
                case CSwordModuleInfo::Commentary:
329
 
                return CReferenceManager::Commentary;
330
 
 
331
 
                case CSwordModuleInfo::Lexicon:
332
 
                return CReferenceManager::Lexicon;
333
 
 
334
 
                case CSwordModuleInfo::GenericBook:
335
 
                return CReferenceManager::GenericBook;
336
 
 
337
 
                default:
338
 
                return CReferenceManager::Unknown;
339
 
        }
340
 
}
341
 
 
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) {
344
 
 
345
 
        CSwordModuleInfo* const mod = CPointers::backend()->findModuleByName(options.refDestinationModule);
346
 
        //Q_ASSERT(mod); tested later
347
 
 
348
 
        if (!mod) {
349
 
                //parsing of non-verse based references is not supported
350
 
                return ref;
351
 
        }
352
 
 
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;
356
 
        }
357
 
 
358
 
        QString sourceLanguage = options.sourceLanguage;
359
 
        QString destinationLanguage = options.destinationLanguage;
360
 
 
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";
364
 
        }
365
 
 
366
 
        if (/*options.destinationLanguage == "en" ||*/ std::find(locales.begin(), locales.end(), sourceLanguage.toUtf8().constData()) == locales.end()) { //destination not available
367
 
                destinationLanguage = "en_US";
368
 
        }
369
 
 
370
 
        QString ret;
371
 
        QStringList refList = ref.split(";");
372
 
 
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
377
 
 
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);
382
 
 
383
 
        sword::VerseKey dummy;
384
 
        dummy.setLocale( sourceLanguage.toUtf8().constData() );
385
 
        Q_ASSERT( !strcmp(dummy.getLocale(), sourceLanguage.toUtf8().constData()) );
386
 
 
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());
388
 
 
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());
393
 
 
394
 
                //Q_ASSERT(lk.Count());
395
 
                if (!lk.Count()) {
396
 
                        ret.append( *it ); //don't change the original
397
 
                        continue;
398
 
                }
399
 
 
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));
403
 
                                Q_ASSERT(k);
404
 
                                k->setLocale( destinationLanguage.toUtf8().constData() );
405
 
 
406
 
                                ret.append( QString::fromUtf8(k->getRangeText()) ).append("; ");
407
 
                        }
408
 
                        else { // a single ref
409
 
                                sword::VerseKey vk;
410
 
                                vk.setLocale( sourceLanguage.toUtf8().constData() );
411
 
                                vk = lk.getElement(i)->getText();
412
 
                                vk.setLocale( destinationLanguage.toUtf8().constData() );
413
 
 
414
 
                                ret.append( QString::fromUtf8(vk.getText()) ).append("; ");
415
 
                        }
416
 
                }
417
 
 
418
 
        }
419
 
 
420
 
        CPointers::backend()->booknameLanguage(oldLocaleName);
421
 
        return ret;
422
 
}