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

Last change on this file since 868 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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