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"