7#include <qstylepainter.h>
8#include <qpa/qplatformtheme.h>
9#include <qpa/qplatformmenu.h>
11#include <qapplication.h>
13#if QT_CONFIG(tableview)
14#include <qtableview.h>
16#include <qabstractitemdelegate.h>
23#include <qscrollbar.h>
24#if QT_CONFIG(treeview)
27#include <qheaderview.h>
29#include <qmetaobject.h>
30#if QT_CONFIG(proxymodel)
31#include <qabstractproxymodel.h>
33#include <qstylehints.h>
34#include <private/qguiapplication_p.h>
35#include <private/qhighdpiscaling_p.h>
36#include <private/qapplication_p.h>
37#include <private/qcombobox_p.h>
38#include <private/qabstractitemmodel_p.h>
39#include <private/qabstractscrollarea_p.h>
40#include <private/qlineedit_p.h>
41#if QT_CONFIG(completer)
42#include <private/qcompleter_p.h>
46# include <private/qeffects_p.h>
48#include <private/qstyle_p.h>
49#if QT_CONFIG(accessibility)
50#include "qaccessible.h"
54#include <QtCore/qpointer.h>
58using namespace Qt::StringLiterals;
60QComboBoxPrivate::QComboBoxPrivate()
63 duplicatesEnabled(
false),
70QComboBoxPrivate::~QComboBoxPrivate()
78QStyleOptionMenuItem QComboMenuDelegate::getStyleOption(
const QStyleOptionViewItem &option,
79 const QModelIndex &index)
const
81 QStyleOptionMenuItem menuOption;
83 QPalette resolvedpalette = option.palette.resolve(QApplication::palette(
"QMenu"));
84 QVariant value = index.data(Qt::ForegroundRole);
85 if (value.canConvert<QBrush>()) {
86 resolvedpalette.setBrush(QPalette::WindowText, qvariant_cast<QBrush>(value));
87 resolvedpalette.setBrush(QPalette::ButtonText, qvariant_cast<QBrush>(value));
88 resolvedpalette.setBrush(QPalette::Text, qvariant_cast<QBrush>(value));
90 menuOption.palette = resolvedpalette;
91 menuOption.state = QStyle::State_None;
92 if (mCombo->window()->isActiveWindow())
93 menuOption.state = QStyle::State_Active;
94 if ((option.state & QStyle::State_Enabled) && (index.model()->flags(index) & Qt::ItemIsEnabled))
95 menuOption.state |= QStyle::State_Enabled;
97 menuOption.palette.setCurrentColorGroup(QPalette::Disabled);
98 if (option.state & QStyle::State_Selected)
99 menuOption.state |= QStyle::State_Selected;
100 menuOption.checkType = QStyleOptionMenuItem::NonExclusive;
102 const QVariant checkState = index.data(Qt::CheckStateRole);
103 if (!checkState.isValid()) {
104 menuOption.checked = mCombo->currentIndex() == index.row();
106 menuOption.checked = qvariant_cast<
int>(checkState) == Qt::Checked;
107 menuOption.state |= qvariant_cast<
int>(checkState) == Qt::Checked
108 ? QStyle::State_On : QStyle::State_Off;
110 if (QComboBoxDelegate::isSeparator(index))
111 menuOption.menuItemType = QStyleOptionMenuItem::Separator;
113 menuOption.menuItemType = QStyleOptionMenuItem::Normal;
115 const QVariant variant = index.data(Qt::DecorationRole);
116 switch (variant.userType()) {
117 case QMetaType::QIcon:
118 menuOption.icon = qvariant_cast<QIcon>(variant);
120 case QMetaType::QColor: {
121 static QPixmap pixmap(option.decorationSize);
122 pixmap.fill(qvariant_cast<QColor>(variant));
123 menuOption.icon = pixmap;
126 menuOption.icon = qvariant_cast<QPixmap>(variant);
129 if (index.data(Qt::BackgroundRole).canConvert<QBrush>()) {
130 menuOption.palette.setBrush(QPalette::All, QPalette::Window,
131 qvariant_cast<QBrush>(index.data(Qt::BackgroundRole)));
133 menuOption.text = index.data(Qt::DisplayRole).toString().replace(u'&',
"&&"_L1);
134 menuOption.reservedShortcutWidth = 0;
135 menuOption.maxIconWidth = option.decorationSize.width() + 4;
136 menuOption.menuRect = option.rect;
137 menuOption.rect = option.rect;
141 QVariant fontRoleData = index.data(Qt::FontRole);
142 if (fontRoleData.isValid()) {
143 menuOption.font = qvariant_cast<QFont>(fontRoleData);
144 }
else if (mCombo->testAttribute(Qt::WA_SetFont)
145 || mCombo->testAttribute(Qt::WA_MacSmallSize)
146 || mCombo->testAttribute(Qt::WA_MacMiniSize)
147 || mCombo->font() != qt_app_fonts_hash()->value(
"QComboBox", QFont())) {
148 menuOption.font = mCombo->font();
150 menuOption.font = qt_app_fonts_hash()->value(
"QComboMenuItem", mCombo->font());
153 menuOption.fontMetrics = QFontMetrics(menuOption.font);
158bool QComboMenuDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
159 const QStyleOptionViewItem &option,
const QModelIndex &index)
165 Qt::ItemFlags flags = model->flags(index);
166 if (!(flags & Qt::ItemIsUserCheckable) || !(option.state & QStyle::State_Enabled)
167 || !(flags & Qt::ItemIsEnabled))
171 const QVariant checkState = index.data(Qt::CheckStateRole);
172 if (!checkState.isValid())
176 if ((event->type() == QEvent::MouseButtonRelease)
177 || (event->type() == QEvent::MouseButtonDblClick)
178 || (event->type() == QEvent::MouseButtonPress)) {
179 QMouseEvent *me =
static_cast<QMouseEvent*>(event);
180 if (me->button() != Qt::LeftButton)
183 if ((event->type() == QEvent::MouseButtonPress)
184 || (event->type() == QEvent::MouseButtonDblClick)) {
185 pressedIndex = index.row();
189 if (index.row() != pressedIndex)
193 }
else if (event->type() == QEvent::KeyPress) {
194 if (
static_cast<QKeyEvent*>(event)->key() != Qt::Key_Space
195 &&
static_cast<QKeyEvent*>(event)->key() != Qt::Key_Select)
202 Qt::CheckState newState = (
static_cast<Qt::CheckState>(checkState.toInt()) == Qt::Checked)
203 ? Qt::Unchecked : Qt::Checked;
204 return model->setData(index, newState, Qt::CheckStateRole);
207#if QT_CONFIG(completer)
208void QComboBoxPrivate::completerActivated(
const QModelIndex &index)
211#if QT_CONFIG(proxymodel)
212 if (index.isValid() && q->completer()) {
213 QAbstractProxyModel *proxy = qobject_cast<QAbstractProxyModel *>(q->completer()->completionModel());
215 const QModelIndex &completerIndex = proxy->mapToSource(index);
217 if (completerIndex.model() == model) {
218 row = completerIndex.row();
221 QAbstractProxyModel *completerProxy = qobject_cast<QAbstractProxyModel *>(q->completer()->model());
222 if (completerProxy && completerProxy->sourceModel() == model) {
223 row = completerProxy->mapToSource(completerIndex).row();
225 QString match = q->completer()->model()->data(completerIndex).toString();
226 row = q->findText(match, matchFlags());
229 q->setCurrentIndex(row);
230 emitActivated(currentIndex);
237void QComboBoxPrivate::updateArrow(QStyle::StateFlag state)
240 if (arrowState == state)
243 QStyleOptionComboBox opt;
244 q->initStyleOption(&opt);
245 q->update(q->rect());
248void QComboBoxPrivate::modelReset()
252 lineEdit->setText(QString());
253 updateLineEditGeometry();
260void QComboBoxPrivate::modelDestroyed()
262 model = QAbstractItemModelPrivate::staticEmptyModel();
265void QComboBoxPrivate::trySetValidIndex()
268 bool currentReset =
false;
270 const int rowCount = q->count();
271 for (
int pos = 0; pos < rowCount; ++pos) {
272 const QModelIndex idx(model->index(pos, modelColumn, root));
273 if (idx.flags() & Qt::ItemIsEnabled) {
274 setCurrentIndex(idx);
281 setCurrentIndex(QModelIndex());
284QRect QComboBoxPrivate::popupGeometry(
const QPoint &globalPosition)
const
286 Q_Q(
const QComboBox);
287 return QStylePrivate::useFullScreenForPopup()
288 ? QWidgetPrivate::screenGeometry(q, globalPosition)
289 : QWidgetPrivate::availableScreenGeometry(q, globalPosition);
292bool QComboBoxPrivate::updateHoverControl(
const QPoint &pos)
296 QRect lastHoverRect = hoverRect;
297 QStyle::SubControl lastHoverControl = hoverControl;
298 bool doesHover = q->testAttribute(Qt::WA_Hover);
299 if (lastHoverControl != newHoverControl(pos) && doesHover) {
300 q->update(lastHoverRect);
301 q->update(hoverRect);
307QStyle::SubControl QComboBoxPrivate::newHoverControl(
const QPoint &pos)
310 QStyleOptionComboBox opt;
311 q->initStyleOption(&opt);
312 opt.subControls = QStyle::SC_All;
313 hoverControl = q->style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt, pos, q);
314 hoverRect = (hoverControl != QStyle::SC_None)
315 ? q->style()->subControlRect(QStyle::CC_ComboBox, &opt, hoverControl, q)
321
322
323
324int QComboBoxPrivate::computeWidthHint()
const
326 Q_Q(
const QComboBox);
329 const int count = q->count();
330 const int iconWidth = q->iconSize().width() + 4;
331 const QFontMetrics &fontMetrics = q->fontMetrics();
333 for (
int i = 0; i < count; ++i) {
334 const int textWidth = fontMetrics.horizontalAdvance(q->itemText(i));
335 if (q->itemIcon(i).isNull())
336 width = (qMax(width, textWidth));
338 width = (qMax(width, textWidth + iconWidth));
341 QStyleOptionComboBox opt;
342 q->initStyleOption(&opt);
344 tmp = q->style()->sizeFromContents(QStyle::CT_ComboBox, &opt, tmp, q);
348QSize QComboBoxPrivate::recomputeSizeHint(QSize &sh)
const
350 Q_Q(
const QComboBox);
352 if (q->itemDelegate() && q->labelDrawingMode() == QComboBox::LabelDrawingMode::UseDelegate) {
353 QStyleOptionViewItem option;
354 initViewItemOption(&option);
355 sh = q->itemDelegate()->sizeHint(option, currentIndex);
358 bool hasIcon = sizeAdjustPolicy == QComboBox::AdjustToMinimumContentsLengthWithIcon;
359 int count = q->count();
360 QSize iconSize = q->iconSize();
361 const QFontMetrics &fm = q->fontMetrics();
364 if (&sh == &sizeHint || minimumContentsLength == 0) {
365 switch (sizeAdjustPolicy) {
366 case QComboBox::AdjustToContents:
367 case QComboBox::AdjustToContentsOnFirstShow:
369 sh.rwidth() = 7 * fm.horizontalAdvance(u'x');
371 for (
int i = 0; i < count; ++i) {
372 if (!q->itemIcon(i).isNull()) {
374 sh.setWidth(qMax(sh.width(), fm.boundingRect(q->itemText(i)).width() + iconSize.width() + 4));
376 sh.setWidth(qMax(sh.width(), fm.boundingRect(q->itemText(i)).width()));
381 case QComboBox::AdjustToMinimumContentsLengthWithIcon:
385 for (
int i = 0; i < count && !hasIcon; ++i)
386 hasIcon = !q->itemIcon(i).isNull();
388 if (minimumContentsLength > 0) {
389 auto r = qint64{minimumContentsLength} * fm.horizontalAdvance(u'X');
391 r += iconSize.width() + 4;
392 if (r <= QWIDGETSIZE_MAX) {
393 sh.setWidth(qMax(sh.width(),
int(r)));
395 qWarning(
"QComboBox: cannot take minimumContentsLength %d into account for sizeHint(), "
396 "since it causes the widget to be wider than QWIDGETSIZE_MAX. "
397 "Consider setting it to a less extreme value.",
398 minimumContentsLength);
401 if (!placeholderText.isEmpty())
402 sh.setWidth(qMax(sh.width(), fm.boundingRect(placeholderText).width()));
406 sh.setHeight(qMax(qCeil(QFontMetricsF(fm).height()), 14) + 2);
408 sh.setHeight(qMax(sh.height(), iconSize.height() + 2));
412 QStyleOptionComboBox opt;
413 q->initStyleOption(&opt);
414 sh = q->style()->sizeFromContents(QStyle::CT_ComboBox, &opt, sh, q);
419void QComboBoxPrivate::adjustComboBoxSize()
421 viewContainer()->adjustSizeTimer.start(20, container);
424void QComboBoxPrivate::updateLayoutDirection()
426 Q_Q(
const QComboBox);
427 QStyleOptionComboBox opt;
428 q->initStyleOption(&opt);
429 Qt::LayoutDirection dir = Qt::LayoutDirection(
430 q->style()->styleHint(QStyle::SH_ComboBox_LayoutDirection, &opt, q));
432 lineEdit->setLayoutDirection(dir);
434 container->setLayoutDirection(dir);
438void QComboBoxPrivateContainer::timerEvent(QTimerEvent *timerEvent)
440 if (timerEvent->timerId() == adjustSizeTimer.timerId()) {
441 adjustSizeTimer.stop();
442 if (combo->sizeAdjustPolicy() == QComboBox::AdjustToContents) {
443 combo->updateGeometry();
450void QComboBoxPrivateContainer::resizeEvent(QResizeEvent *e)
452 QStyleOptionComboBox opt = comboStyleOption();
453 if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo)) {
455 myOpt.initFrom(
this);
456 QStyleHintReturnMask mask;
457 if (combo->style()->styleHint(QStyle::SH_Menu_Mask, &myOpt,
this, &mask)) {
458 setMask(mask.region);
463 QFrame::resizeEvent(e);
466void QComboBoxPrivateContainer::paintEvent(QPaintEvent *e)
468 QStyleOptionComboBox cbOpt = comboStyleOption();
469 if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &cbOpt, combo)
470 && mask().isEmpty()) {
474 style()->drawPrimitive(QStyle::PE_PanelMenu, &opt, &p,
this);
477 QFrame::paintEvent(e);
480QComboBoxPrivateContainer::QComboBoxPrivateContainer(QAbstractItemView *itemView, QComboBox *parent)
481 : QFrame(parent, Qt::Popup), combo(parent)
487 setAttribute(Qt::WA_WindowPropagation);
488 setAttribute(Qt::WA_X11NetWmWindowTypeCombo);
491 blockMouseReleaseTimer.setSingleShot(
true);
494 QBoxLayout *layout =
new QBoxLayout(QBoxLayout::TopToBottom,
this);
495 layout->setSpacing(0);
496 layout->setContentsMargins(QMargins());
499 setItemView(itemView);
502 QStyleOptionComboBox opt = comboStyleOption();
503 const bool usePopup = combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo);
505 top =
new QComboBoxPrivateScroller(QAbstractSlider::SliderSingleStepSub,
this);
506 bottom =
new QComboBoxPrivateScroller(QAbstractSlider::SliderSingleStepAdd,
this);
514 layout->insertWidget(0, top);
515 connect(top, &QComboBoxPrivateScroller::doScroll,
516 this, &QComboBoxPrivateContainer::scrollItemView);
519 layout->addWidget(bottom);
520 connect(bottom, &QComboBoxPrivateScroller::doScroll,
521 this, &QComboBoxPrivateContainer::scrollItemView);
525 layout->insertSpacing(0, 0);
526 layout->addSpacing(0);
527 updateStyleSettings();
530QComboBoxPrivateContainer::~QComboBoxPrivateContainer()
532 disconnect(view, &QAbstractItemView::destroyed,
533 this, &QComboBoxPrivateContainer::viewDestroyed);
536void QComboBoxPrivateContainer::scrollItemView(
int action)
538#if QT_CONFIG(scrollbar)
539 if (view->verticalScrollBar())
540 view->verticalScrollBar()->triggerAction(
static_cast<QAbstractSlider::SliderAction>(action));
544void QComboBoxPrivateContainer::hideScrollers()
553
554
555void QComboBoxPrivateContainer::updateScrollers()
557#if QT_CONFIG(scrollbar)
561 if (isVisible() ==
false)
564 QStyleOptionComboBox opt = comboStyleOption();
565 if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo) &&
566 view->verticalScrollBar()->minimum() < view->verticalScrollBar()->maximum()) {
568 bool needTop = view->verticalScrollBar()->value()
569 > (view->verticalScrollBar()->minimum() + topMargin());
570 bool needBottom = view->verticalScrollBar()->value()
571 < (view->verticalScrollBar()->maximum() - bottomMargin() - topMargin());
588
589
590void QComboBoxPrivateContainer::viewDestroyed()
593 setItemView(
new QComboBoxListView());
597
598
599QAbstractItemView *QComboBoxPrivateContainer::itemView()
const
605
606
607void QComboBoxPrivateContainer::setItemView(QAbstractItemView *itemView)
613 view->removeEventFilter(
this);
614 view->viewport()->removeEventFilter(
this);
615#if QT_CONFIG(scrollbar)
616 disconnect(view->verticalScrollBar(), &QScrollBar::valueChanged,
617 this, &QComboBoxPrivateContainer::updateScrollers);
618 disconnect(view->verticalScrollBar(), &QScrollBar::rangeChanged,
619 this, &QComboBoxPrivateContainer::updateScrollers);
621 disconnect(view, &QAbstractItemView::destroyed,
622 this, &QComboBoxPrivateContainer::viewDestroyed);
624 if (isAncestorOf(view))
631 view->setParent(
this);
632 view->setAttribute(Qt::WA_MacShowFocusRect,
false);
633 qobject_cast<QBoxLayout*>(layout())->insertWidget(top ? 2 : 0, view);
634 view->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
635 view->installEventFilter(
this);
636 view->viewport()->installEventFilter(
this);
637 view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
638 QStyleOptionComboBox opt = comboStyleOption();
639 const bool usePopup = combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo);
640#if QT_CONFIG(scrollbar)
642 view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
645 combo->style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking_Current, &opt, combo) ||
646 combo->style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking_Active, &opt, combo)
648 view->setMouseTracking(
true);
650 view->setSelectionMode(QAbstractItemView::SingleSelection);
651 view->setFrameStyle(QFrame::NoFrame);
652 view->setLineWidth(0);
653 view->setEditTriggers(QAbstractItemView::NoEditTriggers);
654#if QT_CONFIG(scrollbar)
655 connect(view->verticalScrollBar(), &QScrollBar::valueChanged,
656 this, &QComboBoxPrivateContainer::updateScrollers);
657 connect(view->verticalScrollBar(), &QScrollBar::rangeChanged,
658 this, &QComboBoxPrivateContainer::updateScrollers);
660 connect(view, &QAbstractItemView::destroyed,
661 this, &QComboBoxPrivateContainer::viewDestroyed);
665
666
667int QComboBoxPrivateContainer::topMargin()
const
669 if (
const QListView *lview = qobject_cast<
const QListView*>(view))
670 return lview->spacing();
671#if QT_CONFIG(tableview)
672 if (
const QTableView *tview = qobject_cast<
const QTableView*>(view))
673 return tview->showGrid() ? 1 : 0;
679
680
681int QComboBoxPrivateContainer::spacing()
const
683 QListView *lview = qobject_cast<QListView*>(view);
685 return 2 * lview->spacing();
686#if QT_CONFIG(tableview)
687 QTableView *tview = qobject_cast<QTableView*>(view);
689 return tview->showGrid() ? 1 : 0;
694void QComboBoxPrivateContainer::updateTopBottomMargin()
696 if (!layout() || layout()->count() < 1)
699 QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(layout());
703 const QStyleOptionComboBox opt = comboStyleOption();
704 const bool usePopup = combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo);
705 const int margin = usePopup ? combo->style()->pixelMetric(QStyle::PM_MenuVMargin, &opt, combo) : 0;
707 QSpacerItem *topSpacer = boxLayout->itemAt(0)->spacerItem();
709 topSpacer->changeSize(0, margin, QSizePolicy::Minimum, QSizePolicy::Fixed);
711 QSpacerItem *bottomSpacer = boxLayout->itemAt(boxLayout->count() - 1)->spacerItem();
712 if (bottomSpacer && bottomSpacer != topSpacer)
713 bottomSpacer->changeSize(0, margin, QSizePolicy::Minimum, QSizePolicy::Fixed);
715 boxLayout->invalidate();
718void QComboBoxPrivateContainer::updateStyleSettings()
721 QStyleOptionComboBox opt = comboStyleOption();
722 view->setMouseTracking(combo->style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking, &opt, combo) ||
723 combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo));
724 setFrameStyle(combo->style()->styleHint(QStyle::SH_ComboBox_PopupFrameStyle, &opt, combo));
725 updateTopBottomMargin();
728void QComboBoxPrivateContainer::changeEvent(QEvent *e)
730 if (e->type() == QEvent::StyleChange)
731 updateStyleSettings();
733 QFrame::changeEvent(e);
737bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e)
740 case QEvent::ShortcutOverride: {
741 QKeyEvent *keyEvent =
static_cast<QKeyEvent*>(e);
742 switch (keyEvent->key()) {
745#ifdef QT_KEYPAD_NAVIGATION
748 if (view->currentIndex().isValid() && view->currentIndex().flags().testFlag(Qt::ItemIsEnabled)) {
751 emit itemSelected(view->currentIndex());
755 if (!(keyEvent->modifiers() & Qt::AltModifier))
761 emit itemSelected(view->currentIndex());
764#if QT_CONFIG(shortcut)
765 if (keyEvent->matches(QKeySequence::Cancel) && isVisible()) {
774 case QEvent::MouseMove:
776 QMouseEvent *m =
static_cast<QMouseEvent *>(e);
777 QWidget *widget =
static_cast<QWidget *>(o);
778 QPoint vector = widget->mapToGlobal(m->position().toPoint()) - initialClickPosition;
779 if (vector.manhattanLength() > 9 && blockMouseReleaseTimer.isActive())
780 blockMouseReleaseTimer.stop();
781 if (combo->style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking_Current,
nullptr, combo)) {
782 QModelIndex indexUnderMouse = view->indexAt(m->position().toPoint());
783 if (indexUnderMouse.isValid()
784 && !QComboBoxDelegate::isSeparator(indexUnderMouse)) {
785 view->setCurrentIndex(indexUnderMouse);
790 case QEvent::MouseButtonPress:
791 maybeIgnoreMouseButtonRelease =
false;
793 case QEvent::MouseButtonRelease: {
794 bool ignoreEvent = maybeIgnoreMouseButtonRelease && popupTimer.elapsed() < QApplication::doubleClickInterval();
796 QMouseEvent *m =
static_cast<QMouseEvent *>(e);
797 if (isVisible() && view->rect().contains(m->position().toPoint()) && view->currentIndex().isValid()
798 && !blockMouseReleaseTimer.isActive() && !ignoreEvent
799 && (view->currentIndex().flags().testFlag(Qt::ItemIsEnabled))
800 && (view->currentIndex().flags().testFlag(Qt::ItemIsSelectable))) {
802 emit itemSelected(view->currentIndex());
810 return QFrame::eventFilter(o, e);
813void QComboBoxPrivateContainer::showEvent(QShowEvent *)
818void QComboBoxPrivateContainer::hideEvent(QHideEvent *)
822#if QT_CONFIG(graphicsview)
826 if (QGraphicsProxyWidget *proxy = graphicsProxyWidget())
831void QComboBoxPrivateContainer::mousePressEvent(QMouseEvent *e)
834 QStyleOptionComboBox opt = comboStyleOption();
835 opt.subControls = QStyle::SC_All;
836 opt.activeSubControls = QStyle::SC_ComboBoxArrow;
837 QStyle::SubControl sc = combo->style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt,
838 combo->mapFromGlobal(e->globalPosition().toPoint()),
840 if ((combo->isEditable() && sc == QStyle::SC_ComboBoxArrow)
841 || (!combo->isEditable() && sc != QStyle::SC_None))
842 setAttribute(Qt::WA_NoMouseReplay);
846void QComboBoxPrivateContainer::mouseReleaseEvent(QMouseEvent *e)
849 if (!blockMouseReleaseTimer.isActive()) {
855QStyleOptionComboBox QComboBoxPrivateContainer::comboStyleOption()
const
859 QStyleOptionComboBox opt;
861 opt.subControls = QStyle::SC_All;
862 opt.activeSubControls = QStyle::SC_None;
863 opt.editable = combo->isEditable();
868
869
870
871
872
873
874
875
876
877
878
879
880
883
884
885
886
887
888
889
890
891
892
895
896
897
898
899
900
901
902
905
906
907
908
909
910
911
912
913
916
917
918
919
920
923
924
925
926
927
928
931
932
933
934
935
936
937
938
941
942
943
944
945
946
947
948
949
952
953
954
955QComboBox::QComboBox(QWidget *parent)
956 : QWidget(*
new QComboBoxPrivate(), parent, { })
963
964
965QComboBox::QComboBox(QComboBoxPrivate &dd, QWidget *parent)
966 : QWidget(dd, parent, { })
973
974
975
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
1058void QComboBoxPrivate::init()
1066 if (!q->isEditable())
1067 q->setFocusPolicy(Qt::TabFocus);
1070 q->setFocusPolicy(Qt::WheelFocus);
1072 q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed,
1073 QSizePolicy::ComboBox));
1074 setLayoutItemMargins(QStyle::SE_ComboBoxLayoutItem);
1075 q->setModel(
new QStandardItemModel(0, 1, q));
1076 if (!q->isEditable())
1077 q->setAttribute(Qt::WA_InputMethodEnabled,
false);
1079 q->setAttribute(Qt::WA_InputMethodEnabled);
1082QComboBoxPrivateContainer* QComboBoxPrivate::viewContainer()
1088 container =
new QComboBoxPrivateContainer(
new QComboBoxListView(q), q);
1090 container->itemView()->setModel(model);
1092 container->itemView()->setTextElideMode(Qt::ElideMiddle);
1093 updateDelegate(
true);
1094 updateLayoutDirection();
1095 updateViewContainerPaletteAndOpacity();
1096 QObjectPrivate::connect(container, &QComboBoxPrivateContainer::itemSelected,
1097 this, &QComboBoxPrivate::itemSelected);
1098 QObjectPrivate::connect(container->itemView()->selectionModel(),
1099 &QItemSelectionModel::currentChanged,
1100 this, &QComboBoxPrivate::emitHighlighted);
1101 QObjectPrivate::connect(container, &QComboBoxPrivateContainer::resetButton,
1102 this, &QComboBoxPrivate::resetButton);
1107void QComboBoxPrivate::resetButton()
1109 updateArrow(QStyle::State_None);
1112void QComboBoxPrivate::dataChanged(
const QModelIndex &topLeft,
const QModelIndex &bottomRight)
1115 if (inserting || topLeft.parent() != root)
1118 if (sizeAdjustPolicy == QComboBox::AdjustToContents) {
1120 adjustComboBoxSize();
1121 q->updateGeometry();
1124 if (currentIndex.row() >= topLeft.row() && currentIndex.row() <= bottomRight.row()) {
1125 const QString text = q->itemText(currentIndex.row());
1127 lineEdit->setText(text);
1128 updateLineEditGeometry();
1130 updateCurrentText(text);
1133#if QT_CONFIG(accessibility)
1134 QAccessibleValueChangeEvent event(q, text);
1135 QAccessible::updateAccessibility(&event);
1140void QComboBoxPrivate::rowsInserted(
const QModelIndex &parent,
int start,
int end)
1143 if (inserting || parent != root)
1146 if (sizeAdjustPolicy == QComboBox::AdjustToContents) {
1148 adjustComboBoxSize();
1149 q->updateGeometry();
1153 if (start == 0 && (end - start + 1) == q->count() && !currentIndex.isValid() &&
1154 placeholderText.isEmpty()) {
1155#if QT_CONFIG(accessibility)
1160 if (container && container->itemView()) {
1161 QAccessibleTableModelChangeEvent event(container->itemView(),
1162 QAccessibleTableModelChangeEvent::ModelReset);
1163 QAccessible::updateAccessibility(&event);
1166 q->setCurrentIndex(0);
1168 }
else if (currentIndex.row() != indexBeforeChange) {
1170 emitCurrentIndexChanged(currentIndex);
1174void QComboBoxPrivate::updateIndexBeforeChange()
1176 indexBeforeChange = currentIndex.row();
1179void QComboBoxPrivate::rowsRemoved(
const QModelIndex &parent,
int ,
int )
1185 if (sizeAdjustPolicy == QComboBox::AdjustToContents) {
1187 adjustComboBoxSize();
1188 q->updateGeometry();
1192 if (model->rowCount(root) == 0) {
1193 setCurrentIndex(QModelIndex());
1198 if (currentIndex.row() != indexBeforeChange) {
1199 if (!currentIndex.isValid() && q->count()) {
1200 q->setCurrentIndex(qMin(q->count() - 1, qMax(indexBeforeChange, 0)));
1204 lineEdit->setText(q->itemText(currentIndex.row()));
1205 updateLineEditGeometry();
1208 emitCurrentIndexChanged(currentIndex);
1213void QComboBoxPrivate::updateViewContainerPaletteAndOpacity()
1218 QStyleOptionComboBox opt;
1219 q->initStyleOption(&opt);
1221 if (q->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, q)) {
1223 menu.ensurePolished();
1224 container->setPalette(menu.palette());
1225 container->setWindowOpacity(menu.windowOpacity());
1229 container->setPalette(q->palette());
1230 container->setWindowOpacity(1.0);
1233 lineEdit->setPalette(q->palette());
1236void QComboBoxPrivate::updateFocusPolicy()
1242 if (q->isEditable())
1243 q->setFocusPolicy(Qt::WheelFocus);
1245 q->setFocusPolicy(Qt::TabFocus);
1250
1251
1252
1253
1254
1255
1256void QComboBox::initStyleOption(QStyleOptionComboBox *option)
const
1261 Q_D(
const QComboBox);
1262 option->initFrom(
this);
1263 option->editable = isEditable();
1264 option->frame = d->frame;
1265 if (hasFocus() && !option->editable)
1266 option->state |= QStyle::State_Selected;
1267 option->subControls = QStyle::SC_All;
1268 if (d->arrowState == QStyle::State_Sunken) {
1269 option->activeSubControls = QStyle::SC_ComboBoxArrow;
1270 option->state |= d->arrowState;
1272 option->activeSubControls = d->hoverControl;
1274 option->currentText = currentText();
1275 if (d->currentIndex.isValid()) {
1276 option->currentIcon = d->itemIcon(d->currentIndex);
1277 QVariant alignment = d->model->data(d->currentIndex, Qt::TextAlignmentRole);
1278 if (alignment.isValid())
1279 option->textAlignment =
static_cast<Qt::Alignment>(alignment.toUInt());
1281 option->iconSize = iconSize();
1282 if (d->container && d->container->isVisible())
1283 option->state |= QStyle::State_On;
1286void QComboBoxPrivate::initViewItemOption(QStyleOptionViewItem *option)
const
1288 Q_Q(
const QComboBox);
1289 q->view()->initViewItemOption(option);
1291 option->index = currentIndex;
1292 option->text = q->currentText();
1293 option->icon = itemIcon(currentIndex);
1296void QComboBoxPrivate::updateLineEditGeometry()
1302 QStyleOptionComboBox opt;
1303 q->initStyleOption(&opt);
1304 QRect editRect = q->style()->subControlRect(QStyle::CC_ComboBox, &opt,
1305 QStyle::SC_ComboBoxEditField, q);
1306 if (currentIndex.isValid() && !q->itemIcon(q->currentIndex()).isNull()) {
1307 QRect comboRect(editRect);
1308 editRect.setWidth(editRect.width() - q->iconSize().width() - 4);
1309 editRect = QStyle::alignedRect(q->layoutDirection(), Qt::AlignRight,
1310 editRect.size(), comboRect);
1312 lineEdit->setGeometry(editRect);
1315Qt::MatchFlags QComboBoxPrivate::matchFlags()
const
1318 Qt::MatchFlags flags = Qt::MatchFixedString;
1319#if QT_CONFIG(completer)
1320 if (!lineEdit->completer() || lineEdit->completer()->caseSensitivity() == Qt::CaseSensitive)
1322 flags |= Qt::MatchCaseSensitive;
1327void QComboBoxPrivate::editingFinished()
1332 const auto leText = lineEdit->text();
1333 if (!leText.isEmpty() && itemText(currentIndex) != leText) {
1334#if QT_CONFIG(completer)
1335 const auto *leCompleter = lineEdit->completer();
1336 const auto *popup = leCompleter ? QCompleterPrivate::get(leCompleter)->popup :
nullptr;
1337 if (popup && popup->isVisible()) {
1342 const QItemSelectionModel *selModel = popup->selectionModel();
1343 const QModelIndex curIndex = popup->currentIndex();
1344 const bool completerIsActive = selModel && selModel->selectedIndexes().contains(curIndex);
1346 if (completerIsActive)
1350 const int index = q_func()->findText(leText, matchFlags());
1352 q->setCurrentIndex(index);
1353 emitActivated(currentIndex);
1359void QComboBoxPrivate::returnPressed()
1367 if (insertPolicy == QComboBox::NoInsert)
1370 if (lineEdit && !lineEdit->text().isEmpty()) {
1371 if (q->count() >= maxCount && !(
this->insertPolicy == QComboBox::InsertAtCurrent))
1373 lineEdit->deselect();
1374 lineEdit->end(
false);
1375 QString text = lineEdit->text();
1378 if (!duplicatesEnabled) {
1379 index = q->findText(text, matchFlags());
1381 q->setCurrentIndex(index);
1382 emitActivated(currentIndex);
1386 switch (insertPolicy) {
1387 case QComboBox::InsertAtTop:
1390 case QComboBox::InsertAtBottom:
1393 case QComboBox::InsertAtCurrent:
1394 case QComboBox::InsertAfterCurrent:
1395 case QComboBox::InsertBeforeCurrent:
1396 if (!q->count() || !currentIndex.isValid())
1398 else if (insertPolicy == QComboBox::InsertAtCurrent)
1399 q->setItemText(q->currentIndex(), text);
1400 else if (insertPolicy == QComboBox::InsertAfterCurrent)
1401 index = q->currentIndex() + 1;
1402 else if (insertPolicy == QComboBox::InsertBeforeCurrent)
1403 index = q->currentIndex();
1405 case QComboBox::InsertAlphabetically:
1407 for (
int i = 0; i < q->count(); ++i, ++index) {
1408 if (text.toLower() < q->itemText(i).toLower())
1416 q->insertItem(index, text);
1417 q->setCurrentIndex(index);
1418 emitActivated(currentIndex);
1423void QComboBoxPrivate::itemSelected(
const QModelIndex &item)
1426 if (item != currentIndex) {
1427 setCurrentIndex(item);
1428 }
else if (lineEdit) {
1429 lineEdit->selectAll();
1430 lineEdit->setText(q->itemText(currentIndex.row()));
1432 emitActivated(currentIndex);
1435void QComboBoxPrivate::emitActivated(
const QModelIndex &index)
1438 if (!index.isValid())
1440 QString text(itemText(index));
1441 emit q->activated(index.row());
1442 emit q->textActivated(text);
1445void QComboBoxPrivate::emitHighlighted(
const QModelIndex &index)
1448 if (!index.isValid())
1450 QString text(itemText(index));
1451 emit q->highlighted(index.row());
1452 emit q->textHighlighted(text);
1455void QComboBoxPrivate::emitCurrentIndexChanged(
const QModelIndex &index)
1458 const QString text = itemText(index);
1459 emit q->currentIndexChanged(index.row());
1462 updateCurrentText(text);
1463#if QT_CONFIG(accessibility)
1464 QAccessibleValueChangeEvent event(q, text);
1465 QAccessible::updateAccessibility(&event);
1469QString QComboBoxPrivate::itemText(
const QModelIndex &index)
const
1471 return index.isValid() ? model->data(index, itemRole()).toString() : QString();
1474int QComboBoxPrivate::itemRole()
const
1476 return q_func()->isEditable() ? Qt::EditRole : Qt::DisplayRole;
1480
1481
1482QComboBox::~QComboBox()
1488 d->disconnectModel();
1497 d->container->close();
1498 delete d->container;
1499 d->container =
nullptr;
1504
1505
1506
1507
1508
1509
1510
1511
1512int QComboBox::maxVisibleItems()
const
1514 Q_D(
const QComboBox);
1515 return d->maxVisibleItems;
1518void QComboBox::setMaxVisibleItems(
int maxItems)
1521 if (Q_UNLIKELY(maxItems < 0)) {
1522 qWarning(
"QComboBox::setMaxVisibleItems: "
1523 "Invalid max visible items (%d) must be >= 0", maxItems);
1526 d->maxVisibleItems = maxItems;
1530
1531
1532
1533
1534
1535int QComboBox::count()
const
1537 Q_D(
const QComboBox);
1538 return d->model->rowCount(d->root);
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553void QComboBox::setMaxCount(
int max)
1556 if (Q_UNLIKELY(max < 0)) {
1557 qWarning(
"QComboBox::setMaxCount: Invalid count (%d) must be >= 0", max);
1561 const int rowCount = count();
1563 d->model->removeRows(max, rowCount - max, d->root);
1568int QComboBox::maxCount()
const
1570 Q_D(
const QComboBox);
1575
1576
1577
1578
1579
1580
1581
1582
1583bool QComboBox::duplicatesEnabled()
const
1585 Q_D(
const QComboBox);
1586 return d->duplicatesEnabled;
1589void QComboBox::setDuplicatesEnabled(
bool enable)
1592 d->duplicatesEnabled = enable;
1596
1597
1598
1599
1600
1601
1604
1605
1606
1607
1608
1609int QComboBox::findData(
const QVariant &data,
int role, Qt::MatchFlags flags)
const
1611 Q_D(
const QComboBox);
1612 QModelIndex start = d->model->index(0, d->modelColumn, d->root);
1613 const QModelIndexList result = d->model->match(start, role, data, 1, flags);
1614 if (result.isEmpty())
1616 return result.first().row();
1620
1621
1622
1623
1624
1625
1626
1627
1628
1630QComboBox::InsertPolicy QComboBox::insertPolicy()
const
1632 Q_D(
const QComboBox);
1633 return d->insertPolicy;
1636void QComboBox::setInsertPolicy(InsertPolicy policy)
1639 d->insertPolicy = policy;
1643
1644
1645
1646
1647
1648
1649
1650
1652QComboBox::SizeAdjustPolicy QComboBox::sizeAdjustPolicy()
const
1654 Q_D(
const QComboBox);
1655 return d->sizeAdjustPolicy;
1658void QComboBox::setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy policy)
1661 if (policy == d->sizeAdjustPolicy)
1664 d->sizeAdjustPolicy = policy;
1665 d->sizeHint = QSize();
1666 d->adjustComboBoxSize();
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681int QComboBox::minimumContentsLength()
const
1683 Q_D(
const QComboBox);
1684 return d->minimumContentsLength;
1687void QComboBox::setMinimumContentsLength(
int characters)
1690 if (characters == d->minimumContentsLength || characters < 0)
1693 d->minimumContentsLength = characters;
1695 if (d->sizeAdjustPolicy == AdjustToContents
1696 || d->sizeAdjustPolicy == AdjustToMinimumContentsLengthWithIcon) {
1697 d->sizeHint = QSize();
1698 d->adjustComboBoxSize();
1704
1705
1706
1707
1708
1709
1710
1712QSize QComboBox::iconSize()
const
1714 Q_D(
const QComboBox);
1715 if (d->iconSize.isValid())
1718 int iconWidth = style()->pixelMetric(QStyle::PM_SmallIconSize,
nullptr,
this);
1719 return QSize(iconWidth, iconWidth);
1722void QComboBox::setIconSize(
const QSize &size)
1725 if (size == d->iconSize)
1728 view()->setIconSize(size);
1730 d->sizeHint = QSize();
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750void QComboBox::setPlaceholderText(
const QString &placeholderText)
1753 if (placeholderText == d->placeholderText)
1756 d->placeholderText = placeholderText;
1757 if (currentIndex() == -1) {
1758 if (d->placeholderText.isEmpty())
1767QString QComboBox::placeholderText()
const
1769 Q_D(
const QComboBox);
1770 return d->placeholderText;
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785bool QComboBox::isEditable()
const
1787 Q_D(
const QComboBox);
1788 return d->lineEdit !=
nullptr;
1792
1793
1794
1795
1796
1797
1798void QComboBoxPrivate::updateDelegate(
bool force)
1801 QStyleOptionComboBox opt;
1802 q->initStyleOption(&opt);
1803 if (q->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, q)) {
1804 if (force || qobject_cast<QComboBoxDelegate *>(q->itemDelegate()))
1805 q->setItemDelegate(
new QComboMenuDelegate(q->view(), q));
1807 if (force || qobject_cast<QComboMenuDelegate *>(q->itemDelegate()))
1808 q->setItemDelegate(
new QComboBoxDelegate(q->view(), q));
1812QIcon QComboBoxPrivate::itemIcon(
const QModelIndex &index)
const
1814 if (!index.isValid())
1816 QVariant decoration = model->data(index, Qt::DecorationRole);
1817 if (decoration.userType() == QMetaType::QPixmap)
1818 return QIcon(qvariant_cast<QPixmap>(decoration));
1820 return qvariant_cast<QIcon>(decoration);
1823void QComboBox::setEditable(
bool editable)
1826 if (isEditable() == editable)
1829 QStyleOptionComboBox opt;
1830 initStyleOption(&opt);
1832 if (style()->styleHint(QStyle::SH_ComboBox_Popup, &opt,
this)) {
1833 d->viewContainer()->updateScrollers();
1834 view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1836 QLineEdit *le =
new QLineEdit(
this);
1837 le->setPalette(palette());
1840 if (style()->styleHint(QStyle::SH_ComboBox_Popup, &opt,
this)) {
1841 d->viewContainer()->updateScrollers();
1842 view()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1844 setAttribute(Qt::WA_InputMethodEnabled,
false);
1845 d->lineEdit->hide();
1846 d->lineEdit->deleteLater();
1847 d->lineEdit =
nullptr;
1850 d->updateDelegate();
1851 d->updateFocusPolicy();
1853 d->viewContainer()->updateTopBottomMargin();
1854 if (!testAttribute(Qt::WA_Resized))
1859
1860
1861
1862
1863
1864
1865
1866void QComboBox::setLineEdit(QLineEdit *edit)
1869 if (Q_UNLIKELY(!edit)) {
1870 qWarning(
"QComboBox::setLineEdit: cannot set a 0 line edit");
1874 if (edit == d->lineEdit)
1877 edit->setText(currentText());
1882 qt_widget_private(d->lineEdit)->inheritsInputMethodHints = 1;
1884 if (d->lineEdit->parent() !=
this)
1885 d->lineEdit->setParent(
this);
1886 QObjectPrivate::connect(d->lineEdit, &QLineEdit::returnPressed,
1887 d, &QComboBoxPrivate::returnPressed);
1888 QObjectPrivate::connect(d->lineEdit, &QLineEdit::editingFinished,
1889 d, &QComboBoxPrivate::editingFinished);
1890 connect(d->lineEdit, &QLineEdit::textChanged,
this, &QComboBox::editTextChanged);
1891 connect(d->lineEdit, &QLineEdit::textChanged,
this, &QComboBox::currentTextChanged);
1892 QObjectPrivate::connect(d->lineEdit, &QLineEdit::cursorPositionChanged,
1893 d, &QComboBoxPrivate::updateMicroFocus);
1894 QObjectPrivate::connect(d->lineEdit, &QLineEdit::selectionChanged,
1895 d, &QComboBoxPrivate::updateMicroFocus);
1896 QObjectPrivate::connect(d->lineEdit->d_func()->control, &QWidgetLineControl::updateMicroFocus,
1897 d, &QComboBoxPrivate::updateMicroFocus);
1898 d->lineEdit->setFrame(
false);
1899 d->lineEdit->setContextMenuPolicy(Qt::NoContextMenu);
1900 d->updateFocusPolicy();
1901 d->lineEdit->setFocusProxy(
this);
1902 d->lineEdit->setAttribute(Qt::WA_MacShowFocusRect,
false);
1904#if QT_CONFIG(completer)
1906 if (!d->lineEdit->completer()) {
1907 QCompleter *completer =
new QCompleter(d->model, d->lineEdit);
1908 completer->setCaseSensitivity(Qt::CaseInsensitive);
1909 completer->setCompletionMode(QCompleter::InlineCompletion);
1910 completer->setCompletionColumn(d->modelColumn);
1912#ifdef QT_KEYPAD_NAVIGATION
1916 if (QApplicationPrivate::keypadNavigationEnabled())
1917 completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
1920 setCompleter(completer);
1924 setAttribute(Qt::WA_InputMethodEnabled);
1925 d->updateLayoutDirection();
1926 d->updateLineEditGeometry();
1928 d->lineEdit->show();
1934
1935
1936
1937
1938
1939QLineEdit *QComboBox::lineEdit()
const
1941 Q_D(
const QComboBox);
1945#ifndef QT_NO_VALIDATOR
1947
1948
1949
1950
1951
1952
1954void QComboBox::setValidator(
const QValidator *v)
1958 d->lineEdit->setValidator(v);
1962
1963
1964
1965
1966
1967const QValidator *QComboBox::validator()
const
1969 Q_D(
const QComboBox);
1970 return d->lineEdit ? d->lineEdit->validator() :
nullptr;
1974#if QT_CONFIG(completer)
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990void QComboBox::setCompleter(QCompleter *c)
1994 qWarning(
"Setting a QCompleter on non-editable QComboBox is not allowed.");
1997 d->lineEdit->setCompleter(c);
1999 QObjectPrivate::connect(c, QOverload<
const QModelIndex &>::of(&QCompleter::activated),
2000 d, &QComboBoxPrivate::completerActivated);
2006
2007
2008
2009
2010
2011
2012
2013QCompleter *QComboBox::completer()
const
2015 Q_D(
const QComboBox);
2016 return d->lineEdit ? d->lineEdit->completer() :
nullptr;
2022
2023
2024
2025
2026QAbstractItemDelegate *QComboBox::itemDelegate()
const
2028 return view()->itemDelegate();
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046void QComboBox::setItemDelegate(QAbstractItemDelegate *delegate)
2048 if (Q_UNLIKELY(!delegate)) {
2049 qWarning(
"QComboBox::setItemDelegate: cannot set a 0 delegate");
2052 view()->setItemDelegate(delegate);
2056
2057
2059QAbstractItemModel *QComboBox::model()
const
2061 Q_D(
const QComboBox);
2062 if (d->model == QAbstractItemModelPrivate::staticEmptyModel()) {
2063 QComboBox *that =
const_cast<QComboBox*>(
this);
2064 that->setModel(
new QStandardItemModel(0, 1, that));
2070
2071
2072
2073
2074
2075
2076
2077
2078void QComboBox::setModel(QAbstractItemModel *model)
2082 if (Q_UNLIKELY(!model)) {
2083 qWarning(
"QComboBox::setModel: cannot set a 0 model");
2087 if (model == d->model)
2090#if QT_CONFIG(completer)
2091 if (d->lineEdit && d->lineEdit->completer())
2092 d->lineEdit->completer()->setModel(model);
2094 d->disconnectModel();
2095 if (d->model && d->model->QObject::parent() ==
this) {
2103 d->container->itemView()->setModel(model);
2104 QObjectPrivate::connect(d->container->itemView()->selectionModel(),
2105 &QItemSelectionModel::currentChanged,
2106 d, &QComboBoxPrivate::emitHighlighted, Qt::UniqueConnection);
2111 setRootModelIndex(QModelIndex());
2113 d->trySetValidIndex();
2117void QComboBoxPrivate::connectModel()
2122 modelConnections = {
2123 QObjectPrivate::connect(model, &QAbstractItemModel::dataChanged,
2124 this, &QComboBoxPrivate::dataChanged),
2125 QObjectPrivate::connect(model, &QAbstractItemModel::rowsAboutToBeInserted,
2126 this, &QComboBoxPrivate::updateIndexBeforeChange),
2127 QObjectPrivate::connect(model, &QAbstractItemModel::rowsInserted,
2128 this, &QComboBoxPrivate::rowsInserted),
2129 QObjectPrivate::connect(model, &QAbstractItemModel::rowsAboutToBeRemoved,
2130 this, &QComboBoxPrivate::updateIndexBeforeChange),
2131 QObjectPrivate::connect(model, &QAbstractItemModel::rowsRemoved,
2132 this, &QComboBoxPrivate::rowsRemoved),
2133 QObjectPrivate::connect(model, &QObject::destroyed,
2134 this, &QComboBoxPrivate::modelDestroyed),
2135 QObjectPrivate::connect(model, &QAbstractItemModel::modelAboutToBeReset,
2136 this, &QComboBoxPrivate::updateIndexBeforeChange),
2137 QObjectPrivate::connect(model, &QAbstractItemModel::modelReset,
2138 this, &QComboBoxPrivate::modelReset)
2142void QComboBoxPrivate::disconnectModel()
2144 for (
auto &connection : modelConnections)
2145 QObject::disconnect(connection);
2149
2150
2151
2152
2154QModelIndex QComboBox::rootModelIndex()
const
2156 Q_D(
const QComboBox);
2157 return QModelIndex(d->root);
2161
2162
2163
2164
2165void QComboBox::setRootModelIndex(
const QModelIndex &index)
2168 if (d->root == index)
2170 d->root = QPersistentModelIndex(index);
2171 view()->setRootIndex(index);
2176
2177
2178
2179
2180
2181
2182
2183
2184int QComboBox::currentIndex()
const
2186 Q_D(
const QComboBox);
2187 return d->currentIndex.row();
2190void QComboBox::setCurrentIndex(
int index)
2193 QModelIndex mi = index >= 0 ? d->model->index(index, d->modelColumn, d->root) : QModelIndex();
2194 d->setCurrentIndex(mi);
2197void QComboBox::setCurrentText(
const QString &text)
2202 const int i = findText(text);
2208void QComboBoxPrivate::setCurrentIndex(
const QModelIndex &mi)
2212 QModelIndex normalized = mi.sibling(mi.row(), modelColumn);
2213 if (!normalized.isValid())
2216 bool indexChanged = (normalized != currentIndex);
2218 currentIndex = QPersistentModelIndex(normalized);
2220 const QString newText = itemText(normalized);
2221 if (lineEdit->text() != newText) {
2222 lineEdit->setText(newText);
2223#if QT_CONFIG(completer)
2224 if (lineEdit && lineEdit->completer())
2225 lineEdit->completer()->setCompletionPrefix(newText);
2228 updateLineEditGeometry();
2235 const bool modelResetToEmpty = !normalized.isValid() && indexBeforeChange != -1;
2236 if (modelResetToEmpty)
2237 indexBeforeChange = -1;
2239 if (indexChanged || modelResetToEmpty) {
2240 QItemSelectionModel::SelectionFlags selectionMode = QItemSelectionModel::ClearAndSelect;
2241 if (q->view()->selectionBehavior() == QAbstractItemView::SelectRows)
2242 selectionMode.setFlag(QItemSelectionModel::Rows);
2243 if (
auto *model = q->view()->selectionModel())
2244 model->setCurrentIndex(currentIndex, selectionMode);
2247 emitCurrentIndexChanged(currentIndex);
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265QString QComboBox::currentText()
const
2267 Q_D(
const QComboBox);
2269 return d->lineEdit->text();
2270 if (d->currentIndex.isValid())
2271 return d->itemText(d->currentIndex);
2276
2277
2278
2279
2280
2281
2282
2283QVariant QComboBox::currentData(
int role)
const
2285 Q_D(
const QComboBox);
2286 return d->currentIndex.data(role);
2290
2291
2292QString QComboBox::itemText(
int index)
const
2294 Q_D(
const QComboBox);
2295 QModelIndex mi = d->model->index(index, d->modelColumn, d->root);
2296 return d->itemText(mi);
2300
2301
2302QIcon QComboBox::itemIcon(
int index)
const
2304 Q_D(
const QComboBox);
2305 QModelIndex mi = d->model->index(index, d->modelColumn, d->root);
2306 return d->itemIcon(mi);
2310
2311
2312
2313QVariant QComboBox::itemData(
int index,
int role)
const
2315 Q_D(
const QComboBox);
2316 QModelIndex mi = d->model->index(index, d->modelColumn, d->root);
2317 return d->model->data(mi, role);
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346void QComboBox::insertItem(
int index,
const QIcon &icon,
const QString &text,
const QVariant &userData)
2349 int itemCount = count();
2350 index = qBound(0, index, itemCount);
2351 if (index >= d->maxCount)
2356 if (QStandardItemModel *m = qobject_cast<QStandardItemModel*>(d->model)) {
2357 QStandardItem *item =
new QStandardItem(text);
2358 if (!icon.isNull()) item->setData(icon, Qt::DecorationRole);
2359 if (userData.isValid()) item->setData(userData, Qt::UserRole);
2360 m->insertRow(index, item);
2363 d->inserting =
true;
2364 if (d->model->insertRows(index, 1, d->root)) {
2365 QModelIndex item = d->model->index(index, d->modelColumn, d->root);
2366 if (icon.isNull() && !userData.isValid()) {
2367 d->model->setData(item, text, Qt::EditRole);
2369 QMap<
int, QVariant> values;
2370 if (!text.isNull()) values.insert(Qt::EditRole, text);
2371 if (!icon.isNull()) values.insert(Qt::DecorationRole, icon);
2372 if (userData.isValid()) values.insert(Qt::UserRole, userData);
2373 if (!values.isEmpty()) d->model->setItemData(item, values);
2375 d->inserting =
false;
2376 d->rowsInserted(d->root, index, index);
2379 d->inserting =
false;
2383 if (itemCount > d->maxCount)
2384 d->model->removeRows(itemCount - 1, itemCount - d->maxCount, d->root);
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397void QComboBox::insertItems(
int index,
const QStringList &list)
2402 index = qBound(0, index, count());
2403 int insertCount = qMin(d->maxCount - index, list.size());
2404 if (insertCount <= 0)
2408 if (QStandardItemModel *m = qobject_cast<QStandardItemModel*>(d->model)) {
2409 QList<QStandardItem *> items;
2410 items.reserve(insertCount);
2411 QStandardItem *hiddenRoot = m->invisibleRootItem();
2412 for (
int i = 0; i < insertCount; ++i)
2413 items.append(
new QStandardItem(list.at(i)));
2414 hiddenRoot->insertRows(index, items);
2416 d->inserting =
true;
2417 if (d->model->insertRows(index, insertCount, d->root)) {
2419 for (
int i = 0; i < insertCount; ++i) {
2420 item = d->model->index(i+index, d->modelColumn, d->root);
2421 d->model->setData(item, list.at(i), Qt::EditRole);
2423 d->inserting =
false;
2424 d->rowsInserted(d->root, index, index + insertCount - 1);
2426 d->inserting =
false;
2431 if (mc > d->maxCount)
2432 d->model->removeRows(d->maxCount, mc - d->maxCount, d->root);
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446void QComboBox::insertSeparator(
int index)
2449 int itemCount = count();
2450 index = qBound(0, index, itemCount);
2451 if (index >= d->maxCount)
2453 insertItem(index, QIcon(), QString());
2454 QComboBoxDelegate::setSeparator(d->model, d->model->index(index, 0, d->root));
2458
2459
2460
2461
2462
2463void QComboBox::removeItem(
int index)
2466 if (index < 0 || index >= count())
2468 d->model->removeRows(index, 1, d->root);
2472
2473
2474void QComboBox::setItemText(
int index,
const QString &text)
2476 Q_D(
const QComboBox);
2477 QModelIndex item = d->model->index(index, d->modelColumn, d->root);
2478 if (item.isValid()) {
2479 d->model->setData(item, text, Qt::EditRole);
2484
2485
2486void QComboBox::setItemIcon(
int index,
const QIcon &icon)
2488 Q_D(
const QComboBox);
2489 QModelIndex item = d->model->index(index, d->modelColumn, d->root);
2490 if (item.isValid()) {
2491 d->model->setData(item, icon, Qt::DecorationRole);
2496
2497
2498
2499void QComboBox::setItemData(
int index,
const QVariant &value,
int role)
2501 Q_D(
const QComboBox);
2502 QModelIndex item = d->model->index(index, d->modelColumn, d->root);
2503 if (item.isValid()) {
2504 d->model->setData(item, value, role);
2509
2510
2511QAbstractItemView *QComboBox::view()
const
2513 Q_D(
const QComboBox);
2514 return const_cast<QComboBoxPrivate*>(d)->viewContainer()->itemView();
2518
2519
2520
2521
2522
2523
2524
2525
2526void QComboBox::setView(QAbstractItemView *itemView)
2529 if (Q_UNLIKELY(!itemView)) {
2530 qWarning(
"QComboBox::setView: cannot set a 0 view");
2534 if (itemView->model() != d->model) {
2535 d->disconnectModel();
2536 itemView->setModel(d->model);
2539 d->viewContainer()->setItemView(itemView);
2543
2544
2545QSize QComboBox::minimumSizeHint()
const
2547 Q_D(
const QComboBox);
2548 return d->recomputeSizeHint(d->minimumSizeHint);
2552
2553
2554
2555
2556
2557
2558QSize QComboBox::sizeHint()
const
2560 Q_D(
const QComboBox);
2561 return d->recomputeSizeHint(d->sizeHint);
2565void QComboBoxPrivate::cleanupNativePopup()
2567 if (!m_platformMenu)
2570 m_platformMenu->setVisible(
false);
2571 int count =
int(m_platformMenu->tag());
2572 for (
int i = 0; i < count; ++i)
2573 m_platformMenu->menuItemAt(i)->deleteLater();
2575 delete m_platformMenu;
2576 m_platformMenu =
nullptr;
2580
2581
2582
2583
2584
2585bool QComboBoxPrivate::showNativePopup()
2589 cleanupNativePopup();
2591 QPlatformTheme *theme = QGuiApplicationPrivate::instance()->platformTheme();
2592 m_platformMenu = theme->createPlatformMenu();
2593 if (!m_platformMenu)
2596 int itemsCount = q->count();
2597 m_platformMenu->setTag(quintptr(itemsCount));
2599 QPlatformMenuItem *currentItem =
nullptr;
2600 int currentIndex = q->currentIndex();
2602 for (
int i = 0; i < itemsCount; ++i) {
2603 QPlatformMenuItem *item = theme->createPlatformMenuItem();
2604 QModelIndex rowIndex = model->index(i, modelColumn, root);
2605 QVariant textVariant = model->data(rowIndex, Qt::EditRole);
2606 item->setText(textVariant.toString());
2607 QVariant iconVariant = model->data(rowIndex, Qt::DecorationRole);
2608 const Qt::ItemFlags itemFlags = model->flags(rowIndex);
2609 if (iconVariant.canConvert<QIcon>())
2610 item->setIcon(iconVariant.value<QIcon>());
2611 item->setCheckable(
true);
2612 item->setChecked(i == currentIndex);
2613 item->setEnabled(itemFlags & Qt::ItemIsEnabled);
2614 if (!currentItem || i == currentIndex)
2617 IndexSetter setter = { i, q };
2618 QObject::connect(item, &QPlatformMenuItem::activated, q, setter);
2620 m_platformMenu->insertMenuItem(item, 0);
2621 m_platformMenu->syncMenuItem(item);
2624 QWindow *tlw = q->window()->windowHandle();
2625 m_platformMenu->setFont(q->font());
2626 m_platformMenu->setMinimumWidth(q->rect().width());
2627 QPoint offset = QPoint(0, 7);
2628 if (q->testAttribute(Qt::WA_MacSmallSize))
2629 offset = QPoint(-1, 7);
2630 else if (q->testAttribute(Qt::WA_MacMiniSize))
2631 offset = QPoint(-2, 6);
2633 [[maybe_unused]] QPointer<QComboBox> guard(q);
2634 const QRect targetRect = QRect(tlw->mapFromGlobal(q->mapToGlobal(offset)), QSize());
2635 m_platformMenu->showPopup(tlw, QHighDpi::toNativePixels(targetRect, tlw), currentItem);
2641 QMouseEvent mouseReleased(QEvent::MouseButtonRelease, q->pos(), q->mapToGlobal(QPoint(0, 0)),
2642 Qt::LeftButton, Qt::MouseButtons(Qt::LeftButton), {});
2643 QCoreApplication::sendEvent(q, &mouseReleased);
2653
2654
2655
2656
2657
2658
2659
2660
2661void QComboBox::showPopup()
2667 QStyle *
const style =
this->style();
2668 QStyleOptionComboBox opt;
2669 initStyleOption(&opt);
2670 const bool usePopup = style->styleHint(QStyle::SH_ComboBox_Popup, &opt,
this);
2675 || (view()->metaObject()->className() == QByteArray(
"QComboBoxListView")
2676 && view()->itemDelegate()->metaObject()->className() == QByteArray(
"QComboMenuDelegate")))
2677 && style->styleHint(QStyle::SH_ComboBox_UseNativePopup, &opt,
this)
2678 && d->showNativePopup())
2682 QComboBoxPrivateContainer* container = d->viewContainer();
2683 QRect listRect(style->subControlRect(QStyle::CC_ComboBox, &opt,
2684 QStyle::SC_ComboBoxListBoxPopup,
this));
2685 QRect screen = d->popupGeometry(mapToGlobal(listRect.topLeft()));
2687 QPoint below = mapToGlobal(listRect.bottomLeft());
2688 int belowHeight = screen.bottom() - below.y();
2689 QPoint above = mapToGlobal(listRect.topLeft());
2690 int aboveHeight = above.y() - screen.y();
2691 bool boundToScreen = !window()->testAttribute(Qt::WA_DontShowOnScreen);
2692 const auto listView = qobject_cast<QListView *>(d->viewContainer()->itemView());
2697 QStack<QModelIndex> toCheck;
2698 toCheck.push(view()->rootIndex());
2699#if QT_CONFIG(treeview)
2700 QTreeView *treeView = qobject_cast<QTreeView*>(view());
2701 if (treeView && treeView->header() && !treeView->header()->isHidden())
2702 listHeight += treeView->header()->height();
2704 while (!toCheck.isEmpty()) {
2705 QModelIndex parent = toCheck.pop();
2706 for (
int i = 0, end = d->model->rowCount(parent); i < end; ++i) {
2707 if (listView && listView->isRowHidden(i))
2709 QModelIndex idx = d->model->index(i, d->modelColumn, parent);
2712 listHeight += view()->visualRect(idx).height();
2713#if QT_CONFIG(treeview)
2714 if (d->model->hasChildren(idx) && treeView && treeView->isExpanded(idx))
2718 if (!usePopup && count >= d->maxVisibleItems) {
2725 listHeight += (count - 1) * container->spacing();
2726 listRect.setHeight(listHeight);
2731 int heightMargin = container->topMargin() + container->bottomMargin();
2734 const QMargins cm = container->contentsMargins();
2735 heightMargin += cm.top() + cm.bottom();
2738 const QMargins vm = view()->contentsMargins();
2739 heightMargin += vm.top() + vm.bottom();
2740 heightMargin +=
static_cast<QAbstractScrollAreaPrivate *>(QObjectPrivate::get(view()))->top;
2741 heightMargin +=
static_cast<QAbstractScrollAreaPrivate *>(QObjectPrivate::get(view()))->bottom;
2743 listRect.setHeight(listRect.height() + heightMargin);
2748 listRect.setHeight(listRect.height() + style->pixelMetric(QStyle::PM_MenuVMargin, &opt,
this) * 2);
2752 const int diff = d->computeWidthHint() - width();
2754 listRect.setWidth(listRect.width() + diff);
2758 container->layout()->activate();
2760 listRect.setSize( listRect.size().expandedTo(container->minimumSize())
2761 .boundedTo(container->maximumSize()));
2764 if (boundToScreen) {
2765 if (listRect.width() > screen.width() )
2766 listRect.setWidth(screen.width());
2767 if (mapToGlobal(listRect.bottomRight()).x() > screen.right()) {
2768 below.setX(screen.x() + screen.width() - listRect.width());
2769 above.setX(screen.x() + screen.width() - listRect.width());
2771 if (mapToGlobal(listRect.topLeft()).x() < screen.x() ) {
2772 below.setX(screen.x());
2773 above.setX(screen.x());
2779 listRect.moveLeft(above.x());
2788 view()->scrollToTop();
2789 const QRect currentItemRect = view()->visualRect(view()->currentIndex());
2790 const int offset = listRect.top() - currentItemRect.top();
2791 listRect.moveTop(above.y() + offset - listRect.top());
2796 const int height = !boundToScreen ? listRect.height() : qMin(listRect.height(), screen.height());
2797 listRect.setHeight(height);
2799 if (boundToScreen) {
2800 if (listRect.top() < screen.top())
2801 listRect.moveTop(screen.top());
2802 if (listRect.bottom() > screen.bottom())
2803 listRect.moveBottom(screen.bottom());
2805 }
else if (!boundToScreen || listRect.height() <= belowHeight) {
2806 listRect.moveTopLeft(below);
2807 }
else if (listRect.height() <= aboveHeight) {
2808 listRect.moveBottomLeft(above);
2809 }
else if (belowHeight >= aboveHeight) {
2810 listRect.setHeight(belowHeight);
2811 listRect.moveTopLeft(below);
2813 listRect.setHeight(aboveHeight);
2814 listRect.moveBottomLeft(above);
2818 QGuiApplication::inputMethod()->reset();
2821 const QScrollBar *sb = view()->horizontalScrollBar();
2822 const auto needHorizontalScrollBar = [
this, sb]{
2823 const Qt::ScrollBarPolicy policy = view()->horizontalScrollBarPolicy();
2824 return (policy == Qt::ScrollBarAsNeeded || policy == Qt::ScrollBarAlwaysOn)
2825 && sb->minimum() < sb->maximum();
2827 const bool neededHorizontalScrollBar = needHorizontalScrollBar();
2828 if (neededHorizontalScrollBar)
2829 listRect.adjust(0, 0, 0, sb->height());
2834 container->hideScrollers();
2835 container->setGeometry(listRect);
2838 const bool updatesEnabled = container->updatesEnabled();
2841#if QT_CONFIG(effects)
2842 bool scrollDown = (listRect.topLeft() == below);
2843 if (QApplication::isEffectEnabled(Qt::UI_AnimateCombo)
2844 && !style->styleHint(QStyle::SH_ComboBox_Popup, &opt,
this) && !window()->testAttribute(Qt::WA_DontShowOnScreen))
2845 qScrollEffect(container, scrollDown ? QEffects::DownScroll : QEffects::UpScroll, 150);
2854 container->setUpdatesEnabled(
false);
2857 bool startTimer = !container->isVisible();
2859 container->create();
2860 if (QWindow *containerWindow = qt_widget_private(container)->windowHandle(QWidgetPrivate::WindowHandleMode::TopLevel)) {
2861 QScreen *currentScreen = d->associatedScreen();
2862 if (currentScreen && !currentScreen->virtualSiblings().contains(containerWindow->screen())) {
2863 containerWindow->setScreen(currentScreen);
2872 if (!neededHorizontalScrollBar && needHorizontalScrollBar()) {
2873 listRect.adjust(0, 0, 0, sb->height());
2874 container->setGeometry(listRect);
2877 container->updateScrollers();
2880 view()->scrollTo(view()->currentIndex(),
2881 style->styleHint(QStyle::SH_ComboBox_Popup, &opt,
this)
2882 ? QAbstractItemView::PositionAtCenter
2883 : QAbstractItemView::EnsureVisible);
2886 container->setUpdatesEnabled(updatesEnabled);
2889 container->update();
2891 container->popupTimer.start();
2892 container->maybeIgnoreMouseButtonRelease =
true;
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906void QComboBox::hidePopup()
2911 d->hidingPopup =
true;
2913 auto resetHidingPopup = qScopeGuard([d]{
2914 d->hidingPopup =
false;
2917 if (!d->container || !d->container->isVisible())
2920#if QT_CONFIG(effects)
2921 QItemSelectionModel *selectionModel = d->container->itemView()
2922 ? d->container->itemView()->selectionModel() :
nullptr;
2924 if (style()->styleHint(QStyle::SH_Menu_FlashTriggeredItem,
nullptr,
this) &&
2925 selectionModel && selectionModel->hasSelection()) {
2926 const QItemSelection selection = selectionModel->selection();
2928 QTimer::singleShot(0, d->container, [d, selection, selectionModel]{
2929 QSignalBlocker modelBlocker(d->model);
2930 QSignalBlocker viewBlocker(d->container->itemView());
2931 QSignalBlocker containerBlocker(d->container);
2934 selectionModel->select(selection, QItemSelectionModel::Toggle);
2935 QTimer::singleShot(60, d->container, [d, selection, selectionModel]{
2936 QSignalBlocker modelBlocker(d->model);
2937 QSignalBlocker viewBlocker(d->container->itemView());
2938 QSignalBlocker containerBlocker(d->container);
2939 selectionModel->select(selection, QItemSelectionModel::Toggle);
2940 QTimer::singleShot(20, d->container, [d] {
2952void QComboBoxPrivate::doHidePopup()
2954 if (container && container->isVisible())
2960void QComboBoxPrivate::updateCurrentText(
const QString &text)
2962 if (text == currentText)
2966 emit q_func()->currentTextChanged(text);
2970
2971
2972
2973
2974
2975void QComboBox::clear()
2978 d->model->removeRows(0, d->model->rowCount(d->root), d->root);
2979#if QT_CONFIG(accessibility)
2980 QAccessibleValueChangeEvent event(
this, QString());
2981 QAccessible::updateAccessibility(&event);
2986
2987
2988void QComboBox::clearEditText()
2992 d->lineEdit->clear();
2993#if QT_CONFIG(accessibility)
2994 QAccessibleValueChangeEvent event(
this, QString());
2995 QAccessible::updateAccessibility(&event);
3000
3001
3002void QComboBox::setEditText(
const QString &text)
3006 d->lineEdit->setText(text);
3007#if QT_CONFIG(accessibility)
3008 QAccessibleValueChangeEvent event(
this, text);
3009 QAccessible::updateAccessibility(&event);
3014
3015
3016void QComboBox::focusInEvent(QFocusEvent *e)
3021 d->lineEdit->event(e);
3022#if QT_CONFIG(completer)
3023 if (d->lineEdit->completer())
3024 d->lineEdit->completer()->setWidget(
this);
3030
3031
3032void QComboBox::focusOutEvent(QFocusEvent *e)
3037 d->lineEdit->event(e);
3041void QComboBox::changeEvent(QEvent *e)
3044 switch (e->type()) {
3045 case QEvent::StyleChange:
3047 d->container->updateStyleSettings();
3048 d->updateDelegate();
3051 case QEvent::MacSizeChange:
3053 d->sizeHint = QSize();
3054 d->minimumSizeHint = QSize();
3055 d->updateLayoutDirection();
3057 d->updateLineEditGeometry();
3058 d->setLayoutItemMargins(QStyle::SE_ComboBoxLayoutItem);
3060 if (e->type() == QEvent::MacSizeChange) {
3061 QPlatformTheme::Font f = QPlatformTheme::SystemFont;
3062 if (testAttribute(Qt::WA_MacSmallSize))
3063 f = QPlatformTheme::SmallFont;
3064 else if (testAttribute(Qt::WA_MacMiniSize))
3065 f = QPlatformTheme::MiniFont;
3066 if (
const QFont *platformFont = QApplicationPrivate::platformTheme()->font(f)) {
3068 f.setPointSizeF(platformFont->pointSizeF());
3074 case QEvent::EnabledChange:
3078 case QEvent::PaletteChange: {
3079 d->updateViewContainerPaletteAndOpacity();
3082 case QEvent::FontChange: {
3083 d->sizeHint = QSize();
3084 d->viewContainer()->setFont(font());
3085 d->viewContainer()->itemView()->doItemsLayout();
3087 d->updateLineEditGeometry();
3093 QWidget::changeEvent(e);
3097
3098
3099void QComboBox::resizeEvent(QResizeEvent *)
3102 d->updateLineEditGeometry();
3106
3107
3108void QComboBox::paintEvent(QPaintEvent *)
3111 QStylePainter painter(
this);
3112 painter.setPen(palette().color(QPalette::Text));
3115 QStyleOptionComboBox opt;
3116 initStyleOption(&opt);
3117 painter.drawComplexControl(QStyle::CC_ComboBox, opt);
3119 if (currentIndex() < 0 && !placeholderText().isEmpty()) {
3120 opt.palette.setBrush(QPalette::ButtonText, opt.palette.placeholderText());
3121 opt.currentText = placeholderText();
3125 if (itemDelegate() && labelDrawingMode() == QComboBox::LabelDrawingMode::UseDelegate) {
3126 QStyleOptionViewItem itemOption;
3127 d->initViewItemOption(&itemOption);
3128 itemOption.rect = style()->subControlRect(QStyle::CC_ComboBox, &opt,
3129 QStyle::SC_ComboBoxEditField,
this);
3130 itemDelegate()->paint(&painter, itemOption, d->currentIndex);
3133 painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
3138
3139
3140void QComboBox::showEvent(QShowEvent *e)
3143 if (!d->shownOnce && d->sizeAdjustPolicy == QComboBox::AdjustToContentsOnFirstShow) {
3144 d->sizeHint = QSize();
3147 d->shownOnce =
true;
3148 QWidget::showEvent(e);
3152
3153
3154void QComboBox::hideEvent(QHideEvent *)
3160
3161
3162bool QComboBox::event(QEvent *event)
3165 switch(event->type()) {
3166 case QEvent::LayoutDirectionChange:
3167 case QEvent::ApplicationLayoutDirectionChange:
3168 d->updateLayoutDirection();
3169 d->updateLineEditGeometry();
3171 case QEvent::HoverEnter:
3172 case QEvent::HoverLeave:
3173 case QEvent::HoverMove:
3174 if (
const QHoverEvent *he =
static_cast<
const QHoverEvent *>(event))
3175 d->updateHoverControl(he->position().toPoint());
3177 case QEvent::ShortcutOverride:
3179 return d->lineEdit->event(event);
3181#ifdef QT_KEYPAD_NAVIGATION
3182 case QEvent::EnterEditFocus:
3184 d->lineEdit->event(event);
3186 case QEvent::LeaveEditFocus:
3188 d->lineEdit->event(event);
3194 return QWidget::event(event);
3198
3199
3200void QComboBox::mousePressEvent(QMouseEvent *e)
3203 if (!QGuiApplication::styleHints()->setFocusOnTouchRelease())
3204 d->showPopupFromMouseEvent(e);
3207void QComboBoxPrivate::showPopupFromMouseEvent(QMouseEvent *e)
3210 QStyleOptionComboBox opt;
3211 q->initStyleOption(&opt);
3212 QStyle::SubControl sc = q->style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt, e->position().toPoint(), q);
3214 if (e->button() == Qt::LeftButton
3215 && !(sc == QStyle::SC_None && e->type() == QEvent::MouseButtonRelease)
3216 && (sc == QStyle::SC_ComboBoxArrow || !q->isEditable())
3217 && !viewContainer()->isVisible()) {
3218 if (sc == QStyle::SC_ComboBoxArrow)
3219 updateArrow(QStyle::State_Sunken);
3220#ifdef QT_KEYPAD_NAVIGATION
3228 viewContainer()->initialClickPosition = q->mapToGlobal(e->position().toPoint());
3230 QPointer<QComboBox> guard = q;
3237 if (viewContainer()) {
3238 viewContainer()->blockMouseReleaseTimer.start(QApplication::doubleClickInterval());
3239 viewContainer()->maybeIgnoreMouseButtonRelease =
false;
3242#ifdef QT_KEYPAD_NAVIGATION
3243 if (QApplicationPrivate::keypadNavigationEnabled() && sc == QStyle::SC_ComboBoxEditField && lineEdit) {
3253
3254
3255void QComboBox::mouseReleaseEvent(QMouseEvent *e)
3258 d->updateArrow(QStyle::State_None);
3259 if (QGuiApplication::styleHints()->setFocusOnTouchRelease() && hasFocus())
3260 d->showPopupFromMouseEvent(e);
3264
3265
3266void QComboBox::keyPressEvent(QKeyEvent *e)
3270#if QT_CONFIG(completer)
3271 if (
const auto *cmpltr = completer()) {
3272 const auto *popup = QCompleterPrivate::get(cmpltr)->popup;
3273 if (popup && popup->isVisible()) {
3275 d->lineEdit->event(e);
3281 enum Move { NoMove=0 , MoveUp , MoveDown , MoveFirst , MoveLast};
3284 int newIndex = currentIndex();
3286 bool pressLikeButton = !d->lineEdit;
3287#ifdef QT_KEYPAD_NAVIGATION
3288 pressLikeButton |= QApplicationPrivate::keypadNavigationEnabled() && !hasEditFocus();
3290 auto key = e->key();
3291 if (pressLikeButton) {
3292 const auto buttonPressKeys = QGuiApplicationPrivate::platformTheme()
3293 ->themeHint(QPlatformTheme::ButtonPressKeys)
3294 .value<QList<Qt::Key>>();
3295 if (buttonPressKeys.contains(key)) {
3303 if (e->modifiers() & Qt::ControlModifier)
3306 case Qt::Key_PageUp:
3307#ifdef QT_KEYPAD_NAVIGATION
3308 if (QApplicationPrivate::keypadNavigationEnabled())
3315 if (e->modifiers() & Qt::AltModifier) {
3318 }
else if (e->modifiers() & Qt::ControlModifier)
3321 case Qt::Key_PageDown:
3322#ifdef QT_KEYPAD_NAVIGATION
3323 if (QApplicationPrivate::keypadNavigationEnabled())
3338 if (!e->modifiers()) {
3344 case Qt::Key_Return:
3345 case Qt::Key_Escape:
3349#ifdef QT_KEYPAD_NAVIGATION
3352 if (QApplicationPrivate::keypadNavigationEnabled() && !hasEditFocus())
3356 if (QApplicationPrivate::keypadNavigationEnabled()) {
3357 if (!hasEditFocus() || !d->lineEdit)
3365#if QT_CONFIG(shortcut)
3366 if (d->container && d->container->isVisible() && e->matches(QKeySequence::Cancel)) {
3373 const auto text = e->text();
3374 if (!text.isEmpty() && text.at(0).isPrint())
3375 d->keyboardSearchString(text);
3381 const int rowCount = count();
3383 if (move != NoMove) {
3391 while (newIndex < rowCount && !(d->model->index(newIndex, d->modelColumn, d->root).flags() & Qt::ItemIsEnabled))
3395 newIndex = rowCount;
3399 while ((newIndex >= 0) && !(d->model->flags(d->model->index(newIndex,d->modelColumn,d->root)) & Qt::ItemIsEnabled))
3407 if (newIndex >= 0 && newIndex < rowCount && newIndex != currentIndex()) {
3408 setCurrentIndex(newIndex);
3409 d->emitActivated(d->currentIndex);
3411 }
else if (d->lineEdit) {
3412 d->lineEdit->event(e);
3418
3419
3420void QComboBox::keyReleaseEvent(QKeyEvent *e)
3424 d->lineEdit->event(e);
3426 QWidget::keyReleaseEvent(e);
3430
3431
3432#if QT_CONFIG(wheelevent)
3433void QComboBox::wheelEvent(QWheelEvent *e)
3436 QStyleOptionComboBox opt;
3437 initStyleOption(&opt);
3438 if (style()->styleHint(QStyle::SH_ComboBox_AllowWheelScrolling, &opt,
this) &&
3439 !d->viewContainer()->isVisible()) {
3440 const int rowCount = count();
3441 int newIndex = currentIndex();
3442 int delta = e->angleDelta().y();
3446 while ((newIndex >= 0) && !(d->model->flags(d->model->index(newIndex,d->modelColumn,d->root)) & Qt::ItemIsEnabled))
3448 }
else if (delta < 0) {
3450 while (newIndex < rowCount && !(d->model->index(newIndex, d->modelColumn, d->root).flags() & Qt::ItemIsEnabled))
3454 if (newIndex >= 0 && newIndex < rowCount && newIndex != currentIndex()) {
3455 setCurrentIndex(newIndex);
3456 d->emitActivated(d->currentIndex);
3465#ifndef QT_NO_CONTEXTMENU
3467
3468
3469void QComboBox::contextMenuEvent(QContextMenuEvent *e)
3473 Qt::ContextMenuPolicy p = d->lineEdit->contextMenuPolicy();
3474 d->lineEdit->setContextMenuPolicy(Qt::DefaultContextMenu);
3475 d->lineEdit->event(e);
3476 d->lineEdit->setContextMenuPolicy(p);
3481void QComboBoxPrivate::keyboardSearchString(
const QString &text)
3484 QAbstractItemView *view = viewContainer()->itemView();
3485 view->setCurrentIndex(currentIndex);
3486 int currentRow = view->currentIndex().row();
3487 view->keyboardSearch(text);
3488 if (currentRow != view->currentIndex().row()) {
3489 setCurrentIndex(view->currentIndex());
3490 emitActivated(currentIndex);
3494void QComboBoxPrivate::modelChanged()
3498 if (sizeAdjustPolicy == QComboBox::AdjustToContents) {
3500 adjustComboBoxSize();
3501 q->updateGeometry();
3506
3507
3508void QComboBox::inputMethodEvent(QInputMethodEvent *e)
3512 d->lineEdit->event(e);
3514 if (!e->commitString().isEmpty())
3515 d->keyboardSearchString(e->commitString());
3522
3523
3524QVariant QComboBox::inputMethodQuery(Qt::InputMethodQuery query)
const
3526 Q_D(
const QComboBox);
3528 return d->lineEdit->inputMethodQuery(query);
3529 return QWidget::inputMethodQuery(query);
3533
3534QVariant QComboBox::inputMethodQuery(Qt::InputMethodQuery query,
const QVariant &argument)
const
3536 Q_D(
const QComboBox);
3538 return d->lineEdit->inputMethodQuery(query, argument);
3539 return QWidget::inputMethodQuery(query);
3543
3544
3545
3546
3547
3548
3551
3552
3553
3554
3555
3556
3557
3560
3561
3562
3563
3564
3567
3568
3569
3570
3571
3574
3575
3576
3577
3578
3579
3580
3581bool QComboBox::hasFrame()
const
3583 Q_D(
const QComboBox);
3588void QComboBox::setFrame(
bool enable)
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609int QComboBox::modelColumn()
const
3611 Q_D(
const QComboBox);
3612 return d->modelColumn;
3615void QComboBox::setModelColumn(
int visibleColumn)
3618 d->modelColumn = visibleColumn;
3619 QListView *lv = qobject_cast<QListView *>(d->viewContainer()->itemView());
3621 lv->setModelColumn(visibleColumn);
3622#if QT_CONFIG(completer)
3623 if (d->lineEdit && d->lineEdit->completer())
3624 d->lineEdit->completer()->setCompletionColumn(visibleColumn);
3626 setCurrentIndex(currentIndex());
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655QComboBox::LabelDrawingMode QComboBox::labelDrawingMode()
const
3657 Q_D(
const QComboBox);
3658 return d->labelDrawingMode;
3661void QComboBox::setLabelDrawingMode(LabelDrawingMode drawingLabel)
3664 if (d->labelDrawingMode != drawingLabel) {
3665 d->labelDrawingMode = drawingLabel;
3672#include "moc_qcombobox.cpp"
3673#include "moc_qcombobox_p.cpp"