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