BibleTime
btbiblekeywidget.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 "btbiblekeywidget.h"
14
15#include <QApplication>
16#include <QDebug>
17#include <QEvent>
18#include <QHBoxLayout>
19#include <QLineEdit>
20#include <QMenu>
21#include <QMouseEvent>
22#include <QPixmap>
23#include <QString>
24#include <QStringList>
25#include <QtGlobal>
26#include <QToolButton>
27#include "../../../backend/keys/cswordversekey.h"
28#include "../../../util/btconnect.h"
29#include "../../../util/cresmgr.h"
30#include "../btlocationedit.h"
31#include "../cscrollerwidgetset.h"
33
34
36 CSwordBibleModuleInfo const * mod,
37 CSwordVerseKey * key,
38 QWidget * parent)
39 : QWidget(parent)
40 , m_key(key)
41 , m_dropDownHoverTimer(this)
42 , m_module(mod)
43{
44 auto const slotStep =
45 [this](int offset, CSwordVerseKey::JumpType const jumpType) {
46 if (!offset)
47 return;
48 if (offset > 0) {
49 do {
50 m_key->next(jumpType);
51 } while (--offset);
52 } else {
53 do {
54 m_key->previous(jumpType);
55 } while (++offset);
56 }
57 if (!updatelock)
58 Q_EMIT changed(m_key);
59 };
60 auto const slotStepBook =
61 [slotStep](int offset)
62 { slotStep(offset, CSwordVerseKey::UseBook); };
63 auto const slotStepChapter =
64 [slotStep](int offset)
65 { slotStep(offset, CSwordVerseKey::UseChapter); };
66 auto const slotStepVerse =
67 [slotStep](int offset)
68 { slotStep(offset, CSwordVerseKey::UseVerse); };
69
70 updatelock = false;
71
72 setFocusPolicy(Qt::WheelFocus);
73
74 QToolButton* clearRef = new QToolButton(this);
75 clearRef->setIcon(CResMgr::icon_clearEdit());
76 clearRef->setAutoRaise(true);
77 clearRef->setStyleSheet(QStringLiteral("QToolButton{margin:0px;}"));
78 BT_CONNECT(clearRef, &QToolButton::clicked,
79 [this]{
80 m_textbox->setText(QString());
81 m_textbox->setFocus();
82 });
83
84 auto * const bookScroller = new CScrollerWidgetSet(this);
85
86 m_textbox = new BtLocationEdit(this);
87 setFocusProxy(m_textbox);
88 m_textbox->setContentsMargins(0, 0, 0, 0);
89
90 auto * const chapterScroller = new CScrollerWidgetSet(this);
91 auto * const verseScroller = new CScrollerWidgetSet(this);
92
93 QHBoxLayout* m_mainLayout = new QHBoxLayout( this );
94 m_mainLayout->setContentsMargins(0, 0, 0, 0);
95 m_mainLayout->setSpacing(0);
96 m_mainLayout->addWidget(clearRef);
97 m_mainLayout->addWidget(bookScroller);
98 m_mainLayout->addWidget(m_textbox);
99 m_mainLayout->addWidget(chapterScroller);
100 m_mainLayout->addWidget(verseScroller);
101
102
103 setTabOrder(m_textbox, nullptr);
104
105 m_dropDownButtons = new QWidget(this);
106 m_dropDownButtons->setWindowFlags(Qt::Popup);
107 m_dropDownButtons->setAttribute(Qt::WA_WindowPropagation);
108 m_dropDownButtons->setCursor(Qt::ArrowCursor);
109 QHBoxLayout *dropDownButtonsLayout(new QHBoxLayout(m_dropDownButtons));
110
111 auto * const bookChooser =
113 *this);
114 bookChooser->setToolTip(tr("Select book"));
115 BT_CONNECT(bookChooser->menu(), &QMenu::triggered,
116 [this](QAction * const action) {
117 auto bookname = action->property("bookname").toString();
118 if (m_key->bookName() != bookname) {
119 m_key->setBookName(std::move(bookname));
120 updateText();
121 }
122 if (!updatelock)
123 Q_EMIT changed(m_key);
124 });
125 BT_CONNECT(bookChooser, &BtDropdownChooserButton::stepItem, slotStepBook);
126 dropDownButtonsLayout->addWidget(bookChooser, 2);
127
128 auto * const chapterChooser =
130 *this);
131 chapterChooser->setToolTip(tr("Select chapter"));
132 BT_CONNECT(chapterChooser->menu(), &QMenu::triggered,
133 [this](QAction * const action) {
134 int const n = action->property("chapter").toInt();
135 if (m_key->chapter() != n) {
136 m_key->setChapter(n);
137 updateText();
138 }
139 if (!updatelock)
140 Q_EMIT changed(m_key);
141 });
142 BT_CONNECT(chapterChooser,
144 slotStepChapter);
145 dropDownButtonsLayout->addWidget(chapterChooser, 1);
146
147 auto * const verseChooser =
149 *this);
150 verseChooser->setToolTip(tr("Select verse"));
151 BT_CONNECT(verseChooser->menu(), &QMenu::triggered,
152 [this](QAction * const action) {
153 int const n = action->property("verse").toInt();
154 if (m_key->verse() != n) {
155 m_key->setVerse(n);
156 updateText();
157 }
158 if (!updatelock)
159 Q_EMIT changed(m_key);
160 });
161 BT_CONNECT(verseChooser, &BtDropdownChooserButton::stepItem, slotStepVerse);
162 dropDownButtonsLayout->addWidget(verseChooser, 1);
163
164 dropDownButtonsLayout->setContentsMargins(0, 0, 0, 0);
165 dropDownButtonsLayout->setSpacing(0);
166 m_dropDownButtons->setLayout(dropDownButtonsLayout);
167 m_dropDownButtons->hide();
168
169 m_dropDownButtons->installEventFilter(this);
170
171 m_dropDownHoverTimer.setInterval(500);
172 m_dropDownHoverTimer.setSingleShot(true);
173 BT_CONNECT(&m_dropDownHoverTimer, &QTimer::timeout,
174 m_dropDownButtons, &QWidget::hide);
175
176 QString scrollButtonToolTip(tr("Scroll through the entries of the list. Press the button and move the mouse to increase or decrease the item."));
177 bookScroller->setToolTips(
178 tr("Next book"),
179 scrollButtonToolTip,
180 tr("Previous book")
181 );
182 chapterScroller->setToolTips(
183 tr("Next chapter"),
184 scrollButtonToolTip,
185 tr("Previous chapter")
186 );
187 verseScroller->setToolTips(
188 tr("Next verse"),
189 scrollButtonToolTip,
190 tr("Previous verse")
191 );
192
193 // signals and slots connections
194 auto const initScrollerConnections =
195 [this](CScrollerWidgetSet & scroller, auto stepFunction)
196 {
197 BT_CONNECT(&scroller,
199 stepFunction);
201 [this]{
202 updatelock = true;
203 oldKey = m_key->key();
204 });
206 [this]{
207 updatelock = false;
208 if (oldKey != m_key->key())
209 Q_EMIT changed(m_key);
210 });
211 };
212 initScrollerConnections(*bookScroller, slotStepBook);
213 initScrollerConnections(*chapterScroller, slotStepChapter);
214 initScrollerConnections(*verseScroller, slotStepVerse);
215
216 BT_CONNECT(m_textbox, &QLineEdit::returnPressed,
217 [this]{
218 m_key->setKey(m_textbox->text());
219 Q_EMIT changed(m_key);
220 });
221
222 BT_CONNECT(m_key->afterChangedSignaller(), &BtSignal::signal,
224
225 setKey(key); // The order of these two functions is important.
226 setModule();
227}
228
232
234 if (m) { //can be null
235 m_module = m;
236 m_key->setModule(m);
237 }
238}
239
241 if (o != m_dropDownButtons) return false;
242 switch (e->type()) {
243 case QEvent::Enter:
245 return true;
246 case QEvent::Leave:
247 m_dropDownHoverTimer.start();
248 return true;
249 default:
250 return false;
251 }
252}
253
254void BtBibleKeyWidget::enterEvent(QEnterEvent *) {
256
258
259 m_dropDownButtons->raise();
260 m_dropDownButtons->show();
261}
262
264 m_dropDownHoverTimer.start();
265}
266
267void BtBibleKeyWidget::resizeEvent(QResizeEvent *event) {
268 if (m_dropDownButtons->isVisible()) {
270 }
271 QWidget::resizeEvent(event);
272}
273
275 m_dropDownButtons->setParent(window());
276 int h(m_dropDownButtons->layout()->minimumSize().height());
277 QPoint topLeft(mapTo(window(),
278 QPoint(m_textbox->x(), m_textbox->y() + m_textbox->height())));
279 m_dropDownButtons->setGeometry(topLeft.x(), topLeft.y(),
280 m_textbox->width(), h);
281}
282
284 QString text(m_key->key());
285 m_textbox->setText(text);
286 QFontMetrics fm(m_textbox->font());
287 int nw(m_textbox->minimumSizeHint().width() + fm.horizontalAdvance(text));
288 if (nw > m_textbox->minimumWidth()) {
289 m_textbox->setMinimumWidth(nw);
290 m_textbox->updateGeometry();
291 }
292}
293
295 if (!key) return false;
296
297 m_key->setKey(key->key());
298 return true;
299}
300
302 for (auto const & bookname : m_module->books())
303 menu.addAction(bookname)->setProperty("bookname", bookname);
304}
305
307 int count = m_module->chapterCount(m_key->bibleBook());
308 for (int i = 1; i <= count; i++)
309 menu.addAction(QString::number(i))->setProperty("chapter", i);
310}
311
313 int count = m_module->verseCount(m_key->bookName(), m_key->chapter());
314 for (int i = 1; i <= count; i++)
315 menu.addAction(QString::number(i))->setProperty("verse", i);
316}
#define BT_CONNECT(...)
Definition btconnect.h:20
BtBibleKeyWidget(CSwordBibleModuleInfo const *module, CSwordVerseKey *key, QWidget *parent=nullptr)
const CSwordBibleModuleInfo * m_module
void enterEvent(QEnterEvent *event) override
CSwordVerseKey * m_key
bool eventFilter(QObject *o, QEvent *e) override
void resizeEvent(QResizeEvent *event) override
void populateBookMenu(QMenu &menu)
QLineEdit * m_textbox
void setModule(const CSwordBibleModuleInfo *m=nullptr)
void leaveEvent(QEvent *event) override
void populateChapterMenu(QMenu &menu)
void changed(CSwordVerseKey *key)
void populateVerseMenu(QMenu &menu)
bool setKey(CSwordVerseKey *key)
QWidget * m_dropDownButtons
void stepItem(int step)
void signal()
void change(int count)
Implementation for Sword Bibles.
unsigned int verseCount(const unsigned int book, const unsigned int chapter) const
unsigned int chapterCount(const unsigned int book) const
QStringList const & books() const
CSwordKey implementation for Sword's VerseKey.
char bibleBook() const
QString bookName() const
bool next(const JumpType type=JumpType::UseVerse)
void setModule(const CSwordModuleInfo *newModule) final override
bool previous(const JumpType type=JumpType::UseVerse)
QString key() const final override
bool setKey(const QString &key) final override
int chapter() const
if(plainSearchedText)