BibleTime
teitohtml.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 "teitohtml.h"
14 
15 #include <QString>
16 #include <string_view>
17 #include "../config/btconfig.h"
18 #include "../drivers/cswordmoduleinfo.h"
19 #include "../managers/cswordbackend.h"
20 #include "../managers/referencemanager.h"
21 
22 // Sword includes:
23 #pragma GCC diagnostic push
24 #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
25 #include <swbuf.h>
26 #include <swmodule.h>
27 #include <utilxml.h>
28 #pragma GCC diagnostic pop
29 
30 
31 namespace Filters {
32 
34  : sword::TEIHTMLHREF()
35 {
36  setPassThruUnknownEscapeString(true); // the HTML widget will render the HTML escape codes
37 }
38 
39 bool TeiToHtml::handleToken(sword::SWBuf &buf, const char *token,
40  sword::BasicFilterUserData *userData)
41 {
42  using namespace std::literals;
43  // manually process if it wasn't a simple substitution
44 
45  if (!substituteToken(buf, token)) {
46 
47  sword::XMLTag const tag(token);
48  std::string_view const tagName(tag.getName());
49 
50  if (tagName == "ref"sv) {
51 
52  if (!tag.isEndTag() && !tag.isEmpty()) {
53 
54  const char * attribute = tag.getAttribute("osisRef");
55  if (attribute != nullptr)
56  renderReference(attribute, buf, userData);
57  else {
58  attribute = tag.getAttribute("target");
59  renderTargetReference(attribute, buf, userData);
60  }
61 
62  }
63  else if (tag.isEndTag()) {
64  buf.append("</a>");
65  }
66  else { // empty reference marker
67  // -- what should we do? nothing for now.
68  }
69  }
70  else if (tagName == "hi"sv) { // <hi> highlighted text
71  const sword::SWBuf type = tag.getAttribute("rend");
72 
73  if ((!tag.isEndTag()) && (!tag.isEmpty())) {
74  if (type == "bold") {
75  buf.append("<span class=\"bold\">");
76  }
77  else if (type == "illuminated") {
78  buf.append("<span class=\"illuminated\">");
79  }
80  else if (type == "italic") {
81  buf.append("<span class=\"italic\">");
82  }
83  else if (type == "line-through") {
84  buf.append("<span class=\"line-through\">");
85  }
86  else if (type == "normal") {
87  buf.append("<span class=\"normal\">");
88  }
89  else if (type == "small-caps") {
90  buf.append("<span class=\"small-caps\">");
91  }
92  else if (type == "underline") {
93  buf.append("<span class=\"underline\">");
94  }
95  else {
96  buf.append("<span>"); //don't break markup, </span> is inserted later
97  }
98  }
99  else if (tag.isEndTag()) { //all hi replacements are html spans
100  buf.append("</span>");
101  }
102  }
103  else { //all tokens handled by OSISHTMLHref will run through the filter now
104  return sword::TEIHTMLHREF::handleToken(buf, token, userData);
105  }
106  }
107 
108  return false;
109 }
110 
111 void TeiToHtml::renderReference(const char *osisRef, sword::SWBuf &buf,
112  sword::BasicFilterUserData *myUserData)
113 {
114 
115  if (QString ref = osisRef; !ref.isEmpty()) {
116  //find out the mod, using the current module makes sense if it's a bible or commentary because the refs link into a bible by default.
117  //If the osisRef is something like "ModuleID:key comes here" then the
118  // modulename is given, so we'll use that one
119 
120  CSwordModuleInfo * mod;
121  QString hrefRef;
122 
123  //if the osisRef like "GerLut:key" contains a module, use that
124  if (auto const pos = ref.indexOf(':');
125  (pos > 0)
126  && (pos < ref.size() - 1)
127  && ref.at(pos - 1).isLetter()
128  && ref.at(pos + 1).isLetter())
129  {
130  hrefRef = ref.mid(pos + 1);
131  mod = CSwordBackend::instance().findModuleByName(ref.left(pos));
132  if (!mod)
134  QStringLiteral("standardBible"));
135  } else {
136  hrefRef = ref;
138  QStringLiteral("standardBible"));
139  }
140  if (!mod)
143 
144  if (mod) {
145  ReferenceManager::ParseOptions const options{
146  mod->name(),
147  QString::fromUtf8(myUserData->key->getText()),
148  mod->swordModule().getLanguage()};
149 
150  buf.append("<a href=\"")
151  .append( // create the hyperlink with key and mod
153  *mod,
154  ReferenceManager::parseVerseReference(hrefRef, options)
155  ).toUtf8().constData()
156  )
157  .append("\" crossrefs=\"")
158  // ref must contain the osisRef module marker if there was any:
159  .append(ReferenceManager::parseVerseReference(ref, options).toUtf8().constData())
160  .append("\">");
161  }
162  // should we add something if there were no referenced module available?
163  }
164 }
165 
166 void TeiToHtml::renderTargetReference(const char *osisRef, sword::SWBuf &buf,
167  sword::BasicFilterUserData *myUserData)
168 {
169  if (QString ref = osisRef; !ref.isEmpty()) {
170  //find out the mod, using the current module makes sense if it's a bible or commentary because the refs link into a bible by default.
171  //If the target is something like "ModuleID:key comes here" then the
172  // modulename is given, so we'll use that one
173 
174  CSwordModuleInfo * mod;
175  auto const & backend = CSwordBackend::instance();
176 
177  //if the target like "GerLut:key" contains a module, use that
178  if (auto const pos = ref.indexOf(':'); pos >= 0) {
179  QString newModuleName = ref.left(pos);
180  ref.remove(0, pos + 1);
181 
182  mod = backend.findModuleByName(newModuleName);
183  if (!mod)
184  mod = backend.findModuleByName(myUserData->module->getName());
185  } else {
186  mod = backend.findModuleByName(myUserData->module->getName());
187  }
188 
189  if (mod) {
190  ReferenceManager::ParseOptions const options{
191  mod->name(),
192  QString::fromUtf8(myUserData->key->getText()),
193  mod->swordModule().getLanguage()};
194 
195  buf.append("<a class=\"crossreference\" href=\"")
196  .append( // create the hyperlink with key and mod
198  *mod,
199  ref.toUtf8().constData()
200  ).toUtf8().constData()
201  )
202  .append("\">");
203  }
204  }
205 }
206 
207 } // namespace Filters
BtConfig & btConfig()
This is a shortchand for BtConfig::getInstance().
Definition: btconfig.h:305
CSwordModuleInfo * getDefaultSwordModuleByType(const QString &moduleType)
Returns default sword module info class for a given module type.
Definition: btconfig.cpp:503
CSwordModuleInfo * findFirstAvailableModule(CSwordModuleInfo::ModuleType type)
CSwordModuleInfo * findModuleByName(const QString &name) const
Searches for a module with the given name.
static CSwordBackend & instance() noexcept
Definition: cswordbackend.h:98
QString const & name() const
sword::SWModule & swordModule() const
void renderTargetReference(const char *osisRef, sword::SWBuf &buf, sword::BasicFilterUserData *myUserData)
Definition: teitohtml.cpp:166
void renderReference(const char *osisRef, sword::SWBuf &buf, sword::BasicFilterUserData *myUserData)
Definition: teitohtml.cpp:111
bool handleToken(sword::SWBuf &buf, const char *token, sword::BasicFilterUserData *userData) override
Definition: teitohtml.cpp:39
std::unique_ptr< CSwordBackend > backend(sword::InstallSource const &is)
QString parseVerseReference(QString const &ref, ParseOptions const &options)
QString encodeHyperlink(CSwordModuleInfo const &module, QString const &key)