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