BibleTime
crangechooserdialog.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
13#include "crangechooserdialog.h"
14
15#include <QByteArray>
16#include <QDialogButtonBox>
17#include <QFlags>
18#include <QFrame>
19#include <QHBoxLayout>
20#include <QLabel>
21#include <QLineEdit>
22#include <QList>
23#include <QListWidget>
24#include <QListWidgetItem>
25#include <QMap>
26#include <QPushButton>
27#include <Qt>
28#include <QTextEdit>
29#include <QVBoxLayout>
30#include "../../backend/config/btconfig.h"
31#include "../../backend/drivers/cswordmoduleinfo.h"
32#include "../../backend/managers/cswordbackend.h"
33#include "../../util/btassert.h"
34#include "../../util/btconnect.h"
35#include "../messagedialog.h"
36
37// Sword includes:
38#ifdef __GNUC__
39#pragma GCC diagnostic push
40#pragma GCC diagnostic ignored "-Wextra-semi"
41#pragma GCC diagnostic ignored "-Wsuggest-override"
42#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
43#endif
44#ifdef __clang__
45#pragma clang diagnostic push
46#pragma clang diagnostic ignored "-Wsuggest-destructor-override"
47#endif
48#include <versekey.h>
49#include <listkey.h>
50#include <swkey.h>
51#include <swmodule.h>
52#ifdef __clang__
53#pragma clang diagnostic pop
54#endif
55#ifdef __GNUC__
56#pragma GCC diagnostic pop
57#endif
58
59namespace Search {
60
61CRangeChooserDialog::CRangeChooserDialog(const QStringList& scopeModules, QWidget *parentDialog)
62 : QDialog(parentDialog),
63 m_scopeModules(scopeModules)
64{
65 initView();
67
69
70 // Add the existing scopes
72 for (auto it = map.begin(); it != map.end(); ++it)
73 new RangeItem(it.key(), it.value(), m_rangeList);
75}
76
78 m_rangeList = new QListWidget(this);
79 m_rangeListLabel = new QLabel(this);
81
82 m_newRangeButton = new QPushButton(this);
83 m_deleteRangeButton = new QPushButton(this);
84
85 m_nameEdit = new QLineEdit(this);
86 m_nameEditLabel = new QLabel(this);
87 m_nameEditLabel->setBuddy(m_nameEdit);
88
89 m_rangeEdit = new QTextEdit(this);
90 m_rangeEditLabel = new QLabel(this);
92
93 m_resultList = new QListWidget(this);
94 m_resultListLabel = new QLabel(this);
96
97 QFrame *hSeparatorLine = new QFrame(this);
98 hSeparatorLine->setFrameShape(QFrame::HLine);
99 hSeparatorLine->setFrameShadow(QFrame::Sunken);
100
101 m_buttonBox = new QDialogButtonBox(this);
102 m_buttonBox->setOrientation(Qt::Horizontal);
103 m_buttonBox->setStandardButtons(QDialogButtonBox::Ok
104 | QDialogButtonBox::Cancel
105 | QDialogButtonBox::RestoreDefaults);
107
108 QHBoxLayout *rangeButtonsLayout = new QHBoxLayout();
109 rangeButtonsLayout->addWidget(m_newRangeButton);
110 rangeButtonsLayout->addWidget(m_deleteRangeButton);
111
112 QVBoxLayout* rangeListLayout = new QVBoxLayout;
113 rangeListLayout->addWidget(m_rangeListLabel);
114 rangeListLayout->addWidget(m_rangeList);
115 rangeListLayout->addLayout(rangeButtonsLayout);
116
117 QHBoxLayout* nameEditLayout = new QHBoxLayout();
118 nameEditLayout->addWidget(m_nameEditLabel);
119 nameEditLayout->addWidget(m_nameEdit);
120
121 QVBoxLayout* rangeEditLayout = new QVBoxLayout();
122 rangeEditLayout->addLayout(nameEditLayout);
123 rangeEditLayout->addWidget(m_rangeEditLabel);
124 rangeEditLayout->addWidget(m_rangeEdit);
125 rangeEditLayout->addWidget(m_resultListLabel);
126 rangeEditLayout->addWidget(m_resultList);
127
128 QHBoxLayout *topLayout = new QHBoxLayout;
129 topLayout->addLayout(rangeListLayout);
130 topLayout->addLayout(rangeEditLayout);
131
132 QVBoxLayout *vboxLayout = new QVBoxLayout(this);
133 vboxLayout->addLayout(topLayout);
134 vboxLayout->addWidget(hSeparatorLine);
135 vboxLayout->addWidget(m_buttonBox);
136}
137
139 BT_CONNECT(m_rangeList, &QListWidget::currentItemChanged,
140 [this](QListWidgetItem *, QListWidgetItem * const previous) {
141 if (previous) {
142 BT_ASSERT(dynamic_cast<RangeItem *>(previous));
143 saveCurrentToRange(static_cast<RangeItem*>(previous));
144 }
146 });
147 BT_CONNECT(m_nameEdit, &QLineEdit::textEdited,
149 BT_CONNECT(m_rangeEdit, &QTextEdit::textChanged,
150 [this]{
151 m_resultList->clear();
152 static QRegularExpression const re(
153 QStringLiteral(R"PCRE(\s*-\s*)PCRE"));
154 auto const range =
155 m_rangeEdit->toPlainText().replace(
156 re,
157 QStringLiteral("-"));
158
159 auto const & backend = CSwordBackend::instance();
160 for (auto const & moduleName : m_scopeModules) {
161 auto * const module =
162 backend.findModuleByName(moduleName);
163 if (!module)
164 continue;
165 auto const verses(
166 sword::VerseKey(
167 module->swordModule().getKey())
168 .parseVerseList(
169 range.toUtf8().constData(),
170 "Genesis 1:1",
171 true));
172 if (verses.getCount() > 0) {
173 for (int i = 0; i < verses.getCount(); i++) {
174 auto const * const elementText =
175 verses.getElement(i)->getRangeText();
176 new QListWidgetItem(
177 QString::fromUtf8(elementText),
179 }
180 break;
181 }
182 }
183 });
184
185 // Connect buttons:
186 BT_CONNECT(m_buttonBox, &QDialogButtonBox::accepted,
188 BT_CONNECT(m_buttonBox, &QDialogButtonBox::rejected,
189 this, &CRangeChooserDialog::reject);
190 BT_CONNECT(m_newRangeButton, &QPushButton::clicked,
191 [this]{
192 m_rangeList->setCurrentItem(
193 new RangeItem(tr("New range"),
194 QString(),
195 m_rangeList));
197 });
198 BT_CONNECT(m_deleteRangeButton, &QPushButton::clicked,
199 [this]{
200 BT_ASSERT(dynamic_cast<RangeItem *>(
201 m_rangeList->currentItem()));
202 QListWidgetItem * const i = m_rangeList->currentItem();
203 m_rangeList->removeItemWidget(i);
204 delete i;
205
207 });
208 QPushButton * defaultsButton = m_buttonBox->button(QDialogButtonBox::RestoreDefaults);
209 BT_CONNECT(defaultsButton, &QPushButton::clicked,
210 [this]{
211 m_rangeList->clear();
213 auto const map(
214 btConfig().getSearchScopesForCurrentLocale(
216 for (auto it = map.begin(); it != map.end(); ++it)
217 new RangeItem(it.key(), it.value(), m_rangeList);
218 m_rangeList->setCurrentItem(nullptr);
220 });
221}
222
224 setWindowTitle(tr("Setup Search Scopes"));
225
226 m_rangeListLabel->setText(tr("S&earch range:"));
227 m_rangeList->setToolTip(tr("Select a scope from the list to edit the search"
228 "ranges"));
229
230 m_newRangeButton->setText(tr("&Add new scope"));
231 m_newRangeButton->setToolTip(tr("Add a new search scope. First enter an "
232 "appropriate name, then edit the search "
233 "ranges."));
234
235 m_deleteRangeButton->setText(tr("Delete current &scope"));
236 m_deleteRangeButton->setToolTip(tr("Delete the selected search scope"));
237
238 m_nameEditLabel->setText(tr("&Name:"));
239 m_nameEdit->setToolTip(tr("Change the name of the selected search scope"));
240
241 m_rangeEditLabel->setText(tr("Edi&t current range:"));
242 m_rangeEdit->setToolTip(tr("Change the search ranges of the selected search"
243 "scope item. Have a look at the predefined "
244 "search scopes to see how search ranges are "
245 "constructed."));
246
247 m_resultListLabel->setText(tr("Parsed search range:"));
248 m_resultList->setToolTip(tr("The search ranges which will be used for the "
249 "search, parsed to the canonical form"));
250}
251
253 if (!m_nameEdit->text().isEmpty())
254 i->setCaption(m_nameEdit->text());
255
256 i->setRange(m_rangeEdit->toPlainText());
257}
258
260 const QListWidgetItem * const item = m_rangeList->currentItem();
261 BT_ASSERT(!item || dynamic_cast<RangeItem const *>(item));
262 const RangeItem * rangeItem = static_cast<const RangeItem *>(item);
263
264 m_nameEdit->setEnabled(item != nullptr);
265 m_rangeEdit->setEnabled(item != nullptr);
266 m_resultList->setEnabled(item != nullptr);
267 m_deleteRangeButton->setEnabled(item != nullptr);
268 m_nameEdit->setText(item != nullptr ? rangeItem->caption() : QString());
269 m_rangeEdit->setText(item != nullptr ? rangeItem->range() : QString());
270
271 if (item != nullptr)
272 m_nameEdit->setFocus();
273
274 nameEditTextChanged(item != nullptr ? rangeItem->caption() : QString());
275}
276
278 // Update the active item:
279 QListWidgetItem *currentItem = m_rangeList->currentItem();
280 if (currentItem != nullptr) {
281 BT_ASSERT(dynamic_cast<RangeItem *>(currentItem));
282 saveCurrentToRange(static_cast<RangeItem*>(currentItem));
283 }
284
285 // Save the new sorted map of search scopes:
286 m_rangeList->sortItems();
288 for (int i = 0; i < m_rangeList->count(); i++) {
289 BT_ASSERT(dynamic_cast<RangeItem *>(m_rangeList->item(i)));
290 const RangeItem * item = static_cast<RangeItem*>(m_rangeList->item(i));
291 map[item->caption()] = item->range();
292 }
294
295 QDialog::accept();
296}
297
298void CRangeChooserDialog::nameEditTextChanged(const QString &newText) {
299 const bool e = !newText.isEmpty() || m_rangeList->count() <= 0;
300 m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(e);
301}
302
303} //end of namespace Search
#define BT_ASSERT(...)
Definition btassert.h:17
BtConfig & btConfig()
This is a shortchand for BtConfig::getInstance().
Definition btconfig.h:305
#define BT_CONNECT(...)
Definition btconnect.h:20
QMap< QString, QString > StringMap
Definition btconfig.h:48
void setSearchScopesWithCurrentLocale(const QStringList &scopeModules, StringMap searchScopes)
Definition btconfig.cpp:435
void deleteSearchScopesWithCurrentLocale()
Definition btconfig.cpp:493
StringMap getSearchScopesForCurrentLocale(const QStringList &scopeModules)
Definition btconfig.cpp:406
static CSwordBackend & instance() noexcept
void setCaption(QString const &caption)
CRangeChooserDialog(const QStringList &rangeScopeModule, QWidget *parentDialog=nullptr)
void nameEditTextChanged(const QString &newText)
void prepareDialogBox(QDialogButtonBox *box)