1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtWidgets module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qcombobox.h"
41
42#ifndef QT_NO_COMBOBOX
43#include <qstylepainter.h>
44#include <qpa/qplatformtheme.h>
45#include <qpa/qplatformmenu.h>
46#include <qlineedit.h>
47#include <qapplication.h>
48#include <qdesktopwidget.h>
49#include <qlistview.h>
50#include <qtableview.h>
51#include <qitemdelegate.h>
52#include <qmap.h>
53#include <qmenu.h>
54#include <qevent.h>
55#include <qlayout.h>
56#include <qscrollbar.h>
57#include <qtreeview.h>
58#include <qheaderview.h>
59#include <qmath.h>
60#include <qmetaobject.h>
61#include <qabstractproxymodel.h>
62#include <qstylehints.h>
63#include <private/qguiapplication_p.h>
64#include <private/qapplication_p.h>
65#include <private/qcombobox_p.h>
66#include <private/qabstractitemmodel_p.h>
67#include <private/qabstractscrollarea_p.h>
68#include <private/qlineedit_p.h>
69#include <qdebug.h>
70#ifndef QT_NO_EFFECTS
71# include <private/qeffects_p.h>
72#endif
73#ifndef QT_NO_ACCESSIBILITY
74#include "qaccessible.h"
75#endif
76
77QT_BEGIN_NAMESPACE
78
79QComboBoxPrivate::QComboBoxPrivate()
80 : QWidgetPrivate(),
81 model(0),
82 lineEdit(0),
83 container(0),
84 insertPolicy(QComboBox::InsertAtBottom),
85 sizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow),
86 minimumContentsLength(0),
87 shownOnce(false),
88 autoCompletion(true),
89 duplicatesEnabled(false),
90 frame(true),
91 maxVisibleItems(10),
92 maxCount(INT_MAX),
93 modelColumn(0),
94 inserting(false),
95 arrowState(QStyle::State_None),
96 hoverControl(QStyle::SC_None),
97 autoCompletionCaseSensitivity(Qt::CaseInsensitive),
98 indexBeforeChange(-1)
99#ifdef Q_OS_MAC
100 , m_platformMenu(0)
101#endif
102#ifndef QT_NO_COMPLETER
103 , completer(0)
104#endif
105{
106}
107
108QComboBoxPrivate::~QComboBoxPrivate()
109{
110#ifdef Q_OS_MAC
111 cleanupNativePopup();
112#endif
113}
114
115QStyleOptionMenuItem QComboMenuDelegate::getStyleOption(const QStyleOptionViewItem &option,
116 const QModelIndex &index) const
117{
118 QStyleOptionMenuItem menuOption;
119
120 QPalette resolvedpalette = option.palette.resolve(QApplication::palette("QMenu"));
121 QVariant value = index.data(Qt::ForegroundRole);
122 if (value.canConvert<QBrush>()) {
123 resolvedpalette.setBrush(QPalette::WindowText, qvariant_cast<QBrush>(value));
124 resolvedpalette.setBrush(QPalette::ButtonText, qvariant_cast<QBrush>(value));
125 resolvedpalette.setBrush(QPalette::Text, qvariant_cast<QBrush>(value));
126 }
127 menuOption.palette = resolvedpalette;
128 menuOption.state = QStyle::State_None;
129 if (mCombo->window()->isActiveWindow())
130 menuOption.state = QStyle::State_Active;
131 if ((option.state & QStyle::State_Enabled) && (index.model()->flags(index) & Qt::ItemIsEnabled))
132 menuOption.state |= QStyle::State_Enabled;
133 else
134 menuOption.palette.setCurrentColorGroup(QPalette::Disabled);
135 if (option.state & QStyle::State_Selected)
136 menuOption.state |= QStyle::State_Selected;
137 menuOption.checkType = QStyleOptionMenuItem::NonExclusive;
138 menuOption.checked = mCombo->currentIndex() == index.row();
139 if (QComboBoxDelegate::isSeparator(index))
140 menuOption.menuItemType = QStyleOptionMenuItem::Separator;
141 else
142 menuOption.menuItemType = QStyleOptionMenuItem::Normal;
143
144 QVariant variant = index.model()->data(index, Qt::DecorationRole);
145 switch (variant.type()) {
146 case QVariant::Icon:
147 menuOption.icon = qvariant_cast<QIcon>(variant);
148 break;
149 case QVariant::Color: {
150 static QPixmap pixmap(option.decorationSize);
151 pixmap.fill(qvariant_cast<QColor>(variant));
152 menuOption.icon = pixmap;
153 break; }
154 default:
155 menuOption.icon = qvariant_cast<QPixmap>(variant);
156 break;
157 }
158 if (index.data(Qt::BackgroundRole).canConvert<QBrush>()) {
159 menuOption.palette.setBrush(QPalette::All, QPalette::Background,
160 qvariant_cast<QBrush>(index.data(Qt::BackgroundRole)));
161 }
162 menuOption.text = index.model()->data(index, Qt::DisplayRole).toString()
163 .replace(QLatin1Char('&'), QLatin1String("&&"));
164 menuOption.tabWidth = 0;
165 menuOption.maxIconWidth = option.decorationSize.width() + 4;
166 menuOption.menuRect = option.rect;
167 menuOption.rect = option.rect;
168
169 // Make sure fonts set on the model or on the combo box, in
170 // that order, also override the font for the popup menu.
171 QVariant fontRoleData = index.data(Qt::FontRole);
172 if (fontRoleData.isValid()) {
173 menuOption.font = fontRoleData.value<QFont>();
174 } else if (mCombo->testAttribute(Qt::WA_SetFont)
175 || mCombo->testAttribute(Qt::WA_MacSmallSize)
176 || mCombo->testAttribute(Qt::WA_MacMiniSize)
177 || mCombo->font() != qt_app_fonts_hash()->value("QComboBox", QFont())) {
178 menuOption.font = mCombo->font();
179 } else {
180 menuOption.font = qt_app_fonts_hash()->value("QComboMenuItem", mCombo->font());
181 }
182
183 menuOption.fontMetrics = QFontMetrics(menuOption.font);
184
185 return menuOption;
186}
187
188#ifndef QT_NO_COMPLETER
189void QComboBoxPrivate::_q_completerActivated(const QModelIndex &index)
190{
191 Q_Q(QComboBox);
192 if (index.isValid() && q->completer()) {
193 QAbstractProxyModel *proxy = qobject_cast<QAbstractProxyModel *>(q->completer()->completionModel());
194 if (proxy) {
195 q->setCurrentIndex(proxy->mapToSource(index).row());
196 emitActivated(currentIndex);
197 }
198 }
199
200# ifdef QT_KEYPAD_NAVIGATION
201 if ( QApplication::keypadNavigationEnabled()
202 && q->isEditable()
203 && q->completer()
204 && q->completer()->completionMode() == QCompleter::UnfilteredPopupCompletion ) {
205 q->setEditFocus(false);
206 }
207# endif // QT_KEYPAD_NAVIGATION
208}
209#endif // !QT_NO_COMPLETER
210
211void QComboBoxPrivate::updateArrow(QStyle::StateFlag state)
212{
213 Q_Q(QComboBox);
214 if (arrowState == state)
215 return;
216 arrowState = state;
217 QStyleOptionComboBox opt;
218 q->initStyleOption(&opt);
219 q->update(q->rect());
220}
221
222void QComboBoxPrivate::_q_modelReset()
223{
224 Q_Q(QComboBox);
225 if (lineEdit) {
226 lineEdit->setText(QString());
227 updateLineEditGeometry();
228 }
229 if (currentIndex.row() != indexBeforeChange)
230 _q_emitCurrentIndexChanged(currentIndex);
231 modelChanged();
232 q->update();
233}
234
235void QComboBoxPrivate::_q_modelDestroyed()
236{
237 model = QAbstractItemModelPrivate::staticEmptyModel();
238}
239
240
241//Windows and KDE allows menus to cover the taskbar, while GNOME and Mac don't
242QRect QComboBoxPrivate::popupGeometry(int screen) const
243{
244 bool useFullScreenForPopupMenu = false;
245 if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
246 useFullScreenForPopupMenu = theme->themeHint(QPlatformTheme::UseFullScreenForPopupMenu).toBool();
247 return useFullScreenForPopupMenu ?
248 QApplication::desktop()->screenGeometry(screen) :
249 QApplication::desktop()->availableGeometry(screen);
250}
251
252bool QComboBoxPrivate::updateHoverControl(const QPoint &pos)
253{
254
255 Q_Q(QComboBox);
256 QRect lastHoverRect = hoverRect;
257 QStyle::SubControl lastHoverControl = hoverControl;
258 bool doesHover = q->testAttribute(Qt::WA_Hover);
259 if (lastHoverControl != newHoverControl(pos) && doesHover) {
260 q->update(lastHoverRect);
261 q->update(hoverRect);
262 return true;
263 }
264 return !doesHover;
265}
266
267QStyle::SubControl QComboBoxPrivate::newHoverControl(const QPoint &pos)
268{
269 Q_Q(QComboBox);
270 QStyleOptionComboBox opt;
271 q->initStyleOption(&opt);
272 opt.subControls = QStyle::SC_All;
273 hoverControl = q->style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt, pos, q);
274 hoverRect = (hoverControl != QStyle::SC_None)
275 ? q->style()->subControlRect(QStyle::CC_ComboBox, &opt, hoverControl, q)
276 : QRect();
277 return hoverControl;
278}
279
280/*
281 Computes a size hint based on the maximum width
282 for the items in the combobox.
283*/
284int QComboBoxPrivate::computeWidthHint() const
285{
286 Q_Q(const QComboBox);
287
288 int width = 0;
289 const int count = q->count();
290 const int iconWidth = q->iconSize().width() + 4;
291 const QFontMetrics &fontMetrics = q->fontMetrics();
292
293 for (int i = 0; i < count; ++i) {
294 const int textWidth = fontMetrics.width(q->itemText(i));
295 if (q->itemIcon(i).isNull())
296 width = (qMax(width, textWidth));
297 else
298 width = (qMax(width, textWidth + iconWidth));
299 }
300
301 QStyleOptionComboBox opt;
302 q->initStyleOption(&opt);
303 QSize tmp(width, 0);
304 tmp = q->style()->sizeFromContents(QStyle::CT_ComboBox, &opt, tmp, q);
305 return tmp.width();
306}
307
308QSize QComboBoxPrivate::recomputeSizeHint(QSize &sh) const
309{
310 Q_Q(const QComboBox);
311 if (!sh.isValid()) {
312 bool hasIcon = sizeAdjustPolicy == QComboBox::AdjustToMinimumContentsLengthWithIcon;
313 int count = q->count();
314 QSize iconSize = q->iconSize();
315 const QFontMetrics &fm = q->fontMetrics();
316
317 // text width
318 if (&sh == &sizeHint || minimumContentsLength == 0) {
319 switch (sizeAdjustPolicy) {
320 case QComboBox::AdjustToContents:
321 case QComboBox::AdjustToContentsOnFirstShow:
322 if (count == 0) {
323 sh.rwidth() = 7 * fm.width(QLatin1Char('x'));
324 } else {
325 for (int i = 0; i < count; ++i) {
326 if (!q->itemIcon(i).isNull()) {
327 hasIcon = true;
328 sh.setWidth(qMax(sh.width(), fm.boundingRect(q->itemText(i)).width() + iconSize.width() + 4));
329 } else {
330 sh.setWidth(qMax(sh.width(), fm.boundingRect(q->itemText(i)).width()));
331 }
332 }
333 }
334 break;
335 case QComboBox::AdjustToMinimumContentsLength:
336 for (int i = 0; i < count && !hasIcon; ++i)
337 hasIcon = !q->itemIcon(i).isNull();
338 default:
339 ;
340 }
341 } else {
342 for (int i = 0; i < count && !hasIcon; ++i)
343 hasIcon = !q->itemIcon(i).isNull();
344 }
345 if (minimumContentsLength > 0)
346 sh.setWidth(qMax(sh.width(), minimumContentsLength * fm.width(QLatin1Char('X')) + (hasIcon ? iconSize.width() + 4 : 0)));
347
348
349 // height
350 sh.setHeight(qMax(qCeil(QFontMetricsF(fm).height()), 14) + 2);
351 if (hasIcon) {
352 sh.setHeight(qMax(sh.height(), iconSize.height() + 2));
353 }
354
355 // add style and strut values
356 QStyleOptionComboBox opt;
357 q->initStyleOption(&opt);
358 sh = q->style()->sizeFromContents(QStyle::CT_ComboBox, &opt, sh, q);
359 }
360 return sh.expandedTo(QApplication::globalStrut());
361}
362
363void QComboBoxPrivate::adjustComboBoxSize()
364{
365 viewContainer()->adjustSizeTimer.start(20, container);
366}
367
368void QComboBoxPrivate::updateLayoutDirection()
369{
370 Q_Q(const QComboBox);
371 QStyleOptionComboBox opt;
372 q->initStyleOption(&opt);
373 Qt::LayoutDirection dir = Qt::LayoutDirection(
374 q->style()->styleHint(QStyle::SH_ComboBox_LayoutDirection, &opt, q));
375 if (lineEdit)
376 lineEdit->setLayoutDirection(dir);
377 if (container)
378 container->setLayoutDirection(dir);
379}
380
381
382void QComboBoxPrivateContainer::timerEvent(QTimerEvent *timerEvent)
383{
384 if (timerEvent->timerId() == adjustSizeTimer.timerId()) {
385 adjustSizeTimer.stop();
386 if (combo->sizeAdjustPolicy() == QComboBox::AdjustToContents) {
387 combo->updateGeometry();
388 combo->adjustSize();
389 combo->update();
390 }
391 }
392}
393
394void QComboBoxPrivateContainer::resizeEvent(QResizeEvent *e)
395{
396 QStyleOptionComboBox opt = comboStyleOption();
397 if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo)) {
398 QStyleOption myOpt;
399 myOpt.initFrom(this);
400 QStyleHintReturnMask mask;
401 if (combo->style()->styleHint(QStyle::SH_Menu_Mask, &myOpt, this, &mask)) {
402 setMask(mask.region);
403 }
404 } else {
405 clearMask();
406 }
407 QFrame::resizeEvent(e);
408}
409
410void QComboBoxPrivateContainer::leaveEvent(QEvent *)
411{
412// On Mac using the Mac style we want to clear the selection
413// when the mouse moves outside the popup.
414#if 0 // Used to be included in Qt4 for Q_WS_MAC
415 QStyleOptionComboBox opt = comboStyleOption();
416 if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo))
417 view->clearSelection();
418#endif
419}
420
421QComboBoxPrivateContainer::QComboBoxPrivateContainer(QAbstractItemView *itemView, QComboBox *parent)
422 : QFrame(parent, Qt::Popup), combo(parent), view(0), top(0), bottom(0), maybeIgnoreMouseButtonRelease(false)
423{
424 // we need the combobox and itemview
425 Q_ASSERT(parent);
426 Q_ASSERT(itemView);
427
428 setAttribute(Qt::WA_WindowPropagation);
429 setAttribute(Qt::WA_X11NetWmWindowTypeCombo);
430
431 // setup container
432 blockMouseReleaseTimer.setSingleShot(true);
433
434 // we need a vertical layout
435 QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, this);
436 layout->setSpacing(0);
437 layout->setMargin(0);
438
439 // set item view
440 setItemView(itemView);
441
442 // add scroller arrows if style needs them
443 QStyleOptionComboBox opt = comboStyleOption();
444 const bool usePopup = combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo);
445 if (usePopup) {
446 top = new QComboBoxPrivateScroller(QAbstractSlider::SliderSingleStepSub, this);
447 bottom = new QComboBoxPrivateScroller(QAbstractSlider::SliderSingleStepAdd, this);
448 top->hide();
449 bottom->hide();
450 } else {
451 setLineWidth(1);
452 }
453
454 setFrameStyle(combo->style()->styleHint(QStyle::SH_ComboBox_PopupFrameStyle, &opt, combo));
455
456 if (top) {
457 layout->insertWidget(0, top);
458 connect(top, SIGNAL(doScroll(int)), this, SLOT(scrollItemView(int)));
459 }
460 if (bottom) {
461 layout->addWidget(bottom);
462 connect(bottom, SIGNAL(doScroll(int)), this, SLOT(scrollItemView(int)));
463 }
464
465 // Some styles (Mac) have a margin at the top and bottom of the popup.
466 layout->insertSpacing(0, 0);
467 layout->addSpacing(0);
468 updateTopBottomMargin();
469}
470
471void QComboBoxPrivateContainer::scrollItemView(int action)
472{
473#ifndef QT_NO_SCROLLBAR
474 if (view->verticalScrollBar())
475 view->verticalScrollBar()->triggerAction(static_cast<QAbstractSlider::SliderAction>(action));
476#endif
477}
478
479/*
480 Hides or shows the scrollers when we emulate a popupmenu
481*/
482void QComboBoxPrivateContainer::updateScrollers()
483{
484#ifndef QT_NO_SCROLLBAR
485 if (!top || !bottom)
486 return;
487
488 if (isVisible() == false)
489 return;
490
491 QStyleOptionComboBox opt = comboStyleOption();
492 if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo) &&
493 view->verticalScrollBar()->minimum() < view->verticalScrollBar()->maximum()) {
494
495 bool needTop = view->verticalScrollBar()->value()
496 > (view->verticalScrollBar()->minimum() + topMargin());
497 bool needBottom = view->verticalScrollBar()->value()
498 < (view->verticalScrollBar()->maximum() - bottomMargin() - topMargin());
499 if (needTop)
500 top->show();
501 else
502 top->hide();
503 if (needBottom)
504 bottom->show();
505 else
506 bottom->hide();
507 } else {
508 top->hide();
509 bottom->hide();
510 }
511#endif // QT_NO_SCROLLBAR
512}
513
514/*
515 Cleans up when the view is destroyed.
516*/
517void QComboBoxPrivateContainer::viewDestroyed()
518{
519 view = 0;
520 setItemView(new QComboBoxListView());
521}
522
523/*
524 Returns the item view used for the combobox popup.
525*/
526QAbstractItemView *QComboBoxPrivateContainer::itemView() const
527{
528 return view;
529}
530
531/*!
532 Sets the item view to be used for the combobox popup.
533*/
534void QComboBoxPrivateContainer::setItemView(QAbstractItemView *itemView)
535{
536 Q_ASSERT(itemView);
537
538 // clean up old one
539 if (view) {
540 view->removeEventFilter(this);
541 view->viewport()->removeEventFilter(this);
542#ifndef QT_NO_SCROLLBAR
543 disconnect(view->verticalScrollBar(), SIGNAL(valueChanged(int)),
544 this, SLOT(updateScrollers()));
545 disconnect(view->verticalScrollBar(), SIGNAL(rangeChanged(int,int)),
546 this, SLOT(updateScrollers()));
547#endif
548 disconnect(view, SIGNAL(destroyed()),
549 this, SLOT(viewDestroyed()));
550
551 if (isAncestorOf(view))
552 delete view;
553 view = 0;
554 }
555
556 // setup the item view
557 view = itemView;
558 view->setParent(this);
559 view->setAttribute(Qt::WA_MacShowFocusRect, false);
560 qobject_cast<QBoxLayout*>(layout())->insertWidget(top ? 2 : 0, view);
561 view->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
562 view->installEventFilter(this);
563 view->viewport()->installEventFilter(this);
564 view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
565 QStyleOptionComboBox opt = comboStyleOption();
566 const bool usePopup = combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo);
567#ifndef QT_NO_SCROLLBAR
568 if (usePopup)
569 view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
570#endif
571 if (combo->style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking, &opt, combo) ||
572 usePopup) {
573 view->setMouseTracking(true);
574 }
575 view->setSelectionMode(QAbstractItemView::SingleSelection);
576 view->setFrameStyle(QFrame::NoFrame);
577 view->setLineWidth(0);
578 view->setEditTriggers(QAbstractItemView::NoEditTriggers);
579#ifndef QT_NO_SCROLLBAR
580 connect(view->verticalScrollBar(), SIGNAL(valueChanged(int)),
581 this, SLOT(updateScrollers()));
582 connect(view->verticalScrollBar(), SIGNAL(rangeChanged(int,int)),
583 this, SLOT(updateScrollers()));
584#endif
585 connect(view, SIGNAL(destroyed()),
586 this, SLOT(viewDestroyed()));
587}
588
589/*!
590 Returns the top/bottom vertical margin of the view.
591*/
592int QComboBoxPrivateContainer::topMargin() const
593{
594 if (const QListView *lview = qobject_cast<const QListView*>(view))
595 return lview->spacing();
596#ifndef QT_NO_TABLEVIEW
597 if (const QTableView *tview = qobject_cast<const QTableView*>(view))
598 return tview->showGrid() ? 1 : 0;
599#endif
600 return 0;
601}
602
603/*!
604 Returns the spacing between the items in the view.
605*/
606int QComboBoxPrivateContainer::spacing() const
607{
608 QListView *lview = qobject_cast<QListView*>(view);
609 if (lview)
610 return 2 * lview->spacing(); // QListView::spacing is the padding around the item.
611#ifndef QT_NO_TABLEVIEW
612 QTableView *tview = qobject_cast<QTableView*>(view);
613 if (tview)
614 return tview->showGrid() ? 1 : 0;
615#endif
616 return 0;
617}
618
619void QComboBoxPrivateContainer::updateTopBottomMargin()
620{
621 if (!layout() || layout()->count() < 1)
622 return;
623
624 QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(layout());
625 if (!boxLayout)
626 return;
627
628 const QStyleOptionComboBox opt = comboStyleOption();
629 const bool usePopup = combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo);
630 const int margin = usePopup ? combo->style()->pixelMetric(QStyle::PM_MenuVMargin, &opt, combo) : 0;
631
632 QSpacerItem *topSpacer = boxLayout->itemAt(0)->spacerItem();
633 if (topSpacer)
634 topSpacer->changeSize(0, margin, QSizePolicy::Minimum, QSizePolicy::Fixed);
635
636 QSpacerItem *bottomSpacer = boxLayout->itemAt(boxLayout->count() - 1)->spacerItem();
637 if (bottomSpacer && bottomSpacer != topSpacer)
638 bottomSpacer->changeSize(0, margin, QSizePolicy::Minimum, QSizePolicy::Fixed);
639
640 boxLayout->invalidate();
641}
642
643void QComboBoxPrivateContainer::changeEvent(QEvent *e)
644{
645 if (e->type() == QEvent::StyleChange) {
646 QStyleOptionComboBox opt = comboStyleOption();
647 view->setMouseTracking(combo->style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking, &opt, combo) ||
648 combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo));
649 setFrameStyle(combo->style()->styleHint(QStyle::SH_ComboBox_PopupFrameStyle, &opt, combo));
650 }
651
652 QWidget::changeEvent(e);
653}
654
655
656bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e)
657{
658 switch (e->type()) {
659 case QEvent::ShortcutOverride: {
660 QKeyEvent *keyEvent = static_cast<QKeyEvent*>(e);
661 switch (keyEvent->key()) {
662 case Qt::Key_Enter:
663 case Qt::Key_Return:
664#ifdef QT_KEYPAD_NAVIGATION
665 case Qt::Key_Select:
666#endif
667 if (view->currentIndex().isValid() && (view->currentIndex().flags() & Qt::ItemIsEnabled) ) {
668 combo->hidePopup();
669 emit itemSelected(view->currentIndex());
670 }
671 return true;
672 case Qt::Key_Down:
673 if (!(keyEvent->modifiers() & Qt::AltModifier))
674 break;
675 Q_FALLTHROUGH();
676 case Qt::Key_F4:
677 combo->hidePopup();
678 return true;
679 default:
680#if QT_CONFIG(shortcut)
681 if (keyEvent->matches(QKeySequence::Cancel)) {
682 combo->hidePopup();
683 return true;
684 }
685#endif
686 break;
687 }
688 break;
689 }
690 case QEvent::MouseMove:
691 if (isVisible()) {
692 QMouseEvent *m = static_cast<QMouseEvent *>(e);
693 QWidget *widget = static_cast<QWidget *>(o);
694 QPoint vector = widget->mapToGlobal(m->pos()) - initialClickPosition;
695 if (vector.manhattanLength() > 9 && blockMouseReleaseTimer.isActive())
696 blockMouseReleaseTimer.stop();
697 QModelIndex indexUnderMouse = view->indexAt(m->pos());
698 if (indexUnderMouse.isValid()
699 && !QComboBoxDelegate::isSeparator(indexUnderMouse)) {
700 view->setCurrentIndex(indexUnderMouse);
701 }
702 }
703 break;
704 case QEvent::MouseButtonPress:
705 maybeIgnoreMouseButtonRelease = false;
706 break;
707 case QEvent::MouseButtonRelease: {
708 bool ignoreEvent = maybeIgnoreMouseButtonRelease && popupTimer.elapsed() < QApplication::doubleClickInterval();
709
710 QMouseEvent *m = static_cast<QMouseEvent *>(e);
711 if (isVisible() && view->rect().contains(m->pos()) && view->currentIndex().isValid()
712 && !blockMouseReleaseTimer.isActive() && !ignoreEvent
713 && (view->currentIndex().flags() & Qt::ItemIsEnabled)
714 && (view->currentIndex().flags() & Qt::ItemIsSelectable)) {
715 combo->hidePopup();
716 emit itemSelected(view->currentIndex());
717 return true;
718 }
719 break;
720 }
721 default:
722 break;
723 }
724 return QFrame::eventFilter(o, e);
725}
726
727void QComboBoxPrivateContainer::showEvent(QShowEvent *)
728{
729 combo->update();
730}
731
732void QComboBoxPrivateContainer::hideEvent(QHideEvent *)
733{
734 emit resetButton();
735 combo->update();
736#ifndef QT_NO_GRAPHICSVIEW
737 // QGraphicsScenePrivate::removePopup closes the combo box popup, it hides it non-explicitly.
738 // Hiding/showing the QComboBox after this will unexpectedly show the popup as well.
739 // Re-hiding the popup container makes sure it is explicitly hidden.
740 if (QGraphicsProxyWidget *proxy = graphicsProxyWidget())
741 proxy->hide();
742#endif
743}
744
745void QComboBoxPrivateContainer::mousePressEvent(QMouseEvent *e)
746{
747
748 QStyleOptionComboBox opt = comboStyleOption();
749 opt.subControls = QStyle::SC_All;
750 opt.activeSubControls = QStyle::SC_ComboBoxArrow;
751 QStyle::SubControl sc = combo->style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt,
752 combo->mapFromGlobal(e->globalPos()),
753 combo);
754 if ((combo->isEditable() && sc == QStyle::SC_ComboBoxArrow)
755 || (!combo->isEditable() && sc != QStyle::SC_None))
756 setAttribute(Qt::WA_NoMouseReplay);
757 combo->hidePopup();
758}
759
760void QComboBoxPrivateContainer::mouseReleaseEvent(QMouseEvent *e)
761{
762 Q_UNUSED(e);
763 if (!blockMouseReleaseTimer.isActive()){
764 combo->hidePopup();
765 emit resetButton();
766 }
767}
768
769QStyleOptionComboBox QComboBoxPrivateContainer::comboStyleOption() const
770{
771 // ### This should use QComboBox's initStyleOption(), but it's protected
772 // perhaps, we could cheat by having the QCombo private instead?
773 QStyleOptionComboBox opt;
774 opt.initFrom(combo);
775 opt.subControls = QStyle::SC_All;
776 opt.activeSubControls = QStyle::SC_None;
777 opt.editable = combo->isEditable();
778 return opt;
779}
780
781/*!
782 \enum QComboBox::InsertPolicy
783
784 This enum specifies what the QComboBox should do when a new string is
785 entered by the user.
786
787 \value NoInsert The string will not be inserted into the combobox.
788 \value InsertAtTop The string will be inserted as the first item in the combobox.
789 \value InsertAtCurrent The current item will be \e replaced by the string.
790 \value InsertAtBottom The string will be inserted after the last item in the combobox.
791 \value InsertAfterCurrent The string is inserted after the current item in the combobox.
792 \value InsertBeforeCurrent The string is inserted before the current item in the combobox.
793 \value InsertAlphabetically The string is inserted in the alphabetic order in the combobox.
794*/
795
796/*!
797 \enum QComboBox::SizeAdjustPolicy
798
799 This enum specifies how the size hint of the QComboBox should
800 adjust when new content is added or content changes.
801
802 \value AdjustToContents The combobox will always adjust to the contents
803 \value AdjustToContentsOnFirstShow The combobox will adjust to its contents the first time it is shown.
804 \value AdjustToMinimumContentsLength Use AdjustToContents or AdjustToContentsOnFirstShow instead.
805 \value AdjustToMinimumContentsLengthWithIcon The combobox will adjust to \l minimumContentsLength plus space for an icon. For performance reasons use this policy on large models.
806*/
807
808/*!
809 \fn void QComboBox::activated(int index)
810
811 This signal is sent when the user chooses an item in the combobox.
812 The item's \a index is passed. Note that this signal is sent even
813 when the choice is not changed. If you need to know when the
814 choice actually changes, use signal currentIndexChanged().
815
816*/
817
818/*!
819 \fn void QComboBox::activated(const QString &text)
820
821 This signal is sent when the user chooses an item in the combobox.
822 The item's \a text is passed. Note that this signal is sent even
823 when the choice is not changed. If you need to know when the
824 choice actually changes, use signal currentIndexChanged().
825
826*/
827
828/*!
829 \fn void QComboBox::highlighted(int index)
830
831 This signal is sent when an item in the combobox popup list is
832 highlighted by the user. The item's \a index is passed.
833*/
834
835/*!
836 \fn void QComboBox::highlighted(const QString &text)
837
838 This signal is sent when an item in the combobox popup list is
839 highlighted by the user. The item's \a text is passed.
840*/
841
842/*!
843 \fn void QComboBox::currentIndexChanged(int index)
844 \since 4.1
845
846 This signal is sent whenever the currentIndex in the combobox
847 changes either through user interaction or programmatically. The
848 item's \a index is passed or -1 if the combobox becomes empty or the
849 currentIndex was reset.
850*/
851
852/*!
853 \fn void QComboBox::currentIndexChanged(const QString &text)
854 \since 4.1
855
856 This signal is sent whenever the currentIndex in the combobox
857 changes either through user interaction or programmatically. The
858 item's \a text is passed.
859*/
860
861/*!
862 \fn void QComboBox::currentTextChanged(const QString &text)
863 \since 5.0
864
865 This signal is sent whenever currentText changes. The new value
866 is passed as \a text.
867*/
868
869/*!
870 Constructs a combobox with the given \a parent, using the default
871 model QStandardItemModel.
872*/
873QComboBox::QComboBox(QWidget *parent)
874 : QWidget(*new QComboBoxPrivate(), parent, 0)
875{
876 Q_D(QComboBox);
877 d->init();
878}
879
880/*!
881 \internal
882*/
883QComboBox::QComboBox(QComboBoxPrivate &dd, QWidget *parent)
884 : QWidget(dd, parent, 0)
885{
886 Q_D(QComboBox);
887 d->init();
888}
889
890
891/*!
892 \class QComboBox
893 \brief The QComboBox widget is a combined button and popup list.
894
895 \ingroup basicwidgets
896 \inmodule QtWidgets
897
898 A QComboBox provides a means of presenting a list of options to the user
899 in a way that takes up the minimum amount of screen space.
900
901 A combobox is a selection widget that displays the current item,
902 and can pop up a list of selectable items. A combobox may be editable,
903 allowing the user to modify each item in the list.
904
905 Comboboxes can contain pixmaps as well as strings; the
906 insertItem() and setItemText() functions are suitably overloaded.
907 For editable comboboxes, the function clearEditText() is provided,
908 to clear the displayed string without changing the combobox's
909 contents.
910
911 There are two signals emitted if the current item of a combobox
912 changes, currentIndexChanged() and activated().
913 currentIndexChanged() is always emitted regardless if the change
914 was done programmatically or by user interaction, while
915 activated() is only emitted when the change is caused by user
916 interaction. The highlighted() signal is emitted when the user
917 highlights an item in the combobox popup list. All three signals
918 exist in two versions, one with a QString argument and one with an
919 \c int argument. If the user selects or highlights a pixmap, only
920 the \c int signals are emitted. Whenever the text of an editable
921 combobox is changed the editTextChanged() signal is emitted.
922
923 When the user enters a new string in an editable combobox, the
924 widget may or may not insert it, and it can insert it in several
925 locations. The default policy is \l InsertAtBottom but you can change
926 this using setInsertPolicy().
927
928 It is possible to constrain the input to an editable combobox
929 using QValidator; see setValidator(). By default, any input is
930 accepted.
931
932 A combobox can be populated using the insert functions,
933 insertItem() and insertItems() for example. Items can be
934 changed with setItemText(). An item can be removed with
935 removeItem() and all items can be removed with clear(). The text
936 of the current item is returned by currentText(), and the text of
937 a numbered item is returned with text(). The current item can be
938 set with setCurrentIndex(). The number of items in the combobox is
939 returned by count(); the maximum number of items can be set with
940 setMaxCount(). You can allow editing using setEditable(). For
941 editable comboboxes you can set auto-completion using
942 setCompleter() and whether or not the user can add duplicates
943 is set with setDuplicatesEnabled().
944
945 QComboBox uses the \l{Model/View Programming}{model/view
946 framework} for its popup list and to store its items. By default
947 a QStandardItemModel stores the items and a QListView subclass
948 displays the popuplist. You can access the model and view directly
949 (with model() and view()), but QComboBox also provides functions
950 to set and get item data (e.g., setItemData() and itemText()). You
951 can also set a new model and view (with setModel() and setView()).
952 For the text and icon in the combobox label, the data in the model
953 that has the Qt::DisplayRole and Qt::DecorationRole is used. Note
954 that you cannot alter the \l{QAbstractItemView::}{SelectionMode}
955 of the view(), e.g., by using
956 \l{QAbstractItemView::}{setSelectionMode()}.
957
958 \image qstyle-comboboxes.png Comboboxes in the different built-in styles.
959
960 \sa QLineEdit, QSpinBox, QRadioButton, QButtonGroup,
961 {fowler}{GUI Design Handbook: Combo Box, Drop-Down List Box}
962*/
963
964void QComboBoxPrivate::init()
965{
966 Q_Q(QComboBox);
967#ifdef Q_OS_OSX
968 // On OS X, only line edits and list views always get tab focus. It's only
969 // when we enable full keyboard access that other controls can get tab focus.
970 // When it's not editable, a combobox looks like a button, and it behaves as
971 // such in this respect.
972 if (!q->isEditable())
973 q->setFocusPolicy(Qt::TabFocus);
974 else
975#endif
976 q->setFocusPolicy(Qt::WheelFocus);
977
978 q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed,
979 QSizePolicy::ComboBox));
980 setLayoutItemMargins(QStyle::SE_ComboBoxLayoutItem);
981 q->setModel(new QStandardItemModel(0, 1, q));
982 if (!q->isEditable())
983 q->setAttribute(Qt::WA_InputMethodEnabled, false);
984 else
985 q->setAttribute(Qt::WA_InputMethodEnabled);
986}
987
988QComboBoxPrivateContainer* QComboBoxPrivate::viewContainer()
989{
990 if (container)
991 return container;
992
993 Q_Q(QComboBox);
994 container = new QComboBoxPrivateContainer(new QComboBoxListView(q), q);
995 container->itemView()->setModel(model);
996 container->itemView()->setTextElideMode(Qt::ElideMiddle);
997 updateDelegate(true);
998 updateLayoutDirection();
999 updateViewContainerPaletteAndOpacity();
1000 QObject::connect(container, SIGNAL(itemSelected(QModelIndex)),
1001 q, SLOT(_q_itemSelected(QModelIndex)));
1002 QObject::connect(container->itemView()->selectionModel(),
1003 SIGNAL(currentChanged(QModelIndex,QModelIndex)),
1004 q, SLOT(_q_emitHighlighted(QModelIndex)));
1005 QObject::connect(container, SIGNAL(resetButton()), q, SLOT(_q_resetButton()));
1006 return container;
1007}
1008
1009
1010void QComboBoxPrivate::_q_resetButton()
1011{
1012 updateArrow(QStyle::State_None);
1013}
1014
1015void QComboBoxPrivate::_q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
1016{
1017 Q_Q(QComboBox);
1018 if (inserting || topLeft.parent() != root)
1019 return;
1020
1021 if (sizeAdjustPolicy == QComboBox::AdjustToContents) {
1022 sizeHint = QSize();
1023 adjustComboBoxSize();
1024 q->updateGeometry();
1025 }
1026
1027 if (currentIndex.row() >= topLeft.row() && currentIndex.row() <= bottomRight.row()) {
1028 const QString text = q->itemText(currentIndex.row());
1029 if (lineEdit) {
1030 lineEdit->setText(text);
1031 updateLineEditGeometry();
1032 } else {
1033 emit q->currentTextChanged(text);
1034 }
1035 q->update();
1036#ifndef QT_NO_ACCESSIBILITY
1037 QAccessibleValueChangeEvent event(q, text);
1038 QAccessible::updateAccessibility(&event);
1039#endif
1040 }
1041}
1042
1043void QComboBoxPrivate::_q_rowsInserted(const QModelIndex &parent, int start, int end)
1044{
1045 Q_Q(QComboBox);
1046 if (inserting || parent != root)
1047 return;
1048
1049 if (sizeAdjustPolicy == QComboBox::AdjustToContents) {
1050 sizeHint = QSize();
1051 adjustComboBoxSize();
1052 q->updateGeometry();
1053 }
1054
1055 // set current index if combo was previously empty
1056 if (start == 0 && (end - start + 1) == q->count() && !currentIndex.isValid()) {
1057 q->setCurrentIndex(0);
1058 // need to emit changed if model updated index "silently"
1059 } else if (currentIndex.row() != indexBeforeChange) {
1060 q->update();
1061 _q_emitCurrentIndexChanged(currentIndex);
1062 }
1063}
1064
1065void QComboBoxPrivate::_q_updateIndexBeforeChange()
1066{
1067 indexBeforeChange = currentIndex.row();
1068}
1069
1070void QComboBoxPrivate::_q_rowsRemoved(const QModelIndex &parent, int /*start*/, int /*end*/)
1071{
1072 Q_Q(QComboBox);
1073 if (parent != root)
1074 return;
1075
1076 if (sizeAdjustPolicy == QComboBox::AdjustToContents) {
1077 sizeHint = QSize();
1078 adjustComboBoxSize();
1079 q->updateGeometry();
1080 }
1081
1082 // model has changed the currentIndex
1083 if (currentIndex.row() != indexBeforeChange) {
1084 if (!currentIndex.isValid() && q->count()) {
1085 q->setCurrentIndex(qMin(q->count() - 1, qMax(indexBeforeChange, 0)));
1086 return;
1087 }
1088 if (lineEdit) {
1089 lineEdit->setText(q->itemText(currentIndex.row()));
1090 updateLineEditGeometry();
1091 }
1092 q->update();
1093 _q_emitCurrentIndexChanged(currentIndex);
1094 }
1095}
1096
1097
1098void QComboBoxPrivate::updateViewContainerPaletteAndOpacity()
1099{
1100 if (!container)
1101 return;
1102 Q_Q(QComboBox);
1103 QStyleOptionComboBox opt;
1104 q->initStyleOption(&opt);
1105#ifndef QT_NO_MENU
1106 if (q->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, q)) {
1107 QMenu menu;
1108 menu.ensurePolished();
1109 container->setPalette(menu.palette());
1110 container->setWindowOpacity(menu.windowOpacity());
1111 } else
1112#endif
1113 {
1114 container->setPalette(q->palette());
1115 container->setWindowOpacity(1.0);
1116 }
1117 if (lineEdit)
1118 lineEdit->setPalette(q->palette());
1119}
1120
1121void QComboBoxPrivate::updateFocusPolicy()
1122{
1123#ifdef Q_OS_OSX
1124 Q_Q(QComboBox);
1125
1126 // See comment in QComboBoxPrivate::init()
1127 if (q->isEditable())
1128 q->setFocusPolicy(Qt::WheelFocus);
1129 else
1130 q->setFocusPolicy(Qt::TabFocus);
1131#endif
1132}
1133
1134/*!
1135 Initialize \a option with the values from this QComboBox. This method
1136 is useful for subclasses when they need a QStyleOptionComboBox, but don't want
1137 to fill in all the information themselves.
1138
1139 \sa QStyleOption::initFrom()
1140*/
1141void QComboBox::initStyleOption(QStyleOptionComboBox *option) const
1142{
1143 if (!option)
1144 return;
1145
1146 Q_D(const QComboBox);
1147 option->initFrom(this);
1148 option->editable = isEditable();
1149 option->frame = d->frame;
1150 if (hasFocus() && !option->editable)
1151 option->state |= QStyle::State_Selected;
1152 option->subControls = QStyle::SC_All;
1153 if (d->arrowState == QStyle::State_Sunken) {
1154 option->activeSubControls = QStyle::SC_ComboBoxArrow;
1155 option->state |= d->arrowState;
1156 } else {
1157 option->activeSubControls = d->hoverControl;
1158 }
1159 if (d->currentIndex.isValid()) {
1160 option->currentText = currentText();
1161 option->currentIcon = d->itemIcon(d->currentIndex);
1162 }
1163 option->iconSize = iconSize();
1164 if (d->container && d->container->isVisible())
1165 option->state |= QStyle::State_On;
1166}
1167
1168void QComboBoxPrivate::updateLineEditGeometry()
1169{
1170 if (!lineEdit)
1171 return;
1172
1173 Q_Q(QComboBox);
1174 QStyleOptionComboBox opt;
1175 q->initStyleOption(&opt);
1176 QRect editRect = q->style()->subControlRect(QStyle::CC_ComboBox, &opt,
1177 QStyle::SC_ComboBoxEditField, q);
1178 if (!q->itemIcon(q->currentIndex()).isNull()) {
1179 QRect comboRect(editRect);
1180 editRect.setWidth(editRect.width() - q->iconSize().width() - 4);
1181 editRect = QStyle::alignedRect(q->layoutDirection(), Qt::AlignRight,
1182 editRect.size(), comboRect);
1183 }
1184 lineEdit->setGeometry(editRect);
1185}
1186
1187Qt::MatchFlags QComboBoxPrivate::matchFlags() const
1188{
1189 // Base how duplicates are determined on the autocompletion case sensitivity
1190 Qt::MatchFlags flags = Qt::MatchFixedString;
1191#ifndef QT_NO_COMPLETER
1192 if (!lineEdit->completer() || lineEdit->completer()->caseSensitivity() == Qt::CaseSensitive)
1193#endif
1194 flags |= Qt::MatchCaseSensitive;
1195 return flags;
1196}
1197
1198
1199void QComboBoxPrivate::_q_editingFinished()
1200{
1201 Q_Q(QComboBox);
1202 if (lineEdit && !lineEdit->text().isEmpty() && itemText(currentIndex) != lineEdit->text()) {
1203 const int index = q_func()->findText(lineEdit->text(), matchFlags());
1204 if (index != -1) {
1205 q->setCurrentIndex(index);
1206 emitActivated(currentIndex);
1207 }
1208 }
1209
1210}
1211
1212void QComboBoxPrivate::_q_returnPressed()
1213{
1214 Q_Q(QComboBox);
1215
1216 // The insertion code below does not apply when the policy is QComboBox::NoInsert.
1217 // In case a completer is installed, item activation via the completer is handled
1218 // in _q_completerActivated(). Otherwise _q_editingFinished() updates the current
1219 // index as appropriate.
1220 if (insertPolicy == QComboBox::NoInsert)
1221 return;
1222
1223 if (lineEdit && !lineEdit->text().isEmpty()) {
1224 if (q->count() >= maxCount && !(this->insertPolicy == QComboBox::InsertAtCurrent))
1225 return;
1226 lineEdit->deselect();
1227 lineEdit->end(false);
1228 QString text = lineEdit->text();
1229 // check for duplicates (if not enabled) and quit
1230 int index = -1;
1231 if (!duplicatesEnabled) {
1232 index = q->findText(text, matchFlags());
1233 if (index != -1) {
1234 q->setCurrentIndex(index);
1235 emitActivated(currentIndex);
1236 return;
1237 }
1238 }
1239 switch (insertPolicy) {
1240 case QComboBox::InsertAtTop:
1241 index = 0;
1242 break;
1243 case QComboBox::InsertAtBottom:
1244 index = q->count();
1245 break;
1246 case QComboBox::InsertAtCurrent:
1247 case QComboBox::InsertAfterCurrent:
1248 case QComboBox::InsertBeforeCurrent:
1249 if (!q->count() || !currentIndex.isValid())
1250 index = 0;
1251 else if (insertPolicy == QComboBox::InsertAtCurrent)
1252 q->setItemText(q->currentIndex(), text);
1253 else if (insertPolicy == QComboBox::InsertAfterCurrent)
1254 index = q->currentIndex() + 1;
1255 else if (insertPolicy == QComboBox::InsertBeforeCurrent)
1256 index = q->currentIndex();
1257 break;
1258 case QComboBox::InsertAlphabetically:
1259 index = 0;
1260 for (int i=0; i< q->count(); i++, index++ ) {
1261 if (text.toLower() < q->itemText(i).toLower())
1262 break;
1263 }
1264 break;
1265 default:
1266 break;
1267 }
1268 if (index >= 0) {
1269 q->insertItem(index, text);
1270 q->setCurrentIndex(index);
1271 emitActivated(currentIndex);
1272 }
1273 }
1274}
1275
1276void QComboBoxPrivate::_q_itemSelected(const QModelIndex &item)
1277{
1278 Q_Q(QComboBox);
1279 if (item != currentIndex) {
1280 setCurrentIndex(item);
1281 } else if (lineEdit) {
1282 lineEdit->selectAll();
1283 lineEdit->setText(q->itemText(currentIndex.row()));
1284 }
1285 emitActivated(currentIndex);
1286}
1287
1288void QComboBoxPrivate::emitActivated(const QModelIndex &index)
1289{
1290 Q_Q(QComboBox);
1291 if (!index.isValid())
1292 return;
1293 QString text(itemText(index));
1294 emit q->activated(index.row());
1295 emit q->activated(text);
1296}
1297
1298void QComboBoxPrivate::_q_emitHighlighted(const QModelIndex &index)
1299{
1300 Q_Q(QComboBox);
1301 if (!index.isValid())
1302 return;
1303 QString text(itemText(index));
1304 emit q->highlighted(index.row());
1305 emit q->highlighted(text);
1306}
1307
1308void QComboBoxPrivate::_q_emitCurrentIndexChanged(const QModelIndex &index)
1309{
1310 Q_Q(QComboBox);
1311 const QString text = itemText(index);
1312 emit q->currentIndexChanged(index.row());
1313 emit q->currentIndexChanged(text);
1314 // signal lineEdit.textChanged already connected to signal currentTextChanged, so don't emit double here
1315 if (!lineEdit)
1316 emit q->currentTextChanged(text);
1317#ifndef QT_NO_ACCESSIBILITY
1318 QAccessibleValueChangeEvent event(q, text);
1319 QAccessible::updateAccessibility(&event);
1320#endif
1321}
1322
1323QString QComboBoxPrivate::itemText(const QModelIndex &index) const
1324{
1325 return index.isValid() ? model->data(index, itemRole()).toString() : QString();
1326}
1327
1328int QComboBoxPrivate::itemRole() const
1329{
1330 return q_func()->isEditable() ? Qt::EditRole : Qt::DisplayRole;
1331}
1332
1333/*!
1334 Destroys the combobox.
1335*/
1336QComboBox::~QComboBox()
1337{
1338 // ### check delegateparent and delete delegate if us?
1339 Q_D(QComboBox);
1340
1341 QT_TRY {
1342 disconnect(d->model, SIGNAL(destroyed()),
1343 this, SLOT(_q_modelDestroyed()));
1344 } QT_CATCH(...) {
1345 ; // objects can't throw in destructor
1346 }
1347}
1348
1349/*!
1350 \property QComboBox::maxVisibleItems
1351 \brief the maximum allowed size on screen of the combo box, measured in items
1352
1353 By default, this property has a value of 10.
1354
1355 \note This property is ignored for non-editable comboboxes in styles that returns
1356 true for QStyle::SH_ComboBox_Popup such as the Mac style or the Gtk+ Style.
1357*/
1358int QComboBox::maxVisibleItems() const
1359{
1360 Q_D(const QComboBox);
1361 return d->maxVisibleItems;
1362}
1363
1364void QComboBox::setMaxVisibleItems(int maxItems)
1365{
1366 Q_D(QComboBox);
1367 if (Q_UNLIKELY(maxItems < 0)) {
1368 qWarning("QComboBox::setMaxVisibleItems: "
1369 "Invalid max visible items (%d) must be >= 0", maxItems);
1370 return;
1371 }
1372 d->maxVisibleItems = maxItems;
1373}
1374
1375/*!
1376 \property QComboBox::count
1377 \brief the number of items in the combobox
1378
1379 By default, for an empty combo box, this property has a value of 0.
1380*/
1381int QComboBox::count() const
1382{
1383 Q_D(const QComboBox);
1384 return d->model->rowCount(d->root);
1385}
1386
1387/*!
1388 \property QComboBox::maxCount
1389 \brief the maximum number of items allowed in the combobox
1390
1391 \note If you set the maximum number to be less then the current
1392 amount of items in the combobox, the extra items will be
1393 truncated. This also applies if you have set an external model on
1394 the combobox.
1395
1396 By default, this property's value is derived from the highest
1397 signed integer available (typically 2147483647).
1398*/
1399void QComboBox::setMaxCount(int max)
1400{
1401 Q_D(QComboBox);
1402 if (Q_UNLIKELY(max < 0)) {
1403 qWarning("QComboBox::setMaxCount: Invalid count (%d) must be >= 0", max);
1404 return;
1405 }
1406
1407 const int rowCount = count();
1408 if (rowCount > max)
1409 d->model->removeRows(max, rowCount - max, d->root);
1410
1411 d->maxCount = max;
1412}
1413
1414int QComboBox::maxCount() const
1415{
1416 Q_D(const QComboBox);
1417 return d->maxCount;
1418}
1419
1420#ifndef QT_NO_COMPLETER
1421
1422/*!
1423 \property QComboBox::autoCompletion
1424 \brief whether the combobox provides auto-completion for editable items
1425 \since 4.1
1426 \obsolete
1427
1428 Use setCompleter() instead.
1429
1430 By default, this property is \c true.
1431
1432 \sa editable
1433*/
1434
1435/*!
1436 \obsolete
1437
1438 Use setCompleter() instead.
1439*/
1440bool QComboBox::autoCompletion() const
1441{
1442 Q_D(const QComboBox);
1443 return d->autoCompletion;
1444}
1445
1446/*!
1447 \obsolete
1448
1449 Use setCompleter() instead.
1450*/
1451void QComboBox::setAutoCompletion(bool enable)
1452{
1453 Q_D(QComboBox);
1454
1455#ifdef QT_KEYPAD_NAVIGATION
1456 if (Q_UNLIKELY(QApplication::keypadNavigationEnabled() && !enable && isEditable()))
1457 qWarning("QComboBox::setAutoCompletion: auto completion is mandatory when combo box editable");
1458#endif
1459
1460 d->autoCompletion = enable;
1461 if (!d->lineEdit)
1462 return;
1463 if (enable) {
1464 if (d->lineEdit->completer())
1465 return;
1466 d->completer = new QCompleter(d->model, d->lineEdit);
1467 connect(d->completer, SIGNAL(activated(QModelIndex)), this, SLOT(_q_completerActivated(QModelIndex)));
1468 d->completer->setCaseSensitivity(d->autoCompletionCaseSensitivity);
1469 d->completer->setCompletionMode(QCompleter::InlineCompletion);
1470 d->completer->setCompletionColumn(d->modelColumn);
1471 d->lineEdit->setCompleter(d->completer);
1472 d->completer->setWidget(this);
1473 } else {
1474 d->lineEdit->setCompleter(0);
1475 }
1476}
1477
1478/*!
1479 \property QComboBox::autoCompletionCaseSensitivity
1480 \brief whether string comparisons are case-sensitive or case-insensitive for auto-completion
1481 \obsolete
1482
1483 By default, this property is Qt::CaseInsensitive.
1484
1485 Use setCompleter() instead. Case sensitivity of the auto completion can be
1486 changed using QCompleter::setCaseSensitivity().
1487
1488 \sa autoCompletion
1489*/
1490
1491/*!
1492 \obsolete
1493
1494 Use setCompleter() and QCompleter::setCaseSensitivity() instead.
1495*/
1496Qt::CaseSensitivity QComboBox::autoCompletionCaseSensitivity() const
1497{
1498 Q_D(const QComboBox);
1499 return d->autoCompletionCaseSensitivity;
1500}
1501
1502/*!
1503 \obsolete
1504
1505 Use setCompleter() and QCompleter::setCaseSensitivity() instead.
1506*/
1507void QComboBox::setAutoCompletionCaseSensitivity(Qt::CaseSensitivity sensitivity)
1508{
1509 Q_D(QComboBox);
1510 d->autoCompletionCaseSensitivity = sensitivity;
1511 if (d->lineEdit && d->lineEdit->completer())
1512 d->lineEdit->completer()->setCaseSensitivity(sensitivity);
1513}
1514
1515#endif // QT_NO_COMPLETER
1516
1517/*!
1518 \property QComboBox::duplicatesEnabled
1519 \brief whether the user can enter duplicate items into the combobox
1520
1521 Note that it is always possible to programmatically insert duplicate items into the
1522 combobox.
1523
1524 By default, this property is \c false (duplicates are not allowed).
1525*/
1526bool QComboBox::duplicatesEnabled() const
1527{
1528 Q_D(const QComboBox);
1529 return d->duplicatesEnabled;
1530}
1531
1532void QComboBox::setDuplicatesEnabled(bool enable)
1533{
1534 Q_D(QComboBox);
1535 d->duplicatesEnabled = enable;
1536}
1537
1538/*! \fn int QComboBox::findText(const QString &text, Qt::MatchFlags flags = Qt::MatchExactly|Qt::MatchCaseSensitive) const
1539
1540 Returns the index of the item containing the given \a text; otherwise
1541 returns -1.
1542
1543 The \a flags specify how the items in the combobox are searched.
1544*/
1545
1546/*!
1547 Returns the index of the item containing the given \a data for the
1548 given \a role; otherwise returns -1.
1549
1550 The \a flags specify how the items in the combobox are searched.
1551*/
1552int QComboBox::findData(const QVariant &data, int role, Qt::MatchFlags flags) const
1553{
1554 Q_D(const QComboBox);
1555 QModelIndex start = d->model->index(0, d->modelColumn, d->root);
1556 const QModelIndexList result = d->model->match(start, role, data, 1, flags);
1557 if (result.isEmpty())
1558 return -1;
1559 return result.first().row();
1560}
1561
1562/*!
1563 \property QComboBox::insertPolicy
1564 \brief the policy used to determine where user-inserted items should
1565 appear in the combobox
1566
1567 The default value is \l InsertAtBottom, indicating that new items will appear
1568 at the bottom of the list of items.
1569
1570 \sa InsertPolicy
1571*/
1572
1573QComboBox::InsertPolicy QComboBox::insertPolicy() const
1574{
1575 Q_D(const QComboBox);
1576 return d->insertPolicy;
1577}
1578
1579void QComboBox::setInsertPolicy(InsertPolicy policy)
1580{
1581 Q_D(QComboBox);
1582 d->insertPolicy = policy;
1583}
1584
1585/*!
1586 \property QComboBox::sizeAdjustPolicy
1587 \brief the policy describing how the size of the combobox changes
1588 when the content changes
1589
1590 The default value is \l AdjustToContentsOnFirstShow.
1591
1592 \sa SizeAdjustPolicy
1593*/
1594
1595QComboBox::SizeAdjustPolicy QComboBox::sizeAdjustPolicy() const
1596{
1597 Q_D(const QComboBox);
1598 return d->sizeAdjustPolicy;
1599}
1600
1601void QComboBox::setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy policy)
1602{
1603 Q_D(QComboBox);
1604 if (policy == d->sizeAdjustPolicy)
1605 return;
1606
1607 d->sizeAdjustPolicy = policy;
1608 d->sizeHint = QSize();
1609 d->adjustComboBoxSize();
1610 updateGeometry();
1611}
1612
1613/*!
1614 \property QComboBox::minimumContentsLength
1615 \brief the minimum number of characters that should fit into the combobox.
1616
1617 The default value is 0.
1618
1619 If this property is set to a positive value, the
1620 minimumSizeHint() and sizeHint() take it into account.
1621
1622 \sa sizeAdjustPolicy
1623*/
1624int QComboBox::minimumContentsLength() const
1625{
1626 Q_D(const QComboBox);
1627 return d->minimumContentsLength;
1628}
1629
1630void QComboBox::setMinimumContentsLength(int characters)
1631{
1632 Q_D(QComboBox);
1633 if (characters == d->minimumContentsLength || characters < 0)
1634 return;
1635
1636 d->minimumContentsLength = characters;
1637
1638 if (d->sizeAdjustPolicy == AdjustToContents
1639 || d->sizeAdjustPolicy == AdjustToMinimumContentsLength
1640 || d->sizeAdjustPolicy == AdjustToMinimumContentsLengthWithIcon) {
1641 d->sizeHint = QSize();
1642 d->adjustComboBoxSize();
1643 updateGeometry();
1644 }
1645}
1646
1647/*!
1648 \property QComboBox::iconSize
1649 \brief the size of the icons shown in the combobox.
1650
1651 Unless explicitly set this returns the default value of the
1652 current style. This size is the maximum size that icons can have;
1653 icons of smaller size are not scaled up.
1654*/
1655
1656QSize QComboBox::iconSize() const
1657{
1658 Q_D(const QComboBox);
1659 if (d->iconSize.isValid())
1660 return d->iconSize;
1661
1662 int iconWidth = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this);
1663 return QSize(iconWidth, iconWidth);
1664}
1665
1666void QComboBox::setIconSize(const QSize &size)
1667{
1668 Q_D(QComboBox);
1669 if (size == d->iconSize)
1670 return;
1671
1672 view()->setIconSize(size);
1673 d->iconSize = size;
1674 d->sizeHint = QSize();
1675 updateGeometry();
1676}
1677
1678/*!
1679 \property QComboBox::editable
1680 \brief whether the combo box can be edited by the user
1681
1682 By default, this property is \c false. The effect of editing depends
1683 on the insert policy.
1684
1685 \note When disabling the \a editable state, the validator and
1686 completer are removed.
1687
1688 \sa InsertPolicy
1689*/
1690bool QComboBox::isEditable() const
1691{
1692 Q_D(const QComboBox);
1693 return d->lineEdit != 0;
1694}
1695
1696/*! \internal
1697 update the default delegate
1698 depending on the style's SH_ComboBox_Popup hint, we use a different default delegate.
1699
1700 but we do not change the delegate is the combobox use a custom delegate,
1701 unless \a force is set to true.
1702 */
1703void QComboBoxPrivate::updateDelegate(bool force)
1704{
1705 Q_Q(QComboBox);
1706 QStyleOptionComboBox opt;
1707 q->initStyleOption(&opt);
1708 if (q->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, q)) {
1709 if (force || qobject_cast<QComboBoxDelegate *>(q->itemDelegate()))
1710 q->setItemDelegate(new QComboMenuDelegate(q->view(), q));
1711 } else {
1712 if (force || qobject_cast<QComboMenuDelegate *>(q->itemDelegate()))
1713 q->setItemDelegate(new QComboBoxDelegate(q->view(), q));
1714 }
1715}
1716
1717QIcon QComboBoxPrivate::itemIcon(const QModelIndex &index) const
1718{
1719 QVariant decoration = model->data(index, Qt::DecorationRole);
1720 if (decoration.type() == QVariant::Pixmap)
1721 return QIcon(qvariant_cast<QPixmap>(decoration));
1722 else
1723 return qvariant_cast<QIcon>(decoration);
1724}
1725
1726void QComboBox::setEditable(bool editable)
1727{
1728 Q_D(QComboBox);
1729 if (isEditable() == editable)
1730 return;
1731
1732 QStyleOptionComboBox opt;
1733 initStyleOption(&opt);
1734 if (editable) {
1735 if (style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this)) {
1736 d->viewContainer()->updateScrollers();
1737 view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1738 }
1739 QLineEdit *le = new QLineEdit(this);
1740 setLineEdit(le);
1741 } else {
1742 if (style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this)) {
1743 d->viewContainer()->updateScrollers();
1744 view()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1745 }
1746 setAttribute(Qt::WA_InputMethodEnabled, false);
1747 d->lineEdit->hide();
1748 d->lineEdit->deleteLater();
1749 d->lineEdit = 0;
1750 }
1751
1752 d->updateDelegate();
1753 d->updateFocusPolicy();
1754
1755 d->viewContainer()->updateTopBottomMargin();
1756 if (!testAttribute(Qt::WA_Resized))
1757 adjustSize();
1758}
1759
1760/*!
1761 Sets the line \a edit to use instead of the current line edit widget.
1762
1763 The combo box takes ownership of the line edit.
1764*/
1765void QComboBox::setLineEdit(QLineEdit *edit)
1766{
1767 Q_D(QComboBox);
1768 if (Q_UNLIKELY(!edit)) {
1769 qWarning("QComboBox::setLineEdit: cannot set a 0 line edit");
1770 return;
1771 }
1772
1773 if (edit == d->lineEdit)
1774 return;
1775
1776 edit->setText(currentText());
1777 delete d->lineEdit;
1778
1779 d->lineEdit = edit;
1780#ifndef QT_NO_IM
1781 qt_widget_private(d->lineEdit)->inheritsInputMethodHints = 1;
1782#endif
1783 if (d->lineEdit->parent() != this)
1784 d->lineEdit->setParent(this);
1785 connect(d->lineEdit, SIGNAL(returnPressed()), this, SLOT(_q_returnPressed()));
1786 connect(d->lineEdit, SIGNAL(editingFinished()), this, SLOT(_q_editingFinished()));
1787 connect(d->lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(editTextChanged(QString)));
1788 connect(d->lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(currentTextChanged(QString)));
1789 connect(d->lineEdit, SIGNAL(cursorPositionChanged(int,int)), this, SLOT(updateMicroFocus()));
1790 connect(d->lineEdit, SIGNAL(selectionChanged()), this, SLOT(updateMicroFocus()));
1791 connect(d->lineEdit->d_func()->control, SIGNAL(updateMicroFocus()), this, SLOT(updateMicroFocus()));
1792 d->lineEdit->setFrame(false);
1793 d->lineEdit->setContextMenuPolicy(Qt::NoContextMenu);
1794 d->updateFocusPolicy();
1795 d->lineEdit->setFocusProxy(this);
1796 d->lineEdit->setAttribute(Qt::WA_MacShowFocusRect, false);
1797#ifndef QT_NO_COMPLETER
1798 setAutoCompletion(d->autoCompletion);
1799#endif
1800
1801#ifdef QT_KEYPAD_NAVIGATION
1802#ifndef QT_NO_COMPLETER
1803 if (QApplication::keypadNavigationEnabled()) {
1804 // Editable combo boxes will have a completer that is set to UnfilteredPopupCompletion.
1805 // This means that when the user enters edit mode they are immediately presented with a
1806 // list of possible completions.
1807 setAutoCompletion(true);
1808 if (d->completer) {
1809 d->completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
1810 connect(d->completer, SIGNAL(activated(QModelIndex)), this, SLOT(_q_completerActivated()));
1811 }
1812 }
1813#endif
1814#endif
1815
1816 setAttribute(Qt::WA_InputMethodEnabled);
1817 d->updateLayoutDirection();
1818 d->updateLineEditGeometry();
1819 if (isVisible())
1820 d->lineEdit->show();
1821
1822 update();
1823}
1824
1825/*!
1826 Returns the line edit used to edit items in the combobox, or 0 if there
1827 is no line edit.
1828
1829 Only editable combo boxes have a line edit.
1830*/
1831QLineEdit *QComboBox::lineEdit() const
1832{
1833 Q_D(const QComboBox);
1834 return d->lineEdit;
1835}
1836
1837#ifndef QT_NO_VALIDATOR
1838/*!
1839 \fn void QComboBox::setValidator(const QValidator *validator)
1840
1841 Sets the \a validator to use instead of the current validator.
1842
1843 \note The validator is removed when the \l editable property becomes \c false.
1844*/
1845
1846void QComboBox::setValidator(const QValidator *v)
1847{
1848 Q_D(QComboBox);
1849 if (d->lineEdit)
1850 d->lineEdit->setValidator(v);
1851}
1852
1853/*!
1854 Returns the validator that is used to constrain text input for the
1855 combobox.
1856
1857 \sa editable
1858*/
1859const QValidator *QComboBox::validator() const
1860{
1861 Q_D(const QComboBox);
1862 return d->lineEdit ? d->lineEdit->validator() : 0;
1863}
1864#endif // QT_NO_VALIDATOR
1865
1866#ifndef QT_NO_COMPLETER
1867
1868/*!
1869 \fn void QComboBox::setCompleter(QCompleter *completer)
1870 \since 4.2
1871
1872 Sets the \a completer to use instead of the current completer.
1873 If \a completer is 0, auto completion is disabled.
1874
1875 By default, for an editable combo box, a QCompleter that
1876 performs case insensitive inline completion is automatically created.
1877
1878 \note The completer is removed when the \l editable property becomes \c false.
1879*/
1880void QComboBox::setCompleter(QCompleter *c)
1881{
1882 Q_D(QComboBox);
1883 if (!d->lineEdit)
1884 return;
1885 d->lineEdit->setCompleter(c);
1886 if (c) {
1887 connect(c, SIGNAL(activated(QModelIndex)), this, SLOT(_q_completerActivated(QModelIndex)));
1888 c->setWidget(this);
1889 }
1890}
1891
1892/*!
1893 \since 4.2
1894
1895 Returns the completer that is used to auto complete text input for the
1896 combobox.
1897
1898 \sa editable
1899*/
1900QCompleter *QComboBox::completer() const
1901{
1902 Q_D(const QComboBox);
1903 return d->lineEdit ? d->lineEdit->completer() : 0;
1904}
1905
1906#endif // QT_NO_COMPLETER
1907
1908/*!
1909 Returns the item delegate used by the popup list view.
1910
1911 \sa setItemDelegate()
1912*/
1913QAbstractItemDelegate *QComboBox::itemDelegate() const
1914{
1915 return view()->itemDelegate();
1916}
1917
1918/*!
1919 Sets the item \a delegate for the popup list view.
1920 The combobox takes ownership of the delegate.
1921
1922 \warning You should not share the same instance of a delegate between comboboxes,
1923 widget mappers or views. Doing so can cause incorrect or unintuitive editing behavior
1924 since each view connected to a given delegate may receive the
1925 \l{QAbstractItemDelegate::}{closeEditor()} signal, and attempt to access, modify or
1926 close an editor that has already been closed.
1927
1928 \sa itemDelegate()
1929*/
1930void QComboBox::setItemDelegate(QAbstractItemDelegate *delegate)
1931{
1932 if (Q_UNLIKELY(!delegate)) {
1933 qWarning("QComboBox::setItemDelegate: cannot set a 0 delegate");
1934 return;
1935 }
1936 delete view()->itemDelegate();
1937 view()->setItemDelegate(delegate);
1938}
1939
1940/*!
1941 Returns the model used by the combobox.
1942*/
1943
1944QAbstractItemModel *QComboBox::model() const
1945{
1946 Q_D(const QComboBox);
1947 if (d->model == QAbstractItemModelPrivate::staticEmptyModel()) {
1948 QComboBox *that = const_cast<QComboBox*>(this);
1949 that->setModel(new QStandardItemModel(0, 1, that));
1950 }
1951 return d->model;
1952}
1953
1954/*!
1955 Sets the model to be \a model. \a model must not be 0.
1956 If you want to clear the contents of a model, call clear().
1957
1958 \sa clear()
1959*/
1960void QComboBox::setModel(QAbstractItemModel *model)
1961{
1962 Q_D(QComboBox);
1963
1964 if (Q_UNLIKELY(!model)) {
1965 qWarning("QComboBox::setModel: cannot set a 0 model");
1966 return;
1967 }
1968
1969 if (model == d->model)
1970 return;
1971
1972#ifndef QT_NO_COMPLETER
1973 if (d->lineEdit && d->lineEdit->completer()
1974 && d->lineEdit->completer() == d->completer)
1975 d->lineEdit->completer()->setModel(model);
1976#endif
1977 if (d->model) {
1978 disconnect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
1979 this, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
1980 disconnect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
1981 this, SLOT(_q_updateIndexBeforeChange()));
1982 disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
1983 this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
1984 disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
1985 this, SLOT(_q_updateIndexBeforeChange()));
1986 disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
1987 this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
1988 disconnect(d->model, SIGNAL(destroyed()),
1989 this, SLOT(_q_modelDestroyed()));
1990 disconnect(d->model, SIGNAL(modelAboutToBeReset()),
1991 this, SLOT(_q_updateIndexBeforeChange()));
1992 disconnect(d->model, SIGNAL(modelReset()),
1993 this, SLOT(_q_modelReset()));
1994 if (d->model->QObject::parent() == this)
1995 delete d->model;
1996 }
1997
1998 d->model = model;
1999
2000 connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
2001 this, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
2002 connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
2003 this, SLOT(_q_updateIndexBeforeChange()));
2004 connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
2005 this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
2006 connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
2007 this, SLOT(_q_updateIndexBeforeChange()));
2008 connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
2009 this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
2010 connect(model, SIGNAL(destroyed()),
2011 this, SLOT(_q_modelDestroyed()));
2012 connect(model, SIGNAL(modelAboutToBeReset()),
2013 this, SLOT(_q_updateIndexBeforeChange()));
2014 connect(model, SIGNAL(modelReset()),
2015 this, SLOT(_q_modelReset()));
2016
2017 if (d->container) {
2018 d->container->itemView()->setModel(model);
2019 connect(d->container->itemView()->selectionModel(),
2020 SIGNAL(currentChanged(QModelIndex,QModelIndex)),
2021 this, SLOT(_q_emitHighlighted(QModelIndex)), Qt::UniqueConnection);
2022 }
2023
2024 setRootModelIndex(QModelIndex());
2025
2026 bool currentReset = false;
2027
2028 const int rowCount = count();
2029 for (int pos=0; pos < rowCount; pos++) {
2030 if (d->model->index(pos, d->modelColumn, d->root).flags() & Qt::ItemIsEnabled) {
2031 setCurrentIndex(pos);
2032 currentReset = true;
2033 break;
2034 }
2035 }
2036
2037 if (!currentReset)
2038 setCurrentIndex(-1);
2039
2040 d->modelChanged();
2041}
2042
2043/*!
2044 Returns the root model item index for the items in the combobox.
2045
2046 \sa setRootModelIndex()
2047*/
2048
2049QModelIndex QComboBox::rootModelIndex() const
2050{
2051 Q_D(const QComboBox);
2052 return QModelIndex(d->root);
2053}
2054
2055/*!
2056 Sets the root model item \a index for the items in the combobox.
2057
2058 \sa rootModelIndex()
2059*/
2060void QComboBox::setRootModelIndex(const QModelIndex &index)
2061{
2062 Q_D(QComboBox);
2063 if (d->root == index)
2064 return;
2065 d->root = QPersistentModelIndex(index);
2066 view()->setRootIndex(index);
2067 update();
2068}
2069
2070/*!
2071 \property QComboBox::currentIndex
2072 \brief the index of the current item in the combobox.
2073
2074 The current index can change when inserting or removing items.
2075
2076 By default, for an empty combo box or a combo box in which no current
2077 item is set, this property has a value of -1.
2078*/
2079int QComboBox::currentIndex() const
2080{
2081 Q_D(const QComboBox);
2082 return d->currentIndex.row();
2083}
2084
2085void QComboBox::setCurrentIndex(int index)
2086{
2087 Q_D(QComboBox);
2088 QModelIndex mi = d->model->index(index, d->modelColumn, d->root);
2089 d->setCurrentIndex(mi);
2090}
2091
2092void QComboBox::setCurrentText(const QString &text)
2093{
2094 if (isEditable()) {
2095 setEditText(text);
2096 } else {
2097 const int i = findText(text);
2098 if (i > -1)
2099 setCurrentIndex(i);
2100 }
2101}
2102
2103void QComboBoxPrivate::setCurrentIndex(const QModelIndex &mi)
2104{
2105 Q_Q(QComboBox);
2106
2107 QModelIndex normalized = mi.sibling(mi.row(), modelColumn); // no-op if mi.column() == modelColumn
2108 if (!normalized.isValid())
2109 normalized = mi; // Fallback to passed index.
2110
2111 bool indexChanged = (normalized != currentIndex);
2112 if (indexChanged)
2113 currentIndex = QPersistentModelIndex(normalized);
2114 if (lineEdit) {
2115 const QString newText = itemText(normalized);
2116 if (lineEdit->text() != newText) {
2117 lineEdit->setText(newText); // may cause lineEdit -> nullptr (QTBUG-54191)
2118#ifndef QT_NO_COMPLETER
2119 if (lineEdit && lineEdit->completer())
2120 lineEdit->completer()->setCompletionPrefix(newText);
2121#endif
2122 }
2123 updateLineEditGeometry();
2124 }
2125 if (indexChanged) {
2126 q->update();
2127 _q_emitCurrentIndexChanged(currentIndex);
2128 }
2129}
2130
2131/*!
2132 \property QComboBox::currentText
2133 \brief the current text
2134
2135 If the combo box is editable, the current text is the value displayed
2136 by the line edit. Otherwise, it is the value of the current item or
2137 an empty string if the combo box is empty or no current item is set.
2138
2139 The setter setCurrentText() simply calls setEditText() if the combo box is editable.
2140 Otherwise, if there is a matching text in the list, currentIndex is set to the
2141 corresponding index.
2142
2143 \sa editable, setEditText()
2144*/
2145QString QComboBox::currentText() const
2146{
2147 Q_D(const QComboBox);
2148 if (d->lineEdit)
2149 return d->lineEdit->text();
2150 else if (d->currentIndex.isValid())
2151 return d->itemText(d->currentIndex);
2152 else
2153 return QString();
2154}
2155
2156/*!
2157 \property QComboBox::currentData
2158 \brief the data for the current item
2159 \since 5.2
2160
2161 By default, for an empty combo box or a combo box in which no current
2162 item is set, this property contains an invalid QVariant.
2163*/
2164QVariant QComboBox::currentData(int role) const
2165{
2166 Q_D(const QComboBox);
2167 return d->currentIndex.data(role);
2168}
2169
2170/*!
2171 Returns the text for the given \a index in the combobox.
2172*/
2173QString QComboBox::itemText(int index) const
2174{
2175 Q_D(const QComboBox);
2176 QModelIndex mi = d->model->index(index, d->modelColumn, d->root);
2177 return d->itemText(mi);
2178}
2179
2180/*!
2181 Returns the icon for the given \a index in the combobox.
2182*/
2183QIcon QComboBox::itemIcon(int index) const
2184{
2185 Q_D(const QComboBox);
2186 QModelIndex mi = d->model->index(index, d->modelColumn, d->root);
2187 return d->itemIcon(mi);
2188}
2189
2190/*!
2191 Returns the data for the given \a role in the given \a index in the
2192 combobox, or QVariant::Invalid if there is no data for this role.
2193*/
2194QVariant QComboBox::itemData(int index, int role) const
2195{
2196 Q_D(const QComboBox);
2197 QModelIndex mi = d->model->index(index, d->modelColumn, d->root);
2198 return d->model->data(mi, role);
2199}
2200
2201/*!
2202 \fn void QComboBox::insertItem(int index, const QString &text, const QVariant &userData)
2203
2204 Inserts the \a text and \a userData (stored in the Qt::UserRole)
2205 into the combobox at the given \a index.
2206
2207 If the index is equal to or higher than the total number of items,
2208 the new item is appended to the list of existing items. If the
2209 index is zero or negative, the new item is prepended to the list
2210 of existing items.
2211
2212 \sa insertItems()
2213*/
2214
2215/*!
2216
2217 Inserts the \a icon, \a text and \a userData (stored in the
2218 Qt::UserRole) into the combobox at the given \a index.
2219
2220 If the index is equal to or higher than the total number of items,
2221 the new item is appended to the list of existing items. If the
2222 index is zero or negative, the new item is prepended to the list
2223 of existing items.
2224
2225 \sa insertItems()
2226*/
2227void QComboBox::insertItem(int index, const QIcon &icon, const QString &text, const QVariant &userData)
2228{
2229 Q_D(QComboBox);
2230 int itemCount = count();
2231 index = qBound(0, index, itemCount);
2232 if (index >= d->maxCount)
2233 return;
2234
2235 // For the common case where we are using the built in QStandardItemModel
2236 // construct a QStandardItem, reducing the number of expensive signals from the model
2237 if (QStandardItemModel *m = qobject_cast<QStandardItemModel*>(d->model)) {
2238 QStandardItem *item = new QStandardItem(text);
2239 if (!icon.isNull()) item->setData(icon, Qt::DecorationRole);
2240 if (userData.isValid()) item->setData(userData, Qt::UserRole);
2241 m->insertRow(index, item);
2242 ++itemCount;
2243 } else {
2244 d->inserting = true;
2245 if (d->model->insertRows(index, 1, d->root)) {
2246 QModelIndex item = d->model->index(index, d->modelColumn, d->root);
2247 if (icon.isNull() && !userData.isValid()) {
2248 d->model->setData(item, text, Qt::EditRole);
2249 } else {
2250 QMap<int, QVariant> values;
2251 if (!text.isNull()) values.insert(Qt::EditRole, text);
2252 if (!icon.isNull()) values.insert(Qt::DecorationRole, icon);
2253 if (userData.isValid()) values.insert(Qt::UserRole, userData);
2254 if (!values.isEmpty()) d->model->setItemData(item, values);
2255 }
2256 d->inserting = false;
2257 d->_q_rowsInserted(d->root, index, index);
2258 ++itemCount;
2259 } else {
2260 d->inserting = false;
2261 }
2262 }
2263
2264 if (itemCount > d->maxCount)
2265 d->model->removeRows(itemCount - 1, itemCount - d->maxCount, d->root);
2266}
2267
2268/*!
2269 Inserts the strings from the \a list into the combobox as separate items,
2270 starting at the \a index specified.
2271
2272 If the index is equal to or higher than the total number of items, the new items
2273 are appended to the list of existing items. If the index is zero or negative, the
2274 new items are prepended to the list of existing items.
2275
2276 \sa insertItem()
2277 */
2278void QComboBox::insertItems(int index, const QStringList &list)
2279{
2280 Q_D(QComboBox);
2281 if (list.isEmpty())
2282 return;
2283 index = qBound(0, index, count());
2284 int insertCount = qMin(d->maxCount - index, list.count());
2285 if (insertCount <= 0)
2286 return;
2287 // For the common case where we are using the built in QStandardItemModel
2288 // construct a QStandardItem, reducing the number of expensive signals from the model
2289 if (QStandardItemModel *m = qobject_cast<QStandardItemModel*>(d->model)) {
2290 QList<QStandardItem *> items;
2291 items.reserve(insertCount);
2292 QStandardItem *hiddenRoot = m->invisibleRootItem();
2293 for (int i = 0; i < insertCount; ++i)
2294 items.append(new QStandardItem(list.at(i)));
2295 hiddenRoot->insertRows(index, items);
2296 } else {
2297 d->inserting = true;
2298 if (d->model->insertRows(index, insertCount, d->root)) {
2299 QModelIndex item;
2300 for (int i = 0; i < insertCount; ++i) {
2301 item = d->model->index(i+index, d->modelColumn, d->root);
2302 d->model->setData(item, list.at(i), Qt::EditRole);
2303 }
2304 d->inserting = false;
2305 d->_q_rowsInserted(d->root, index, index + insertCount - 1);
2306 } else {
2307 d->inserting = false;
2308 }
2309 }
2310
2311 int mc = count();
2312 if (mc > d->maxCount)
2313 d->model->removeRows(d->maxCount, mc - d->maxCount, d->root);
2314}
2315
2316/*!
2317 \since 4.4
2318
2319 Inserts a separator item into the combobox at the given \a index.
2320
2321 If the index is equal to or higher than the total number of items, the new item
2322 is appended to the list of existing items. If the index is zero or negative, the
2323 new item is prepended to the list of existing items.
2324
2325 \sa insertItem()
2326*/
2327void QComboBox::insertSeparator(int index)
2328{
2329 Q_D(QComboBox);
2330 int itemCount = count();
2331 index = qBound(0, index, itemCount);
2332 if (index >= d->maxCount)
2333 return;
2334 insertItem(index, QIcon(), QString());
2335 QComboBoxDelegate::setSeparator(d->model, d->model->index(index, 0, d->root));
2336}
2337
2338/*!
2339 Removes the item at the given \a index from the combobox.
2340 This will update the current index if the index is removed.
2341
2342 This function does nothing if \a index is out of range.
2343*/
2344void QComboBox::removeItem(int index)
2345{
2346 Q_D(QComboBox);
2347 if (index < 0 || index >= count())
2348 return;
2349 d->model->removeRows(index, 1, d->root);
2350}
2351
2352/*!
2353 Sets the \a text for the item on the given \a index in the combobox.
2354*/
2355void QComboBox::setItemText(int index, const QString &text)
2356{
2357 Q_D(const QComboBox);
2358 QModelIndex item = d->model->index(index, d->modelColumn, d->root);
2359 if (item.isValid()) {
2360 d->model->setData(item, text, Qt::EditRole);
2361 }
2362}
2363
2364/*!
2365 Sets the \a icon for the item on the given \a index in the combobox.
2366*/
2367void QComboBox::setItemIcon(int index, const QIcon &icon)
2368{
2369 Q_D(const QComboBox);
2370 QModelIndex item = d->model->index(index, d->modelColumn, d->root);
2371 if (item.isValid()) {
2372 d->model->setData(item, icon, Qt::DecorationRole);
2373 }
2374}
2375
2376/*!
2377 Sets the data \a role for the item on the given \a index in the combobox
2378 to the specified \a value.
2379*/
2380void QComboBox::setItemData(int index, const QVariant &value, int role)
2381{
2382 Q_D(const QComboBox);
2383 QModelIndex item = d->model->index(index, d->modelColumn, d->root);
2384 if (item.isValid()) {
2385 d->model->setData(item, value, role);
2386 }
2387}
2388
2389/*!
2390 Returns the list view used for the combobox popup.
2391*/
2392QAbstractItemView *QComboBox::view() const
2393{
2394 Q_D(const QComboBox);
2395 return const_cast<QComboBoxPrivate*>(d)->viewContainer()->itemView();
2396}
2397
2398/*!
2399 Sets the view to be used in the combobox popup to the given \a
2400 itemView. The combobox takes ownership of the view.
2401
2402 Note: If you want to use the convenience views (like QListWidget,
2403 QTableWidget or QTreeWidget), make sure to call setModel() on the
2404 combobox with the convenience widgets model before calling this
2405 function.
2406*/
2407void QComboBox::setView(QAbstractItemView *itemView)
2408{
2409 Q_D(QComboBox);
2410 if (Q_UNLIKELY(!itemView)) {
2411 qWarning("QComboBox::setView: cannot set a 0 view");
2412 return;
2413 }
2414
2415 if (itemView->model() != d->model)
2416 itemView->setModel(d->model);
2417 d->viewContainer()->setItemView(itemView);
2418}
2419
2420/*!
2421 \reimp
2422*/
2423QSize QComboBox::minimumSizeHint() const
2424{
2425 Q_D(const QComboBox);
2426 return d->recomputeSizeHint(d->minimumSizeHint);
2427}
2428
2429/*!
2430 \reimp
2431
2432 This implementation caches the size hint to avoid resizing when
2433 the contents change dynamically. To invalidate the cached value
2434 change the \l sizeAdjustPolicy.
2435*/
2436QSize QComboBox::sizeHint() const
2437{
2438 Q_D(const QComboBox);
2439 return d->recomputeSizeHint(d->sizeHint);
2440}
2441
2442#ifdef Q_OS_MAC
2443
2444namespace {
2445struct IndexSetter {
2446 int index;
2447 QComboBox *cb;
2448
2449 void operator()(void)
2450 {
2451 cb->setCurrentIndex(index);
2452 emit cb->activated(index);
2453 emit cb->activated(cb->itemText(index));
2454 }
2455};
2456}
2457
2458void QComboBoxPrivate::cleanupNativePopup()
2459{
2460 if (!m_platformMenu)
2461 return;
2462
2463 int count = int(m_platformMenu->tag());
2464 for (int i = 0; i < count; ++i)
2465 m_platformMenu->menuItemAt(i)->deleteLater();
2466
2467 delete m_platformMenu;
2468 m_platformMenu = 0;
2469}
2470
2471/*!
2472 * \internal
2473 *
2474 * Tries to show a native popup. Returns true if it could, false otherwise.
2475 *
2476 */
2477bool QComboBoxPrivate::showNativePopup()
2478{
2479 Q_Q(QComboBox);
2480
2481 cleanupNativePopup();
2482
2483 QPlatformTheme *theme = QGuiApplicationPrivate::instance()->platformTheme();
2484 m_platformMenu = theme->createPlatformMenu();
2485 if (!m_platformMenu)
2486 return false;
2487
2488 int itemsCount = q->count();
2489 m_platformMenu->setTag(quintptr(itemsCount));
2490
2491 QPlatformMenuItem *currentItem = 0;
2492 int currentIndex = q->currentIndex();
2493
2494 for (int i = 0; i < itemsCount; ++i) {
2495 QPlatformMenuItem *item = theme->createPlatformMenuItem();
2496 QModelIndex rowIndex = model->index(i, modelColumn, root);
2497 QVariant textVariant = model->data(rowIndex, Qt::EditRole);
2498 item->setText(textVariant.toString());
2499 QVariant iconVariant = model->data(rowIndex, Qt::DecorationRole);
2500 if (iconVariant.canConvert<QIcon>())
2501 item->setIcon(iconVariant.value<QIcon>());
2502 item->setCheckable(true);
2503 item->setChecked(i == currentIndex);
2504 if (!currentItem || i == currentIndex)
2505 currentItem = item;
2506
2507 IndexSetter setter = { i, q };
2508 QObject::connect(item, &QPlatformMenuItem::activated, setter);
2509
2510 m_platformMenu->insertMenuItem(item, 0);
2511 m_platformMenu->syncMenuItem(item);
2512 }
2513
2514 QWindow *tlw = q->window()->windowHandle();
2515 m_platformMenu->setFont(q->font());
2516 m_platformMenu->setMinimumWidth(q->rect().width());
2517 QPoint offset = QPoint(0, 7);
2518 if (q->testAttribute(Qt::WA_MacSmallSize))
2519 offset = QPoint(-1, 7);
2520 else if (q->testAttribute(Qt::WA_MacMiniSize))
2521 offset = QPoint(-2, 6);
2522
2523 m_platformMenu->showPopup(tlw, QRect(tlw->mapFromGlobal(q->mapToGlobal(offset)), QSize()), currentItem);
2524
2525#ifdef Q_OS_OSX
2526 // The Cocoa popup will swallow any mouse release event.
2527 // We need to fake one here to un-press the button.
2528 QMouseEvent mouseReleased(QEvent::MouseButtonRelease, q->pos(), Qt::LeftButton,
2529 Qt::MouseButtons(Qt::LeftButton), Qt::KeyboardModifiers());
2530 qApp->sendEvent(q, &mouseReleased);
2531#endif
2532
2533 return true;
2534}
2535
2536#endif // Q_OS_MAC
2537
2538/*!
2539 Displays the list of items in the combobox. If the list is empty
2540 then the no items will be shown.
2541
2542 If you reimplement this function to show a custom pop-up, make
2543 sure you call hidePopup() to reset the internal state.
2544
2545 \sa hidePopup()
2546*/
2547void QComboBox::showPopup()
2548{
2549 Q_D(QComboBox);
2550 if (count() <= 0)
2551 return;
2552
2553 QStyle * const style = this->style();
2554 QStyleOptionComboBox opt;
2555 initStyleOption(&opt);
2556 const bool usePopup = style->styleHint(QStyle::SH_ComboBox_Popup, &opt, this);
2557
2558#ifdef Q_OS_MAC
2559 if (usePopup
2560 && (!d->container
2561 || (view()->metaObject()->className() == QByteArray("QComboBoxListView")
2562 && view()->itemDelegate()->metaObject()->className() == QByteArray("QComboMenuDelegate")))
2563 && style->styleHint(QStyle::SH_ComboBox_UseNativePopup, &opt, this)
2564 && d->showNativePopup())
2565 return;
2566#endif // Q_OS_MAC
2567
2568#ifdef QT_KEYPAD_NAVIGATION
2569#ifndef QT_NO_COMPLETER
2570 if (QApplication::keypadNavigationEnabled() && d->completer) {
2571 // editable combo box is line edit plus completer
2572 setEditFocus(true);
2573 d->completer->complete(); // show popup
2574 return;
2575 }
2576#endif
2577#endif
2578
2579 // set current item and select it
2580 view()->selectionModel()->setCurrentIndex(d->currentIndex,
2581 QItemSelectionModel::ClearAndSelect);
2582 QComboBoxPrivateContainer* container = d->viewContainer();
2583 QRect listRect(style->subControlRect(QStyle::CC_ComboBox, &opt,
2584 QStyle::SC_ComboBoxListBoxPopup, this));
2585 QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(this));
2586
2587 QPoint below = mapToGlobal(listRect.bottomLeft());
2588 int belowHeight = screen.bottom() - below.y();
2589 QPoint above = mapToGlobal(listRect.topLeft());
2590 int aboveHeight = above.y() - screen.y();
2591 bool boundToScreen = !window()->testAttribute(Qt::WA_DontShowOnScreen);
2592
2593 {
2594 int listHeight = 0;
2595 int count = 0;
2596 QStack<QModelIndex> toCheck;
2597 toCheck.push(view()->rootIndex());
2598#ifndef QT_NO_TREEVIEW
2599 QTreeView *treeView = qobject_cast<QTreeView*>(view());
2600 if (treeView && treeView->header() && !treeView->header()->isHidden())
2601 listHeight += treeView->header()->height();
2602#endif
2603 while (!toCheck.isEmpty()) {
2604 QModelIndex parent = toCheck.pop();
2605 for (int i = 0, end = d->model->rowCount(parent); i < end; ++i) {
2606 QModelIndex idx = d->model->index(i, d->modelColumn, parent);
2607 if (!idx.isValid())
2608 continue;
2609 listHeight += view()->visualRect(idx).height();
2610#ifndef QT_NO_TREEVIEW
2611 if (d->model->hasChildren(idx) && treeView && treeView->isExpanded(idx))
2612 toCheck.push(idx);
2613#endif
2614 ++count;
2615 if (!usePopup && count >= d->maxVisibleItems) {
2616 toCheck.clear();
2617 break;
2618 }
2619 }
2620 }
2621 if (count > 1)
2622 listHeight += (count - 1) * container->spacing();
2623 listRect.setHeight(listHeight);
2624 }
2625
2626 {
2627 // add the spacing for the grid on the top and the bottom;
2628 int heightMargin = container->topMargin() + container->bottomMargin();
2629
2630 // add the frame of the container
2631 int marginTop, marginBottom;
2632 container->getContentsMargins(0, &marginTop, 0, &marginBottom);
2633 heightMargin += marginTop + marginBottom;
2634
2635 //add the frame of the view
2636 view()->getContentsMargins(0, &marginTop, 0, &marginBottom);
2637 marginTop += static_cast<QAbstractScrollAreaPrivate *>(QObjectPrivate::get(view()))->top;
2638 marginBottom += static_cast<QAbstractScrollAreaPrivate *>(QObjectPrivate::get(view()))->bottom;
2639 heightMargin += marginTop + marginBottom;
2640
2641 listRect.setHeight(listRect.height() + heightMargin);
2642 }
2643
2644 // Add space for margin at top and bottom if the style wants it.
2645 if (usePopup)
2646 listRect.setHeight(listRect.height() + style->pixelMetric(QStyle::PM_MenuVMargin, &opt, this) * 2);
2647
2648 // Make sure the popup is wide enough to display its contents.
2649 if (usePopup) {
2650 const int diff = d->computeWidthHint() - width();
2651 if (diff > 0)
2652 listRect.setWidth(listRect.width() + diff);
2653 }
2654
2655 //we need to activate the layout to make sure the min/maximum size are set when the widget was not yet show
2656 container->layout()->activate();
2657 //takes account of the minimum/maximum size of the container
2658 listRect.setSize( listRect.size().expandedTo(container->minimumSize())
2659 .boundedTo(container->maximumSize()));
2660
2661 // make sure the widget fits on screen
2662 if (boundToScreen) {
2663 if (listRect.width() > screen.width() )
2664 listRect.setWidth(screen.width());
2665 if (mapToGlobal(listRect.bottomRight()).x() > screen.right()) {
2666 below.setX(screen.x() + screen.width() - listRect.width());
2667 above.setX(screen.x() + screen.width() - listRect.width());
2668 }
2669 if (mapToGlobal(listRect.topLeft()).x() < screen.x() ) {
2670 below.setX(screen.x());
2671 above.setX(screen.x());
2672 }
2673 }
2674
2675 if (usePopup) {
2676 // Position horizontally.
2677 listRect.moveLeft(above.x());
2678
2679 // Position vertically so the curently selected item lines up
2680 // with the combo box.
2681 const QRect currentItemRect = view()->visualRect(view()->currentIndex());
2682 const int offset = listRect.top() - currentItemRect.top();
2683 listRect.moveTop(above.y() + offset - listRect.top());
2684
2685 // Clamp the listRect height and vertical position so we don't expand outside the
2686 // available screen geometry.This may override the vertical position, but it is more
2687 // important to show as much as possible of the popup.
2688 const int height = !boundToScreen ? listRect.height() : qMin(listRect.height(), screen.height());
2689 listRect.setHeight(height);
2690
2691 if (boundToScreen) {
2692 if (listRect.top() < screen.top())
2693 listRect.moveTop(screen.top());
2694 if (listRect.bottom() > screen.bottom())
2695 listRect.moveBottom(screen.bottom());
2696 }
2697 } else if (!boundToScreen || listRect.height() <= belowHeight) {
2698 listRect.moveTopLeft(below);
2699 } else if (listRect.height() <= aboveHeight) {
2700 listRect.moveBottomLeft(above);
2701 } else if (belowHeight >= aboveHeight) {
2702 listRect.setHeight(belowHeight);
2703 listRect.moveTopLeft(below);
2704 } else {
2705 listRect.setHeight(aboveHeight);
2706 listRect.moveBottomLeft(above);
2707 }
2708
2709 if (qApp) {
2710 QGuiApplication::inputMethod()->reset();
2711 }
2712
2713 QScrollBar *sb = view()->horizontalScrollBar();
2714 Qt::ScrollBarPolicy policy = view()->horizontalScrollBarPolicy();
2715 bool needHorizontalScrollBar = (policy == Qt::ScrollBarAsNeeded || policy == Qt::ScrollBarAlwaysOn)
2716 && sb->minimum() < sb->maximum();
2717 if (needHorizontalScrollBar) {
2718 listRect.adjust(0, 0, 0, sb->height());
2719 }
2720 container->setGeometry(listRect);
2721
2722#ifndef Q_OS_MAC
2723 const bool updatesEnabled = container->updatesEnabled();
2724#endif
2725
2726#if !defined(QT_NO_EFFECTS)
2727 bool scrollDown = (listRect.topLeft() == below);
2728 if (QApplication::isEffectEnabled(Qt::UI_AnimateCombo)
2729 && !style->styleHint(QStyle::SH_ComboBox_Popup, &opt, this) && !window()->testAttribute(Qt::WA_DontShowOnScreen))
2730 qScrollEffect(container, scrollDown ? QEffects::DownScroll : QEffects::UpScroll, 150);
2731#endif
2732
2733// Don't disable updates on OS X. Windows are displayed immediately on this platform,
2734// which means that the window will be visible before the call to container->show() returns.
2735// If updates are disabled at this point we'll miss our chance at painting the popup
2736// menu before it's shown, causing flicker since the window then displays the standard gray
2737// background.
2738#ifndef Q_OS_MAC
2739 container->setUpdatesEnabled(false);
2740#endif
2741
2742 bool startTimer = !container->isVisible();
2743 container->raise();
2744 container->create();
2745 QWindow *containerWindow = container->window()->windowHandle();
2746 if (containerWindow) {
2747 QWindow *win = window()->windowHandle();
2748 if (win) {
2749 QScreen *currentScreen = win->screen();
2750 if (currentScreen && !currentScreen->virtualSiblings().contains(containerWindow->screen())) {
2751 containerWindow->setScreen(currentScreen);
2752
2753 // This seems to workaround an issue in xcb+multi GPU+multiscreen
2754 // environment where the window might not always show up when screen
2755 // is changed.
2756 container->hide();
2757 }
2758 }
2759 }
2760 container->show();
2761 container->updateScrollers();
2762 view()->setFocus();
2763
2764 view()->scrollTo(view()->currentIndex(),
2765 style->styleHint(QStyle::SH_ComboBox_Popup, &opt, this)
2766 ? QAbstractItemView::PositionAtCenter
2767 : QAbstractItemView::EnsureVisible);
2768
2769#ifndef Q_OS_MAC
2770 container->setUpdatesEnabled(updatesEnabled);
2771#endif
2772
2773 container->update();
2774#ifdef QT_KEYPAD_NAVIGATION
2775 if (QApplication::keypadNavigationEnabled())
2776 view()->setEditFocus(true);
2777#endif
2778 if (startTimer) {
2779 container->popupTimer.start();
2780 container->maybeIgnoreMouseButtonRelease = true;
2781 }
2782}
2783
2784/*!
2785 Hides the list of items in the combobox if it is currently visible
2786 and resets the internal state, so that if the custom pop-up was
2787 shown inside the reimplemented showPopup(), then you also need to
2788 reimplement the hidePopup() function to hide your custom pop-up
2789 and call the base class implementation to reset the internal state
2790 whenever your custom pop-up widget is hidden.
2791
2792 \sa showPopup()
2793*/
2794void QComboBox::hidePopup()
2795{
2796 Q_D(QComboBox);
2797 if (d->container && d->container->isVisible()) {
2798#if !defined(QT_NO_EFFECTS)
2799 QSignalBlocker modelBlocker(d->model);
2800 QSignalBlocker viewBlocker(d->container->itemView());
2801 QSignalBlocker containerBlocker(d->container);
2802 // Flash selected/triggered item (if any).
2803 if (style()->styleHint(QStyle::SH_Menu_FlashTriggeredItem)) {
2804 QItemSelectionModel *selectionModel = view() ? view()->selectionModel() : 0;
2805 if (selectionModel && selectionModel->hasSelection()) {
2806 QEventLoop eventLoop;
2807 const QItemSelection selection = selectionModel->selection();
2808
2809 // Deselect item and wait 60 ms.
2810 selectionModel->select(selection, QItemSelectionModel::Toggle);
2811 QTimer::singleShot(60, &eventLoop, SLOT(quit()));
2812 eventLoop.exec();
2813
2814 // Select item and wait 20 ms.
2815 selectionModel->select(selection, QItemSelectionModel::Toggle);
2816 QTimer::singleShot(20, &eventLoop, SLOT(quit()));
2817 eventLoop.exec();
2818 }
2819 }
2820
2821 // Fade out.
2822 bool needFade = style()->styleHint(QStyle::SH_Menu_FadeOutOnHide);
2823 bool didFade = false;
2824 if (needFade) {
2825#if defined(Q_OS_MAC)
2826 QPlatformNativeInterface *platformNativeInterface = qApp->platformNativeInterface();
2827 int at = platformNativeInterface->metaObject()->indexOfMethod("fadeWindow()");
2828 if (at != -1) {
2829 QMetaMethod windowFade = platformNativeInterface->metaObject()->method(at);
2830 windowFade.invoke(platformNativeInterface, Q_ARG(QWindow *, d->container->windowHandle()));
2831 didFade = true;
2832 }
2833
2834#endif // Q_OS_MAC
2835 // Other platform implementations welcome :-)
2836 }
2837 containerBlocker.unblock();
2838 viewBlocker.unblock();
2839 modelBlocker.unblock();
2840
2841 if (!didFade)
2842#endif // QT_NO_EFFECTS
2843 // Fade should implicitly hide as well ;-)
2844 d->container->hide();
2845 }
2846#ifdef QT_KEYPAD_NAVIGATION
2847 if (QApplication::keypadNavigationEnabled() && isEditable() && hasFocus())
2848 setEditFocus(true);
2849#endif
2850 d->_q_resetButton();
2851}
2852
2853/*!
2854 Clears the combobox, removing all items.
2855
2856 Note: If you have set an external model on the combobox this model
2857 will still be cleared when calling this function.
2858*/
2859void QComboBox::clear()
2860{
2861 Q_D(QComboBox);
2862 d->model->removeRows(0, d->model->rowCount(d->root), d->root);
2863#ifndef QT_NO_ACCESSIBILITY
2864 QAccessibleValueChangeEvent event(this, QString());
2865 QAccessible::updateAccessibility(&event);
2866#endif
2867}
2868
2869/*!
2870 Clears the contents of the line edit used for editing in the combobox.
2871*/
2872void QComboBox::clearEditText()
2873{
2874 Q_D(QComboBox);
2875 if (d->lineEdit)
2876 d->lineEdit->clear();
2877#ifndef QT_NO_ACCESSIBILITY
2878 QAccessibleValueChangeEvent event(this, QString());
2879 QAccessible::updateAccessibility(&event);
2880#endif
2881}
2882
2883/*!
2884 Sets the \a text in the combobox's text edit.
2885*/
2886void QComboBox::setEditText(const QString &text)
2887{
2888 Q_D(QComboBox);
2889 if (d->lineEdit)
2890 d->lineEdit->setText(text);
2891#ifndef QT_NO_ACCESSIBILITY
2892 QAccessibleValueChangeEvent event(this, text);
2893 QAccessible::updateAccessibility(&event);
2894#endif
2895}
2896
2897/*!
2898 \reimp
2899*/
2900void QComboBox::focusInEvent(QFocusEvent *e)
2901{
2902 Q_D(QComboBox);
2903 update();
2904 if (d->lineEdit) {
2905 d->lineEdit->event(e);
2906#ifndef QT_NO_COMPLETER
2907 if (d->lineEdit->completer())
2908 d->lineEdit->completer()->setWidget(this);
2909#endif
2910 }
2911}
2912
2913/*!
2914 \reimp
2915*/
2916void QComboBox::focusOutEvent(QFocusEvent *e)
2917{
2918 Q_D(QComboBox);
2919 update();
2920 if (d->lineEdit)
2921 d->lineEdit->event(e);
2922}
2923
2924/*! \reimp */
2925void QComboBox::changeEvent(QEvent *e)
2926{
2927 Q_D(QComboBox);
2928 switch (e->type()) {
2929 case QEvent::StyleChange:
2930 d->updateDelegate();
2931#ifdef Q_OS_MAC
2932 case QEvent::MacSizeChange:
2933#endif
2934 d->sizeHint = QSize(); // invalidate size hint
2935 d->minimumSizeHint = QSize();
2936 d->updateLayoutDirection();
2937 if (d->lineEdit)
2938 d->updateLineEditGeometry();
2939 d->setLayoutItemMargins(QStyle::SE_ComboBoxLayoutItem);
2940
2941 if (e->type() == QEvent::MacSizeChange){
2942 QPlatformTheme::Font f = QPlatformTheme::SystemFont;
2943 if (testAttribute(Qt::WA_MacSmallSize))
2944 f = QPlatformTheme::SmallFont;
2945 else if (testAttribute(Qt::WA_MacMiniSize))
2946 f = QPlatformTheme::MiniFont;
2947 if (const QFont *platformFont = QApplicationPrivate::platformTheme()->font(f)) {
2948 QFont f = font();
2949 f.setPointSizeF(platformFont->pointSizeF());
2950 setFont(f);
2951 }
2952 }
2953 // ### need to update scrollers etc. as well here
2954 break;
2955 case QEvent::EnabledChange:
2956 if (!isEnabled())
2957 hidePopup();
2958 break;
2959 case QEvent::PaletteChange: {
2960 d->updateViewContainerPaletteAndOpacity();
2961 break;
2962 }
2963 case QEvent::FontChange:
2964 d->sizeHint = QSize(); // invalidate size hint
2965 d->viewContainer()->setFont(font());
2966 if (d->lineEdit)
2967 d->updateLineEditGeometry();
2968 break;
2969 default:
2970 break;
2971 }
2972 QWidget::changeEvent(e);
2973}
2974
2975/*!
2976 \reimp
2977*/
2978void QComboBox::resizeEvent(QResizeEvent *)
2979{
2980 Q_D(QComboBox);
2981 d->updateLineEditGeometry();
2982}
2983
2984/*!
2985 \reimp
2986*/
2987void QComboBox::paintEvent(QPaintEvent *)
2988{
2989 QStylePainter painter(this);
2990 painter.setPen(palette().color(QPalette::Text));
2991
2992 // draw the combobox frame, focusrect and selected etc.
2993 QStyleOptionComboBox opt;
2994 initStyleOption(&opt);
2995 painter.drawComplexControl(QStyle::CC_ComboBox, opt);
2996
2997 // draw the icon and text
2998 painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
2999}
3000
3001/*!
3002 \reimp
3003*/
3004void QComboBox::showEvent(QShowEvent *e)
3005{
3006 Q_D(QComboBox);
3007 if (!d->shownOnce && d->sizeAdjustPolicy == QComboBox::AdjustToContentsOnFirstShow) {
3008 d->sizeHint = QSize();
3009 updateGeometry();
3010 }
3011 d->shownOnce = true;
3012 QWidget::showEvent(e);
3013}
3014
3015/*!
3016 \reimp
3017*/
3018void QComboBox::hideEvent(QHideEvent *)
3019{
3020 hidePopup();
3021}
3022
3023/*!
3024 \reimp
3025*/
3026bool QComboBox::event(QEvent *event)
3027{
3028 Q_D(QComboBox);
3029 switch(event->type()) {
3030 case QEvent::LayoutDirectionChange:
3031 case QEvent::ApplicationLayoutDirectionChange:
3032 d->updateLayoutDirection();
3033 d->updateLineEditGeometry();
3034 break;
3035 case QEvent::HoverEnter:
3036 case QEvent::HoverLeave:
3037 case QEvent::HoverMove:
3038 if (const QHoverEvent *he = static_cast<const QHoverEvent *>(event))
3039 d->updateHoverControl(he->pos());
3040 break;
3041 case QEvent::ShortcutOverride:
3042 if (d->lineEdit)
3043 return d->lineEdit->event(event);
3044 break;
3045#ifdef QT_KEYPAD_NAVIGATION
3046 case QEvent::EnterEditFocus:
3047 if (!d->lineEdit)
3048 setEditFocus(false); // We never want edit focus if we are not editable
3049 else
3050 d->lineEdit->event(event); //so cursor starts
3051 break;
3052 case QEvent::LeaveEditFocus:
3053 if (d->lineEdit)
3054 d->lineEdit->event(event); //so cursor stops
3055 break;
3056#endif
3057 default:
3058 break;
3059 }
3060 return QWidget::event(event);
3061}
3062
3063/*!
3064 \reimp
3065*/
3066void QComboBox::mousePressEvent(QMouseEvent *e)
3067{
3068 Q_D(QComboBox);
3069 if (!QGuiApplication::styleHints()->setFocusOnTouchRelease())
3070 d->showPopupFromMouseEvent(e);
3071}
3072
3073void QComboBoxPrivate::showPopupFromMouseEvent(QMouseEvent *e)
3074{
3075 Q_Q(QComboBox);
3076 QStyleOptionComboBox opt;
3077 q->initStyleOption(&opt);
3078 QStyle::SubControl sc = q->style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt, e->pos(), q);
3079
3080 if (e->button() == Qt::LeftButton
3081 && !(sc == QStyle::SC_None && e->type() == QEvent::MouseButtonRelease)
3082 && (sc == QStyle::SC_ComboBoxArrow || !q->isEditable())
3083 && !viewContainer()->isVisible()) {
3084 if (sc == QStyle::SC_ComboBoxArrow)
3085 updateArrow(QStyle::State_Sunken);
3086#ifdef QT_KEYPAD_NAVIGATION
3087 //if the container already exists, then d->viewContainer() is safe to call
3088 if (container) {
3089#endif
3090 // We've restricted the next couple of lines, because by not calling
3091 // viewContainer(), we avoid creating the QComboBoxPrivateContainer.
3092 viewContainer()->blockMouseReleaseTimer.start(QApplication::doubleClickInterval());
3093 viewContainer()->initialClickPosition = q->mapToGlobal(e->pos());
3094#ifdef QT_KEYPAD_NAVIGATION
3095 }
3096#endif
3097 q->showPopup();
3098 // The code below ensures that regular mousepress and pick item still works
3099 // If it was not called the viewContainer would ignore event since it didn't have
3100 // a mousePressEvent first.
3101 if (viewContainer())
3102 viewContainer()->maybeIgnoreMouseButtonRelease = false;
3103 } else {
3104#ifdef QT_KEYPAD_NAVIGATION
3105 if (QApplication::keypadNavigationEnabled() && sc == QStyle::SC_ComboBoxEditField && lineEdit) {
3106 lineEdit->event(e); //so lineedit can move cursor, etc
3107 return;
3108 }
3109#endif
3110 e->ignore();
3111 }
3112}
3113
3114/*!
3115 \reimp
3116*/
3117void QComboBox::mouseReleaseEvent(QMouseEvent *e)
3118{
3119 Q_D(QComboBox);
3120 d->updateArrow(QStyle::State_None);
3121 if (QGuiApplication::styleHints()->setFocusOnTouchRelease() && hasFocus())
3122 d->showPopupFromMouseEvent(e);
3123}
3124
3125/*!
3126 \reimp
3127*/
3128void QComboBox::keyPressEvent(QKeyEvent *e)
3129{
3130 Q_D(QComboBox);
3131
3132#ifndef QT_NO_COMPLETER
3133 if (d->lineEdit
3134 && d->lineEdit->completer()
3135 && d->lineEdit->completer()->popup()
3136 && d->lineEdit->completer()->popup()->isVisible()) {
3137 // provide same autocompletion support as line edit
3138 d->lineEdit->event(e);
3139 return;
3140 }
3141#endif
3142
3143 enum Move { NoMove=0 , MoveUp , MoveDown , MoveFirst , MoveLast};
3144
3145 Move move = NoMove;
3146 int newIndex = currentIndex();
3147 switch (e->key()) {
3148 case Qt::Key_Up:
3149 if (e->modifiers() & Qt::ControlModifier)
3150 break; // pass to line edit for auto completion
3151 // fall through
3152 case Qt::Key_PageUp:
3153#ifdef QT_KEYPAD_NAVIGATION
3154 if (QApplication::keypadNavigationEnabled())
3155 e->ignore();
3156 else
3157#endif
3158 move = MoveUp;
3159 break;
3160 case Qt::Key_Down:
3161 if (e->modifiers() & Qt::AltModifier) {
3162 showPopup();
3163 return;
3164 } else if (e->modifiers() & Qt::ControlModifier)
3165 break; // pass to line edit for auto completion
3166 Q_FALLTHROUGH();
3167 case Qt::Key_PageDown:
3168#ifdef QT_KEYPAD_NAVIGATION
3169 if (QApplication::keypadNavigationEnabled())
3170 e->ignore();
3171 else
3172#endif
3173 move = MoveDown;
3174 break;
3175 case Qt::Key_Home:
3176 if (!d->lineEdit)
3177 move = MoveFirst;
3178 break;
3179 case Qt::Key_End:
3180 if (!d->lineEdit)
3181 move = MoveLast;
3182 break;
3183 case Qt::Key_F4:
3184 if (!e->modifiers()) {
3185 showPopup();
3186 return;
3187 }
3188 break;
3189 case Qt::Key_Space:
3190 if (!d->lineEdit) {
3191 showPopup();
3192 return;
3193 }
3194 break;
3195 case Qt::Key_Enter:
3196 case Qt::Key_Return:
3197 case Qt::Key_Escape:
3198 if (!d->lineEdit)
3199 e->ignore();
3200 break;
3201#ifdef QT_KEYPAD_NAVIGATION
3202 case Qt::Key_Select:
3203 if (QApplication::keypadNavigationEnabled()
3204 && (!hasEditFocus() || !d->lineEdit)) {
3205 showPopup();
3206 return;
3207 }
3208 break;
3209 case Qt::Key_Left:
3210 case Qt::Key_Right:
3211 if (QApplication::keypadNavigationEnabled() && !hasEditFocus())
3212 e->ignore();
3213 break;
3214 case Qt::Key_Back:
3215 if (QApplication::keypadNavigationEnabled()) {
3216 if (!hasEditFocus() || !d->lineEdit)
3217 e->ignore();
3218 } else {
3219 e->ignore(); // let the surounding dialog have it
3220 }
3221 break;
3222#endif
3223 default:
3224 if (!d->lineEdit) {
3225 if (!e->text().isEmpty())
3226 d->keyboardSearchString(e->text());
3227 else
3228 e->ignore();
3229 }
3230 }
3231
3232 const int rowCount = count();
3233
3234 if (move != NoMove) {
3235 e->accept();
3236 switch (move) {
3237 case MoveFirst:
3238 newIndex = -1;
3239 // fall through
3240 case MoveDown:
3241 newIndex++;
3242 while (newIndex < rowCount && !(d->model->index(newIndex, d->modelColumn, d->root).flags() & Qt::ItemIsEnabled))
3243 newIndex++;
3244 break;
3245 case MoveLast:
3246 newIndex = rowCount;
3247 // fall through
3248 case MoveUp:
3249 newIndex--;
3250 while ((newIndex >= 0) && !(d->model->flags(d->model->index(newIndex,d->modelColumn,d->root)) & Qt::ItemIsEnabled))
3251 newIndex--;
3252 break;
3253 default:
3254 e->ignore();
3255 break;
3256 }
3257
3258 if (newIndex >= 0 && newIndex < rowCount && newIndex != currentIndex()) {
3259 setCurrentIndex(newIndex);
3260 d->emitActivated(d->currentIndex);
3261 }
3262 } else if (d->lineEdit) {
3263 d->lineEdit->event(e);
3264 }
3265}
3266
3267
3268/*!
3269 \reimp
3270*/
3271void QComboBox::keyReleaseEvent(QKeyEvent *e)
3272{
3273 Q_D(QComboBox);
3274 if (d->lineEdit)
3275 d->lineEdit->event(e);
3276 else
3277 QWidget::keyReleaseEvent(e);
3278}
3279
3280/*!
3281 \reimp
3282*/
3283#ifndef QT_NO_WHEELEVENT
3284void QComboBox::wheelEvent(QWheelEvent *e)
3285{
3286#ifdef Q_OS_DARWIN
3287 Q_UNUSED(e);
3288#else
3289 Q_D(QComboBox);
3290 if (!d->viewContainer()->isVisible()) {
3291 const int rowCount = count();
3292 int newIndex = currentIndex();
3293
3294 if (e->delta() > 0) {
3295 newIndex--;
3296 while ((newIndex >= 0) && !(d->model->flags(d->model->index(newIndex,d->modelColumn,d->root)) & Qt::ItemIsEnabled))
3297 newIndex--;
3298 } else if (e->delta() < 0) {
3299 newIndex++;
3300 while (newIndex < rowCount && !(d->model->index(newIndex, d->modelColumn, d->root).flags() & Qt::ItemIsEnabled))
3301 newIndex++;
3302 }
3303
3304 if (newIndex >= 0 && newIndex < rowCount && newIndex != currentIndex()) {
3305 setCurrentIndex(newIndex);
3306 d->emitActivated(d->currentIndex);
3307 }
3308 e->accept();
3309 }
3310#endif
3311}
3312#endif
3313
3314#ifndef QT_NO_CONTEXTMENU
3315/*!
3316 \reimp
3317*/
3318void QComboBox::contextMenuEvent(QContextMenuEvent *e)
3319{
3320 Q_D(QComboBox);
3321 if (d->lineEdit) {
3322 Qt::ContextMenuPolicy p = d->lineEdit->contextMenuPolicy();
3323 d->lineEdit->setContextMenuPolicy(Qt::DefaultContextMenu);
3324 d->lineEdit->event(e);
3325 d->lineEdit->setContextMenuPolicy(p);
3326 }
3327}
3328#endif // QT_NO_CONTEXTMENU
3329
3330void QComboBoxPrivate::keyboardSearchString(const QString &text)
3331{
3332 // use keyboardSearch from the listView so we do not duplicate code
3333 QAbstractItemView *view = viewContainer()->itemView();
3334 view->setCurrentIndex(currentIndex);
3335 int currentRow = view->currentIndex().row();
3336 view->keyboardSearch(text);
3337 if (currentRow != view->currentIndex().row()) {
3338 setCurrentIndex(view->currentIndex());
3339 emitActivated(currentIndex);
3340 }
3341}
3342
3343void QComboBoxPrivate::modelChanged()
3344{
3345 Q_Q(QComboBox);
3346
3347 if (sizeAdjustPolicy == QComboBox::AdjustToContents) {
3348 sizeHint = QSize();
3349 adjustComboBoxSize();
3350 q->updateGeometry();
3351 }
3352}
3353
3354/*!
3355 \reimp
3356*/
3357void QComboBox::inputMethodEvent(QInputMethodEvent *e)
3358{
3359 Q_D(QComboBox);
3360 if (d->lineEdit) {
3361 d->lineEdit->event(e);
3362 } else {
3363 if (!e->commitString().isEmpty())
3364 d->keyboardSearchString(e->commitString());
3365 else
3366 e->ignore();
3367 }
3368}
3369
3370/*!
3371 \reimp
3372*/
3373QVariant QComboBox::inputMethodQuery(Qt::InputMethodQuery query) const
3374{
3375 Q_D(const QComboBox);
3376 if (d->lineEdit)
3377 return d->lineEdit->inputMethodQuery(query);
3378 return QWidget::inputMethodQuery(query);
3379}
3380
3381/*!\internal
3382*/
3383QVariant QComboBox::inputMethodQuery(Qt::InputMethodQuery query, const QVariant &argument) const
3384{
3385 Q_D(const QComboBox);
3386 if (d->lineEdit)
3387 return d->lineEdit->inputMethodQuery(query, argument);
3388 return QWidget::inputMethodQuery(query);
3389}
3390
3391/*!
3392 \fn void QComboBox::addItem(const QString &text, const QVariant &userData)
3393
3394 Adds an item to the combobox with the given \a text, and
3395 containing the specified \a userData (stored in the Qt::UserRole).
3396 The item is appended to the list of existing items.
3397*/
3398
3399/*!
3400 \fn void QComboBox::addItem(const QIcon &icon, const QString &text,
3401 const QVariant &userData)
3402
3403 Adds an item to the combobox with the given \a icon and \a text,
3404 and containing the specified \a userData (stored in the
3405 Qt::UserRole). The item is appended to the list of existing items.
3406*/
3407
3408/*!
3409 \fn void QComboBox::addItems(const QStringList &texts)
3410
3411 Adds each of the strings in the given \a texts to the combobox. Each item
3412 is appended to the list of existing items in turn.
3413*/
3414
3415/*!
3416 \fn void QComboBox::editTextChanged(const QString &text)
3417
3418 This signal is emitted when the text in the combobox's line edit
3419 widget is changed. The new text is specified by \a text.
3420*/
3421
3422/*!
3423 \property QComboBox::frame
3424 \brief whether the combo box draws itself with a frame
3425
3426
3427 If enabled (the default) the combo box draws itself inside a
3428 frame, otherwise the combo box draws itself without any frame.
3429*/
3430bool QComboBox::hasFrame() const
3431{
3432 Q_D(const QComboBox);
3433 return d->frame;
3434}
3435
3436
3437void QComboBox::setFrame(bool enable)
3438{
3439 Q_D(QComboBox);
3440 d->frame = enable;
3441 update();
3442 updateGeometry();
3443}
3444
3445/*!
3446 \property QComboBox::modelColumn
3447 \brief the column in the model that is visible.
3448
3449 If set prior to populating the combo box, the pop-up view will
3450 not be affected and will show the first column (using this property's
3451 default value).
3452
3453 By default, this property has a value of 0.
3454*/
3455int QComboBox::modelColumn() const
3456{
3457 Q_D(const QComboBox);
3458 return d->modelColumn;
3459}
3460
3461void QComboBox::setModelColumn(int visibleColumn)
3462{
3463 Q_D(QComboBox);
3464 d->modelColumn = visibleColumn;
3465 QListView *lv = qobject_cast<QListView *>(d->viewContainer()->itemView());
3466 if (lv)
3467 lv->setModelColumn(visibleColumn);
3468#ifndef QT_NO_COMPLETER
3469 if (d->lineEdit && d->lineEdit->completer()
3470 && d->lineEdit->completer() == d->completer)
3471 d->lineEdit->completer()->setCompletionColumn(visibleColumn);
3472#endif
3473 setCurrentIndex(currentIndex()); //update the text to the text of the new column;
3474}
3475
3476QT_END_NAMESPACE
3477
3478#include "moc_qcombobox.cpp"
3479#include "moc_qcombobox_p.cpp"
3480
3481#endif // QT_NO_COMBOBOX
3482