BibleTime
csearchdialog.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 "csearchdialog.h"
14
15#include <QDebug>
16#include <QLabel>
17#include <QLineEdit>
18#include <QPushButton>
19#include <QSizePolicy>
20#include <QString>
21#include <QRegularExpression>
22#include <QVBoxLayout>
23#include <QWidget>
24#include <utility>
25#include "../../backend/config/btconfig.h"
26#include "../../backend/cswordmodulesearch.h"
27#include "../../backend/drivers/cswordmoduleinfo.h"
28#include "../../util/btassert.h"
29#include "../../util/btconnect.h"
30#include "../../util/cresmgr.h"
31#include "../btmoduleindexdialog.h"
32#include "../messagedialog.h"
33#include "btindexdialog.h"
34#include "btsearchoptionsarea.h"
35#include "btsearchresultarea.h"
36
37
38namespace {
39const QString GeometryKey = "GUI/SearchDialog/geometry";
40} // anonymous namespace
41
42namespace Search {
43
45 : QDialog(parent)
46{
47 setWindowIcon(CResMgr::searchdialog::icon());
48 setWindowTitle(tr("Search"));
49 setAttribute(Qt::WA_DeleteOnClose);
50
51
52 QVBoxLayout* verticalLayout = new QVBoxLayout(this);
53 setLayout(verticalLayout);
54
56 verticalLayout->addWidget(m_searchOptionsArea);
57
59 m_searchResultArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
60 verticalLayout->addWidget(m_searchResultArea);
61
62 QLabel* hint = new QLabel(tr("Drag any verse reference onto an open Bible window"), this);
63 verticalLayout->addWidget(hint);
64
65 QHBoxLayout* horizontalLayout = new QHBoxLayout();
66
67 QSpacerItem* spacerItem = new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum);
68 horizontalLayout->addItem(spacerItem);
69
70 m_analyseButton = new QPushButton(tr("&Analyze results..."), this);
71 m_analyseButton->setToolTip(tr("Show a graphical analysis of the search result"));
72 horizontalLayout->addWidget(m_analyseButton);
73
74 m_manageIndexes = new QPushButton(tr("&Manage Indexes..."), this);
75 m_manageIndexes->setToolTip(tr("Recreate search indexes"));
76 horizontalLayout->addWidget(m_manageIndexes);
77
78 m_closeButton = new QPushButton(this);
79 m_closeButton->setText(tr("&Close"));
80 m_closeButton->setIcon(CResMgr::searchdialog::icon_close());
81 horizontalLayout->addWidget(m_closeButton);
82
83 verticalLayout->addLayout(horizontalLayout);
84
85 // Load dialog settings:
86 restoreGeometry(btConfig().value<QByteArray>(GeometryKey, QByteArray()));
87
88 // Search button is clicked
89 // Return/Enter is pressed in the search text field
92 BT_CONNECT(m_closeButton, &QPushButton::clicked,
93 this, &CSearchDialog::close);
94
95 BT_CONNECT(m_analyseButton, &QPushButton::clicked,
97
98 BT_CONNECT(m_manageIndexes, &QPushButton::clicked,
99 [this] { BtIndexDialog(this).exec(); });
100}
101
102CSearchDialog::~CSearchDialog() // Save dialog settings:
103{ btConfig().setValue(GeometryKey, saveGeometry()); }
104
106 QString originalSearchText(m_searchOptionsArea->searchText());
107
108 // first check the search string for errors
109 {
110 QString TestString(originalSearchText);
111 static QRegularExpression const ReservedWords(
112 QStringLiteral("heading:|footnote:|morph:|strong:"));
113 if (TestString.replace(ReservedWords, QString()).simplified().isEmpty()) {
114 return;
115 }
116 }
117 QString searchText = CSwordModuleSearch::prepareSearchText(originalSearchText, m_searchOptionsArea->searchType());
118
119 // Insert search text into history list of combobox
120 m_searchOptionsArea->addToHistory(originalSearchText);
121
122 auto const & searchModules = m_searchOptionsArea->modules();
123
124 // Check that we have the indices we need for searching
125 /// \warning indexing is some kind of internal optimization, so we leave
126 /// modules const, but unconst them here only
127 QList<CSwordModuleInfo*> unindexedModules;
128 for (auto const * const m : searchModules)
129 if (!m->hasIndex())
130 unindexedModules.append(const_cast<CSwordModuleInfo*>(m));
131
132 if (unindexedModules.size() > 0) {
133 // Build the list of module names:
134 QStringList moduleNameList;
135 for (auto const * const m : unindexedModules)
136 moduleNameList.append(m->name());
137
138 // Ask the user about unindexed modules:
139 auto const result =
141 this,
142 tr("Missing indices"),
143 QStringLiteral("%1<br><center>%2</center><br>%3")
144 .arg(tr("The following modules need to be indexed before "
145 "they can be searched in:"),
146 moduleNameList.join(QStringLiteral(", ")),
147 tr("Indexing could take a long time. Click \"Yes\" to "
148 "index the modules and start the search, or \"No\" "
149 "to cancel the search.")),
150 QMessageBox::Yes | QMessageBox::No,
151 QMessageBox::Yes);
152
153 // User didn't press "Yes":
154 if ((result & (QMessageBox::Yes | QMessageBox::Default)) == 0x0) {
155 return;
156 }
157
158 // Show indexing dialog, and index the modules:
159 if (!BtModuleIndexDialog::indexAllModules(unindexedModules)) {
160 // Failed or user cancelled.
161 return;
162 }
163 }
164
165 // Disable the dialog:
166 setEnabled(false);
167 setCursor(Qt::WaitCursor);
168
169 // Execute search:
170 CSwordModuleSearch::Results searchResult;
171 try {
172 searchResult =
174 searchModules,
176 } catch (...) {
177 QString msg;
178 try {
179 throw;
180 } catch (std::exception const & e) {
181 msg = e.what();
182 } catch (...) {
183 msg = tr("<UNKNOWN EXCEPTION>");
184 }
185
187 tr("Search aborted"),
188 tr("An internal error occurred while executing "
189 "your search:<br/><br/>%1").arg(msg));
190 // Re-enable the dialog:
191 setEnabled(true);
192 setCursor(Qt::ArrowCursor);
193 return;
194 }
195
196 // Display the search results:
197 if (!searchResult.empty()) {
199 std::move(searchResult));
200 m_analyseButton->setEnabled(true);
201 } else {
203 }
204 raise();
205 activateWindow();
206
207 // Re-enable the dialog:
208 setEnabled(true);
209 setCursor(Qt::ArrowCursor);
210}
211
212void CSearchDialog::reset(BtConstModuleList modules, QString const & searchText)
213{
216 m_analyseButton->setEnabled(false);
217
218 auto const haveModules = !modules.isEmpty();
219 if (haveModules) {
220 m_searchOptionsArea->setModules(std::move(modules));
221 } else {
223 }
224
226 if (isHidden())
227 show();
228
229 if (haveModules && !searchText.isEmpty())
230 startSearch();
231
232 // moved these to after the startSearch() because
233 // the progress dialog caused them to loose focus.
234 raise();
235 activateWindow();
236}
237
238} //end of 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
void setValue(QString const &key, T const &value)
Sets a value for a key.
static bool indexAllModules(QList< CSwordModuleInfo * > const &modules)
void setSearchText(const QString &text)
BtConstModuleList const & modules() const
void setModules(const BtConstModuleList &modules)
CSwordModuleSearch::SearchType searchType()
void addToHistory(const QString &text)
void setSearchResult(QString searchedText, CSwordModuleSearch::Results results)
BtSearchOptionsArea * m_searchOptionsArea
QPushButton * m_closeButton
CSearchDialog(QWidget *parent)
BtSearchResultArea * m_searchResultArea
QPushButton * m_analyseButton
QPushButton * m_manageIndexes
void reset(BtConstModuleList modules, QString const &searchText)
QString prepareSearchText(QString const &orig, SearchType const searchType)
Results search(QString const &searchText, BtConstModuleList const &modules, sword::ListKey scope)
std::vector< ModuleSearchResult > Results
QMessageBox::StandardButton showQuestion(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
QMessageBox::StandardButton showWarning(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)