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

« back to all changes in this revision

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