BibleTime
cdisplayrendering.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 "cdisplayrendering.h"
14
15#include <QRegularExpression>
16#include <QString>
17#include <QtGlobal>
18#include "../../util/btassert.h"
19#include "../config/btconfig.h"
20#include "../drivers/cswordmoduleinfo.h"
21#include "../keys/cswordkey.h"
22#include "../keys/cswordversekey.h"
23#include "../managers/cdisplaytemplatemgr.h"
24#include "../managers/referencemanager.h"
25
26// Sword includes:
27#pragma GCC diagnostic push
28#pragma GCC diagnostic ignored "-Wextra-semi"
29#pragma GCC diagnostic ignored "-Wsuggest-override"
30#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
31#ifdef __clang__
32#pragma clang diagnostic push
33#pragma clang diagnostic ignored "-Wsuggest-destructor-override"
34#endif
35#include <swmodule.h>
36#include <listkey.h>
37#include <versekey.h> // For search scope configuration
38#ifdef __clang__
39#pragma clang diagnostic pop
40#endif
41#pragma GCC diagnostic pop
42
43namespace Rendering {
44
46 : CDisplayRendering(btConfig().getDisplayOptions(),
47 btConfig().getFilterOptions())
48{}
49
51 FilterOptions const & filterOptions)
52 : CTextRendering(true, displayOptions, filterOptions)
53{}
54
56 BtConstModuleList const & modules,
57 QString const & keyName,
59 const
60{
61 BT_ASSERT(!keyName.isEmpty());
62
63 //no highlighted key and no extra key link in the text
64 const CSwordModuleInfo *module = modules.first();
65
67
68 //in Bibles and Commentaries we need to check if 0:0 and X:0 contain something
69 if (module->type() == CSwordModuleInfo::Bible
70 || module->type() == CSwordModuleInfo::Commentary)
71 {
72 // HACK: enable headings for VerseKeys
73 static_cast<sword::VerseKey *>(module->swordModule().getKey())
74 ->setIntros(true);
75
76 CSwordVerseKey k1(module);
77 k1.setIntros(true);
78 k1.setKey(keyName);
79
80 // don't print the key
82 false,
84
85 if (k1.verse() == 1) { // X:1, prepend X:0
86 if (k1.chapter() == 1) { // 1:1, also prepend 0:0 before that
87 k1.setChapter(0);
88 k1.setVerse(0);
89 if (k1.rawText().length() > 0)
90 tree.emplace_back(k1.key(), modules, preverse_settings);
91 k1.setChapter(1);
92 }
93 k1.setVerse(0);
94 if (k1.rawText().length() > 0)
95 tree.emplace_back(k1.key(), modules, preverse_settings);
96 }
97 }
99 tree.emplace_back(keyName, modules, Settings{false, keyRendering});
100 return renderKeyTree(tree);
101}
102
104 CSwordModuleInfo const & module) const
105{
106 QString linkText;
107
108 const bool isBible = module.type() == CSwordModuleInfo::Bible;
109 CSwordVerseKey vk(&module); // only valid for bible modules, i.e. isBible == true
110 vk.setIntros(true);
111
112 if (isBible) {
113 vk.setKey(item.mappedKey() ? item.mappedKey()->key() : item.key());
114 }
115
116 if (isBible && (vk.verse() == 0)) {
117 return QString(); //Warning: return already here
118 }
119
120 switch (item.settings().keyRenderingFace) {
121
122 case KeyTreeItem::Settings::NoKey:
123 linkText = QString();
124 break; //no key is valid for all modules
125
126 case KeyTreeItem::Settings::ExpandedShort:
127 if (isBible) {
128 linkText = module.name() + ':' + vk.shortText();
129 break;
130 }
131 [[fallthrough]];
132
133 case KeyTreeItem::Settings::CompleteShort:
134 if (isBible) {
135 linkText = vk.shortText();
136 break;
137 }
138 [[fallthrough]];
139
140 case KeyTreeItem::Settings::ExpandedLong:
141 if (isBible) {
142 linkText = QStringLiteral("%1 (%2)").arg(vk.key(), module.name());
143 break;
144 }
145 [[fallthrough]];
146
147 case KeyTreeItem::Settings::CompleteLong:
148 if (isBible) {
149 linkText = vk.key();
150 break;
151 }
152 [[fallthrough]];
153
154 case KeyTreeItem::Settings::SimpleKey:
155 if (isBible) {
156 if(item.mappedKey() != nullptr) {
157 CSwordVerseKey baseKey(*item.modules().begin());
158 baseKey.setKey(item.key());
159
160 if (vk.bookName() != baseKey.bookName()) {
161 linkText = vk.shortText();
162 } else if (vk.chapter() != baseKey.chapter()) {
163 linkText =
164 QStringLiteral("%1:%2")
165 .arg(vk.chapter())
166 .arg(vk.verse());
167 } else {
168 linkText = QString::number(vk.verse());
169 }
170
171 if(vk.isBoundSet()) {
172 linkText += '-';
173 auto const upper = vk.upperBound();
174 auto const lower = vk.lowerBound();
175 if (upper.book() != lower.book()) {
176 linkText += upper.shortText();
177 } else if(upper.chapter() != lower.chapter()) {
178 linkText += QStringLiteral("%1:%2").arg(upper.chapter())
179 .arg(lower.verse());
180 } else {
181 linkText += QString::number(upper.verse());
182 }
183 }
184 } else {
185 linkText = QString::number(vk.verse());
186 }
187 break;
188 } // else fall through for non-Bible modules
189 [[fallthrough]];
190
191 default: //default behaviour to return the passed key
192 linkText = item.key();
193 break;
194
195 }
196
197
198 if (linkText.isEmpty()) {
199 return QStringLiteral("<a name=\"%1\"></a>").arg(
200 keyToHTMLAnchor(item.key()));
201 }
202 else {
203 return QStringLiteral("<a name=\"%1\" href=\"%2\">%3</a>\n")
204 .arg(keyToHTMLAnchor(item.key()),
206 linkText);
207 }
208}
209
210QString CDisplayRendering::keyToHTMLAnchor(QString const & key) {
211 // Be careful not to remove non-ASCII characters, this causes problems
212 // with many languages.
213 static QRegularExpression const re(QStringLiteral(R"PCRE(\s)PCRE"));
214 return key.trimmed().remove(re).replace(':', '_');
215}
216
217QString
218CDisplayRendering::finishText(QString const & text, KeyTree const & tree) const
219{
220 BtConstModuleList modules = collectModules(tree);
221
222 //marking words is very slow, we have to find a better solution
223
224 /*
225 //mark all words by spans
226
227 QString text = oldText;
228
229 QRegExp re("(\\b)(?=\\w)"); //word begin marker
230 int pos = text.find(re, 0);
231
232 while (pos != -1) { //word begin found
233 //qWarning("found word at %i in %i", pos, text.length());
234 int endPos = pos + 1;
235 if (!util::tool::inHTMLTag(pos+1, text)) { //the re has a positive look ahead which matches one char before the word start
236 //qWarning("matched %s", text.mid(pos+1, 4).latin1());
237
238 //find end of word and put a marker around it
239 endPos = text.find(QRegExp("\\b|[,.:]"), pos+1);
240 if ((endPos != -1) && !util::tool::inHTMLTag(endPos, text) && (endPos - pos >= 3)) { //reuire wordslonger than 3 chars
241 text.insert(endPos, "</span>");
242 text.insert(pos, "<span class=\"word\">");
243
244 endPos += 26;
245 }
246 }
247 pos = text.find(re, endPos);
248 }
249 */
250
252
253 //BT_ASSERT(modules.count() >= 1);
254
256 settings.modules = modules;
257 if (modules.count() == 1)
258 if (auto const lang = modules.first()->language())
259 if (auto const & abbrev = lang->abbrev(); !abbrev.isEmpty())
260 settings.langAbbrev = abbrev;
261
262 if (modules.count() == 1)
263 settings.textDirection = modules.first()->textDirection();
264
265 return tMgr->fillTemplate(m_displayTemplateName.isEmpty()
268 text,
269 settings);
270}
271}
#define BT_ASSERT(...)
Definition btassert.h:17
BtConfig & btConfig()
This is a shortchand for BtConfig::getInstance().
Definition btconfig.h:305
QList< CSwordModuleInfo const * > BtConstModuleList
QString fillTemplate(const QString &name, const QString &content, const Settings &settings) const
Fills the template.
static QString activeTemplateName()
static CDisplayTemplateMgr * instance()
QString rawText()
Definition cswordkey.cpp:45
virtual QString key() const =0
QString const & name() const
CSwordKey implementation for Sword's VerseKey.
CSwordVerseKey upperBound() const
void setChapter(int v)
QString bookName() const
void setIntros(bool v)
QString key() const final override
bool setKey(const QString &key) final override
int verse() const
bool isBoundSet() const
int chapter() const
QString shortText() const
void setVerse(int v)
CSwordVerseKey lowerBound() const
Rendering for the html display widget.
QString entryLink(KeyTreeItem const &item, CSwordModuleInfo const &module) const override
static QString keyToHTMLAnchor(QString const &key)
QString finishText(QString const &text, KeyTree const &tree) const override
QString renderDisplayEntry(BtConstModuleList const &modules, QString const &key, CTextRendering::KeyTreeItem::Settings::KeyRenderingFace keyRendering=CTextRendering::KeyTreeItem::Settings::CompleteShort) const
CSwordKey const * mappedKey() const
BtConstModuleList const & modules() const
Text rendering based on trees.
std::list< KeyTreeItem > KeyTree
QString renderKeyTree(KeyTree const &tree) const
static BtConstModuleList collectModules(KeyTree const &tree)
QString encodeHyperlink(CSwordModuleInfo const &module, QString const &key)
CSwordModuleInfo::TextDirection textDirection