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