source: trunk/src/gui/widgets/qcombobox.cpp@ 64

Last change on this file since 64 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 94.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qcombobox.h"
43
44#ifndef QT_NO_COMBOBOX
45#include <qstylepainter.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#ifndef QT_NO_IM
60#include "qinputcontext.h"
61#endif
62#include <private/qcombobox_p.h>
63#include <private/qabstractitemmodel_p.h>
64#include <private/qabstractscrollarea_p.h>
65#include <qdebug.h>
66
67#ifdef Q_WS_X11
68#include <private/qt_x11_p.h>
69#endif
70#if defined(Q_WS_MAC) && !defined(QT_NO_EFFECTS) && !defined(QT_NO_STYLE_MAC)
71#include <private/qcore_mac_p.h>
72#include <QMacStyle>
73#include <private/qt_cocoa_helpers_mac_p.h>
74#endif
75#ifndef QT_NO_EFFECTS
76# include <private/qeffects_p.h>
77#endif
78QT_BEGIN_NAMESPACE
79
80extern QHash<QByteArray, QFont> *qt_app_fonts_hash();
81
82QComboBoxPrivate::QComboBoxPrivate()
83 : QWidgetPrivate(),
84 model(0),
85 lineEdit(0),
86 container(0),
87 insertPolicy(QComboBox::InsertAtBottom),
88 sizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow),
89 minimumContentsLength(0),
90 shownOnce(false),
91 autoCompletion(true),
92 duplicatesEnabled(false),
93 frame(true),
94 maxVisibleItems(10),
95 maxCount(INT_MAX),
96 modelColumn(0),
97 inserting(false),
98 arrowState(QStyle::State_None),
99 hoverControl(QStyle::SC_None),
100 autoCompletionCaseSensitivity(Qt::CaseInsensitive),
101 indexBeforeChange(-1)
102#ifndef QT_NO_COMPLETER
103 , completer(0)
104#endif
105{
106}
107
108QStyleOptionMenuItem QComboMenuDelegate::getStyleOption(const QStyleOptionViewItem &option,
109 const QModelIndex &index) const
110{
111 QStyleOptionMenuItem menuOption;
112 menuOption.palette = option.palette.resolve(QApplication::palette("QMenu"));
113 menuOption.state = QStyle::State_None;
114 if (mCombo->window()->isActiveWindow())
115 menuOption.state = QStyle::State_Active;
116 if ((option.state & QStyle::State_Enabled) && (index.model()->flags(index) & Qt::ItemIsEnabled))
117 menuOption.state |= QStyle::State_Enabled;
118 else
119 menuOption.palette.setCurrentColorGroup(QPalette::Disabled);
120 if (option.state & QStyle::State_Selected)
121 menuOption.state |= QStyle::State_Selected;
122 menuOption.checkType = QStyleOptionMenuItem::NonExclusive;
123 menuOption.checked = mCombo->currentIndex() == index.row();
124 if (QComboBoxDelegate::isSeparator(index))
125 menuOption.menuItemType = QStyleOptionMenuItem::Separator;
126 else
127 menuOption.menuItemType = QStyleOptionMenuItem::Normal;
128
129 QVariant variant = index.model()->data(index, Qt::DecorationRole);
130 switch (variant.type()) {
131 case QVariant::Icon:
132 menuOption.icon = qvariant_cast<QIcon>(variant);
133 break;
134 case QVariant::Color: {
135 static QPixmap pixmap(option.decorationSize);
136 pixmap.fill(qvariant_cast<QColor>(variant));
137 menuOption.icon = pixmap;
138 break; }
139 default:
140 menuOption.icon = qvariant_cast<QPixmap>(variant);
141 break;
142 }
143
144 menuOption.text = index.model()->data(index, Qt::DisplayRole).toString()
145 .replace(QLatin1Char('&'), QLatin1String("&&"));
146 menuOption.tabWidth = 0;
147 menuOption.maxIconWidth = option.decorationSize.width() + 4;
148 menuOption.menuRect = option.rect;
149 menuOption.rect = option.rect;
150
151 // Make sure fonts set on the combo box also overrides the font for the popup menu.
152 if (mCombo->testAttribute(Qt::WA_SetFont) || mCombo->testAttribute(Qt::WA_MacSmallSize)
153 || mCombo->testAttribute(Qt::WA_MacMiniSize))
154 menuOption.font = mCombo->font();
155 else
156 menuOption.font = qt_app_fonts_hash()->value("QComboMenuItem", mCombo->font());
157
158 menuOption.fontMetrics = QFontMetrics(menuOption.font);
159
160 return menuOption;
161}
162
163#ifdef QT_KEYPAD_NAVIGATION
164void QComboBoxPrivate::_q_completerActivated()
165{
166 Q_Q(QComboBox);
167 if ( QApplication::keypadNavigationEnabled()
168 && q->isEditable()
169 && q->completer()
170 && q->completer()->completionMode() == QCompleter::UnfilteredPopupCompletion ) {
171 q->setEditFocus(false);
172 }
173}
174#endif
175
176void QComboBoxPrivate::updateArrow(QStyle::StateFlag state)
177{
178 Q_Q(QComboBox);
179 if (arrowState == state)
180 return;
181 arrowState = state;
182 QStyleOptionComboBox opt;
183 q->initStyleOption(&opt);
184 q->update(q->style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxArrow, q));
185}
186
187void QComboBoxPrivate::_q_modelReset()
188{
189 Q_Q(QComboBox);
190 if (lineEdit) {
191 lineEdit->setText(QString());
192 updateLineEditGeometry();
193 }
194 q->update();
195}
196
197void QComboBoxPrivate::_q_modelDestroyed()
198{
199 model = QAbstractItemModelPrivate::staticEmptyModel();
200}
201
202
203//Windows and KDE allows menus to cover the taskbar, while GNOME and Mac don't
204QRect QComboBoxPrivate::popupGeometry(int screen) const
205{
206#ifdef Q_WS_WIN
207 return QApplication::desktop()->screenGeometry(screen);
208#elif defined Q_WS_X11
209 if (X11->desktopEnvironment == DE_KDE)
210 return QApplication::desktop()->screenGeometry(screen);
211 else
212 return QApplication::desktop()->availableGeometry(screen);
213#else
214 return QApplication::desktop()->availableGeometry(screen);
215#endif
216}
217
218bool QComboBoxPrivate::updateHoverControl(const QPoint &pos)
219{
220
221 Q_Q(QComboBox);
222 QRect lastHoverRect = hoverRect;
223 QStyle::SubControl lastHoverControl = hoverControl;
224 bool doesHover = q->testAttribute(Qt::WA_Hover);
225 if (lastHoverControl != newHoverControl(pos) && doesHover) {
226 q->update(lastHoverRect);
227 q->update(hoverRect);
228 return true;
229 }
230 return !doesHover;
231}
232
233QStyle::SubControl QComboBoxPrivate::newHoverControl(const QPoint &pos)
234{
235 Q_Q(QComboBox);
236 QStyleOptionComboBox opt;
237 q->initStyleOption(&opt);
238 opt.subControls = QStyle::SC_All;
239 hoverControl = q->style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt, pos, q);
240 hoverRect = (hoverControl != QStyle::SC_None)
241 ? q->style()->subControlRect(QStyle::CC_ComboBox, &opt, hoverControl, q)
242 : QRect();
243 return hoverControl;
244}
245
246/*
247 Computes a size hint based on the maximum width
248 for the items in the combobox.
249*/
250int QComboBoxPrivate::computeWidthHint() const
251{
252 Q_Q(const QComboBox);
253
254 int width = 0;
255 const int count = q->count();
256 const int iconWidth = q->iconSize().width() + 4;
257 const QFontMetrics &fontMetrics = q->fontMetrics();
258
259 for (int i = 0; i < count; ++i) {
260 const int textWidth = fontMetrics.width(q->itemText(i));
261 if (q->itemIcon(i).isNull())
262 width = (qMax(width, textWidth));
263 else
264 width = (qMax(width, textWidth + iconWidth));
265 }
266
267 QStyleOptionComboBox opt;
268 q->initStyleOption(&opt);
269 QSize tmp(width, 0);
270 tmp = q->style()->sizeFromContents(QStyle::CT_ComboBox, &opt, tmp, q);
271 return tmp.width();
272}
273
274QSize QComboBoxPrivate::recomputeSizeHint(QSize &sh) const
275{
276 Q_Q(const QComboBox);
277 if (!sh.isValid()) {
278 bool hasIcon = sizeAdjustPolicy == QComboBox::AdjustToMinimumContentsLengthWithIcon ? true : false;
279 int count = q->count();
280 QSize iconSize = q->iconSize();
281 const QFontMetrics &fm = q->fontMetrics();
282
283 // text width
284 if (&sh == &sizeHint || minimumContentsLength == 0) {
285 switch (sizeAdjustPolicy) {
286 case QComboBox::AdjustToContents:
287 case QComboBox::AdjustToContentsOnFirstShow:
288 if (count == 0) {
289 sh.rwidth() = 7 * fm.width(QLatin1Char('x'));
290 } else {
291 for (int i = 0; i < count; ++i) {
292 if (!q->itemIcon(i).isNull()) {
293 hasIcon = true;
294 sh.setWidth(qMax(sh.width(), fm.boundingRect(q->itemText(i)).width() + iconSize.width() + 4));
295 } else {
296 sh.setWidth(qMax(sh.width(), fm.boundingRect(q->itemText(i)).width()));
297 }
298 }
299 }
300 break;
301 case QComboBox::AdjustToMinimumContentsLength:
302 for (int i = 0; i < count && !hasIcon; ++i)
303 hasIcon = !q->itemIcon(i).isNull();
304 default:
305 ;
306 }
307 } else {
308 for (int i = 0; i < count && !hasIcon; ++i)
309 hasIcon = !q->itemIcon(i).isNull();
310 }
311 if (minimumContentsLength > 0)
312 sh.setWidth(qMax(sh.width(), minimumContentsLength * fm.width(QLatin1Char('X')) + (hasIcon ? iconSize.width() + 4 : 0)));
313
314
315 // height
316 sh.setHeight(qMax(fm.lineSpacing(), 14) + 2);
317 if (hasIcon) {
318 sh.setHeight(qMax(sh.height(), iconSize.height() + 2));
319 }
320
321 // add style and strut values
322 QStyleOptionComboBox opt;
323 q->initStyleOption(&opt);
324 sh = q->style()->sizeFromContents(QStyle::CT_ComboBox, &opt, sh, q);
325 }
326 return sh.expandedTo(QApplication::globalStrut());
327}
328
329void QComboBoxPrivate::adjustComboBoxSize()
330{
331 viewContainer()->adjustSizeTimer.start(20, container);
332}
333
334void QComboBoxPrivate::updateLayoutDirection()
335{
336 Q_Q(const QComboBox);
337 QStyleOptionComboBox opt;
338 q->initStyleOption(&opt);
339 Qt::LayoutDirection dir = Qt::LayoutDirection(
340 q->style()->styleHint(QStyle::SH_ComboBox_LayoutDirection, &opt, q));
341 if (lineEdit)
342 lineEdit->setLayoutDirection(dir);
343 if (container)
344 container->setLayoutDirection(dir);
345}
346
347
348void QComboBoxPrivateContainer::timerEvent(QTimerEvent *timerEvent)
349{
350 if (timerEvent->timerId() == adjustSizeTimer.timerId()) {
351 adjustSizeTimer.stop();
352 if (combo->sizeAdjustPolicy() == QComboBox::AdjustToContents) {
353 combo->adjustSize();
354 combo->update();
355 }
356 }
357}
358
359void QComboBoxPrivateContainer::resizeEvent(QResizeEvent *e)
360{
361 QStyleOptionComboBox opt = comboStyleOption();
362 if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo)) {
363 QStyleOption myOpt;
364 myOpt.initFrom(this);
365 QStyleHintReturnMask mask;
366 if (combo->style()->styleHint(QStyle::SH_Menu_Mask, &myOpt, this, &mask)) {
367 setMask(mask.region);
368 }
369 } else {
370 clearMask();
371 }
372 QFrame::resizeEvent(e);
373}
374
375void QComboBoxPrivateContainer::leaveEvent(QEvent *)
376{
377// On Mac using the Mac style we want to clear the selection
378// when the mouse moves outside the popup.
379#ifdef Q_WS_MAC
380 QStyleOptionComboBox opt = comboStyleOption();
381 if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo))
382 view->clearSelection();
383#endif
384}
385
386QComboBoxPrivateContainer::QComboBoxPrivateContainer(QAbstractItemView *itemView, QComboBox *parent)
387 : QFrame(parent, Qt::Popup), combo(parent), view(0), top(0), bottom(0)
388{
389 // we need the combobox and itemview
390 Q_ASSERT(parent);
391 Q_ASSERT(itemView);
392
393 setAttribute(Qt::WA_WindowPropagation);
394 setAttribute(Qt::WA_X11NetWmWindowTypeCombo);
395
396 // setup container
397 blockMouseReleaseTimer.setSingleShot(true);
398
399 // we need a vertical layout
400 QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, this);
401 layout->setSpacing(0);
402 layout->setMargin(0);
403
404 // set item view
405 setItemView(itemView);
406
407 // add scroller arrows if style needs them
408 QStyleOptionComboBox opt = comboStyleOption();
409 const bool usePopup = combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo);
410 if (usePopup) {
411 top = new QComboBoxPrivateScroller(QAbstractSlider::SliderSingleStepSub, this);
412 bottom = new QComboBoxPrivateScroller(QAbstractSlider::SliderSingleStepAdd, this);
413 top->hide();
414 bottom->hide();
415 } else {
416 setLineWidth(1);
417 }
418
419 setFrameStyle(combo->style()->styleHint(QStyle::SH_ComboBox_PopupFrameStyle, &opt, combo));
420
421 if (top) {
422 layout->insertWidget(0, top);
423 connect(top, SIGNAL(doScroll(int)), this, SLOT(scrollItemView(int)));
424 }
425 if (bottom) {
426 layout->addWidget(bottom);
427 connect(bottom, SIGNAL(doScroll(int)), this, SLOT(scrollItemView(int)));
428 }
429
430 // Some styles (Mac) have a margin at the top and bottom of the popup.
431 layout->insertSpacing(0, 0);
432 layout->addSpacing(0);
433 updateTopBottomMargin();
434}
435
436void QComboBoxPrivateContainer::scrollItemView(int action)
437{
438#ifndef QT_NO_SCROLLBAR
439 if (view->verticalScrollBar())
440 view->verticalScrollBar()->triggerAction(static_cast<QAbstractSlider::SliderAction>(action));
441#endif
442}
443
444/*
445 Hides or shows the scrollers when we emulate a popupmenu
446*/
447void QComboBoxPrivateContainer::updateScrollers()
448{
449#ifndef QT_NO_SCROLLBAR
450 if (!top || !bottom)
451 return;
452
453 if (isVisible() == false)
454 return;
455
456 QStyleOptionComboBox opt = comboStyleOption();
457 if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo) &&
458 view->verticalScrollBar()->minimum() < view->verticalScrollBar()->maximum()) {
459
460 bool needTop = view->verticalScrollBar()->value()
461 > (view->verticalScrollBar()->minimum() + spacing());
462 bool needBottom = view->verticalScrollBar()->value()
463 < (view->verticalScrollBar()->maximum() - spacing()*2);
464 if (needTop)
465 top->show();
466 else
467 top->hide();
468 if (needBottom)
469 bottom->show();
470 else
471 bottom->hide();
472 } else {
473 top->hide();
474 bottom->hide();
475 }
476#endif // QT_NO_SCROLLBAR
477}
478
479/*
480 Cleans up when the view is destroyed.
481*/
482void QComboBoxPrivateContainer::viewDestroyed()
483{
484 view = 0;
485 setItemView(new QComboBoxListView());
486}
487
488/*
489 Sets currentIndex on entered if the LeftButton is not pressed. This
490 means that if mouseTracking(...) is on, we setCurrentIndex and select
491 even when LeftButton is not pressed.
492*/
493void QComboBoxPrivateContainer::setCurrentIndex(const QModelIndex &index)
494{
495 if (QComboBoxDelegate::isSeparator(index))
496 return;
497 view->setCurrentIndex(index);
498}
499
500/*
501 Returns the item view used for the combobox popup.
502*/
503QAbstractItemView *QComboBoxPrivateContainer::itemView() const
504{
505 return view;
506}
507
508/*!
509 Sets the item view to be used for the combobox popup.
510*/
511void QComboBoxPrivateContainer::setItemView(QAbstractItemView *itemView)
512{
513 Q_ASSERT(itemView);
514
515 // clean up old one
516 if (view) {
517 view->removeEventFilter(this);
518 view->viewport()->removeEventFilter(this);
519#ifndef QT_NO_SCROLLBAR
520 disconnect(view->verticalScrollBar(), SIGNAL(valueChanged(int)),
521 this, SLOT(updateScrollers()));
522 disconnect(view->verticalScrollBar(), SIGNAL(rangeChanged(int,int)),
523 this, SLOT(updateScrollers()));
524#endif
525 disconnect(view, SIGNAL(entered(QModelIndex)),
526 this, SLOT(setCurrentIndex(QModelIndex)));
527 disconnect(view, SIGNAL(destroyed()),
528 this, SLOT(viewDestroyed()));
529 delete view;
530 view = 0;
531 }
532
533 // setup the item view
534 view = itemView;
535 view->setParent(this);
536 view->setAttribute(Qt::WA_MacShowFocusRect, false);
537 qobject_cast<QBoxLayout*>(layout())->insertWidget(top ? 2 : 0, view);
538 view->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
539 view->installEventFilter(this);
540 view->viewport()->installEventFilter(this);
541 view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
542 QStyleOptionComboBox opt = comboStyleOption();
543 const bool usePopup = combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo);
544#ifndef QT_NO_SCROLLBAR
545 if (usePopup)
546 view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
547#endif
548 if (combo->style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking, &opt, combo) ||
549 usePopup) {
550 view->setMouseTracking(true);
551 }
552 view->setSelectionMode(QAbstractItemView::SingleSelection);
553 view->setFrameStyle(QFrame::NoFrame);
554 view->setLineWidth(0);
555 view->setEditTriggers(QAbstractItemView::NoEditTriggers);
556#ifndef QT_NO_SCROLLBAR
557 connect(view->verticalScrollBar(), SIGNAL(valueChanged(int)),
558 this, SLOT(updateScrollers()));
559 connect(view->verticalScrollBar(), SIGNAL(rangeChanged(int,int)),
560 this, SLOT(updateScrollers()));
561#endif
562 connect(view, SIGNAL(entered(QModelIndex)),
563 this, SLOT(setCurrentIndex(QModelIndex)));
564 connect(view, SIGNAL(destroyed()),
565 this, SLOT(viewDestroyed()));
566}
567
568/*!
569 Returns the spacing between the items in the view.
570*/
571int QComboBoxPrivateContainer::spacing() const
572{
573 QListView *lview = qobject_cast<QListView*>(view);
574 if (lview)
575 return lview->spacing();
576#ifndef QT_NO_TABLEVIEW
577 QTableView *tview = qobject_cast<QTableView*>(view);
578 if (tview)
579 return tview->showGrid() ? 1 : 0;
580#endif
581 return 0;
582}
583
584void QComboBoxPrivateContainer::updateTopBottomMargin()
585{
586 if (!layout() || layout()->count() < 1)
587 return;
588
589 QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(layout());
590 if (!boxLayout)
591 return;
592
593 const QStyleOptionComboBox opt = comboStyleOption();
594 const bool usePopup = combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo);
595 const int margin = usePopup ? combo->style()->pixelMetric(QStyle::PM_MenuVMargin, &opt, combo) : 0;
596
597 QSpacerItem *topSpacer = boxLayout->itemAt(0)->spacerItem();
598 if (topSpacer)
599 topSpacer->changeSize(0, margin, QSizePolicy::Minimum, QSizePolicy::Fixed);
600
601 QSpacerItem *bottomSpacer = boxLayout->itemAt(boxLayout->count() - 1)->spacerItem();
602 if (bottomSpacer && bottomSpacer != topSpacer)
603 bottomSpacer->changeSize(0, margin, QSizePolicy::Minimum, QSizePolicy::Fixed);
604
605 boxLayout->invalidate();
606}
607
608void QComboBoxPrivateContainer::changeEvent(QEvent *e)
609{
610 if (e->type() == QEvent::StyleChange) {
611 QStyleOptionComboBox opt = comboStyleOption();
612 view->setMouseTracking(combo->style()->styleHint(QStyle::SH_ComboBox_ListMouseTracking, &opt, combo) ||
613 combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo));
614 setFrameStyle(combo->style()->styleHint(QStyle::SH_ComboBox_PopupFrameStyle, &opt, combo));
615 }
616 QWidget::changeEvent(e);
617}
618
619
620bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e)
621{
622 switch (e->type()) {
623 case QEvent::ShortcutOverride:
624 switch (static_cast<QKeyEvent*>(e)->key()) {
625 case Qt::Key_Enter:
626 case Qt::Key_Return:
627#ifdef QT_KEYPAD_NAVIGATION
628 case Qt::Key_Select:
629#endif
630 if (view->currentIndex().isValid() && (view->currentIndex().flags() & Qt::ItemIsEnabled) ) {
631 combo->hidePopup();
632 emit itemSelected(view->currentIndex());
633 }
634 return true;
635 case Qt::Key_Down:
636 if (!(static_cast<QKeyEvent*>(e)->modifiers() & Qt::AltModifier))
637 break;
638 // fall through
639 case Qt::Key_F4:
640 case Qt::Key_Escape:
641#ifdef QT_KEYPAD_NAVIGATION
642 case Qt::Key_Back:
643#endif
644 combo->hidePopup();
645 return true;
646 default:
647 break;
648 }
649 break;
650 case QEvent::MouseMove: {
651 if (isVisible()) {
652 QMouseEvent *m = static_cast<QMouseEvent *>(e);
653 QWidget *widget = static_cast<QWidget *>(o);
654 QPoint vector = widget->mapToGlobal(m->pos()) - initialClickPosition;
655 if (vector.manhattanLength() > 9 && blockMouseReleaseTimer.isActive())
656 blockMouseReleaseTimer.stop();
657 }
658 break;
659 }
660 case QEvent::MouseButtonRelease: {
661 QMouseEvent *m = static_cast<QMouseEvent *>(e);
662 if (isVisible() && view->rect().contains(m->pos()) && view->currentIndex().isValid()
663 && !blockMouseReleaseTimer.isActive()
664 && (view->currentIndex().flags() & Qt::ItemIsEnabled)
665 && (view->currentIndex().flags() & Qt::ItemIsSelectable)) {
666 combo->hidePopup();
667 emit itemSelected(view->currentIndex());
668 return true;
669 }
670 break;
671 }
672 default:
673 break;
674 }
675 return QFrame::eventFilter(o, e);
676}
677
678void QComboBoxPrivateContainer::showEvent(QShowEvent *)
679{
680 combo->update();
681}
682
683void QComboBoxPrivateContainer::hideEvent(QHideEvent *)
684{
685 emit resetButton();
686 combo->update();
687}
688
689void QComboBoxPrivateContainer::mousePressEvent(QMouseEvent *e)
690{
691
692 QStyleOptionComboBox opt = comboStyleOption();
693 opt.subControls = QStyle::SC_All;
694 opt.activeSubControls = QStyle::SC_ComboBoxArrow;
695 QStyle::SubControl sc = combo->style()->hitTestComplexControl(QStyle::CC_ComboBox, &opt,
696 combo->mapFromGlobal(e->globalPos()),
697 combo);
698 if ((combo->isEditable() && sc == QStyle::SC_ComboBoxArrow)
699 || (!combo->isEditable() && sc != QStyle::SC_None))
700 setAttribute(Qt::WA_NoMouseReplay);
701 combo->hidePopup();
702}
703
704void QComboBoxPrivateContainer::mouseReleaseEvent(QMouseEvent *e)
705{
706 Q_UNUSED(e);
707 if (!blockMouseReleaseTimer.isActive()){
708 combo->hidePopup();
709 emit resetButton();
710 }
711}
712
713QStyleOptionComboBox QComboBoxPrivateContainer::comboStyleOption() const
714{
715 // ### This should use QComboBox's initStyleOption(), but it's protected
716 // perhaps, we could cheat by having the QCombo private instead?
717 QStyleOptionComboBox opt;
718 opt.initFrom(combo);
719 opt.subControls = QStyle::SC_All;
720 opt.activeSubControls = QStyle::SC_None;
721 opt.editable = combo->isEditable();
722 return opt;
723}
724
725/*!
726 \enum QComboBox::InsertPolicy
727
728 This enum specifies what the QComboBox should do when a new string is
729 entered by the user.
730
731 \value NoInsert The string will not be inserted into the combobox.
732 \value InsertAtTop The string will be inserted as the first item in the combobox.
733 \value InsertAtCurrent The current item will be \e replaced by the string.
734 \value InsertAtBottom The string will be inserted after the last item in the combobox.
735 \value InsertAfterCurrent The string is inserted after the current item in the combobox.
736 \value InsertBeforeCurrent The string is inserted before the current item in the combobox.
737 \value InsertAlphabetically The string is inserted in the alphabetic order in the combobox.
738 \omitvalue NoInsertion
739 \omitvalue AtTop
740 \omitvalue AtCurrent
741 \omitvalue AtBottom
742 \omitvalue AfterCurrent
743 \omitvalue BeforeCurrent
744*/
745
746/*!
747 \enum QComboBox::SizeAdjustPolicy
748
749 This enum specifies how the size hint of the QComboBox should
750 adjust when new content is added or content changes.
751
752 \value AdjustToContents The combobox will always adjust to the contents
753 \value AdjustToContentsOnFirstShow The combobox will adjust to its contents the first time it is shown.
754 \value AdjustToMinimumContentsLength Use AdjustToContents or AdjustToContentsOnFirstShow instead.
755 \value AdjustToMinimumContentsLengthWithIcon The combobox will adjust to \l minimumContentsLength plus space for an icon. For performance reasons use this policy on large models.
756*/
757
758/*!
759 \fn void QComboBox::activated(int index)
760
761 This signal is sent when the user chooses an item in the combobox.
762 The item's \a index is passed. Note that this signal is sent even
763 when the choice is not changed. If you need to know when the
764 choice actually changes, use signal currentIndexChanged().
765
766*/
767
768/*!
769 \fn void QComboBox::activated(const QString &text)
770
771 This signal is sent when the user chooses an item in the combobox.
772 The item's \a text is passed. Note that this signal is sent even
773 when the choice is not changed. If you need to know when the
774 choice actually changes, use signal currentIndexChanged().
775
776*/
777
778/*!
779 \fn void QComboBox::highlighted(int index)
780
781 This signal is sent when an item in the combobox popup list is
782 highlighted by the user. The item's \a index is passed.
783*/
784
785/*!
786 \fn void QComboBox::highlighted(const QString &text)
787
788 This signal is sent when an item in the combobox popup list is
789 highlighted by the user. The item's \a text is passed.
790*/
791
792/*!
793 \fn void QComboBox::currentIndexChanged(int index)
794 \since 4.1
795
796 This signal is sent whenever the currentIndex in the combobox
797 changes either through user interaction or programmatically. The
798 item's \a index is passed or -1 if the combobox becomes empty or the
799 currentIndex was reset.
800*/
801
802/*!
803 \fn void QComboBox::currentIndexChanged(const QString &text)
804 \since 4.1
805
806 This signal is sent whenever the currentIndex in the combobox
807 changes either through user interaction or programmatically. The
808 item's \a text is passed.
809*/
810
811/*!
812 Constructs a combobox with the given \a parent, using the default
813 model QStandardItemModel.
814*/
815QComboBox::QComboBox(QWidget *parent)
816 : QWidget(*new QComboBoxPrivate(), parent, 0)
817{
818 Q_D(QComboBox);
819 d->init();
820}
821
822/*!
823 \internal
824*/
825QComboBox::QComboBox(QComboBoxPrivate &dd, QWidget *parent)
826 : QWidget(dd, parent, 0)
827{
828 Q_D(QComboBox);
829 d->init();
830}
831
832#ifdef QT3_SUPPORT
833/*!
834 Use one of the constructors that doesn't take the \a name
835 argument and then use setObjectName() instead.
836*/
837QComboBox::QComboBox(QWidget *parent, const char *name)
838 : QWidget(*new QComboBoxPrivate(), parent, 0)
839{
840 Q_D(QComboBox);
841 d->init();
842 setObjectName(QString::fromAscii(name));
843}
844
845/*!
846 Use one of the constructors that doesn't take the \a name
847 argument and then use setObjectName() instead.
848*/
849QComboBox::QComboBox(bool rw, QWidget *parent, const char *name)
850 : QWidget(*new QComboBoxPrivate(), parent, 0)
851{
852 Q_D(QComboBox);
853 d->init();
854 setEditable(rw);
855 setObjectName(QString::fromAscii(name));
856}
857
858#endif //QT3_SUPPORT
859
860/*!
861 \class QComboBox
862 \brief The QComboBox widget is a combined button and popup list.
863
864 \ingroup basicwidgets
865 \mainclass
866
867 A QComboBox provides a means of presenting a list of options to the user
868 in a way that takes up the minimum amount of screen space.
869
870 A combobox is a selection widget that displays the current item,
871 and can pop up a list of selectable items. A combobox may be editable,
872 allowing the user to modify each item in the list.
873
874 Comboboxes can contain pixmaps as well as strings; the
875 insertItem() and setItemText() functions are suitably overloaded.
876 For editable comboboxes, the function clearEditText() is provided,
877 to clear the displayed string without changing the combobox's
878 contents.
879
880 There are two signals emitted if the current item of a combobox
881 changes, currentIndexChanged() and activated().
882 currentIndexChanged() is always emitted regardless if the change
883 was done programmatically or by user interaction, while
884 activated() is only emitted when the change is caused by user
885 interaction. The highlighted() signal is emitted when the user
886 highlights an item in the combobox popup list. All three signals
887 exist in two versions, one with a QString argument and one with an
888 \c int argument. If the user selectes or highlights a pixmap, only
889 the \c int signals are emitted. Whenever the text of an editable
890 combobox is changed the editTextChanged() signal is emitted.
891
892 When the user enters a new string in an editable combobox, the
893 widget may or may not insert it, and it can insert it in several
894 locations. The default policy is is \l AtBottom but you can change
895 this using setInsertPolicy().
896
897 It is possible to constrain the input to an editable combobox
898 using QValidator; see setValidator(). By default, any input is
899 accepted.
900
901 A combobox can be populated using the insert functions,
902 insertItem() and insertItems() for example. Items can be
903 changed with setItemText(). An item can be removed with
904 removeItem() and all items can be removed with clear(). The text
905 of the current item is returned by currentText(), and the text of
906 a numbered item is returned with text(). The current item can be
907 set with setCurrentIndex(). The number of items in the combobox is
908 returned by count(); the maximum number of items can be set with
909 setMaxCount(). You can allow editing using setEditable(). For
910 editable comboboxes you can set auto-completion using
911 setCompleter() and whether or not the user can add duplicates
912 is set with setDuplicatesEnabled().
913
914 QComboBox uses the \l{Model/View Programming}{model/view
915 framework} for its popup list and to store its items. By default
916 a QStandardItemModel stores the items and a QListView subclass
917 displays the popuplist. You can access the model and view directly
918 (with model() and view()), but QComboBox also provides functions
919 to set and get item data (e.g., setItemData() and itemText()). You
920 can also set a new model and view (with setModel() and setView()).
921 For the text and icon in the combobox label, the data in the model
922 that has the Qt::DisplayRole and Qt::DecorationRole is used.
923
924 \image qstyle-comboboxes.png Comboboxes in the different built-in styles.
925
926 \sa QLineEdit, QSpinBox, QRadioButton, QButtonGroup,
927 {fowler}{GUI Design Handbook: Combo Box, Drop-Down List Box}
928*/
929
930void QComboBoxPrivate::init()
931{
932 Q_Q(QComboBox);
933 q->setFocusPolicy(Qt::WheelFocus);
934 q->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed,
935 QSizePolicy::ComboBox));
936 setLayoutItemMargins(QStyle::SE_ComboBoxLayoutItem);
937 q->setModel(new QStandardItemModel(0, 1, q));
938 q->setAttribute(Qt::WA_InputMethodEnabled);
939}
940
941QComboBoxPrivateContainer* QComboBoxPrivate::viewContainer()
942{
943 if (container)
944 return container;
945
946 Q_Q(QComboBox);
947 container = new QComboBoxPrivateContainer(new QComboBoxListView(q), q);
948 container->itemView()->setModel(model);
949 container->itemView()->setTextElideMode(Qt::ElideMiddle);
950 updateDelegate();
951 updateLayoutDirection();
952 QObject::connect(container, SIGNAL(itemSelected(QModelIndex)),
953 q, SLOT(_q_itemSelected(QModelIndex)));
954 QObject::connect(container->itemView()->selectionModel(),
955 SIGNAL(currentChanged(QModelIndex,QModelIndex)),
956 q, SLOT(_q_emitHighlighted(QModelIndex)));
957 QObject::connect(container, SIGNAL(resetButton()), q, SLOT(_q_resetButton()));
958 return container;
959}
960
961
962void QComboBoxPrivate::_q_resetButton()
963{
964 updateArrow(QStyle::State_None);
965}
966
967void QComboBoxPrivate::_q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
968{
969 Q_Q(QComboBox);
970 if (inserting || topLeft.parent() != root)
971 return;
972
973 if (sizeAdjustPolicy == QComboBox::AdjustToContents) {
974 sizeHint = QSize();
975 adjustComboBoxSize();
976 q->updateGeometry();
977 }
978
979 if (currentIndex.row() >= topLeft.row() && currentIndex.row() <= bottomRight.row()) {
980 if (lineEdit) {
981 lineEdit->setText(q->itemText(currentIndex.row()));
982 updateLineEditGeometry();
983 }
984 q->update();
985 }
986}
987
988void QComboBoxPrivate::_q_rowsAboutToBeInserted(const QModelIndex & parent,
989 int /*start*/, int /*end*/)
990{
991 if (parent != root)
992 return;
993 indexBeforeChange = currentIndex.row();
994}
995
996void QComboBoxPrivate::_q_rowsInserted(const QModelIndex &parent, int start, int end)
997{
998 Q_Q(QComboBox);
999 if (inserting || parent != root)
1000 return;
1001
1002 if (sizeAdjustPolicy == QComboBox::AdjustToContents) {
1003 sizeHint = QSize();
1004 adjustComboBoxSize();
1005 q->updateGeometry();
1006 }
1007
1008 // set current index if combo was previously empty
1009 if (start == 0 && (end - start + 1) == q->count() && !currentIndex.isValid()) {
1010 q->setCurrentIndex(0);
1011 // need to emit changed if model updated index "silently"
1012 } else if (currentIndex.row() != indexBeforeChange) {
1013 q->update();
1014 _q_emitCurrentIndexChanged(currentIndex);
1015 }
1016}
1017
1018void QComboBoxPrivate::_q_rowsAboutToBeRemoved(const QModelIndex &parent, int /*start*/, int /*end*/)
1019{
1020 if (parent != root)
1021 return;
1022
1023 indexBeforeChange = currentIndex.row();
1024}
1025
1026void QComboBoxPrivate::_q_rowsRemoved(const QModelIndex &parent, int /*start*/, int /*end*/)
1027{
1028 Q_Q(QComboBox);
1029 if (parent != root)
1030 return;
1031
1032 if (sizeAdjustPolicy == QComboBox::AdjustToContents) {
1033 sizeHint = QSize();
1034 adjustComboBoxSize();
1035 q->updateGeometry();
1036 }
1037
1038 // model has changed the currentIndex
1039 if (currentIndex.row() != indexBeforeChange) {
1040 if (!currentIndex.isValid() && q->count()) {
1041 q->setCurrentIndex(qMin(q->count() - 1, qMax(indexBeforeChange, 0)));
1042 return;
1043 }
1044 if (lineEdit) {
1045 lineEdit->setText(q->itemText(currentIndex.row()));
1046 updateLineEditGeometry();
1047 }
1048 q->update();
1049 _q_emitCurrentIndexChanged(currentIndex);
1050 }
1051}
1052
1053
1054/*!
1055 Initialize \a option with the values from this QComboBox. This method
1056 is useful for subclasses when they need a QStyleOptionComboBox, but don't want
1057 to fill in all the information themselves.
1058
1059 \sa QStyleOption::initFrom()
1060*/
1061void QComboBox::initStyleOption(QStyleOptionComboBox *option) const
1062{
1063 if (!option)
1064 return;
1065
1066 Q_D(const QComboBox);
1067 option->initFrom(this);
1068 option->editable = isEditable();
1069 option->frame = d->frame;
1070 if (hasFocus() && !option->editable)
1071 option->state |= QStyle::State_Selected;
1072 option->subControls = QStyle::SC_All;
1073 if (d->arrowState == QStyle::State_Sunken) {
1074 option->activeSubControls = QStyle::SC_ComboBoxArrow;
1075 option->state |= d->arrowState;
1076 } else {
1077 option->activeSubControls = d->hoverControl;
1078 }
1079 if (d->currentIndex.isValid()) {
1080 option->currentText = currentText();
1081 option->currentIcon = d->itemIcon(d->currentIndex);
1082 }
1083 option->iconSize = iconSize();
1084 if (d->container && d->container->isVisible())
1085 option->state |= QStyle::State_On;
1086}
1087
1088void QComboBoxPrivate::updateLineEditGeometry()
1089{
1090 if (!lineEdit)
1091 return;
1092
1093 Q_Q(QComboBox);
1094 QStyleOptionComboBox opt;
1095 q->initStyleOption(&opt);
1096 QRect editRect = q->style()->subControlRect(QStyle::CC_ComboBox, &opt,
1097 QStyle::SC_ComboBoxEditField, q);
1098 if (!q->itemIcon(q->currentIndex()).isNull()) {
1099 QRect comboRect(editRect);
1100 editRect.setWidth(editRect.width() - q->iconSize().width() - 4);
1101 editRect = QStyle::alignedRect(q->layoutDirection(), Qt::AlignRight,
1102 editRect.size(), comboRect);
1103 }
1104 lineEdit->setGeometry(editRect);
1105}
1106
1107void QComboBoxPrivate::_q_returnPressed()
1108{
1109 Q_Q(QComboBox);
1110 if (lineEdit && !lineEdit->text().isEmpty()) {
1111 if (q->count() >= maxCount && !(this->insertPolicy == QComboBox::InsertAtCurrent))
1112 return;
1113 lineEdit->deselect();
1114 lineEdit->end(false);
1115 QString text = lineEdit->text();
1116 // check for duplicates (if not enabled) and quit
1117 int index = -1;
1118 if (!duplicatesEnabled) {
1119 // Base how duplicates are determined on the autocompletion case sensitivity
1120 Qt::MatchFlags flags = Qt::MatchFixedString;
1121#ifndef QT_NO_COMPLETER
1122 if (!lineEdit->completer() || lineEdit->completer()->caseSensitivity() == Qt::CaseSensitive)
1123#endif
1124 flags |= Qt::MatchCaseSensitive;
1125 index = q->findText(text, flags);
1126 if (index != -1) {
1127 q->setCurrentIndex(index);
1128 emitActivated(currentIndex);
1129 return;
1130 }
1131 }
1132 switch (insertPolicy) {
1133 case QComboBox::InsertAtTop:
1134 index = 0;
1135 break;
1136 case QComboBox::InsertAtBottom:
1137 index = q->count();
1138 break;
1139 case QComboBox::InsertAtCurrent:
1140 case QComboBox::InsertAfterCurrent:
1141 case QComboBox::InsertBeforeCurrent:
1142 if (!q->count() || !currentIndex.isValid())
1143 index = 0;
1144 else if (insertPolicy == QComboBox::InsertAtCurrent)
1145 q->setItemText(q->currentIndex(), text);
1146 else if (insertPolicy == QComboBox::InsertAfterCurrent)
1147 index = q->currentIndex() + 1;
1148 else if (insertPolicy == QComboBox::InsertBeforeCurrent)
1149 index = q->currentIndex();
1150 break;
1151 case QComboBox::InsertAlphabetically:
1152 index = 0;
1153 for (int i=0; i< q->count(); i++, index++ ) {
1154 if (text.toLower() < q->itemText(i).toLower())
1155 break;
1156 }
1157 break;
1158 case QComboBox::NoInsert:
1159 default:
1160 break;
1161 }
1162 if (index >= 0) {
1163 q->insertItem(index, text);
1164 q->setCurrentIndex(index);
1165 emitActivated(currentIndex);
1166 }
1167 }
1168}
1169
1170void QComboBoxPrivate::_q_itemSelected(const QModelIndex &item)
1171{
1172 Q_Q(QComboBox);
1173 if (item != currentIndex) {
1174 setCurrentIndex(item);
1175 } else if (lineEdit) {
1176 lineEdit->selectAll();
1177 lineEdit->setText(q->itemText(currentIndex.row()));
1178 }
1179 emitActivated(currentIndex);
1180}
1181
1182void QComboBoxPrivate::emitActivated(const QModelIndex &index)
1183{
1184 Q_Q(QComboBox);
1185 if (!index.isValid())
1186 return;
1187 QString text(itemText(index));
1188 emit q->activated(index.row());
1189 emit q->activated(text);
1190}
1191
1192void QComboBoxPrivate::_q_emitHighlighted(const QModelIndex &index)
1193{
1194 Q_Q(QComboBox);
1195 if (!index.isValid())
1196 return;
1197 QString text(itemText(index));
1198 emit q->highlighted(index.row());
1199 emit q->highlighted(text);
1200}
1201
1202void QComboBoxPrivate::_q_emitCurrentIndexChanged(const QModelIndex &index)
1203{
1204 Q_Q(QComboBox);
1205 emit q->currentIndexChanged(index.row());
1206 emit q->currentIndexChanged(itemText(index));
1207}
1208
1209QString QComboBoxPrivate::itemText(const QModelIndex &index) const
1210{
1211 return index.isValid() ? model->data(index, itemRole()).toString() : QString();
1212}
1213
1214int QComboBoxPrivate::itemRole() const
1215{
1216 return q_func()->isEditable() ? Qt::EditRole : Qt::DisplayRole;
1217}
1218
1219/*!
1220 Destroys the combobox.
1221*/
1222QComboBox::~QComboBox()
1223{
1224 // ### check delegateparent and delete delegate if us?
1225 Q_D(QComboBox);
1226
1227 disconnect(d->model, SIGNAL(destroyed()),
1228 this, SLOT(_q_modelDestroyed()));
1229}
1230
1231/*!
1232 \property QComboBox::maxVisibleItems
1233 \brief the maximum allowed size on screen of the combo box, measured in items
1234
1235 By default, this property has a value of 10.
1236
1237 \note This property is ignored for non-editable comboboxes in Mac style.
1238*/
1239int QComboBox::maxVisibleItems() const
1240{
1241 Q_D(const QComboBox);
1242 return d->maxVisibleItems;
1243}
1244
1245void QComboBox::setMaxVisibleItems(int maxItems)
1246{
1247 Q_D(QComboBox);
1248 if (maxItems < 0) {
1249 qWarning("QComboBox::setMaxVisibleItems: "
1250 "Invalid max visible items (%d) must be >= 0", maxItems);
1251 return;
1252 }
1253 d->maxVisibleItems = maxItems;
1254}
1255
1256/*!
1257 \property QComboBox::count
1258 \brief the number of items in the combobox
1259
1260 By default, for an empty combo box, this property has a value of 0.
1261*/
1262int QComboBox::count() const
1263{
1264 Q_D(const QComboBox);
1265 return d->model->rowCount(d->root);
1266}
1267
1268/*!
1269 \property QComboBox::maxCount
1270 \brief the maximum number of items allowed in the combobox
1271
1272 \note If you set the maximum number to be less then the current
1273 amount of items in the combobox, the extra items will be
1274 truncated. This also applies if you have set an external model on
1275 the combobox.
1276
1277 By default, this property's value is derived from the highest
1278 signed integer available (typically 2147483647).
1279*/
1280void QComboBox::setMaxCount(int max)
1281{
1282 Q_D(QComboBox);
1283 if (max < 0) {
1284 qWarning("QComboBox::setMaxCount: Invalid count (%d) must be >= 0", max);
1285 return;
1286 }
1287
1288 if (max < count())
1289 d->model->removeRows(max, count() - max, d->root);
1290
1291 d->maxCount = max;
1292}
1293
1294int QComboBox::maxCount() const
1295{
1296 Q_D(const QComboBox);
1297 return d->maxCount;
1298}
1299
1300#ifndef QT_NO_COMPLETER
1301
1302/*!
1303 \property QComboBox::autoCompletion
1304 \brief whether the combobox provides auto-completion for editable items
1305 \since 4.1
1306 \obsolete
1307
1308 Use setCompleter() instead.
1309
1310 By default, this property is true.
1311
1312 \sa editable
1313*/
1314
1315/*!
1316 \obsolete
1317
1318 Use setCompleter() instead.
1319*/
1320bool QComboBox::autoCompletion() const
1321{
1322 Q_D(const QComboBox);
1323 return d->autoCompletion;
1324}
1325
1326/*!
1327 \obsolete
1328
1329 Use setCompleter() instead.
1330*/
1331void QComboBox::setAutoCompletion(bool enable)
1332{
1333 Q_D(QComboBox);
1334
1335#ifdef QT_KEYPAD_NAVIGATION
1336 if (QApplication::keypadNavigationEnabled() && !enable && isEditable())
1337 qWarning("QComboBox::setAutoCompletion: auto completion is mandatory when combo box editable");
1338#endif
1339
1340 d->autoCompletion = enable;
1341 if (!d->lineEdit)
1342 return;
1343 if (enable) {
1344 if (d->lineEdit->completer())
1345 return;
1346 d->completer = new QCompleter(d->model, d->lineEdit);
1347 d->completer->setCaseSensitivity(d->autoCompletionCaseSensitivity);
1348 d->completer->setCompletionMode(QCompleter::InlineCompletion);
1349 d->completer->setCompletionColumn(d->modelColumn);
1350 d->lineEdit->setCompleter(d->completer);
1351 d->completer->setWidget(this);
1352 } else {
1353 d->lineEdit->setCompleter(0);
1354 }
1355}
1356
1357/*!
1358 \property QComboBox::autoCompletionCaseSensitivity
1359 \brief whether string comparisons are case-sensitive or case-insensitive for auto-completion
1360 \obsolete
1361
1362 By default, this property is Qt::CaseInsensitive.
1363
1364 Use setCompleter() instead. Case sensitivity of the auto completion can be
1365 changed using QCompleter::setCaseSensitivity().
1366
1367 \sa autoCompletion
1368*/
1369
1370/*!
1371 \obsolete
1372
1373 Use setCompleter() and QCompleter::setCaseSensitivity() instead.
1374*/
1375Qt::CaseSensitivity QComboBox::autoCompletionCaseSensitivity() const
1376{
1377 Q_D(const QComboBox);
1378 return d->autoCompletionCaseSensitivity;
1379}
1380
1381/*!
1382 \obsolete
1383
1384 Use setCompleter() and QCompleter::setCaseSensitivity() instead.
1385*/
1386void QComboBox::setAutoCompletionCaseSensitivity(Qt::CaseSensitivity sensitivity)
1387{
1388 Q_D(QComboBox);
1389 d->autoCompletionCaseSensitivity = sensitivity;
1390 if (d->lineEdit && d->lineEdit->completer())
1391 d->lineEdit->completer()->setCaseSensitivity(sensitivity);
1392}
1393
1394#endif // QT_NO_COMPLETER
1395
1396/*!
1397 \property QComboBox::duplicatesEnabled
1398 \brief whether the user can enter duplicate items into the combobox
1399
1400 Note that it is always possible to programmatically insert duplicate items into the
1401 combobox.
1402
1403 By default, this property is false (duplicates are not allowed).
1404*/
1405bool QComboBox::duplicatesEnabled() const
1406{
1407 Q_D(const QComboBox);
1408 return d->duplicatesEnabled;
1409}
1410
1411void QComboBox::setDuplicatesEnabled(bool enable)
1412{
1413 Q_D(QComboBox);
1414 d->duplicatesEnabled = enable;
1415}
1416
1417/*! \fn int QComboBox::findText(const QString &text, Qt::MatchFlags flags = Qt::MatchExactly|Qt::MatchCaseSensitive) const
1418
1419 Returns the index of the item containing the given \a text; otherwise
1420 returns -1.
1421
1422 The \a flags specify how the items in the combobox are searched.
1423*/
1424
1425/*!
1426 Returns the index of the item containing the given \a data for the
1427 given \a role; otherwise returns -1.
1428
1429 The \a flags specify how the items in the combobox are searched.
1430*/
1431int QComboBox::findData(const QVariant &data, int role, Qt::MatchFlags flags) const
1432{
1433 Q_D(const QComboBox);
1434 QModelIndexList result;
1435 QModelIndex start = d->model->index(0, d->modelColumn, d->root);
1436 result = d->model->match(start, role, data, 1, flags);
1437 if (result.isEmpty())
1438 return -1;
1439 return result.first().row();
1440}
1441
1442/*!
1443 \property QComboBox::insertPolicy
1444 \brief the policy used to determine where user-inserted items should
1445 appear in the combobox
1446
1447 The default value is \l AtBottom, indicating that new items will appear
1448 at the bottom of the list of items.
1449
1450 \sa InsertPolicy
1451*/
1452
1453QComboBox::InsertPolicy QComboBox::insertPolicy() const
1454{
1455 Q_D(const QComboBox);
1456 return d->insertPolicy;
1457}
1458
1459void QComboBox::setInsertPolicy(InsertPolicy policy)
1460{
1461 Q_D(QComboBox);
1462 d->insertPolicy = policy;
1463}
1464
1465/*!
1466 \property QComboBox::sizeAdjustPolicy
1467 \brief the policy describing how the size of the combobox changes
1468 when the content changes
1469
1470 The default value is \l AdjustToContentsOnFirstShow.
1471
1472 \sa SizeAdjustPolicy
1473*/
1474
1475QComboBox::SizeAdjustPolicy QComboBox::sizeAdjustPolicy() const
1476{
1477 Q_D(const QComboBox);
1478 return d->sizeAdjustPolicy;
1479}
1480
1481void QComboBox::setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy policy)
1482{
1483 Q_D(QComboBox);
1484 if (policy == d->sizeAdjustPolicy)
1485 return;
1486
1487 d->sizeAdjustPolicy = policy;
1488 d->sizeHint = QSize();
1489 d->adjustComboBoxSize();
1490 updateGeometry();
1491}
1492
1493/*!
1494 \property QComboBox::minimumContentsLength
1495 \brief the minimum number of characters that should fit into the combobox.
1496
1497 The default value is 0.
1498
1499 If this property is set to a positive value, the
1500 minimumSizeHint() and sizeHint() take it into account.
1501
1502 \sa sizeAdjustPolicy
1503*/
1504int QComboBox::minimumContentsLength() const
1505{
1506 Q_D(const QComboBox);
1507 return d->minimumContentsLength;
1508}
1509
1510void QComboBox::setMinimumContentsLength(int characters)
1511{
1512 Q_D(QComboBox);
1513 if (characters == d->minimumContentsLength || characters < 0)
1514 return;
1515
1516 d->minimumContentsLength = characters;
1517
1518 if (d->sizeAdjustPolicy == AdjustToContents
1519 || d->sizeAdjustPolicy == AdjustToMinimumContentsLength
1520 || d->sizeAdjustPolicy == AdjustToMinimumContentsLengthWithIcon) {
1521 d->sizeHint = QSize();
1522 d->adjustComboBoxSize();
1523 updateGeometry();
1524 }
1525}
1526
1527/*!
1528 \property QComboBox::iconSize
1529 \brief the size of the icons shown in the combobox.
1530
1531 Unless explicitly set this returns the default value of the
1532 current style. This size is the maximum size that icons can have;
1533 icons of smaller size are not scaled up.
1534*/
1535
1536QSize QComboBox::iconSize() const
1537{
1538 Q_D(const QComboBox);
1539 if (d->iconSize.isValid())
1540 return d->iconSize;
1541
1542 int iconWidth = style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this);
1543 return QSize(iconWidth, iconWidth);
1544}
1545
1546void QComboBox::setIconSize(const QSize &size)
1547{
1548 Q_D(QComboBox);
1549 if (size == d->iconSize)
1550 return;
1551
1552 view()->setIconSize(size);
1553 d->iconSize = size;
1554 d->sizeHint = QSize();
1555 updateGeometry();
1556}
1557
1558/*!
1559 \property QComboBox::editable
1560 \brief whether the combo box can be edited by the user
1561
1562 By default, this property is false.
1563*/
1564bool QComboBox::isEditable() const
1565{
1566 Q_D(const QComboBox);
1567 return d->lineEdit != 0;
1568}
1569
1570void QComboBoxPrivate::updateDelegate()
1571{
1572 Q_Q(QComboBox);
1573 QStyleOptionComboBox opt;
1574 q->initStyleOption(&opt);
1575 if (q->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, q))
1576 q->setItemDelegate(new QComboMenuDelegate(q->view(), q));
1577 else
1578 q->setItemDelegate(new QComboBoxDelegate(q->view(), q));
1579}
1580
1581QIcon QComboBoxPrivate::itemIcon(const QModelIndex &index) const
1582{
1583 QVariant decoration = model->data(index, Qt::DecorationRole);
1584 if (decoration.type() == QVariant::Pixmap)
1585 return QIcon(qvariant_cast<QPixmap>(decoration));
1586 else
1587 return qvariant_cast<QIcon>(decoration);
1588}
1589
1590void QComboBox::setEditable(bool editable)
1591{
1592 Q_D(QComboBox);
1593 if (isEditable() == editable)
1594 return;
1595
1596 d->updateDelegate();
1597
1598 QStyleOptionComboBox opt;
1599 initStyleOption(&opt);
1600 if (editable) {
1601 if (style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this)) {
1602 d->viewContainer()->updateScrollers();
1603 view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1604 }
1605 QLineEdit *le = new QLineEdit(this);
1606 setLineEdit(le);
1607 } else {
1608 if (style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this)) {
1609 d->viewContainer()->updateScrollers();
1610 view()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1611 }
1612 setAttribute(Qt::WA_InputMethodEnabled, false);
1613 d->lineEdit->hide();
1614 d->lineEdit->deleteLater();
1615 d->lineEdit = 0;
1616 }
1617
1618 d->viewContainer()->updateTopBottomMargin();
1619 if (!testAttribute(Qt::WA_Resized))
1620 adjustSize();
1621}
1622
1623/*!
1624 Sets the line \a edit to use instead of the current line edit widget.
1625
1626 The combo box takes ownership of the line edit.
1627*/
1628void QComboBox::setLineEdit(QLineEdit *edit)
1629{
1630 Q_D(QComboBox);
1631 if (!edit) {
1632 qWarning("QComboBox::setLineEdit: cannot set a 0 line edit");
1633 return;
1634 }
1635
1636 if (edit == d->lineEdit)
1637 return;
1638
1639 edit->setText(currentText());
1640 delete d->lineEdit;
1641
1642 d->lineEdit = edit;
1643 if (d->lineEdit->parent() != this)
1644 d->lineEdit->setParent(this);
1645 connect(d->lineEdit, SIGNAL(returnPressed()), this, SLOT(_q_returnPressed()));
1646 connect(d->lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(editTextChanged(QString)));
1647#ifdef QT3_SUPPORT
1648 connect(d->lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(textChanged(QString)));
1649#endif
1650 d->lineEdit->setFrame(false);
1651 d->lineEdit->setContextMenuPolicy(Qt::NoContextMenu);
1652 d->lineEdit->setFocusProxy(this);
1653 d->lineEdit->setAttribute(Qt::WA_MacShowFocusRect, false);
1654#ifndef QT_NO_COMPLETER
1655 setAutoCompletion(d->autoCompletion);
1656#endif
1657
1658#ifdef QT_KEYPAD_NAVIGATION
1659#ifndef QT_NO_COMPLETER
1660 if (QApplication::keypadNavigationEnabled()) {
1661 // Editable combo boxes will have a completer that is set to UnfilteredPopupCompletion.
1662 // This means that when the user enters edit mode they are immediately presented with a
1663 // list of possible completions.
1664 setAutoCompletion(true);
1665 if (d->completer) {
1666 d->completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
1667 connect(d->completer, SIGNAL(activated(QModelIndex)), this, SLOT(_q_completerActivated()));
1668 }
1669 }
1670#endif
1671#endif
1672
1673 setAttribute(Qt::WA_InputMethodEnabled);
1674 d->updateLayoutDirection();
1675 d->updateLineEditGeometry();
1676 if (isVisible())
1677 d->lineEdit->show();
1678
1679 update();
1680}
1681
1682/*!
1683 Returns the line edit used to edit items in the combobox, or 0 if there
1684 is no line edit.
1685
1686 Only editable combo boxes have a line edit.
1687*/
1688QLineEdit *QComboBox::lineEdit() const
1689{
1690 Q_D(const QComboBox);
1691 return d->lineEdit;
1692}
1693
1694#ifndef QT_NO_VALIDATOR
1695/*!
1696 \fn void QComboBox::setValidator(const QValidator *validator)
1697
1698 Sets the \a validator to use instead of the current validator.
1699*/
1700
1701void QComboBox::setValidator(const QValidator *v)
1702{
1703 Q_D(QComboBox);
1704 if (d->lineEdit)
1705 d->lineEdit->setValidator(v);
1706}
1707
1708/*!
1709 Returns the validator that is used to constrain text input for the
1710 combobox.
1711
1712 \sa editable
1713*/
1714const QValidator *QComboBox::validator() const
1715{
1716 Q_D(const QComboBox);
1717 return d->lineEdit ? d->lineEdit->validator() : 0;
1718}
1719#endif // QT_NO_VALIDATOR
1720
1721#ifndef QT_NO_COMPLETER
1722
1723/*!
1724 \fn void QComboBox::setCompleter(QCompleter *completer)
1725 \since 4.2
1726
1727 Sets the \a completer to use instead of the current completer.
1728 If \a completer is 0, auto completion is disabled.
1729
1730 By default, for an editable combo box, a QCompleter that
1731 performs case insensitive inline completion is automatically created.
1732*/
1733void QComboBox::setCompleter(QCompleter *c)
1734{
1735 Q_D(QComboBox);
1736 if (!d->lineEdit)
1737 return;
1738 d->lineEdit->setCompleter(c);
1739 if (c)
1740 c->setWidget(this);
1741}
1742
1743/*!
1744 \since 4.2
1745
1746 Returns the completer that is used to auto complete text input for the
1747 combobox.
1748
1749 \sa editable
1750*/
1751QCompleter *QComboBox::completer() const
1752{
1753 Q_D(const QComboBox);
1754 return d->lineEdit ? d->lineEdit->completer() : 0;
1755}
1756
1757#endif // QT_NO_COMPLETER
1758
1759/*!
1760 Returns the item delegate used by the popup list view.
1761
1762 \sa setItemDelegate()
1763*/
1764QAbstractItemDelegate *QComboBox::itemDelegate() const
1765{
1766 return view()->itemDelegate();
1767}
1768
1769/*!
1770 Sets the item \a delegate for the popup list view.
1771 The combobox takes ownership of the delegate.
1772
1773 \warning You should not share the same instance of a delegate between comboboxes,
1774 widget mappers or views. Doing so can cause incorrect or unintuitive editing behavior
1775 since each view connected to a given delegate may receive the
1776 \l{QAbstractItemDelegate::}{closeEditor()} signal, and attempt to access, modify or
1777 close an editor that has already been closed.
1778
1779 \sa itemDelegate()
1780*/
1781void QComboBox::setItemDelegate(QAbstractItemDelegate *delegate)
1782{
1783 if (!delegate) {
1784 qWarning("QComboBox::setItemDelegate: cannot set a 0 delegate");
1785 return;
1786 }
1787 delete view()->itemDelegate();
1788 view()->setItemDelegate(delegate);
1789}
1790
1791/*!
1792 Returns the model used by the combobox.
1793*/
1794
1795QAbstractItemModel *QComboBox::model() const
1796{
1797 Q_D(const QComboBox);
1798 if (d->model == QAbstractItemModelPrivate::staticEmptyModel()) {
1799 QComboBox *that = const_cast<QComboBox*>(this);
1800 that->setModel(new QStandardItemModel(0, 1, that));
1801 }
1802 return d->model;
1803}
1804
1805/*!
1806 Sets the model to be \a model. \a model must not be 0.
1807 If you want to clear the contents of a model, call clear().
1808
1809 \sa clear()
1810*/
1811void QComboBox::setModel(QAbstractItemModel *model)
1812{
1813 Q_D(QComboBox);
1814
1815 if (!model) {
1816 qWarning("QComboBox::setModel: cannot set a 0 model");
1817 return;
1818 }
1819
1820#ifndef QT_NO_COMPLETER
1821 if (d->lineEdit && d->lineEdit->completer()
1822 && d->lineEdit->completer() == d->completer)
1823 d->lineEdit->completer()->setModel(model);
1824#endif
1825 if (d->model) {
1826 disconnect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
1827 this, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
1828 disconnect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
1829 this, SLOT(_q_rowsAboutToBeInserted(QModelIndex,int,int)));
1830 disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
1831 this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
1832 disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
1833 this, SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)));
1834 disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
1835 this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
1836 disconnect(d->model, SIGNAL(destroyed()),
1837 this, SLOT(_q_modelDestroyed()));
1838 disconnect(d->model, SIGNAL(modelReset()),
1839 this, SLOT(_q_modelReset()));
1840 if (d->model->QObject::parent() == this)
1841 delete d->model;
1842 }
1843
1844 d->model = model;
1845
1846 connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
1847 this, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
1848 connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
1849 this, SLOT(_q_rowsAboutToBeInserted(QModelIndex,int,int)));
1850 connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
1851 this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
1852 connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
1853 this, SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)));
1854 connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
1855 this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
1856 connect(model, SIGNAL(destroyed()),
1857 this, SLOT(_q_modelDestroyed()));
1858 connect(model, SIGNAL(modelReset()),
1859 this, SLOT(_q_modelReset()));
1860
1861 if (d->container)
1862 d->container->itemView()->setModel(model);
1863
1864 bool currentReset = false;
1865
1866 if (count()) {
1867 for (int pos=0; pos < count(); pos++) {
1868 if (d->model->index(pos, d->modelColumn, d->root).flags() & Qt::ItemIsEnabled) {
1869 setCurrentIndex(pos);
1870 currentReset = true;
1871 break;
1872 }
1873 }
1874 }
1875
1876 if (!currentReset)
1877 setCurrentIndex(-1);
1878
1879 d->modelChanged();
1880}
1881
1882/*!
1883 Returns the root model item index for the items in the combobox.
1884
1885 \sa setRootModelIndex()
1886*/
1887
1888QModelIndex QComboBox::rootModelIndex() const
1889{
1890 Q_D(const QComboBox);
1891 return QModelIndex(d->root);
1892}
1893
1894/*!
1895 Sets the root model item \a index for the items in the combobox.
1896
1897 \sa rootModelIndex()
1898*/
1899void QComboBox::setRootModelIndex(const QModelIndex &index)
1900{
1901 Q_D(QComboBox);
1902 d->root = QPersistentModelIndex(index);
1903 view()->setRootIndex(index);
1904 update();
1905}
1906
1907/*!
1908 \property QComboBox::currentIndex
1909 \brief the index of the current item in the combobox.
1910
1911 The current index can change when inserting or removing items.
1912
1913 By default, for an empty combo box or a combo box in which no current
1914 item is set, this property has a value of -1.
1915*/
1916int QComboBox::currentIndex() const
1917{
1918 Q_D(const QComboBox);
1919 return d->currentIndex.row();
1920}
1921
1922void QComboBox::setCurrentIndex(int index)
1923{
1924 Q_D(QComboBox);
1925 QModelIndex mi = d->model->index(index, d->modelColumn, d->root);
1926 d->setCurrentIndex(mi);
1927}
1928
1929void QComboBoxPrivate::setCurrentIndex(const QModelIndex &mi)
1930{
1931 Q_Q(QComboBox);
1932 bool indexChanged = (mi != currentIndex);
1933 if (indexChanged)
1934 currentIndex = QPersistentModelIndex(mi);
1935 if (lineEdit) {
1936 QString newText = q->itemText(currentIndex.row());
1937 if (lineEdit->text() != newText)
1938 lineEdit->setText(q->itemText(currentIndex.row()));
1939 updateLineEditGeometry();
1940 }
1941 if (indexChanged) {
1942 q->update();
1943 _q_emitCurrentIndexChanged(currentIndex);
1944 }
1945}
1946
1947/*!
1948 \property QComboBox::currentText
1949 \brief the text of the current item
1950
1951 By default, for an empty combo box or a combo box in which no current
1952 item is set, this property contains an empty string.
1953*/
1954QString QComboBox::currentText() const
1955{
1956 Q_D(const QComboBox);
1957 if (d->lineEdit)
1958 return d->lineEdit->text();
1959 else if (d->currentIndex.isValid())
1960 return d->itemText(d->currentIndex);
1961 else
1962 return QString();
1963}
1964
1965/*!
1966 Returns the text for the given \a index in the combobox.
1967*/
1968QString QComboBox::itemText(int index) const
1969{
1970 Q_D(const QComboBox);
1971 QModelIndex mi = d->model->index(index, d->modelColumn, d->root);
1972 return d->itemText(mi);
1973}
1974
1975/*!
1976 Returns the icon for the given \a index in the combobox.
1977*/
1978QIcon QComboBox::itemIcon(int index) const
1979{
1980 Q_D(const QComboBox);
1981 QModelIndex mi = d->model->index(index, d->modelColumn, d->root);
1982 return d->itemIcon(mi);
1983}
1984
1985/*!
1986 Returns the data for the given \a role in the given \a index in the
1987 combobox, or QVariant::Invalid if there is no data for this role.
1988*/
1989QVariant QComboBox::itemData(int index, int role) const
1990{
1991 Q_D(const QComboBox);
1992 QModelIndex mi = d->model->index(index, d->modelColumn, d->root);
1993 return d->model->data(mi, role);
1994}
1995
1996/*!
1997 \fn void QComboBox::insertItem(int index, const QString &text, const QVariant &userData)
1998
1999 Inserts the \a text and \a userData (stored in the Qt::UserRole)
2000 into the combobox at the given \a index.
2001
2002 If the index is equal to or higher than the total number of items,
2003 the new item is appended to the list of existing items. If the
2004 index is zero or negative, the new item is prepended to the list
2005 of existing items.
2006
2007 \sa insertItems()
2008*/
2009
2010/*!
2011
2012 Inserts the \a icon, \a text and \a userData (stored in the
2013 Qt::UserRole) into the combobox at the given \a index.
2014
2015 If the index is equal to or higher than the total number of items,
2016 the new item is appended to the list of existing items. If the
2017 index is zero or negative, the new item is prepended to the list
2018 of existing items.
2019
2020 \sa insertItems()
2021*/
2022void QComboBox::insertItem(int index, const QIcon &icon, const QString &text, const QVariant &userData)
2023{
2024 Q_D(QComboBox);
2025 int itemCount = count();
2026 index = qBound(0, index, itemCount);
2027 if (index >= d->maxCount)
2028 return;
2029
2030 // For the common case where we are using the built in QStandardItemModel
2031 // construct a QStandardItem, reducing the number of expensive signals from the model
2032 if (QStandardItemModel *m = qobject_cast<QStandardItemModel*>(d->model)) {
2033 QStandardItem *item = new QStandardItem(text);
2034 if (!icon.isNull()) item->setData(icon, Qt::DecorationRole);
2035 if (userData.isValid()) item->setData(userData, Qt::UserRole);
2036 m->insertRow(index, item);
2037 ++itemCount;
2038 } else {
2039 d->inserting = true;
2040 if (d->model->insertRows(index, 1, d->root)) {
2041 QModelIndex item = d->model->index(index, d->modelColumn, d->root);
2042 if (icon.isNull() && !userData.isValid()) {
2043 d->model->setData(item, text, Qt::EditRole);
2044 } else {
2045 QMap<int, QVariant> values;
2046 if (!text.isNull()) values.insert(Qt::EditRole, text);
2047 if (!icon.isNull()) values.insert(Qt::DecorationRole, icon);
2048 if (userData.isValid()) values.insert(Qt::UserRole, userData);
2049 if (!values.isEmpty()) d->model->setItemData(item, values);
2050 }
2051 d->inserting = false;
2052 d->_q_rowsInserted(d->root, index, index);
2053 ++itemCount;
2054 } else {
2055 d->inserting = false;
2056 }
2057 }
2058
2059 if (itemCount > d->maxCount)
2060 d->model->removeRows(itemCount - 1, itemCount - d->maxCount, d->root);
2061}
2062
2063/*!
2064 Inserts the strings from the \a list into the combobox as separate items,
2065 starting at the \a index specified.
2066
2067 If the index is equal to or higher than the total number of items, the new items
2068 are appended to the list of existing items. If the index is zero or negative, the
2069 new items are prepended to the list of existing items.
2070
2071 \sa insertItem()
2072 */
2073void QComboBox::insertItems(int index, const QStringList &list)
2074{
2075 Q_D(QComboBox);
2076 if (list.isEmpty())
2077 return;
2078 index = qBound(0, index, count());
2079 int insertCount = qMin(d->maxCount - index, list.count());
2080 if (insertCount <= 0)
2081 return;
2082 // For the common case where we are using the built in QStandardItemModel
2083 // construct a QStandardItem, reducing the number of expensive signals from the model
2084 if (QStandardItemModel *m = qobject_cast<QStandardItemModel*>(d->model)) {
2085 QList<QStandardItem *> items;
2086 QStandardItem *hiddenRoot = m->invisibleRootItem();
2087 for (int i = 0; i < insertCount; ++i)
2088 items.append(new QStandardItem(list.at(i)));
2089 hiddenRoot->insertRows(index, items);
2090 } else {
2091 d->inserting = true;
2092 if (d->model->insertRows(index, insertCount, d->root)) {
2093 QModelIndex item;
2094 for (int i = 0; i < insertCount; ++i) {
2095 item = d->model->index(i+index, d->modelColumn, d->root);
2096 d->model->setData(item, list.at(i), Qt::EditRole);
2097 }
2098 d->inserting = false;
2099 d->_q_rowsInserted(d->root, index, index + insertCount - 1);
2100 } else {
2101 d->inserting = false;
2102 }
2103 }
2104
2105 int mc = count();
2106 if (mc > d->maxCount)
2107 d->model->removeRows(d->maxCount, mc - d->maxCount, d->root);
2108}
2109
2110/*!
2111 \since 4.4
2112
2113 Inserts a separator item into the combobox at the given \a index.
2114
2115 If the index is equal to or higher than the total number of items, the new item
2116 is appended to the list of existing items. If the index is zero or negative, the
2117 new item is prepended to the list of existing items.
2118
2119 \sa insertItem()
2120*/
2121void QComboBox::insertSeparator(int index)
2122{
2123 Q_D(QComboBox);
2124 int itemCount = count();
2125 index = qBound(0, index, itemCount);
2126 if (index >= d->maxCount)
2127 return;
2128 insertItem(index, QIcon(), QString());
2129 QComboBoxDelegate::setSeparator(d->model, d->model->index(index, 0, d->root));
2130}
2131
2132/*!
2133 Removes the item at the given \a index from the combobox.
2134 This will update the current index if the index is removed.
2135*/
2136void QComboBox::removeItem(int index)
2137{
2138 Q_ASSERT(index >= 0 && index < count());
2139 Q_D(QComboBox);
2140 d->model->removeRows(index, 1, d->root);
2141}
2142
2143/*!
2144 Sets the \a text for the item on the given \a index in the combobox.
2145*/
2146void QComboBox::setItemText(int index, const QString &text)
2147{
2148 Q_D(const QComboBox);
2149 QModelIndex item = d->model->index(index, d->modelColumn, d->root);
2150 if (item.isValid()) {
2151 d->model->setData(item, text, Qt::EditRole);
2152 }
2153}
2154
2155/*!
2156 Sets the \a icon for the item on the given \a index in the combobox.
2157*/
2158void QComboBox::setItemIcon(int index, const QIcon &icon)
2159{
2160 Q_D(const QComboBox);
2161 QModelIndex item = d->model->index(index, d->modelColumn, d->root);
2162 if (item.isValid()) {
2163 d->model->setData(item, icon, Qt::DecorationRole);
2164 }
2165}
2166
2167/*!
2168 Sets the data \a role for the item on the given \a index in the combobox
2169 to the specified \a value.
2170*/
2171void QComboBox::setItemData(int index, const QVariant &value, int role)
2172{
2173 Q_D(const QComboBox);
2174 QModelIndex item = d->model->index(index, d->modelColumn, d->root);
2175 if (item.isValid()) {
2176 d->model->setData(item, value, role);
2177 }
2178}
2179
2180/*!
2181 Returns the list view used for the combobox popup.
2182*/
2183QAbstractItemView *QComboBox::view() const
2184{
2185 Q_D(const QComboBox);
2186 return const_cast<QComboBoxPrivate*>(d)->viewContainer()->itemView();
2187}
2188
2189/*!
2190 Sets the view to be used in the combobox popup to the given \a
2191 itemView. The combobox takes ownership of the view.
2192
2193 Note: If you want to use the convenience views (like QListWidget,
2194 QTableWidget or QTreeWidget), make sure to call setModel() on the
2195 combobox with the convenience widgets model before calling this
2196 function.
2197*/
2198void QComboBox::setView(QAbstractItemView *itemView)
2199{
2200 Q_D(QComboBox);
2201 if (!itemView) {
2202 qWarning("QComboBox::setView: cannot set a 0 view");
2203 return;
2204 }
2205
2206 if (itemView->model() != d->model)
2207 itemView->setModel(d->model);
2208 d->viewContainer()->setItemView(itemView);
2209}
2210
2211/*!
2212 \reimp
2213*/
2214QSize QComboBox::minimumSizeHint() const
2215{
2216 Q_D(const QComboBox);
2217 return d->recomputeSizeHint(d->minimumSizeHint);
2218}
2219
2220/*!
2221 \reimp
2222
2223 This implementation caches the size hint to avoid resizing when
2224 the contents change dynamically. To invalidate the cached value
2225 change the \l sizeAdjustPolicy.
2226*/
2227QSize QComboBox::sizeHint() const
2228{
2229 Q_D(const QComboBox);
2230 return d->recomputeSizeHint(d->sizeHint);
2231}
2232
2233/*!
2234 Displays the list of items in the combobox. If the list is empty
2235 then the no items will be shown.
2236
2237 If you reimplement this function to show a custom pop-up, make
2238 sure you call hidePopup() to reset the internal state.
2239
2240 \sa hidePopup()
2241*/
2242void QComboBox::showPopup()
2243{
2244 Q_D(QComboBox);
2245 if (count() <= 0)
2246 return;
2247
2248#ifdef QT_KEYPAD_NAVIGATION
2249#ifndef QT_NO_COMPLETER
2250 if (QApplication::keypadNavigationEnabled() && d->completer) {
2251 // editable combo box is line edit plus completer
2252 setEditFocus(true);
2253 d->completer->complete(); // show popup
2254 return;
2255 }
2256#endif
2257#endif
2258
2259 QStyle * const style = this->style();
2260
2261 // set current item and select it
2262 view()->selectionModel()->setCurrentIndex(d->currentIndex,
2263 QItemSelectionModel::ClearAndSelect);
2264 QComboBoxPrivateContainer* container = d->viewContainer();
2265 QStyleOptionComboBox opt;
2266 initStyleOption(&opt);
2267 QRect listRect(style->subControlRect(QStyle::CC_ComboBox, &opt,
2268 QStyle::SC_ComboBoxListBoxPopup, this));
2269 QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(this));
2270 QPoint below = mapToGlobal(listRect.bottomLeft());
2271 int belowHeight = screen.bottom() - below.y();
2272 QPoint above = mapToGlobal(listRect.topLeft());
2273 int aboveHeight = above.y() - screen.y();
2274 bool boundToScreen = !window()->testAttribute(Qt::WA_DontShowOnScreen);
2275
2276 const bool usePopup = style->styleHint(QStyle::SH_ComboBox_Popup, &opt, this);
2277 {
2278 int listHeight = 0;
2279 int count = 0;
2280 QStack<QModelIndex> toCheck;
2281 toCheck.push(view()->rootIndex());
2282#ifndef QT_NO_TREEVIEW
2283 QTreeView *treeView = qobject_cast<QTreeView*>(view());
2284 if (treeView && treeView->header() && !treeView->header()->isHidden())
2285 listHeight += treeView->header()->height();
2286#endif
2287 while (!toCheck.isEmpty()) {
2288 QModelIndex parent = toCheck.pop();
2289 for (int i = 0; i < d->model->rowCount(parent); ++i) {
2290 QModelIndex idx = d->model->index(i, d->modelColumn, parent);
2291 if (!idx.isValid())
2292 continue;
2293 listHeight += view()->visualRect(idx).height() + container->spacing();
2294#ifndef QT_NO_TREEVIEW
2295 if (d->model->hasChildren(idx) && treeView && treeView->isExpanded(idx))
2296 toCheck.push(idx);
2297#endif
2298 ++count;
2299 if (!usePopup && count > d->maxVisibleItems) {
2300 toCheck.clear();
2301 break;
2302 }
2303 }
2304 }
2305 listRect.setHeight(listHeight);
2306 }
2307
2308 {
2309 // add the spacing for the grid on the top and the bottom;
2310 int heightMargin = 2*container->spacing();
2311
2312 // add the frame of the container
2313 int marginTop, marginBottom;
2314 container->getContentsMargins(0, &marginTop, 0, &marginBottom);
2315 heightMargin += marginTop + marginBottom;
2316
2317 //add the frame of the view
2318 view()->getContentsMargins(0, &marginTop, 0, &marginBottom);
2319 marginTop += static_cast<QAbstractScrollAreaPrivate *>(QObjectPrivate::get(view()))->top;
2320 marginBottom += static_cast<QAbstractScrollAreaPrivate *>(QObjectPrivate::get(view()))->bottom;
2321 heightMargin += marginTop + marginBottom;
2322
2323 listRect.setHeight(listRect.height() + heightMargin);
2324 }
2325
2326 // Add space for margin at top and bottom if the style wants it.
2327 if (usePopup)
2328 listRect.setHeight(listRect.height() + style->pixelMetric(QStyle::PM_MenuVMargin, &opt, this) * 2);
2329
2330 // Make sure the popup is wide enough to display its contents.
2331 if (usePopup) {
2332 const int diff = d->computeWidthHint() - width();
2333 if (diff > 0)
2334 listRect.setWidth(listRect.width() + diff);
2335 }
2336
2337 //we need to activate the layout to make sure the min/maximum size are set when the widget was not yet show
2338 container->layout()->activate();
2339 //takes account of the minimum/maximum size of the container
2340 listRect.setSize( listRect.size().expandedTo(container->minimumSize())
2341 .boundedTo(container->maximumSize()));
2342
2343 // make sure the widget fits on screen
2344 if (boundToScreen) {
2345 if (listRect.width() > screen.width() )
2346 listRect.setWidth(screen.width());
2347 if (mapToGlobal(listRect.bottomRight()).x() > screen.right()) {
2348 below.setX(screen.x() + screen.width() - listRect.width());
2349 above.setX(screen.x() + screen.width() - listRect.width());
2350 }
2351 if (mapToGlobal(listRect.topLeft()).x() < screen.x() ) {
2352 below.setX(screen.x());
2353 above.setX(screen.x());
2354 }
2355 }
2356
2357 if (usePopup) {
2358 // Position horizontally.
2359 listRect.moveLeft(above.x());
2360
2361 // Position vertically so the curently selected item lines up
2362 // with the combo box.
2363 const QRect currentItemRect = view()->visualRect(view()->currentIndex());
2364 const int offset = listRect.top() - currentItemRect.top();
2365 listRect.moveTop(above.y() + offset - listRect.top());
2366
2367
2368 // Clamp the listRect height and vertical position so we don't expand outside the
2369 // available screen geometry.This may override the vertical position, but it is more
2370 // important to show as much as possible of the popup.
2371 const int height = !boundToScreen ? listRect.height() : qMin(listRect.height(), screen.height());
2372 listRect.setHeight(height);
2373 if (boundToScreen) {
2374 if (listRect.top() < screen.top())
2375 listRect.moveTop(screen.top());
2376 if (listRect.bottom() > screen.bottom())
2377 listRect.moveBottom(screen.bottom());
2378 }
2379 } else if (!boundToScreen || listRect.height() <= belowHeight) {
2380 listRect.moveTopLeft(below);
2381 } else if (listRect.height() <= aboveHeight) {
2382 listRect.moveBottomLeft(above);
2383 } else if (belowHeight >= aboveHeight) {
2384 listRect.setHeight(belowHeight);
2385 listRect.moveTopLeft(below);
2386 } else {
2387 listRect.setHeight(aboveHeight);
2388 listRect.moveBottomLeft(above);
2389 }
2390
2391#ifndef QT_NO_IM
2392 if (QInputContext *qic = inputContext())
2393 qic->reset();
2394#endif
2395 QScrollBar *sb = view()->horizontalScrollBar();
2396 Qt::ScrollBarPolicy policy = view()->horizontalScrollBarPolicy();
2397 bool needHorizontalScrollBar = (policy == Qt::ScrollBarAsNeeded || policy == Qt::ScrollBarAlwaysOn)
2398 && sb->minimum() < sb->maximum();
2399 if (needHorizontalScrollBar) {
2400 listRect.adjust(0, 0, 0, sb->height());
2401 }
2402 container->setGeometry(listRect);
2403
2404 bool updatesEnabled = container->updatesEnabled();
2405#if defined(Q_WS_WIN) && !defined(QT_NO_EFFECTS)
2406 bool scrollDown = (listRect.topLeft() == below);
2407 if (QApplication::isEffectEnabled(Qt::UI_AnimateCombo)
2408 && !style->styleHint(QStyle::SH_ComboBox_Popup, &opt, this) && !window()->testAttribute(Qt::WA_DontShowOnScreen))
2409 qScrollEffect(container, scrollDown ? QEffects::DownScroll : QEffects::UpScroll, 150);
2410#endif
2411 container->setUpdatesEnabled(false);
2412 container->raise();
2413 container->show();
2414 container->updateScrollers();
2415 view()->setFocus();
2416
2417 view()->scrollTo(view()->currentIndex(),
2418 style->styleHint(QStyle::SH_ComboBox_Popup, &opt, this)
2419 ? QAbstractItemView::PositionAtCenter
2420 : QAbstractItemView::EnsureVisible);
2421
2422 container->setUpdatesEnabled(updatesEnabled);
2423 container->update();
2424}
2425
2426/*!
2427 Hides the list of items in the combobox if it is currently visible
2428 and resets the internal state, so that if the custom pop-up was
2429 shown inside the reimplemented showPopup(), then you also need to
2430 reimplement the hidePopup() function to hide your custom pop-up
2431 and call the base class implementation to reset the internal state
2432 whenever your custom pop-up widget is hidden.
2433
2434 \sa showPopup()
2435*/
2436void QComboBox::hidePopup()
2437{
2438 Q_D(QComboBox);
2439 if (d->container && d->container->isVisible()) {
2440#if !defined(QT_NO_EFFECTS)
2441 d->model->blockSignals(true);
2442 d->container->itemView()->blockSignals(true);
2443 d->container->blockSignals(true);
2444 // Flash selected/triggered item (if any).
2445 if (style()->styleHint(QStyle::SH_Menu_FlashTriggeredItem)) {
2446 QItemSelectionModel *selectionModel = view() ? view()->selectionModel() : 0;
2447 if (selectionModel && selectionModel->hasSelection()) {
2448 QEventLoop eventLoop;
2449 const QItemSelection selection = selectionModel->selection();
2450
2451 // Deselect item and wait 60 ms.
2452 selectionModel->select(selection, QItemSelectionModel::Toggle);
2453 QTimer::singleShot(60, &eventLoop, SLOT(quit()));
2454 eventLoop.exec();
2455
2456 // Select item and wait 20 ms.
2457 selectionModel->select(selection, QItemSelectionModel::Toggle);
2458 QTimer::singleShot(20, &eventLoop, SLOT(quit()));
2459 eventLoop.exec();
2460 }
2461 }
2462
2463 // Fade out.
2464 bool needFade = style()->styleHint(QStyle::SH_Menu_FadeOutOnHide);
2465 if (needFade) {
2466#if defined(Q_WS_MAC)
2467 macWindowFade(qt_mac_window_for(d->container));
2468#endif // Q_WS_MAC
2469 // Other platform implementations welcome :-)
2470 }
2471 d->model->blockSignals(false);
2472 d->container->itemView()->blockSignals(false);
2473 d->container->blockSignals(false);
2474
2475 if (!needFade)
2476#endif // QT_NO_EFFECTS
2477 // Fade should implicitly hide as well ;-)
2478 d->container->hide();
2479 }
2480#ifdef QT_KEYPAD_NAVIGATION
2481 if (QApplication::keypadNavigationEnabled() && isEditable() && hasFocus())
2482 setEditFocus(true);
2483#endif
2484 d->_q_resetButton();
2485}
2486
2487/*!
2488 Clears the combobox, removing all items.
2489
2490 Note: If you have set an external model on the combobox this model
2491 will still be cleared when calling this function.
2492*/
2493void QComboBox::clear()
2494{
2495 Q_D(QComboBox);
2496 d->model->removeRows(0, d->model->rowCount(d->root), d->root);
2497}
2498
2499/*!
2500 \fn void QComboBox::clearValidator()
2501
2502 Use setValidator(0) instead.
2503*/
2504
2505/*!
2506 Clears the contents of the line edit used for editing in the combobox.
2507*/
2508void QComboBox::clearEditText()
2509{
2510 Q_D(QComboBox);
2511 if (d->lineEdit)
2512 d->lineEdit->clear();
2513}
2514
2515/*!
2516 Sets the \a text in the combobox's text edit.
2517*/
2518void QComboBox::setEditText(const QString &text)
2519{
2520 Q_D(QComboBox);
2521 if (d->lineEdit)
2522 d->lineEdit->setText(text);
2523}
2524
2525/*!
2526 \reimp
2527*/
2528void QComboBox::focusInEvent(QFocusEvent *e)
2529{
2530 Q_D(QComboBox);
2531 update();
2532 if (d->lineEdit) {
2533 d->lineEdit->event(e);
2534#ifndef QT_NO_COMPLETER
2535 if (d->lineEdit->completer())
2536 d->lineEdit->completer()->setWidget(this);
2537#endif
2538 }
2539}
2540
2541/*!
2542 \reimp
2543*/
2544void QComboBox::focusOutEvent(QFocusEvent *e)
2545{
2546 Q_D(QComboBox);
2547 update();
2548 if (d->lineEdit)
2549 d->lineEdit->event(e);
2550}
2551
2552/*! \reimp */
2553void QComboBox::changeEvent(QEvent *e)
2554{
2555 Q_D(QComboBox);
2556 switch (e->type()) {
2557 case QEvent::StyleChange:
2558 d->updateDelegate();
2559#ifdef Q_WS_MAC
2560 case QEvent::MacSizeChange:
2561#endif
2562 d->sizeHint = QSize(); // invalidate size hint
2563 d->minimumSizeHint = QSize();
2564 d->updateLayoutDirection();
2565 if (d->lineEdit)
2566 d->updateLineEditGeometry();
2567 d->setLayoutItemMargins(QStyle::SE_ComboBoxLayoutItem);
2568 // ### need to update scrollers etc. as well here
2569 break;
2570 case QEvent::EnabledChange:
2571 if (!isEnabled())
2572 hidePopup();
2573 break;
2574 case QEvent::PaletteChange: {
2575 QStyleOptionComboBox opt;
2576 initStyleOption(&opt);
2577#ifndef QT_NO_MENU
2578 if (style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, this)) {
2579 QMenu menu;
2580 menu.ensurePolished();
2581 d->viewContainer()->setPalette(menu.palette());
2582 d->viewContainer()->setWindowOpacity(menu.windowOpacity());
2583 } else
2584#endif
2585 {
2586 d->viewContainer()->setPalette(palette());
2587 d->viewContainer()->setWindowOpacity(1.0);
2588 }
2589 break;
2590 }