BibleTime
btmodelviewreaddisplay.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
14
15#include <memory>
16#include <QApplication>
17#include <QClipboard>
18#include <QDebug>
19#include <QDrag>
20#include <QFileDialog>
21#include <QGuiApplication>
22#include <QHBoxLayout>
23#include <QMenu>
24#include <QQmlProperty>
25#include <QQuickItem>
26#include <QScrollBar>
27#include <QString>
28#include <QTextEdit>
29#ifdef BUILD_TEXT_TO_SPEECH
30#include <QTextToSpeech>
31#endif
32#include <QTimer>
33#include <QToolBar>
34#include <QVariant>
35#include <utility>
36#include "../../backend/keys/cswordkey.h"
37#include "../../backend/drivers/cswordbiblemoduleinfo.h"
38#include "../../backend/managers/cswordbackend.h"
39#include "../../backend/managers/referencemanager.h"
40#include "../../util/btassert.h"
41#include "../../util/btconnect.h"
42#include "../../util/tool.h"
43#include "../bibletime.h"
44#include "../btcopybyreferencesdialog.h"
45#include "../BtMimeData.h"
46#include "../cexportmanager.h"
47#include "../debugwindow.h"
48#include "../displaywindow/cdisplaywindow.h"
49#include "../keychooser/ckeychooser.h"
52
53
55 CDisplayWindow * const displayWindow,
56 QWidget * const parentWidget)
57 : QWidget(parentWidget)
58 , m_parentWindow(displayWindow)
59 , m_quickWidget(new BtQuickWidget(this))
60 , m_qmlInterface(m_quickWidget->qmlInterface())
61 , m_scrollBar(new QScrollBar(this))
62{
63 auto * const layout = new QHBoxLayout(this);
64 layout->setContentsMargins(0, 0, 0, 0);
65
66 m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
67 m_quickWidget->show();
69 [this](QString const & reference) { /// \todo Fix me
70 auto key(m_parentWindow->swordKey());
71 key->setKey(reference);
72 m_parentWindow->lookupKey(reference);
73 });
74 layout->addWidget(m_quickWidget);
75
76 m_scrollBar->setRange(-100,100);
77 m_scrollBar->setValue(0);
78 BT_CONNECT(m_scrollBar, &QScrollBar::sliderMoved,
80 BT_CONNECT(m_scrollBar, &QScrollBar::sliderPressed,
82 BT_CONNECT(m_scrollBar, &QScrollBar::sliderReleased,
84 layout->addWidget(m_scrollBar);
85
87 [this](QString const & reference) {
88 auto * const key = m_parentWindow->swordKey();
89 key->setKey(reference);
90 m_parentWindow->keyChooser()->updateKey(key);
92 });
94 [this](const QString& moduleName, const QString& keyName) {
95 auto & drag = *new QDrag(this);
96 auto mimedata =
97 std::make_unique<BTMimeData>(
98 BTMimeData::ItemList{{moduleName, keyName, {}}});
99 //add real Bible text from module/key
100 if (auto * const module =
101 CSwordBackend::instance().findModuleByName(moduleName))
102 {
103 drag.setPixmap(
104 module->moduleIcon().pixmap(
105 m_parentWindow->mainToolBar()->iconSize()));
106 std::unique_ptr<CSwordKey> key(module->createKey());
107 key->setKey(keyName);
108 // This works across applications:
109 mimedata->setText(key->strippedText());
110 }
111 drag.setMimeData(mimedata.release());
112 drag.exec(Qt::CopyAction, Qt::CopyAction);
113 });
119 [this](QString const & newLink) {
120 auto newAnchor = m_qmlInterface->getBibleUrlFromLink(newLink);
121 if (m_activeAnchor != newAnchor) {
122 m_activeAnchor = newAnchor;
123 activeAnchorChanged(std::move(newAnchor));
124 }
126 });
127
128 setLayout(layout);
129}
130
132
133void BtModelViewReadDisplay::setBibleReference(const QString& reference) {
135}
136
138 int speed = 25 * (1 + std::abs(value/30));
139 int relative = value - m_scrollBarPosition;
140 m_quickWidget->scroll(relative * speed);
141 m_scrollBarPosition = value;
143}
144
148
153
155{ QGuiApplication::clipboard()->setText(text(part)); }
156
157void BtModelViewReadDisplay::contextMenuEvent(QContextMenuEvent * event) {
158 auto const position = event->globalPos();
159 if (m_popup) {
160 if (auto const * const action = m_popup->exec(position);
161 action && action->property("bibletime_show_raw_text").toBool())
162 {
163 if (QApplication::widgetAt(position) == m_quickWidget) {
164 auto const * const item =
166 auto const textProperty =
167 QQmlProperty::read(item, QStringLiteral("text"));
168 if (textProperty.isValid()) {
169 auto * const window = new QTextEdit();
170 window->setPlainText(textProperty.toString());
171 window->setReadOnly(true);
172 window->show();
173 } else {
174 qDebug() << Q_FUNC_INFO << "text property is not valid";
175 }
176 } else {
177 qDebug() << Q_FUNC_INFO << "m_quickWidget not in focus";
178 }
179 }
180 }
181}
182
184{ QGuiApplication::clipboard()->setText(qmlInterface()->getSelectedText()); }
185
187 auto const & qml = *qmlInterface();
188 BtCopyByReferencesDialog dlg(qml.textModel(),
189 qml.selection(),
191 if (dlg.exec() != QDialog::Accepted)
192 return;
193
194 auto const & result = dlg.result();
195 BT_ASSERT(result.module);
196 auto const & module = *result.module;
197 if (module.type() == CSwordModuleInfo::Bible
198 || module.type() == CSwordModuleInfo::Commentary)
199 {
200 qml.copyVerseRange(static_cast<CSwordVerseKey const &>(*result.key1),
201 static_cast<CSwordVerseKey const &>(*result.key2));
202 } else {
203 qml.copyRange(result.index1, result.index2);
204 }
205}
206
208 auto const filename =
209 QFileDialog::getSaveFileName(
210 nullptr,
211 QObject::tr("Save document ..."),
212 "",
213 QObject::tr("Text files") + " (*.txt);;"
214 + QObject::tr("All files") + " (*)");
215 if (!filename.isEmpty())
216 util::tool::savePlainFile(filename, text(part));
217}
218
220 DisplayOptions const & displayOptions,
221 FilterOptions const & filterOptions)
222{
223 using CSBiMI = CSwordBibleModuleInfo;
224 CSwordKey* const key = m_parentWindow->swordKey();
225 const CSwordModuleInfo *module = key->module();
226
227 CExportManager mgr(false,
228 QString(),
231
232 switch (type) {
233 case Document: {
234 if (module->type() == CSwordModuleInfo::Bible) {
235 CSwordVerseKey* vk = dynamic_cast<CSwordVerseKey*>(key);
236
237 CSwordVerseKey startKey(*vk);
238 startKey.setVerse(1);
239
240 CSwordVerseKey stopKey(*vk);
241
242 const CSBiMI *bible = dynamic_cast<const CSBiMI*>(module);
243 if (bible) {
244 stopKey.setVerse(bible->verseCount(bible->bookNumber(startKey.bookName()), startKey.chapter()));
245 }
246
247 mgr.printKey(module, startKey.key(), stopKey.key(), displayOptions, filterOptions);
248 }
249 else if (module->type() == CSwordModuleInfo::Lexicon || module->type() == CSwordModuleInfo::Commentary ) {
250 mgr.printKey(module, key->key(), key->key(), displayOptions, filterOptions);
251 }
252 else if (module->type() == CSwordModuleInfo::GenericBook) {
253 CSwordTreeKey* tree = dynamic_cast<CSwordTreeKey*>(key);
254
255 CSwordTreeKey startKey(*tree);
256 // while (startKey.previousSibling()) { // go to first sibling on this level!
257 // }
258
259 CSwordTreeKey stopKey(*tree);
260 // if (CSwordBookModuleInfo* book = dynamic_cast<CSwordBookModuleInfo*>(module)) {
261 // while ( stopKey.nextSibling() ) { //go to last displayed sibling!
262 // }
263 // }
264 mgr.printKey(module, startKey.key(), stopKey.key(), displayOptions, filterOptions);
265 }
266 break;
267 }
268
269 case AnchorWithText: {
270 if (!m_activeAnchor.isEmpty())
271 mgr.printByHyperlink(m_activeAnchor, displayOptions, filterOptions);
272 break;
273 }
274
275 default:
276 break;
277 }
278}
279
280#ifdef BUILD_TEXT_TO_SPEECH
281void BtModelViewReadDisplay::speakSelectedText() {
282 if (auto const * const qml = qmlInterface(); qml && qml->selection())
283 BibleTime::instance()->speakText(qml->getSelectedText());
284}
285#endif
286
288 qmlInterface()->textModel()->reloadModules();
289}
290
291QString
293 QString text;
294 switch (part) {
295 case Document: {
296 CSwordKey* const key = m_parentWindow->swordKey();
297 const CSwordModuleInfo *module = key->module();
298 //This is never used for Bibles, so it is not implemented for
299 //them. If it should be, see CReadDisplay::print() for example
300 //code.
301 BT_ASSERT(module->type() == CSwordModuleInfo::Lexicon ||
302 module->type() == CSwordModuleInfo::Commentary ||
303 module->type() == CSwordModuleInfo::GenericBook);
304 FilterOptions filterOptions;
306
307 text = QStringLiteral("%1\n(%2, %3)")
308 .arg(key->strippedText(), key->key(), key->module()->name());
309 break;
310 }
311
312 case AnchorOnly: {
313 if (auto const decodedLink =
315 return decodedLink->key;
316 return {};
317 }
318
319 case AnchorTextOnly: {
320 auto const decodedLink(
322 if (decodedLink && decodedLink->module) {
323 std::unique_ptr<CSwordKey> key(decodedLink->module->createKey());
324 key->setKey(decodedLink->key);
325 return key->strippedText();
326 }
327 return {};
328 }
329
330 case AnchorWithText: {
331 auto const decodedLink(
333 if (decodedLink && decodedLink->module) {
334 std::unique_ptr<CSwordKey> key(decodedLink->module->createKey());
335 key->setKey(decodedLink->key);
336
337 FilterOptions filterOptions;
339
340 return QStringLiteral("%1\n(%2, %3)")
341 .arg(key->strippedText(), key->key(), key->module()->name());
342 }
343 return {};
344 }
345 default:
346 break;
347 }
348 return QString();
349
350}
351
353
355 FilterOptions const & filterOptions)
356{ m_qmlInterface->textModel()->setOptions(displayOptions, filterOptions); }
357
358void BtModelViewReadDisplay::setModules(const QStringList &modules) {
359 m_qmlInterface->setModules(modules);
360}
361
365
367
371
375
377
379
380void BtModelViewReadDisplay::highlightText(const QString& text, bool caseSensitive) {
381 m_qmlInterface->setHighlightWords(text, caseSensitive);
382}
383
384void BtModelViewReadDisplay::findText(bool const backward)
385{ m_qmlInterface->findText(backward); }
386
387// Save the Lemma (Strongs number) attribute
388void BtModelViewReadDisplay::setNodeInfo(QString const & newNodeInfo) {
389 if (m_nodeInfo != newNodeInfo) {
390 m_nodeInfo = newNodeInfo;
391 Q_EMIT nodeInfoChanged(newNodeInfo);
392 }
393}
#define BT_ASSERT(...)
Definition btassert.h:17
#define BT_CONNECT(...)
Definition btconnect.h:20
QList< BookmarkItem > ItemList
Definition BtMimeData.h:38
void colorThemeChanged()
static BibleTime * instance() noexcept
Definition bibletime.h:226
void autoScrollStop()
Result const & result() const noexcept
void findText(bool const backward)
void highlightText(const QString &text, bool caseSensitive)
void copySelectedText()
Copies the currently selected text.
void setModules(QStringList const &modules)
void setNodeInfo(QString const &newNodeInfo)
QString text(TextPart const part=Document)
void activeAnchorChanged(QString newActiveAnchor)
void copyAsPlainText(TextPart const part)
void copyByReferences()
Copies the given text specified by asking user for first and last references.
void save(TextPart const part)
Saves the given text with the specified format into the applications clipboard.
void setOptions(DisplayOptions const &displayOptions, FilterOptions const &filterOptions)
BtQmlInterface * qmlInterface() const noexcept
BtQuickWidget *const m_quickWidget
BtQmlInterface *const m_qmlInterface
void nodeInfoChanged(QString newNodeInfo)
BtModelViewReadDisplay(CDisplayWindow *displayWindow, QWidget *parent=nullptr)
void print(TextPart const, DisplayOptions const &displayOptions, FilterOptions const &filterOptions)
void contextMenuEvent(QContextMenuEvent *event) final override
void setBibleReference(const QString &reference)
~BtModelViewReadDisplay() override
void scrollToSwordKey(CSwordKey *key)
QString getBibleUrlFromLink(const QString &url)
void dragOccuring(const QString &moduleName, const QString &keyName)
void setBibleReference(const QString &reference)
void activeLinkChanged(QString newActiveLink)
std::optional< Selection > const & selection() const noexcept
void updateReference(const QString &reference)
void setModules(const QStringList &modules)
void setHighlightWords(const QString &words, bool caseSensitivy)
void findText(bool backward)
QString getLemmaFromLink(const QString &url)
void referenceDropped(const QString &reference)
void scroll(int pixels)
void updateReferenceText()
The base class for all display windows of BibleTime.
QToolBar * mainToolBar() const noexcept
FilterOptions const & filterOptions() const noexcept
CKeyChooser * keyChooser() const noexcept
void lookupKey(QString const &key)
DisplayOptions const & displayOptions() const noexcept
CSwordKey * swordKey() const noexcept
void setBibleReference(const QString &reference)
static CSwordBackend & instance() noexcept
void setFilterOptions(const FilterOptions &options)
Implementation for Sword Bibles.
QString strippedText()
CSwordModuleInfo const * module() const
Definition cswordkey.h:68
virtual bool setKey(const QString &key)=0
virtual QString key() const =0
QString const & name() const
CSwordKey implementation for Sword's TreeKey.
QString key() const final override
CSwordKey implementation for Sword's VerseKey.
QString bookName() const
QString key() const final override
int chapter() const
void setVerse(int v)
static QQuickItem const * quickItemInFocus(QQuickWidget const *quickWidget, QPointF cursorPosition)
std::optional< DecodedHyperlink > decodeHyperlink(QString const &hyperlink)
bool savePlainFile(const QString &filename, void(&writer)(QTextStream &, void *), void *userPtr)
Definition tool.cpp:33