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-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 <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 return ColorManager::replaceColors(std::move(text));
329 }
330 else if (role == ModuleEntry::ReferenceRole){
331 return keyName;
332 }
333 return QString();
334}
335
336QString BtModuleTextModel::bookData(const QModelIndex & index, int role) const {
337 if (role == ModuleEntry::TextRole ||
338 role == ModuleEntry::Text0Role) {
339 const CSwordBookModuleInfo *bookModule = qobject_cast<const CSwordBookModuleInfo*>(m_moduleInfoList.at(0));
340 CSwordTreeKey key(bookModule->tree(), bookModule);
341 int bookIndex = index.row() * 4;
342 key.setOffset(bookIndex);
343 BtConstModuleList moduleList;
344 moduleList << bookModule;
345 if (key.key().isEmpty())
346 return {};
347 auto text =
349 moduleList,
350 key.key(),
353 : Rendering::CTextRendering::KeyTreeItem::Settings::NoKey);
354 text.replace(QStringLiteral("#CHAPTERTITLE#"), QString());
355 text.replace(QStringLiteral("#TEXT_ALIGN#"), QStringLiteral("left"));
356 return ColorManager::replaceColors(std::move(text));
357 }
358 return QString();
359}
360
361static int getColumnFromRole(int role) {
362 if (role >= ModuleEntry::Text0Role && role <= ModuleEntry::Text9Role)
363 return role - ModuleEntry::Text0Role;
365 return role - ModuleEntry::Title0Role;
366 if (role >= ModuleEntry::Edit0Role && role <= ModuleEntry::Edit9Role)
367 return role - ModuleEntry::Edit0Role;
368 return 0;
369}
370
371QString BtModuleTextModel::verseData(const QModelIndex & index, int role) const {
372 int row = index.row();
374 int verse = key.verse();
375
376 if (role >= ModuleEntry::TextRole && role <= ModuleEntry::Edit9Role) {
377 if (verse == 0)
378 return QString();
379
380 QString chapterTitle;
381 if (verse == 1)
382 chapterTitle =
383 QStringLiteral("%1 %2").arg(key.bookName(),
384 QString::number(key.chapter()));
385
386 BtConstModuleList modules;
387 if ( role == ModuleEntry::TextRole) {
388 modules = m_moduleInfoList;
389 } else {
390 int column = getColumnFromRole(role);
391 CSwordModuleInfo const * module;
392 if ((column + 1) > m_moduleInfoList.count())
393 module = m_moduleInfoList.at(0);
394 else
395 module = m_moduleInfoList.at(column);
396 modules.append(module);
397 CSwordVerseKey mKey(module);
398 mKey.setKey(key.key());
399
400 // Title only for verse 1 of Personal commentary
401 if (role >= ModuleEntry::Title0Role && role <= ModuleEntry::Title9Role) {
402 if (module->isWritable() && verse == 1)
403 return QStringLiteral("<center><h3>%1</h3></center>")
404 .arg(chapterTitle);
405 return {};
406 }
407
408 // Personal commentary
409 if (role >= ModuleEntry::Edit0Role && role <= ModuleEntry::Edit9Role)
410 return mKey.rawText();
411 if (module->isWritable()) {
412 auto const & rawText = mKey.rawText();
413 auto text =
414 QStringLiteral("%1 %2")
415 .arg(QString::number(verse),
416 rawText.isEmpty()
417 ? QStringLiteral("<span style=\"color:gray\">"
418 "<small>%1</small></span>")
419 .arg(tr("Click to edit"))
420 : rawText);
422 ColorManager::replaceColors(std::move(text)),
424 }
425 }
426
427 QString text;
428 if (!key.key().isEmpty())
429 text +=
431 modules,
432 key.key(),
435 : Rendering::CTextRendering::KeyTreeItem::Settings::NoKey);
436
437 text.replace(QStringLiteral("#CHAPTERTITLE#"), chapterTitle);
438 text.replace(QStringLiteral("#TEXT_ALIGN#"), QStringLiteral("left"));
439 return ColorManager::replaceColors(std::move(text));
440 }
441 return QString();
442}
443
444int BtModuleTextModel::columnCount(const QModelIndex & /*parent*/) const {
445 return 1;
446}
447
448int BtModuleTextModel::rowCount(const QModelIndex & /*parent*/) const {
449 return m_maxEntries;
450}
451
453 static auto const roleNames_ =
454 []() {
456 r[ModuleEntry::ReferenceRole] = "keyName"; // reference
457 r[ModuleEntry::TextRole] = "line"; // not used
458 r[ModuleEntry::Text0Role] = "text0"; // text in column 0
459 r[ModuleEntry::Text1Role] = "text1"; // text in column 1
460 r[ModuleEntry::Text2Role] = "text2"; // text in column 2
461 r[ModuleEntry::Text3Role] = "text3"; // text in column 3
462 r[ModuleEntry::Text4Role] = "text4"; // text in column 4
463 r[ModuleEntry::Text5Role] = "text5"; // text in column 5
464 r[ModuleEntry::Text6Role] = "text6"; // text in column 6
465 r[ModuleEntry::Text7Role] = "text7"; // text in column 7
466 r[ModuleEntry::Text8Role] = "text8"; // text in column 8
467 r[ModuleEntry::Text9Role] = "text9"; // text in column 9
468 r[ModuleEntry::Title0Role] = "title0"; // title in column 0
469 r[ModuleEntry::Title1Role] = "title1"; // title in column 1
470 r[ModuleEntry::Title2Role] = "title2"; // title in column 2
471 r[ModuleEntry::Title3Role] = "title3"; // title in column 3
472 r[ModuleEntry::Title4Role] = "title4"; // title in column 4
473 r[ModuleEntry::Title5Role] = "title5"; // title in column 5
474 r[ModuleEntry::Title6Role] = "title6"; // title in column 6
475 r[ModuleEntry::Title7Role] = "title7"; // title in column 7
476 r[ModuleEntry::Title8Role] = "title8"; // title in column 8
477 r[ModuleEntry::Title9Role] = "title9"; // title in column 9
478 return r;
479 }();
480 return roleNames_;
481}
482
483bool BtModuleTextModel::isBible() const {
484 const CSwordModuleInfo* module = m_moduleInfoList.at(0);
485 if (module == nullptr)
486 return false;
487 return module->type() == CSwordModuleInfo::Bible;
488}
489
490bool BtModuleTextModel::isBook() const {
491 const CSwordModuleInfo* module = m_moduleInfoList.at(0);
492 if (module == nullptr)
493 return false;
494 return module->type() == CSwordModuleInfo::GenericBook;
495}
496
498 const CSwordModuleInfo* module = m_moduleInfoList.at(0);
499 if (module == nullptr)
500 return false;
501 return module->type() == CSwordModuleInfo::Commentary;
502}
503
504bool BtModuleTextModel::isLexicon() const {
505 const CSwordModuleInfo* module = m_moduleInfoList.at(0);
506 if (module == nullptr)
507 return false;
508 return module->type() == CSwordModuleInfo::Lexicon;
509}
510
511// Function is valid for Bibles, Commentaries, and Books
512int BtModuleTextModel::keyToIndex(CSwordKey const & key) const {
513 if (auto const * const treeKey = dynamic_cast<CSwordTreeKey const *>(&key))
514 return treeKey->offset() / 4u;
515 if (auto const * const vKey = dynamic_cast<CSwordVerseKey const *>(&key))
516 return vKey->index();
517 return 0;
518}
519
521 int index = key.index() - m_firstEntry;
522 return index;
523}
524
526{ return indexToVerseKey(index, *m_moduleInfoList.front()); }
527
530 CSwordModuleInfo const & module) const
531{
532 CSwordVerseKey key(&module);
533 key.setIntros(true);
534 key.setIndex(index + m_firstEntry);
535 return key;
536}
537
538int BtModuleTextModel::indexToVerse(int index) const
539{
540 const CSwordModuleInfo* module = m_moduleInfoList.at(0);
541 CSwordVerseKey key(module);
542
543 key.setIntros(true);
544 key.setIndex(index + m_firstEntry);
545 return key.verse();
546}
547
548CSwordKey* BtModuleTextModel::indexToKey(int index, int moduleNum) const
549{
550 const CSwordModuleInfo* module = m_moduleInfoList.at(moduleNum);
551 auto * const key = module->createKey();
552 QString keyName = indexToKeyName(index);
553 key->setKey(keyName);
554 return key;
555}
556
558{
559 const CSwordModuleInfo* module = m_moduleInfoList.at(0);
560 const CSwordBookModuleInfo *bookModule = qobject_cast<const CSwordBookModuleInfo*>(module);
561 CSwordTreeKey key(bookModule->tree(), bookModule);
562 int bookIndex = index * 4;
563 key.setOffset(bookIndex);
564 return key;
565}
566
567QString BtModuleTextModel::indexToKeyName(int index) const {
568 if (index < 0)
569 return {};
570 if (isBible() || isCommentary())
571 return indexToVerseKey(index).key();
572 if (isBook())
573 return indexToBookKey(index).key();
574 if (isLexicon())
575 return qobject_cast<CSwordLexiconModuleInfo const *>(
576 m_moduleInfoList.at(0))->entries()[index];
577 return QStringLiteral("???");
578}
579
580void BtModuleTextModel::setFindState(std::optional<FindState> findState) {
581 if (m_findState
582 && (!findState || (m_findState->index != findState->index)))
583 {
584 QModelIndex oldIndexToClear = index(m_findState->index, 0);
585 m_findState = std::move(findState);
586 Q_EMIT dataChanged(oldIndexToClear, oldIndexToClear);
587 } else {
588 m_findState = std::move(findState);
589 }
590 if (m_findState) {
591 QModelIndex index = this->index(m_findState->index, 0);
592 Q_EMIT dataChanged(index, index);
593 }
594}
596 const QString& highlightWords, bool /* caseSensitive */) {
597 beginResetModel();
598 m_highlightWords = highlightWords;
599 endResetModel();
600}
601
602void BtModuleTextModel::setOptions(DisplayOptions const & displayOptions,
603 FilterOptions const & filterOptions)
604{
606 displayOptions)
608 filterOptions))
609 return;
610 beginResetModel();
613 endResetModel();
614}
615
617 const QModelIndex &index,
618 const QVariant &value,
619 int role) {
620 if (role < ModuleEntry::Edit0Role || role > ModuleEntry::Edit9Role)
621 return false;
622 auto const & module = *m_moduleInfoList.at(getColumnFromRole(role));
623 CSwordVerseKey mKey(indexToVerseKey(index.row(), module));
624 const_cast<CSwordModuleInfo &>(module).write(&mKey, value.toString());
625 Q_EMIT dataChanged(index, index);
626 return true;
627}
#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