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

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

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

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