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