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