File indexing completed on 2024-04-14 14:19:44
0001 /* This file is part of the KDE libraries 0002 0003 Copyright (c) 2008 David Faure <faure@kde.org> 0004 0005 This library is free software; you can redistribute it and/or 0006 modify it under the terms of the GNU Library General Public 0007 License as published by the Free Software Foundation; either 0008 version 2 of the License, or (at your option) any later version. 0009 0010 This library is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 Library General Public License for more details. 0014 0015 You should have received a copy of the GNU Library General Public License 0016 along with this library; see the file COPYING.LIB. If not, write to 0017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include <QTest> 0022 #include <qtestevent.h> 0023 #include <ktabwidget.h> 0024 #include <klineedit.h> 0025 #include <QComboBox> 0026 #include <QTabBar> 0027 0028 class KTabWidget_UnitTest : public QObject 0029 { 0030 Q_OBJECT 0031 0032 private Q_SLOTS: 0033 // Test calling tabText() from slotCurrentChanged(). 0034 // Because QTabBar::insertTab() emits currentChanged before 0035 // QTabWidget calls tabInserted(), we were getting an assert in tabText(). 0036 void testTabTextFromSlotCurrentChanged() 0037 { 0038 KTabWidget w; 0039 w.setAutomaticResizeTabs(true); 0040 const QString firstTitle = "First post!"; 0041 connect(&w, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentChanged(int))); 0042 const int zero = w.insertTab(0, new QWidget, firstTitle); // calls slotCurrentChanged 0043 QCOMPARE(zero, 0); 0044 QCOMPARE(w.tabText(0), firstTitle); 0045 } 0046 0047 void testCloseFirstTab() 0048 { 0049 // Test inspired by #170470, but the bug only happened when calling setTabText 0050 // in slotCurrentChanged so the real unit test for that bug is in konqueror. 0051 KTabWidget w; 0052 w.setAutomaticResizeTabs(true); 0053 w.resize(300, 400); 0054 // Send the pending resize event (resize() only sets Qt::WA_PendingResizeEvent) 0055 QResizeEvent e(w.size(), QSize()); 0056 QApplication::sendEvent(&w, &e); 0057 0058 QString prefix = "This is a long prefix for the tab title. "; 0059 for (int i = 0; i < 6; ++i) { 0060 w.insertTab(i, new QWidget, prefix + QString::number(i)); 0061 } 0062 w.removeTab(0); 0063 for (int i = 0; i < 5; ++i) { 0064 //kDebug() << i << w.tabText(i); 0065 QCOMPARE(w.tabText(i), QString(prefix + QString::number(i + 1))); 0066 } 0067 w.removeTab(0); 0068 for (int i = 0; i < 4; ++i) { 0069 //kDebug() << i << w.tabText(i); 0070 QCOMPARE(w.tabText(i), QString(prefix + QString::number(i + 2))); 0071 } 0072 } 0073 void testMoveTab() 0074 { 0075 // Test inspired by #170470 and #177036 (title messup). 0076 // Then expanded to include the problem of #159295 (focus loss). 0077 QWidget topLevel; 0078 QComboBox *combo = new QComboBox(&topLevel); 0079 combo->setEditable(true); 0080 KTabWidget *w = new KTabWidget(&topLevel); 0081 w->setAutomaticResizeTabs(true); 0082 w->resize(300, 400); 0083 QResizeEvent e(w->size(), QSize()); 0084 QApplication::sendEvent(w, &e); 0085 QString prefix = "This is a long prefix for the tab title. "; 0086 KLineEdit *lineEdits[4]; 0087 for (int i = 0; i < 4; ++i) { 0088 QWidget *page = new QWidget; 0089 page->setObjectName(QString::number(i)); 0090 lineEdits[i] = new KLineEdit(page); // a widget that can take focus 0091 lineEdits[i]->setObjectName("LineEdit" + QString::number(i)); 0092 w->insertTab(i, page, prefix + QString::number(i)); 0093 //kDebug() << i << w->tabText(i); 0094 } 0095 topLevel.show(); 0096 // Necessary after show(), otherwise topLevel.focusWidget() returns NULL 0097 QApplication::setActiveWindow(&topLevel); 0098 0099 // Make sure the tab order is so that the combo gets focus after this tab 0100 QWidget::setTabOrder(lineEdits[0], combo->lineEdit()); 0101 QWidget::setTabOrder(combo->lineEdit(), lineEdits[1]); 0102 0103 w->setCurrentIndex(0); 0104 lineEdits[0]->setFocus(); 0105 QCOMPARE(topLevel.focusWidget()->objectName(), lineEdits[0]->objectName()); 0106 QVERIFY(lineEdits[0]->isVisible()); 0107 0108 w->moveTab(0, 3); 0109 //for (int i = 0; i < 4; ++i) 0110 //kDebug() << i << w->tabText(i); 0111 QCOMPARE(w->tabText(0), QString(prefix + QString::number(1))); 0112 QCOMPARE(w->tabText(1), QString(prefix + QString::number(2))); 0113 QCOMPARE(w->tabText(2), QString(prefix + QString::number(3))); 0114 QCOMPARE(w->tabText(3), QString(prefix + QString::number(0))); 0115 0116 // Did the focus switch to the lineEdit, due to removeTab+insertTab? Whoops. 0117 QCOMPARE(topLevel.focusWidget()->objectName(), lineEdits[0]->objectName()); 0118 0119 w->moveTab(3, 0); 0120 QCOMPARE(topLevel.focusWidget()->objectName(), lineEdits[0]->objectName()); 0121 for (int i = 0; i < 4; ++i) { 0122 //kDebug() << i << w->tabText(i); 0123 QCOMPARE(w->tabText(i), QString(prefix + QString::number(i))); 0124 } 0125 } 0126 0127 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED 0128 void testSetHidden() 0129 { 0130 KTabWidget w; 0131 w.insertTab(0, new QWidget, "a tab"); 0132 QVERIFY(!w.isTabBarHidden()); 0133 w.show(); 0134 QVERIFY(!w.isTabBarHidden()); 0135 w.setTabBarHidden(true); 0136 QVERIFY(w.isTabBarHidden()); 0137 } 0138 #endif 0139 void testMouseButtonTabReordering(); 0140 void testTabMoved(); 0141 0142 private Q_SLOTS: 0143 void slotCurrentChanged(int index) 0144 { 0145 QCOMPARE(index, 0); 0146 KTabWidget *w = qobject_cast<KTabWidget *>(sender()); 0147 QVERIFY(w); 0148 QCOMPARE(w->tabText(0), QString("First post!")); 0149 } 0150 }; 0151 0152 // MyTabWidget is a tab widget that provides access to the tab bar. 0153 // This is needed for the following unit test. 0154 0155 class MyTabWidget : public KTabWidget 0156 { 0157 0158 public: 0159 QTabBar *getTabBar() const 0160 { 0161 return tabBar(); 0162 } 0163 }; 0164 0165 void KTabWidget_UnitTest::testMouseButtonTabReordering() 0166 { 0167 // This test passes locally but fails on CI. 0168 // Tab reordering works, let's not spend time on this. 0169 #if 0 0170 MyTabWidget tabWidget; 0171 tabWidget.setMovable(true); 0172 0173 QWidget *w0 = new QWidget; 0174 QWidget *w1 = new QWidget; 0175 tabWidget.insertTab(0, w0, "Tab 0"); 0176 tabWidget.insertTab(1, w1, "Tab 1"); 0177 tabWidget.show(); 0178 0179 QPoint pos0 = tabWidget.getTabBar()->tabRect(0).center(); 0180 QPoint pos1 = tabWidget.getTabBar()->tabRect(1).center(); 0181 0182 // Press LMB 0183 QTest::mousePress(tabWidget.getTabBar(), Qt::LeftButton, Qt::NoModifier, pos0); 0184 0185 // We need a first move event on tab 0 to initialize tab moving 0186 QMouseEvent moveEvent(QEvent::MouseMove, pos0, Qt::NoButton, Qt::LeftButton, Qt::NoModifier); 0187 bool moveEventReceived = qApp->notify(tabWidget.getTabBar(), &moveEvent); 0188 QVERIFY(moveEventReceived); 0189 0190 // Move tab 0 to tab 1 0191 moveEvent = QMouseEvent(QEvent::MouseMove, pos1, Qt::NoButton, Qt::LeftButton, Qt::NoModifier); 0192 moveEventReceived = qApp->notify(tabWidget.getTabBar(), &moveEvent); 0193 QVERIFY(moveEventReceived); 0194 0195 QCOMPARE(tabWidget.tabText(0), QString("Tab 1")); 0196 QCOMPARE(tabWidget.tabText(1), QString("Tab 0")); 0197 QCOMPARE(tabWidget.widget(0), w1); 0198 QCOMPARE(tabWidget.widget(1), w0); 0199 0200 QTest::mouseRelease(tabWidget.getTabBar(), Qt::LeftButton, Qt::NoModifier, pos1); 0201 #endif 0202 } 0203 0204 void KTabWidget_UnitTest::testTabMoved() 0205 { 0206 MyTabWidget tabWidget; 0207 tabWidget.setMovable(true); 0208 tabWidget.setAutomaticResizeTabs(true); 0209 0210 tabWidget.insertTab(0, new QWidget, "Tab A"); 0211 tabWidget.insertTab(1, new QWidget, "Tab B"); 0212 tabWidget.insertTab(2, new QWidget, "Tab C"); 0213 tabWidget.insertTab(3, new QWidget, "Tab D"); 0214 0215 tabWidget.getTabBar()->moveTab(3, 1); 0216 0217 QCOMPARE(tabWidget.tabText(0), QString("Tab A")); 0218 QCOMPARE(tabWidget.tabText(1), QString("Tab D")); 0219 QCOMPARE(tabWidget.tabText(2), QString("Tab B")); 0220 QCOMPARE(tabWidget.tabText(3), QString("Tab C")); 0221 } 0222 0223 QTEST_MAIN(KTabWidget_UnitTest) 0224 0225 #include "ktabwidget_unittest.moc"