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-2021 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 
38 namespace {
39 const QString GeometryKey = "GUI/SearchDialog/geometry";
40 } // anonymous namespace
41 
42 namespace 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 
102 CSearchDialog::~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 =
173  CSwordModuleSearch::search(searchText,
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 
212 void 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 
225  m_searchOptionsArea->setSearchText(searchText);
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
Definition: btmodulelist.h:21
void setValue(QString const &key, T const &value)
Sets a value for a key.
Definition: btconfigcore.h:73
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
Definition: csearchdialog.h:54
QPushButton * m_closeButton
Definition: csearchdialog.h:52
CSearchDialog(QWidget *parent)
BtSearchResultArea * m_searchResultArea
Definition: csearchdialog.h:53
QPushButton * m_analyseButton
Definition: csearchdialog.h:50
QPushButton * m_manageIndexes
Definition: csearchdialog.h:51
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)