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
111
114
115
116
117
118
119
120
121
122
123
124
125
128
129
130
131
132
133
134
135
136
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
177 QQuickComboBox *combo =
nullptr;
192 if (role == QLatin1String(
"modelData")) {
193 const QVariant model = combo->model();
194 if (model.metaType() == QMetaType::fromType<QVariantList>()) {
195 const QVariant object = model.toList().value(index);
196 if (object.metaType() == QMetaType::fromType<QVariantMap>()) {
197 const QVariantMap data = object.toMap();
198 if (data.size() == 1)
204 return QQmlDelegateModel::variantValue(index, role);
210 Q_DECLARE_PUBLIC(QQuickComboBox)
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
243
272 void onDataChanged(
const QModelIndex &topLeft,
const QModelIndex &bottomRight,
const QList<
int> &roles);
287 int match(
int start,
const QString &text, Qt::MatchFlags flags)
const;
292 bool handleMove(
const QPointF &point, ulong timestamp)
override;
351#if QT_CONFIG(validator)
360 return popup && popup->isVisible();
368 if (popup && !popup->isVisible())
379 emit q->activated(highlightedIndex);
381 if (popup && popup->isVisible())
387 if (!popup || !popup->isVisible())
396 if (isPopupVisible())
397 QGuiApplication::inputMethod()->reset();
399#if QT_CONFIG(quick_itemview)
400 QQuickItemView *itemView = popup->findChild<QQuickItemView *>();
402 itemView->setHighlightRangeMode(QQuickItemView::NoHighlightRange);
407#if QT_CONFIG(quick_itemview)
409 itemView->positionViewAtIndex(highlightedIndex, QQuickItemView::Beginning);
413 q->setDown(pressed || isPopupVisible());
422 emit q->popupChanged();
441 QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(q->sender());
442 if (!button || !button->isHovered() || !button->isEnabled() || QQuickAbstractButtonPrivate::get(button)->touchId != -1)
449#if QT_CONFIG(quick_itemview)
450 if (QQuickItemView *itemView = popup->findChild<QQuickItemView *>())
451 itemView->positionViewAtIndex(index, QQuickItemView::Contain);
459 QQuickItem *item = qobject_cast<QQuickItem *>(object);
460 if (item && !item->parentItem()) {
462 item->setParentItem(popup->contentItem());
464 item->setParentItem(q);
465 QQuickItemPrivate::get(item)->setCulled(
true);
468 QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(object);
470 button->setFocusPolicy(Qt::NoFocus);
475 if (index == currentIndex && !q->isEditable())
481 if (componentComplete && (!extra.isAllocated() || !extra->accepting)) {
484 if (implicitContentWidthPolicy == QQuickComboBox::WidestText)
485 updateImplicitContentSize();
492 if (q->count() == 0) {
493 if (currentElementCriteria == CurrentElementCriteria::CurrentValue)
498 emit q->countChanged();
503 return textRole.isEmpty() ? QStringLiteral(
"modelData") : textRole;
509 QQuickTextInput *input = qobject_cast<QQuickTextInput *>(contentItem);
513 const QString text = input->text();
515 if (extra.isAllocated() && extra->allowComplete && !text.isEmpty()) {
516 const QString completed = tryComplete(text);
517 if (completed.size() > text.size()) {
518 input->setText(completed);
520 input->select(completed.size(), text.size());
524 q->setEditText(text);
530 const int index = q->indexOfValue(currentValue);
535 emit q->currentIndexChanged();
541 const QString text = q->textAt(currentIndex);
542 if (currentText != text) {
545 q->maybeSetAccessibleName(text);
546 emit q->currentTextChanged();
548 if (!hasDisplayText && displayText != text) {
550 emit q->displayTextChanged();
552 if (!extra.isAllocated() || !extra->accepting)
553 q->setEditText(currentText);
559 const QVariant value = q->valueAt(currentIndex);
560 if (currentValue == value)
563 currentValue = value;
564 emit q->currentValueChanged();
569 switch (currentElementCriteria) {
570 case CurrentElementCriteria::None:
572 case CurrentElementCriteria::CurrentIndex:
576 case CurrentElementCriteria::CurrentValue:
590 const QQuickTextInput *textInputContentItem = qobject_cast<QQuickTextInput *>(contentItem);
592 if (!textInputContentItem)
595 const bool newValue = textInputContentItem->hasAcceptableInput();
599 emit q->acceptableInputChanged();
618 int idx = q->find(extra.value().editText, Qt::MatchFixedString);
623 QQuickTextInput *input = qobject_cast<QQuickTextInput *>(contentItem);
625 const auto text = input->text();
626 input->select(text.size(), text.size());
630 extra.value().accepting =
true;
636 idx = q->find(extra.value().editText, Qt::MatchFixedString);
639 extra.value().accepting =
false;
647 const int itemCount = q->count();
648 for (
int idx = 0; idx < itemCount; ++idx) {
649 const QString text = q->textAt(idx);
650 if (!text.startsWith(input, Qt::CaseInsensitive))
654 if (match.isEmpty() || text.size() < match.size())
661 return input + match.mid(input.size());
671 emit q->currentIndexChanged();
673 if (componentComplete)
684 emit q->currentIndexChanged();
690 emit q->activated(index);
696 if (extra.isAllocated())
697 extra->allowComplete =
false;
699 if (highlightedIndex < q->count() - 1)
702 if (currentIndex < q->count() - 1)
705 if (extra.isAllocated())
706 extra->allowComplete =
true;
711 if (extra.isAllocated())
712 extra->allowComplete =
false;
720 if (extra.isAllocated())
721 extra->allowComplete =
true;
736 emit q->highlightedIndexChanged();
739 emit q->highlighted(index);
745 const int index = match(startIndex + 1, text, Qt::MatchStartsWith | Qt::MatchWrap);
756 Q_Q(
const QQuickComboBox);
757 uint matchType = flags & 0x0F;
758 bool wrap = flags & Qt::MatchWrap;
759 Qt::CaseSensitivity cs = flags & Qt::MatchCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
760 QRegularExpression::PatternOptions options = flags & Qt::MatchCaseSensitive ? QRegularExpression::NoPatternOption
761 : QRegularExpression::CaseInsensitiveOption;
766 for (
int i = 0; (wrap && i < 2) || (!wrap && i < 1); ++i) {
767 for (
int idx = from; idx < to; ++idx) {
768 QString t = q->textAt(idx);
770 case Qt::MatchExactly:
774 case Qt::MatchRegularExpression: {
775 QRegularExpression rx(QRegularExpression::anchoredPattern(text), options);
776 if (rx.match(t).hasMatch())
780 case Qt::MatchWildcard: {
781 QRegularExpression rx(QRegularExpression::wildcardToRegularExpression(text),
783 if (rx.match(t).hasMatch())
787 case Qt::MatchStartsWith:
788 if (t.startsWith(text, cs))
791 case Qt::MatchEndsWith:
792 if (t.endsWith(text, cs))
795 case Qt::MatchFixedString:
796 if (t.compare(text, cs) == 0)
799 case Qt::MatchContains:
801 if (t.contains(text, cs))
825 delegateModel = model.value<QQmlInstanceModel *>();
827 if (!delegateModel && model.isValid()) {
828 QQmlDelegateModel *dataModel =
new QQuickComboBoxDelegateModel(q);
829 dataModel->setModel(model);
831 if (q->isComponentComplete())
832 dataModel->componentComplete();
844 emit q->delegateModelChanged();
853 QQuickControlPrivate::handlePress(point, timestamp);
861 QQuickControlPrivate::handleMove(point, timestamp);
862 q->setPressed(q->contains(point));
869 QQuickControlPrivate::handleRelease(point, timestamp);
871 q->setPressed(
false);
880 QQuickControlPrivate::handleUngrab();
881 q->setPressed(
false);
887 quickCancelDeferred(q, indicatorName());
893 if (indicator.wasExecuted())
896 if (!indicator || complete)
897 quickBeginDeferred(q, indicatorName(), indicator);
899 quickCompleteDeferred(q, indicatorName(), indicator);
902static inline QString
popupName() {
return QStringLiteral(
"popup"); }
907 quickCancelDeferred(q, popupName());
913 if (popup.wasExecuted())
916 if (!popup || complete)
917 quickBeginDeferred(q, popupName(), popup);
919 quickCompleteDeferred(q, popupName(), popup);
925 QQuickControlPrivate::itemImplicitWidthChanged(item);
926 if (item == indicator)
927 emit q->implicitIndicatorWidthChanged();
933 if (!force && hints == q->inputMethodHints())
936 extra.value().inputMethodHints = hints;
937 emit q->inputMethodHintsChanged();
943 QQuickControlPrivate::itemImplicitHeightChanged(item);
944 if (item == indicator)
945 emit q->implicitIndicatorHeightChanged();
951 QQuickControlPrivate::itemDestroyed(item);
952 if (item == indicator) {
954 emit q->indicatorChanged();
960 if (componentComplete) {
961 switch (implicitContentWidthPolicy) {
962 case QQuickComboBox::WidestText:
963 return calculateWidestTextWidth();
964 case QQuickComboBox::WidestTextWhenCompleted:
965 if (!hasCalculatedWidestText)
966 return calculateWidestTextWidth();
973 return QQuickControlPrivate::getContentWidth();
978 Q_Q(
const QQuickComboBox);
979 if (!componentComplete)
982 const int count = q->count();
986 auto textInput = qobject_cast<QQuickTextInput*>(contentItem);
990 qCDebug(lcCalculateWidestTextWidth) <<
"calculating widest text from" << count <<
"items...";
994 const QString textRole = effectiveTextRole();
995 auto textInputPrivate = QQuickTextInputPrivate::get(textInput);
997 for (
int i = 0; i < count; ++i) {
998 const QString text = delegateModel->stringValue(i, textRole);
999 const qreal textImplicitWidth = textInputPrivate->calculateImplicitWidthForText(text);
1000 widest = qMax(widest, textImplicitWidth);
1003 qCDebug(lcCalculateWidestTextWidth) <<
"... widest text is" << widest;
1008
1009
1010
1011
1012
1015 if (!componentComplete)
1018 if (implicitContentWidthPolicy == QQuickComboBox::ContentItemImplicitWidth
1019 || (implicitContentWidthPolicy == QQuickComboBox::WidestTextWhenCompleted && hasCalculatedWidestText))
1022 updateImplicitContentWidth();
1031 qCDebug(lcItemManagement) <<
"hiding old popup" << popup;
1033 popup->setVisible(
false);
1034 popup->setParentItem(
nullptr);
1035#if QT_CONFIG(accessibility)
1037 QQuickAccessibleAttached *accessible = accessibleAttached(popup);
1039 accessible->setIgnored(
true);
1043QQuickComboBox::QQuickComboBox(QQuickItem *parent)
1044 : QQuickControl(*(
new QQuickComboBoxPrivate), parent)
1046 setFocusPolicy(Qt::StrongFocus);
1047 setFlag(QQuickItem::ItemIsFocusScope);
1048 setAcceptedMouseButtons(Qt::LeftButton);
1049#if QT_CONFIG(cursor)
1050 setCursor(Qt::ArrowCursor);
1052 Q_D(QQuickComboBox);
1053 d->setInputMethodHints(Qt::ImhNoPredictiveText,
true);
1054 d->setSizePolicy(QLayoutPolicy::Preferred, QLayoutPolicy::Fixed);
1057QQuickComboBox::~QQuickComboBox()
1059 Q_D(QQuickComboBox);
1060 d->removeImplicitSizeListener(d->indicator);
1064 QObjectPrivate::disconnect(d->popup.data(), &QQuickPopup::visibleChanged, d, &QQuickComboBoxPrivate::popupVisibleChanged);
1065 QQuickComboBoxPrivate::hideOldPopup(d->popup);
1071
1072
1073
1074
1075
1076int QQuickComboBox::count()
const
1078 Q_D(
const QQuickComboBox);
1079 return d->delegateModel ? d->delegateModel->count() : 0;
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100QVariant QQuickComboBox::model()
const
1102 Q_D(
const QQuickComboBox);
1103 if (!d->qobjectModelGuard.has_value()) {
1109 return !d->qobjectModelGuard->isNull() ? d->model : QVariant();
1112void QQuickComboBox::setModel(
const QVariant& m)
1114 Q_D(QQuickComboBox);
1115 QVariant newModel = m;
1116 if (newModel.userType() == qMetaTypeId<QJSValue>())
1117 newModel = newModel.value<QJSValue>().toVariant();
1119 if (d->model == newModel)
1122 if (d->qobjectModelGuard.has_value() && !d->qobjectModelGuard->isNull()) {
1123 if (QAbstractItemModel* aim = qvariant_cast<QAbstractItemModel *>(d->model)) {
1124 QObjectPrivate::disconnect(aim, &QAbstractItemModel::dataChanged,
1125 d, &QQuickComboBoxPrivate::onDataChanged);
1128 if (QObject* newModelAsQObject = qvariant_cast<QObject *>(newModel)) {
1132 d->qobjectModelGuard = QPointer<QObject>(newModelAsQObject);
1134 if (QAbstractItemModel* aim = qvariant_cast<QAbstractItemModel *>(newModel)) {
1135 QObjectPrivate::connect(aim, &QAbstractItemModel::dataChanged,
1136 d, &QQuickComboBoxPrivate::onDataChanged);
1140 d->qobjectModelGuard.reset();
1143 d->model = newModel;
1144 d->createDelegateModel();
1145 emit countChanged();
1146 if (isComponentComplete()) {
1147 if (d->currentElementCriteria != QQuickComboBoxPrivate::CurrentElementCriteria::CurrentValue)
1148 d->setCurrentIndex(count() > 0 ? 0 : -1);
1149 d->updateCurrentElements();
1151 emit modelChanged();
1153 d->maybeUpdateImplicitContentWidth();
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167QQmlInstanceModel *QQuickComboBox::delegateModel()
const
1169 Q_D(
const QQuickComboBox);
1170 return d->delegateModel;
1175
1176
1177
1178
1179
1180
1181
1182
1183bool QQuickComboBox::isPressed()
const
1185 Q_D(
const QQuickComboBox);
1189void QQuickComboBox::setPressed(
bool pressed)
1191 Q_D(QQuickComboBox);
1192 if (d->pressed == pressed)
1195 d->pressed = pressed;
1196 emit pressedChanged();
1199 setDown(d->pressed || d->isPopupVisible());
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216int QQuickComboBox::highlightedIndex()
const
1218 Q_D(
const QQuickComboBox);
1219 return d->highlightedIndex;
1223
1224
1225
1226
1227
1228
1229
1230
1231int QQuickComboBox::currentIndex()
const
1233 Q_D(
const QQuickComboBox);
1234 return d->currentIndex;
1237void QQuickComboBox::setCurrentIndex(
int index)
1239 Q_D(QQuickComboBox);
1240 d->currentElementCriteria = QQuickComboBoxPrivate::CurrentElementCriteria::CurrentIndex;
1241 d->setCurrentIndex(index);
1245
1246
1247
1248
1249
1250
1251
1252QString QQuickComboBox::currentText()
const
1254 Q_D(
const QQuickComboBox);
1255 return d->currentText;
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277QString QQuickComboBox::displayText()
const
1279 Q_D(
const QQuickComboBox);
1280 return d->displayText;
1283void QQuickComboBox::setDisplayText(
const QString &text)
1285 Q_D(QQuickComboBox);
1286 d->hasDisplayText =
true;
1287 if (d->displayText == text)
1290 d->displayText = text;
1291 maybeSetAccessibleName(text);
1292 emit displayTextChanged();
1295void QQuickComboBox::resetDisplayText()
1297 Q_D(QQuickComboBox);
1298 if (!d->hasDisplayText)
1301 d->hasDisplayText =
false;
1302 d->updateCurrentText();
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316QString QQuickComboBox::textRole()
const
1318 Q_D(
const QQuickComboBox);
1322void QQuickComboBox::setTextRole(
const QString &role)
1324 Q_D(QQuickComboBox);
1325 if (d->textRole == role)
1329 if (isComponentComplete())
1330 d->updateCurrentText();
1331 emit textRoleChanged();
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345QString QQuickComboBox::valueRole()
const
1347 Q_D(
const QQuickComboBox);
1348 return d->valueRole;
1351void QQuickComboBox::setValueRole(
const QString &role)
1353 Q_D(QQuickComboBox);
1354 if (d->valueRole == role)
1357 d->valueRole = role;
1358 if (isComponentComplete())
1359 d->updateCurrentElements();
1360 emit valueRoleChanged();
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388QQmlComponent *QQuickComboBox::delegate()
const
1390 Q_D(
const QQuickComboBox);
1394void QQuickComboBox::setDelegate(QQmlComponent* delegate)
1396 Q_D(QQuickComboBox);
1397 if (d->delegate == delegate)
1400 d->delegate = delegate;
1401 QQmlDelegateModel *delegateModel = qobject_cast<QQmlDelegateModel*>(d->delegateModel);
1403 delegateModel->setDelegate(d->delegate);
1404 emit delegateChanged();
1408
1409
1410
1411
1412
1413
1414QQuickItem *QQuickComboBox::indicator()
const
1416 QQuickComboBoxPrivate *d =
const_cast<QQuickComboBoxPrivate *>(d_func());
1418 d->executeIndicator();
1419 return d->indicator;
1422void QQuickComboBox::setIndicator(QQuickItem *indicator)
1424 Q_D(QQuickComboBox);
1425 if (d->indicator == indicator)
1428 QQuickControlPrivate::warnIfCustomizationNotSupported(
this, indicator, QStringLiteral(
"indicator"));
1430 if (!d->indicator.isExecuting())
1431 d->cancelIndicator();
1433 const qreal oldImplicitIndicatorWidth = implicitIndicatorWidth();
1434 const qreal oldImplicitIndicatorHeight = implicitIndicatorHeight();
1436 d->removeImplicitSizeListener(d->indicator);
1437 QQuickControlPrivate::hideOldItem(d->indicator);
1438 d->indicator = indicator;
1440 if (!indicator->parentItem())
1441 indicator->setParentItem(
this);
1442 d->addImplicitSizeListener(indicator);
1445 if (!qFuzzyCompare(oldImplicitIndicatorWidth, implicitIndicatorWidth()))
1446 emit implicitIndicatorWidthChanged();
1447 if (!qFuzzyCompare(oldImplicitIndicatorHeight, implicitIndicatorHeight()))
1448 emit implicitIndicatorHeightChanged();
1449 if (!d->indicator.isExecuting())
1450 emit indicatorChanged();
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466QQuickPopup *QQuickComboBox::popup()
const
1468 QQuickComboBoxPrivate *d =
const_cast<QQuickComboBoxPrivate *>(d_func());
1470 d->executePopup(isComponentComplete());
1474void QQuickComboBox::setPopup(QQuickPopup *popup)
1476 Q_D(QQuickComboBox);
1477 if (d->popup == popup)
1480 if (!d->popup.isExecuting())
1484 QObjectPrivate::disconnect(d->popup.data(), &QQuickPopup::destroyed, d, &QQuickComboBoxPrivate::popupDestroyed);
1485 QObjectPrivate::disconnect(d->popup.data(), &QQuickPopup::visibleChanged, d, &QQuickComboBoxPrivate::popupVisibleChanged);
1486 QQuickComboBoxPrivate::hideOldPopup(d->popup);
1489 QQuickPopupPrivate::get(popup)->allowVerticalFlip =
true;
1490 popup->setClosePolicy(QQuickPopup::CloseOnEscape | QQuickPopup::CloseOnPressOutsideParent);
1491 QObjectPrivate::connect(popup, &QQuickPopup::visibleChanged, d, &QQuickComboBoxPrivate::popupVisibleChanged);
1494 QObjectPrivate::connect(popup, &QQuickPopup::destroyed, d, &QQuickComboBoxPrivate::popupDestroyed);
1496#if QT_CONFIG(quick_itemview)
1497 if (QQuickItemView *itemView = popup->findChild<QQuickItemView *>())
1498 itemView->setHighlightRangeMode(QQuickItemView::NoHighlightRange);
1502 if (!d->popup.isExecuting())
1503 emit popupChanged();
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520bool QQuickComboBox::isFlat()
const
1522 Q_D(
const QQuickComboBox);
1526void QQuickComboBox::setFlat(
bool flat)
1528 Q_D(QQuickComboBox);
1529 if (d->flat == flat)
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548bool QQuickComboBox::isDown()
const
1550 Q_D(
const QQuickComboBox);
1554void QQuickComboBox::setDown(
bool down)
1556 Q_D(QQuickComboBox);
1559 if (d->down == down)
1566void QQuickComboBox::resetDown()
1568 Q_D(QQuickComboBox);
1572 setDown(d->pressed || d->isPopupVisible());
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586bool QQuickComboBox::isEditable()
const
1588 Q_D(
const QQuickComboBox);
1589 return d->extra.isAllocated() && d->extra->editable;
1592void QQuickComboBox::setEditable(
bool editable)
1594 Q_D(QQuickComboBox);
1595 if (editable == isEditable())
1598 if (d->contentItem) {
1600 d->contentItem->installEventFilter(
this);
1601 if (QQuickTextInput *input = qobject_cast<QQuickTextInput *>(d->contentItem)) {
1602 QObjectPrivate::connect(input, &QQuickTextInput::textChanged, d, &QQuickComboBoxPrivate::updateEditText);
1603 QObjectPrivate::connect(input, &QQuickTextInput::accepted, d, &QQuickComboBoxPrivate::acceptInput);
1605#if QT_CONFIG(cursor)
1606 d->contentItem->setCursor(Qt::IBeamCursor);
1609 d->contentItem->removeEventFilter(
this);
1610 if (QQuickTextInput *input = qobject_cast<QQuickTextInput *>(d->contentItem)) {
1611 QObjectPrivate::disconnect(input, &QQuickTextInput::textChanged, d, &QQuickComboBoxPrivate::updateEditText);
1612 QObjectPrivate::disconnect(input, &QQuickTextInput::accepted, d, &QQuickComboBoxPrivate::acceptInput);
1614#if QT_CONFIG(cursor)
1615 d->contentItem->unsetCursor();
1620 d->extra.value().editable = editable;
1621 setAccessibleProperty(
"editable", editable);
1622 emit editableChanged();
1626
1627
1628
1629
1630
1631
1632
1633QString QQuickComboBox::editText()
const
1635 Q_D(
const QQuickComboBox);
1636 return d->extra.isAllocated() ? d->extra->editText : QString();
1639void QQuickComboBox::setEditText(
const QString &text)
1641 Q_D(QQuickComboBox);
1642 if (text == editText())
1645 d->extra.value().editText = text;
1646 emit editTextChanged();
1649void QQuickComboBox::resetEditText()
1651 setEditText(QString());
1654#if QT_CONFIG(validator)
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
1683
1684QValidator *QQuickComboBox::validator()
const
1686 Q_D(
const QQuickComboBox);
1687 return d->extra.isAllocated() ? d->extra->validator :
nullptr;
1690void QQuickComboBox::setValidator(QValidator *validator)
1692 Q_D(QQuickComboBox);
1693 if (validator == QQuickComboBox::validator())
1696 d->extra.value().validator = validator;
1697#if QT_CONFIG(validator)
1699 validator->setLocale(d->locale);
1701 emit validatorChanged();
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716Qt::InputMethodHints QQuickComboBox::inputMethodHints()
const
1718 Q_D(
const QQuickComboBox);
1719 return d->extra.isAllocated() ? d->extra->inputMethodHints : Qt::ImhNoPredictiveText;
1722void QQuickComboBox::setInputMethodHints(Qt::InputMethodHints hints)
1724 Q_D(QQuickComboBox);
1725 d->setInputMethodHints(hints);
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739bool QQuickComboBox::isInputMethodComposing()
const
1741 Q_D(
const QQuickComboBox);
1742 return d->contentItem && d->contentItem->property(
"inputMethodComposing").toBool();
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757bool QQuickComboBox::hasAcceptableInput()
const
1759 Q_D(
const QQuickComboBox);
1760 return d->m_acceptableInput;
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777qreal QQuickComboBox::implicitIndicatorWidth()
const
1779 Q_D(
const QQuickComboBox);
1782 return d->indicator->implicitWidth();
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799qreal QQuickComboBox::implicitIndicatorHeight()
const
1801 Q_D(
const QQuickComboBox);
1804 return d->indicator->implicitHeight();
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822QVariant QQuickComboBox::currentValue()
const
1824 Q_D(
const QQuickComboBox);
1825 return d->currentValue;
1828void QQuickComboBox::setCurrentValue(
const QVariant &value)
1830 Q_D(QQuickComboBox);
1831 d->currentElementCriteria = QQuickComboBoxPrivate::CurrentElementCriteria::CurrentValue;
1832 if (value == d->currentValue)
1835 d->currentValue = value;
1836 emit currentValueChanged();
1838 if (d->componentComplete)
1839 d->updateCurrentElements();
1843
1844
1845
1846
1847
1848
1849
1850
1851QVariant QQuickComboBox::valueAt(
int index)
const
1853 Q_D(
const QQuickComboBox);
1854 if (!d->isValidIndex(index))
1857 const QString effectiveValueRole = d->valueRole.isEmpty() ? QStringLiteral(
"modelData") : d->valueRole;
1858 return d->delegateModel->variantValue(index, effectiveValueRole);
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873int QQuickComboBox::indexOfValue(
const QVariant &value)
const
1875 for (
int i = 0; i < count(); ++i) {
1876 const QVariant ourValue = valueAt(i);
1877 if (value == ourValue)
1884
1885
1886
1887
1888
1889
1890
1891
1892bool QQuickComboBox::selectTextByMouse()
const
1894 Q_D(
const QQuickComboBox);
1895 return d->extra.isAllocated() ? d->extra->selectTextByMouse :
false;
1898void QQuickComboBox::setSelectTextByMouse(
bool canSelect)
1900 Q_D(QQuickComboBox);
1901 if (canSelect == selectTextByMouse())
1904 d->extra.value().selectTextByMouse = canSelect;
1905 emit selectTextByMouseChanged();
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
1961
1962QQuickComboBox::ImplicitContentWidthPolicy QQuickComboBox::implicitContentWidthPolicy()
const
1964 Q_D(
const QQuickComboBox);
1965 return d->implicitContentWidthPolicy;
1968void QQuickComboBox::setImplicitContentWidthPolicy(QQuickComboBox::ImplicitContentWidthPolicy policy)
1970 Q_D(QQuickComboBox);
1971 if (policy == d->implicitContentWidthPolicy)
1974 d->implicitContentWidthPolicy = policy;
1975 d->maybeUpdateImplicitContentWidth();
1976 emit implicitContentWidthPolicyChanged();
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990QString QQuickComboBox::textAt(
int index)
const
1992 Q_D(
const QQuickComboBox);
1993 if (!d->isValidIndex(index))
1996 return d->delegateModel->stringValue(index, d->effectiveTextRole());
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023int QQuickComboBox::find(
const QString &text, Qt::MatchFlags flags)
const
2025 Q_D(
const QQuickComboBox);
2026 return d->match(0, text, flags);
2030
2031
2032
2033
2034
2035
2036
2037void QQuickComboBox::incrementCurrentIndex()
2039 Q_D(QQuickComboBox);
2040 d->incrementCurrentIndex();
2044
2045
2046
2047
2048
2049
2050
2051void QQuickComboBox::decrementCurrentIndex()
2053 Q_D(QQuickComboBox);
2054 d->decrementCurrentIndex();
2058
2059
2060
2061
2062
2063
2064
2065void QQuickComboBox::selectAll()
2067 Q_D(QQuickComboBox);
2068 QQuickTextInput *input = qobject_cast<QQuickTextInput *>(d->contentItem);
2074bool QQuickComboBox::eventFilter(QObject *object, QEvent *event)
2076 Q_D(QQuickComboBox);
2077 switch (event->type()) {
2078 case QEvent::MouseButtonRelease:
2079 if (d->isPopupVisible())
2080 d->hidePopup(
false);
2082 case QEvent::KeyPress: {
2083 QKeyEvent *ke =
static_cast<QKeyEvent *>(event);
2084 if (d->filterKeyEvent(ke,
false))
2087 if (d->extra.isAllocated())
2088 d->extra->allowComplete = ke->key() != Qt::Key_Backspace && ke->key() != Qt::Key_Delete;
2091 case QEvent::FocusOut: {
2092 const bool hasActiveFocus = d->popup && d->popup->hasActiveFocus();
2093 const bool usingPopupWindows =
2094 d->popup ? QQuickPopupPrivate::get(d->popup)->usePopupWindow() :
false;
2095 if (qGuiApp->focusObject() !=
this && !(hasActiveFocus && !usingPopupWindows)) {
2099 d->hidePopup(
false);
2104 const int indexForEditText = find(d->extra.value().editText, Qt::MatchFixedString);
2105 if (indexForEditText > -1)
2106 d->setCurrentItemAtIndex(indexForEditText, Activate);
2111 case QEvent::InputMethod:
2112 if (d->extra.isAllocated())
2113 d->extra->allowComplete = !
static_cast<QInputMethodEvent*>(event)->commitString().isEmpty();
2119 return QQuickControl::eventFilter(object, event);
2122void QQuickComboBox::focusInEvent(QFocusEvent *event)
2124 Q_D(QQuickComboBox);
2125 QQuickControl::focusInEvent(event);
2129 if ((event->reason() == Qt::TabFocusReason || event->reason() == Qt::BacktabFocusReason ||
2130 event->reason() == Qt::ShortcutFocusReason) && d->contentItem && isEditable())
2131 d->contentItem->forceActiveFocus(event->reason());
2134void QQuickComboBox::focusOutEvent(QFocusEvent *event)
2136 Q_D(QQuickComboBox);
2137 QQuickControl::focusOutEvent(event);
2139 const bool hasActiveFocus = d->popup && d->popup->hasActiveFocus();
2140 const bool usingPopupWindows = d->popup && QQuickPopupPrivate::get(d->popup)->usePopupWindow();
2141 if (qGuiApp->focusObject() != d->contentItem && !(hasActiveFocus && !usingPopupWindows)) {
2145 d->hidePopup(
false);
2151void QQuickComboBox::inputMethodEvent(QInputMethodEvent *event)
2153 Q_D(QQuickComboBox);
2154 QQuickControl::inputMethodEvent(event);
2155 if (!isEditable() && !event->commitString().isEmpty())
2156 d->keySearch(event->commitString());
2162void QQuickComboBox::keyPressEvent(QKeyEvent *event)
2164 Q_D(QQuickComboBox);
2165 QQuickControl::keyPressEvent(event);
2167 const auto key = event->key();
2168 if (!isEditable()) {
2169 const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::ButtonPressKeys).value<QList<Qt::Key>>();
2170 if (buttonPressKeys.contains(key)) {
2171 if (!event->isAutoRepeat())
2179 case Qt::Key_Escape:
2181 d->acceptedEscKeyPress = d->isPopupVisible();
2182 d->receivedEscKeyPress =
true;
2183 if (d->acceptedEscKeyPress) {
2184 d->hidePopup(
false);
2190 case Qt::Key_Return:
2191 if (d->isPopupVisible())
2196 d->keyNavigating =
true;
2197 d->decrementCurrentIndex();
2201 d->keyNavigating =
true;
2202 d->incrementCurrentIndex();
2206 d->keyNavigating =
true;
2207 if (d->isPopupVisible())
2208 d->setHighlightedIndex(0, Highlight);
2210 d->setCurrentItemAtIndex(0, Activate);
2214 d->keyNavigating =
true;
2215 if (d->isPopupVisible())
2216 d->setHighlightedIndex(count() - 1, Highlight);
2218 d->setCurrentItemAtIndex(count() - 1, Activate);
2222 if (!isEditable() && !event->text().isEmpty())
2223 d->keySearch(event->text());
2230void QQuickComboBox::keyReleaseEvent(QKeyEvent *event)
2232 Q_D(QQuickComboBox);
2233 QQuickControl::keyReleaseEvent(event);
2234 d->keyNavigating =
false;
2235 if (event->isAutoRepeat())
2238 const auto key = event->key();
2239 if (!isEditable()) {
2240 const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::ButtonPressKeys).value<QList<Qt::Key>>();
2241 if (buttonPressKeys.contains(key)) {
2242 if (!isEditable() && isPressed())
2243 d->togglePopup(
true);
2252 case Qt::Key_Return:
2253 if (!isEditable() || d->isPopupVisible())
2254 d->hidePopup(d->isPopupVisible());
2258 case Qt::Key_Escape:
2264 if (d->acceptedEscKeyPress || !d->receivedEscKeyPress)
2266 d->acceptedEscKeyPress =
false;
2267 d->receivedEscKeyPress =
false;
2274#if QT_CONFIG(wheelevent)
2275void QQuickComboBox::wheelEvent(QWheelEvent *event)
2277 Q_D(QQuickComboBox);
2278 QQuickControl::wheelEvent(event);
2279 if (d->wheelEnabled && !d->isPopupVisible()) {
2280 if (event->angleDelta().y() > 0)
2281 d->decrementCurrentIndex();
2283 d->incrementCurrentIndex();
2288bool QQuickComboBox::event(QEvent *e)
2290 Q_D(QQuickComboBox);
2291 if (e->type() == QEvent::LanguageChange)
2292 d->updateCurrentElements();
2293 return QQuickControl::event(e);
2296void QQuickComboBox::componentComplete()
2298 Q_D(QQuickComboBox);
2299 d->executeIndicator(
true);
2300 QQuickControl::componentComplete();
2302 d->executePopup(
true);
2304 if (d->delegateModel && d->ownModel)
2305 static_cast<QQmlDelegateModel *>(d->delegateModel)->componentComplete();
2308 if (d->currentElementCriteria == QQuickComboBoxPrivate::CurrentElementCriteria::None && d->currentIndex == -1)
2309 d->setCurrentIndex(0);
2311 d->updateCurrentElements();
2315 if (!d->hasCalculatedWidestText)
2316 d->maybeUpdateImplicitContentWidth();
2320void QQuickComboBox::itemChange(QQuickItem::ItemChange change,
const QQuickItem::ItemChangeData &value)
2322 Q_D(QQuickComboBox);
2323 QQuickControl::itemChange(change, value);
2324 if (change == ItemVisibleHasChanged && !value.boolValue) {
2325 d->hidePopup(
false);
2330void QQuickComboBox::fontChange(
const QFont &newFont,
const QFont &oldFont)
2332 Q_D(QQuickComboBox);
2333 QQuickControl::fontChange(newFont, oldFont);
2334 d->maybeUpdateImplicitContentWidth();
2337void QQuickComboBox::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
2339 Q_D(QQuickComboBox);
2341 oldItem->removeEventFilter(
this);
2342 if (QQuickTextInput *oldInput = qobject_cast<QQuickTextInput *>(oldItem)) {
2343 QObjectPrivate::disconnect(oldInput, &QQuickTextInput::accepted, d, &QQuickComboBoxPrivate::acceptInput);
2344 QObjectPrivate::disconnect(oldInput, &QQuickTextInput::textChanged, d, &QQuickComboBoxPrivate::updateEditText);
2345 disconnect(oldInput, &QQuickTextInput::inputMethodComposingChanged,
this, &QQuickComboBox::inputMethodComposingChanged);
2346 QObjectPrivate::disconnect(oldInput, &QQuickTextInput::acceptableInputChanged, d, &QQuickComboBoxPrivate::updateAcceptableInput);
2349 if (newItem && isEditable()) {
2350 newItem->installEventFilter(
this);
2351 if (QQuickTextInput *newInput = qobject_cast<QQuickTextInput *>(newItem)) {
2352 QObjectPrivate::connect(newInput, &QQuickTextInput::accepted, d, &QQuickComboBoxPrivate::acceptInput);
2353 QObjectPrivate::connect(newInput, &QQuickTextInput::textChanged, d, &QQuickComboBoxPrivate::updateEditText);
2354 connect(newInput, &QQuickTextInput::inputMethodComposingChanged,
this, &QQuickComboBox::inputMethodComposingChanged);
2355 QObjectPrivate::connect(newInput, &QQuickTextInput::acceptableInputChanged, d, &QQuickComboBoxPrivate::updateAcceptableInput);
2357#if QT_CONFIG(cursor)
2358 newItem->setCursor(Qt::IBeamCursor);
2362 d->updateAcceptableInput();
2365void QQuickComboBox::localeChange(
const QLocale &newLocale,
const QLocale &oldLocale)
2367 QQuickControl::localeChange(newLocale, oldLocale);
2368#if QT_CONFIG(validator)
2369 if (QValidator *v = validator())
2370 v->setLocale(newLocale);
2374QFont QQuickComboBox::defaultFont()
const
2376 return QQuickTheme::font(QQuickTheme::ComboBox);
2379#if QT_CONFIG(accessibility)
2380QAccessible::Role QQuickComboBox::accessibleRole()
const
2382 return QAccessible::ComboBox;
2385void QQuickComboBox::accessibilityActiveChanged(
bool active)
2387 Q_D(QQuickComboBox);
2388 QQuickControl::accessibilityActiveChanged(active);
2391 maybeSetAccessibleName(d->hasDisplayText ? d->displayText : d->currentText);
2392 setAccessibleProperty(
"editable", isEditable());
2399#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()
Combined button and popup list for selecting options.
static QString popupName()