BibleTime
ckeychooserwidget.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 "ckeychooserwidget.h"
14
15#include <QComboBox>
16#include <QEvent>
17#include <QFocusEvent>
18#include <QHBoxLayout>
19#include <QLineEdit>
20#include <QNonConstOverload>
21#include <QString>
22#include <Qt>
23#include "../../util/btassert.h"
24#include "../../util/btconnect.h"
25#include "cscrollerwidgetset.h"
26
27
28class BtKeyLineEdit : public QLineEdit {
29
30public: // methods:
31
33 : QLineEdit(parent) {}
34
35protected: // methods:
36
37 void focusInEvent(QFocusEvent * event) override {
38 const Qt::FocusReason reason = event->reason();
39 if (reason == Qt::OtherFocusReason)
40 selectAll();
41 QWidget::focusInEvent(event);
42 }
43
44};
45
46
48 : QComboBox(parent)
49{
50 setFocusPolicy(Qt::WheelFocus);
51 setLineEdit(new BtKeyLineEdit(this));
52 if (lineEdit())
53 installEventFilter(lineEdit());
54}
55
56bool CKCComboBox::eventFilter(QObject * o, QEvent * e) {
57 if (e->type() == QEvent::FocusOut) {
58 QFocusEvent * const f = static_cast<QFocusEvent *>(e);
59
60 if (o == lineEdit() && f->reason() == Qt::TabFocusReason) {
61 int index = findText(currentText());
62 if (index == -1)
63 index = 0; // return 0 if not found
64 setCurrentIndex(index);
65 Q_EMIT focusOut(index);
66 return false;
67 }
68
69 if (f->reason() == Qt::PopupFocusReason)
70 return false;
71
72 if (f->reason() == Qt::ActiveWindowFocusReason) {
73 Q_EMIT textActivated(currentText());
74 return false;
75 }
76
77 if (f->reason() == Qt::MouseFocusReason) {
78 Q_EMIT textActivated(currentText());
79 return false;
80 }
81
82 if (o == this) {
83 Q_EMIT textActivated(currentText());
84 return false;
85 }
86 }
87
88 return QComboBox::eventFilter(o, e);
89}
90
91
92//**********************************************************************************/
93
95 : QWidget(parent)
96{
97 for (int index = 1; index <= count; index++) {
98 m_list.append( QString::number(index) );
99 }
100 init();
101 reset(m_list, 0, false);
102}
103
104CKeyChooserWidget::CKeyChooserWidget(QStringList * list, QWidget * parent )
105 : QWidget(parent)
106{
107 if (list)
108 m_list = *list;
109
110 init();
111 reset(m_list, 0, false);
112}
113
114void CKeyChooserWidget::reset(const int count, int index, bool do_emit) {
115 //This prevents the widget from resetting during application load, which
116 //produces undesirable behavior.
117 //if (!updatesEnabled())
118 // return;
119
120 m_list.clear();
121 for (int i = 1; i <= count; i++) /// \todo CHECK
122 m_list.append(QString::number(i));
123
124 reset(&m_list, index, do_emit);
125}
126
127void CKeyChooserWidget::reset(const QStringList & list, int index, bool do_emit) {
128 //This prevents the widget from resetting during application load, which
129 //produces undesirable behavior.
130 //if (!updatesEnabled())
131 // return;
132
133 m_list = list;
134 reset(&m_list, index, do_emit);
135}
136
137
138void CKeyChooserWidget::reset(const QStringList * list, int index, bool do_emit) {
139 //if (isResetting || !updatesEnabled())
140 if (m_isResetting)
141 return;
142
143 // qWarning("starting insert");
144 m_isResetting = true;
145
146 m_oldKey = QString();
147
148 // m_comboBox->setUpdatesEnabled(false);
149 //DON'T REMOVE THE HIDE: Otherwise QComboBox's sizeHint() function won't work properly
150 m_comboBox->hide();
151 m_comboBox->clear();
152 if (list && !list->empty()) {
153 m_comboBox->insertItems(0, *list); // Prepend items
154 setEnabled(true);
155 m_comboBox->setCurrentIndex(index);
156 } else {
157 setEnabled(false);
158 }
159
160 if (do_emit)
161 Q_EMIT changed(m_comboBox->currentIndex());
162
163 m_comboBox->sizeHint(); //without this function call the combo box won't be properly sized!
164 //DON'T REMOVE OR MOVE THE show()! Otherwise QComboBox's sizeHint() function won't work properly!
165 m_comboBox->show();
166
167 // m_comboBox->setFont( m_comboBox->font() );
168 // m_comboBox->setUpdatesEnabled(true);
169
170 m_isResetting = false;
171 // qWarning("inserted");
172}
173
174/** Initializes this widget. We need this function because we have more than one constructor. */
176 m_oldKey = QString();
177
178 setFocusPolicy(Qt::WheelFocus);
179
180 m_comboBox = new CKCComboBox(this);
181 setFocusProxy(m_comboBox);
182 m_comboBox->setEditable(true); // Also sets completer
183 BT_ASSERT(m_comboBox->completer());
184 m_comboBox->setInsertPolicy(QComboBox::NoInsert);
185 m_comboBox->setFocusPolicy(Qt::WheelFocus);
186
187 m_mainLayout = new QHBoxLayout(this);
188 m_mainLayout->setSpacing(0);
189 m_mainLayout->setContentsMargins(0, 0, 0, 0);
190 m_mainLayout->addWidget(m_comboBox);
191
192 m_scroller = new CScrollerWidgetSet(this);
193
194 m_mainLayout->addWidget(m_scroller);
195 m_mainLayout->addSpacing(0);
196
197 setTabOrder(m_comboBox, nullptr);
198 setFocusProxy(m_comboBox);
199
201 [this]{
202 updatelock = true;
203 m_comboBox->setEditable(false);
204 m_oldKey = m_comboBox->currentText();
205 });
207 [this]{
208 updatelock = false;
209 m_comboBox->setEditable(true);
210 m_comboBox->setEditText(
211 m_comboBox->itemText(
212 m_comboBox->currentIndex()));
213 if (m_comboBox->currentText() != m_oldKey)
214 Q_EMIT changed(m_comboBox->currentIndex());
215 });
217 [this](int n) {
218 const int old_index = m_comboBox->currentIndex();
219 int new_index = old_index + n;
220
221 //index of highest Item
222 const int max = m_comboBox->count() - 1;
223 if (new_index > max)
224 new_index = max;
225 if (new_index < 0)
226 new_index = 0;
227
228 if (new_index != old_index) {
229 m_comboBox->setCurrentIndex(new_index);
230 if (!updatelock)
231 Q_EMIT changed(new_index);
232 }
233 });
234 BT_CONNECT(m_comboBox, qOverload<int>(&QComboBox::activated),
235 [this](int index) {
236 if (!updatesEnabled())
237 return;
238
239 setUpdatesEnabled(false);
240
241 const QString key(m_comboBox->itemText(index));
242 if (m_oldKey.isNull() || (m_oldKey != key))
243 Q_EMIT changed(index);
244
245 m_oldKey = key;
246
247 setUpdatesEnabled(true);
248 });
249 BT_CONNECT(m_comboBox->lineEdit(), &QLineEdit::returnPressed,
250 [this]{
251 BT_ASSERT(m_comboBox->lineEdit());
252
253 const QString text(m_comboBox->lineEdit()->text());
254 for (int index = 0; index < m_comboBox->count(); ++index) {
255 if (m_comboBox->itemText(index) == text) {
256 // emit changed(index);
257 /* a workaround because focusOut is not checked, the
258 slot connected to changed to check: */
259 Q_EMIT focusOut(index);
260 break;
261 }
262 }
263 });
266
267 updatelock = false;
268 m_isResetting = false;
269}
270
271/** Sets the tooltips for the given entries using the parameters as text. */
272void CKeyChooserWidget::setToolTips(const QString & comboTip,
273 const QString & nextEntryTip,
274 const QString & scrollButtonTip,
275 const QString & previousEntryTip)
276{
277 m_comboBox->setToolTip(comboTip);
278 m_scroller->setToolTips(nextEntryTip, scrollButtonTip, previousEntryTip);
279}
280
281/** Sets the current item to the one with the given text */
282bool CKeyChooserWidget::setItem(const QString & item) {
283 bool ret = false;
284 const int count = m_comboBox->count();
285 for (int i = 0; i < count; ++i) {
286 if (m_comboBox->itemText(i) == item) {
287 m_comboBox->setCurrentIndex(i);
288 ret = true;
289 break;
290 }
291 }
292 if (!ret)
293 m_comboBox->setCurrentIndex(-1);
294 return ret;
295}
#define BT_ASSERT(...)
Definition btassert.h:17
#define BT_CONNECT(...)
Definition btconnect.h:20
BtKeyLineEdit(QWidget *parent)
void focusInEvent(QFocusEvent *event) override
CKCComboBox(QWidget *parent=nullptr)
void focusOut(int itemIndex)
bool eventFilter(QObject *o, QEvent *e) override
QHBoxLayout * m_mainLayout
void focusOut(int index)
bool setItem(const QString &item)
CKeyChooserWidget(QStringList *list=nullptr, QWidget *parent=nullptr)
void setToolTips(const QString &comboTip, const QString &nextEntry, const QString &scrollButton, const QString &previousEntry)
void changed(int index)
void reset(const int count, int index, bool do_emit)
CScrollerWidgetSet * m_scroller
CKCComboBox * m_comboBox
void setToolTips(const QString &nextEntry, const QString &scrollButton, const QString &previousEntry)
void change(int count)