BibleTime
btmoduletextmodel.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 <QTextEdit>
14#include "btmoduletextmodel.h"
15
16#include <QRegularExpression>
17#include <QRegularExpressionMatch>
18#include "../../util/btassert.h"
19#include "../drivers/cswordmoduleinfo.h"
20#include "../drivers/cswordbiblemoduleinfo.h"
21#include "../drivers/cswordbookmoduleinfo.h"
22#include "../drivers/cswordlexiconmoduleinfo.h"
23#include "../cswordmodulesearch.h"
24#include "../keys/cswordtreekey.h"
25#include "../keys/cswordversekey.h"
26#include "../managers/colormanager.h"
27#include "../managers/cswordbackend.h"
28#include "../rendering/ctextrendering.h"
29
30
31namespace {
32
33DisplayOptions const defaultDisplayOptions = []() noexcept {
34 DisplayOptions opts;
35 opts.lineBreaks = 1;
36 opts.verseNumbers = 1;
37 return opts;
38}();
39
40FilterOptions const defaultFilterOptions = []() noexcept {
41 FilterOptions opts;
42 opts.footnotes = 0;
43 opts.greekAccents = 1;
44 opts.headings = 1;
45 opts.hebrewCantillation = 1;
46 opts.hebrewPoints = 1;
47 opts.lemmas = 0;
48 opts.morphSegmentation = 1;
49 opts.morphTags = 1;
50 opts.redLetterWords = 1;
51 opts.scriptureReferences = 0;
52 opts.strongNumbers = 0;
53 opts.textualVariants = 0;
54 return opts;
55}();
56
57QStringList splitText(QString const & text) {
58 QStringList parts;
59 int from = 0;
60 while (from < text.length()) {
61
62 // Get text before tag
63 int end = text.indexOf('<', from);
64 if (end == -1)
65 end = text.length();
66 parts.append(text.mid(from, end-from));
67 from = end;
68
69 //Get tag text
70 end = text.indexOf('>', from);
71 if (end == -1)
72 end = text.length();
73 parts.append(text.mid(from, end-from+1));
74 from = end+1;
75 }
76 return parts;
77}
78
79void fixDoubleBR(QStringList & parts) {
80 static QRegularExpression const rx(R"regex(<br\s*/>)regex");
81 for (int index = 2; index < parts.count(); ++index) {
82 if (parts.at(index).contains(rx) && parts.at(index-2).contains(rx))
83 parts[index] = "";
84 }
85}
86
87// Typical input: <span class="footnote" note="ESV2011/Luke 11:37/1">
88// Output: <span class="footnote" note="ESV2011/Luke 11:37/1">1</span>
89
90int rewriteFootnoteAsLink(QStringList & parts, int i, QString const & part) {
91 if (i + 2 >= parts.count())
92 return 1;
93
94 static QRegularExpression const rx(R"regex(note="([^"]*))regex");
95 if (auto const match = rx.match(part); match.hasMatch()) {
96 auto const & footnoteText = parts.at(i + 1);
97 parts[i] =
98 QStringLiteral(
99 R"HTML(<a class="footnote" href="sword://footnote/%1=%2">)HTML")
100 .arg(match.captured(1)).arg(footnoteText);
101 parts[i+1] = QStringLiteral("(%1)").arg(footnoteText);
102 parts[i+2] = QStringLiteral("</a>");
103 return 3;
104 }
105 return 1;
106}
107
108// Packs attribute part of href into the link
109// Typical input: <a name="Luke11_29" href="sword://Bible/ESV2011/Luke 11:29">
110// Output: <a href="sword://Bible/ESV2011/Luke 11:29||name=Luke11_29">
111
112void rewriteHref(QStringList & parts, int i, QString const & part) {
113 static QRegularExpression const rx(
114 R"regex(<a\s+(\w+)="([^"]*)"\s+(\w+)="([^"]*)")regex");
115 if (auto const match = rx.match(part); match.hasMatch()) {
116 parts[i] =
117 ((match.captured(1) == QStringLiteral("href"))
118 ? QStringLiteral(R"HTML(<a %1="%2||%3=%4" name="crossref">)HTML")
119 : QStringLiteral(R"HTML(<a %3="%4||%1=%2" name="crossref">)HTML"))
120 .arg(match.captured(1),
121 match.captured(2),
122 match.captured(3),
123 match.captured(4));
124 }
125}
126
127// Typical input: <span lemma="H07225">God</span>
128// Output: "<a href="sword://lemmamorph/lemma=H0430||/God" style="color: black">"
129int rewriteLemmaOrMorphAsLink(QStringList & parts, int i, QString const & part)
130{
131 if (i + 2 >= parts.count())
132 return 1;
133
134 QString value;
135 {
136 static QRegularExpression const rx(R"regex(lemma="([^"]*)")regex");
137 if (auto const match = rx.match(part); match.hasMatch())
138 value = QStringLiteral("lemma=") + match.captured(1);
139 }{
140 static QRegularExpression const rx(R"regex(morph="([^"]*)")regex");
141 if (auto const match = rx.match(part); match.hasMatch()) {
142 if (value.isEmpty()) {
143 value = QStringLiteral("morph=") + match.captured(1);
144 } else {
145 value = QStringLiteral("%1||morph=%2")
146 .arg(value, match.captured(1));
147 }
148 }
149 }
150
151 auto const & refText = parts.at(i + 1);
152 parts[i] =
153 QStringLiteral(
154 R"HTM(<a id="lemmamorph" href="sword://lemmamorph/%1/%2">)HTM")
155 .arg(value, refText);
156 parts[i + 2] = QStringLiteral("</a>");
157 return 3;
158}
159
160int rewriteTag(QStringList & parts, int i, QString const & tag) {
161 if (i + 2 >= parts.count())
162 return 1;
163 parts[i] = "<" + tag + ">";
164 parts[i+2] ="</" + tag + ">";
165 return 3;
166}
167
168int rewriteTitle(QStringList & parts, int i, QString const & tag) {
169 if (i + 2 >= parts.count())
170 return 1;
171 parts[i] = "<div><big><" + tag + ">";
172 parts[i+2] ="</" + tag + "></big></div>";
173 return 3;
174}
175
176int rewriteClass(QStringList & parts, int i, QString const & part) {
177
178 if (part.contains(QStringLiteral(R"HTML(class="footnote")HTML"))) {
179 return rewriteFootnoteAsLink(parts, i, part);
180 } else if (part.contains(QStringLiteral(R"HTML(class="bold")HTML"))) {
181 return rewriteTag(parts, i, "b");
182 } else if (part.contains(QStringLiteral(R"HTML(class="italic")HTML"))) {
183 return rewriteTag(parts, i, "i");
184 } else if (part.contains(QStringLiteral(R"HTML(class="chaptertitle")HTML"))) {
185 return rewriteTitle(parts, i, "b");
186 } else if (part.contains(QStringLiteral(R"HTML(class="sectiontitle")HTML"))) {
187 return rewriteTitle(parts, i, "b");
188 } else if (part.contains(QStringLiteral(R"HTML(class="booktitle")HTML"))) {
189 return rewriteTitle(parts, i, "b");
190 }
191 return 3;
192}
193
194QString processText(const QString &text) {
195 if (text.isEmpty())
196 return text;
197 QString localText = text;
198 { // Fix !P tag which is not rich text:
199 int index = 0;
200 while ((index = localText.indexOf(QStringLiteral("<!P>"))) >= 0)
201 localText.remove(index,4);
202 }
203 auto parts = splitText(localText);
204 fixDoubleBR(parts);
205
206 for (int i = 0; i < parts.count();) {
207 if (auto const & part = parts.at(i); part.startsWith('<')) { // is tag
208 if (part.contains(QStringLiteral(R"HTML(class=)HTML"))) {
209 i += rewriteClass(parts, i, part);
210 } else if (part.contains(QStringLiteral(R"HTML(class="footnote")HTML"))) {
211 i += rewriteFootnoteAsLink(parts, i, part);
212 } else if (part.contains(QStringLiteral(R"HTML(href=")HTML"))) {
213 rewriteHref(parts, i, part);
214 ++i;
215 } else if (part.contains(QStringLiteral(R"HTML(lemma=")HTML"))
216 || part.contains(QStringLiteral(R"HTML(morph=")HTML")))
217 {
218 i += rewriteLemmaOrMorphAsLink(parts, i, part);
219 } else {
220 ++i;
221 }
222 } else {
223 ++i;
224 }
225 }
226 return parts.join(QString());
227}
228
229} // anonymous namespace
230
232 : QAbstractListModel(parent)
233 , m_firstEntry(0)
234 , m_maxEntries(0)
235 , m_displayRendering(defaultDisplayOptions, defaultFilterOptions)
236{}
237
239 m_moduleInfoList.clear();
240 for (auto const & moduleName : m_modules)
241 m_moduleInfoList.append(
242 CSwordBackend::instance().findModuleByName(
243 moduleName));
244
245 beginResetModel();
246 const CSwordModuleInfo* firstModule = m_moduleInfoList.at(0);
247 if (isBible() || isCommentary()) {
248 CSwordBibleModuleInfo const * const m =
249 static_cast<const CSwordBibleModuleInfo *>(firstModule);
252 } else if(isLexicon()) {
254 static_cast<CSwordLexiconModuleInfo const *>(firstModule)
255 ->entries().size();
256 } else if(isBook()) {
257 sword::TreeKeyIdx tk(
258 *static_cast<CSwordBookModuleInfo const *>(firstModule)
259 ->tree());
260 tk.root();
261 tk.firstChild();
262 BT_ASSERT(tk.getOffset() == 4);
263 tk.setPosition(sword::BOTTOM);
264 m_maxEntries = tk.getOffset() / 4;
265 }
266
267 endResetModel();
268}
269
270void BtModuleTextModel::setModules(const QStringList& modules) {
271 m_modules = modules;
273}
274
275
276QVariant BtModuleTextModel::data(const QModelIndex & index, int role) const {
277
278 QString text;
279 if (isBible() || isCommentary())
280 text = verseData(index, role);
281 else if (isBook())
282 text = bookData(index, role);
283 else if (isLexicon())
284 text = lexiconData(index, role);
285 else
286 text = QStringLiteral("invalid");
287
288 text = processText(text);
289
290 if ( ! m_highlightWords.isEmpty()) {
293 true);
294 if (m_findState && index.row() == m_findState->index) {
295 // t = highlightFindPreviousNextField(t); now inlined:
296 int from = 0;
297 for (int i = 0; i < m_findState->subIndex; ++i) {
298 int pos = t.indexOf(QStringLiteral("\"highlightwords\""), from);
299 if (pos == -1)
300 return t;
301 else {
302 from = pos + 1;
303 }
304 }
305 int position = from + 14; // highlightwords = 14, quote was already added
306 t.insert(position, '2');
307 }
308 return QVariant(t);
309 }
310
311 return QVariant(text);
312}
313
314QString BtModuleTextModel::lexiconData(const QModelIndex & index, int role) const {
315 int row = index.row();
316
317 const CSwordLexiconModuleInfo *lexiconModule = qobject_cast<const CSwordLexiconModuleInfo*>(m_moduleInfoList.at(0));
318 BtConstModuleList moduleList;
319 moduleList << lexiconModule;
320 QString keyName = lexiconModule->entries()[row];
321
322 if (role == ModuleEntry::TextRole || role == ModuleEntry::Text0Role) {
323 if (keyName.isEmpty())
324 return {};
325 auto text = m_displayRendering.renderDisplayEntry(moduleList, keyName);
326 text.replace(QStringLiteral("#CHAPTERTITLE#"), QString());
327 text.replace(QStringLiteral("#TEXT_ALIGN#"), QStringLiteral("left"));
328 text = ColorManager::replaceColors(text);
329 return text;
330 }
331 else if (role == ModuleEntry::ReferenceRole){
332 return keyName;
333 }
334 return QString();
335}
336
337QString BtModuleTextModel::bookData(const QModelIndex & index, int role) const {
338 if (role == ModuleEntry::TextRole ||
339 role == ModuleEntry::Text0Role) {
340 const CSwordBookModuleInfo *bookModule = qobject_cast<const CSwordBookModuleInfo*>(m_moduleInfoList.at(0));
341 CSwordTreeKey key(bookModule->tree(), bookModule);
342 int bookIndex = index.row() * 4;
343 key.setOffset(bookIndex);
344 BtConstModuleList moduleList;
345 moduleList << bookModule;
346 if (key.key().isEmpty())
347 return {};
348 auto text =
350 moduleList,
351 key.key(),
354 : Rendering::CTextRendering::KeyTreeItem::Settings::NoKey);
355 text.replace(QStringLiteral("#CHAPTERTITLE#"), QString());
356 text.replace(QStringLiteral("#TEXT_ALIGN#"), QStringLiteral("left"));
357 return text;
358 }
359 return QString();
360}
361
362static int getColumnFromRole(int role) {
363 if (role >= ModuleEntry::Text0Role && role <= ModuleEntry::Text9Role)
364 return role - ModuleEntry::Text0Role;
366 return role - ModuleEntry::Title0Role;
367 if (role >= ModuleEntry::Edit0Role && role <= ModuleEntry::Edit9Role)
368 return role - ModuleEntry::Edit0Role;
369 return 0;
370}
371
372QString BtModuleTextModel::verseData(const QModelIndex & index, int role) const {
373 int row = index.row();
375 int verse = key.verse();
376
377 if (role >= ModuleEntry::TextRole && role <= ModuleEntry::Edit9Role) {
378 if (verse == 0)
379 return QString();
380 QString text;
381
382 QString chapterTitle;
383 if (verse == 1)
384 chapterTitle =
385 QStringLiteral("%1 %2").arg(key.bookName(),
386 QString::number(key.chapter()));
387
388 BtConstModuleList modules;
389 if ( role == ModuleEntry::TextRole) {
390 modules = m_moduleInfoList;
391 } else {
392 int column = getColumnFromRole(role);
393 CSwordModuleInfo const * module;
394 if ((column + 1) > m_moduleInfoList.count())
395 module = m_moduleInfoList.at(0);
396 else
397 module = m_moduleInfoList.at(column);
398 modules.append(module);
399 CSwordVerseKey mKey(module);
400 mKey.setKey(key.key());
401
402 // Title only for verse 1 of Personal commentary
403 if (role >= ModuleEntry::Title0Role && role <= ModuleEntry::Title9Role) {
404 if (module->isWritable() && verse == 1)
405 return QStringLiteral("<center><h3>%1</h3></center>")
406 .arg(chapterTitle);
407 return {};
408 }
409
410 // Personal commentary
411 if (role >= ModuleEntry::Edit0Role && role <= ModuleEntry::Edit9Role)
412 return mKey.rawText();
413 if (module->isWritable()) {
414 auto const & rawText = mKey.rawText();
415 auto text =
416 QStringLiteral("%1 %2")
417 .arg(QString::number(verse),
418 rawText.isEmpty()
419 ? QStringLiteral("<span style=\"color:gray\">"
420 "<small>%1</small></span>")
421 .arg(tr("Click to edit"))
422 : rawText);
424 ColorManager::replaceColors(std::move(text)),
426 }
427 }
428
429 if (!key.key().isEmpty())
430 text +=
432 modules,
433 key.key(),
436 : Rendering::CTextRendering::KeyTreeItem::Settings::NoKey);
437
438 text.replace(QStringLiteral("#CHAPTERTITLE#"), chapterTitle);
439 text.replace(QStringLiteral("#TEXT_ALIGN#"), QStringLiteral("left"));
440 text = ColorManager::replaceColors(text);
441 return text;
442 }
443 return QString();
444}
445
446int BtModuleTextModel::columnCount(const QModelIndex & /*parent*/) const {
447 return 1;
448}
449
450int BtModuleTextModel::rowCount(const QModelIndex & /*parent*/) const {
451 return m_maxEntries;
452}
453
455 static auto const roleNames_ =
456 []() {
458 r[ModuleEntry::ReferenceRole] = "keyName"; // reference
459 r[ModuleEntry::TextRole] = "line"; // not used
460 r[ModuleEntry::Text0Role] = "text0"; // text in column 0
461 r[ModuleEntry::Text1Role] = "text1"; // text in column 1
462 r[ModuleEntry::Text2Role] = "text2"; // text in column 2
463 r[ModuleEntry::Text3Role] = "text3"; // text in column 3
464 r[ModuleEntry::Text4Role] = "text4"; // text in column 4
465 r[ModuleEntry::Text5Role] = "text5"; // text in column 5
466 r[ModuleEntry::Text6Role] = "text6"; // text in column 6
467 r[ModuleEntry::Text7Role] = "text7"; // text in column 7
468 r[ModuleEntry::Text8Role] = "text8"; // text in column 8
469 r[ModuleEntry::Text9Role] = "text9"; // text in column 9
470 r[ModuleEntry::Title0Role] = "title0"; // title in column 0
471 r[ModuleEntry::Title1Role] = "title1"; // title in column 1
472 r[ModuleEntry::Title2Role] = "title2"; // title in column 2
473 r[ModuleEntry::Title3Role] = "title3"; // title in column 3
474 r[ModuleEntry::Title4Role] = "title4"; // title in column 4
475 r[ModuleEntry::Title5Role] = "title5"; // title in column 5
476 r[ModuleEntry::Title6Role] = "title6"; // title in column 6
477 r[ModuleEntry::Title7Role] = "title7"; // title in column 7
478 r[ModuleEntry::Title8Role] = "title8"; // title in column 8
479 r[ModuleEntry::Title9Role] = "title9"; // title in column 9
480 return r;
481 }();
482 return roleNames_;
483}
484
485bool BtModuleTextModel::isBible() const {
486 const CSwordModuleInfo* module = m_moduleInfoList.at(0);
487 if (module == nullptr)
488 return false;
489 return module->type() == CSwordModuleInfo::Bible;
490}
491
492bool BtModuleTextModel::isBook() const {
493 const CSwordModuleInfo* module = m_moduleInfoList.at(0);
494 if (module == nullptr)
495 return false;
496 return module->type() == CSwordModuleInfo::GenericBook;
497}
498
500 const CSwordModuleInfo* module = m_moduleInfoList.at(0);
501 if (module == nullptr)
502 return false;
503 return module->type() == CSwordModuleInfo::Commentary;
504}
505
506bool BtModuleTextModel::isLexicon() const {
507 const CSwordModuleInfo* module = m_moduleInfoList.at(0);
508 if (module == nullptr)
509 return false;
510 return module->type() == CSwordModuleInfo::Lexicon;
511}
512
513// Function is valid for Bibles, Commentaries, and Books
514int BtModuleTextModel::keyToIndex(CSwordKey const & key) const {
515 if (auto const * const treeKey = dynamic_cast<CSwordTreeKey const *>(&key))
516 return treeKey->offset() / 4u;
517 if (auto const * const vKey = dynamic_cast<CSwordVerseKey const *>(&key))
518 return vKey->index();
519 return 0;
520}
521
523 int index = key.index() - m_firstEntry;
524 return index;
525}
526
528{ return indexToVerseKey(index, *m_moduleInfoList.front()); }
529
532 CSwordModuleInfo const & module) const
533{
534 CSwordVerseKey key(&module);
535 key.setIntros(true);
536 key.setIndex(index + m_firstEntry);
537 return key;
538}
539
540int BtModuleTextModel::indexToVerse(int index) const
541{
542 const CSwordModuleInfo* module = m_moduleInfoList.at(0);
543 CSwordVerseKey key(module);
544
545 key.setIntros(true);
546 key.setIndex(index + m_firstEntry);
547 return key.verse();
548}
549
550CSwordKey* BtModuleTextModel::indexToKey(int index, int moduleNum) const
551{
552 const CSwordModuleInfo* module = m_moduleInfoList.at(moduleNum);
553 auto * const key = module->createKey();
554 QString keyName = indexToKeyName(index);
555 key->setKey(keyName);
556 return key;
557}
558
560{
561 const CSwordModuleInfo* module = m_moduleInfoList.at(0);
562 const CSwordBookModuleInfo *bookModule = qobject_cast<const CSwordBookModuleInfo*>(module);
563 CSwordTreeKey key(bookModule->tree(), bookModule);
564 int bookIndex = index * 4;
565 key.setOffset(bookIndex);
566 return key;
567}
568
569QString BtModuleTextModel::indexToKeyName(int index) const {
570 if (index < 0)
571 return {};
572 if (isBible() || isCommentary())
573 return indexToVerseKey(index).key();
574 if (isBook())
575 return indexToBookKey(index).key();
576 if (isLexicon())
577 return qobject_cast<CSwordLexiconModuleInfo const *>(
578 m_moduleInfoList.at(0))->entries()[index];
579 return QStringLiteral("???");
580}
581
582void BtModuleTextModel::setFindState(std::optional<FindState> findState) {
583 if (m_findState
584 && (!findState || (m_findState->index != findState->index)))
585 {
586 QModelIndex oldIndexToClear = index(m_findState->index, 0);
587 m_findState = std::move(findState);
588 Q_EMIT dataChanged(oldIndexToClear, oldIndexToClear);
589 } else {
590 m_findState = std::move(findState);
591 }
592 if (m_findState) {
593 QModelIndex index = this->index(m_findState->index, 0);
594 Q_EMIT dataChanged(index, index);
595 }
596}
598 const QString& highlightWords, bool /* caseSensitive */) {
599 beginResetModel();
600 m_highlightWords = highlightWords;
601 endResetModel();
602}
603
604void BtModuleTextModel::setOptions(DisplayOptions const & displayOptions,
605 FilterOptions const & filterOptions)
606{
608 displayOptions)
610 filterOptions))
611 return;
612 beginResetModel();
615 endResetModel();
616}
617
619 const QModelIndex &index,
620 const QVariant &value,
621 int role) {
622 if (role < ModuleEntry::Edit0Role || role > ModuleEntry::Edit9Role)
623 return false;
624 auto const & module = *m_moduleInfoList.at(getColumnFromRole(role));
625 CSwordVerseKey mKey(indexToVerseKey(index.row(), module));
626 const_cast<CSwordModuleInfo &>(module).write(&mKey, value.toString());
627 Q_EMIT dataChanged(index, index);
628 return true;
629}
#define BT_ASSERT(...)
Definition btassert.h:17
QList< CSwordModuleInfo const * > BtConstModuleList
QString bookData(const QModelIndex &index, int role=Qt::DisplayRole) const
CSwordKey * indexToKey(int index, int moduleNum) const
int rowCount(const QModelIndex &parent=QModelIndex()) const override
bool isBible() const
std::optional< FindState > m_findState
int verseKeyToIndex(const CSwordVerseKey &key) const
int columnCount(const QModelIndex &parent=QModelIndex()) const override
CSwordTreeKey indexToBookKey(int index) const
BtConstModuleList m_moduleInfoList
BtModuleTextModel(QObject *parent=nullptr)
bool isLexicon() const
QString lexiconData(const QModelIndex &index, int role=Qt::DisplayRole) const
bool isCommentary() const
void setModules(const QStringList &modules)
void setHighlightWords(const QString &highlightWords, bool caseSensitive)
int keyToIndex(CSwordKey const &key) const
int indexToVerse(int index) const
bool isBook() const
CSwordVerseKey indexToVerseKey(int index) const
QString verseData(const QModelIndex &index, int role=Qt::DisplayRole) const
void setOptions(DisplayOptions const &displayOptions, FilterOptions const &filterOptions)
QString indexToKeyName(int index) const
QHash< int, QByteArray > roleNames() const override
virtual bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
Rendering::CDisplayRendering m_displayRendering
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
void setFindState(std::optional< FindState > findState)
The backend layer main class, a backend implementation of Sword.
Implementation for Sword Bibles.
CSwordVerseKey const & lowerBound() const
CSwordVerseKey const & upperBound() const
Class for generic book support.
sword::TreeKeyIdx * tree() const
const QStringList & entries() const
CSwordKey implementation for Sword's TreeKey.
QString key() const final override
CSwordKey implementation for Sword's VerseKey.
QString bookName() const
void setIndex(long v)
void setIntros(bool v)
QString key() const final override
int verse() const
long index() const
int chapter() const
QString renderDisplayEntry(BtConstModuleList const &modules, QString const &key, CTextRendering::KeyTreeItem::Settings::KeyRenderingFace keyRendering=CTextRendering::KeyTreeItem::Settings::CompleteShort) const
FilterOptions const & filterOptions() const noexcept
void setFilterOptions(FilterOptions const &filterOptions) noexcept
DisplayOptions const & displayOptions() const noexcept
void setDisplayOptions(DisplayOptions const &displayOptions) noexcept
QStringList r(content.left(bodyIndex))
QString highlightSearchedText(QString const &content, QString const &searchedText, bool plainSearchedText)
QString replaceColors(QString content)
bool displayOptionsAreEqual(DisplayOptions const &opts) const noexcept
Definition btglobal.cpp:55
int morphSegmentation
Definition btglobal.h:37
int hebrewCantillation
Definition btglobal.h:32
int textualVariants
Definition btglobal.h:34
int hebrewPoints
Definition btglobal.h:31
int scriptureReferences
Definition btglobal.h:36
int greekAccents
Definition btglobal.h:33
int redLetterWords
Definition btglobal.h:35
bool filterOptionsAreEqual(FilterOptions const &opts) const noexcept
Definition btglobal.cpp:38
int strongNumbers
Definition btglobal.h:27
@ SimpleKey
means only versenumber or only lexicon entry name