QComboBox: Use platform theme hint to determine popup geometry.
[profile/ivi/qtbase.git] / tests / auto / widgets / widgets / qcombobox / tst_qcombobox.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QtTest/QtTest>
43
44 #include "qcombobox.h"
45 #include <private/qcombobox_p.h>
46 #include <private/qguiapplication_p.h>
47 #include <qplatformtheme_qpa.h>
48
49 #include <qfontcombobox.h>
50 #include <qdesktopwidget.h>
51 #include <qapplication.h>
52 #include <qpushbutton.h>
53 #include <qdialog.h>
54 #include <qevent.h>
55 #include <qlineedit.h>
56 #include <qlistview.h>
57 #include <qheaderview.h>
58 #include <qlistwidget.h>
59 #include <qtreewidget.h>
60 #include <qtablewidget.h>
61 #include <qscrollbar.h>
62 #include <qboxlayout.h>
63 #ifdef Q_OS_MAC
64 #include <qmacstyle_mac.h>
65 #elif defined Q_WS_X11
66 #include <private/qt_x11_p.h>
67 #endif
68
69 #include <qstandarditemmodel.h>
70 #include <qstringlistmodel.h>
71 #include <qcombobox.h>
72 #include <qpushbutton.h>
73 #include <qdialog.h>
74 #include <qstringlist.h>
75 #include <qvalidator.h>
76 #include <qcompleter.h>
77 #ifndef QT_NO_STYLE_CLEANLOOKS
78 #include <qcleanlooksstyle.h>
79 #endif
80 #include <qabstractitemview.h>
81 #include <qstyleditemdelegate.h>
82 #ifndef QT_NO_STYLE_WINDOWS
83 #include <qwindowsstyle.h>
84 #endif
85
86 class tst_QComboBox : public QObject
87 {
88     Q_OBJECT
89
90 public:
91     tst_QComboBox();
92     ~tst_QComboBox();
93
94 public slots:
95     void initTestCase();
96     void cleanupTestCase();
97     void init();
98     void cleanup();
99
100 private slots:
101     void getSetCheck();
102     void ensureReturnIsIgnored();
103     void setEditable();
104     void setPalette();
105     void sizeAdjustPolicy();
106     void clear();
107     void insertPolicy_data();
108     void insertPolicy();
109     void virtualAutocompletion();
110     void autoCompletionCaseSensitivity();
111     void hide();
112     void currentIndex_data();
113     void currentIndex();
114     void insertItems_data();
115     void insertItems();
116     void insertItem_data();
117     void insertItem();
118     void insertOnCurrentIndex();
119     void textpixmapdata_data();
120     void textpixmapdata();
121     void editTextChanged();
122     void setModel();
123     void modelDeleted();
124     void setMaxCount();
125     void setCurrentIndex();
126     void convenienceViews();
127     void findText_data();
128     void findText();
129     void flaggedItems_data();
130     void flaggedItems();
131     void pixmapIcon();
132     void mouseWheel_data();
133     void mouseWheel();
134     void layoutDirection();
135     void itemListPosition();
136     void separatorItem_data();
137     void separatorItem();
138 #ifndef QT_NO_STYLE_CLEANLOOKS
139     void task190351_layout();
140     void task191329_size();
141 #endif
142     void task166349_setEditableOnReturn();
143     void task190205_setModelAdjustToContents();
144     void task248169_popupWithMinimalSize();
145     void task247863_keyBoardSelection();
146     void task220195_keyBoardSelection2();
147     void setModelColumn();
148     void noScrollbar_data();
149     void noScrollbar();
150     void setItemDelegate();
151     void task253944_itemDelegateIsReset();
152     void subControlRectsWithOffset_data();
153     void subControlRectsWithOffset();
154 #ifndef QT_NO_STYLE_WINDOWS
155     void task260974_menuItemRectangleForComboBoxPopup();
156 #endif
157     void removeItem();
158     void resetModel();
159     void keyBoardNavigationWithMouse();
160     void task_QTBUG_1071_changingFocusEmitsActivated();
161     void maxVisibleItems();
162     void task_QTBUG_10491_currentIndexAndModelColumn();
163
164 protected slots:
165     void onEditTextChanged( const QString &newString );
166
167 private:
168     QComboBox *testWidget;
169     QWidget *parent;
170     QPushButton* ok;
171     int editTextCount;
172     QString editText;
173 };
174
175 class MyAbstractItemDelegate : public QAbstractItemDelegate
176 {
177 public:
178     MyAbstractItemDelegate() : QAbstractItemDelegate() {};
179     void paint(QPainter *, const QStyleOptionViewItem &, const QModelIndex &) const {}
180     QSize sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const { return QSize(); }
181 };
182
183 class MyAbstractItemModel: public QAbstractItemModel
184 {
185 public:
186     MyAbstractItemModel() : QAbstractItemModel() {};
187     QModelIndex index(int, int, const QModelIndex &) const { return QModelIndex(); }
188     QModelIndex parent(const QModelIndex &) const  { return QModelIndex(); }
189     int rowCount(const QModelIndex &) const { return 0; }
190     int columnCount(const QModelIndex &) const { return 0; }
191     bool hasChildren(const QModelIndex &) const { return false; }
192     QVariant data(const QModelIndex &, int) const { return QVariant(); }
193     bool setData(const QModelIndex &, const QVariant &, int) { return false; }
194     bool insertRows(int, int, const QModelIndex &) { return false; }
195     bool insertColumns(int, int, const QModelIndex &) { return false; }
196     void setPersistent(const QModelIndex &, const QModelIndex &) {}
197     bool removeRows (int, int, const QModelIndex &) { return false; }
198     bool removeColumns(int, int, const QModelIndex &) { return false; }
199     void reset() {}
200 };
201
202 class MyAbstractItemView : public QAbstractItemView
203 {
204 public:
205     MyAbstractItemView() : QAbstractItemView() {}
206     QRect visualRect(const QModelIndex &) const { return QRect(); }
207     void scrollTo(const QModelIndex &, ScrollHint) {}
208     QModelIndex indexAt(const QPoint &) const { return QModelIndex(); }
209 protected:
210     QModelIndex moveCursor(CursorAction, Qt::KeyboardModifiers) { return QModelIndex(); }
211     int horizontalOffset() const { return 0; }
212     int verticalOffset() const { return 0; }
213     bool isIndexHidden(const QModelIndex &) const { return false; }
214     void setSelection(const QRect &, QItemSelectionModel::SelectionFlags) {}
215     QRegion visualRegionForSelection(const QItemSelection &) const { return QRegion(); }
216 };
217
218 // Testing get/set functions
219 void tst_QComboBox::getSetCheck()
220 {
221     QComboBox obj1;
222     // int QComboBox::maxVisibleItems()
223     // void QComboBox::setMaxVisibleItems(int)
224     obj1.setMaxVisibleItems(100);
225     QCOMPARE(100, obj1.maxVisibleItems());
226     obj1.setMaxVisibleItems(0);
227     QCOMPARE(obj1.maxVisibleItems(), 0);
228     QTest::ignoreMessage(QtWarningMsg, "QComboBox::setMaxVisibleItems: "
229                          "Invalid max visible items (-2147483648) must be >= 0");
230     obj1.setMaxVisibleItems(INT_MIN);
231     QCOMPARE(obj1.maxVisibleItems(), 0); // Cannot be set to something negative => old value
232     obj1.setMaxVisibleItems(INT_MAX);
233     QCOMPARE(INT_MAX, obj1.maxVisibleItems());
234
235     // int QComboBox::maxCount()
236     // void QComboBox::setMaxCount(int)
237     obj1.setMaxCount(0);
238     QCOMPARE(0, obj1.maxCount());
239 #ifndef QT_DEBUG
240     QTest::ignoreMessage(QtWarningMsg, "QComboBox::setMaxCount: Invalid count (-2147483648) must be >= 0");
241     obj1.setMaxCount(INT_MIN);
242     QCOMPARE(0, obj1.maxCount()); // Setting a value below 0 makes no sense, and shouldn't be allowed
243 #endif
244     obj1.setMaxCount(INT_MAX);
245     QCOMPARE(INT_MAX, obj1.maxCount());
246
247     // bool QComboBox::autoCompletion()
248     // void QComboBox::setAutoCompletion(bool)
249     obj1.setAutoCompletion(false);
250     QCOMPARE(false, obj1.autoCompletion());
251     obj1.setAutoCompletion(true);
252     QCOMPARE(true, obj1.autoCompletion());
253
254     // bool QComboBox::duplicatesEnabled()
255     // void QComboBox::setDuplicatesEnabled(bool)
256     obj1.setDuplicatesEnabled(false);
257     QCOMPARE(false, obj1.duplicatesEnabled());
258     obj1.setDuplicatesEnabled(true);
259     QCOMPARE(true, obj1.duplicatesEnabled());
260
261     // InsertPolicy QComboBox::insertPolicy()
262     // void QComboBox::setInsertPolicy(InsertPolicy)
263     obj1.setInsertPolicy(QComboBox::InsertPolicy(QComboBox::NoInsert));
264     QCOMPARE(QComboBox::InsertPolicy(QComboBox::NoInsert), obj1.insertPolicy());
265     obj1.setInsertPolicy(QComboBox::InsertPolicy(QComboBox::InsertAtTop));
266     QCOMPARE(QComboBox::InsertPolicy(QComboBox::InsertAtTop), obj1.insertPolicy());
267     obj1.setInsertPolicy(QComboBox::InsertPolicy(QComboBox::InsertAtCurrent));
268     QCOMPARE(QComboBox::InsertPolicy(QComboBox::InsertAtCurrent), obj1.insertPolicy());
269     obj1.setInsertPolicy(QComboBox::InsertPolicy(QComboBox::InsertAtBottom));
270     QCOMPARE(QComboBox::InsertPolicy(QComboBox::InsertAtBottom), obj1.insertPolicy());
271     obj1.setInsertPolicy(QComboBox::InsertPolicy(QComboBox::InsertAfterCurrent));
272     QCOMPARE(QComboBox::InsertPolicy(QComboBox::InsertAfterCurrent), obj1.insertPolicy());
273     obj1.setInsertPolicy(QComboBox::InsertPolicy(QComboBox::InsertBeforeCurrent));
274     QCOMPARE(QComboBox::InsertPolicy(QComboBox::InsertBeforeCurrent), obj1.insertPolicy());
275     obj1.setInsertPolicy(QComboBox::InsertPolicy(QComboBox::InsertAlphabetically));
276     QCOMPARE(QComboBox::InsertPolicy(QComboBox::InsertAlphabetically), obj1.insertPolicy());
277
278     // SizeAdjustPolicy QComboBox::sizeAdjustPolicy()
279     // void QComboBox::setSizeAdjustPolicy(SizeAdjustPolicy)
280     obj1.setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy(QComboBox::AdjustToContents));
281     QCOMPARE(QComboBox::SizeAdjustPolicy(QComboBox::AdjustToContents), obj1.sizeAdjustPolicy());
282     obj1.setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow));
283     QCOMPARE(QComboBox::SizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow), obj1.sizeAdjustPolicy());
284     obj1.setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength));
285     QCOMPARE(QComboBox::SizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength), obj1.sizeAdjustPolicy());
286     obj1.setSizeAdjustPolicy(QComboBox::SizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon));
287     QCOMPARE(QComboBox::SizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon), obj1.sizeAdjustPolicy());
288
289     // int QComboBox::minimumContentsLength()
290     // void QComboBox::setMinimumContentsLength(int)
291     obj1.setMinimumContentsLength(0);
292     QCOMPARE(0, obj1.minimumContentsLength());
293     obj1.setMinimumContentsLength(100);
294     QCOMPARE(100, obj1.minimumContentsLength());
295     obj1.setMinimumContentsLength(INT_MIN);
296     QCOMPARE(100, obj1.minimumContentsLength()); // Cannot be set to something negative => old value
297     obj1.setMinimumContentsLength(INT_MAX);
298     QCOMPARE(INT_MAX, obj1.minimumContentsLength());
299
300     // QLineEdit * QComboBox::lineEdit()
301     // void QComboBox::setLineEdit(QLineEdit *)
302     QLineEdit *var8 = new QLineEdit(0);
303     obj1.setLineEdit(var8);
304     QCOMPARE(var8, obj1.lineEdit());
305     QTest::ignoreMessage(QtWarningMsg, "QComboBox::setLineEdit: cannot set a 0 line edit");
306     obj1.setLineEdit((QLineEdit *)0);
307     QCOMPARE(var8, obj1.lineEdit());
308     // delete var8; // No delete, since QComboBox takes ownership
309
310     // const QValidator * QComboBox::validator()
311     // void QComboBox::setValidator(const QValidator *)
312     QIntValidator *var9 = new QIntValidator(0);
313     obj1.setValidator(var9);
314     QCOMPARE(obj1.validator(), (const QValidator *)var9);
315     obj1.setValidator((QValidator *)0);
316     QCOMPARE(obj1.validator(), (const QValidator *)0);
317     delete var9;
318
319     // QAbstractItemDelegate * QComboBox::itemDelegate()
320     // void QComboBox::setItemDelegate(QAbstractItemDelegate *)
321     MyAbstractItemDelegate *var10 = new MyAbstractItemDelegate;
322     obj1.setItemDelegate(var10);
323     QCOMPARE(obj1.itemDelegate(), (QAbstractItemDelegate *)var10);
324     QTest::ignoreMessage(QtWarningMsg, "QComboBox::setItemDelegate: cannot set a 0 delegate");
325     obj1.setItemDelegate((QAbstractItemDelegate *)0);
326     QCOMPARE(obj1.itemDelegate(), (QAbstractItemDelegate *)var10);
327     // delete var10; // No delete, since QComboBox takes ownership
328
329     // QAbstractItemModel * QComboBox::model()
330     // void QComboBox::setModel(QAbstractItemModel *)
331     MyAbstractItemModel *var11 = new MyAbstractItemModel;
332     obj1.setModel(var11);
333     QCOMPARE(obj1.model(), (QAbstractItemModel *)var11);
334     QTest::ignoreMessage(QtWarningMsg, "QComboBox::setModel: cannot set a 0 model");
335     obj1.setModel((QAbstractItemModel *)0);
336     QCOMPARE(obj1.model(), (QAbstractItemModel *)var11);
337     delete var11;
338     obj1.model();
339
340     // int QComboBox::modelColumn()
341     // void QComboBox::setModelColumn(int)
342     obj1.setModelColumn(0);
343     QCOMPARE(0, obj1.modelColumn());
344     obj1.setModelColumn(INT_MIN);
345 //    QCOMPARE(0, obj1.modelColumn()); // Cannot be set to something negative => column 0
346     obj1.setModelColumn(INT_MAX);
347     QCOMPARE(INT_MAX, obj1.modelColumn());
348     obj1.setModelColumn(0); // back to normal
349
350     // QAbstractItemView * QComboBox::view()
351     // void QComboBox::setView(QAbstractItemView *)
352     MyAbstractItemView *var13 = new MyAbstractItemView;
353     obj1.setView(var13);
354     QCOMPARE(obj1.view(), (QAbstractItemView *)var13);
355     QTest::ignoreMessage(QtWarningMsg, "QComboBox::setView: cannot set a 0 view");
356     obj1.setView((QAbstractItemView *)0);
357     QCOMPARE(obj1.view(), (QAbstractItemView *)var13);
358     delete var13;
359
360     // int QComboBox::currentIndex()
361     // void QComboBox::setCurrentIndex(int)
362     obj1.setEditable(false);
363     obj1.setCurrentIndex(0);
364     QCOMPARE(-1, obj1.currentIndex());
365     obj1.setCurrentIndex(INT_MIN);
366     QCOMPARE(-1, obj1.currentIndex());
367     obj1.setCurrentIndex(INT_MAX);
368     QCOMPARE(-1, obj1.currentIndex());
369     obj1.addItems(QStringList() << "1" << "2" << "3" << "4" << "5");
370     obj1.setCurrentIndex(0);
371     QCOMPARE(0, obj1.currentIndex()); // Valid
372     obj1.setCurrentIndex(INT_MIN);
373     QCOMPARE(-1, obj1.currentIndex()); // Invalid => -1
374     obj1.setCurrentIndex(4);
375     QCOMPARE(4, obj1.currentIndex()); // Valid
376     obj1.setCurrentIndex(INT_MAX);
377     QCOMPARE(-1, obj1.currentIndex()); // Invalid => -1
378 }
379
380 typedef QList<QVariant> VariantList;
381 typedef QList<QIcon> IconList;
382
383 Q_DECLARE_METATYPE(VariantList)
384 Q_DECLARE_METATYPE(IconList)
385 Q_DECLARE_METATYPE(QComboBox::InsertPolicy)
386
387 tst_QComboBox::tst_QComboBox()
388 {
389     qRegisterMetaType<QModelIndex>("QModelIndex");
390     parent = 0;
391 }
392
393 tst_QComboBox::~tst_QComboBox()
394 {
395 }
396
397
398 void tst_QComboBox::initTestCase()
399 {
400     // Create the test class
401     parent = new QWidget(0, Qt::Window);
402     parent->setObjectName("parent");
403     parent->resize(400, 400);
404     testWidget = new QComboBox(parent);
405     testWidget->setObjectName("testObject");
406     testWidget->setGeometry(0, 0, 100, 100);
407     editTextCount = 0;
408     editText.clear();
409     connect(testWidget, SIGNAL(editTextChanged(const QString&)),
410             this, SLOT(onEditTextChanged(const QString&)));
411     parent->show();
412 }
413
414 void tst_QComboBox::cleanupTestCase()
415 {
416     delete parent;
417     parent = 0;
418 }
419
420
421 void tst_QComboBox::init()
422 {
423     // all tests starts with a clean non-editable combobox
424     testWidget->setEditable(false);
425     testWidget->clear();
426 #ifdef Q_OS_WINCE //disable magic for WindowsCE
427     qApp->setAutoMaximizeThreshold(-1);
428 #endif
429 }
430
431 void tst_QComboBox::cleanup()
432 {
433     //nothing
434 }
435
436
437 void tst_QComboBox::setEditable()
438 {
439     // make sure we have no lineedit
440     QVERIFY(!testWidget->lineEdit());
441     // test setEditable(true)
442     testWidget->setEditable(true);
443     QVERIFY(testWidget->lineEdit());
444     testWidget->addItem("foo");
445     QCOMPARE(testWidget->lineEdit()->text(), QString("foo"));
446     // test setEditable(false)
447
448     QLineEdit *lineEdit = testWidget->lineEdit();
449     // line edit is visible when combobox is editable
450     QVERIFY(lineEdit->isVisible());
451     testWidget->setEditable(false);
452     QVERIFY(!testWidget->lineEdit());
453     // line edit should have been explicitly hidden when editable was turned off
454     QVERIFY(!lineEdit->isVisible());
455 }
456
457
458 void tst_QComboBox::setPalette()
459 {
460 #ifdef Q_OS_MAC
461     if (qobject_cast<QMacStyle *>(testWidget->style())) {
462         QSKIP("This test doesn't make sense for pixmap-based styles");
463     }
464 #endif
465     QPalette pal = testWidget->palette();
466     pal.setColor(QPalette::Base, Qt::red);
467     testWidget->setPalette(pal);
468     testWidget->setEditable(!testWidget->isEditable());
469
470     pal.setColor(QPalette::Base, Qt::blue);
471     testWidget->setPalette(pal);
472
473     const QObjectList comboChildren = testWidget->children();
474     for (int i = 0; i < comboChildren.size(); ++i) {
475         QObject *o = comboChildren.at(i);
476         if (o->isWidgetType()) {
477             QVERIFY(((QWidget*)o)->palette() == pal);
478         }
479     }
480
481     testWidget->setEditable(true);
482     pal.setColor(QPalette::Base, Qt::red);
483     //Setting it on the lineedit should be separate form the combo
484     testWidget->lineEdit()->setPalette(pal);
485     QVERIFY(testWidget->palette() != pal);
486     QVERIFY(testWidget->lineEdit()->palette() == pal);
487     pal.setColor(QPalette::Base, Qt::green);
488     //Setting it on the combo directly should override lineedit
489     testWidget->setPalette(pal);
490     QVERIFY(testWidget->palette() == pal);
491     QVERIFY(testWidget->lineEdit()->palette() == pal);
492 }
493
494 void tst_QComboBox::sizeAdjustPolicy()
495 {
496     // test that adding new items will not change the sizehint for AdjustToContentsOnFirstShow
497     QVERIFY(!testWidget->count());
498     QVERIFY(testWidget->sizeAdjustPolicy() == QComboBox::AdjustToContentsOnFirstShow);
499     QVERIFY(testWidget->isVisible());
500     QSize firstShow = testWidget->sizeHint();
501     testWidget->addItem("normal item");
502     QCOMPARE(testWidget->sizeHint(), firstShow);
503
504     // check that with minimumContentsLength/AdjustToMinimumContentsLength sizehint changes
505     testWidget->setMinimumContentsLength(30);
506     QCOMPARE(testWidget->sizeHint(), firstShow);
507     testWidget->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
508     QSize minimumContentsLength = testWidget->sizeHint();
509     QVERIFY(minimumContentsLength.width() > firstShow.width());
510     testWidget->setMinimumContentsLength(60);
511     QVERIFY(minimumContentsLength.width() < testWidget->sizeHint().width());
512
513     // check that with minimumContentsLength/AdjustToMinimumContentsLengthWithIcon sizehint changes
514     testWidget->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
515     testWidget->setMinimumContentsLength(30);
516     minimumContentsLength = testWidget->sizeHint();
517     QVERIFY(minimumContentsLength.width() > firstShow.width());
518     testWidget->setMinimumContentsLength(60);
519     QVERIFY(minimumContentsLength.width() < testWidget->sizeHint().width());
520     minimumContentsLength = testWidget->sizeHint();
521     testWidget->setIconSize(QSize(128,128));
522     QVERIFY(minimumContentsLength.width() < testWidget->sizeHint().width());
523
524     // check AdjustToContents changes with content
525     testWidget->setSizeAdjustPolicy(QComboBox::AdjustToContents);
526     QSize content = testWidget->sizeHint();
527     testWidget->addItem("small");
528     QCOMPARE(testWidget->sizeHint(), content);
529     testWidget->addItem("looooooooooooooooooooooong item");
530     // minimumContentsLength() > sizeof("looooooooooooooooooooooong item"), so the sizeHint()
531     // stays the same
532     QCOMPARE(testWidget->sizeHint(), content);
533     // over 60 characters (cf. setMinimumContentsLength() call above)
534     testWidget->addItem("loooooooooooooooooooooooooooooooooooooooooooooo"
535                         "ooooooooooooooooooooooooooooooooooooooooooooooo"
536                         "ooooooooooooooooooooooooooooong item");
537     QVERIFY(testWidget->sizeHint().width() > content.width());
538
539     // check AdjustToContents also shrinks when item changes
540     content = testWidget->sizeHint();
541     for (int i=0; i<testWidget->count(); ++i)
542         testWidget->setItemText(i, "XXXXXXXXXX");
543     QVERIFY(testWidget->sizeHint().width() < content.width());
544
545     // check AdjustToContents shrinks when items are removed
546     content = testWidget->sizeHint();
547     while (testWidget->count())
548         testWidget->removeItem(0);
549     QCOMPARE(testWidget->sizeHint(), content);
550     testWidget->setMinimumContentsLength(0);
551     QVERIFY(testWidget->sizeHint().width() < content.width());
552 }
553
554 void tst_QComboBox::clear()
555 {
556     // first non editable combobox
557     testWidget->addItem("foo");
558     testWidget->addItem("bar");
559     QVERIFY(testWidget->count() > 0);
560     QCOMPARE(testWidget->currentIndex(), 0);
561
562     testWidget->clear();
563     QCOMPARE(testWidget->count(), 0);
564     QCOMPARE(testWidget->currentIndex(), -1);
565     QVERIFY(testWidget->currentText().isEmpty());
566
567     // then editable combobox
568     testWidget->clear();
569     testWidget->setEditable(true);
570     testWidget->addItem("foo");
571     testWidget->addItem("bar");
572     QVERIFY(testWidget->count() > 0);
573     QCOMPARE(testWidget->currentIndex(), 0);
574     QVERIFY(testWidget->lineEdit());
575     QVERIFY(!testWidget->lineEdit()->text().isEmpty());
576     testWidget->clear();
577     QCOMPARE(testWidget->count(), 0);
578     QCOMPARE(testWidget->currentIndex(), -1);
579     QVERIFY(testWidget->currentText().isEmpty());
580     QVERIFY(testWidget->lineEdit()->text().isEmpty());
581 }
582
583 void tst_QComboBox::insertPolicy_data()
584 {
585     QTest::addColumn<QStringList>("initialEntries");
586     QTest::addColumn<QComboBox::InsertPolicy>("insertPolicy");
587     QTest::addColumn<int>("currentIndex");
588     QTest::addColumn<QString>("userInput");
589     QTest::addColumn<QStringList>("result");
590
591     /* Each insertPolicy should test at least:
592        no initial entries
593        one initial entry
594        five initial entries, current is first item
595        five initial entries, current is third item
596        five initial entries, current is last item
597     */
598
599     /* QComboBox::NoInsert - the string will not be inserted into the combobox.
600        QComboBox::InsertAtTop - insert the string as the first item in the combobox.
601        QComboBox::InsertAtCurrent - replace the previously selected item with the string the user has entered.
602        QComboBox::InsertAtBottom - insert the string as the last item in the combobox.
603        QComboBox::InsertAfterCurrent - insert the string after the previously selected item.
604        QComboBox::InsertBeforeCurrent - insert the string before the previously selected item.
605        QComboBox::InsertAlphabetically - insert the string at the alphabetic position.
606     */
607     QStringList initial;
608     QStringList oneEntry("One");
609     QStringList fiveEntries;
610     fiveEntries << "One" << "Two" << "Three" << "Four" << "Five";
611     QString input("insert");
612
613     {
614         QTest::newRow("NoInsert-NoInitial") << initial << QComboBox::NoInsert << 0 << input << initial;
615         QTest::newRow("NoInsert-OneInitial") << oneEntry << QComboBox::NoInsert << 0 << input << oneEntry;
616         QTest::newRow("NoInsert-FiveInitial-FirstCurrent") << fiveEntries << QComboBox::NoInsert << 0 << input << fiveEntries;
617         QTest::newRow("NoInsert-FiveInitial-ThirdCurrent") << fiveEntries << QComboBox::NoInsert << 2 << input << fiveEntries;
618         QTest::newRow("NoInsert-FiveInitial-LastCurrent") << fiveEntries << QComboBox::NoInsert << 4 << input << fiveEntries;
619     }
620
621     {
622         QStringList initialAtTop("insert");
623         QStringList oneAtTop;
624         oneAtTop << "insert" << "One";
625         QStringList fiveAtTop;
626         fiveAtTop << "insert" << "One" << "Two" << "Three" << "Four" << "Five";
627
628         QTest::newRow("AtTop-NoInitial") << initial << QComboBox::InsertAtTop << 0 << input << initialAtTop;
629         QTest::newRow("AtTop-OneInitial") << oneEntry << QComboBox::InsertAtTop << 0 << input << oneAtTop;
630         QTest::newRow("AtTop-FiveInitial-FirstCurrent") << fiveEntries << QComboBox::InsertAtTop << 0 << input << fiveAtTop;
631         QTest::newRow("AtTop-FiveInitial-ThirdCurrent") << fiveEntries << QComboBox::InsertAtTop << 2 << input << fiveAtTop;
632         QTest::newRow("AtTop-FiveInitial-LastCurrent") << fiveEntries << QComboBox::InsertAtTop << 4 << input << fiveAtTop;
633     }
634
635     {
636         QStringList initialAtCurrent("insert");
637         QStringList oneAtCurrent("insert");
638         QStringList fiveAtCurrentFirst;
639         fiveAtCurrentFirst << "insert" << "Two" << "Three" << "Four" << "Five";
640         QStringList fiveAtCurrentThird;
641         fiveAtCurrentThird << "One" << "Two" << "insert" << "Four" << "Five";
642         QStringList fiveAtCurrentLast;
643         fiveAtCurrentLast << "One" << "Two" << "Three" << "Four" << "insert";
644
645         QTest::newRow("AtCurrent-NoInitial") << initial << QComboBox::InsertAtCurrent << 0 << input << initialAtCurrent;
646         QTest::newRow("AtCurrent-OneInitial") << oneEntry << QComboBox::InsertAtCurrent << 0 << input << oneAtCurrent;
647         QTest::newRow("AtCurrent-FiveInitial-FirstCurrent") << fiveEntries << QComboBox::InsertAtCurrent << 0 << input << fiveAtCurrentFirst;
648         QTest::newRow("AtCurrent-FiveInitial-ThirdCurrent") << fiveEntries << QComboBox::InsertAtCurrent << 2 << input << fiveAtCurrentThird;
649         QTest::newRow("AtCurrent-FiveInitial-LastCurrent") << fiveEntries << QComboBox::InsertAtCurrent << 4 << input << fiveAtCurrentLast;
650     }
651
652     {
653         QStringList initialAtBottom("insert");
654         QStringList oneAtBottom;
655         oneAtBottom << "One" << "insert";
656         QStringList fiveAtBottom;
657         fiveAtBottom << "One" << "Two" << "Three" << "Four" << "Five" << "insert";
658
659         QTest::newRow("AtBottom-NoInitial") << initial << QComboBox::InsertAtBottom << 0 << input << initialAtBottom;
660         QTest::newRow("AtBottom-OneInitial") << oneEntry << QComboBox::InsertAtBottom << 0 << input << oneAtBottom;
661         QTest::newRow("AtBottom-FiveInitial-FirstCurrent") << fiveEntries << QComboBox::InsertAtBottom << 0 << input << fiveAtBottom;
662         QTest::newRow("AtBottom-FiveInitial-ThirdCurrent") << fiveEntries << QComboBox::InsertAtBottom << 2 << input << fiveAtBottom;
663         QTest::newRow("AtBottom-FiveInitial-LastCurrent") << fiveEntries << QComboBox::InsertAtBottom << 4 << input << fiveAtBottom;
664     }
665
666     {
667         QStringList initialAfterCurrent("insert");
668         QStringList oneAfterCurrent;
669         oneAfterCurrent << "One" << "insert";
670         QStringList fiveAfterCurrentFirst;
671         fiveAfterCurrentFirst << "One" << "insert" << "Two" << "Three" << "Four" << "Five";
672         QStringList fiveAfterCurrentThird;
673         fiveAfterCurrentThird << "One" << "Two" << "Three" << "insert" << "Four" << "Five";
674         QStringList fiveAfterCurrentLast;
675         fiveAfterCurrentLast << "One" << "Two" << "Three" << "Four" << "Five" << "insert";
676
677         QTest::newRow("AfterCurrent-NoInitial") << initial << QComboBox::InsertAfterCurrent << 0 << input << initialAfterCurrent;
678         QTest::newRow("AfterCurrent-OneInitial") << oneEntry << QComboBox::InsertAfterCurrent << 0 << input << oneAfterCurrent;
679         QTest::newRow("AfterCurrent-FiveInitial-FirstCurrent") << fiveEntries << QComboBox::InsertAfterCurrent << 0 << input << fiveAfterCurrentFirst;
680         QTest::newRow("AfterCurrent-FiveInitial-ThirdCurrent") << fiveEntries << QComboBox::InsertAfterCurrent << 2 << input << fiveAfterCurrentThird;
681         QTest::newRow("AfterCurrent-FiveInitial-LastCurrent") << fiveEntries << QComboBox::InsertAfterCurrent << 4 << input << fiveAfterCurrentLast;
682     }
683
684     {
685         QStringList initialBeforeCurrent("insert");
686         QStringList oneBeforeCurrent;
687         oneBeforeCurrent << "insert" << "One";
688         QStringList fiveBeforeCurrentFirst;
689         fiveBeforeCurrentFirst << "insert" << "One" << "Two" << "Three" << "Four" << "Five";
690         QStringList fiveBeforeCurrentThird;
691         fiveBeforeCurrentThird << "One" << "Two" << "insert" << "Three" << "Four" << "Five";
692         QStringList fiveBeforeCurrentLast;
693         fiveBeforeCurrentLast << "One" << "Two" << "Three" << "Four" << "insert" << "Five";
694
695         QTest::newRow("BeforeCurrent-NoInitial") << initial << QComboBox::InsertBeforeCurrent << 0 << input << initialBeforeCurrent;
696         QTest::newRow("BeforeCurrent-OneInitial") << oneEntry << QComboBox::InsertBeforeCurrent << 0 << input << oneBeforeCurrent;
697         QTest::newRow("BeforeCurrent-FiveInitial-FirstCurrent") << fiveEntries << QComboBox::InsertBeforeCurrent << 0 << input << fiveBeforeCurrentFirst;
698         QTest::newRow("BeforeCurrent-FiveInitial-ThirdCurrent") << fiveEntries << QComboBox::InsertBeforeCurrent << 2 << input << fiveBeforeCurrentThird;
699         QTest::newRow("BeforeCurrent-FiveInitial-LastCurrent") << fiveEntries << QComboBox::InsertBeforeCurrent << 4 << input << fiveBeforeCurrentLast;
700     }
701
702     {
703         oneEntry.clear();
704         oneEntry << "foobar";
705         fiveEntries.clear();
706         fiveEntries << "bar" << "foo" << "initial" << "Item" << "stamp";
707
708         QStringList initialAlphabetically("insert");
709         QStringList oneAlphabetically;
710         oneAlphabetically << "foobar" << "insert";
711         QStringList fiveAlphabetically;
712         fiveAlphabetically << "bar" << "foo" << "initial" << "insert" << "Item" << "stamp";
713
714         QTest::newRow("Alphabetically-NoInitial") << initial << QComboBox::InsertAlphabetically << 0 << input << initialAlphabetically;
715         QTest::newRow("Alphabetically-OneInitial") << oneEntry << QComboBox::InsertAlphabetically << 0 << input << oneAlphabetically;
716         QTest::newRow("Alphabetically-FiveInitial-FirstCurrent") << fiveEntries << QComboBox::InsertAlphabetically << 0 << input << fiveAlphabetically;
717         QTest::newRow("Alphabetically-FiveInitial-ThirdCurrent") << fiveEntries << QComboBox::InsertAlphabetically << 2 << input << fiveAlphabetically;
718         QTest::newRow("Alphabetically-FiveInitial-LastCurrent") << fiveEntries << QComboBox::InsertAlphabetically << 4 << input << fiveAlphabetically;
719     }
720 }
721
722 void tst_QComboBox::insertPolicy()
723 {
724     QFETCH(QStringList, initialEntries);
725     QFETCH(QComboBox::InsertPolicy, insertPolicy);
726     QFETCH(int, currentIndex);
727     QFETCH(QString, userInput);
728     QFETCH(QStringList, result);
729
730     testWidget->clear();
731     testWidget->setInsertPolicy(insertPolicy);
732     testWidget->addItems(initialEntries);
733     testWidget->setEditable(true);
734     if (initialEntries.count() > 0)
735         testWidget->setCurrentIndex(currentIndex);
736
737     // clear
738     QTest::mouseDClick(testWidget->lineEdit(), Qt::LeftButton);
739     QTest::keyClick(testWidget->lineEdit(), Qt::Key_Delete);
740
741     QTest::keyClicks(testWidget->lineEdit(), userInput);
742     QTest::keyClick(testWidget->lineEdit(), Qt::Key_Return);
743
744     // First check that there is the right number of entries, or
745     // we may unwittingly pass
746     QVERIFY((int)result.count() == testWidget->count());
747
748     // No need to compare if there are no strings to compare
749     if (result.count() > 0) {
750         for (int i=0; i<testWidget->count(); ++i) {
751             QCOMPARE(testWidget->itemText(i), result.at(i));
752         }
753     }
754 }
755
756 // Apps running with valgrind are not fast enough.
757 void tst_QComboBox::virtualAutocompletion()
758 {
759     testWidget->clear();
760     testWidget->setAutoCompletion(true);
761     testWidget->addItem("Foo");
762     testWidget->addItem("Bar");
763     testWidget->addItem("Boat");
764     testWidget->addItem("Boost");
765     testWidget->clearEditText();
766
767     // We need to set the keyboard input interval to a higher value
768     // as the processEvent() call takes too much time, so it restarts
769     // the keyboard search then
770 #if defined(Q_PROCESSOR_ARM) || defined(Q_PROCESSOR_MIPS)
771     int oldInterval = QApplication::keyboardInputInterval();
772     QApplication::setKeyboardInputInterval(1500);
773 #endif
774
775     // NOTE:
776     // Cannot use keyClick for this test, as it simulates keyclicks too well
777     // The virtual keyboards we're trying to catch here, do not perform that
778     // well, and send a keypress & keyrelease right after each other.
779     // This provokes the actual error, as there's no events in between to do
780     // the text completion.
781     QKeyEvent kp1(QEvent::KeyPress, Qt::Key_B, 0, "b");
782     QKeyEvent kr1(QEvent::KeyRelease, Qt::Key_B, 0, "b");
783     QApplication::sendEvent(testWidget, &kp1);
784     QApplication::sendEvent(testWidget, &kr1);
785
786     qApp->processEvents(); // Process events to trigger autocompletion
787     QTRY_VERIFY(testWidget->currentIndex() == 1);
788
789     QKeyEvent kp2(QEvent::KeyPress, Qt::Key_O, 0, "o");
790     QKeyEvent kr2(QEvent::KeyRelease, Qt::Key_O, 0, "o");
791
792     QApplication::sendEvent(testWidget, &kp2);
793     QApplication::sendEvent(testWidget, &kr2);
794
795     qApp->processEvents(); // Process events to trigger autocompletion
796     QTRY_COMPARE(testWidget->currentIndex(), 2);
797
798     QApplication::sendEvent(testWidget, &kp2);
799     QApplication::sendEvent(testWidget, &kr2);
800     qApp->processEvents(); // Process events to trigger autocompletion
801     QTRY_COMPARE(testWidget->currentIndex(), 3);
802 #if defined(Q_PROCESSOR_ARM) || defined(Q_PROCESSOR_MIPS)
803     QApplication::setKeyboardInputInterval(oldInterval);
804 #endif
805 }
806
807 void tst_QComboBox::autoCompletionCaseSensitivity()
808 {
809     //we have put the focus because the completer
810     //is only used when the widget actually has the focus
811     testWidget->setFocus();
812     qApp->setActiveWindow(testWidget);
813     QTRY_COMPARE(qApp->focusWidget(), (QWidget *)testWidget);
814
815     testWidget->clear();
816     testWidget->setAutoCompletion(true);
817     testWidget->addItem("Cow");
818     testWidget->addItem("irrelevant1");
819     testWidget->addItem("aww");
820     testWidget->addItem("A*");
821     testWidget->addItem("irrelevant2");
822     testWidget->addItem("aBCDEF");
823     testWidget->addItem("irrelevant3");
824     testWidget->addItem("abcdef");
825     testWidget->addItem("abCdef");
826     testWidget->setEditable(true);
827
828     // case insensitive
829     testWidget->clearEditText();
830     QSignalSpy spyReturn(testWidget, SIGNAL(activated(int)));
831     testWidget->setAutoCompletionCaseSensitivity(Qt::CaseInsensitive);
832     QVERIFY(testWidget->autoCompletionCaseSensitivity() == Qt::CaseInsensitive);
833
834     QTest::keyClick(testWidget->lineEdit(), Qt::Key_A);
835     qApp->processEvents();
836     QCOMPARE(testWidget->currentText(), QString("aww"));
837     QCOMPARE(spyReturn.count(), 0);
838
839     QTest::keyClick(testWidget->lineEdit(), Qt::Key_B);
840     qApp->processEvents();
841     // autocompletions preserve userkey-case from 4.2
842     QCOMPARE(testWidget->currentText(), QString("abCDEF"));
843     QCOMPARE(spyReturn.count(), 0);
844
845     QTest::keyClick(testWidget->lineEdit(), Qt::Key_Enter);
846     qApp->processEvents();
847     QCOMPARE(testWidget->currentText(), QString("aBCDEF")); // case restored to item's case
848     QCOMPARE(spyReturn.count(), 1);
849
850     testWidget->clearEditText();
851     QTest::keyClick(testWidget->lineEdit(), 'c');
852     QCOMPARE(testWidget->currentText(), QString("cow"));
853     QTest::keyClick(testWidget->lineEdit(), Qt::Key_Enter);
854     QCOMPARE(testWidget->currentText(), QString("Cow")); // case restored to item's case
855
856     testWidget->clearEditText();
857     QTest::keyClick(testWidget->lineEdit(), 'a');
858     QTest::keyClick(testWidget->lineEdit(), '*');
859     QCOMPARE(testWidget->currentText(), QString("a*"));
860     QTest::keyClick(testWidget->lineEdit(), Qt::Key_Enter);
861     QCOMPARE(testWidget->currentText(), QString("A*"));
862
863     // case sensitive
864     testWidget->clearEditText();
865     testWidget->setAutoCompletionCaseSensitivity(Qt::CaseSensitive);
866     QVERIFY(testWidget->autoCompletionCaseSensitivity() == Qt::CaseSensitive);
867     QTest::keyClick(testWidget->lineEdit(), Qt::Key_A);
868     qApp->processEvents();
869     QCOMPARE(testWidget->currentText(), QString("aww"));
870     QTest::keyClick(testWidget->lineEdit(), Qt::Key_B);
871     qApp->processEvents();
872     QCOMPARE(testWidget->currentText(), QString("abcdef"));
873
874     testWidget->setCurrentIndex(0); // to reset the completion's "start"
875     testWidget->clearEditText();
876     QTest::keyClick(testWidget->lineEdit(), 'a');
877     QTest::keyClick(testWidget->lineEdit(), 'b');
878     QCOMPARE(testWidget->currentText(), QString("abcdef"));
879     QTest::keyClick(testWidget->lineEdit(), 'C');
880     qApp->processEvents();
881     QCOMPARE(testWidget->currentText(), QString("abCdef"));
882     QTest::keyClick(testWidget->lineEdit(), Qt::Key_Enter);
883     qApp->processEvents();
884     QCOMPARE(testWidget->currentText(), QString("abCdef")); // case restored to item's case
885
886     testWidget->clearEditText();
887     QTest::keyClick(testWidget->lineEdit(), 'c');
888     QCOMPARE(testWidget->currentText(), QString("c"));
889     QTest::keyClick(testWidget->lineEdit(), Qt::Key_Backspace);
890     QTest::keyClick(testWidget->lineEdit(), 'C');
891     QCOMPARE(testWidget->currentText(), QString("Cow"));
892     QTest::keyClick(testWidget->lineEdit(), Qt::Key_Enter);
893     QCOMPARE(testWidget->currentText(), QString("Cow"));
894
895     testWidget->clearEditText();
896     QTest::keyClick(testWidget->lineEdit(), 'a');
897     QTest::keyClick(testWidget->lineEdit(), '*');
898     QCOMPARE(testWidget->currentText(), QString("a*"));
899     QTest::keyClick(testWidget->lineEdit(), Qt::Key_Enter);
900     QCOMPARE(testWidget->currentText(), QString("a*")); // A* not matched
901 }
902
903 void tst_QComboBox::hide()
904 {
905     testWidget->addItem("foo");
906     testWidget->showPopup();
907     //allow combobox effect to complete
908     QTRY_VERIFY(testWidget->view());
909     QTRY_VERIFY(testWidget->view()->isVisible());
910     testWidget->hidePopup();
911     //allow combobox effect to complete
912 #ifdef Q_OS_MAC
913     QEXPECT_FAIL("", "QTBUG-23678", Continue);
914 #endif
915     QTRY_VERIFY(!testWidget->view()->isVisible());
916     testWidget->hide();
917     QVERIFY(!testWidget->isVisible());
918 }
919
920
921
922 void tst_QComboBox::currentIndex_data()
923 {
924     QTest::addColumn<QStringList>("initialItems");
925     QTest::addColumn<int>("setCurrentIndex");
926     QTest::addColumn<int>("removeIndex");
927     QTest::addColumn<int>("insertIndex");
928     QTest::addColumn<QString>("insertText");
929     QTest::addColumn<int>("expectedCurrentIndex");
930     QTest::addColumn<QString>("expectedCurrentText");
931     QTest::addColumn<int>("expectedSignalCount");
932
933     QStringList initialItems;
934     int setCurrentIndex;
935     int removeIndex;
936     int insertIndex;
937     QString insertText;
938     int expectedCurrentIndex;
939     QString expectedCurrentText;
940     int expectedSignalCount;
941
942     {
943         initialItems.clear();
944         initialItems << "foo" << "bar";
945         setCurrentIndex = -2;
946         removeIndex = -1;
947         insertIndex = -1;
948         insertText = "";
949         expectedCurrentIndex = 0;
950         expectedCurrentText = "foo";
951         expectedSignalCount = 1;
952         QTest::newRow("first added item is set to current if there is no current")
953             << initialItems << setCurrentIndex << removeIndex
954             << insertIndex << insertText << expectedCurrentIndex << expectedCurrentText
955             << expectedSignalCount;
956     }
957     {
958         initialItems.clear();
959         initialItems << "foo" << "bar";
960         setCurrentIndex = 1;
961         removeIndex = -1;
962         insertIndex = -1;
963         insertText = "";
964         expectedCurrentIndex = 1;
965         expectedCurrentText = "bar";
966         expectedSignalCount = 2;
967         QTest::newRow("check that setting the index works")
968             << initialItems << setCurrentIndex << removeIndex
969             << insertIndex << insertText << expectedCurrentIndex << expectedCurrentText
970             << expectedSignalCount;
971
972     }
973     {
974         initialItems.clear();
975         initialItems << "foo" << "bar";
976         setCurrentIndex = -1; // will invalidate the currentIndex
977         removeIndex = -1;
978         insertIndex = -1;
979         insertText = "";
980         expectedCurrentIndex = -1;
981         expectedCurrentText = "";
982         expectedSignalCount = 2;
983         QTest::newRow("check that isetting the index to -1 works")
984             << initialItems << setCurrentIndex << removeIndex
985             << insertIndex << insertText << expectedCurrentIndex << expectedCurrentText
986             << expectedSignalCount;
987
988     }
989     {
990         initialItems.clear();
991         initialItems << "foo";
992         setCurrentIndex = 0;
993         removeIndex = 0;
994         insertIndex = -1;
995         insertText = "";
996         expectedCurrentIndex = -1;
997         expectedCurrentText = "";
998         expectedSignalCount = 2;
999         QTest::newRow("check that current index is invalid when removing the only item")
1000             << initialItems << setCurrentIndex << removeIndex
1001             << insertIndex << insertText << expectedCurrentIndex << expectedCurrentText
1002             << expectedSignalCount;
1003     }
1004     {
1005         initialItems.clear();
1006         initialItems << "foo" << "bar";
1007         setCurrentIndex = 1;
1008         removeIndex = 0;
1009         insertIndex = -1;
1010         insertText = "";
1011         expectedCurrentIndex = 0;
1012         expectedCurrentText = "bar";
1013         expectedSignalCount = 3;
1014         QTest::newRow("check that the current index follows the item when removing an item above")
1015             << initialItems << setCurrentIndex << removeIndex
1016             << insertIndex << insertText << expectedCurrentIndex << expectedCurrentText
1017             << expectedSignalCount;
1018
1019     }
1020     {
1021         initialItems.clear();
1022         initialItems << "foo" << "bar" << "baz";
1023         setCurrentIndex = 1;
1024         removeIndex = 1;
1025         insertIndex = -1;
1026         insertText = "";
1027         expectedCurrentIndex = 1;
1028         expectedCurrentText = "baz";
1029         expectedSignalCount = 3;
1030         QTest::newRow("check that the current index uses the next item if current is removed")
1031             << initialItems << setCurrentIndex << removeIndex
1032             << insertIndex << insertText << expectedCurrentIndex << expectedCurrentText
1033             << expectedSignalCount;
1034     }
1035     {
1036         initialItems.clear();
1037         initialItems << "foo" << "bar" << "baz";
1038         setCurrentIndex = 2;
1039         removeIndex = 2;
1040         insertIndex = -1;
1041         insertText = "";
1042         expectedCurrentIndex = 1;
1043         expectedCurrentText = "bar";
1044         expectedSignalCount = 3;
1045         QTest::newRow("check that the current index is moved to the one before if current is removed")
1046             << initialItems << setCurrentIndex << removeIndex
1047             << insertIndex << insertText << expectedCurrentIndex << expectedCurrentText
1048             << expectedSignalCount;
1049     }
1050     {
1051         initialItems.clear();
1052         initialItems << "foo" << "bar" << "baz";
1053         setCurrentIndex = 1;
1054         removeIndex = 2;
1055         insertIndex = -1;
1056         insertText = "";
1057         expectedCurrentIndex = 1;
1058         expectedCurrentText = "bar";
1059         expectedSignalCount = 2;
1060         QTest::newRow("check that the current index is unchanged if you remove an item after")
1061             << initialItems << setCurrentIndex << removeIndex
1062             << insertIndex << insertText << expectedCurrentIndex << expectedCurrentText
1063             << expectedSignalCount;
1064     }
1065     {
1066         initialItems.clear();
1067         initialItems << "foo" << "bar";
1068         setCurrentIndex = 1;
1069         removeIndex = -1;
1070         insertIndex = 0;
1071         insertText = "baz";
1072         expectedCurrentIndex = 2;
1073         expectedCurrentText = "bar";
1074         expectedSignalCount = 3;
1075         QTest::newRow("check that the current index follows the item if you insert before current")
1076             << initialItems << setCurrentIndex << removeIndex
1077             << insertIndex << insertText << expectedCurrentIndex << expectedCurrentText
1078             << expectedSignalCount;
1079     }
1080     {
1081         initialItems.clear();
1082         initialItems << "foo";
1083         setCurrentIndex = 0;
1084         removeIndex = -1;
1085         insertIndex = 0;
1086         insertText = "bar";
1087         expectedCurrentIndex = 1;
1088         expectedCurrentText = "foo";
1089         expectedSignalCount = 2;
1090         QTest::newRow("check that the current index follows the item if you insert on the current")
1091             << initialItems << setCurrentIndex << removeIndex
1092             << insertIndex << insertText << expectedCurrentIndex << expectedCurrentText
1093             << expectedSignalCount;
1094     }
1095     {
1096         initialItems.clear();
1097         initialItems << "foo";
1098         setCurrentIndex = 0;
1099         removeIndex = -1;
1100         insertIndex = 1;
1101         insertText = "bar";
1102         expectedCurrentIndex = 0;
1103         expectedCurrentText = "foo";
1104         expectedSignalCount = 1;
1105         QTest::newRow("check that the current index stays the same if you insert after the current")
1106             << initialItems << setCurrentIndex << removeIndex
1107             << insertIndex << insertText << expectedCurrentIndex << expectedCurrentText
1108             << expectedSignalCount;
1109     }
1110 }
1111
1112 void tst_QComboBox::currentIndex()
1113 {
1114     QFETCH(QStringList, initialItems);
1115     QFETCH(int, setCurrentIndex);
1116     QFETCH(int, removeIndex);
1117     QFETCH(int, insertIndex);
1118     QFETCH(QString, insertText);
1119     QFETCH(int, expectedCurrentIndex);
1120     QFETCH(QString, expectedCurrentText);
1121     QFETCH(int, expectedSignalCount);
1122
1123     // test both editable/non-editable combobox
1124     for (int edit = 0; edit < 2; ++edit) {
1125         testWidget->clear();
1126         testWidget->setEditable(edit ? true : false);
1127         if (edit)
1128             QVERIFY(testWidget->lineEdit());
1129
1130         // verify it is empty, has no current index and no current text
1131         QCOMPARE(testWidget->count(), 0);
1132         QCOMPARE(testWidget->currentIndex(), -1);
1133         QVERIFY(testWidget->currentText().isEmpty());
1134
1135         // spy on currentIndexChanged
1136         QSignalSpy indexChangedInt(testWidget, SIGNAL(currentIndexChanged(int)));
1137         QSignalSpy indexChangedString(testWidget, SIGNAL(currentIndexChanged(const QString&)));
1138
1139         // stuff items into it
1140         foreach(QString text, initialItems) {
1141             testWidget->addItem(text);
1142         }
1143         QCOMPARE(testWidget->count(), initialItems.count());
1144
1145         // set current index, remove and/or insert
1146         if (setCurrentIndex >= -1) {
1147             testWidget->setCurrentIndex(setCurrentIndex);
1148             QCOMPARE(testWidget->currentIndex(), setCurrentIndex);
1149         }
1150
1151         if (removeIndex >= 0)
1152             testWidget->removeItem(removeIndex);
1153         if (insertIndex >= 0)
1154             testWidget->insertItem(insertIndex, insertText);
1155
1156         // compare with expected index and text
1157         QCOMPARE(testWidget->currentIndex(), expectedCurrentIndex);
1158         QCOMPARE(testWidget->currentText(), expectedCurrentText);
1159
1160         // check that signal count is correct
1161         QCOMPARE(indexChangedInt.count(), expectedSignalCount);
1162         QCOMPARE(indexChangedString.count(), expectedSignalCount);
1163
1164         // compare with last sent signal values
1165         if (indexChangedInt.count())
1166             QCOMPARE(indexChangedInt.at(indexChangedInt.count() - 1).at(0).toInt(),
1167                     testWidget->currentIndex());
1168         if (indexChangedString.count())
1169             QCOMPARE(indexChangedString.at(indexChangedString.count() - 1).at(0).toString(),
1170                      testWidget->currentText());
1171
1172         if (edit) {
1173             testWidget->setCurrentIndex(-1);
1174             testWidget->setInsertPolicy(QComboBox::InsertAtBottom);
1175             QTest::keyPress(testWidget, 'a');
1176             QTest::keyPress(testWidget, 'b');
1177             QCOMPARE(testWidget->currentText(), QString("ab"));
1178             QCOMPARE(testWidget->currentIndex(), -1);
1179             int numItems = testWidget->count();
1180             QTest::keyPress(testWidget, Qt::Key_Return);
1181             QCOMPARE(testWidget->count(), numItems + 1);
1182             QCOMPARE(testWidget->currentIndex(), numItems);
1183             testWidget->setCurrentIndex(-1);
1184             QTest::keyPress(testWidget, 'a');
1185             QTest::keyPress(testWidget, 'b');
1186             QCOMPARE(testWidget->currentIndex(), -1);
1187         }
1188     }
1189 }
1190
1191 void tst_QComboBox::insertItems_data()
1192 {
1193     QTest::addColumn<QStringList>("initialItems");
1194     QTest::addColumn<QStringList>("insertedItems");
1195     QTest::addColumn<int>("insertIndex");
1196     QTest::addColumn<int>("expectedIndex");
1197
1198     QStringList initialItems;
1199     QStringList insertedItems;
1200
1201     initialItems << "foo" << "bar";
1202     insertedItems << "mongo";
1203
1204     QTest::newRow("prepend") << initialItems << insertedItems << 0 << 0;
1205     QTest::newRow("prepend with negative value") << initialItems << insertedItems << -1 << 0;
1206     QTest::newRow("append") << initialItems << insertedItems << initialItems.count() << initialItems.count();
1207     QTest::newRow("append with too high value") << initialItems << insertedItems << 999 << initialItems.count();
1208     QTest::newRow("insert") << initialItems << insertedItems << 1 << 1;
1209 }
1210
1211 void tst_QComboBox::insertItems()
1212 {
1213     QFETCH(QStringList, initialItems);
1214     QFETCH(QStringList, insertedItems);
1215     QFETCH(int, insertIndex);
1216     QFETCH(int, expectedIndex);
1217
1218     testWidget->insertItems(0, initialItems);
1219     QCOMPARE(testWidget->count(), initialItems.count());
1220
1221     testWidget->insertItems(insertIndex, insertedItems);
1222
1223     QCOMPARE(testWidget->count(), initialItems.count() + insertedItems.count());
1224     for (int i=0; i<insertedItems.count(); ++i)
1225         QCOMPARE(testWidget->itemText(expectedIndex + i), insertedItems.at(i));
1226 }
1227
1228 void tst_QComboBox::insertItem_data()
1229 {
1230     QTest::addColumn<QStringList>("initialItems");
1231     QTest::addColumn<int>("insertIndex");
1232     QTest::addColumn<QString>("itemLabel");
1233     QTest::addColumn<int>("expectedIndex");
1234     QTest::addColumn<bool>("editable");
1235
1236     QStringList initialItems;
1237     initialItems << "foo" << "bar";
1238     for(int e = 0 ; e<2 ; e++) {
1239         bool editable = (e==0);
1240         QTest::newRow("Insert less then 0") << initialItems << -1 << "inserted" << 0 << editable;
1241         QTest::newRow("Insert at 0") << initialItems << 0 << "inserted" << 0 << editable;
1242         QTest::newRow("Insert beyond count") << initialItems << 3 << "inserted" << 2 << editable;
1243         QTest::newRow("Insert at count") << initialItems << 2 << "inserted" << 2 << editable;
1244         QTest::newRow("Insert in the middle") << initialItems << 1 << "inserted" << 1 << editable;
1245     }
1246 }
1247
1248 void tst_QComboBox::insertItem()
1249 {
1250     QFETCH(QStringList, initialItems);
1251     QFETCH(int, insertIndex);
1252     QFETCH(QString, itemLabel);
1253     QFETCH(int, expectedIndex);
1254     QFETCH(bool, editable);
1255
1256     testWidget->insertItems(0, initialItems);
1257     QCOMPARE(testWidget->count(), initialItems.count());
1258
1259     testWidget->setEditable(true);
1260     if (editable)
1261         testWidget->setEditText("FOO");
1262     testWidget->insertItem(insertIndex, itemLabel);
1263
1264     QCOMPARE(testWidget->count(), initialItems.count() + 1);
1265     QCOMPARE(testWidget->itemText(expectedIndex), itemLabel);
1266
1267     if (editable)
1268         QCOMPARE(testWidget->currentText(), QString("FOO"));
1269 }
1270
1271 void tst_QComboBox::insertOnCurrentIndex()
1272 {
1273     testWidget->setEditable(true);
1274     testWidget->addItem("first item");
1275     testWidget->setCurrentIndex(0);
1276     testWidget->insertItem(0, "second item");
1277     QCOMPARE(testWidget->lineEdit()->text(), QString::fromAscii("first item"));
1278 }
1279
1280 void tst_QComboBox::textpixmapdata_data()
1281 {
1282     QTest::addColumn<QStringList>("text");
1283     QTest::addColumn<IconList>("icons");
1284     QTest::addColumn<VariantList>("variant");
1285
1286     QStringList text;
1287     IconList icon;
1288     VariantList variant;
1289
1290     {
1291         text.clear(); icon.clear(); variant.clear();
1292         text << "foo" << "bar";
1293         icon << QIcon() << QIcon();
1294         variant << QVariant() << QVariant();
1295         QTest::newRow("just text") << text << icon << variant;
1296     }
1297     {
1298         text.clear(); icon.clear(); variant.clear();
1299         text << QString() << QString();
1300         icon << QIcon(QPixmap("qtlogo.png")) << QIcon(QPixmap("qtlogoinverted.png"));
1301         variant << QVariant() << QVariant();
1302         QTest::newRow("just icons") << text << icon << variant;
1303     }
1304     {
1305         text.clear(); icon.clear(); variant.clear();
1306         text << QString() << QString();
1307         icon << QIcon() << QIcon();
1308         variant << 12 << "bingo";
1309         QTest::newRow("just user data") << text << icon << variant;
1310     }
1311     {
1312         text.clear(); icon.clear(); variant.clear();
1313         text << "foo" << "bar";
1314         icon << QIcon(QPixmap("qtlogo.png")) << QIcon(QPixmap("qtlogoinverted.png"));
1315         variant << 12 << "bingo";
1316         QTest::newRow("text, icons and user data") << text << icon << variant;
1317     }
1318 }
1319
1320 void tst_QComboBox::textpixmapdata()
1321 {
1322     QFETCH(QStringList, text);
1323     QFETCH(IconList, icons);
1324     QFETCH(VariantList, variant);
1325
1326     QVERIFY(text.count() == icons.count() && text.count() == variant.count());
1327
1328     for (int i = 0; i<text.count(); ++i) {
1329         testWidget->insertItem(i, text.at(i));
1330         testWidget->setItemIcon(i, icons.at(i));
1331         testWidget->setItemData(i, variant.at(i), Qt::UserRole);
1332     }
1333
1334     QCOMPARE(testWidget->count(), text.count());
1335
1336     for (int i = 0; i<text.count(); ++i) {
1337         QIcon icon = testWidget->itemIcon(i);
1338         QVERIFY(icon.serialNumber() == icons.at(i).serialNumber());
1339         QPixmap original = icons.at(i).pixmap(1024);
1340         QPixmap pixmap = icon.pixmap(1024);
1341         QVERIFY(pixmap.toImage() == original.toImage());
1342     }
1343
1344     for (int i = 0; i<text.count(); ++i) {
1345         QCOMPARE(testWidget->itemText(i), text.at(i));
1346         // ### we should test icons/pixmap as well, but I need to fix the api mismatch first
1347         QCOMPARE(testWidget->itemData(i, Qt::UserRole), variant.at(i));
1348     }
1349 }
1350
1351 void tst_QComboBox::setCurrentIndex()
1352 {
1353     QCOMPARE(testWidget->count(), 0);
1354     testWidget->addItem("foo");
1355     testWidget->addItem("bar");
1356     QCOMPARE(testWidget->count(), 2);
1357
1358     QCOMPARE(testWidget->currentIndex(), 0);
1359     testWidget->setCurrentIndex(0);
1360     QCOMPARE(testWidget->currentText(), QString("foo"));
1361
1362     testWidget->setCurrentIndex(1);
1363     QCOMPARE(testWidget->currentText(), QString("bar"));
1364
1365     testWidget->setCurrentIndex(0);
1366     QCOMPARE(testWidget->currentText(), QString("foo"));
1367 }
1368
1369 void tst_QComboBox::editTextChanged()
1370 {
1371     QCOMPARE(testWidget->count(), 0);
1372     testWidget->addItem("foo");
1373     testWidget->addItem("bar");
1374     QCOMPARE(testWidget->count(), 2);
1375
1376     // first we test non editable
1377     testWidget->setEditable(false);
1378     QCOMPARE(testWidget->isEditable(), false);
1379
1380     // no signal should be sent when current is set to the same
1381     QCOMPARE(testWidget->currentIndex(), 0);
1382     editTextCount = 0;
1383     editText.clear();
1384     testWidget->setCurrentIndex(0);
1385     QCOMPARE(testWidget->currentIndex(), 0);
1386     QCOMPARE(editTextCount, 0);
1387     QCOMPARE(editText.isEmpty(), true);
1388
1389     // no signal should be sent when changing to other index because we are not editable
1390     QCOMPARE(testWidget->currentIndex(), 0);
1391     editTextCount = 0;
1392     editText.clear();
1393     testWidget->setCurrentIndex(1);
1394     QCOMPARE(testWidget->currentIndex(), 1);
1395     QCOMPARE(editTextCount, 0);
1396     QCOMPARE(editText.isEmpty(), true);
1397
1398     // now set to editable and reset current index
1399     testWidget->setEditable(true);
1400     QCOMPARE(testWidget->isEditable(), true);
1401     testWidget->setCurrentIndex(0);
1402
1403     // no signal should be sent when current is set to the same
1404     QCOMPARE(testWidget->currentIndex(), 0);
1405     editTextCount = 0;
1406     editText.clear();
1407     testWidget->setCurrentIndex(0);
1408     QCOMPARE(testWidget->currentIndex(), 0);
1409     QCOMPARE(editTextCount, 0);
1410     QCOMPARE(editText.isEmpty(), true);
1411
1412     // signal should be sent when changing to other index
1413     QCOMPARE(testWidget->currentIndex(), 0);
1414     editTextCount = 0;
1415     editText.clear();
1416     testWidget->setCurrentIndex(1);
1417     QCOMPARE(testWidget->currentIndex(), 1);
1418     QCOMPARE(editTextCount, 1);
1419     QCOMPARE(editText, QString("bar"));
1420
1421     // insert some keys and notice they are all signaled
1422     editTextCount = 0;
1423     editText.clear();
1424     QTest::keyClicks(testWidget, "bingo");
1425     QCOMPARE(editTextCount, 5);
1426     QCOMPARE(editText, QString("barbingo"));
1427 }
1428
1429 void tst_QComboBox::onEditTextChanged(const QString &text)
1430 {
1431     editTextCount++;
1432     editText = text;
1433 }
1434
1435 void tst_QComboBox::setModel()
1436 {
1437     QComboBox box;
1438     QCOMPARE(box.currentIndex(), -1);
1439     box.addItems((QStringList() << "foo" << "bar"));
1440     QCOMPARE(box.currentIndex(), 0);
1441     box.setCurrentIndex(1);
1442     QCOMPARE(box.currentIndex(), 1);
1443
1444     // check that currentIndex is set to invalid
1445     QAbstractItemModel *oldModel = box.model();
1446     box.setModel(new QStandardItemModel(&box));
1447     QCOMPARE(box.currentIndex(), -1);
1448     QVERIFY(box.model() != oldModel);
1449
1450     // check that currentIndex is set to first item
1451     oldModel = box.model();
1452     box.setModel(new QStandardItemModel(2,1, &box));
1453     QCOMPARE(box.currentIndex(), 0);
1454     QVERIFY(box.model() != oldModel);
1455 }
1456
1457 void tst_QComboBox::modelDeleted()
1458 {
1459     QComboBox box;
1460     QStandardItemModel *model = new QStandardItemModel;
1461     box.setModel(model);
1462     QCOMPARE(box.model(), static_cast<QAbstractItemModel *>(model));
1463     delete model;
1464     QVERIFY(box.model());
1465     QCOMPARE(box.findText("bubu"), -1);
1466
1467     delete box.model();
1468     QVERIFY(box.model());
1469     delete box.model();
1470     QVERIFY(box.model());
1471 }
1472
1473 void tst_QComboBox::setMaxCount()
1474 {
1475     QStringList items;
1476     items << "1" << "2" << "3" << "4" << "5";
1477
1478     QComboBox box;
1479     box.addItems(items);
1480     QCOMPARE(box.count(), 5);
1481
1482     box.setMaxCount(4);
1483     QCOMPARE(box.count(), 4);
1484     QCOMPARE(box.itemText(0), QString("1"));
1485     QCOMPARE(box.itemText(1), QString("2"));
1486     QCOMPARE(box.itemText(2), QString("3"));
1487     QCOMPARE(box.itemText(3), QString("4"));
1488
1489     // appending should do nothing
1490     box.addItem("foo");
1491     QCOMPARE(box.count(), 4);
1492     QCOMPARE(box.findText("foo"), -1);
1493
1494     // inserting one item at top should remove the last
1495     box.insertItem(0, "0");
1496     QCOMPARE(box.count(), 4);
1497     QCOMPARE(box.itemText(0), QString("0"));
1498     QCOMPARE(box.itemText(1), QString("1"));
1499     QCOMPARE(box.itemText(2), QString("2"));
1500     QCOMPARE(box.itemText(3), QString("3"));
1501
1502     // insert 5 items in a box with maxCount 4
1503     box.insertItems(0, items);
1504     QCOMPARE(box.count(), 4);
1505     QCOMPARE(box.itemText(0), QString("1"));
1506     QCOMPARE(box.itemText(1), QString("2"));
1507     QCOMPARE(box.itemText(2), QString("3"));
1508     QCOMPARE(box.itemText(3), QString("4"));
1509
1510     // insert 5 items at pos 2. Make sure only two get inserted
1511     QSignalSpy spy(box.model(), SIGNAL(rowsInserted(QModelIndex,int,int)));
1512     box.insertItems(2, items);
1513     QCOMPARE(spy.count(), 1);
1514     QCOMPARE(spy.at(0).at(1).toInt(), 2);
1515     QCOMPARE(spy.at(0).at(2).toInt(), 3);
1516
1517     QCOMPARE(box.count(), 4);
1518     QCOMPARE(box.itemText(0), QString("1"));
1519     QCOMPARE(box.itemText(1), QString("2"));
1520     QCOMPARE(box.itemText(2), QString("1"));
1521     QCOMPARE(box.itemText(3), QString("2"));
1522
1523     box.insertItems(0, QStringList());
1524     QCOMPARE(box.count(), 4);
1525
1526     box.setMaxCount(0);
1527     QCOMPARE(box.count(), 0);
1528     box.addItem("foo");
1529     QCOMPARE(box.count(), 0);
1530     box.addItems(items);
1531     QCOMPARE(box.count(), 0);
1532 }
1533
1534 void tst_QComboBox::convenienceViews()
1535 {
1536     // QListWidget
1537     QComboBox listCombo;
1538     QListWidget *list = new QListWidget();
1539     listCombo.setModel(list->model());
1540     listCombo.setView(list);
1541     // add items
1542     list->addItem("list0");
1543     listCombo.addItem("list1");
1544     QCOMPARE(listCombo.count(), 2);
1545     QCOMPARE(listCombo.itemText(0), QString("list0"));
1546     QCOMPARE(listCombo.itemText(1), QString("list1"));
1547
1548     // QTreeWidget
1549     QComboBox treeCombo;
1550     QTreeWidget *tree = new QTreeWidget();
1551     tree->setColumnCount(1);
1552     tree->header()->hide();
1553     treeCombo.setModel(tree->model());
1554     treeCombo.setView(tree);
1555     // add items
1556     tree->addTopLevelItem(new QTreeWidgetItem(QStringList("tree0")));
1557     treeCombo.addItem("tree1");
1558     QCOMPARE(treeCombo.count(), 2);
1559     QCOMPARE(treeCombo.itemText(0), QString("tree0"));
1560     QCOMPARE(treeCombo.itemText(1), QString("tree1"));
1561
1562     // QTableWidget
1563     QComboBox tableCombo;
1564     QTableWidget *table = new QTableWidget(0,1);
1565     table->verticalHeader()->hide();
1566     table->horizontalHeader()->hide();
1567     tableCombo.setModel(table->model());
1568     tableCombo.setView(table);
1569     // add items
1570     table->setRowCount(table->rowCount() + 1);
1571     table->setItem(0, table->rowCount() - 1, new QTableWidgetItem("table0"));
1572     tableCombo.addItem("table1");
1573     QCOMPARE(tableCombo.count(), 2);
1574     QCOMPARE(tableCombo.itemText(0), QString("table0"));
1575     QCOMPARE(tableCombo.itemText(1), QString("table1"));
1576 }
1577
1578 class ReturnClass : public QWidget
1579 {
1580     Q_OBJECT
1581 public:
1582     ReturnClass(QWidget *parent = 0)
1583         : QWidget(parent), received(false)
1584     {
1585         QComboBox *box = new QComboBox(this);
1586         box->setEditable(true);
1587         edit = box->lineEdit();
1588         box->setGeometry(rect());
1589     }
1590
1591     void keyPressEvent(QKeyEvent *e)
1592     {
1593         received = (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter);
1594     }
1595
1596     QLineEdit *edit;
1597
1598     bool received;
1599
1600 };
1601
1602
1603
1604 void tst_QComboBox::ensureReturnIsIgnored()
1605 {
1606     ReturnClass r;
1607     r.show();
1608
1609     QTest::keyClick(r.edit, Qt::Key_Return);
1610     QVERIFY(r.received);
1611     r.received = false;
1612     QTest::keyClick(r.edit, Qt::Key_Enter);
1613     QVERIFY(r.received);
1614 }
1615
1616
1617 void tst_QComboBox::findText_data()
1618 {
1619     QTest::addColumn<QStringList>("items");
1620     QTest::addColumn<int>("matchflags");
1621     QTest::addColumn<QString>("search");
1622     QTest::addColumn<int>("result");
1623
1624     QStringList list;
1625     list << "One" << "Two" << "Three" << "Four" << "Five" << "Six" << "one";
1626     QTest::newRow("CaseSensitive_1") << list << (int)(Qt::MatchExactly|Qt::MatchCaseSensitive)
1627                                      << QString("Two") << 1;
1628     QTest::newRow("CaseSensitive_2") << list << (int)(Qt::MatchExactly|Qt::MatchCaseSensitive)
1629                                      << QString("two") << -1;
1630     QTest::newRow("CaseSensitive_3") << list << (int)(Qt::MatchExactly|Qt::MatchCaseSensitive)
1631                                      << QString("One") << 0;
1632     QTest::newRow("CaseSensitive_4") << list << (int)(Qt::MatchExactly|Qt::MatchCaseSensitive)
1633                                      << QString("one") << 6;
1634     QTest::newRow("CaseInsensitive_1") << list << (int)(Qt::MatchExactly) << QString("Two") << 1;
1635     QTest::newRow("CaseInsensitive_2") << list << (int)(Qt::MatchExactly) << QString("two") << -1;
1636     QTest::newRow("CaseInsensitive_3") << list << (int)(Qt::MatchExactly) << QString("One") << 0;
1637     QTest::newRow("CaseInsensitive_4") << list << (int)(Qt::MatchExactly) << QString("one") << 6;
1638 }
1639 void tst_QComboBox::findText()
1640 {
1641     QFETCH(QStringList, items);
1642     QFETCH(int, matchflags);
1643     QFETCH(QString, search);
1644     QFETCH(int, result);
1645
1646     testWidget->clear();
1647     testWidget->addItems(items);
1648
1649     QCOMPARE(testWidget->findText(search, (Qt::MatchFlags)matchflags), result);
1650 }
1651
1652 typedef QList<int> IntList;
1653 typedef QList<Qt::Key> KeyList;
1654 Q_DECLARE_METATYPE(IntList)
1655 Q_DECLARE_METATYPE(KeyList)
1656
1657 void tst_QComboBox::flaggedItems_data()
1658 {
1659     QTest::addColumn<QStringList>("itemList");
1660     QTest::addColumn<IntList>("deselectFlagList");
1661     QTest::addColumn<IntList>("disableFlagList");
1662     QTest::addColumn<KeyList>("keyMovementList");
1663     QTest::addColumn<bool>("editable");
1664     QTest::addColumn<int>("expectedIndex");
1665
1666     for (int editable=0;editable<2;editable++) {
1667         QString testCase = editable ? "editable:" : "non-editable:";
1668         QStringList itemList;
1669         itemList << "One" << "Two" << "Three" << "Four" << "Five" << "Six" << "Seven" << "Eight";
1670         IntList deselectFlagList;
1671         IntList disableFlagList;
1672         KeyList keyMovementList;
1673
1674         keyMovementList << Qt::Key_Down << Qt::Key_Down << Qt::Key_Down << Qt::Key_Down;
1675         QTest::newRow(testCase.toAscii() + "normal") << itemList << deselectFlagList << disableFlagList << keyMovementList << bool(editable) << 4;
1676
1677         deselectFlagList.clear();
1678         disableFlagList.clear();
1679         deselectFlagList << 1 << 3;
1680         QTest::newRow(testCase.toAscii() + "non-selectable") << itemList << deselectFlagList << disableFlagList << keyMovementList << bool(editable) << 4;
1681
1682         deselectFlagList.clear();
1683         disableFlagList.clear();
1684         disableFlagList << 2;
1685         QTest::newRow(testCase.toAscii() + "disabled") << itemList << deselectFlagList << disableFlagList << keyMovementList << bool(editable) << 5;
1686
1687         deselectFlagList.clear();
1688         disableFlagList.clear();
1689         deselectFlagList << 1 << 3;
1690         disableFlagList << 2 << 3;
1691         QTest::newRow(testCase.toAscii() + "mixed") << itemList << deselectFlagList << disableFlagList << keyMovementList << bool(editable) << 6;
1692         deselectFlagList.clear();
1693         disableFlagList.clear();
1694         disableFlagList << 0 << 1 << 2 << 3 << 4 << 5 << 6;
1695         QTest::newRow(testCase.toAscii() + "nearly-empty") << itemList << deselectFlagList << disableFlagList << keyMovementList << bool(editable) << 7;
1696
1697         deselectFlagList.clear();
1698         disableFlagList.clear();
1699         disableFlagList << 0 << 1 << 2 << 3 << 5 << 6 << 7;
1700         keyMovementList.clear();
1701         QTest::newRow(testCase.toAscii() + "only one enabled") << itemList << deselectFlagList << disableFlagList << keyMovementList << bool(editable) << 4;
1702
1703         if (!editable) {
1704             deselectFlagList.clear();
1705             disableFlagList.clear();
1706             keyMovementList.clear();
1707             disableFlagList << 0 << 2 << 3;
1708             keyMovementList << Qt::Key_Down << Qt::Key_Home;
1709             QTest::newRow(testCase.toAscii() + "home-disabled") << itemList << deselectFlagList << disableFlagList << keyMovementList << bool(editable) << 1;
1710
1711             keyMovementList.clear();
1712             keyMovementList << Qt::Key_End;
1713             QTest::newRow(testCase.toAscii() + "end-key") << itemList << deselectFlagList << disableFlagList << keyMovementList << bool(editable) << 7;
1714
1715             disableFlagList.clear();
1716             disableFlagList << 1 ;
1717             keyMovementList << Qt::Key_T;
1718             QTest::newRow(testCase.toAscii() + "keyboard-search") << itemList << deselectFlagList << disableFlagList << keyMovementList << bool(editable) << 2;
1719
1720             itemList << "nine" << "ten";
1721             keyMovementList << Qt::Key_T;
1722             QTest::newRow(testCase.toAscii() + "search same start letter") << itemList << deselectFlagList << disableFlagList << keyMovementList << bool(editable) << 9;
1723
1724             keyMovementList.clear();
1725             keyMovementList << Qt::Key_T << Qt::Key_H;
1726             QTest::newRow(testCase.toAscii() + "keyboard search item") << itemList << deselectFlagList << disableFlagList << keyMovementList << bool(editable) << 2;
1727
1728             disableFlagList.clear();
1729             disableFlagList << 1 << 3 << 5 << 7 << 9;
1730             keyMovementList.clear();
1731             keyMovementList << Qt::Key_End << Qt::Key_Up << Qt::Key_Up << Qt::Key_PageDown << Qt::Key_PageUp << Qt::Key_PageUp << Qt::Key_Down;
1732             QTest::newRow(testCase.toAscii() + "all key combinations") << itemList << deselectFlagList << disableFlagList << keyMovementList << bool(editable) << 4;
1733         } else {
1734             deselectFlagList.clear();
1735             disableFlagList.clear();
1736             disableFlagList << 1;
1737             keyMovementList.clear();
1738             keyMovementList << Qt::Key_T << Qt::Key_Enter;
1739             QTest::newRow(testCase.toAscii() + "disabled") << itemList << deselectFlagList << disableFlagList << keyMovementList << bool(editable) << 2;
1740             QTest::newRow(testCase.toAscii() + "broken autocompletion") << itemList << deselectFlagList << disableFlagList << keyMovementList << bool(editable) << 2;
1741         }
1742     }
1743 }
1744
1745 void tst_QComboBox::flaggedItems()
1746 {
1747     QFETCH(QStringList, itemList);
1748     QFETCH(IntList, deselectFlagList);
1749     QFETCH(IntList, disableFlagList);
1750     QFETCH(KeyList, keyMovementList);
1751     QFETCH(bool, editable);
1752     QFETCH(int, expectedIndex);
1753
1754     QComboBox comboBox;
1755     QListWidget listWidget;
1756     listWidget.addItems(itemList);
1757
1758     comboBox.setEditable(editable);
1759     foreach (int index, deselectFlagList)
1760         listWidget.item(index)->setFlags(listWidget.item(index)->flags() & ~Qt::ItemIsSelectable);
1761
1762     foreach (int index, disableFlagList)
1763         listWidget.item(index)->setFlags(listWidget.item(index)->flags() & ~Qt::ItemIsEnabled);
1764
1765     comboBox.setModel(listWidget.model());
1766     comboBox.setView(&listWidget);
1767     comboBox.show();
1768     QApplication::setActiveWindow(&comboBox);
1769     comboBox.activateWindow();
1770     comboBox.setFocus();
1771     QTRY_VERIFY(comboBox.isVisible());
1772     QTRY_VERIFY(comboBox.hasFocus());
1773
1774     if (editable)
1775         comboBox.lineEdit()->selectAll();
1776
1777     QSignalSpy indexChangedInt(&comboBox, SIGNAL(currentIndexChanged(int)));
1778     for (int i = 0; i < keyMovementList.count(); ++i) {
1779         Qt::Key key = keyMovementList[i];
1780         QTest::keyClick(&comboBox, key);
1781         if (indexChangedInt.count() != i + 1) {
1782             QTest::qWait(400);
1783         }
1784     }
1785
1786     QCOMPARE(comboBox.currentIndex() , expectedIndex);
1787 }
1788
1789 void tst_QComboBox::pixmapIcon()
1790 {
1791     QComboBox box;
1792     QStandardItemModel *model = new QStandardItemModel(2, 1, &box);
1793
1794     QPixmap pix(10, 10);
1795     pix.fill(Qt::red);
1796     model->setData(model->index(0, 0), "Element 1");
1797     model->setData(model->index(0, 0), pix, Qt::DecorationRole);
1798
1799     QIcon icon(pix);
1800     model->setData(model->index(1, 0), "Element 2");
1801     model->setData(model->index(1, 0), icon, Qt::DecorationRole);
1802
1803     box.setModel(model);
1804
1805     QCOMPARE( box.itemIcon(0).isNull(), false );
1806     QCOMPARE( box.itemIcon(1).isNull(), false );
1807 }
1808
1809 // defined to be 120 by the wheel mouse vendors according to the docs
1810 #define WHEEL_DELTA 120
1811
1812 void tst_QComboBox::mouseWheel_data()
1813 {
1814     QTest::addColumn<IntList>("disabledItems");
1815     QTest::addColumn<int>("startIndex");
1816     QTest::addColumn<int>("wheelDirection");
1817     QTest::addColumn<int>("expectedIndex");
1818
1819     IntList disabled;
1820     disabled << 0 << 1 << 2 << 4;
1821     int start = 3;
1822     int wheel = 1;
1823     int expected = 3;
1824     QTest::newRow("upper locked") << disabled << start << wheel << expected;
1825
1826     wheel = -1;
1827     expected = 5;
1828     QTest::newRow("jump over") << disabled << start << wheel << expected;
1829
1830     disabled.clear();
1831     disabled << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9;
1832     start = 0;
1833     wheel = -1;
1834     expected = 0;
1835     QTest::newRow("single Item enabled") << disabled << start << wheel << expected;
1836 }
1837
1838 void tst_QComboBox::mouseWheel()
1839 {
1840     QFETCH(IntList, disabledItems);
1841     QFETCH(int, startIndex);
1842     QFETCH(int, wheelDirection);
1843     QFETCH(int, expectedIndex);
1844
1845     QCoreApplication *applicationInstance = QCoreApplication::instance();
1846     QVERIFY(applicationInstance != 0);
1847
1848     QComboBox box;
1849     QStringList list;
1850     list << "one" << "two" << "three" << "four" << "five" << "six" << "seven" << "eight" << "nine" << "ten";
1851
1852     QListWidget listWidget;
1853     listWidget.addItems(list);
1854
1855     foreach (int index, disabledItems)
1856         listWidget.item(index)->setFlags(listWidget.item(index)->flags() & ~Qt::ItemIsEnabled);
1857
1858     box.setModel(listWidget.model());
1859     box.setView(&listWidget);
1860     for (int i=0; i < 2; ++i) {
1861         box.setEditable(i==0?false:true);
1862         box.setCurrentIndex(startIndex);
1863
1864         QWheelEvent event = QWheelEvent(box.rect().bottomRight() , WHEEL_DELTA * wheelDirection, Qt::NoButton, Qt::NoModifier);
1865         QVERIFY(applicationInstance->sendEvent(&box,&event));
1866
1867         QCOMPARE(box.currentIndex(), expectedIndex);
1868     }
1869 }
1870
1871 void tst_QComboBox::layoutDirection()
1872 {
1873     QComboBox box;
1874     Qt::LayoutDirection dir;
1875     QLineEdit *lineEdit;
1876
1877     // RTL
1878     box.setLayoutDirection(Qt::RightToLeft);
1879     QStyleOptionComboBox opt;
1880     opt.direction = Qt::RightToLeft;
1881     dir = (Qt::LayoutDirection)box.style()->styleHint(QStyle::SH_ComboBox_LayoutDirection, &opt, &box);
1882
1883     QCOMPARE(box.view()->layoutDirection(), dir);
1884     box.setEditable(true);
1885     QCOMPARE(box.lineEdit()->layoutDirection(), dir);
1886     lineEdit = new QLineEdit;
1887     QCOMPARE(lineEdit->layoutDirection(), qApp->layoutDirection());
1888     box.setLineEdit(lineEdit);
1889     QCOMPARE(lineEdit->layoutDirection(), dir);
1890
1891     // LTR
1892     box.setLayoutDirection(Qt::LeftToRight);
1893     qApp->setLayoutDirection(Qt::RightToLeft);
1894
1895     opt.direction = Qt::LeftToRight;
1896     dir = (Qt::LayoutDirection)box.style()->styleHint(QStyle::SH_ComboBox_LayoutDirection, &opt, &box);
1897
1898     QCOMPARE(box.view()->layoutDirection(), dir);
1899     box.setEditable(true);
1900     QCOMPARE(box.lineEdit()->layoutDirection(), dir);
1901     lineEdit = new QLineEdit;
1902     QCOMPARE(lineEdit->layoutDirection(), qApp->layoutDirection());
1903     box.setLineEdit(lineEdit);
1904     QCOMPARE(lineEdit->layoutDirection(), dir);
1905
1906 }
1907
1908 void tst_QComboBox::itemListPosition()
1909 {
1910     //tests that the list is not out of the screen boundaries
1911
1912     //put the QApplication layout back
1913     QApplication::setLayoutDirection(Qt::LeftToRight);
1914
1915     //we test QFontComboBox because it has the specific behaviour to set a fixed size
1916     //to the list view
1917     QWidget topLevel;
1918     QFontComboBox combo(&topLevel);
1919
1920     //the code to get the available screen space is copied from QComboBox code
1921     const int scrNumber = QApplication::desktop()->screenNumber(&combo);
1922
1923     bool useFullScreenForPopupMenu = false;
1924     if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
1925         useFullScreenForPopupMenu = theme->themeHint(QPlatformTheme::UseFullScreenForPopupMenu).toBool();
1926     const QRect screen = useFullScreenForPopupMenu ?
1927                          QApplication::desktop()->screenGeometry(scrNumber) :
1928                          QApplication::desktop()->availableGeometry(scrNumber);
1929
1930     combo.move(screen.width()-combo.sizeHint().width(), 0); //puts the combo to the top-right corner
1931
1932     topLevel.show();
1933     //wait because the window manager can move the window if there is a right panel
1934     QTRY_VERIFY(combo.isVisible());
1935     combo.showPopup();
1936     QTRY_VERIFY(combo.view());
1937     QTRY_VERIFY(combo.view()->isVisible());
1938     QVERIFY( combo.view()->window()->x() + combo.view()->window()->width() <= screen.x() + screen.width() );
1939 }
1940
1941 void tst_QComboBox::separatorItem_data()
1942 {
1943     QTest::addColumn<QStringList>("items");
1944     QTest::addColumn<IntList>("separators");
1945
1946     QTest::newRow("test") << (QStringList() << "one" << "two" << "three" << "other...")
1947                           << (IntList() << 4);
1948 }
1949
1950 void tst_QComboBox::separatorItem()
1951 {
1952     QFETCH(QStringList, items);
1953     QFETCH(IntList, separators);
1954
1955     QComboBox box;
1956     box.addItems(items);
1957     foreach(int index, separators)
1958         box.insertSeparator(index);
1959     QCOMPARE(box.count(), (items.count() + separators.count()));
1960     for (int i = 0, s = 0; i < box.count(); ++i) {
1961         if (i == separators.at(s)) {
1962             QCOMPARE(box.itemText(i), QString());
1963             ++s;
1964         } else {
1965             QCOMPARE(box.itemText(i), items.at(i - s));
1966         }
1967     }
1968 }
1969
1970 // This test requires the Cleanlooks style
1971 #ifndef QT_NO_STYLE_CLEANLOOKS
1972 void tst_QComboBox::task190351_layout()
1973 {
1974     const QString oldStyle = QApplication::style()->objectName();
1975     QApplication::setStyle(new QCleanlooksStyle);
1976
1977     QComboBox listCombo;
1978     QListWidget *list = new QListWidget();
1979     listCombo.setModel(list->model());
1980     listCombo.setView(list);
1981     for(int i = 1; i < 150; i++)
1982         list->addItem(QLatin1String("list") + QString::number(i));
1983
1984     listCombo.show();
1985     QTest::qWaitForWindowShown(&listCombo);
1986     QTRY_VERIFY(listCombo.isVisible());
1987     listCombo.setCurrentIndex(70);
1988     listCombo.showPopup();
1989     QTRY_VERIFY(listCombo.view());
1990     QTest::qWaitForWindowShown(listCombo.view());
1991     QTRY_VERIFY(listCombo.view()->isVisible());
1992     QApplication::processEvents();
1993
1994 #ifdef QT_BUILD_INTERNAL
1995     QFrame *container = qFindChild<QComboBoxPrivateContainer *>(&listCombo);
1996     QVERIFY(container);
1997     QCOMPARE(static_cast<QAbstractItemView *>(list), qFindChild<QAbstractItemView *>(container));
1998     QWidget *top = qFindChild<QComboBoxPrivateScroller *>(container);
1999     QVERIFY(top);
2000     QVERIFY(top->isVisible());
2001     QCOMPARE(top->mapToGlobal(QPoint(0, top->height())).y(), list->mapToGlobal(QPoint()).y());
2002 #endif
2003
2004     QApplication::setStyle(oldStyle);
2005 }
2006 #endif
2007
2008 class task166349_ComboBox : public QComboBox
2009 {
2010     Q_OBJECT
2011 public:
2012     task166349_ComboBox(QWidget *parent = 0) : QComboBox(parent)
2013     {
2014         QStringList list;
2015         list << "one" << "two";
2016         connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(onCurrentIndexChanged(int)));
2017         addItems(list);
2018     }
2019 public slots:
2020     void onCurrentIndexChanged(int index)
2021     {
2022         setEditable(index % 2 == 1);
2023     }
2024 };
2025
2026 void tst_QComboBox::task166349_setEditableOnReturn()
2027 {
2028     task166349_ComboBox comboBox;
2029     QTest::keyClick(&comboBox, Qt::Key_Down);
2030     QTest::keyClick(&comboBox, Qt::Key_1);
2031     QTest::keyClick(&comboBox, Qt::Key_Enter);
2032     QCOMPARE(QLatin1String("two1"), comboBox.itemText(comboBox.count() - 1));
2033 }
2034
2035 // This test requires the Cleanlooks style.
2036 #ifndef QT_NO_STYLE_CLEANLOOKS
2037 void tst_QComboBox::task191329_size()
2038 {
2039     const QString oldStyle = QApplication::style()->objectName();
2040     QApplication::setStyle(new QCleanlooksStyle);
2041
2042     QComboBox tableCombo;
2043     int rows;
2044     if (QApplication::desktop()->screenGeometry().height() < 480)
2045         rows = 8;
2046     else
2047         rows = 15;
2048
2049     QStandardItemModel model(rows, 2);
2050     for (int row = 0; row < model.rowCount(); ++row) {
2051         for (int column = 0; column < model.columnCount(); ++column) {
2052             QStandardItem *item = new QStandardItem(QString("row %0, column %1").arg(row).arg(column));
2053             model.setItem(row, column, item);
2054         }
2055     }
2056     QTableView *table = new QTableView();
2057     table->verticalHeader()->hide();
2058     table->horizontalHeader()->hide();
2059     tableCombo.setView(table);
2060     tableCombo.setModel(&model);
2061
2062     tableCombo.show();
2063     QTRY_VERIFY(tableCombo.isVisible());
2064     tableCombo.showPopup();
2065     QTRY_VERIFY(tableCombo.view());
2066     QTRY_VERIFY(tableCombo.view()->isVisible());
2067
2068 #ifdef QT_BUILD_INTERNAL
2069     QFrame *container = qFindChild<QComboBoxPrivateContainer *>(&tableCombo);
2070     QVERIFY(container);
2071     QCOMPARE(static_cast<QAbstractItemView *>(table), qFindChild<QAbstractItemView *>(container));
2072     foreach (QWidget *button, qFindChildren<QComboBoxPrivateScroller *>(container)) {
2073         //the popup should be large enough to contains everithing so the top and left button are hidden
2074         QVERIFY(!button->isVisible());
2075     }
2076 #endif
2077
2078     QApplication::setStyle(oldStyle);
2079 }
2080 #endif
2081
2082 void tst_QComboBox::task190205_setModelAdjustToContents()
2083 {
2084     QStringList initialContent;
2085     QStringList finalContent;
2086     initialContent << "foo" << "bar";
2087     finalContent << "bar" << "foooooooobar";
2088
2089     QComboBox box;
2090     box.setSizeAdjustPolicy(QComboBox::AdjustToContents);
2091     box.addItems(initialContent);
2092     box.show();
2093
2094     //wait needed in order to get the combo initial size
2095     QTRY_VERIFY(box.isVisible());
2096
2097     box.setModel(new QStringListModel(finalContent));
2098
2099     QComboBox correctBox;
2100     correctBox.addItems(finalContent);
2101     correctBox.show();
2102
2103     QCoreApplication::processEvents();
2104 #ifdef Q_WS_X11
2105     qt_x11_wait_for_window_manager(&box);
2106     qt_x11_wait_for_window_manager(&correctBox);
2107 #endif
2108
2109     // box should be resized to the same size as correctBox
2110     QTRY_COMPARE(box.size(), correctBox.size());
2111 }
2112
2113 void tst_QComboBox::task248169_popupWithMinimalSize()
2114 {
2115     QStringList initialContent;
2116     initialContent << "foo" << "bar" << "foobar";
2117
2118     QComboBox comboBox;
2119     comboBox.addItems(initialContent);
2120     QDesktopWidget desktop;
2121     QRect desktopSize = desktop.availableGeometry();
2122     comboBox.view()->setMinimumWidth(desktopSize.width() / 2);
2123
2124     comboBox.setGeometry(desktopSize.width() - (desktopSize.width() / 4), (desktopSize.width() / 4), (desktopSize.width() / 2), (desktopSize.width() / 4));
2125
2126     comboBox.show();
2127     QTest::qWaitForWindowShown(&comboBox);
2128     QTRY_VERIFY(comboBox.isVisible());
2129     comboBox.showPopup();
2130     QTRY_VERIFY(comboBox.view());
2131     QTest::qWaitForWindowShown(comboBox.view());
2132     QTRY_VERIFY(comboBox.view()->isVisible());
2133
2134 #ifdef QT_BUILD_INTERNAL
2135     QFrame *container = qFindChild<QComboBoxPrivateContainer *>(&comboBox);
2136     QVERIFY(container);
2137     QTRY_VERIFY(desktop.screenGeometry(container).contains(container->geometry()));
2138 #endif
2139 }
2140
2141 void tst_QComboBox::task247863_keyBoardSelection()
2142 {
2143   QComboBox combo;
2144   combo.setEditable(false);
2145   combo.addItem( QLatin1String("111"));
2146   combo.addItem( QLatin1String("222"));
2147   combo.show();
2148   QApplication::setActiveWindow(&combo);
2149   QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&combo));
2150
2151   QSignalSpy spy(&combo, SIGNAL(activated(const QString &)));
2152   qApp->setEffectEnabled(Qt::UI_AnimateCombo, false);
2153   QTest::keyClick(&combo, Qt::Key_Space);
2154   qApp->setEffectEnabled(Qt::UI_AnimateCombo, true);
2155   QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Down);
2156   QTest::keyClick(static_cast<QWidget *>(0), Qt::Key_Enter);
2157   QCOMPARE(combo.currentText(), QLatin1String("222"));
2158   QCOMPARE(spy.count(), 1);
2159 }
2160
2161 void tst_QComboBox::task220195_keyBoardSelection2()
2162 {
2163     QComboBox combo;
2164     combo.setEditable(false);
2165     combo.addItem( QLatin1String("foo1"));
2166     combo.addItem( QLatin1String("foo2"));
2167     combo.addItem( QLatin1String("foo3"));
2168     combo.show();
2169     QApplication::setActiveWindow(&combo);
2170     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&combo));
2171
2172     combo.setCurrentIndex(-1);
2173     QVERIFY(combo.currentText().isNull());
2174
2175     QTest::keyClick(&combo, 'f');
2176     QCOMPARE(combo.currentText(), QLatin1String("foo1"));
2177     QTest::qWait(QApplication::keyboardInputInterval() + 30);
2178     QTest::keyClick(&combo, 'f');
2179     QCOMPARE(combo.currentText(), QLatin1String("foo2"));
2180     QTest::qWait(QApplication::keyboardInputInterval() + 30);
2181     QTest::keyClick(&combo, 'f');
2182     QCOMPARE(combo.currentText(), QLatin1String("foo3"));
2183     QTest::qWait(QApplication::keyboardInputInterval() + 30);
2184     QTest::keyClick(&combo, 'f');
2185     QCOMPARE(combo.currentText(), QLatin1String("foo1"));
2186     QTest::qWait(QApplication::keyboardInputInterval() + 30);
2187
2188     combo.setCurrentIndex(1);
2189     QCOMPARE(combo.currentText(), QLatin1String("foo2"));
2190     QTest::keyClick(&combo, 'f');
2191     QCOMPARE(combo.currentText(), QLatin1String("foo3"));
2192 }
2193
2194
2195 void tst_QComboBox::setModelColumn()
2196 {
2197     QStandardItemModel model(5,3);
2198     model.setItem(0,0, new QStandardItem("0"));
2199     model.setItem(1,0, new QStandardItem("1"));
2200     model.setItem(2,0, new QStandardItem("2"));
2201     model.setItem(3,0, new QStandardItem("3"));
2202     model.setItem(4,0, new QStandardItem("4"));
2203     model.setItem(0,1, new QStandardItem("zero"));
2204     model.setItem(1,1, new QStandardItem("un"));
2205     model.setItem(2,1, new QStandardItem("deux"));
2206     model.setItem(3,1, new QStandardItem("trois"));
2207     model.setItem(4,1, new QStandardItem("quatre"));
2208     model.setItem(0,2, new QStandardItem("a"));
2209     model.setItem(1,2, new QStandardItem("b"));
2210     model.setItem(2,2, new QStandardItem("c"));
2211     model.setItem(3,2, new QStandardItem("d"));
2212     model.setItem(4,2, new QStandardItem("e"));
2213
2214     QComboBox box;
2215     box.setModel(&model);
2216     QCOMPARE(box.currentText(), QString("0"));
2217     box.setModelColumn(1);
2218     QCOMPARE(box.currentText(), QString("zero"));
2219 }
2220
2221 void tst_QComboBox::noScrollbar_data()
2222 {
2223     QTest::addColumn<QString>("stylesheet");
2224
2225     QTest::newRow("normal") << QString();
2226     QTest::newRow("border") << QString::fromLatin1("QAbstractItemView { border: 12px solid blue;}");
2227     QTest::newRow("margin") << QString::fromLatin1("QAbstractItemView { margin: 12px 15px 13px 10px; }");
2228     QTest::newRow("padding") << QString::fromLatin1("QAbstractItemView { padding: 12px 15px 13px 10px;}");
2229     QTest::newRow("everything") << QString::fromLatin1("QAbstractItemView {  border: 12px  solid blue; "
2230                                                        " padding: 12px 15px 13px 10px; margin: 12px 15px 13px 10px;  }");
2231     QTest::newRow("everything and more") << QString::fromLatin1("QAbstractItemView {  border: 1px 3px 5px 1px solid blue; "
2232                                                        " padding: 2px 5px 3px 1px; margin: 2px 5px 3px 1px;  } "
2233                                                        " QAbstractItemView::item {  border: 2px solid green; "
2234                                                        "                      padding: 1px 1px 2px 2px; margin: 1px; } " );
2235 }
2236
2237 void tst_QComboBox::noScrollbar()
2238 {
2239     QStringList initialContent;
2240     initialContent << "foo" << "bar" << "foobar" << "moo";
2241     QFETCH(QString, stylesheet);
2242     QString oldCss = qApp->styleSheet();
2243     qApp->setStyleSheet(stylesheet);
2244
2245     {
2246         QWidget topLevel;
2247         QComboBox comboBox(&topLevel);
2248         comboBox.addItems(initialContent);
2249         topLevel.show();
2250         comboBox.resize(200, comboBox.height());
2251         QTRY_VERIFY(comboBox.isVisible());
2252         comboBox.showPopup();
2253         QTRY_VERIFY(comboBox.view());
2254         QTRY_VERIFY(comboBox.view()->isVisible());
2255
2256         QVERIFY(!comboBox.view()->horizontalScrollBar()->isVisible());
2257         QVERIFY(!comboBox.view()->verticalScrollBar()->isVisible());
2258     }
2259
2260     {
2261         QTableWidget *table = new QTableWidget(2,2);
2262         QComboBox comboBox;
2263         comboBox.setModel(table->model());
2264         comboBox.setView(table);
2265         comboBox.show();
2266         QTRY_VERIFY(comboBox.isVisible());
2267         comboBox.resize(200, comboBox.height());
2268         comboBox.showPopup();
2269         QTRY_VERIFY(comboBox.view());
2270         QTRY_VERIFY(comboBox.view()->isVisible());
2271
2272         QVERIFY(!comboBox.view()->horizontalScrollBar()->isVisible());
2273         QVERIFY(!comboBox.view()->verticalScrollBar()->isVisible());
2274     }
2275
2276     qApp->setStyleSheet(oldCss);
2277 }
2278
2279 void tst_QComboBox::setItemDelegate()
2280 {
2281     QComboBox comboBox;
2282     QStyledItemDelegate *itemDelegate = new QStyledItemDelegate;
2283     comboBox.setItemDelegate(itemDelegate);
2284     // the cast is a workaround for the XLC and Metrowerks compilers
2285     QCOMPARE(static_cast<QStyledItemDelegate *>(comboBox.itemDelegate()), itemDelegate);
2286 }
2287
2288 void tst_QComboBox::task253944_itemDelegateIsReset()
2289 {
2290     QComboBox comboBox;
2291     QStyledItemDelegate *itemDelegate = new QStyledItemDelegate;
2292     comboBox.setItemDelegate(itemDelegate);
2293
2294     // the casts are workarounds for the XLC and Metrowerks compilers
2295
2296     comboBox.setEditable(true);
2297     QCOMPARE(static_cast<QStyledItemDelegate *>(comboBox.itemDelegate()), itemDelegate);
2298
2299     comboBox.setStyleSheet("QComboBox { border: 1px solid gray; }");
2300     QCOMPARE(static_cast<QStyledItemDelegate *>(comboBox.itemDelegate()), itemDelegate);
2301 }
2302
2303
2304 void tst_QComboBox::subControlRectsWithOffset_data()
2305 {
2306     QTest::addColumn<bool>("editable");
2307
2308     QTest::newRow("editable = true") << true;
2309     QTest::newRow("editable = false") << false;
2310 }
2311
2312 void tst_QComboBox::subControlRectsWithOffset()
2313 {
2314     // The sub control rect relative position should not depends
2315     // on the position of the combobox
2316
2317     class FriendlyCombo : public QComboBox {
2318     public:
2319         void styleOption(QStyleOptionComboBox *optCombo) {
2320             initStyleOption(optCombo);
2321         }
2322     } combo;
2323     QStyleOptionComboBox optCombo;
2324     combo.styleOption(&optCombo);
2325
2326
2327     const QRect rectAtOrigin(0, 0, 80, 30);
2328     const QPoint offset(25, 50);
2329     const QRect rectWithOffset = rectAtOrigin.translated(offset);
2330
2331     QStyle *style = combo.style();
2332
2333     QFETCH(bool, editable);
2334     optCombo.editable = editable;
2335
2336     optCombo.rect = rectAtOrigin;
2337     QRect editFieldRect = style->subControlRect(QStyle::CC_ComboBox, &optCombo, QStyle::SC_ComboBoxEditField, 0);
2338     QRect arrowRect = style->subControlRect(QStyle::CC_ComboBox, &optCombo, QStyle::SC_ComboBoxArrow, 0);
2339     QRect listboxRect = style->subControlRect(QStyle::CC_ComboBox, &optCombo, QStyle::SC_ComboBoxListBoxPopup, 0);
2340
2341     optCombo.rect = rectWithOffset;
2342     QRect editFieldRectWithOffset = style->subControlRect(QStyle::CC_ComboBox, &optCombo, QStyle::SC_ComboBoxEditField, 0);
2343     QRect arrowRectWithOffset = style->subControlRect(QStyle::CC_ComboBox, &optCombo, QStyle::SC_ComboBoxArrow, 0);
2344     QRect listboxRectWithOffset = style->subControlRect(QStyle::CC_ComboBox, &optCombo, QStyle::SC_ComboBoxListBoxPopup, 0);
2345
2346     QCOMPARE(editFieldRect, editFieldRectWithOffset.translated(-offset));
2347     QCOMPARE(arrowRect, arrowRectWithOffset.translated(-offset));
2348     QCOMPARE(listboxRect, listboxRectWithOffset.translated(-offset));
2349
2350 }
2351
2352 // This test depends on Windows style.
2353 #ifndef QT_NO_STYLE_WINDOWS
2354 void tst_QComboBox::task260974_menuItemRectangleForComboBoxPopup()
2355 {
2356     class TestStyle: public QWindowsStyle
2357     {
2358     public:
2359         int styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *ret) const
2360         {
2361             if (hint == SH_ComboBox_Popup) return 1;
2362             else return QCommonStyle::styleHint(hint, option, widget, ret);
2363         }
2364
2365         void drawControl(ControlElement element, const QStyleOption *option, QPainter *, const QWidget *) const
2366         {
2367             if (element == CE_MenuItem)
2368                 discoveredRect = option->rect;
2369         }
2370
2371         mutable QRect discoveredRect;
2372     } style;
2373
2374
2375     {
2376         QComboBox comboBox;
2377         comboBox.setStyle(&style);
2378         comboBox.addItem("Item 1");
2379
2380         comboBox.show();
2381         QTRY_VERIFY(comboBox.isVisible());
2382         comboBox.showPopup();
2383         QTRY_VERIFY(comboBox.view());
2384         QTRY_VERIFY(comboBox.view()->isVisible());
2385
2386         QTRY_VERIFY(style.discoveredRect.width() <= comboBox.width());
2387     }
2388 }
2389 #endif
2390
2391 void tst_QComboBox::removeItem()
2392 {
2393     QComboBox cb;
2394     cb.removeItem(-1);
2395     cb.removeItem(1);
2396     cb.removeItem(0);
2397     QCOMPARE(cb.count(), 0);
2398
2399     cb.addItem("foo");
2400     cb.removeItem(-1);
2401     QCOMPARE(cb.count(), 1);
2402     cb.removeItem(1);
2403     QCOMPARE(cb.count(), 1);
2404     cb.removeItem(0);
2405     QCOMPARE(cb.count(), 0);
2406 }
2407
2408 void tst_QComboBox::resetModel()
2409 {
2410     class StringListModel : public QStringListModel
2411     {
2412     public:
2413         StringListModel(const QStringList &list) : QStringListModel(list)
2414         {
2415         }
2416
2417         void reset()
2418         {
2419             QStringListModel::reset();
2420         }
2421     };
2422     QComboBox cb;
2423     StringListModel model( QStringList() << "1" << "2");
2424     QSignalSpy spy(&cb, SIGNAL(currentIndexChanged(int)));
2425     QCOMPARE(spy.count(), 0);
2426     QCOMPARE(cb.currentIndex(), -1); //no selection
2427
2428     cb.setModel(&model);
2429
2430     QCOMPARE(spy.count(), 1);
2431     QCOMPARE(cb.currentIndex(), 0); //first item selected
2432
2433     model.reset();
2434     QCOMPARE(spy.count(), 2);
2435     QCOMPARE(cb.currentIndex(), -1); //no selection
2436
2437 }
2438
2439 void tst_QComboBox::keyBoardNavigationWithMouse()
2440 {
2441     QComboBox combo;
2442     combo.setEditable(false);
2443     for (int i = 0; i < 80; i++)
2444         combo.addItem( QString::number(i));
2445     combo.show();
2446     QApplication::setActiveWindow(&combo);
2447     QTest::qWaitForWindowShown(&combo);
2448     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(&combo));
2449
2450     QCOMPARE(combo.currentText(), QLatin1String("0"));
2451
2452     combo.setFocus();
2453     QTRY_VERIFY(combo.hasFocus());
2454
2455     QTest::keyClick(testWidget->lineEdit(), Qt::Key_Space);
2456     QTest::qWait(30);
2457     QTRY_VERIFY(combo.view());
2458     QTRY_VERIFY(combo.view()->isVisible());
2459     QTest::qWait(130);
2460
2461     QCOMPARE(combo.currentText(), QLatin1String("0"));
2462
2463     // When calling cursor function, Windows CE responds with: This function is not supported on this system.
2464 #ifndef Q_OS_WINCE
2465     // Force cursor movement to prevent QCursor::setPos() from returning prematurely on QPA:
2466     const QPoint target(combo.view()->mapToGlobal(combo.view()->rect().center()));
2467     QCursor::setPos(QPoint(target.x() + 1, target.y()));
2468     QCursor::setPos(target);
2469
2470     QTest::qWait(200);
2471
2472 #define GET_SELECTION(SEL) \
2473     QCOMPARE(combo.view()->selectionModel()->selection().count(), 1); \
2474     QCOMPARE(combo.view()->selectionModel()->selection().indexes().count(), 1); \
2475     SEL = combo.view()->selectionModel()->selection().indexes().first().row()
2476
2477     int selection;
2478     GET_SELECTION(selection);
2479
2480     //since we moved the mouse is in the middle it should even be around 5;
2481     QVERIFY(selection > 3);
2482
2483     static const int final = 40;
2484     for (int i = selection + 1;  i <= final; i++)
2485     {
2486         QTest::keyClick(combo.view(), Qt::Key_Down);
2487         QTest::qWait(20);
2488         GET_SELECTION(selection);
2489         QCOMPARE(selection, i);
2490     }
2491
2492     QTest::keyClick(combo.view(), Qt::Key_Enter);
2493     QTRY_COMPARE(combo.currentText(), QString::number(final));
2494 #endif
2495 }
2496
2497 void tst_QComboBox::task_QTBUG_1071_changingFocusEmitsActivated()
2498 {
2499     QWidget w;
2500     QVBoxLayout layout(&w);
2501     QComboBox cb;
2502     cb.setEditable(true);
2503     QSignalSpy spy(&cb, SIGNAL(activated(int)));
2504     cb.addItem("0");
2505     cb.addItem("1");
2506     cb.addItem("2");
2507     QLineEdit edit;
2508     layout.addWidget(&cb);
2509     layout.addWidget(&edit);
2510
2511     w.show();
2512     QApplication::setActiveWindow(&w);
2513     QTest::qWaitForWindowShown(&w);
2514     cb.clearEditText();
2515     cb.setFocus();
2516     QApplication::processEvents();
2517     QTRY_VERIFY(cb.hasFocus());
2518     QTest::keyClick(static_cast<QWidget *>(0), '1');
2519     QCOMPARE(spy.count(), 0);
2520     edit.setFocus();
2521     QTRY_VERIFY(edit.hasFocus());
2522     QTRY_COMPARE(spy.count(), 1);
2523 }
2524
2525 void tst_QComboBox::maxVisibleItems()
2526 {
2527     QComboBox comboBox;
2528     QCOMPARE(comboBox.maxVisibleItems(), 10); //default value.
2529
2530     QStringList content;
2531     for(int i = 1; i < 50; i++)
2532         content += QString::number(i);
2533
2534     comboBox.addItems(content);
2535     comboBox.show();
2536     comboBox.resize(200, comboBox.height());
2537     QTRY_VERIFY(comboBox.isVisible());
2538
2539     comboBox.setMaxVisibleItems(5);
2540     QCOMPARE(comboBox.maxVisibleItems(), 5);
2541
2542     comboBox.showPopup();
2543     QTRY_VERIFY(comboBox.view());
2544     QTRY_VERIFY(comboBox.view()->isVisible());
2545
2546     QAbstractItemView *v = comboBox.view();
2547     int itemHeight = v->visualRect(v->model()->index(0,0)).height();
2548     QListView *lv = qobject_cast<QListView*>(v);
2549     if (lv)
2550         itemHeight += lv->spacing();
2551     QStyleOptionComboBox opt;
2552     opt.initFrom(&comboBox);
2553     if (!comboBox.style()->styleHint(QStyle::SH_ComboBox_Popup, &opt))
2554         QCOMPARE(v->viewport()->height(), itemHeight * comboBox.maxVisibleItems());
2555 }
2556
2557 void tst_QComboBox::task_QTBUG_10491_currentIndexAndModelColumn()
2558 {
2559     QComboBox comboBox;
2560
2561     QStandardItemModel model(4, 4, &comboBox);
2562     for (int i = 0; i < 4; i++){
2563         model.setItem(i, 0, new QStandardItem(QString("Employee Nr %1").arg(i)));
2564         model.setItem(i, 1, new QStandardItem(QString("Street Nr %1").arg(i)));
2565         model.setItem(i, 2, new QStandardItem(QString("Town Nr %1").arg(i)));
2566         model.setItem(i, 3, new QStandardItem(QString("Phone Nr %1").arg(i)));
2567     }
2568     comboBox.setModel(&model);
2569     comboBox.setModelColumn(0);
2570
2571     QComboBoxPrivate *d = static_cast<QComboBoxPrivate *>(QComboBoxPrivate::get(&comboBox));
2572     d->setCurrentIndex(model.index(2, 2));
2573     QCOMPARE(QModelIndex(d->currentIndex), model.index(2, comboBox.modelColumn()));
2574 }
2575
2576 QTEST_MAIN(tst_QComboBox)
2577 #include "tst_qcombobox.moc"