7#include <qstylepainter.h>
8#include <qpa/qplatformtheme.h>
9#include <qpa/qplatformmenu.h>
10#include <qpa/qplatformwindow.h>
11#include <qpa/qplatformwindow_p.h>
14#include <qapplication.h>
16#if QT_CONFIG(tableview)
17#include <qtableview.h>
19#include <qabstractitemdelegate.h>
26#include <qscrollbar.h>
27#if QT_CONFIG(treeview)
30#include <qheaderview.h>
32#include <qmetaobject.h>
33#if QT_CONFIG(proxymodel)
34#include <qabstractproxymodel.h>
36#include <qstylehints.h>
37#include <private/qguiapplication_p.h>
38#include <private/qhighdpiscaling_p.h>
39#include <private/qapplication_p.h>
40#include <private/qcombobox_p.h>
41#include <private/qabstractitemmodel_p.h>
42#include <private/qabstractscrollarea_p.h>
43#include <private/qlineedit_p.h>
44#if QT_CONFIG(completer)
45#include <private/qcompleter_p.h>
49# include <private/qeffects_p.h>
51#include <private/qstyle_p.h>
52#if QT_CONFIG(accessibility)
53#include "qaccessible.h"
57#include <QtCore/qpointer.h>
61using namespace Qt::StringLiterals;
63QComboBoxPrivate::QComboBoxPrivate()
66 duplicatesEnabled(
false),
73QComboBoxPrivate::~QComboBoxPrivate()
81QStyleOptionMenuItem QComboMenuDelegate::getStyleOption(
const QStyleOptionViewItem &option,
82 const QModelIndex &index)
const
84 QStyleOptionMenuItem menuOption;
86 QPalette resolvedpalette = option.palette.resolve(QApplication::palette(
"QMenu"));
87 QVariant value = index.data(Qt::ForegroundRole);
88 if (value.canConvert<QBrush>()) {
89 resolvedpalette.setBrush(QPalette::WindowText, qvariant_cast<QBrush>(value));
90 resolvedpalette.setBrush(QPalette::ButtonText, qvariant_cast<QBrush>(value));
91 resolvedpalette.setBrush(QPalette::Text, qvariant_cast<QBrush>(value));
93 menuOption.palette = resolvedpalette;
94 menuOption.state = QStyle::State_None;
95 if (mCombo->window()->isActiveWindow())
96 menuOption.state = QStyle::State_Active;
97 if ((option.state & QStyle::State_Enabled) && (index.model()->flags(index) & Qt::ItemIsEnabled))
98 menuOption.state |= QStyle::State_Enabled;
100 menuOption.palette.setCurrentColorGroup(QPalette::Disabled);
101 if (option.state & QStyle::State_Selected)
102 menuOption.state |= QStyle::State_Selected;
103 menuOption.checkType = QStyleOptionMenuItem::NonExclusive;
105 const QVariant checkState = index.data(Qt::CheckStateRole);
106 if (!checkState.isValid()) {
107 menuOption.checked = mCombo->currentIndex() == index.row();
109 menuOption.checked = qvariant_cast<
int>(checkState) == Qt::Checked;
110 menuOption.state |= qvariant_cast<
int>(checkState) == Qt::Checked
111 ? QStyle::State_On : QStyle::State_Off;
113 if (QComboBoxDelegate::isSeparator(index))
114 menuOption.menuItemType = QStyleOptionMenuItem::Separator;
116 menuOption.menuItemType = QStyleOptionMenuItem::Normal;
118 const QVariant variant = index.data(Qt::DecorationRole);
119 switch (variant.userType()) {
120 case QMetaType::QIcon:
121 menuOption.icon = qvariant_cast<QIcon>(variant);
123 case QMetaType::QColor: {
124 static QPixmap pixmap(option.decorationSize);
125 pixmap.fill(qvariant_cast<QColor>(variant));
126 menuOption.icon = pixmap;
129 menuOption.icon = qvariant_cast<QPixmap>(variant);
132 if (index.data(Qt::BackgroundRole).canConvert<QBrush>()) {
133 menuOption.palette.setBrush(QPalette::All, QPalette::Window,
134 qvariant_cast<QBrush>(index.data(Qt::BackgroundRole)));
136 menuOption.text = index.data(Qt::DisplayRole).toString().replace(u'&',
"&&"_L1);
137 menuOption.reservedShortcutWidth = 0;
138 menuOption.maxIconWidth = option.decorationSize.width() + 4;
139 menuOption.menuRect = option.rect;
140 menuOption.rect = option.rect;
144 QVariant fontRoleData = index.data(Qt::FontRole);
145 if (fontRoleData.isValid()) {
146 menuOption.font = qvariant_cast<QFont>(fontRoleData);
147 }
else if (mCombo->testAttribute(Qt::WA_SetFont)
148 || mCombo->testAttribute(Qt::WA_MacSmallSize)
149 || mCombo->testAttribute(Qt::WA_MacMiniSize)
150 || mCombo->font() != qt_app_fonts_hash()->value(
"QComboBox", QFont())) {
151 menuOption.font = mCombo->font();
153 menuOption.font = qt_app_fonts_hash()->value(
"QComboMenuItem", mCombo->font());
156 menuOption.fontMetrics = QFontMetrics(menuOption.font);
161bool QComboMenuDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
162 const QStyleOptionViewItem &option,
const QModelIndex &index)
168 Qt::ItemFlags flags = model->flags(index);
169 if (!(flags & Qt::ItemIsUserCheckable) || !(option.state & QStyle::State_Enabled)
170 || !(flags & Qt::ItemIsEnabled))
174 const QVariant checkState = index.data(Qt::CheckStateRole);
175 if (!checkState.isValid())
179 if ((event->type() == QEvent::MouseButtonRelease)
180 || (event->type() == QEvent::MouseButtonDblClick)
181 || (event->type() == QEvent::MouseButtonPress)) {
182 QMouseEvent *me =
static_cast<QMouseEvent*>(event);
183 if (me->button() != Qt::LeftButton)
186 if ((event->type() == QEvent::MouseButtonPress)
187 || (event->type() == QEvent::MouseButtonDblClick)) {
188 pressedIndex = index.row();
192 if (index.row() != pressedIndex)
196 }
else if (event->type() == QEvent::KeyPress) {
197 if (
static_cast<QKeyEvent*>(event)->key() != Qt::Key_Space
198 &&
static_cast<QKeyEvent*>(event)->key() != Qt::Key_Select)
205 Qt::CheckState newState = (
static_cast<Qt::CheckState>(checkState.toInt()) == Qt::Checked)
206 ? Qt::Unchecked : Qt::Checked;
207 return model->setData(index, newState, Qt::CheckStateRole);
210#if QT_CONFIG(completer)
211void QComboBoxPrivate::completerActivated(
const QModelIndex &index)
214#if QT_CONFIG(proxymodel)
215 if (index.isValid() && q->completer()) {
216 QAbstractProxyModel *proxy = qobject_cast<QAbstractProxyModel *>(q->completer()->completionModel());
218 const QModelIndex &completerIndex = proxy->mapToSource(index);
220 if (completerIndex.model() == model) {
221 row = completerIndex.row();
224 QAbstractProxyModel *completerProxy = qobject_cast<QAbstractProxyModel *>(q->completer()->model());
225 if (completerProxy && completerProxy->sourceModel() == model) {
226 row = completerProxy->mapToSource(completerIndex).row();
228 QString match = q->completer()->model()->data(completerIndex).toString();
229 row = q->findText(match, matchFlags());
232 q->setCurrentIndex(row);
233 emitActivated(currentIndex);
240void QComboBoxPrivate::updateArrow(QStyle::StateFlag state)
243 if (arrowState == state)
246 QStyleOptionComboBox opt;
247 q->initStyleOption(&opt);
248 q->update(q->rect());
251void QComboBoxPrivate::modelReset()
255 lineEdit->setText(QString());
256 updateLineEditGeometry();
263void QComboBoxPrivate::modelDestroyed()
265 model = QAbstractItemModelPrivate::staticEmptyModel();
268void QComboBoxPrivate::trySetValidIndex()
271 bool currentReset =
false;
273 const int rowCount = q->count();
274 for (
int pos = 0; pos < rowCount; ++pos) {
275 const QModelIndex idx(model->index(pos, modelColumn, root));
276 if (idx.flags() & Qt::ItemIsEnabled) {
277 setCurrentIndex(idx);
284 setCurrentIndex(QModelIndex());
287QRect QComboBoxPrivate::popupGeometry(
const QPoint &globalPosition)
const
289 Q_Q(
const QComboBox);
290 return QStylePrivate::useFullScreenForPopup()
291 ? QWidgetPrivate::screenGeometry(q, globalPosition)
292 : QWidgetPrivate::availableScreenGeometry(q, globalPosition);
295bool QComboBoxPrivate::updateHoverControl(
const QPoint &pos)
299 QRect lastHoverRect = hoverRect;
300 QStyle::SubControl lastHoverControl = hoverControl;
301 bool doesHover = q->testAttribute(Qt::WA_Hover);
302 if (lastHoverControl != newHoverControl(pos) && doesHover) {
303 q->update(lastHoverRect);
304 q->update(hoverRect);
310QStyle::SubControl QComboBoxPrivate::newHoverControl(
const QPoint &pos)
313 QStyleOptionComboBox opt;
314 q->initStyleOption(&opt);
315 opt.subControls = QStyle::SC_All;
316 hoverControl = q->style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt, pos, q);
317 hoverRect = (hoverControl != QStyle::SC_None)
318 ? q->style()->subControlRect(QStyle::CC_ComboBox, &opt, hoverControl, q)
324
325
326
327int QComboBoxPrivate::computeWidthHint()
const
329 Q_Q(
const QComboBox);
332 const int count = q->count();
333 const int iconWidth = q->iconSize().width() + 4;
334 const QFontMetrics &fontMetrics = q->fontMetrics();
336 for (
int i = 0; i < count; ++i) {
337 const int textWidth = fontMetrics.horizontalAdvance(q->itemText(i));
338 if (q->itemIcon(i).isNull())
339 width = (qMax(width, textWidth));
341 width = (qMax(width, textWidth + iconWidth));
344 QStyleOptionComboBox opt;
345 q->initStyleOption(&opt);
347 tmp = q->style()->sizeFromContents(QStyle::CT_ComboBox, &opt, tmp, q);
351QSize QComboBoxPrivate::recomputeSizeHint(QSize &sh)
const
353 Q_Q(
const QComboBox);
355 if (q->itemDelegate() && q->labelDrawingMode() == QComboBox::LabelDrawingMode::UseDelegate) {
356 QStyleOptionViewItem option;
357 initViewItemOption(&option);
358 sh = q->itemDelegate()->sizeHint(option, currentIndex);
361 bool hasIcon = sizeAdjustPolicy == QComboBox::AdjustToMinimumContentsLengthWithIcon;
362 int count = q->count();
363 QSize iconSize = q->iconSize();
364 const QFontMetrics &fm = q->fontMetrics();
367 if (&sh == &sizeHint || minimumContentsLength == 0) {
368 switch (sizeAdjustPolicy) {
369 case QComboBox::AdjustToContents:
370 case QComboBox::AdjustToContentsOnFirstShow:
372 sh.rwidth() = 7 * fm.horizontalAdvance(u'x');
374 for (
int i = 0; i < count; ++i) {
375 if (!q->itemIcon(i).isNull()) {
377 sh.setWidth(qMax(sh.width(), fm.boundingRect(q->itemText(i)).width() + iconSize.width() + 4));
379 sh.setWidth(qMax(sh.width(), fm.boundingRect(q->itemText(i)).width()));
384 case QComboBox::AdjustToMinimumContentsLengthWithIcon:
388 for (
int i = 0; i < count && !hasIcon; ++i)
389 hasIcon = !q->itemIcon(i).isNull();
391 if (minimumContentsLength > 0) {
392 auto r = qint64{minimumContentsLength} * fm.horizontalAdvance(u'X');
394 r += iconSize.width() + 4;
395 if (r <= QWIDGETSIZE_MAX) {
396 sh.setWidth(qMax(sh.width(),
int(r)));
398 qWarning(
"QComboBox: cannot take minimumContentsLength %d into account for sizeHint(), "
399 "since it causes the widget to be wider than QWIDGETSIZE_MAX. "
400 "Consider setting it to a less extreme value.",
401 minimumContentsLength);
404 if (!placeholderText.isEmpty())
405 sh.setWidth(qMax(sh.width(), fm.boundingRect(placeholderText).width()));
409 sh.setHeight(qMax(qCeil(QFontMetricsF(fm).height()), 14) + 2);
411 sh.setHeight(qMax(sh.height(), iconSize.height() + 2));
415 QStyleOptionComboBox opt;
416 q->initStyleOption(&opt);
417 sh = q->style()->sizeFromContents(QStyle::CT_ComboBox, &opt, sh, q);
422void QComboBoxPrivate::adjustComboBoxSize()
424 viewContainer()->adjustSizeTimer.start(20, container);
427void QComboBoxPrivate::updateLayoutDirection()
429 Q_Q(
const QComboBox);
430 QStyleOptionComboBox opt;
431 q->initStyleOption(&opt);
432 Qt::LayoutDirection dir = Qt::LayoutDirection(
433 q->style()->styleHint(QStyle::SH_ComboBox_LayoutDirection, &opt, q));
435 lineEdit->setLayoutDirection(dir);
437 container->setLayoutDirection(dir);
441void QComboBoxPrivateContainer::timerEvent(QTimerEvent *timerEvent)
443 if (timerEvent->timerId() == adjustSizeTimer.timerId()) {
444 adjustSizeTimer.stop();
445 if (combo->sizeAdjustPolicy() == QComboBox::AdjustToContents) {
446 combo->updateGeometry();
453void QComboBoxPrivateContainer::resizeEvent(QResizeEvent *e)
455 QStyleOptionComboBox opt = comboStyleOption();
456 if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo)) {
458 myOpt.initFrom(
this);
459 QStyleHintReturnMask mask;
460 if (combo->style()->styleHint(QStyle::SH_Menu_Mask, &myOpt,
this, &mask)) {
461 setMask(mask.region);
466 QFrame::resizeEvent(e);
469void QComboBoxPrivateContainer::paintEvent(QPaintEvent *e)
471 QStyleOptionComboBox cbOpt = comboStyleOption();
472 if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &cbOpt, combo)
473 && mask().isEmpty()) {
477 style()->drawPrimitive(QStyle::PE_PanelMenu, &opt, &p,
this);
480 QFrame::paintEvent(e);
483QComboBoxPrivateContainer::QComboBoxPrivateContainer(QAbstractItemView *itemView, QComboBox *parent)
484 : QFrame(parent, Qt::Popup), combo(parent)
490 setAttribute(Qt::WA_WindowPropagation);
491 setAttribute(Qt::WA_X11NetWmWindowTypeCombo);
494 blockMouseReleaseTimer.setSingleShot(
true);
497 QBoxLayout *layout =
new QBoxLayout(QBoxLayout::TopToBottom,
this);
498 layout->setSpacing(0);
499 layout->setContentsMargins(QMargins());
502 setItemView(itemView);
505 QStyleOptionComboBox opt = comboStyleOption();
506 const bool usePopup = combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo);
508 top =
new QComboBoxPrivateScroller(QAbstractSlider::SliderSingleStepSub,
this);
509 bottom =
new QComboBoxPrivateScroller(QAbstractSlider::SliderSingleStepAdd,
this);
517 layout->insertWidget(0, top);
518 connect(top, &QComboBoxPrivateScroller::doScroll,
519 this, &QComboBoxPrivateContainer::scrollItemView);
522 layout->addWidget(bottom);
523 connect(bottom, &QComboBoxPrivateScroller::doScroll,
524 this, &QComboBoxPrivateContainer::scrollItemView);
528 layout->insertSpacing(0, 0);
529 layout->addSpacing(0);
530 updateStyleSettings();
533QComboBoxPrivateContainer::~QComboBoxPrivateContainer()
535 disconnect(view, &QAbstractItemView::destroyed,
536 this, &QComboBoxPrivateContainer::viewDestroyed);
539void QComboBoxPrivateContainer::scrollItemView(
int action)
541#if QT_CONFIG(scrollbar)
542 if (view->verticalScrollBar())
543 view->verticalScrollBar()->triggerAction(
static_cast<QAbstractSlider::SliderAction>(action));
547void QComboBoxPrivateContainer::hideScrollers()
556
557
558void QComboBoxPrivateContainer::updateScrollers()
560#if QT_CONFIG(scrollbar)
564 if (isVisible() ==
false)
567 QStyleOptionComboBox opt = comboStyleOption();
568 if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo) &&
569 view->verticalScrollBar()->minimum() < view->verticalScrollBar()->maximum()) {
571 bool needTop = view->verticalScrollBar()->value()
572 > (view->verticalScrollBar()->minimum() + topMargin());
573 bool needBottom = view->verticalScrollBar()->value()
574 < (view->verticalScrollBar()->maximum() - bottomMargin() - topMargin());
591
592
593void QComboBoxPrivateContainer::viewDestroyed()
596 setItemView(
new QComboBoxListView());
600
601
602QAbstractItemView *QComboBoxPrivateContainer::itemView()
const
608
609
610void QComboBoxPrivateContainer::setItemView(QAbstractItemView *itemView)
616 view->removeEventFilter(
this);
617 view->viewport()->removeEventFilter(
this);
618#if QT_CONFIG(scrollbar)
619 disconnect(view->verticalScrollBar(), &QScrollBar::valueChanged,
620 this, &QComboBoxPrivateContainer::updateScrollers);
621 disconnect(view->verticalScrollBar(), &QScrollBar::rangeChanged,
622 this, &QComboBoxPrivateContainer::updateScrollers);
624 disconnect(view, &QAbstractItemView::destroyed,
625 this, &QComboBoxPrivateContainer::viewDestroyed);
627 if (isAncestorOf(view))
634 view->setParent(
this);
635 view->setAttribute(Qt::WA_MacShowFocusRect,
false);
636 qobject_cast<QBoxLayout*>(layout())->insertWidget(top ? 2 : 0, view);
637 view->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
638 view->installEventFilter(
this);
639 view->viewport()->installEventFilter(
this);
640 view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
641 QStyleOptionComboBox opt = comboStyleOption();
642 const bool usePopup = combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo);
643#if QT_CONFIG(scrollbar)
645 view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
648 combo->style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking_Current, &opt, combo) ||
649 combo->style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking_Active, &opt, combo)
651 view->setMouseTracking(
true);
653 view->setSelectionMode(QAbstractItemView::SingleSelection);
654 view->setFrameStyle(QFrame::NoFrame);
655 view->setLineWidth(0);
656 view->setEditTriggers(QAbstractItemView::NoEditTriggers);
657#if QT_CONFIG(scrollbar)
658 connect(view->verticalScrollBar(), &QScrollBar::valueChanged,
659 this, &QComboBoxPrivateContainer::updateScrollers);
660 connect(view->verticalScrollBar(), &QScrollBar::rangeChanged,
661 this, &QComboBoxPrivateContainer::updateScrollers);
663 connect(view, &QAbstractItemView::destroyed,
664 this, &QComboBoxPrivateContainer::viewDestroyed);
668
669
670int QComboBoxPrivateContainer::topMargin()
const
672 if (
const QListView *lview = qobject_cast<
const QListView*>(view))
673 return lview->spacing();
674#if QT_CONFIG(tableview)
675 if (
const QTableView *tview = qobject_cast<
const QTableView*>(view))
676 return tview->showGrid() ? 1 : 0;
682
683
684int QComboBoxPrivateContainer::spacing()
const
686 QListView *lview = qobject_cast<QListView*>(view);
688 return 2 * lview->spacing();
689#if QT_CONFIG(tableview)
690 QTableView *tview = qobject_cast<QTableView*>(view);
692 return tview->showGrid() ? 1 : 0;
697void QComboBoxPrivateContainer::updateTopBottomMargin()
699 if (!layout() || layout()->count() < 1)
702 QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(layout());
706 const QStyleOptionComboBox opt = comboStyleOption();
707 const bool usePopup = combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo);
708 const int margin = usePopup ? combo->style()->pixelMetric(QStyle::PM_MenuVMargin, &opt, combo) : 0;
710 QSpacerItem *topSpacer = boxLayout->itemAt(0)->spacerItem();
712 topSpacer->changeSize(0, margin, QSizePolicy::Minimum, QSizePolicy::Fixed);
714 QSpacerItem *bottomSpacer = boxLayout->itemAt(boxLayout->count() - 1)->spacerItem();
715 if (bottomSpacer && bottomSpacer != topSpacer)
716 bottomSpacer->changeSize(0, margin, QSizePolicy::Minimum, QSizePolicy::Fixed);
718 boxLayout->invalidate();
721void QComboBoxPrivateContainer::updateStyleSettings()
724 QStyleOptionComboBox opt = comboStyleOption();
725 view->setMouseTracking(combo->style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking, &opt, combo) ||
726 combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo));
727 setFrameStyle(combo->style()->styleHint(QStyle::SH_ComboBox_PopupFrameStyle, &opt, combo));
728 updateTopBottomMargin();
731void QComboBoxPrivateContainer::changeEvent(QEvent *e)
733 if (e->type() == QEvent::StyleChange)
734 updateStyleSettings();
736 QFrame::changeEvent(e);
740bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e)
743 case QEvent::ShortcutOverride: {
744 QKeyEvent *keyEvent =
static_cast<QKeyEvent*>(e);
745 switch (keyEvent->key()) {
748#ifdef QT_KEYPAD_NAVIGATION
751 if (view->currentIndex().isValid() && view->currentIndex().flags().testFlag(Qt::ItemIsEnabled)) {
754 emit itemSelected(view->currentIndex());
758 if (!(keyEvent->modifiers() & Qt::AltModifier))
764 emit itemSelected(view->currentIndex());
767#if QT_CONFIG(shortcut)
768 if (keyEvent->matches(QKeySequence::Cancel) && isVisible()) {
777 case QEvent::MouseMove:
779 QMouseEvent *m =
static_cast<QMouseEvent *>(e);
780 QWidget *widget =
static_cast<QWidget *>(o);
781 QPoint vector = widget->mapToGlobal(m->position().toPoint()) - initialClickPosition;
782 if (vector.manhattanLength() > 9 && blockMouseReleaseTimer.isActive())
783 blockMouseReleaseTimer.stop();
784 if (combo->style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking_Current,
nullptr, combo)) {
785 QModelIndex indexUnderMouse = view->indexAt(m->position().toPoint());
786 if (indexUnderMouse.isValid()
787 && !QComboBoxDelegate::isSeparator(indexUnderMouse)) {
788 view->setCurrentIndex(indexUnderMouse);
793 case QEvent::MouseButtonPress:
794 maybeIgnoreMouseButtonRelease =
false;
796 case QEvent::MouseButtonRelease: {
797 bool ignoreEvent = maybeIgnoreMouseButtonRelease && popupTimer.elapsed() < QApplication::doubleClickInterval();
799 QMouseEvent *m =
static_cast<QMouseEvent *>(e);
800 if (isVisible() && view->rect().contains(m->position().toPoint()) && view->currentIndex().isValid()
801 && !blockMouseReleaseTimer.isActive() && !ignoreEvent
802 && (view->currentIndex().flags().testFlag(Qt::ItemIsEnabled))
803 && (view->currentIndex().flags().testFlag(Qt::ItemIsSelectable))) {
805 emit itemSelected(view->currentIndex());
813 return QFrame::eventFilter(o, e);
816void QComboBoxPrivateContainer::showEvent(QShowEvent *)
821void QComboBoxPrivateContainer::hideEvent(QHideEvent *)
825#if QT_CONFIG(graphicsview)
829 if (QGraphicsProxyWidget *proxy = graphicsProxyWidget())
834void QComboBoxPrivateContainer::mousePressEvent(QMouseEvent *e)
837 QStyleOptionComboBox opt = comboStyleOption();
838 opt.subControls = QStyle::SC_All;
839 opt.activeSubControls = QStyle::SC_ComboBoxArrow;
840 QStyle::SubControl sc = combo->style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt,
841 combo->mapFromGlobal(e->globalPosition().toPoint()),
843 if ((combo->isEditable() && sc == QStyle::SC_ComboBoxArrow)
844 || (!combo->isEditable() && sc != QStyle::SC_None))
845 setAttribute(Qt::WA_NoMouseReplay);
849void QComboBoxPrivateContainer::mouseReleaseEvent(QMouseEvent *e)
852 if (!blockMouseReleaseTimer.isActive()) {
858QStyleOptionComboBox QComboBoxPrivateContainer::comboStyleOption()
const
862 QStyleOptionComboBox opt;
864 opt.subControls = QStyle::SC_All;
865 opt.activeSubControls = QStyle::SC_None;
866 opt.editable = combo->isEditable();
871
872
873
874
875
876
877
878
879
880
881
882
883
886
887
888
889
890
891
892
893
894
895
898
899
900
901
902
903
904
905
908
909
910
911
912
913
914
915
916
919
920
921
922
923
926
927
928
929
930
931
934
935
936
937
938
939
940
941
944
945
946
947
948
949
950
951
952
955
956
957
958QComboBox::QComboBox(QWidget *parent)
959 : QWidget(*
new QComboBoxPrivate(), parent, { })
966
967
968QComboBox::QComboBox(QComboBoxPrivate &dd, QWidget *parent)
969 : QWidget(dd, parent, { })
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1061void QComboBoxPrivate::init()
1069 if (!q->isEditable())
1070 q->setFocusPolicy(Qt::TabFocus);
1073 q->setFocusPolicy(Qt::WheelFocus);
1075 q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed,
1076 QSizePolicy::ComboBox));
1077 setLayoutItemMargins(QStyle::SE_ComboBoxLayoutItem);
1078 q->setModel(
new QStandardItemModel(0, 1, q));
1079 if (!q->isEditable())
1080 q->setAttribute(Qt::WA_InputMethodEnabled,
false);
1082 q->setAttribute(Qt::WA_InputMethodEnabled);
1085QComboBoxPrivateContainer* QComboBoxPrivate::viewContainer()
1091 container =
new QComboBoxPrivateContainer(
new QComboBoxListView(q), q);
1093 container->itemView()->setModel(model);
1095 container->itemView()->setTextElideMode(Qt::ElideMiddle);
1096 updateDelegate(
true);
1097 updateLayoutDirection();
1098 updateViewContainerPaletteAndOpacity();
1099 QObjectPrivate::connect(container, &QComboBoxPrivateContainer::itemSelected,
1100 this, &QComboBoxPrivate::itemSelected);
1101 QObjectPrivate::connect(container->itemView()->selectionModel(),
1102 &QItemSelectionModel::currentChanged,
1103 this, &QComboBoxPrivate::emitHighlighted);
1104 QObjectPrivate::connect(container, &QComboBoxPrivateContainer::resetButton,
1105 this, &QComboBoxPrivate::resetButton);
1110void QComboBoxPrivate::resetButton()
1112 updateArrow(QStyle::State_None);
1115void QComboBoxPrivate::dataChanged(
const QModelIndex &topLeft,
const QModelIndex &bottomRight)
1118 if (inserting || topLeft.parent() != root)
1121 if (sizeAdjustPolicy == QComboBox::AdjustToContents) {
1123 adjustComboBoxSize();
1124 q->updateGeometry();
1127 if (currentIndex.row() >= topLeft.row() && currentIndex.row() <= bottomRight.row()) {
1128 const QString text = q->itemText(currentIndex.row());
1130 lineEdit->setText(text);
1131 updateLineEditGeometry();
1133 updateCurrentText(text);
1136#if QT_CONFIG(accessibility)
1137 QAccessibleValueChangeEvent event(q, text);
1138 QAccessible::updateAccessibility(&event);
1143void QComboBoxPrivate::rowsInserted(
const QModelIndex &parent,
int start,
int end)
1146 if (inserting || parent != root)
1149 if (sizeAdjustPolicy == QComboBox::AdjustToContents) {
1151 adjustComboBoxSize();
1152 q->updateGeometry();
1156 if (start == 0 && (end - start + 1) == q->count() && !currentIndex.isValid() &&
1157 placeholderText.isEmpty()) {
1158#if QT_CONFIG(accessibility)
1163 if (container && container->itemView()) {
1164 QAccessibleTableModelChangeEvent event(container->itemView(),
1165 QAccessibleTableModelChangeEvent::ModelReset);
1166 QAccessible::updateAccessibility(&event);
1169 q->setCurrentIndex(0);
1171 }
else if (currentIndex.row() != indexBeforeChange) {
1173 emitCurrentIndexChanged(currentIndex);
1177void QComboBoxPrivate::updateIndexBeforeChange()
1179 indexBeforeChange = currentIndex.row();
1182void QComboBoxPrivate::rowsRemoved(
const QModelIndex &parent,
int ,
int )
1188 if (sizeAdjustPolicy == QComboBox::AdjustToContents) {
1190 adjustComboBoxSize();
1191 q->updateGeometry();
1195 if (model->rowCount(root) == 0) {
1196 setCurrentIndex(QModelIndex());
1201 if (currentIndex.row() != indexBeforeChange) {
1202 if (!currentIndex.isValid() && q->count()) {
1203 q->setCurrentIndex(qMin(q->count() - 1, qMax(indexBeforeChange, 0)));
1207 lineEdit->setText(q->itemText(currentIndex.row()));
1208 updateLineEditGeometry();
1211 emitCurrentIndexChanged(currentIndex);
1216void QComboBoxPrivate::updateViewContainerPaletteAndOpacity()
1221 QStyleOptionComboBox opt;
1222 q->initStyleOption(&opt);
1224 if (q->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, q)) {
1226 menu.ensurePolished();
1227 container->setPalette(menu.palette());
1228 container->setWindowOpacity(menu.windowOpacity());
1232 container->setPalette(q->palette());
1233 container->setWindowOpacity(1.0);
1236 lineEdit->setPalette(q->palette());
1239void QComboBoxPrivate::updateFocusPolicy()
1245 if (q->isEditable())
1246 q->setFocusPolicy(Qt::WheelFocus);
1248 q->setFocusPolicy(Qt::TabFocus);
1253
1254
1255
1256
1257
1258
1259void QComboBox::initStyleOption(QStyleOptionComboBox *option)
const
1264 Q_D(
const QComboBox);
1265 option->initFrom(
this);
1266 option->editable = isEditable();
1267 option->frame = d->frame;
1268 if (hasFocus() && !option->editable)
1269 option->state |= QStyle::State_Selected;
1270 option->subControls = QStyle::SC_All;
1271 if (d->arrowState == QStyle::State_Sunken) {
1272 option->activeSubControls = QStyle::SC_ComboBoxArrow;
1273 option->state |= d->arrowState;
1275 option->activeSubControls = d->hoverControl;
1277 option->currentText = currentText();
1278 if (d->currentIndex.isValid()) {
1279 option->currentIcon = d->itemIcon(d->currentIndex);
1280 QVariant alignment = d->model->data(d->currentIndex, Qt::TextAlignmentRole);
1281 if (alignment.isValid())
1282 option->textAlignment =
static_cast<Qt::Alignment>(alignment.toUInt());
1284 option->iconSize = iconSize();
1285 if (d->container && d->container->isVisible())
1286 option->state |= QStyle::State_On;
1289void QComboBoxPrivate::initViewItemOption(QStyleOptionViewItem *option)
const
1291 Q_Q(
const QComboBox);
1292 q->view()->initViewItemOption(option);
1294 option->index = currentIndex;
1295 option->text = q->currentText();
1296 option->icon = itemIcon(currentIndex);
1299void QComboBoxPrivate::updateLineEditGeometry()
1305 QStyleOptionComboBox opt;
1306 q->initStyleOption(&opt);
1307 QRect editRect = q->style()->subControlRect(QStyle::CC_ComboBox, &opt,
1308 QStyle::SC_ComboBoxEditField, q);
1309 if (currentIndex.isValid() && !q->itemIcon(q->currentIndex()).isNull()) {
1310 QRect comboRect(editRect);
1311 editRect.setWidth(editRect.width() - q->iconSize().width() - 4);
1312 editRect = QStyle::alignedRect(q->layoutDirection(), Qt::AlignRight,
1313 editRect.size(), comboRect);
1315 lineEdit->setGeometry(editRect);
1318Qt::MatchFlags QComboBoxPrivate::matchFlags()
const
1321 Qt::MatchFlags flags = Qt::MatchFixedString;
1322#if QT_CONFIG(completer)
1323 if (!lineEdit->completer() || lineEdit->completer()->caseSensitivity() == Qt::CaseSensitive)
1325 flags |= Qt::MatchCaseSensitive;
1330void QComboBoxPrivate::editingFinished()
1335 const auto leText = lineEdit->text();
1336 if (!leText.isEmpty() && itemText(currentIndex) != leText) {
1337#if QT_CONFIG(completer)
1338 const auto *leCompleter = lineEdit->completer();
1339 const auto *popup = leCompleter ? QCompleterPrivate::get(leCompleter)->popup :
nullptr;
1340 if (popup && popup->isVisible()) {
1345 const QItemSelectionModel *selModel = popup->selectionModel();
1346 const QModelIndex curIndex = popup->currentIndex();
1347 const bool completerIsActive = selModel && selModel->selectedIndexes().contains(curIndex);
1349 if (completerIsActive)
1353 const int index = q_func()->findText(leText, matchFlags());
1355 q->setCurrentIndex(index);
1356 emitActivated(currentIndex);
1362void QComboBoxPrivate::returnPressed()
1370 if (insertPolicy == QComboBox::NoInsert)
1373 if (lineEdit && !lineEdit->text().isEmpty()) {
1374 if (q->count() >= maxCount && !(
this->insertPolicy == QComboBox::InsertAtCurrent))
1376 lineEdit->deselect();
1377 lineEdit->end(
false);
1378 QString text = lineEdit->text();
1381 if (!duplicatesEnabled) {
1382 index = q->findText(text, matchFlags());
1384 q->setCurrentIndex(index);
1385 emitActivated(currentIndex);
1389 switch (insertPolicy) {
1390 case QComboBox::InsertAtTop:
1393 case QComboBox::InsertAtBottom:
1396 case QComboBox::InsertAtCurrent:
1397 case QComboBox::InsertAfterCurrent:
1398 case QComboBox::InsertBeforeCurrent:
1399 if (!q->count() || !currentIndex.isValid())
1401 else if (insertPolicy == QComboBox::InsertAtCurrent)
1402 q->setItemText(q->currentIndex(), text);
1403 else if (insertPolicy == QComboBox::InsertAfterCurrent)
1404 index = q->currentIndex() + 1;
1405 else if (insertPolicy == QComboBox::InsertBeforeCurrent)
1406 index = q->currentIndex();
1408 case QComboBox::InsertAlphabetically:
1410 for (
int i = 0; i < q->count(); ++i, ++index) {
1411 if (text.toLower() < q->itemText(i).toLower())
1419 q->insertItem(index, text);
1420 q->setCurrentIndex(index);
1421 emitActivated(currentIndex);
1426void QComboBoxPrivate::itemSelected(
const QModelIndex &item)
1429 if (item != currentIndex) {
1430 setCurrentIndex(item);
1431 }
else if (lineEdit) {
1432 lineEdit->selectAll();
1433 lineEdit->setText(q->itemText(currentIndex.row()));
1435 emitActivated(currentIndex);
1438void QComboBoxPrivate::emitActivated(
const QModelIndex &index)
1441 if (!index.isValid())
1443 QString text(itemText(index));
1444 emit q->activated(index.row());
1445 emit q->textActivated(text);
1448void QComboBoxPrivate::emitHighlighted(
const QModelIndex &index)
1451 if (!index.isValid())
1453 QString text(itemText(index));
1454 emit q->highlighted(index.row());
1455 emit q->textHighlighted(text);
1458void QComboBoxPrivate::emitCurrentIndexChanged(
const QModelIndex &index)
1461 const QString text = itemText(index);
1462 emit q->currentIndexChanged(index.row());
1465 updateCurrentText(text);
1466#if QT_CONFIG(accessibility)
1467 QAccessibleValueChangeEvent event(q, text);
1468 QAccessible::updateAccessibility(&event);
1472QString QComboBoxPrivate::itemText(
const QModelIndex &index)
const
1474 return index.isValid() ? model->data(index, itemRole()).toString() : QString();
1477int QComboBoxPrivate::itemRole()
const
1479 return q_func()->isEditable() ? Qt::EditRole : Qt::DisplayRole;
1483
1484
1485QComboBox::~QComboBox()
1491 d->disconnectModel();
1500 d->container->close();
1501 delete d->container;
1502 d->container =
nullptr;
1507
1508
1509
1510
1511
1512
1513
1514
1515int QComboBox::maxVisibleItems()
const
1517 Q_D(
const QComboBox);
1518 return d->maxVisibleItems;
1521void QComboBox::setMaxVisibleItems(
int maxItems)
1524 if (Q_UNLIKELY(maxItems < 0)) {
1525 qWarning(
"QComboBox::setMaxVisibleItems: "
1526 "Invalid max visible items (%d) must be >= 0", maxItems);
1529 d->maxVisibleItems = maxItems;
1533
1534
1535
1536
1537
1538int QComboBox::count()
const
1540 Q_D(
const QComboBox);
1541 return d->model->rowCount(d->root);
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556void QComboBox::setMaxCount(
int max)
1559 if (Q_UNLIKELY(max < 0)) {
1560 qWarning(
"QComboBox::setMaxCount: Invalid count (%d) must be >= 0", max);
1564 const int rowCount = count();
1566 d->model->removeRows(max, rowCount - max, d->root);
1571int QComboBox::maxCount()
const
1573 Q_D(
const QComboBox);
1578
1579
1580
1581
1582
1583
1584
1585
1586bool QComboBox::duplicatesEnabled()
const
1588 Q_D(
const QComboBox);
1589 return d->duplicatesEnabled;
1592void QComboBox::setDuplicatesEnabled(
bool enable)
1595 d->duplicatesEnabled = enable;
1599
1600
1601
1602
1603
1604
1607
1608
1609
1610
1611
1612int QComboBox::findData(
const QVariant &data,
int role, Qt::MatchFlags flags)
const
1614 Q_D(
const QComboBox);
1615 QModelIndex start = d->model->index(0, d->modelColumn, d->root);
1616 const QModelIndexList result = d->model->match(start, role, data, 1, flags);
1617 if (result.isEmpty())
1619 return result.first().row();
1623
1624
1625
1626
1627
1628
1629
1630
1631
1633QComboBox::InsertPolicy QComboBox::insertPolicy()
const
1635 Q_D(
const QComboBox);
1636 return d->insertPolicy;
1639void QComboBox::setInsertPolicy(InsertPolicy policy)
1642 d->insertPolicy = policy;
1646
1647
1648
1649
1650
1651
1652
1653
1655QComboBox::SizeAdjustPolicy QComboBox::sizeAdjustPolicy()
const
1657 Q_D(
const QComboBox);
1658 return d->sizeAdjustPolicy;
1661void QComboBox::setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy policy)
1664 if (policy == d->sizeAdjustPolicy)
1667 d->sizeAdjustPolicy = policy;
1668 d->sizeHint = QSize();
1669 d->adjustComboBoxSize();
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684int QComboBox::minimumContentsLength()
const
1686 Q_D(
const QComboBox);
1687 return d->minimumContentsLength;
1690void QComboBox::setMinimumContentsLength(
int characters)
1693 if (characters == d->minimumContentsLength || characters < 0)
1696 d->minimumContentsLength = characters;
1698 if (d->sizeAdjustPolicy == AdjustToContents
1699 || d->sizeAdjustPolicy == AdjustToMinimumContentsLengthWithIcon) {
1700 d->sizeHint = QSize();
1701 d->adjustComboBoxSize();
1707
1708
1709
1710
1711
1712
1713
1715QSize QComboBox::iconSize()
const
1717 Q_D(
const QComboBox);
1718 if (d->iconSize.isValid())
1721 int iconWidth = style()->pixelMetric(QStyle::PM_SmallIconSize,
nullptr,
this);
1722 return QSize(iconWidth, iconWidth);
1725void QComboBox::setIconSize(
const QSize &size)
1728 if (size == d->iconSize)
1731 view()->setIconSize(size);
1733 d->sizeHint = QSize();
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753void QComboBox::setPlaceholderText(
const QString &placeholderText)
1756 if (placeholderText == d->placeholderText)
1759 d->placeholderText = placeholderText;
1760 if (currentIndex() == -1) {
1761 if (d->placeholderText.isEmpty())
1770QString QComboBox::placeholderText()
const
1772 Q_D(
const QComboBox);
1773 return d->placeholderText;
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788bool QComboBox::isEditable()
const
1790 Q_D(
const QComboBox);
1791 return d->lineEdit !=
nullptr;
1795
1796
1797
1798
1799
1800
1801void QComboBoxPrivate::updateDelegate(
bool force)
1804 QStyleOptionComboBox opt;
1805 q->initStyleOption(&opt);
1806 if (q->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, q)) {
1807 if (force || qobject_cast<QComboBoxDelegate *>(q->itemDelegate()))
1808 q->setItemDelegate(
new QComboMenuDelegate(q->view(), q));
1810 if (force || qobject_cast<QComboMenuDelegate *>(q->itemDelegate()))
1811 q->setItemDelegate(
new QComboBoxDelegate(q->view(), q));
1815QIcon QComboBoxPrivate::itemIcon(
const QModelIndex &index)
const
1817 if (!index.isValid())
1819 QVariant decoration = model->data(index, Qt::DecorationRole);
1820 if (decoration.userType() == QMetaType::QPixmap)
1821 return QIcon(qvariant_cast<QPixmap>(decoration));
1823 return qvariant_cast<QIcon>(decoration);
1826void QComboBox::setEditable(
bool editable)
1829 if (isEditable() == editable)
1832 QStyleOptionComboBox opt;
1833 initStyleOption(&opt);
1835 if (style()->styleHint(QStyle::SH_ComboBox_Popup, &opt,
this)) {
1836 d->viewContainer()->updateScrollers();
1837 view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1839 QLineEdit *le =
new QLineEdit(
this);
1840 le->setPalette(palette());
1843 if (style()->styleHint(QStyle::SH_ComboBox_Popup, &opt,
this)) {
1844 d->viewContainer()->updateScrollers();
1845 view()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1847 setAttribute(Qt::WA_InputMethodEnabled,
false);
1848 d->lineEdit->hide();
1849 d->lineEdit->deleteLater();
1850 d->lineEdit =
nullptr;
1853 d->updateDelegate();
1854 d->updateFocusPolicy();
1856 d->viewContainer()->updateTopBottomMargin();
1857 if (!testAttribute(Qt::WA_Resized))
1862
1863
1864
1865
1866
1867
1868
1869void QComboBox::setLineEdit(QLineEdit *edit)
1872 if (Q_UNLIKELY(!edit)) {
1873 qWarning(
"QComboBox::setLineEdit: cannot set a 0 line edit");
1877 if (edit == d->lineEdit)
1880 edit->setText(currentText());
1885 qt_widget_private(d->lineEdit)->inheritsInputMethodHints = 1;
1887 if (d->lineEdit->parent() !=
this)
1888 d->lineEdit->setParent(
this);
1889 QObjectPrivate::connect(d->lineEdit, &QLineEdit::returnPressed,
1890 d, &QComboBoxPrivate::returnPressed);
1891 QObjectPrivate::connect(d->lineEdit, &QLineEdit::editingFinished,
1892 d, &QComboBoxPrivate::editingFinished);
1893 connect(d->lineEdit, &QLineEdit::textChanged,
this, &QComboBox::editTextChanged);
1894 connect(d->lineEdit, &QLineEdit::textChanged,
this, &QComboBox::currentTextChanged);
1895 QObjectPrivate::connect(d->lineEdit, &QLineEdit::cursorPositionChanged,
1896 d, &QComboBoxPrivate::updateMicroFocus);
1897 QObjectPrivate::connect(d->lineEdit, &QLineEdit::selectionChanged,
1898 d, &QComboBoxPrivate::updateMicroFocus);
1899 QObjectPrivate::connect(d->lineEdit->d_func()->control, &QWidgetLineControl::updateMicroFocus,
1900 d, &QComboBoxPrivate::updateMicroFocus);
1901 d->lineEdit->setFrame(
false);
1902 d->lineEdit->setContextMenuPolicy(Qt::NoContextMenu);
1903 d->updateFocusPolicy();
1904 d->lineEdit->setFocusProxy(
this);
1905 d->lineEdit->setAttribute(Qt::WA_MacShowFocusRect,
false);
1907#if QT_CONFIG(completer)
1909 if (!d->lineEdit->completer()) {
1910 QCompleter *completer =
new QCompleter(d->model, d->lineEdit);
1911 completer->setCaseSensitivity(Qt::CaseInsensitive);
1912 completer->setCompletionMode(QCompleter::InlineCompletion);
1913 completer->setCompletionColumn(d->modelColumn);
1915#ifdef QT_KEYPAD_NAVIGATION
1919 if (QApplicationPrivate::keypadNavigationEnabled())
1920 completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
1923 setCompleter(completer);
1927 setAttribute(Qt::WA_InputMethodEnabled);
1928 d->updateLayoutDirection();
1929 d->updateLineEditGeometry();
1931 d->lineEdit->show();
1937
1938
1939
1940
1941
1942QLineEdit *QComboBox::lineEdit()
const
1944 Q_D(
const QComboBox);
1948#ifndef QT_NO_VALIDATOR
1950
1951
1952
1953
1954
1955
1957void QComboBox::setValidator(
const QValidator *v)
1961 d->lineEdit->setValidator(v);
1965
1966
1967
1968
1969
1970const QValidator *QComboBox::validator()
const
1972 Q_D(
const QComboBox);
1973 return d->lineEdit ? d->lineEdit->validator() :
nullptr;
1977#if QT_CONFIG(completer)
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993void QComboBox::setCompleter(QCompleter *c)
1997 qWarning(
"Setting a QCompleter on non-editable QComboBox is not allowed.");
2000 d->lineEdit->setCompleter(c);
2002 QObjectPrivate::connect(c, QOverload<
const QModelIndex &>::of(&QCompleter::activated),
2003 d, &QComboBoxPrivate::completerActivated);
2009
2010
2011
2012
2013
2014
2015
2016QCompleter *QComboBox::completer()
const
2018 Q_D(
const QComboBox);
2019 return d->lineEdit ? d->lineEdit->completer() :
nullptr;
2025
2026
2027
2028
2029QAbstractItemDelegate *QComboBox::itemDelegate()
const
2031 return view()->itemDelegate();
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049void QComboBox::setItemDelegate(QAbstractItemDelegate *delegate)
2051 if (Q_UNLIKELY(!delegate)) {
2052 qWarning(
"QComboBox::setItemDelegate: cannot set a 0 delegate");
2055 view()->setItemDelegate(delegate);
2059
2060
2062QAbstractItemModel *QComboBox::model()
const
2064 Q_D(
const QComboBox);
2065 if (d->model == QAbstractItemModelPrivate::staticEmptyModel()) {
2066 QComboBox *that =
const_cast<QComboBox*>(
this);
2067 that->setModel(
new QStandardItemModel(0, 1, that));
2073
2074
2075
2076
2077
2078
2079
2080
2081void QComboBox::setModel(QAbstractItemModel *model)
2085 if (Q_UNLIKELY(!model)) {
2086 qWarning(
"QComboBox::setModel: cannot set a 0 model");
2090 if (model == d->model)
2093#if QT_CONFIG(completer)
2094 if (d->lineEdit && d->lineEdit->completer())
2095 d->lineEdit->completer()->setModel(model);
2097 d->disconnectModel();
2098 if (d->model && d->model->QObject::parent() ==
this) {
2106 d->container->itemView()->setModel(model);
2107 QObjectPrivate::connect(d->container->itemView()->selectionModel(),
2108 &QItemSelectionModel::currentChanged,
2109 d, &QComboBoxPrivate::emitHighlighted, Qt::UniqueConnection);
2114 setRootModelIndex(QModelIndex());
2116 d->trySetValidIndex();
2120void QComboBoxPrivate::connectModel()
2125 modelConnections = {
2126 QObjectPrivate::connect(model, &QAbstractItemModel::dataChanged,
2127 this, &QComboBoxPrivate::dataChanged),
2128 QObjectPrivate::connect(model, &QAbstractItemModel::rowsAboutToBeInserted,
2129 this, &QComboBoxPrivate::updateIndexBeforeChange),
2130 QObjectPrivate::connect(model, &QAbstractItemModel::rowsInserted,
2131 this, &QComboBoxPrivate::rowsInserted),
2132 QObjectPrivate::connect(model, &QAbstractItemModel::rowsAboutToBeRemoved,
2133 this, &QComboBoxPrivate::updateIndexBeforeChange),
2134 QObjectPrivate::connect(model, &QAbstractItemModel::rowsRemoved,
2135 this, &QComboBoxPrivate::rowsRemoved),
2136 QObjectPrivate::connect(model, &QObject::destroyed,
2137 this, &QComboBoxPrivate::modelDestroyed),
2138 QObjectPrivate::connect(model, &QAbstractItemModel::modelAboutToBeReset,
2139 this, &QComboBoxPrivate::updateIndexBeforeChange),
2140 QObjectPrivate::connect(model, &QAbstractItemModel::modelReset,
2141 this, &QComboBoxPrivate::modelReset)
2145void QComboBoxPrivate::disconnectModel()
2147 for (
auto &connection : modelConnections)
2148 QObject::disconnect(connection);
2152
2153
2154
2155
2157QModelIndex QComboBox::rootModelIndex()
const
2159 Q_D(
const QComboBox);
2160 return QModelIndex(d->root);
2164
2165
2166
2167
2168void QComboBox::setRootModelIndex(
const QModelIndex &index)
2171 if (d->root == index)
2173 d->root = QPersistentModelIndex(index);
2174 view()->setRootIndex(index);
2179
2180
2181
2182
2183
2184
2185
2186
2187int QComboBox::currentIndex()
const
2189 Q_D(
const QComboBox);
2190 return d->currentIndex.row();
2193void QComboBox::setCurrentIndex(
int index)
2196 QModelIndex mi = index >= 0 ? d->model->index(index, d->modelColumn, d->root) : QModelIndex();
2197 d->setCurrentIndex(mi);
2200void QComboBox::setCurrentText(
const QString &text)
2205 const int i = findText(text);
2211void QComboBoxPrivate::setCurrentIndex(
const QModelIndex &mi)
2215 QModelIndex normalized = mi.sibling(mi.row(), modelColumn);
2216 if (!normalized.isValid())
2219 bool indexChanged = (normalized != currentIndex);
2221 currentIndex = QPersistentModelIndex(normalized);
2223 const QString newText = itemText(normalized);
2224 if (lineEdit->text() != newText) {
2225 lineEdit->setText(newText);
2226#if QT_CONFIG(completer)
2227 if (lineEdit && lineEdit->completer())
2228 lineEdit->completer()->setCompletionPrefix(newText);
2231 updateLineEditGeometry();
2238 const bool modelResetToEmpty = !normalized.isValid() && indexBeforeChange != -1;
2239 if (modelResetToEmpty)
2240 indexBeforeChange = -1;
2242 if (indexChanged || modelResetToEmpty) {
2243 QItemSelectionModel::SelectionFlags selectionMode = QItemSelectionModel::ClearAndSelect;
2244 if (q->view()->selectionBehavior() == QAbstractItemView::SelectRows)
2245 selectionMode.setFlag(QItemSelectionModel::Rows);
2246 if (
auto *model = q->view()->selectionModel())
2247 model->setCurrentIndex(currentIndex, selectionMode);
2250 emitCurrentIndexChanged(currentIndex);
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268QString QComboBox::currentText()
const
2270 Q_D(
const QComboBox);
2272 return d->lineEdit->text();
2273 if (d->currentIndex.isValid())
2274 return d->itemText(d->currentIndex);
2279
2280
2281
2282
2283
2284
2285
2286QVariant QComboBox::currentData(
int role)
const
2288 Q_D(
const QComboBox);
2289 return d->currentIndex.data(role);
2293
2294
2295QString QComboBox::itemText(
int index)
const
2297 Q_D(
const QComboBox);
2298 QModelIndex mi = d->model->index(index, d->modelColumn, d->root);
2299 return d->itemText(mi);
2303
2304
2305QIcon QComboBox::itemIcon(
int index)
const
2307 Q_D(
const QComboBox);
2308 QModelIndex mi = d->model->index(index, d->modelColumn, d->root);
2309 return d->itemIcon(mi);
2313
2314
2315
2316QVariant QComboBox::itemData(
int index,
int role)
const
2318 Q_D(
const QComboBox);
2319 QModelIndex mi = d->model->index(index, d->modelColumn, d->root);
2320 return d->model->data(mi, role);
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349void QComboBox::insertItem(
int index,
const QIcon &icon,
const QString &text,
const QVariant &userData)
2352 int itemCount = count();
2353 index = qBound(0, index, itemCount);
2354 if (index >= d->maxCount)
2359 if (QStandardItemModel *m = qobject_cast<QStandardItemModel*>(d->model)) {
2360 QStandardItem *item =
new QStandardItem(text);
2361 if (!icon.isNull()) item->setData(icon, Qt::DecorationRole);
2362 if (userData.isValid()) item->setData(userData, Qt::UserRole);
2363 m->insertRow(index, item);
2366 d->inserting =
true;
2367 if (d->model->insertRows(index, 1, d->root)) {
2368 QModelIndex item = d->model->index(index, d->modelColumn, d->root);
2369 if (icon.isNull() && !userData.isValid()) {
2370 d->model->setData(item, text, Qt::EditRole);
2372 QMap<
int, QVariant> values;
2373 if (!text.isNull()) values.insert(Qt::EditRole, text);
2374 if (!icon.isNull()) values.insert(Qt::DecorationRole, icon);
2375 if (userData.isValid()) values.insert(Qt::UserRole, userData);
2376 if (!values.isEmpty()) d->model->setItemData(item, values);
2378 d->inserting =
false;
2379 d->rowsInserted(d->root, index, index);
2382 d->inserting =
false;
2386 if (itemCount > d->maxCount)
2387 d->model->removeRows(itemCount - 1, itemCount - d->maxCount, d->root);
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400void QComboBox::insertItems(
int index,
const QStringList &list)
2405 index = qBound(0, index, count());
2406 int insertCount = qMin(d->maxCount - index, list.size());
2407 if (insertCount <= 0)
2411 if (QStandardItemModel *m = qobject_cast<QStandardItemModel*>(d->model)) {
2412 QList<QStandardItem *> items;
2413 items.reserve(insertCount);
2414 QStandardItem *hiddenRoot = m->invisibleRootItem();
2415 for (
int i = 0; i < insertCount; ++i)
2416 items.append(
new QStandardItem(list.at(i)));
2417 hiddenRoot->insertRows(index, items);
2419 d->inserting =
true;
2420 if (d->model->insertRows(index, insertCount, d->root)) {
2422 for (
int i = 0; i < insertCount; ++i) {
2423 item = d->model->index(i+index, d->modelColumn, d->root);
2424 d->model->setData(item, list.at(i), Qt::EditRole);
2426 d->inserting =
false;
2427 d->rowsInserted(d->root, index, index + insertCount - 1);
2429 d->inserting =
false;
2434 if (mc > d->maxCount)
2435 d->model->removeRows(d->maxCount, mc - d->maxCount, d->root);
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449void QComboBox::insertSeparator(
int index)
2452 int itemCount = count();
2453 index = qBound(0, index, itemCount);
2454 if (index >= d->maxCount)
2456 insertItem(index, QIcon(), QString());
2457 QComboBoxDelegate::setSeparator(d->model, d->model->index(index, 0, d->root));
2461
2462
2463
2464
2465
2466void QComboBox::removeItem(
int index)
2469 if (index < 0 || index >= count())
2471 d->model->removeRows(index, 1, d->root);
2475
2476
2477void QComboBox::setItemText(
int index,
const QString &text)
2479 Q_D(
const QComboBox);
2480 QModelIndex item = d->model->index(index, d->modelColumn, d->root);
2481 if (item.isValid()) {
2482 d->model->setData(item, text, Qt::EditRole);
2487
2488
2489void QComboBox::setItemIcon(
int index,
const QIcon &icon)
2491 Q_D(
const QComboBox);
2492 QModelIndex item = d->model->index(index, d->modelColumn, d->root);
2493 if (item.isValid()) {
2494 d->model->setData(item, icon, Qt::DecorationRole);
2499
2500
2501
2502void QComboBox::setItemData(
int index,
const QVariant &value,
int role)
2504 Q_D(
const QComboBox);
2505 QModelIndex item = d->model->index(index, d->modelColumn, d->root);
2506 if (item.isValid()) {
2507 d->model->setData(item, value, role);
2512
2513
2514QAbstractItemView *QComboBox::view()
const
2516 Q_D(
const QComboBox);
2517 return const_cast<QComboBoxPrivate*>(d)->viewContainer()->itemView();
2521
2522
2523
2524
2525
2526
2527
2528
2529void QComboBox::setView(QAbstractItemView *itemView)
2532 if (Q_UNLIKELY(!itemView)) {
2533 qWarning(
"QComboBox::setView: cannot set a 0 view");
2537 if (itemView->model() != d->model) {
2538 d->disconnectModel();
2539 itemView->setModel(d->model);
2542 d->viewContainer()->setItemView(itemView);
2546
2547
2548QSize QComboBox::minimumSizeHint()
const
2550 Q_D(
const QComboBox);
2551 return d->recomputeSizeHint(d->minimumSizeHint);
2555
2556
2557
2558
2559
2560
2561QSize QComboBox::sizeHint()
const
2563 Q_D(
const QComboBox);
2564 return d->recomputeSizeHint(d->sizeHint);
2568void QComboBoxPrivate::cleanupNativePopup()
2570 if (!m_platformMenu)
2573 m_platformMenu->setVisible(
false);
2574 int count =
int(m_platformMenu->tag());
2575 for (
int i = 0; i < count; ++i)
2576 m_platformMenu->menuItemAt(i)->deleteLater();
2578 delete m_platformMenu;
2579 m_platformMenu =
nullptr;
2583
2584
2585
2586
2587
2588bool QComboBoxPrivate::showNativePopup()
2592 cleanupNativePopup();
2594 QPlatformTheme *theme = QGuiApplicationPrivate::instance()->platformTheme();
2595 m_platformMenu = theme->createPlatformMenu();
2596 if (!m_platformMenu)
2599 int itemsCount = q->count();
2600 m_platformMenu->setTag(quintptr(itemsCount));
2602 QPlatformMenuItem *currentItem =
nullptr;
2603 int currentIndex = q->currentIndex();
2605 for (
int i = 0; i < itemsCount; ++i) {
2606 QPlatformMenuItem *item = theme->createPlatformMenuItem();
2607 QModelIndex rowIndex = model->index(i, modelColumn, root);
2608 QVariant textVariant = model->data(rowIndex, Qt::EditRole);
2609 item->setText(textVariant.toString());
2610 QVariant iconVariant = model->data(rowIndex, Qt::DecorationRole);
2611 const Qt::ItemFlags itemFlags = model->flags(rowIndex);
2612 if (iconVariant.canConvert<QIcon>())
2613 item->setIcon(iconVariant.value<QIcon>());
2614 item->setCheckable(
true);
2615 item->setChecked(i == currentIndex);
2616 item->setEnabled(itemFlags & Qt::ItemIsEnabled);
2617 if (!currentItem || i == currentIndex)
2620 IndexSetter setter = { i, q };
2621 QObject::connect(item, &QPlatformMenuItem::activated, q, setter);
2623 m_platformMenu->insertMenuItem(item, 0);
2624 m_platformMenu->syncMenuItem(item);
2627 QWindow *tlw = q->window()->windowHandle();
2628 m_platformMenu->setFont(q->font());
2629 m_platformMenu->setMinimumWidth(q->rect().width());
2630 QPoint offset = QPoint(0, 7);
2631 if (q->testAttribute(Qt::WA_MacSmallSize))
2632 offset = QPoint(-1, 7);
2633 else if (q->testAttribute(Qt::WA_MacMiniSize))
2634 offset = QPoint(-2, 6);
2636 [[maybe_unused]] QPointer<QComboBox> guard(q);
2637 const QRect targetRect = QRect(tlw->mapFromGlobal(q->mapToGlobal(offset)), QSize());
2638 m_platformMenu->showPopup(tlw, QHighDpi::toNativePixels(targetRect, tlw), currentItem);
2644 QMouseEvent mouseReleased(QEvent::MouseButtonRelease, q->pos(), q->mapToGlobal(QPoint(0, 0)),
2645 Qt::LeftButton, Qt::MouseButtons(Qt::LeftButton), {});
2646 QCoreApplication::sendEvent(q, &mouseReleased);
2656
2657
2658
2659
2660
2661
2662
2663
2664void QComboBox::showPopup()
2670 QStyle *
const style =
this->style();
2671 QStyleOptionComboBox opt;
2672 initStyleOption(&opt);
2673 const bool usePopup = style->styleHint(QStyle::SH_ComboBox_Popup, &opt,
this);
2678 || (view()->metaObject()->className() == QByteArray(
"QComboBoxListView")
2679 && view()->itemDelegate()->metaObject()->className() == QByteArray(
"QComboMenuDelegate")))
2680 && style->styleHint(QStyle::SH_ComboBox_UseNativePopup, &opt,
this)
2681 && d->showNativePopup())
2685 QComboBoxPrivateContainer* container = d->viewContainer();
2686 QRect listRect(style->subControlRect(QStyle::CC_ComboBox, &opt,
2687 QStyle::SC_ComboBoxListBoxPopup,
this));
2688 QRect screen = d->popupGeometry(mapToGlobal(listRect.topLeft()));
2690 QPoint below = mapToGlobal(listRect.bottomLeft());
2691 int belowHeight = screen.bottom() - below.y();
2692 QPoint above = mapToGlobal(listRect.topLeft());
2693 int aboveHeight = above.y() - screen.y();
2694 bool boundToScreen = !window()->testAttribute(Qt::WA_DontShowOnScreen);
2695 const auto listView = qobject_cast<QListView *>(d->viewContainer()->itemView());
2700 QStack<QModelIndex> toCheck;
2701 toCheck.push(view()->rootIndex());
2702#if QT_CONFIG(treeview)
2703 QTreeView *treeView = qobject_cast<QTreeView*>(view());
2704 if (treeView && treeView->header() && !treeView->header()->isHidden())
2705 listHeight += treeView->header()->height();
2707 while (!toCheck.isEmpty()) {
2708 QModelIndex parent = toCheck.pop();
2709 for (
int i = 0, end = d->model->rowCount(parent); i < end; ++i) {
2710 if (listView && listView->isRowHidden(i))
2712 QModelIndex idx = d->model->index(i, d->modelColumn, parent);
2715 listHeight += view()->visualRect(idx).height();
2716#if QT_CONFIG(treeview)
2717 if (d->model->hasChildren(idx) && treeView && treeView->isExpanded(idx))
2721 if (!usePopup && count >= d->maxVisibleItems) {
2728 listHeight += (count - 1) * container->spacing();
2729 listRect.setHeight(listHeight);
2734 int heightMargin = container->topMargin() + container->bottomMargin();
2737 const QMargins cm = container->contentsMargins();
2738 heightMargin += cm.top() + cm.bottom();
2741 const QMargins vm = view()->contentsMargins();
2742 heightMargin += vm.top() + vm.bottom();
2743 heightMargin +=
static_cast<QAbstractScrollAreaPrivate *>(QObjectPrivate::get(view()))->top;
2744 heightMargin +=
static_cast<QAbstractScrollAreaPrivate *>(QObjectPrivate::get(view()))->bottom;
2746 listRect.setHeight(listRect.height() + heightMargin);
2751 listRect.setHeight(listRect.height() + style->pixelMetric(QStyle::PM_MenuVMargin, &opt,
this) * 2);
2755 const int diff = d->computeWidthHint() - width();
2757 listRect.setWidth(listRect.width() + diff);
2761 container->layout()->activate();
2763 listRect.setSize( listRect.size().expandedTo(container->minimumSize())
2764 .boundedTo(container->maximumSize()));
2767 if (boundToScreen) {
2768 if (listRect.width() > screen.width() )
2769 listRect.setWidth(screen.width());
2770 if (mapToGlobal(listRect.bottomRight()).x() > screen.right()) {
2771 below.setX(screen.x() + screen.width() - listRect.width());
2772 above.setX(screen.x() + screen.width() - listRect.width());
2774 if (mapToGlobal(listRect.topLeft()).x() < screen.x() ) {
2775 below.setX(screen.x());
2776 above.setX(screen.x());
2782 listRect.moveLeft(above.x());
2791 view()->scrollToTop();
2792 const QRect currentItemRect = view()->visualRect(view()->currentIndex());
2793 const int offset = listRect.top() - currentItemRect.top();
2794 listRect.moveTop(above.y() + offset - listRect.top());
2799 const int height = !boundToScreen ? listRect.height() : qMin(listRect.height(), screen.height());
2800 listRect.setHeight(height);
2802 if (boundToScreen) {
2803 if (listRect.top() < screen.top())
2804 listRect.moveTop(screen.top());
2805 if (listRect.bottom() > screen.bottom())
2806 listRect.moveBottom(screen.bottom());
2808 }
else if (!boundToScreen || listRect.height() <= belowHeight) {
2809 listRect.moveTopLeft(below);
2810 }
else if (listRect.height() <= aboveHeight) {
2811 listRect.moveBottomLeft(above);
2812 }
else if (belowHeight >= aboveHeight) {
2813 listRect.setHeight(belowHeight);
2814 listRect.moveTopLeft(below);
2816 listRect.setHeight(aboveHeight);
2817 listRect.moveBottomLeft(above);
2821 QGuiApplication::inputMethod()->reset();
2824 const QScrollBar *sb = view()->horizontalScrollBar();
2825 const auto needHorizontalScrollBar = [
this, sb]{
2826 const Qt::ScrollBarPolicy policy = view()->horizontalScrollBarPolicy();
2827 return (policy == Qt::ScrollBarAsNeeded || policy == Qt::ScrollBarAlwaysOn)
2828 && sb->minimum() < sb->maximum();
2830 const bool neededHorizontalScrollBar = needHorizontalScrollBar();
2831 if (neededHorizontalScrollBar)
2832 listRect.adjust(0, 0, 0, sb->height());
2837 container->hideScrollers();
2838 container->setGeometry(listRect);
2841 const bool updatesEnabled = container->updatesEnabled();
2844#if QT_CONFIG(effects)
2845 bool scrollDown = (listRect.topLeft() == below);
2846 if (QApplication::isEffectEnabled(Qt::UI_AnimateCombo)
2847 && !style->styleHint(QStyle::SH_ComboBox_Popup, &opt,
this) && !window()->testAttribute(Qt::WA_DontShowOnScreen))
2848 qScrollEffect(container, scrollDown ? QEffects::DownScroll : QEffects::UpScroll, 150);
2857 container->setUpdatesEnabled(
false);
2860 bool startTimer = !container->isVisible();
2862 container->create();
2863 if (QWindow *containerWindow = qt_widget_private(container)->windowHandle(QWidgetPrivate::WindowHandleMode::TopLevel)) {
2864 QScreen *currentScreen = d->associatedScreen();
2865 if (currentScreen && !currentScreen->virtualSiblings().contains(containerWindow->screen())) {
2866 containerWindow->setScreen(currentScreen);
2875#if QT_CONFIG(wayland)
2876 if (
auto waylandWindow =
dynamic_cast<QNativeInterface::Private::QWaylandWindow*>(container->windowHandle()->handle())) {
2877 const QRect popup(style->subControlRect(QStyle::CC_ComboBox, &opt,
2878 QStyle::SC_ComboBoxListBoxPopup,
this));
2879 const QRect controlGeometry = QRect(mapTo(window(), popup.topLeft()), popup.size());
2880 waylandWindow->setParentControlGeometry(controlGeometry);
2881 waylandWindow->setExtendedWindowType(QNativeInterface::Private::QWaylandWindow::ComboBox);
2886 if (!neededHorizontalScrollBar && needHorizontalScrollBar()) {
2887 listRect.adjust(0, 0, 0, sb->height());
2888 container->setGeometry(listRect);
2891 container->updateScrollers();
2894 view()->scrollTo(view()->currentIndex(),
2895 style->styleHint(QStyle::SH_ComboBox_Popup, &opt,
this)
2896 ? QAbstractItemView::PositionAtCenter
2897 : QAbstractItemView::EnsureVisible);
2900 container->setUpdatesEnabled(updatesEnabled);
2903 container->update();
2905 container->popupTimer.start();
2906 container->maybeIgnoreMouseButtonRelease =
true;
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920void QComboBox::hidePopup()
2925 d->hidingPopup =
true;
2927 auto resetHidingPopup = qScopeGuard([d]{
2928 d->hidingPopup =
false;
2931 if (!d->container || !d->container->isVisible())
2934#if QT_CONFIG(effects)
2935 QItemSelectionModel *selectionModel = d->container->itemView()
2936 ? d->container->itemView()->selectionModel() :
nullptr;
2938 if (style()->styleHint(QStyle::SH_Menu_FlashTriggeredItem,
nullptr,
this) &&
2939 selectionModel && selectionModel->hasSelection()) {
2940 const QItemSelection selection = selectionModel->selection();
2942 QTimer::singleShot(0, d->container, [d, selection, selectionModel]{
2943 QSignalBlocker modelBlocker(d->model);
2944 QSignalBlocker viewBlocker(d->container->itemView());
2945 QSignalBlocker containerBlocker(d->container);
2948 selectionModel->select(selection, QItemSelectionModel::Toggle);
2949 QTimer::singleShot(60, d->container, [d, selection, selectionModel]{
2950 QSignalBlocker modelBlocker(d->model);
2951 QSignalBlocker viewBlocker(d->container->itemView());
2952 QSignalBlocker containerBlocker(d->container);
2953 selectionModel->select(selection, QItemSelectionModel::Toggle);
2954 QTimer::singleShot(20, d->container, [d] {
2966void QComboBoxPrivate::doHidePopup()
2968 if (container && container->isVisible())
2974void QComboBoxPrivate::updateCurrentText(
const QString &text)
2976 if (text == currentText)
2980 emit q_func()->currentTextChanged(text);
2984
2985
2986
2987
2988
2989void QComboBox::clear()
2992 d->model->removeRows(0, d->model->rowCount(d->root), d->root);
2993#if QT_CONFIG(accessibility)
2994 QAccessibleValueChangeEvent event(
this, QString());
2995 QAccessible::updateAccessibility(&event);
3000
3001
3002void QComboBox::clearEditText()
3006 d->lineEdit->clear();
3007#if QT_CONFIG(accessibility)
3008 QAccessibleValueChangeEvent event(
this, QString());
3009 QAccessible::updateAccessibility(&event);
3014
3015
3016void QComboBox::setEditText(
const QString &text)
3020 d->lineEdit->setText(text);
3021#if QT_CONFIG(accessibility)
3022 QAccessibleValueChangeEvent event(
this, text);
3023 QAccessible::updateAccessibility(&event);
3028
3029
3030void QComboBox::focusInEvent(QFocusEvent *e)
3035 d->lineEdit->event(e);
3036#if QT_CONFIG(completer)
3037 if (d->lineEdit->completer())
3038 d->lineEdit->completer()->setWidget(
this);
3044
3045
3046void QComboBox::focusOutEvent(QFocusEvent *e)
3051 d->lineEdit->event(e);
3055void QComboBox::changeEvent(QEvent *e)
3058 switch (e->type()) {
3059 case QEvent::StyleChange:
3061 d->container->updateStyleSettings();
3062 d->updateDelegate();
3065 case QEvent::MacSizeChange:
3067 d->sizeHint = QSize();
3068 d->minimumSizeHint = QSize();
3069 d->updateLayoutDirection();
3071 d->updateLineEditGeometry();
3072 d->setLayoutItemMargins(QStyle::SE_ComboBoxLayoutItem);
3074 if (e->type() == QEvent::MacSizeChange) {
3075 QPlatformTheme::Font f = QPlatformTheme::SystemFont;
3076 if (testAttribute(Qt::WA_MacSmallSize))
3077 f = QPlatformTheme::SmallFont;
3078 else if (testAttribute(Qt::WA_MacMiniSize))
3079 f = QPlatformTheme::MiniFont;
3080 if (
const QFont *platformFont = QApplicationPrivate::platformTheme()->font(f)) {
3082 f.setPointSizeF(platformFont->pointSizeF());
3088 case QEvent::EnabledChange:
3092 case QEvent::PaletteChange: {
3093 d->updateViewContainerPaletteAndOpacity();
3096 case QEvent::FontChange: {
3097 d->sizeHint = QSize();
3098 d->viewContainer()->setFont(font());
3099 d->viewContainer()->itemView()->doItemsLayout();
3101 d->updateLineEditGeometry();
3107 QWidget::changeEvent(e);
3111
3112
3113void QComboBox::resizeEvent(QResizeEvent *)
3116 d->updateLineEditGeometry();
3120
3121
3122void QComboBox::paintEvent(QPaintEvent *)
3125 QStylePainter painter(
this);
3126 painter.setPen(palette().color(QPalette::Text));
3129 QStyleOptionComboBox opt;
3130 initStyleOption(&opt);
3131 painter.drawComplexControl(QStyle::CC_ComboBox, opt);
3133 if (currentIndex() < 0 && !placeholderText().isEmpty()) {
3134 opt.palette.setBrush(QPalette::ButtonText, opt.palette.placeholderText());
3135 opt.currentText = placeholderText();
3139 if (itemDelegate() && labelDrawingMode() == QComboBox::LabelDrawingMode::UseDelegate) {
3140 QStyleOptionViewItem itemOption;
3141 d->initViewItemOption(&itemOption);
3142 itemOption.rect = style()->subControlRect(QStyle::CC_ComboBox, &opt,
3143 QStyle::SC_ComboBoxEditField,
this);
3144 itemDelegate()->paint(&painter, itemOption, d->currentIndex);
3147 painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
3152
3153
3154void QComboBox::showEvent(QShowEvent *e)
3157 if (!d->shownOnce && d->sizeAdjustPolicy == QComboBox::AdjustToContentsOnFirstShow) {
3158 d->sizeHint = QSize();
3161 d->shownOnce =
true;
3162 QWidget::showEvent(e);
3166
3167
3168void QComboBox::hideEvent(QHideEvent *)
3174
3175
3176bool QComboBox::event(QEvent *event)
3179 switch(event->type()) {
3180 case QEvent::LayoutDirectionChange:
3181 case QEvent::ApplicationLayoutDirectionChange:
3182 d->updateLayoutDirection();
3183 d->updateLineEditGeometry();
3185 case QEvent::HoverEnter:
3186 case QEvent::HoverLeave:
3187 case QEvent::HoverMove:
3188 if (
const QHoverEvent *he =
static_cast<
const QHoverEvent *>(event))
3189 d->updateHoverControl(he->position().toPoint());
3191 case QEvent::ShortcutOverride:
3193 return d->lineEdit->event(event);
3195#ifdef QT_KEYPAD_NAVIGATION
3196 case QEvent::EnterEditFocus:
3198 d->lineEdit->event(event);
3200 case QEvent::LeaveEditFocus:
3202 d->lineEdit->event(event);
3208 return QWidget::event(event);
3212
3213
3214void QComboBox::mousePressEvent(QMouseEvent *e)
3217 if (!QGuiApplication::styleHints()->setFocusOnTouchRelease())
3218 d->showPopupFromMouseEvent(e);
3221void QComboBoxPrivate::showPopupFromMouseEvent(QMouseEvent *e)
3224 QStyleOptionComboBox opt;
3225 q->initStyleOption(&opt);
3226 QStyle::SubControl sc = q->style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt, e->position().toPoint(), q);
3228 if (e->button() == Qt::LeftButton
3229 && !(sc == QStyle::SC_None && e->type() == QEvent::MouseButtonRelease)
3230 && (sc == QStyle::SC_ComboBoxArrow || !q->isEditable())
3231 && !viewContainer()->isVisible()) {
3232 if (sc == QStyle::SC_ComboBoxArrow)
3233 updateArrow(QStyle::State_Sunken);
3234#ifdef QT_KEYPAD_NAVIGATION
3242 viewContainer()->initialClickPosition = q->mapToGlobal(e->position().toPoint());
3244 QPointer<QComboBox> guard = q;
3251 if (viewContainer()) {
3252 viewContainer()->blockMouseReleaseTimer.start(QApplication::doubleClickInterval());
3253 viewContainer()->maybeIgnoreMouseButtonRelease =
false;
3256#ifdef QT_KEYPAD_NAVIGATION
3257 if (QApplicationPrivate::keypadNavigationEnabled() && sc == QStyle::SC_ComboBoxEditField && lineEdit) {
3267
3268
3269void QComboBox::mouseReleaseEvent(QMouseEvent *e)
3272 d->updateArrow(QStyle::State_None);
3273 if (QGuiApplication::styleHints()->setFocusOnTouchRelease() && hasFocus())
3274 d->showPopupFromMouseEvent(e);
3278
3279
3280void QComboBox::keyPressEvent(QKeyEvent *e)
3284#if QT_CONFIG(completer)
3285 if (
const auto *cmpltr = completer()) {
3286 const auto *popup = QCompleterPrivate::get(cmpltr)->popup;
3287 if (popup && popup->isVisible()) {
3289 d->lineEdit->event(e);
3295 enum Move { NoMove=0 , MoveUp , MoveDown , MoveFirst , MoveLast};
3298 int newIndex = currentIndex();
3300 bool pressLikeButton = !d->lineEdit;
3301#ifdef QT_KEYPAD_NAVIGATION
3302 pressLikeButton |= QApplicationPrivate::keypadNavigationEnabled() && !hasEditFocus();
3304 auto key = e->key();
3305 if (pressLikeButton) {
3306 const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()
3307 ->themeHint(QPlatformTheme::ButtonPressKeys)
3308 .value<QList<Qt::Key>>();
3309 if (buttonPressKeys.contains(key)) {
3317 if (e->modifiers() & Qt::ControlModifier)
3320 case Qt::Key_PageUp:
3321#ifdef QT_KEYPAD_NAVIGATION
3322 if (QApplicationPrivate::keypadNavigationEnabled())
3329 if (e->modifiers() & Qt::AltModifier) {
3332 }
else if (e->modifiers() & Qt::ControlModifier)
3335 case Qt::Key_PageDown:
3336#ifdef QT_KEYPAD_NAVIGATION
3337 if (QApplicationPrivate::keypadNavigationEnabled())
3352 if (!e->modifiers()) {
3358 case Qt::Key_Return:
3359 case Qt::Key_Escape:
3363#ifdef QT_KEYPAD_NAVIGATION
3366 if (QApplicationPrivate::keypadNavigationEnabled() && !hasEditFocus())
3370 if (QApplicationPrivate::keypadNavigationEnabled()) {
3371 if (!hasEditFocus() || !d->lineEdit)
3379#if QT_CONFIG(shortcut)
3380 if (d->container && d->container->isVisible() && e->matches(QKeySequence::Cancel)) {
3387 const auto text = e->text();
3388 if (!text.isEmpty() && text.at(0).isPrint())
3389 d->keyboardSearchString(text);
3395 const int rowCount = count();
3397 if (move != NoMove) {
3405 while (newIndex < rowCount && !(d->model->index(newIndex, d->modelColumn, d->root).flags() & Qt::ItemIsEnabled))
3409 newIndex = rowCount;
3413 while ((newIndex >= 0) && !(d->model->flags(d->model->index(newIndex,d->modelColumn,d->root)) & Qt::ItemIsEnabled))
3421 if (newIndex >= 0 && newIndex < rowCount && newIndex != currentIndex()) {
3422 setCurrentIndex(newIndex);
3423 d->emitActivated(d->currentIndex);
3425 }
else if (d->lineEdit) {
3426 d->lineEdit->event(e);
3432
3433
3434void QComboBox::keyReleaseEvent(QKeyEvent *e)
3438 d->lineEdit->event(e);
3440 QWidget::keyReleaseEvent(e);
3444
3445
3446#if QT_CONFIG(wheelevent)
3447void QComboBox::wheelEvent(QWheelEvent *e)
3450 QStyleOptionComboBox opt;
3451 initStyleOption(&opt);
3452 if (style()->styleHint(QStyle::SH_ComboBox_AllowWheelScrolling, &opt,
this) &&
3453 !d->viewContainer()->isVisible()) {
3454 const int rowCount = count();
3455 int newIndex = currentIndex();
3456 int delta = e->angleDelta().y();
3460 while ((newIndex >= 0) && !(d->model->flags(d->model->index(newIndex,d->modelColumn,d->root)) & Qt::ItemIsEnabled))
3462 }
else if (delta < 0) {
3464 while (newIndex < rowCount && !(d->model->index(newIndex, d->modelColumn, d->root).flags() & Qt::ItemIsEnabled))
3468 if (newIndex >= 0 && newIndex < rowCount && newIndex != currentIndex()) {
3469 setCurrentIndex(newIndex);
3470 d->emitActivated(d->currentIndex);
3479#ifndef QT_NO_CONTEXTMENU
3481
3482
3483void QComboBox::contextMenuEvent(QContextMenuEvent *e)
3487 Qt::ContextMenuPolicy p = d->lineEdit->contextMenuPolicy();
3488 d->lineEdit->setContextMenuPolicy(Qt::DefaultContextMenu);
3489 d->lineEdit->event(e);
3490 d->lineEdit->setContextMenuPolicy(p);
3495void QComboBoxPrivate::keyboardSearchString(
const QString &text)
3498 QAbstractItemView *view = viewContainer()->itemView();
3499 view->setCurrentIndex(currentIndex);
3500 int currentRow = view->currentIndex().row();
3501 view->keyboardSearch(text);
3502 if (currentRow != view->currentIndex().row()) {
3503 setCurrentIndex(view->currentIndex());
3504 emitActivated(currentIndex);
3508void QComboBoxPrivate::modelChanged()
3512 if (sizeAdjustPolicy == QComboBox::AdjustToContents) {
3514 adjustComboBoxSize();
3515 q->updateGeometry();
3520
3521
3522void QComboBox::inputMethodEvent(QInputMethodEvent *e)
3526 d->lineEdit->event(e);
3528 if (!e->commitString().isEmpty())
3529 d->keyboardSearchString(e->commitString());
3536
3537
3538QVariant QComboBox::inputMethodQuery(Qt::InputMethodQuery query)
const
3540 Q_D(
const QComboBox);
3542 return d->lineEdit->inputMethodQuery(query);
3543 return QWidget::inputMethodQuery(query);
3547
3548QVariant QComboBox::inputMethodQuery(Qt::InputMethodQuery query,
const QVariant &argument)
const
3550 Q_D(
const QComboBox);
3552 return d->lineEdit->inputMethodQuery(query, argument);
3553 return QWidget::inputMethodQuery(query);
3557
3558
3559
3560
3561
3562
3565
3566
3567
3568
3569
3570
3571
3574
3575
3576
3577
3578
3581
3582
3583
3584
3585
3588
3589
3590
3591
3592
3593
3594
3595bool QComboBox::hasFrame()
const
3597 Q_D(
const QComboBox);
3602void QComboBox::setFrame(
bool enable)
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623int QComboBox::modelColumn()
const
3625 Q_D(
const QComboBox);
3626 return d->modelColumn;
3629void QComboBox::setModelColumn(
int visibleColumn)
3632 d->modelColumn = visibleColumn;
3633 QListView *lv = qobject_cast<QListView *>(d->viewContainer()->itemView());
3635 lv->setModelColumn(visibleColumn);
3636#if QT_CONFIG(completer)
3637 if (d->lineEdit && d->lineEdit->completer())
3638 d->lineEdit->completer()->setCompletionColumn(visibleColumn);
3640 setCurrentIndex(currentIndex());
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669QComboBox::LabelDrawingMode QComboBox::labelDrawingMode()
const
3671 Q_D(
const QComboBox);
3672 return d->labelDrawingMode;
3675void QComboBox::setLabelDrawingMode(LabelDrawingMode drawingLabel)
3678 if (d->labelDrawingMode != drawingLabel) {
3679 d->labelDrawingMode = drawingLabel;
3686#include "moc_qcombobox.cpp"
3687#include "moc_qcombobox_p.cpp"
Combined button and popup list for selecting options.