12#include <QtCore/qregularexpression.h>
13#include <QtCore/qabstractitemmodel.h>
14#include <QtCore/qglobal.h>
15#include <QtGui/qinputmethod.h>
16#include <QtGui/qguiapplication.h>
17#include <QtGui/private/qguiapplication_p.h>
18#include <QtGui/qpa/qplatformtheme.h>
19#include <QtQml/qjsvalue.h>
20#include <QtQml/qqmlcontext.h>
21#include <QtQml/qqmlcomponent.h>
22#include <QtQml/private/qlazilyallocated_p.h>
23#include <private/qqmldelegatemodel_p.h>
24#include <QtQuick/private/qquickaccessibleattached_p.h>
25#include <QtQuick/private/qquickevents_p_p.h>
26#include <QtQuick/private/qquicktextinput_p.h>
27#include <QtQuick/private/qquicktextinput_p_p.h>
28#if QT_CONFIG(quick_itemview)
29#include <QtQuick/private/qquickitemview_p.h>
34Q_STATIC_LOGGING_CATEGORY(lcCalculateWidestTextWidth,
"qt.quick.controls.combobox.calculatewidesttextwidth")
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
113
114
115
116
117
118
119
120
121
122
123
124
127
128
129
130
131
132
133
134
135
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
176 QQuickComboBox *combo =
nullptr;
191 if (role == QLatin1String(
"modelData")) {
192 const QVariant model = combo->model();
193 if (model.metaType() == QMetaType::fromType<QVariantList>()) {
194 const QVariant object = model.toList().value(index);
195 if (object.metaType() == QMetaType::fromType<QVariantMap>()) {
196 const QVariantMap data = object.toMap();
197 if (data.size() == 1)
203 return QQmlDelegateModel::variantValue(index, role);
209 Q_DECLARE_PUBLIC(QQuickComboBox)
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
271 void onDataChanged(
const QModelIndex &topLeft,
const QModelIndex &bottomRight,
const QList<
int> &roles);
286 int match(
int start,
const QString &text, Qt::MatchFlags flags)
const;
291 bool handleMove(
const QPointF &point, ulong timestamp)
override;
350#if QT_CONFIG(validator)
359 return popup && popup->isVisible();
367 if (popup && !popup->isVisible())
378 emit q->activated(highlightedIndex);
380 if (popup && popup->isVisible())
386 if (!popup || !popup->isVisible())
395 if (isPopupVisible())
396 QGuiApplication::inputMethod()->reset();
398#if QT_CONFIG(quick_itemview)
399 QQuickItemView *itemView = popup->findChild<QQuickItemView *>();
401 itemView->setHighlightRangeMode(QQuickItemView::NoHighlightRange);
406#if QT_CONFIG(quick_itemview)
408 itemView->positionViewAtIndex(highlightedIndex, QQuickItemView::Beginning);
412 q->setDown(pressed || isPopupVisible());
421 emit q->popupChanged();
427 int index = delegateModel->indexOf(q->sender(),
nullptr);
440 QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(q->sender());
441 if (!button || !button->isHovered() || !button->isEnabled() || QQuickAbstractButtonPrivate::get(button)->touchId != -1)
444 int index = delegateModel->indexOf(button,
nullptr);
448#if QT_CONFIG(quick_itemview)
449 if (QQuickItemView *itemView = popup->findChild<QQuickItemView *>())
450 itemView->positionViewAtIndex(index, QQuickItemView::Contain);
458 QQuickItem *item = qobject_cast<QQuickItem *>(object);
459 if (item && !item->parentItem()) {
461 item->setParentItem(popup->contentItem());
463 item->setParentItem(q);
464 QQuickItemPrivate::get(item)->setCulled(
true);
467 QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(object);
469 button->setFocusPolicy(Qt::NoFocus);
470 connect(button, &QQuickAbstractButton::clicked,
this, &QQuickComboBoxPrivate::itemClicked);
471 connect(button, &QQuickAbstractButton::hoveredChanged,
this, &QQuickComboBoxPrivate::itemHovered);
474 if (index == currentIndex && !q->isEditable())
480 if (componentComplete && (!extra.isAllocated() || !extra->accepting)) {
483 if (implicitContentWidthPolicy == QQuickComboBox::WidestText)
484 updateImplicitContentSize();
491 if (q->count() == 0) {
492 if (currentElementCriteria == CurrentElementCriteria::CurrentValue)
497 emit q->countChanged();
502 return textRole.isEmpty() ? QStringLiteral(
"modelData") : textRole;
508 QQuickTextInput *input = qobject_cast<QQuickTextInput *>(contentItem);
512 const QString text = input->text();
514 if (extra.isAllocated() && extra->allowComplete && !text.isEmpty()) {
515 const QString completed = tryComplete(text);
516 if (completed.size() > text.size()) {
517 input->setText(completed);
519 input->select(completed.size(), text.size());
523 q->setEditText(text);
529 const int index = q->indexOfValue(currentValue);
534 emit q->currentIndexChanged();
540 const QString text = q->textAt(currentIndex);
541 if (currentText != text) {
544 q->maybeSetAccessibleName(text);
545 emit q->currentTextChanged();
547 if (!hasDisplayText && displayText != text) {
549 emit q->displayTextChanged();
551 if (!extra.isAllocated() || !extra->accepting)
552 q->setEditText(currentText);
558 const QVariant value = q->valueAt(currentIndex);
559 if (currentValue == value)
562 currentValue = value;
563 emit q->currentValueChanged();
568 switch (currentElementCriteria) {
569 case CurrentElementCriteria::None:
571 case CurrentElementCriteria::CurrentIndex:
575 case CurrentElementCriteria::CurrentValue:
589 const QQuickTextInput *textInputContentItem = qobject_cast<QQuickTextInput *>(contentItem);
591 if (!textInputContentItem)
594 const bool newValue = textInputContentItem->hasAcceptableInput();
598 emit q->acceptableInputChanged();
617 int idx = q->find(extra.value().editText, Qt::MatchFixedString);
622 QQuickTextInput *input = qobject_cast<QQuickTextInput *>(contentItem);
624 const auto text = input->text();
625 input->select(text.size(), text.size());
629 extra.value().accepting =
true;
635 idx = q->find(extra.value().editText, Qt::MatchFixedString);
638 extra.value().accepting =
false;
646 const int itemCount = q->count();
647 for (
int idx = 0; idx < itemCount; ++idx) {
648 const QString text = q->textAt(idx);
649 if (!text.startsWith(input, Qt::CaseInsensitive))
653 if (match.isEmpty() || text.size() < match.size())
660 return input + match.mid(input.size());
670 emit q->currentIndexChanged();
672 if (componentComplete)
683 emit q->currentIndexChanged();
689 emit q->activated(index);
695 if (extra.isAllocated())
696 extra->allowComplete =
false;
698 if (highlightedIndex < q->count() - 1)
701 if (currentIndex < q->count() - 1)
704 if (extra.isAllocated())
705 extra->allowComplete =
true;
710 if (extra.isAllocated())
711 extra->allowComplete =
false;
719 if (extra.isAllocated())
720 extra->allowComplete =
true;
725 setHighlightedIndex(popup->isVisible() ? currentIndex : -1, NoHighlight);
735 emit q->highlightedIndexChanged();
738 emit q->highlighted(index);
744 const int index = match(startIndex + 1, text, Qt::MatchStartsWith | Qt::MatchWrap);
755 Q_Q(
const QQuickComboBox);
756 uint matchType = flags & 0x0F;
757 bool wrap = flags & Qt::MatchWrap;
758 Qt::CaseSensitivity cs = flags & Qt::MatchCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
759 QRegularExpression::PatternOptions options = flags & Qt::MatchCaseSensitive ? QRegularExpression::NoPatternOption
760 : QRegularExpression::CaseInsensitiveOption;
765 for (
int i = 0; (wrap && i < 2) || (!wrap && i < 1); ++i) {
766 for (
int idx = from; idx < to; ++idx) {
767 QString t = q->textAt(idx);
769 case Qt::MatchExactly:
773 case Qt::MatchRegularExpression: {
774 QRegularExpression rx(QRegularExpression::anchoredPattern(text), options);
775 if (rx.match(t).hasMatch())
779 case Qt::MatchWildcard: {
780 QRegularExpression rx(QRegularExpression::wildcardToRegularExpression(text),
782 if (rx.match(t).hasMatch())
786 case Qt::MatchStartsWith:
787 if (t.startsWith(text, cs))
790 case Qt::MatchEndsWith:
791 if (t.endsWith(text, cs))
794 case Qt::MatchFixedString:
795 if (t.compare(text, cs) == 0)
798 case Qt::MatchContains:
800 if (t.contains(text, cs))
818 disconnect(delegateModel, &QQmlInstanceModel::countChanged,
this, &QQuickComboBoxPrivate::countChanged);
819 disconnect(delegateModel, &QQmlInstanceModel::modelUpdated,
this, &QQuickComboBoxPrivate::modelUpdated);
820 disconnect(delegateModel, &QQmlInstanceModel::createdItem,
this, &QQuickComboBoxPrivate::createdItem);
824 delegateModel = model.value<QQmlInstanceModel *>();
826 if (!delegateModel && model.isValid()) {
827 QQmlDelegateModel *dataModel =
new QQuickComboBoxDelegateModel(q);
828 dataModel->setModel(model);
830 if (q->isComponentComplete())
831 dataModel->componentComplete();
838 connect(delegateModel, &QQmlInstanceModel::countChanged,
this, &QQuickComboBoxPrivate::countChanged);
839 connect(delegateModel, &QQmlInstanceModel::modelUpdated,
this, &QQuickComboBoxPrivate::modelUpdated);
840 connect(delegateModel, &QQmlInstanceModel::createdItem,
this, &QQuickComboBoxPrivate::createdItem);
843 emit q->delegateModelChanged();
852 QQuickControlPrivate::handlePress(point, timestamp);
860 QQuickControlPrivate::handleMove(point, timestamp);
861 q->setPressed(q->contains(point));
868 QQuickControlPrivate::handleRelease(point, timestamp);
870 q->setPressed(
false);
879 QQuickControlPrivate::handleUngrab();
880 q->setPressed(
false);
886 quickCancelDeferred(q, indicatorName());
892 if (indicator.wasExecuted())
895 if (!indicator || complete)
896 quickBeginDeferred(q, indicatorName(), indicator);
898 quickCompleteDeferred(q, indicatorName(), indicator);
901static inline QString
popupName() {
return QStringLiteral(
"popup"); }
906 quickCancelDeferred(q, popupName());
912 if (popup.wasExecuted())
915 if (!popup || complete)
916 quickBeginDeferred(q, popupName(), popup);
918 quickCompleteDeferred(q, popupName(), popup);
924 QQuickControlPrivate::itemImplicitWidthChanged(item);
925 if (item == indicator)
926 emit q->implicitIndicatorWidthChanged();
932 if (!force && hints == q->inputMethodHints())
935 extra.value().inputMethodHints = hints;
936 emit q->inputMethodHintsChanged();
942 QQuickControlPrivate::itemImplicitHeightChanged(item);
943 if (item == indicator)
944 emit q->implicitIndicatorHeightChanged();
950 QQuickControlPrivate::itemDestroyed(item);
951 if (item == indicator) {
953 emit q->indicatorChanged();
959 if (componentComplete) {
960 switch (implicitContentWidthPolicy) {
961 case QQuickComboBox::WidestText:
962 return calculateWidestTextWidth();
963 case QQuickComboBox::WidestTextWhenCompleted:
964 if (!hasCalculatedWidestText)
965 return calculateWidestTextWidth();
972 return QQuickControlPrivate::getContentWidth();
977 Q_Q(
const QQuickComboBox);
978 if (!componentComplete)
981 const int count = q->count();
985 auto textInput = qobject_cast<QQuickTextInput*>(contentItem);
989 qCDebug(lcCalculateWidestTextWidth) <<
"calculating widest text from" << count <<
"items...";
993 const QString textRole = effectiveTextRole();
994 auto textInputPrivate = QQuickTextInputPrivate::get(textInput);
996 for (
int i = 0; i < count; ++i) {
997 const QString text = delegateModel->stringValue(i, textRole);
998 const qreal textImplicitWidth = textInputPrivate->calculateImplicitWidthForText(text);
999 widest = qMax(widest, textImplicitWidth);
1002 qCDebug(lcCalculateWidestTextWidth) <<
"... widest text is" << widest;
1007
1008
1009
1010
1011
1014 if (!componentComplete)
1017 if (implicitContentWidthPolicy == QQuickComboBox::ContentItemImplicitWidth
1018 || (implicitContentWidthPolicy == QQuickComboBox::WidestTextWhenCompleted && hasCalculatedWidestText))
1021 updateImplicitContentWidth();
1030 qCDebug(lcItemManagement) <<
"hiding old popup" << popup;
1032 popup->setVisible(
false);
1033 popup->setParentItem(
nullptr);
1034#if QT_CONFIG(accessibility)
1036 QQuickAccessibleAttached *accessible = accessibleAttached(popup);
1038 accessible->setIgnored(
true);
1042QQuickComboBox::QQuickComboBox(QQuickItem *parent)
1043 : QQuickControl(*(
new QQuickComboBoxPrivate), parent)
1045 setFocusPolicy(Qt::StrongFocus);
1046 setFlag(QQuickItem::ItemIsFocusScope);
1047 setAcceptedMouseButtons(Qt::LeftButton);
1048#if QT_CONFIG(cursor)
1049 setCursor(Qt::ArrowCursor);
1051 Q_D(QQuickComboBox);
1052 d->setInputMethodHints(Qt::ImhNoPredictiveText,
true);
1053 d->setSizePolicy(QLayoutPolicy::Preferred, QLayoutPolicy::Fixed);
1056QQuickComboBox::~QQuickComboBox()
1058 Q_D(QQuickComboBox);
1059 d->removeImplicitSizeListener(d->indicator);
1063 QObjectPrivate::disconnect(d->popup.data(), &QQuickPopup::visibleChanged, d, &QQuickComboBoxPrivate::popupVisibleChanged);
1064 QQuickComboBoxPrivate::hideOldPopup(d->popup);
1070
1071
1072
1073
1074
1075int QQuickComboBox::count()
const
1077 Q_D(
const QQuickComboBox);
1078 return d->delegateModel ? d->delegateModel->count() : 0;
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099QVariant QQuickComboBox::model()
const
1101 Q_D(
const QQuickComboBox);
1102 if (!d->qobjectModelGuard.has_value()) {
1108 return !d->qobjectModelGuard->isNull() ? d->model : QVariant();
1111void QQuickComboBox::setModel(
const QVariant& m)
1113 Q_D(QQuickComboBox);
1114 QVariant newModel = m;
1115 if (newModel.userType() == qMetaTypeId<QJSValue>())
1116 newModel = newModel.value<QJSValue>().toVariant();
1118 if (d->model == newModel)
1121 if (d->qobjectModelGuard.has_value() && !d->qobjectModelGuard->isNull()) {
1122 if (QAbstractItemModel* aim = qvariant_cast<QAbstractItemModel *>(d->model)) {
1123 QObjectPrivate::disconnect(aim, &QAbstractItemModel::dataChanged,
1124 d, &QQuickComboBoxPrivate::onDataChanged);
1127 if (QObject* newModelAsQObject = qvariant_cast<QObject *>(newModel)) {
1131 d->qobjectModelGuard = QPointer<QObject>(newModelAsQObject);
1133 if (QAbstractItemModel* aim = qvariant_cast<QAbstractItemModel *>(newModel)) {
1134 QObjectPrivate::connect(aim, &QAbstractItemModel::dataChanged,
1135 d, &QQuickComboBoxPrivate::onDataChanged);
1139 d->qobjectModelGuard.reset();
1142 d->model = newModel;
1143 d->createDelegateModel();
1144 emit countChanged();
1145 if (isComponentComplete()) {
1146 if (d->currentElementCriteria != QQuickComboBoxPrivate::CurrentElementCriteria::CurrentValue)
1147 d->setCurrentIndex(count() > 0 ? 0 : -1);
1148 d->updateCurrentElements();
1150 emit modelChanged();
1152 d->maybeUpdateImplicitContentWidth();
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166QQmlInstanceModel *QQuickComboBox::delegateModel()
const
1168 Q_D(
const QQuickComboBox);
1169 return d->delegateModel;
1174
1175
1176
1177
1178
1179
1180
1181
1182bool QQuickComboBox::isPressed()
const
1184 Q_D(
const QQuickComboBox);
1188void QQuickComboBox::setPressed(
bool pressed)
1190 Q_D(QQuickComboBox);
1191 if (d->pressed == pressed)
1194 d->pressed = pressed;
1195 emit pressedChanged();
1198 setDown(d->pressed || d->isPopupVisible());
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215int QQuickComboBox::highlightedIndex()
const
1217 Q_D(
const QQuickComboBox);
1218 return d->highlightedIndex;
1222
1223
1224
1225
1226
1227
1228
1229
1230int QQuickComboBox::currentIndex()
const
1232 Q_D(
const QQuickComboBox);
1233 return d->currentIndex;
1236void QQuickComboBox::setCurrentIndex(
int index)
1238 Q_D(QQuickComboBox);
1239 d->currentElementCriteria = QQuickComboBoxPrivate::CurrentElementCriteria::CurrentIndex;
1240 d->setCurrentIndex(index);
1244
1245
1246
1247
1248
1249
1250
1251QString QQuickComboBox::currentText()
const
1253 Q_D(
const QQuickComboBox);
1254 return d->currentText;
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276QString QQuickComboBox::displayText()
const
1278 Q_D(
const QQuickComboBox);
1279 return d->displayText;
1282void QQuickComboBox::setDisplayText(
const QString &text)
1284 Q_D(QQuickComboBox);
1285 d->hasDisplayText =
true;
1286 if (d->displayText == text)
1289 d->displayText = text;
1290 maybeSetAccessibleName(text);
1291 emit displayTextChanged();
1294void QQuickComboBox::resetDisplayText()
1296 Q_D(QQuickComboBox);
1297 if (!d->hasDisplayText)
1300 d->hasDisplayText =
false;
1301 d->updateCurrentText();
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315QString QQuickComboBox::textRole()
const
1317 Q_D(
const QQuickComboBox);
1321void QQuickComboBox::setTextRole(
const QString &role)
1323 Q_D(QQuickComboBox);
1324 if (d->textRole == role)
1328 if (isComponentComplete())
1329 d->updateCurrentText();
1330 emit textRoleChanged();
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344QString QQuickComboBox::valueRole()
const
1346 Q_D(
const QQuickComboBox);
1347 return d->valueRole;
1350void QQuickComboBox::setValueRole(
const QString &role)
1352 Q_D(QQuickComboBox);
1353 if (d->valueRole == role)
1356 d->valueRole = role;
1357 if (isComponentComplete())
1358 d->updateCurrentElements();
1359 emit valueRoleChanged();
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387QQmlComponent *QQuickComboBox::delegate()
const
1389 Q_D(
const QQuickComboBox);
1393void QQuickComboBox::setDelegate(QQmlComponent* delegate)
1395 Q_D(QQuickComboBox);
1396 if (d->delegate == delegate)
1399 d->delegate = delegate;
1400 QQmlDelegateModel *delegateModel = qobject_cast<QQmlDelegateModel*>(d->delegateModel);
1402 delegateModel->setDelegate(d->delegate);
1403 emit delegateChanged();
1407
1408
1409
1410
1411
1412
1413QQuickItem *QQuickComboBox::indicator()
const
1415 QQuickComboBoxPrivate *d =
const_cast<QQuickComboBoxPrivate *>(d_func());
1417 d->executeIndicator();
1418 return d->indicator;
1421void QQuickComboBox::setIndicator(QQuickItem *indicator)
1423 Q_D(QQuickComboBox);
1424 if (d->indicator == indicator)
1427 QQuickControlPrivate::warnIfCustomizationNotSupported(
this, indicator, QStringLiteral(
"indicator"));
1429 if (!d->indicator.isExecuting())
1430 d->cancelIndicator();
1432 const qreal oldImplicitIndicatorWidth = implicitIndicatorWidth();
1433 const qreal oldImplicitIndicatorHeight = implicitIndicatorHeight();
1435 d->removeImplicitSizeListener(d->indicator);
1436 QQuickControlPrivate::hideOldItem(d->indicator);
1437 d->indicator = indicator;
1439 if (!indicator->parentItem())
1440 indicator->setParentItem(
this);
1441 d->addImplicitSizeListener(indicator);
1444 if (!qFuzzyCompare(oldImplicitIndicatorWidth, implicitIndicatorWidth()))
1445 emit implicitIndicatorWidthChanged();
1446 if (!qFuzzyCompare(oldImplicitIndicatorHeight, implicitIndicatorHeight()))
1447 emit implicitIndicatorHeightChanged();
1448 if (!d->indicator.isExecuting())
1449 emit indicatorChanged();
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465QQuickPopup *QQuickComboBox::popup()
const
1467 QQuickComboBoxPrivate *d =
const_cast<QQuickComboBoxPrivate *>(d_func());
1469 d->executePopup(isComponentComplete());
1473void QQuickComboBox::setPopup(QQuickPopup *popup)
1475 Q_D(QQuickComboBox);
1476 if (d->popup == popup)
1479 if (!d->popup.isExecuting())
1483 QObjectPrivate::disconnect(d->popup.data(), &QQuickPopup::destroyed, d, &QQuickComboBoxPrivate::popupDestroyed);
1484 QObjectPrivate::disconnect(d->popup.data(), &QQuickPopup::visibleChanged, d, &QQuickComboBoxPrivate::popupVisibleChanged);
1485 QQuickComboBoxPrivate::hideOldPopup(d->popup);
1488 QQuickPopupPrivate::get(popup)->allowVerticalFlip =
true;
1489 popup->setClosePolicy(QQuickPopup::CloseOnEscape | QQuickPopup::CloseOnPressOutsideParent);
1490 QObjectPrivate::connect(popup, &QQuickPopup::visibleChanged, d, &QQuickComboBoxPrivate::popupVisibleChanged);
1493 QObjectPrivate::connect(popup, &QQuickPopup::destroyed, d, &QQuickComboBoxPrivate::popupDestroyed);
1495#if QT_CONFIG(quick_itemview)
1496 if (QQuickItemView *itemView = popup->findChild<QQuickItemView *>())
1497 itemView->setHighlightRangeMode(QQuickItemView::NoHighlightRange);
1501 if (!d->popup.isExecuting())
1502 emit popupChanged();
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519bool QQuickComboBox::isFlat()
const
1521 Q_D(
const QQuickComboBox);
1525void QQuickComboBox::setFlat(
bool flat)
1527 Q_D(QQuickComboBox);
1528 if (d->flat == flat)
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547bool QQuickComboBox::isDown()
const
1549 Q_D(
const QQuickComboBox);
1553void QQuickComboBox::setDown(
bool down)
1555 Q_D(QQuickComboBox);
1558 if (d->down == down)
1565void QQuickComboBox::resetDown()
1567 Q_D(QQuickComboBox);
1571 setDown(d->pressed || d->isPopupVisible());
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585bool QQuickComboBox::isEditable()
const
1587 Q_D(
const QQuickComboBox);
1588 return d->extra.isAllocated() && d->extra->editable;
1591void QQuickComboBox::setEditable(
bool editable)
1593 Q_D(QQuickComboBox);
1594 if (editable == isEditable())
1597 if (d->contentItem) {
1599 d->contentItem->installEventFilter(
this);
1600 if (QQuickTextInput *input = qobject_cast<QQuickTextInput *>(d->contentItem)) {
1601 QObjectPrivate::connect(input, &QQuickTextInput::textChanged, d, &QQuickComboBoxPrivate::updateEditText);
1602 QObjectPrivate::connect(input, &QQuickTextInput::accepted, d, &QQuickComboBoxPrivate::acceptInput);
1604#if QT_CONFIG(cursor)
1605 d->contentItem->setCursor(Qt::IBeamCursor);
1608 d->contentItem->removeEventFilter(
this);
1609 if (QQuickTextInput *input = qobject_cast<QQuickTextInput *>(d->contentItem)) {
1610 QObjectPrivate::disconnect(input, &QQuickTextInput::textChanged, d, &QQuickComboBoxPrivate::updateEditText);
1611 QObjectPrivate::disconnect(input, &QQuickTextInput::accepted, d, &QQuickComboBoxPrivate::acceptInput);
1613#if QT_CONFIG(cursor)
1614 d->contentItem->unsetCursor();
1619 d->extra.value().editable = editable;
1620 setAccessibleProperty(
"editable", editable);
1621 emit editableChanged();
1625
1626
1627
1628
1629
1630
1631
1632QString QQuickComboBox::editText()
const
1634 Q_D(
const QQuickComboBox);
1635 return d->extra.isAllocated() ? d->extra->editText : QString();
1638void QQuickComboBox::setEditText(
const QString &text)
1640 Q_D(QQuickComboBox);
1641 if (text == editText())
1644 d->extra.value().editText = text;
1645 emit editTextChanged();
1648void QQuickComboBox::resetEditText()
1650 setEditText(QString());
1653#if QT_CONFIG(validator)
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683QValidator *QQuickComboBox::validator()
const
1685 Q_D(
const QQuickComboBox);
1686 return d->extra.isAllocated() ? d->extra->validator :
nullptr;
1689void QQuickComboBox::setValidator(QValidator *validator)
1691 Q_D(QQuickComboBox);
1692 if (validator == QQuickComboBox::validator())
1695 d->extra.value().validator = validator;
1696#if QT_CONFIG(validator)
1698 validator->setLocale(d->locale);
1700 emit validatorChanged();
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715Qt::InputMethodHints QQuickComboBox::inputMethodHints()
const
1717 Q_D(
const QQuickComboBox);
1718 return d->extra.isAllocated() ? d->extra->inputMethodHints : Qt::ImhNoPredictiveText;
1721void QQuickComboBox::setInputMethodHints(Qt::InputMethodHints hints)
1723 Q_D(QQuickComboBox);
1724 d->setInputMethodHints(hints);
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738bool QQuickComboBox::isInputMethodComposing()
const
1740 Q_D(
const QQuickComboBox);
1741 return d->contentItem && d->contentItem->property(
"inputMethodComposing").toBool();
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756bool QQuickComboBox::hasAcceptableInput()
const
1758 Q_D(
const QQuickComboBox);
1759 return d->m_acceptableInput;
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776qreal QQuickComboBox::implicitIndicatorWidth()
const
1778 Q_D(
const QQuickComboBox);
1781 return d->indicator->implicitWidth();
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798qreal QQuickComboBox::implicitIndicatorHeight()
const
1800 Q_D(
const QQuickComboBox);
1803 return d->indicator->implicitHeight();
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821QVariant QQuickComboBox::currentValue()
const
1823 Q_D(
const QQuickComboBox);
1824 return d->currentValue;
1827void QQuickComboBox::setCurrentValue(
const QVariant &value)
1829 Q_D(QQuickComboBox);
1830 d->currentElementCriteria = QQuickComboBoxPrivate::CurrentElementCriteria::CurrentValue;
1831 if (value == d->currentValue)
1834 d->currentValue = value;
1835 emit currentValueChanged();
1837 if (d->componentComplete)
1838 d->updateCurrentElements();
1842
1843
1844
1845
1846
1847
1848
1849
1850QVariant QQuickComboBox::valueAt(
int index)
const
1852 Q_D(
const QQuickComboBox);
1853 if (!d->isValidIndex(index))
1856 const QString effectiveValueRole = d->valueRole.isEmpty() ? QStringLiteral(
"modelData") : d->valueRole;
1857 return d->delegateModel->variantValue(index, effectiveValueRole);
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872int QQuickComboBox::indexOfValue(
const QVariant &value)
const
1874 for (
int i = 0; i < count(); ++i) {
1875 const QVariant ourValue = valueAt(i);
1876 if (value == ourValue)
1883
1884
1885
1886
1887
1888
1889
1890
1891bool QQuickComboBox::selectTextByMouse()
const
1893 Q_D(
const QQuickComboBox);
1894 return d->extra.isAllocated() ? d->extra->selectTextByMouse :
false;
1897void QQuickComboBox::setSelectTextByMouse(
bool canSelect)
1899 Q_D(QQuickComboBox);
1900 if (canSelect == selectTextByMouse())
1903 d->extra.value().selectTextByMouse = canSelect;
1904 emit selectTextByMouseChanged();
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961QQuickComboBox::ImplicitContentWidthPolicy QQuickComboBox::implicitContentWidthPolicy()
const
1963 Q_D(
const QQuickComboBox);
1964 return d->implicitContentWidthPolicy;
1967void QQuickComboBox::setImplicitContentWidthPolicy(QQuickComboBox::ImplicitContentWidthPolicy policy)
1969 Q_D(QQuickComboBox);
1970 if (policy == d->implicitContentWidthPolicy)
1973 d->implicitContentWidthPolicy = policy;
1974 d->maybeUpdateImplicitContentWidth();
1975 emit implicitContentWidthPolicyChanged();
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989QString QQuickComboBox::textAt(
int index)
const
1991 Q_D(
const QQuickComboBox);
1992 if (!d->isValidIndex(index))
1995 return d->delegateModel->stringValue(index, d->effectiveTextRole());
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022int QQuickComboBox::find(
const QString &text, Qt::MatchFlags flags)
const
2024 Q_D(
const QQuickComboBox);
2025 return d->match(0, text, flags);
2029
2030
2031
2032
2033
2034
2035
2036void QQuickComboBox::incrementCurrentIndex()
2038 Q_D(QQuickComboBox);
2039 d->incrementCurrentIndex();
2043
2044
2045
2046
2047
2048
2049
2050void QQuickComboBox::decrementCurrentIndex()
2052 Q_D(QQuickComboBox);
2053 d->decrementCurrentIndex();
2057
2058
2059
2060
2061
2062
2063
2064void QQuickComboBox::selectAll()
2066 Q_D(QQuickComboBox);
2067 QQuickTextInput *input = qobject_cast<QQuickTextInput *>(d->contentItem);
2073bool QQuickComboBox::eventFilter(QObject *object, QEvent *event)
2075 Q_D(QQuickComboBox);
2076 switch (event->type()) {
2077 case QEvent::MouseButtonRelease:
2078 if (d->isPopupVisible())
2079 d->hidePopup(
false);
2081 case QEvent::KeyPress: {
2082 QKeyEvent *ke =
static_cast<QKeyEvent *>(event);
2083 if (d->filterKeyEvent(ke,
false))
2086 if (d->extra.isAllocated())
2087 d->extra->allowComplete = ke->key() != Qt::Key_Backspace && ke->key() != Qt::Key_Delete;
2090 case QEvent::FocusOut: {
2091 const bool hasActiveFocus = d->popup && d->popup->hasActiveFocus();
2092 const bool usingPopupWindows =
2093 d->popup ? QQuickPopupPrivate::get(d->popup)->usePopupWindow() :
false;
2094 if (qGuiApp->focusObject() !=
this && !(hasActiveFocus && !usingPopupWindows)) {
2098 d->hidePopup(
false);
2103 const int indexForEditText = find(d->extra.value().editText, Qt::MatchFixedString);
2104 if (indexForEditText > -1)
2105 d->setCurrentItemAtIndex(indexForEditText, Activate);
2110 case QEvent::InputMethod:
2111 if (d->extra.isAllocated())
2112 d->extra->allowComplete = !
static_cast<QInputMethodEvent*>(event)->commitString().isEmpty();
2118 return QQuickControl::eventFilter(object, event);
2121void QQuickComboBox::focusInEvent(QFocusEvent *event)
2123 Q_D(QQuickComboBox);
2124 QQuickControl::focusInEvent(event);
2128 if ((event->reason() == Qt::TabFocusReason || event->reason() == Qt::BacktabFocusReason ||
2129 event->reason() == Qt::ShortcutFocusReason) && d->contentItem && isEditable())
2130 d->contentItem->forceActiveFocus(event->reason());
2133void QQuickComboBox::focusOutEvent(QFocusEvent *event)
2135 Q_D(QQuickComboBox);
2136 QQuickControl::focusOutEvent(event);
2138 const bool hasActiveFocus = d->popup && d->popup->hasActiveFocus();
2139 const bool usingPopupWindows = d->popup && QQuickPopupPrivate::get(d->popup)->usePopupWindow();
2140 if (qGuiApp->focusObject() != d->contentItem && !(hasActiveFocus && !usingPopupWindows)) {
2144 d->hidePopup(
false);
2150void QQuickComboBox::inputMethodEvent(QInputMethodEvent *event)
2152 Q_D(QQuickComboBox);
2153 QQuickControl::inputMethodEvent(event);
2154 if (!isEditable() && !event->commitString().isEmpty())
2155 d->keySearch(event->commitString());
2161void QQuickComboBox::keyPressEvent(QKeyEvent *event)
2163 Q_D(QQuickComboBox);
2164 QQuickControl::keyPressEvent(event);
2166 const auto key = event->key();
2167 if (!isEditable()) {
2168 const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::ButtonPressKeys).value<QList<Qt::Key>>();
2169 if (buttonPressKeys.contains(key)) {
2170 if (!event->isAutoRepeat())
2178 case Qt::Key_Escape:
2180 d->acceptedEscKeyPress = d->isPopupVisible();
2181 d->receivedEscKeyPress =
true;
2182 if (d->acceptedEscKeyPress) {
2183 d->hidePopup(
false);
2189 case Qt::Key_Return:
2190 if (d->isPopupVisible())
2195 d->keyNavigating =
true;
2196 d->decrementCurrentIndex();
2200 d->keyNavigating =
true;
2201 d->incrementCurrentIndex();
2205 d->keyNavigating =
true;
2206 if (d->isPopupVisible())
2207 d->setHighlightedIndex(0, Highlight);
2209 d->setCurrentItemAtIndex(0, Activate);
2213 d->keyNavigating =
true;
2214 if (d->isPopupVisible())
2215 d->setHighlightedIndex(count() - 1, Highlight);
2217 d->setCurrentItemAtIndex(count() - 1, Activate);
2221 if (!isEditable() && !event->text().isEmpty())
2222 d->keySearch(event->text());
2229void QQuickComboBox::keyReleaseEvent(QKeyEvent *event)
2231 Q_D(QQuickComboBox);
2232 QQuickControl::keyReleaseEvent(event);
2233 d->keyNavigating =
false;
2234 if (event->isAutoRepeat())
2237 const auto key = event->key();
2238 if (!isEditable()) {
2239 const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::ButtonPressKeys).value<QList<Qt::Key>>();
2240 if (buttonPressKeys.contains(key)) {
2241 if (!isEditable() && isPressed())
2242 d->togglePopup(
true);
2251 case Qt::Key_Return:
2252 if (!isEditable() || d->isPopupVisible())
2253 d->hidePopup(d->isPopupVisible());
2257 case Qt::Key_Escape:
2263 if (d->acceptedEscKeyPress || !d->receivedEscKeyPress)
2265 d->acceptedEscKeyPress =
false;
2266 d->receivedEscKeyPress =
false;
2273#if QT_CONFIG(wheelevent)
2274void QQuickComboBox::wheelEvent(QWheelEvent *event)
2276 Q_D(QQuickComboBox);
2277 QQuickControl::wheelEvent(event);
2278 if (d->wheelEnabled && !d->isPopupVisible()) {
2279 if (event->angleDelta().y() > 0)
2280 d->decrementCurrentIndex();
2282 d->incrementCurrentIndex();
2287bool QQuickComboBox::event(QEvent *e)
2289 Q_D(QQuickComboBox);
2290 if (e->type() == QEvent::LanguageChange)
2291 d->updateCurrentElements();
2292 return QQuickControl::event(e);
2295void QQuickComboBox::componentComplete()
2297 Q_D(QQuickComboBox);
2298 d->executeIndicator(
true);
2299 QQuickControl::componentComplete();
2301 d->executePopup(
true);
2303 if (d->delegateModel && d->ownModel)
2304 static_cast<QQmlDelegateModel *>(d->delegateModel)->componentComplete();
2307 if (d->currentElementCriteria == QQuickComboBoxPrivate::CurrentElementCriteria::None && d->currentIndex == -1)
2308 d->setCurrentIndex(0);
2310 d->updateCurrentElements();
2314 if (!d->hasCalculatedWidestText)
2315 d->maybeUpdateImplicitContentWidth();
2319void QQuickComboBox::itemChange(QQuickItem::ItemChange change,
const QQuickItem::ItemChangeData &value)
2321 Q_D(QQuickComboBox);
2322 QQuickControl::itemChange(change, value);
2323 if (change == ItemVisibleHasChanged && !value.boolValue) {
2324 d->hidePopup(
false);
2329void QQuickComboBox::fontChange(
const QFont &newFont,
const QFont &oldFont)
2331 Q_D(QQuickComboBox);
2332 QQuickControl::fontChange(newFont, oldFont);
2333 d->maybeUpdateImplicitContentWidth();
2336void QQuickComboBox::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
2338 Q_D(QQuickComboBox);
2340 oldItem->removeEventFilter(
this);
2341 if (QQuickTextInput *oldInput = qobject_cast<QQuickTextInput *>(oldItem)) {
2342 QObjectPrivate::disconnect(oldInput, &QQuickTextInput::accepted, d, &QQuickComboBoxPrivate::acceptInput);
2343 QObjectPrivate::disconnect(oldInput, &QQuickTextInput::textChanged, d, &QQuickComboBoxPrivate::updateEditText);
2344 disconnect(oldInput, &QQuickTextInput::inputMethodComposingChanged,
this, &QQuickComboBox::inputMethodComposingChanged);
2345 QObjectPrivate::disconnect(oldInput, &QQuickTextInput::acceptableInputChanged, d, &QQuickComboBoxPrivate::updateAcceptableInput);
2348 if (newItem && isEditable()) {
2349 newItem->installEventFilter(
this);
2350 if (QQuickTextInput *newInput = qobject_cast<QQuickTextInput *>(newItem)) {
2351 QObjectPrivate::connect(newInput, &QQuickTextInput::accepted, d, &QQuickComboBoxPrivate::acceptInput);
2352 QObjectPrivate::connect(newInput, &QQuickTextInput::textChanged, d, &QQuickComboBoxPrivate::updateEditText);
2353 connect(newInput, &QQuickTextInput::inputMethodComposingChanged,
this, &QQuickComboBox::inputMethodComposingChanged);
2354 QObjectPrivate::connect(newInput, &QQuickTextInput::acceptableInputChanged, d, &QQuickComboBoxPrivate::updateAcceptableInput);
2356#if QT_CONFIG(cursor)
2357 newItem->setCursor(Qt::IBeamCursor);
2361 d->updateAcceptableInput();
2364void QQuickComboBox::localeChange(
const QLocale &newLocale,
const QLocale &oldLocale)
2366 QQuickControl::localeChange(newLocale, oldLocale);
2367#if QT_CONFIG(validator)
2368 if (QValidator *v = validator())
2369 v->setLocale(newLocale);
2373QFont QQuickComboBox::defaultFont()
const
2375 return QQuickTheme::font(QQuickTheme::ComboBox);
2378#if QT_CONFIG(accessibility)
2379QAccessible::Role QQuickComboBox::accessibleRole()
const
2381 return QAccessible::ComboBox;
2384void QQuickComboBox::accessibilityActiveChanged(
bool active)
2386 Q_D(QQuickComboBox);
2387 QQuickControl::accessibilityActiveChanged(active);
2390 maybeSetAccessibleName(d->hasDisplayText ? d->displayText : d->currentText);
2391 setAccessibleProperty(
"editable", isEditable());
2398#include "moc_qquickcombobox_p.cpp"
QQuickComboBoxDelegateModel(QQuickComboBox *combo)
QVariant variantValue(int index, const QString &role) override
void itemDestroyed(QQuickItem *item) override
bool handleRelease(const QPointF &point, ulong timestamp) override
CurrentElementCriteria currentElementCriteria
QQuickDeferredPointer< QQuickPopup > popup
qreal calculateWidestTextWidth() const
static void hideOldPopup(QQuickPopup *popup)
void setInputMethodHints(Qt::InputMethodHints hints, bool force=false)
void maybeUpdateImplicitContentWidth()
void setHighlightedIndex(int index, Highlighting highlight)
void createdItem(int index, QObject *object)
void updateHighlightedIndex()
QString effectiveTextRole() const
virtual qreal getContentWidth() const override
void keySearch(const QString &text)
void handleUngrab() override
bool hasCalculatedWidestText
void updateCurrentValue()
int match(int start, const QString &text, Qt::MatchFlags flags) const
bool isPopupVisible() const
void updateCurrentElements()
QPalette defaultPalette() const override
void createDelegateModel()
bool handleMove(const QPointF &point, ulong timestamp) override
QQmlInstanceModel * delegateModel
void itemImplicitHeightChanged(QQuickItem *item) override
void togglePopup(bool accept)
void executePopup(bool complete=false)
void itemImplicitWidthChanged(QQuickItem *item) override
void popupVisibleChanged()
void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList< int > &roles)
void executeIndicator(bool complete=false)
QQuickDeferredPointer< QQuickItem > indicator
void hidePopup(bool accept)
void updateCurrentIndex()
void setCurrentIndex(int index)
QLazilyAllocated< ExtraData > extra
std::optional< QPointer< QObject > > qobjectModelGuard
void updateAcceptableInput()
bool handlePress(const QPointF &point, ulong timestamp) override
void decrementCurrentIndex()
void setCurrentItemAtIndex(int, Activation activate)
bool isValidIndex(int index) const
QString tryComplete(const QString &inputText)
void incrementCurrentIndex()
static QString popupName()