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/btassert.h"
30#include "../../util/btconnect.h"
31#include "../../util/tool.h"
32#include "cmoduleresultview.h"
33#include "csearchresultview.h"
34
35// Sword includes:
36#pragma GCC diagnostic push
37#pragma GCC diagnostic ignored "-Wextra-semi"
38#pragma GCC diagnostic ignored "-Wsuggest-override"
39#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
40#include <swmodule.h>
41#pragma GCC diagnostic pop
42
43
44namespace {
46 QStringLiteral("GUI/SearchDialog/SearchResultsArea/mainSplitterSizes");
48 QStringLiteral(
49 "GUI/SearchDialog/SearchResultsArea/resultSplitterSizes");
50} // anonymous namespace
51
52namespace Search {
53
55 : QWidget(parent)
56{
57 QVBoxLayout *mainLayout;
58 QWidget *resultListsWidget;
59 QVBoxLayout *resultListsWidgetLayout;
60
61 //Size is calculated from the font rather than set in pixels,
62 // maybe this is better in different kinds of displays?
63 auto const mWidth = util::tool::mWidth(*this, 1);
64 this->setMinimumSize(QSize(mWidth*40, mWidth*15));
65 mainLayout = new QVBoxLayout(this);
66 m_mainSplitter = new QSplitter(this);
67 m_mainSplitter->setOrientation(Qt::Horizontal);
68
69 resultListsWidget = new QWidget(m_mainSplitter);
70
71 resultListsWidgetLayout = new QVBoxLayout(resultListsWidget);
72 resultListsWidgetLayout->setContentsMargins(0, 0, 0, 0);
73
74 //Splitter for two result lists
75 m_resultListSplitter = new QSplitter(resultListsWidget);
76 m_resultListSplitter->setOrientation(Qt::Vertical);
79
90 resultListsWidgetLayout->addWidget(m_resultListSplitter);
91
92 m_mainSplitter->addWidget(resultListsWidget);
93
94 //Preview ("info") area
96 m_displayFrame->setFrameShape(QFrame::NoFrame);
97 m_displayFrame->setFrameShadow(QFrame::Plain);
99
100 mainLayout->addWidget(m_mainSplitter);
101
102 m_contextMenu = new QMenu(this);
103 m_selectAllAction = new QAction(tr("Select all"), this);
104 m_selectAllAction->setShortcut(QKeySequence::SelectAll);
106
107 m_copyAction = new QAction(tr("Copy"));
108 m_copyAction->setShortcut(QKeySequence::Copy);
109 m_contextMenu->addAction(m_copyAction);
110
111 QVBoxLayout* frameLayout = new QVBoxLayout(m_displayFrame);
112 frameLayout->setContentsMargins(0, 0, 0, 0);
114 m_previewDisplay->setOpenLinks(false);
115 m_previewDisplay->setToolTip(tr("Text of the selected search result item"));
116 m_previewDisplay->setContextMenuPolicy(Qt::CustomContextMenu);
117 BT_CONNECT(m_selectAllAction, &QAction::triggered,
118 m_previewDisplay, &QTextBrowser::selectAll);
119 BT_CONNECT(m_copyAction, &QAction::triggered,
120 m_previewDisplay, &QTextBrowser::copy);
122 m_previewDisplay, &QTextBrowser::clear);
123 BT_CONNECT(m_previewDisplay, &QTextBrowser::customContextMenuRequested,
124 [this](QPoint const & loc) { m_contextMenu->exec(loc); });
125 frameLayout->addWidget(m_previewDisplay);
126
128}
129
130void BtSearchResultArea::setSearchResult(QString searchedText,
132{
133 reset(); //clear current modules
134
135 m_searchedText = std::move(searchedText);
136 m_results = std::move(results);
137
138 // Populate listbox:
139 m_moduleListBox->setupTree(m_results, searchedText);
140
141 // Pre-select the first module in the list:
142 m_moduleListBox->setCurrentItem(m_moduleListBox->topLevelItem(0), 0);
143}
144
146 m_moduleListBox->clear();
147 m_resultListBox->clear();
148 clearPreview();
149}
150
152 m_previewDisplay->setText(
153 QStringLiteral("<html><head/><body></body></html>"));
154}
155
156void BtSearchResultArea::updatePreview(const QString& key) {
157 using namespace Rendering;
158
159 CSwordModuleInfo* module = m_moduleListBox->activeModule();
160 if ( module ) {
161 QString text;
162 CDisplayRendering render;
163
164 BtConstModuleList modules;
165 modules.append(module);
166
168
169 //for bibles render 5 context verses
170 if (module->type() == CSwordModuleInfo::Bible) {
171 CSwordVerseKey vk(module);
172 vk.setIntros(true);
173 vk.setKey(key);
174
175 // HACK: enable headings for VerseKeys:
176 static_cast<sword::VerseKey *>(module->swordModule().getKey())
177 ->setIntros(true);
178
179 //first go back and then go forward the keys to be in context
180 vk.previous();
181 vk.previous();
182
183 //include Headings in display, they are indexed and searched too
184 if (vk.verse() == 1) {
185 if (vk.chapter() == 1) {
186 vk.setChapter(0);
187 }
188 vk.setVerse(0);
189 }
190
191 auto const startKey = vk;
192
193 vk.setKey(key);
194
195 vk.next();
196 vk.next();
197
198 settings.keyRenderingFace = CTextRendering::KeyTreeItem::Settings::CompleteShort;
199 text = render.renderKeyRange(startKey, vk, modules, key, settings);
200 }
201 //for commentaries only one verse, but with heading
202 else if (module->type() == CSwordModuleInfo::Commentary) {
203 CSwordVerseKey vk(module);
204 vk.setIntros(true);
205 vk.setKey(key);
206
207 // HACK: enable headings for VerseKeys:
208 static_cast<sword::VerseKey *>(module->swordModule().getKey())
209 ->setIntros(true);
210
211 //include Headings in display, they are indexed and searched too
212 if (vk.verse() == 1) {
213 if (vk.chapter() == 1) {
214 vk.setChapter(0);
215 }
216 vk.setVerse(0);
217 }
218 auto const startKey = vk;
219
220 vk.setKey(key);
221
222 settings.keyRenderingFace = CTextRendering::KeyTreeItem::Settings::NoKey;
223 text = render.renderKeyRange(startKey, vk, modules, key, settings);
224 }
225 else {
226 text = render.renderSingleKey(key, modules, settings);
227 }
228
229 if (modules.count() > 0)
230 setBrowserFont(modules.at(0));
231
232 QString text2 =
234 text2.replace(QStringLiteral("#CHAPTERTITLE#"), QString());
235 text2.replace(QStringLiteral("#TEXT_ALIGN#"), QStringLiteral("left"));
236 text2 = ColorManager::replaceColors(text2);
237 m_previewDisplay->setText(text2);
238 m_previewDisplay->scrollToAnchor( CDisplayRendering::keyToHTMLAnchor(key) );
239 }
240}
241
243 if (module) {
244 auto const lang = module->language();
245 m_previewDisplay->setFont(btConfig().getFontForLanguage(*lang).second);
246 } else {
247 m_previewDisplay->setFont(btConfig().getDefaultFont());
248 }
249}
250
251/**
252* Load the settings from the resource file
253*/
255 QList<int> mainSplitterSizes = btConfig().value< QList<int> >(MainSplitterSizesKey, QList<int>());
256 if (mainSplitterSizes.count() > 0)
257 m_mainSplitter->setSizes(mainSplitterSizes);
258 else
259 {
260 int w = this->size().width();
261 int w2 = m_moduleListBox->sizeHint().width();
262 mainSplitterSizes << w2 << w - w2;
263 m_mainSplitter->setSizes(mainSplitterSizes);
264 }
265
266 QList<int> resultSplitterSizes = btConfig().value< QList<int> >(ResultSplitterSizesKey, QList<int>());
267 if (resultSplitterSizes.count() > 0)
268 m_resultListSplitter->setSizes(resultSplitterSizes);
269}
270
271/**
272* Save the settings to the resource file
273*/
275 btConfig().setValue(MainSplitterSizesKey, m_mainSplitter->sizes());
276 btConfig().setValue(ResultSplitterSizesKey, m_resultListSplitter->sizes());
277}
278
279} //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:155