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

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

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