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