BibleTime
btsearchresultarea.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 "btsearchresultarea.h"
14
15#include <QApplication>
16#include <QFrame>
17#include <QMenu>
18#include <QPushButton>
19#include <QSize>
20#include <QSplitter>
21#include <QStringList>
22#include <QVBoxLayout>
23#include <QWidget>
24#include "../../backend/config/btconfig.h"
25#include "../../backend/drivers/cswordmoduleinfo.h"
26#include "../../backend/managers/colormanager.h"
27#include "../../backend/keys/cswordversekey.h"
28#include "../../backend/rendering/cdisplayrendering.h"
29#include "../../util/btconnect.h"
30#include "../../util/tool.h"
31#include "cmoduleresultview.h"
32#include "csearchresultview.h"
33
34// Sword includes:
35#pragma GCC diagnostic push
36#pragma GCC diagnostic ignored "-Wextra-semi"
37#pragma GCC diagnostic ignored "-Wsuggest-override"
38#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
39#include <swmodule.h>
40#pragma GCC diagnostic pop
41
42
43namespace {
45 QStringLiteral("GUI/SearchDialog/SearchResultsArea/mainSplitterSizes");
47 QStringLiteral(
48 "GUI/SearchDialog/SearchResultsArea/resultSplitterSizes");
49} // anonymous namespace
50
51namespace Search {
52
54 : QWidget(parent)
55{
56 QVBoxLayout *mainLayout;
57 QWidget *resultListsWidget;
58 QVBoxLayout *resultListsWidgetLayout;
59
60 //Size is calculated from the font rather than set in pixels,
61 // maybe this is better in different kinds of displays?
62 auto const mWidth = util::tool::mWidth(*this, 1);
63 this->setMinimumSize(QSize(mWidth*40, mWidth*15));
64 mainLayout = new QVBoxLayout(this);
65 m_mainSplitter = new QSplitter(this);
66 m_mainSplitter->setOrientation(Qt::Horizontal);
67
68 resultListsWidget = new QWidget(m_mainSplitter);
69
70 resultListsWidgetLayout = new QVBoxLayout(resultListsWidget);
71 resultListsWidgetLayout->setContentsMargins(0, 0, 0, 0);
72
73 //Splitter for two result lists
74 m_resultListSplitter = new QSplitter(resultListsWidget);
75 m_resultListSplitter->setOrientation(Qt::Vertical);
78
89 resultListsWidgetLayout->addWidget(m_resultListSplitter);
90
91 m_mainSplitter->addWidget(resultListsWidget);
92
93 //Preview ("info") area
95 m_displayFrame->setFrameShape(QFrame::NoFrame);
96 m_displayFrame->setFrameShadow(QFrame::Plain);
98
99 mainLayout->addWidget(m_mainSplitter);
100
101 m_contextMenu = new QMenu(this);
102 m_selectAllAction = new QAction(tr("Select all"), this);
103 m_selectAllAction->setShortcut(QKeySequence::SelectAll);
105
106 m_copyAction = new QAction(tr("Copy"));
107 m_copyAction->setShortcut(QKeySequence::Copy);
108 m_contextMenu->addAction(m_copyAction);
109
110 QVBoxLayout* frameLayout = new QVBoxLayout(m_displayFrame);
111 frameLayout->setContentsMargins(0, 0, 0, 0);
113 m_previewDisplay->setOpenLinks(false);
114 m_previewDisplay->setToolTip(tr("Text of the selected search result item"));
115 m_previewDisplay->setContextMenuPolicy(Qt::CustomContextMenu);
116 BT_CONNECT(m_selectAllAction, &QAction::triggered,
117 m_previewDisplay, &QTextBrowser::selectAll);
118 BT_CONNECT(m_copyAction, &QAction::triggered,
119 m_previewDisplay, &QTextBrowser::copy);
121 m_previewDisplay, &QTextBrowser::clear);
122 BT_CONNECT(m_previewDisplay, &QTextBrowser::customContextMenuRequested,
123 [this](QPoint const & loc) { m_contextMenu->exec(loc); });
124 frameLayout->addWidget(m_previewDisplay);
125
127}
128
129void BtSearchResultArea::setSearchResult(QString searchedText,
131{
132 reset(); //clear current modules
133
134 m_searchedText = std::move(searchedText);
135 m_results = std::move(results);
136
137 // Populate listbox:
138 m_moduleListBox->setupTree(m_results, searchedText);
139
140 // Pre-select the first module in the list:
141 m_moduleListBox->setCurrentItem(m_moduleListBox->topLevelItem(0), 0);
142}
143
145 m_moduleListBox->clear();
146 m_resultListBox->clear();
147 clearPreview();
148}
149
151 m_previewDisplay->setText(
152 QStringLiteral("<html><head/><body></body></html>"));
153}
154
155void BtSearchResultArea::updatePreview(const QString& key) {
156 using namespace Rendering;
157
158 CSwordModuleInfo* module = m_moduleListBox->activeModule();
159 if ( module ) {
160 QString text;
161 CDisplayRendering render;
162
163 BtConstModuleList modules;
164 modules.append(module);
165
167
168 //for bibles render 5 context verses
169 if (module->type() == CSwordModuleInfo::Bible) {
170 CSwordVerseKey vk(module);
171 vk.setIntros(true);
172 vk.setKey(key);
173
174 // HACK: enable headings for VerseKeys:
175 static_cast<sword::VerseKey *>(module->swordModule().getKey())
176 ->setIntros(true);
177
178 //first go back and then go forward the keys to be in context
179 vk.previous();
180 vk.previous();
181
182 //include Headings in display, they are indexed and searched too
183 if (vk.verse() == 1) {
184 if (vk.chapter() == 1) {
185 vk.setChapter(0);
186 }
187 vk.setVerse(0);
188 }
189
190 auto const startKey = vk;
191
192 vk.setKey(key);
193
194 vk.next();
195 vk.next();
196
197 settings.keyRenderingFace = CTextRendering::KeyTreeItem::Settings::CompleteShort;
198 text = render.renderKeyRange(startKey, vk, modules, key, settings);
199 }
200 //for commentaries only one verse, but with heading
201 else if (module->type() == CSwordModuleInfo::Commentary) {
202 CSwordVerseKey vk(module);
203 vk.setIntros(true);
204 vk.setKey(key);
205
206 // HACK: enable headings for VerseKeys:
207 static_cast<sword::VerseKey *>(module->swordModule().getKey())
208 ->setIntros(true);
209
210 //include Headings in display, they are indexed and searched too
211 if (vk.verse() == 1) {
212 if (vk.chapter() == 1) {
213 vk.setChapter(0);
214 }
215 vk.setVerse(0);
216 }
217 auto const startKey = vk;
218
219 vk.setKey(key);
220
221 settings.keyRenderingFace = CTextRendering::KeyTreeItem::Settings::NoKey;
222 text = render.renderKeyRange(startKey, vk, modules, key, settings);
223 }
224 else {
225 text = render.renderSingleKey(key, modules, settings);
226 }
227
228 if (modules.count() > 0)
229 setBrowserFont(modules.at(0));
230
231 QString text2 =
233 text2.replace(QStringLiteral("#CHAPTERTITLE#"), QString());
234 text2.replace(QStringLiteral("#TEXT_ALIGN#"), QStringLiteral("left"));
235 text2 = ColorManager::replaceColors(text2);
236 m_previewDisplay->setText(text2);
237 m_previewDisplay->scrollToAnchor( CDisplayRendering::keyToHTMLAnchor(key) );
238 }
239}
240
242 if (module) {
243 auto const lang = module->language();
244 m_previewDisplay->setFont(btConfig().getFontForLanguage(*lang).second);
245 } else {
246 m_previewDisplay->setFont(btConfig().getDefaultFont());
247 }
248}
249
250/**
251* Load the settings from the resource file
252*/
254 QList<int> mainSplitterSizes = btConfig().value< QList<int> >(MainSplitterSizesKey, QList<int>());
255 if (mainSplitterSizes.count() > 0)
256 m_mainSplitter->setSizes(mainSplitterSizes);
257 else
258 {
259 int w = this->size().width();
260 int w2 = m_moduleListBox->sizeHint().width();
261 mainSplitterSizes << w2 << w - w2;
262 m_mainSplitter->setSizes(mainSplitterSizes);
263 }
264
265 QList<int> resultSplitterSizes = btConfig().value< QList<int> >(ResultSplitterSizesKey, QList<int>());
266 if (resultSplitterSizes.count() > 0)
267 m_resultListSplitter->setSizes(resultSplitterSizes);
268}
269
270/**
271* Save the settings to the resource file
272*/
274 btConfig().setValue(MainSplitterSizesKey, m_mainSplitter->sizes());
275 btConfig().setValue(ResultSplitterSizesKey, m_resultListSplitter->sizes());
276}
277
278} //namespace Search
BtConfig & btConfig()
This is a shortchand for BtConfig::getInstance().
Definition btconfig.h:305
#define BT_CONNECT(...)
Definition btconnect.h:20
QList< CSwordModuleInfo const * > BtConstModuleList
T value(QString const &key, T const &defaultValue=T()) const
Returns the settings value for the given global key.
void setValue(QString const &key, T const &value)
Sets a value for a key.
A QTextBrowser subclass which adds the ability to start drags for references.
CSwordKey implementation for Sword's VerseKey.
void setChapter(int v)
void setIntros(bool v)
bool next(const JumpType type=JumpType::UseVerse)
bool previous(const JumpType type=JumpType::UseVerse)
bool setKey(const QString &key) final override
int verse() const
int chapter() const
void setVerse(int v)
Rendering for the html display widget.
QString renderSingleKey(const QString &key, const BtConstModuleList &modules, const KeyTreeItem::Settings &settings=KeyTreeItem::Settings())
QString renderKeyRange(CSwordVerseKey const &lowerBound, CSwordVerseKey const &upperBound, const BtConstModuleList &modules, const QString &hightlightKey=QString(), const KeyTreeItem::Settings &settings=KeyTreeItem::Settings())
CSearchResultView * m_resultListBox
BtSearchResultArea(QWidget *parent=nullptr)
CModuleResultView * m_moduleListBox
void updatePreview(const QString &key)
void setBrowserFont(const CSwordModuleInfo *const module)
void setSearchResult(QString searchedText, CSwordModuleSearch::Results results)
CSwordModuleSearch::Results m_results
QSize sizeHint() const override
void strongsSelected(CSwordModuleInfo *, const QStringList &)
void setupTree(const CSwordModuleSearch::Results &results, const QString &searchedText)
void moduleSelected(CSwordModuleInfo const *, CSwordModuleSearch::ModuleResultList const &)
void setupStrongsTree(CSwordModuleInfo *, const QStringList &)
void keySelected(const QString &)
void setupTree(CSwordModuleInfo const *m, CSwordModuleSearch::ModuleResultList const &results)
QString highlightSearchedText(QString const &content, QString const &searchedText, bool plainSearchedText)
std::vector< ModuleSearchResult > Results
QString replaceColors(QString content)
int mWidth(QWidget const &widget, int const mCount)
Calculates a maximum rendered text width for a widget and a string with the a given length.
Definition tool.cpp:117