BibleTime
cswordversekey.cpp
Go to the documentation of this file.
1/*********
2*
3* In the name of the Father, and of the Son, and of the Holy Spirit.
4*
5* This file is part of BibleTime's source code, https://bibletime.info/
6*
7* Copyright 1999-2026 by the BibleTime developers.
8* The BibleTime source code is licensed under the GNU General Public License
9* version 2.0.
10*
11**********/
12
13#include "cswordversekey.h"
14
15#include <QDebug>
16#include <QStringList>
17#include <string_view>
18#include "../../util/btassert.h"
19#include "../drivers/cswordbiblemoduleinfo.h"
20
21// Sword includes:
22#ifdef __GNUC__
23#pragma GCC diagnostic push
24#pragma GCC diagnostic ignored "-Wextra-semi"
25#pragma GCC diagnostic ignored "-Wsuggest-override"
26#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
27#endif
28#ifdef __clang__
29#pragma clang diagnostic push
30#pragma clang diagnostic ignored "-Wsuggest-destructor-override"
31#endif
32#include <swmodule.h>
33#ifdef __clang__
34#pragma clang diagnostic pop
35#endif
36#ifdef __GNUC__
37#pragma GCC diagnostic pop
38#endif
39
40
42 : CSwordKey(module)
43{
44 if(CSwordBibleModuleInfo const * bible =
45 dynamic_cast<CSwordBibleModuleInfo const *>(module))
46 {
47 // Copy important settings like versification system
48 m_key.copyFrom(bible->swordModule().getKey());
49 setKey(bible->lowerBound().key());
50 }
51 m_key.setAutoNormalize(true);
52}
53
55 : CSwordKey(copy)
56 , m_key(copy.m_key)
57{ m_key.setAutoNormalize(true); }
58
59CSwordVerseKey::CSwordVerseKey(sword::VerseKey const * k,
60 CSwordModuleInfo const * module)
61 : CSwordKey(module)
62 , m_key(*k)
63{}
64
66
67sword::SWKey const & CSwordVerseKey::asSwordKey() const noexcept
68{ return m_key; }
69
70/** Clones this object. */
72{ return new CSwordVerseKey(*this); }
73
74/** Sets the module for this key */
76 BT_ASSERT(newModule);
77 if (m_module == newModule) return;
78 BT_ASSERT(newModule->type() == CSwordModuleInfo::Bible ||
79 newModule->type() == CSwordModuleInfo::Commentary);
80
81 CSwordBibleModuleInfo const * bible = static_cast<CSwordBibleModuleInfo const *>(newModule);
82 const char * newVersification =
83 static_cast<sword::VerseKey *>(
84 bible->swordModule().getKey())->getVersificationSystem();
85 bool inVersification = true;
86
87 if (strcmp(m_key.getVersificationSystem(), newVersification)) {
88 /// Remap key position to new versification
89 sword::VerseKey oldKey(m_key);
90
91 m_key.setVersificationSystem(newVersification);
92
93 m_key.positionFrom(oldKey);
94 inVersification = !m_key.popError();
95 }
96
97 m_module = newModule;
98
100
101 if(inVersification) {
102 /// Limit to Bible bounds
103 if (m_key._compare(bible->lowerBound().m_key) < 0) {
104 setKey(bible->lowerBound().m_key);
105 }
106 if (m_key._compare(bible->upperBound().m_key) > 0) {
107 setKey(bible->upperBound().m_key);
108 }
109 }
110
111 m_valid = inVersification;
112}
113
115{ return ((testament() > 1) ? m_key.BMAX[0] : 0) + book(); }
116
118{ return {&m_key.getLowerBound(), module()}; }
119
121{ m_key.setLowerBound(bound.m_key); }
122
124{ return {&m_key.getUpperBound(), module()}; }
125
127{ m_key.setUpperBound(bound.m_key); }
128
129/** Returns the current book as Text, not as integer. */
131 using CSBMI = CSwordBibleModuleInfo;
132 int min = 0;
133 int max = 1;
134
135 const CSBMI *bible = dynamic_cast<const CSBMI*>(module());
136 if (bible != nullptr) {
137 const bool hasOT = bible->hasOldTestament();
138 const bool hasNT = bible->hasNewTestament();
139
140 if (hasOT && hasNT) {
141 min = 0;
142 max = 1;
143 }
144 else if (hasOT && !hasNT) {
145 min = 0;
146 max = 0;
147 }
148 else if (!hasOT && hasNT) {
149 min = 1;
150 max = 1;
151 }
152 else if (!hasOT && !hasNT) {
153 min = 0;
154 max = -1; //no loop
155 }
156 }
157
158 if ((m_key.getTestament() >= min + 1) && (m_key.getTestament() <= max + 1) && (m_key.getBook() <= m_key.BMAX[min])) {
159 return QString::fromUtf8(m_key.getBookName());
160 }
161
162 //return QString::fromUtf8( books[min][0].name ); //return the first book, i.e. Genesis
163 return QString();
164}
165
166/** Sets the key we use to the parameter. */
167QString CSwordVerseKey::key() const {
168 return QString::fromUtf8(m_key.isBoundSet()
169 ? m_key.getRangeText()
170 : m_key.getText());
171}
172
174 using namespace std::string_view_literals;
175 if (m_key.getLocale() == "en"sv)
176 return key();
177 sword::VerseKey clone(m_key);
178 clone.setLocale("en");
179 return QString::fromUtf8(clone.isBoundSet()
180 ? clone.getRangeText()
181 : clone.getText());
182}
183
184const char * CSwordVerseKey::rawKey() const { return m_key.getText(); }
185
186bool CSwordVerseKey::setKey(const QString &newKey) {
187 return setKey(newKey.toUtf8().constData());
188}
189
190bool CSwordVerseKey::setKey(const char *newKey) {
191 if(QByteArray(newKey).contains('-')) {
192 sword::VerseKey vk(newKey, newKey, m_key.getVersificationSystem());
193 m_key.setLowerBound(vk.getLowerBound());
194 m_key.setUpperBound(vk.getUpperBound());
195 m_key.setPosition(sword::TOP);
196 } else {
197 m_key.clearBounds();
198 m_key.positionFrom(newKey);
199 }
200
201 m_valid = !m_key.popError();
202
203 emitAfterChanged(); /// \todo Do we ALWAYS need to emit this signal
204
205 return m_valid;
206}
207
208bool CSwordVerseKey::next( const JumpType type ) {
209 using CSBMI = CSwordBibleModuleInfo;
210
211 m_key.popError(); //clear Error status
212 bool ret = true;
213
214 switch (type) {
215
216 case UseBook: {
217 const int currentTestament = m_key.getTestament();
218 const int currentBook = m_key.getBook();
219
220 if ((currentTestament == 2) && (currentBook >= m_key.BMAX[currentTestament-1])) { //Revelation, i.e. end of navigation
221 return false;
222 }
223 else if ((currentTestament == 1) && (currentBook >= m_key.BMAX[currentTestament-1])) { //Malachi, switch to the NT
224 m_key.setTestament(currentTestament + 1);
225 m_key.setBook(1);
226 }
227 else {
228 m_key.setBook(m_key.getBook() + 1);
229 }
230 break;
231 }
232
233 case UseChapter: {
234 m_key.setChapter(m_key.getChapter() + 1);
235 break;
236 }
237
238 case UseVerse: {
239 if (!m_module) {
240 m_key.setVerse(m_key.getVerse() + 1);
241 } else {
242 auto & m = m_module->swordModule();
243 const bool oldStatus = m.isSkipConsecutiveLinks();
244 m.setSkipConsecutiveLinks(true);
245
246 auto * vKey = static_cast<sword::VerseKey *>(m.getKey());
247
248 // disable headings for next verse
249 bool const oldHeadingsStatus = vKey->isIntros();
250 vKey->setIntros(true);
251 //don't use setKey(), that would create a new key without Headings set
252 vKey->setText(key().toUtf8().constData());
253
254 m++;
255
256 vKey = static_cast<sword::VerseKey *>(m.getKey());
257 vKey->setIntros(oldHeadingsStatus);
258 m.setSkipConsecutiveLinks(oldStatus);
259
260 if (!m.popError()) {
261 setKey(QString::fromUtf8(vKey->getText()));
262 } else {
263 // Verse(Verse()+1);
264 //don't change the key, restore the module's position
265 vKey->setText(key().toUtf8().constData());
266 ret = false;
267 break;
268 }
269 }
270
271 break;
272 }
273
274 default:
275 return false;
276 }
277
278 const CSBMI *bible = dynamic_cast<const CSBMI*>(module());
279 if (bible != nullptr) {
280 if (m_key._compare(bible->lowerBound().m_key) < 0 ) {
281 setKey(bible->lowerBound().m_key);
282 ret = false;
283 }
284
285 if (m_key._compare(bible->upperBound().m_key) > 0 ) {
286 setKey(bible->upperBound().m_key);
287 ret = false;
288 }
289
291 return ret;
292 }
293 else if (m_key.popError()) { //we have no module, so take care of VerseKey::Error()
294 return false;
295 }
296
298 return ret;
299}
300
302 using CSBMI = CSwordBibleModuleInfo;
303
304 bool ret = true;
305
306 switch (type) {
307
308 case UseBook: {
309 if ((m_key.getBook() == 1) && (m_key.getTestament() == 1)) { //Genesis
310 return false;
311 }
312 else if ((m_key.getBook() == 1) && (m_key.getTestament() == 2)) { //Matthew
313 m_key.setTestament(1);
314 m_key.setBook(m_key.BMAX[0]);
315 }
316 else {
317 m_key.setBook(m_key.getBook() - 1);
318 }
319
320 break;
321 }
322
323 case UseChapter: {
324 m_key.setChapter(m_key.getChapter() - 1);
325 break;
326 }
327
328 case UseVerse: {
329 if (!m_module) {
330 m_key.setVerse(m_key.getVerse() - 1);
331 } else {
332 auto & m = m_module->swordModule();
333 auto * vKey = static_cast<sword::VerseKey *>(m.getKey());
334 bool const oldHeadingsStatus = vKey->isIntros();
335 vKey->setIntros(true);
336 vKey->setText(key().toUtf8().constData());
337
338 bool const oldStatus = m.isSkipConsecutiveLinks();
339 m.setSkipConsecutiveLinks(true);
340 m--;
341
342 vKey = static_cast<sword::VerseKey *>(m.getKey());
343 vKey->setIntros(oldHeadingsStatus);
344 m.setSkipConsecutiveLinks(oldStatus);
345
346 if (!m.popError()) {
347 /// \warning Weird comment:
348 // don't use fromUtf8:
349 setKey(QString::fromUtf8(vKey->getText()));
350 } else {
351 ret = false;
352 // Verse(Verse()-1);
353 // Restore module's key:
354 vKey->setText(key().toUtf8().constData());
355 }
356 }
357
358 break;
359 }
360
361 default:
362 return false;
363 }
364
365 const CSBMI *bible = dynamic_cast<const CSBMI*>(module());
366 if (bible != nullptr) {
367 if (m_key._compare(bible->lowerBound().m_key) < 0 ) {
368 setKey(bible->lowerBound().m_key);
369 ret = false;
370 }
371
372 if (m_key._compare(bible->upperBound().m_key) > 0 ) {
373 setKey(bible->upperBound().m_key);
374 ret = false;
375 }
376
378 return ret;
379 }
380 else if (m_key.popError()) {
381 return false;
382 }
383
385 return ret;
386}
387
394
395
397 if (!m_afterChangedSignaller.isNull())
398 m_afterChangedSignaller->emitSignal();
399}
#define BT_ASSERT(...)
Definition btassert.h:17
Implementation for Sword Bibles.
CSwordVerseKey const & lowerBound() const
CSwordVerseKey const & upperBound() const
CSwordModuleInfo const * module() const
Definition cswordkey.h:68
const CSwordModuleInfo * m_module
Definition cswordkey.h:112
bool m_valid
Definition cswordkey.h:113
ModuleType type() const
sword::SWModule & swordModule() const
CSwordKey implementation for Sword's VerseKey.
CSwordVerseKey upperBound() const
void setLowerBound(CSwordVerseKey const &bound)
char bibleBook() const
char book() const
~CSwordVerseKey() override
QString bookName() const
bool next(const JumpType type=JumpType::UseVerse)
char testament() const
void setModule(const CSwordModuleInfo *newModule) final override
CSwordVerseKey(const CSwordModuleInfo *module)
bool previous(const JumpType type=JumpType::UseVerse)
QString key() const final override
sword::VerseKey m_key
QPointer< BtSignal > m_afterChangedSignaller
bool setKey(const QString &key) final override
const BtSignal * afterChangedSignaller()
CSwordVerseKey * copy() const final override
const char * rawKey() const final override
QString normalizedKey() const final override
void setUpperBound(CSwordVerseKey const &bound)
sword::SWKey const & asSwordKey() const noexcept final override
CSwordVerseKey lowerBound() const