BibleTime
cexportmanager.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 "cexportmanager.h"
14
15#include <QApplication>
16#include <QClipboard>
17#include <QFileDialog>
18#include <QList>
19#include <QProgressDialog>
20#include <QTextStream>
21#include "../backend/drivers/cswordmoduleinfo.h"
22#include "../backend/keys/cswordkey.h"
23#include "../backend/keys/cswordversekey.h"
24#include "../backend/managers/referencemanager.h"
25#include "../backend/rendering/cplaintextexportrendering.h"
26#include "../backend/rendering/ctextrendering.h"
27#include "../util/btassert.h"
28#include "../util/tool.h"
29#include "btprinter.h"
30
31// Sword includes:
32#include <swkey.h>
33#include <listkey.h>
34
35
36using namespace Rendering;
37
39
40CExportManager::CExportManager(bool const showProgress,
41 QString const & progressLabel,
42 FilterOptions const & filterOptions,
43 DisplayOptions const & displayOptions)
44 : m_filterOptions(filterOptions)
45 , m_displayOptions(displayOptions)
46 , m_progressDialog(
47 showProgress
48 ? [&progressLabel]{
49 auto dialog =
50 std::make_unique<QProgressDialog>(nullptr, Qt::Dialog);
51 dialog->setWindowTitle(QStringLiteral("BibleTime"));
52 dialog->setLabelText(progressLabel);
53 return dialog;
54 }()
55 : nullptr)
56{}
57
59
60bool CExportManager::saveKey(CSwordKey const * const key,
61 Format const format,
62 bool const addText,
63 const BtConstModuleList& modules)
64{
65 if (!key || !key->module())
66 return false;
67 QString const filename = getSaveFileName(format);
68 if (filename.isEmpty())
69 return false;
70
71 QString text;
72 {
73 CSwordVerseKey const * const vk =
74 dynamic_cast<CSwordVerseKey const *>(key);
75 auto const render = newRenderer(format, addText);
76 if (vk && vk->isBoundSet()) {
77 text = render->renderKeyRange(vk->lowerBound(),
78 vk->upperBound(),
79 modules);
80 text.replace(QStringLiteral("#CHAPTERTITLE#"),
81 QStringLiteral("%1 %2")
82 .arg(vk->bookName())
83 .arg(QString::number(vk->chapter())));
84 text.replace(QStringLiteral("#TEXT_ALIGN#"),
85 QStringLiteral("right"));
86 } else { // no range supported
87 text = render->renderSingleKey(key->key(), modules);
88 }
89 }
90 util::tool::savePlainFile(filename, text);
91 return true;
92}
93
95 CSwordModuleInfo const * module,
96 Format const format,
97 bool const addText)
98{
99 if (l.empty())
100 return false;
101
102 QString const filename = getSaveFileName(format);
103 if (filename.isEmpty())
104 return false;
105
106 CTextRendering::KeyTree tree; /// \todo Verify that items in tree are properly freed.
107
108 setProgressRange(l.size()); /// \todo check size
109 KTI::Settings itemSettings;
110 itemSettings.highlight = false;
111
112 for (auto const & keyPtr : l) {
114 return false;
115 tree.emplace_back(QString::fromLocal8Bit(keyPtr->getText()),
116 module,
117 itemSettings);
118 incProgress();
119 }
120
121 QString const text = newRenderer(format, addText)->renderKeyTree(tree);
122 util::tool::savePlainFile(filename, text);
124 return true;
125}
126
127bool CExportManager::saveKeyList(QList<CSwordKey *> const & list,
128 Format const format,
129 bool const addText)
130{
131 if (list.empty())
132 return false;
133
134 const QString filename = getSaveFileName(format);
135 if (filename.isEmpty())
136 return false;
137
138 CTextRendering::KeyTree tree; /// \todo Verify that items in tree are properly freed.
139
140 KTI::Settings itemSettings;
141 itemSettings.highlight = false;
142
143 setProgressRange(list.count());
144 for (CSwordKey const * const k : list) {
146 return false;
147 tree.emplace_back(k->key(), k->module(), itemSettings);
148 incProgress();
149 }
150
151 QString const text = newRenderer(format, addText)->renderKeyTree(tree);
152 util::tool::savePlainFile(filename, text);
154 return true;
155}
156
157namespace {
158
159template <typename Arg> inline void copyToClipboard(Arg && arg)
160{ QApplication::clipboard()->setText(std::forward<Arg>(arg)); }
161
162} // anonymous namespace
163
164bool CExportManager::copyKey(CSwordKey const * const key,
165 Format const format,
166 bool const addText)
167{
168 if (!key || !key->module())
169 return false;
170
171 QString text;
172 BtConstModuleList modules;
173 modules.append(key->module());
174
175 {
176 auto const render = newRenderer(format, addText);
177 CSwordVerseKey const * const vk =
178 dynamic_cast<CSwordVerseKey const *>(key);
179 if (vk && vk->isBoundSet()) {
180 text = render->renderKeyRange(vk->lowerBound(),
181 vk->upperBound(),
182 modules);
183 } else { // no range supported
184 text = render->renderSingleKey(key->key(), modules);
185 }
186 }
187
188 copyToClipboard(text);
189 return true;
190}
191
193 CSwordModuleInfo const * const module,
194 Format const format,
195 bool const addText)
196{
197 if (l.empty())
198 return false;
199
200 CTextRendering::KeyTree tree; /// \todo Verify that items in tree are properly freed.
201 KTI::Settings itemSettings;
202 itemSettings.highlight = false;
203
204 for (auto const & keyPtr : l) {
206 return false;
207 tree.emplace_back(QString::fromLocal8Bit(keyPtr->getText()),
208 module,
209 itemSettings);
210 }
211
212 copyToClipboard(newRenderer(format, addText)->renderKeyTree(tree));
214 return true;
215}
216
217
218bool CExportManager::copyKeyList(QList<CSwordKey *> const & list,
219 Format const format,
220 bool const addText)
221{
222 if (list.empty())
223 return false;
224
225 CTextRendering::KeyTree tree; /// \todo Verify that items in tree are properly freed.
226 KTI::Settings itemSettings;
227 itemSettings.highlight = false;
228
229 setProgressRange(list.count());
230 for (CSwordKey const * const k : list) {
232 return false;
233 tree.emplace_back(k->key(), k->module(), itemSettings);
234 incProgress();
235 }
236
237 copyToClipboard(newRenderer(format, addText)->renderKeyTree(tree));
239 return true;
240}
241
242namespace {
243
245
246 PrintSettings(DisplayOptions const & displayOptions)
247 : BtPrinter::KeyTreeItem::Settings{
248 false,
249 displayOptions.verseNumbers ? Settings::SimpleKey : Settings::NoKey}
250 {}
251
252};
253
254} // anonymous namespace
255
256bool CExportManager::printKey(CSwordKey const * const key,
257 DisplayOptions const & displayOptions,
258 FilterOptions const & filterOptions)
259{
260 PrintSettings settings{displayOptions};
261 BtPrinter::KeyTree tree; /// \todo Verify that items in tree are properly freed.
262 tree.emplace_back(key->key(), key->module(), settings);
263 BtPrinter{displayOptions, filterOptions}.printKeyTree(tree);
264 return true;
265}
266
268 QString const & startKey,
269 QString const & stopKey,
270 DisplayOptions const & displayOptions,
271 FilterOptions const & filterOptions)
272{
273 PrintSettings settings{displayOptions};
275 if (startKey != stopKey) {
276 tree.emplace_back(startKey, stopKey, module, settings);
277 } else {
278 tree.emplace_back(startKey, module, settings);
279 }
280 BtPrinter{displayOptions, filterOptions}.printKeyTree(tree);
281 return true;
282}
283
284bool CExportManager::printByHyperlink(QString const & hyperlink,
285 DisplayOptions const & displayOptions,
286 FilterOptions const & filterOptions)
287{
288 auto const decodedLink(ReferenceManager::decodeHyperlink(hyperlink));
289 if (!decodedLink && !decodedLink->module)
290 return false;
291 auto const * const module = decodedLink->module;
292 auto const & keyName = decodedLink->key;
293
294 BtPrinter::KeyTree tree; /// \todo Verify that items in tree are properly freed.
295 PrintSettings settings{displayOptions};
296 //check if we have a range of entries or a single one
297 if ((module->type() == CSwordModuleInfo::Bible)
298 || (module->type() == CSwordModuleInfo::Commentary))
299 {
300 sword::ListKey const verses =
301 sword::VerseKey().parseVerseList(
302 keyName.toUtf8().constData(),
303 "Genesis 1:1",
304 true);
305
306 for (int i = 0; i < verses.getCount(); i++) {
307 if (sword::VerseKey const * const element =
308 dynamic_cast<sword::VerseKey const *>(verses.getElement(i)))
309 {
310 tree.emplace_back(
311 QString::fromUtf8(
312 element->getLowerBound().getText()),
313 QString::fromUtf8(
314 element->getUpperBound().getText()),
315 module,
316 settings);
317 } else if (verses.getElement(i)) {
318 tree.emplace_back(
319 QString::fromUtf8(verses.getElement(i)->getText()),
320 module,
321 settings);
322 }
323 }
324 } else {
325 tree.emplace_back(keyName, module, settings);
326 }
327 BtPrinter{displayOptions, filterOptions}.printKeyTree(tree);
328 return true;
329}
330
333 CSwordModuleInfo const * const module,
334 DisplayOptions const & displayOptions,
335 FilterOptions const & filterOptions)
336{
337 if (list.empty())
338 return false;
339 PrintSettings settings{displayOptions};
340 BtPrinter::KeyTree tree; /// \todo Verify that items in tree are properly freed.
341
342 setProgressRange(list.size());
343 for (auto const & keyPtr : list) {
345 return false;
346 QString const key = keyPtr->getText();
347 tree.emplace_back(key, key, module, settings);
348 incProgress();
349 }
350 BtPrinter{displayOptions, filterOptions}.printKeyTree(tree);
352 return true;
353}
354
355bool CExportManager::printKeyList(QStringList const & list,
356 CSwordModuleInfo const * const module,
357 DisplayOptions const & displayOptions,
358 FilterOptions const & filterOptions)
359{
360 if (list.empty())
361 return false;
362
363 PrintSettings settings{displayOptions};
364 BtPrinter::KeyTree tree; /// \todo Verify that items in tree are properly freed.
365
366 setProgressRange(list.count());
367 for (QString const & key: list) {
369 return false;
370 tree.emplace_back(key, module, settings);
371 incProgress();
372 }
373 BtPrinter{displayOptions, filterOptions}.printKeyTree(tree);
375 return true;
376}
377
378/** Returns a filename to save a file. */
379const QString CExportManager::getSaveFileName(const Format format) {
380 QString filter;
381 switch (format) {
382 case HTML:
383 filter = QObject::tr("HTML files") + " (*.html *.htm);;";
384 break;
385 case Text:
386 filter = QObject::tr("Text files") + " (*.txt);;";
387 break;
388 }
389 filter += QObject::tr("All files") + QStringLiteral(" (*)");
390
391 return QFileDialog::getSaveFileName(nullptr,
392 QObject::tr("Save file"),
393 QString(),
394 filter,
395 nullptr);
396}
397
398std::unique_ptr<CTextRendering> CExportManager::newRenderer(Format const format,
399 bool const addText)
400{
401 FilterOptions filterOptions = m_filterOptions;
402 filterOptions.footnotes = false;
403 filterOptions.strongNumbers = false;
404 filterOptions.morphTags = false;
405 filterOptions.lemmas = false;
406 filterOptions.scriptureReferences = false;
407 filterOptions.textualVariants = false;
408
409 using R = std::unique_ptr<CTextRendering>;
410 BT_ASSERT((format == Text) || (format == HTML));
411 if (format == HTML)
412 return R{new CTextRendering(addText,
414 filterOptions)};
415 return R{new CPlainTextExportRendering(addText,
417 filterOptions)};
418}
419
420void CExportManager::setProgressRange(int const items) {
421 if (!m_progressDialog)
422 return;
423
424 m_progressDialog->setMaximum(items);
425 m_progressDialog->setValue(0);
426 m_progressDialog->setMinimumDuration(0);
427 m_progressDialog->show();
428 // m_progressDialog->repaint();
429 qApp->processEvents(); //do not lock the GUI!
430}
431
432/** Increments the progress by one item. */
435 m_progressDialog->setValue(m_progressDialog->value() + 1);
436}
437
439 return m_progressDialog ? m_progressDialog->wasCanceled() : false;
440}
441
442/** Closes the progress dialog immediatly. */
444 if (m_progressDialog) {
445 m_progressDialog->close();
446 m_progressDialog->reset();
447 }
448 qApp->processEvents(); //do not lock the GUI!
449}
#define BT_ASSERT(...)
Definition btassert.h:17
QList< CSwordModuleInfo const * > BtConstModuleList
Manages the print item queue and printing.
Definition btprinter.h:20
std::unique_ptr< QProgressDialog > const m_progressDialog
bool printKey(CSwordKey const *const key, DisplayOptions const &displayOptions, FilterOptions const &filterOptions)
std::unique_ptr< Rendering::CTextRendering > newRenderer(Format const format, bool const addText)
void setProgressRange(int const items)
FilterOptions const m_filterOptions
bool printByHyperlink(QString const &hyperlink, DisplayOptions const &displayOptions, FilterOptions const &filterOptions)
Prints a key using the hyperlink created by CReferenceManager.
bool printKeyList(CSwordModuleSearch::ModuleResultList const &list, CSwordModuleInfo const *const module, DisplayOptions const &displayOptions, FilterOptions const &filterOptions)
bool copyKeyList(CSwordModuleSearch::ModuleResultList const &list, CSwordModuleInfo const *const module, Format const format, bool const addText)
void incProgress()
Increments the progress by one item.
const QString getSaveFileName(Format const format)
bool saveKey(CSwordKey const *const key, Format const format, bool const addText, const BtConstModuleList &modules)
CExportManager(const bool showProgress=true, const QString &progressLabel=QString(), const FilterOptions &filterOptions=btConfig().getFilterOptions(), const DisplayOptions &displayOptions=btConfig().getDisplayOptions())
bool saveKeyList(CSwordModuleSearch::ModuleResultList const &list, CSwordModuleInfo const *const module, Format const format, bool const addText)
void closeProgressDialog()
Closes the progress dialog immediately.
bool copyKey(CSwordKey const *const key, Format const format, bool const addText)
DisplayOptions const m_displayOptions
CSwordModuleInfo const * module() const
Definition cswordkey.h:68
virtual QString key() const =0
CSwordKey implementation for Sword's VerseKey.
CSwordVerseKey upperBound() const
QString bookName() const
bool isBoundSet() const
int chapter() const
CSwordVerseKey lowerBound() const
Text rendering based on trees.
std::list< KeyTreeItem > KeyTree
std::vector< std::shared_ptr< sword::SWKey const > > ModuleResultList
std::optional< DecodedHyperlink > decodeHyperlink(QString const &hyperlink)
bool savePlainFile(const QString &filename, void(&writer)(QTextStream &, void *), void *userPtr)
Definition tool.cpp:35
int textualVariants
Definition btglobal.h:34
int scriptureReferences
Definition btglobal.h:36
int strongNumbers
Definition btglobal.h:27
PrintSettings(DisplayOptions const &displayOptions)