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-2021 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 
43 namespace 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
81  CTextRendering::KeyTreeItem::Settings preverse_settings{
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()),
205  ReferenceManager::encodeHyperlink(module, item.key()),
206  linkText);
207  }
208 }
209 
210 QString 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 
217 QString
218 CDisplayRendering::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
Definition: btmodulelist.h:21
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
ModuleType type() const
QString const & name() const
sword::SWModule & swordModule() 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
Settings const & settings() 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