File indexing completed on 2024-04-28 04:58:08

0001 /* This file is part of the KDE project
0002     SPDX-FileCopyrightText: 2006 David Faure <faure@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "konqviewmgrtest.h"
0008 #include <konqmainwindowfactory.h>
0009 #include "../src/konqsettingsxt.h"
0010 #include <QToolBar>
0011 #include <QProcess>
0012 #include <QScrollArea>
0013 #include <qtestkeyboard.h>
0014 #include <qtest_gui.h>
0015 #include <qtestmouse.h>
0016 #include <QLabel>
0017 
0018 #include <konqframe.h>
0019 #include <konqmainwindow.h>
0020 #include <konqviewmanager.h>
0021 #include <konqview.h>
0022 #include <konqtabs.h>
0023 #include <konqframevisitor.h>
0024 #include <konqsessionmanager.h>
0025 #include <kconfiggroup.h>
0026 #include <kio/job.h>
0027 #include <ksycoca.h>
0028 #include <KLocalizedString>
0029 
0030 //#define TEST_KHTML 1
0031 
0032 #ifdef TEST_KHTML
0033 #include <khtml_part.h>
0034 #include <khtmlview.h>
0035 #else
0036 #include <webenginepart.h>
0037 #include <webengineview.h>
0038 #include "../webenginepart/autotests/webengine_testutils.h"
0039 #endif
0040 
0041 #include <QStandardPaths>
0042 #include <KSharedConfig>
0043 #include <QSignalSpy>
0044 
0045 QTEST_MAIN(ViewMgrTest)
0046 
0047 #if 0
0048 // could be used to load dummy parts; or to check that the right parts are being loaded
0049 // (and to detect the case where a part is loaded and then replaced with another one for no good reason)
0050 class KonqTestFactory : public KonqAbstractFactory
0051 {
0052 public:
0053     virtual KonqViewFactory createView(const QString &serviceType,
0054                                        const QString &serviceName = QString(),
0055                                        KService::Ptr *serviceImpl = 0,
0056                                        KService::List *partServiceOffers = 0,
0057                                        KService::List *appServiceOffers = 0,
0058                                        bool forceAutoEmbed = false);
0059 
0060 };
0061 #endif
0062 
0063 
0064 // Return the main widget for the given KonqView; used for clicking onto it
0065 // Duplicated from konqhtmltest.cpp -> move to KonqView?
0066 static QWidget *partWidget(KonqView *view)
0067 {
0068     QWidget *widget = view->part()->widget();
0069 #ifdef TEST_KHTML
0070     KHTMLPart *htmlPart = qobject_cast<KHTMLPart *>(view->part());
0071 #else
0072     WebEnginePart *htmlPart = qobject_cast<WebEnginePart *>(view->part());
0073 #endif
0074     if (htmlPart) {
0075         widget = htmlPart->view();    // khtmlview != widget() nowadays, due to find bar
0076     }
0077     if (QScrollArea *scrollArea = qobject_cast<QScrollArea *>(widget)) {
0078         widget = scrollArea->widget();
0079     }
0080     if (widget && widget->focusProxy()) { // for WebEngine's RenderWidgetHostViewQtDelegateWidget
0081         return widget->focusProxy();
0082     }
0083     return widget;
0084 }
0085 
0086 void ViewMgrTest::sendAllPendingResizeEvents(QWidget *mainWindow)
0087 {
0088     bool foundOne = true;
0089     while (foundOne) {
0090         foundOne = false;
0091         QList<QWidget *> allChildWidgets = mainWindow->findChildren<QWidget *>();
0092         allChildWidgets.prepend(mainWindow);
0093         for (QWidget *w: allChildWidgets) {
0094             if (w->testAttribute(Qt::WA_PendingResizeEvent)) {
0095                 w->setAttribute(Qt::WA_WState_Created, true); // hack: avoid assert in Qt-4.6
0096                 //qDebug() << "Resizing" << w << " to " << w->size() << endl;
0097                 QResizeEvent e(w->size(), QSize());
0098                 QApplication::sendEvent(w, &e);
0099                 w->setAttribute(Qt::WA_PendingResizeEvent, false);
0100                 // hack: make QTabWidget think it's visible; no layout otherwise
0101                 w->setAttribute(Qt::WA_WState_Visible, true);
0102                 foundOne = true;
0103             }
0104         }
0105         // Process LayoutRequest events, in particular
0106         qApp->sendPostedEvents();
0107         //qDebug() << "Loop done, checking again";
0108 
0109         if (!foundOne) { // about to exit, reset visible flag, to avoid crashes in qt
0110             for (QWidget *w: allChildWidgets) {
0111                 w->setAttribute(Qt::WA_WState_Visible, false);
0112             }
0113         }
0114     }
0115 }
0116 
0117 class DebugFrameVisitor : public KonqFrameVisitor
0118 {
0119 public:
0120     DebugFrameVisitor() {}
0121     QString output() const
0122     {
0123         return m_output;
0124     }
0125     bool visit(KonqFrame *) override
0126     {
0127         m_output += 'F';
0128         return true;
0129     }
0130     bool visit(KonqFrameContainer *) override
0131     {
0132         m_output += QLatin1String("C(");
0133         return true;
0134     }
0135     bool visit(KonqFrameTabs *) override
0136     {
0137         m_output += QLatin1String("T[");
0138         return true;
0139     }
0140     bool visit(KonqMainWindow *) override
0141     {
0142         m_output += 'M';
0143         return true;
0144     }
0145     bool endVisit(KonqFrameContainer *) override
0146     {
0147         m_output += ')';
0148         return true;
0149     }
0150     bool endVisit(KonqFrameTabs *) override
0151     {
0152         m_output += ']';
0153         return true;
0154     }
0155     bool endVisit(KonqMainWindow *) override
0156     {
0157         m_output += '.';
0158         return true;
0159     }
0160 
0161     static QString inspect(KonqMainWindow *mainWindow)
0162     {
0163         DebugFrameVisitor dfv;
0164         bool ok = mainWindow->accept(&dfv);
0165         if (!ok) {
0166             return QStringLiteral("ERROR: visitor returned false");
0167         }
0168         return dfv.output();
0169     }
0170 
0171 private:
0172     QString m_output;
0173 };
0174 
0175 void ViewMgrTest::initTestCase()
0176 {
0177     KLocalizedString::setApplicationDomain("konqviewmgrtest");
0178 
0179     QStandardPaths::setTestModeEnabled(true);
0180     QDir(KonqSessionManager::self()->autosaveDirectory()).removeRecursively();
0181     QString configLocationDir = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
0182     const QLatin1String expConfigDir(".qttest/config");
0183     QString msg = QString("Can't remove the config file because it isn't in the %1 directory but in %2").arg(expConfigDir).arg(configLocationDir);
0184     QVERIFY2(configLocationDir.endsWith(expConfigDir), msg.toLatin1().constData());
0185     QDir(configLocationDir).remove("konquerorrc");
0186 
0187     KonqSessionManager::self()->disableAutosave();
0188     QCOMPARE(KonqSettings::mmbOpensTab(), true);
0189     QCOMPARE(KonqSettings::popupsWithinTabs(), false);
0190     KonqSettings::setAlwaysHavePreloaded(false); // it would confuse the mainwindow counting
0191 
0192     // Ensure the tests use webenginepart (not khtml or webkit)
0193     // This code is inspired by settings/konqhtml/generalopts.cpp
0194     KSharedConfig::Ptr profile = KSharedConfig::openConfig(QStringLiteral("mimeapps.list"), KConfig::NoGlobals, QStandardPaths::ApplicationsLocation);
0195     KConfigGroup addedServices(profile, "Added KDE Service Associations");
0196     bool needsUpdate = false;
0197     for (const QString &mimeType : QStringList{"text/html", "application/xhtml+xml", "application/xml"}) {
0198         QStringList services = addedServices.readXdgListEntry(mimeType);
0199         const QString wanted = QStringLiteral("webenginepart.desktop");
0200         if (services.isEmpty() || services.at(0) != wanted) {
0201             services.removeAll(wanted);
0202             services.prepend(wanted); // make it the preferred one
0203             addedServices.writeXdgListEntry(mimeType, services);
0204             needsUpdate = true;
0205         }
0206     }
0207     if (needsUpdate) {
0208         profile->sync();
0209         // kbuildsycoca is the one reading mimeapps.list, so we need to run it now
0210         QProcess::execute(QStandardPaths::findExecutable(KBUILDSYCOCA_EXENAME), {});
0211     }
0212 }
0213 
0214 void ViewMgrTest::testCreateFirstView()
0215 {
0216     KonqMainWindow mainWindow;
0217     KonqViewManager *viewManager = mainWindow.viewManager();
0218     KonqView *view = viewManager->createFirstView(QStringLiteral("text/html"), QStringLiteral("webenginepart"));
0219     QVERIFY(view);
0220     QVERIFY(viewManager->tabContainer());
0221 
0222     // Use DebugFrameVisitor to find out the structure of the frame hierarchy
0223     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[F]."));   // mainWindow, one tab, one frame
0224     QCOMPARE(mainWindow.linkableViewsCount(), 1);
0225 
0226     // Check widget parents:  part's widget -> frame -> [tabwidget's stack] -> tabwidget -> mainWindow
0227     QWidget *partWidget = view->part()->widget();
0228     QCOMPARE(partWidget->window(), &mainWindow);
0229     QWidget *frame = view->frame()->asQWidget();
0230     QCOMPARE(partWidget->parentWidget(), frame);
0231     QWidget *tabWidget = viewManager->tabContainer()->asQWidget();
0232     QCOMPARE(frame->parentWidget()->parentWidget(), tabWidget);
0233 
0234     // Check frame geometry, to check that all layouts are there
0235     // (the mainWindow is resized to 700x480 in its constructor)
0236     // But pending resize events are only sent by show(), and we don't want to see
0237     // widgets from unit tests.
0238     // So we iterate over all widgets and ensure the pending resize events are sent.
0239     sendAllPendingResizeEvents(&mainWindow);
0240     for (QWidget *w = partWidget; w; w = w->parentWidget()) {
0241         qDebug() << w << w->geometry();
0242     }
0243     //const QList<QToolBar*> toolbars = mainWindow.findChildren<QToolBar *>();
0244     //foreach( QToolBar* toolbar, toolbars ) {
0245     //    if (!toolbar->isHidden())
0246     //        qDebug() << toolbar << toolbar->geometry();
0247     //}
0248     //qDebug() << "frame geom: " << frame->geometry();
0249     QVERIFY(frame->width() > 680);
0250     QVERIFY(frame->height() > 240);   // usually 325, but can be 256 with oxygen when three toolbars are shown
0251     //qDebug() << "partWidget geom:" << partWidget->geometry();
0252     QVERIFY(partWidget->width() > 680);
0253     QVERIFY(partWidget->height() > frame->height() - 50 /*statusbar*/);
0254     //qDebug() << "tabWidget geom: " << tabWidget->geometry();
0255     QVERIFY(tabWidget->width() > 680);
0256     QVERIFY(tabWidget->height() >= frame->height());   // equal, unless there's a border in the frame
0257 
0258     // Part widget should have focus, not location bar
0259     QCOMPARE(mainWindow.focusWidget()->metaObject()->className(), partWidget->focusWidget()->metaObject()->className());
0260 }
0261 
0262 void ViewMgrTest::testEmptyWindow()
0263 {
0264     QScopedPointer<KonqMainWindow> emptyWindow(KonqMainWindowFactory::createNewWindow());
0265     QCOMPARE(emptyWindow->currentView()->url().url(), QString("konq:konqueror"));
0266     QCOMPARE(emptyWindow->focusWidget()->metaObject()->className(), "KonqCombo");
0267 }
0268 
0269 void ViewMgrTest::testRemoveFirstView()
0270 {
0271     KonqMainWindow mainWindow;
0272     KonqViewManager *viewManager = mainWindow.viewManager();
0273     KonqView *view = viewManager->createFirstView(QStringLiteral("text/html"), QStringLiteral("webenginepart"));
0274     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[F]."));   // mainWindow, tab widget, one frame
0275     viewManager->removeView(view);
0276     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[F]."));   // removing not allowed
0277     // real test for removeView is part of testSplitView
0278 }
0279 
0280 void ViewMgrTest::testSplitView()
0281 {
0282     KonqMainWindow mainWindow;
0283     KonqViewManager *viewManager = mainWindow.viewManager();
0284     KonqView *view = viewManager->createFirstView(QStringLiteral("text/html"), QStringLiteral("webenginepart"));
0285 
0286     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[F]."));   // mainWindow, tab widget, one frame
0287     // mainWindow.show();
0288     // qApp->processEvents();
0289     KonqView *view2 = viewManager->splitView(view, Qt::Horizontal);
0290     QVERIFY(view2);
0291     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[C(FF)]."));   // mainWindow, tab widget, one splitter, two frames
0292 
0293     QCOMPARE(mainWindow.linkableViewsCount(), 2);
0294 
0295     // Check widget parents
0296     //mainWindow.dumpObjectTree();
0297     QWidget *partWidget = view->part()->widget();
0298     QCOMPARE(partWidget->window(), &mainWindow);
0299     QWidget *frame = view->frame()->asQWidget();
0300     QCOMPARE(partWidget->parentWidget(), frame);
0301     QVERIFY(!frame->isHidden());
0302 
0303     QWidget *part2Widget = view2->part()->widget();
0304     QCOMPARE(part2Widget->window(), &mainWindow);
0305     QWidget *frame2 = view2->frame()->asQWidget();
0306     QCOMPARE(part2Widget->parentWidget(), frame2);
0307     QVERIFY(!frame2->isHidden());
0308 
0309     // Check container
0310     QCOMPARE(view->frame()->parentContainer()->frameType(), KonqFrameBase::Container);
0311     KonqFrameContainer *container = static_cast<KonqFrameContainer *>(view->frame()->parentContainer());
0312     QVERIFY(container);
0313     QCOMPARE(container->count(), 2);
0314     QCOMPARE(container, view2->frame()->parentContainer());
0315     QCOMPARE(container->firstChild(), view->frame());
0316     QCOMPARE(container->secondChild(), view2->frame());
0317     QCOMPARE(container->widget(0), view->frame()->asQWidget());
0318     QCOMPARE(container->widget(1), view2->frame()->asQWidget());
0319 
0320     // mainWindow.show();
0321     // qApp->processEvents();
0322     // Check frame geometries
0323     sendAllPendingResizeEvents(&mainWindow);
0324     //for ( QWidget* w = partWidget; w; w = w->parentWidget() )
0325     //    qDebug() << w << w->geometry() << "visible:" << w->isVisible();
0326 
0327     //qDebug() << "view geom:" << frame->geometry();
0328     QVERIFY(frame->width() > 300 && frame->width() < 400);   // horiz split, so half the mainWindow width
0329     QVERIFY(frame->height() > 240);   // usually 325, but can be 256 with oxygen when three toolbars are shown
0330     //qDebug() << "view2 geom:" << frame2->geometry();
0331     QVERIFY(frame2->width() > 300 && frame2->width() < 400);   // horiz split, so half the mainWindow width
0332     QVERIFY(frame2->height() > 240);   // usually 325, but can be 256 with oxygen when three toolbars are shown
0333     // Both frames should have the same size; well, if the width was odd then there can be an off-by-one...
0334     QCOMPARE(frame->height(), frame2->height());
0335     // qDebug() << "FRAME WIDTH" << frame->width() << "FRAME2 WIDTH" << frame2->width();
0336     // qDebug() << "FRAME MINIMUM WIDTH" << frame->minimumSizeHint() << "FRAME2 MINIMIUM WIDTH" << frame2->minimumSizeHint();
0337     QVERIFY(qAbs(frame->width() - frame2->width()) <= 1);   // e.g. 173 and 172 are "close enough"
0338     //qDebug() << "partWidget geom:" << partWidget->geometry();
0339     QVERIFY(partWidget->width() > 300 && partWidget->width() < 400);   // horiz split, so half the mainWindow width
0340     QVERIFY(partWidget->height() > 220);   // frame minus statusbar height
0341     QVERIFY(part2Widget->width() > 300 && part2Widget->width() < 400);   // horiz split, so half the mainWindow width
0342     QVERIFY(part2Widget->height() > 220);
0343 
0344     //KonqFrameContainerBase* container = view->frame()->parentContainer();
0345     //QVERIFY( container );
0346     //qDebug() << "container geom: " << container->asQWidget()->geometry();
0347 
0348     // Split again
0349     int widthFrame2 = frame2->width();
0350     KonqView *view3 = viewManager->splitView(view, Qt::Horizontal);
0351     QVERIFY(view3);
0352     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[C(C(FF)F)]."));
0353     // Check that the width of the second frame has not changed (bug 160407)
0354     QCOMPARE(frame2->width(), widthFrame2);
0355     QCOMPARE(mainWindow.linkableViewsCount(), 3);
0356 
0357     // Now test removing the first view
0358     viewManager->removeView(view);
0359     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[C(FF)]."));   // mainWindow, tab widget, one splitter, two frames
0360     // Check again that the width of the second frame has not changed (bug 160407 comments 18-20)
0361     QCOMPARE(frame2->width(), widthFrame2);
0362     QCOMPARE(mainWindow.linkableViewsCount(), 2);
0363 
0364     // Now test removing the last view
0365     viewManager->removeView(view3);
0366     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[F]."));   // mainWindow, tab widget, one frame
0367     QCOMPARE(mainWindow.linkableViewsCount(), 1);
0368 }
0369 
0370 void ViewMgrTest::testSplitMainContainer()
0371 {
0372     KonqMainWindow mainWindow;
0373     KonqViewManager *viewManager = mainWindow.viewManager();
0374     KonqView *view = viewManager->createFirstView(QStringLiteral("text/html"), QStringLiteral("webenginepage"));
0375     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[F]."));   // mainWindow, tab widget, one frame
0376     KonqFrameContainerBase *tabContainer = view->frame()->parentContainer();
0377     KonqView *view2 = viewManager->splitMainContainer(view, Qt::Horizontal, QStringLiteral("text/html"), QStringLiteral("webenginepart"), true);
0378     QVERIFY(view2);
0379     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MC(FT[F])."));   // mainWindow, splitter, frame, tab widget, one frame
0380 
0381     // Check widget parents
0382     QWidget *partWidget = view->part()->widget();
0383     QCOMPARE(partWidget->window(), &mainWindow);
0384     QWidget *frame = view->frame()->asQWidget();
0385     QCOMPARE(partWidget->parentWidget(), frame);
0386     QVERIFY(!frame->isHidden());
0387 
0388     QWidget *part2Widget = view2->part()->widget();
0389     QCOMPARE(part2Widget->window(), &mainWindow);
0390     QWidget *frame2 = view2->frame()->asQWidget();
0391     QCOMPARE(part2Widget->parentWidget(), frame2);
0392     QVERIFY(!frame2->isHidden());
0393 
0394     // Check container
0395     QCOMPARE(view->frame()->parentContainer()->frameType(), KonqFrameBase::Tabs);
0396     QCOMPARE(view2->frame()->parentContainer()->frameType(), KonqFrameBase::Container);
0397     KonqFrameContainer *container = static_cast<KonqFrameContainer *>(view2->frame()->parentContainer());
0398     QVERIFY(container);
0399     QCOMPARE(container->count(), 2);
0400     QCOMPARE(container, view2->frame()->parentContainer());
0401     QCOMPARE(container->firstChild(), view2->frame());
0402     QCOMPARE(container->secondChild(), tabContainer);
0403     QCOMPARE(container->widget(0), view2->frame()->asQWidget());
0404     QCOMPARE(container->widget(1), tabContainer->asQWidget());
0405 
0406     // Now test removing the view we added last
0407     viewManager->removeView(view2);
0408     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[F]."));   // mainWindow, tab widget, one frame
0409 }
0410 
0411 static void openHtmlWithLink(KonqMainWindow &mainWindow)
0412 {
0413     // Much like KonqHtmlTest::loadSimpleHtml.
0414     // We use text/plain as the linked file, in order to test #67956 (switching parts in new tab)
0415     mainWindow.openUrl(nullptr, QUrl(QStringLiteral("data:text/html, <a href=\"data:text/plain, Link target\" id=\"linkid\">Click me</a>")), QStringLiteral("text/html"));
0416     KonqView *view = mainWindow.currentView();
0417     QVERIFY(view);
0418     QSignalSpy spyCompleted(view, &KonqView::viewCompleted);
0419     QVERIFY(spyCompleted.wait(20000));
0420     QCOMPARE(view->serviceType(), QString("text/html"));
0421 }
0422 
0423 void ViewMgrTest::testLinkedViews()
0424 {
0425     KonqMainWindow mainWindow;
0426     openHtmlWithLink(mainWindow);
0427     KonqView *view = mainWindow.currentView();
0428     WebEnginePart *part = qobject_cast<WebEnginePart *>(view->part());
0429     QVERIFY(part);
0430     // Split it
0431     qDebug() << "SPLITTING";
0432     mainWindow.slotSplitViewHorizontal();
0433     KonqView *view2 = mainWindow.currentView();
0434     QVERIFY(view2);
0435     QCOMPARE(view2->serviceType(), QString("text/html"));
0436     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[C(FF)]."));   // mainWindow, tab widget, one splitter, two frames
0437     QSignalSpy spyCompleted(view2, &KonqView::viewCompleted);
0438     QVERIFY(spyCompleted.wait(20000));
0439     const QUrl origUrl = view->url();
0440     QCOMPARE(view2->url().url(), origUrl.url());
0441     QCOMPARE(mainWindow.linkableViewsCount(), 2);
0442     view->setLinkedView(true);
0443     view2->setLinkedView(true);
0444     view->setLockedLocation(true);
0445 
0446     mainWindow.show();
0447 
0448     // "Click" on the link
0449     qDebug() << "ACTIVATING LINK";
0450 
0451 #ifdef TEST_KHTML
0452     KHTMLPart *part = qobject_cast<KHTMLPart *>(view->part());
0453     QVERIFY(part);
0454     DOM::HTMLAnchorElement anchor = part->htmlDocument().getElementsByTagName(DOM::DOMString("a")).item(0);
0455     QVERIFY(!anchor.isNull());
0456     anchor.focus();
0457     QKeyEvent ev(QKeyEvent::KeyPress, Qt::Key_Return, 0, "\n");
0458     QApplication::sendEvent(part->view(), &ev);
0459     qApp->processEvents(); // openUrlRequestDelayed
0460     QTest::qWait(0);
0461 #else
0462     QTest::mouseClick(part->view()->focusProxy(), Qt::LeftButton, Qt::KeyboardModifiers(),
0463             elementCenter(part->view()->page(), QStringLiteral("linkid")));
0464 
0465     // Check that the link opened in the 2nd view, not the first one
0466 #endif
0467     QCOMPARE(view->url().url(), origUrl.url());
0468 #ifndef TEST_KHTML
0469     QEXPECT_FAIL("", "Broken feature right now, requires URLs to be opened by konq rather than the part", Abort);
0470 #endif
0471     QTRY_COMPARE_WITH_TIMEOUT(view2->url().url(), QUrl("data:text/plain, Link target").url(), 400);
0472 }
0473 
0474 void ViewMgrTest::testPopupNewTab() // RMB, "Open in new tab"
0475 {
0476     KonqMainWindow mainWindow;
0477     openHtmlWithLink(mainWindow);
0478     KonqFrameTabs *tabs = mainWindow.viewManager()->tabContainer();
0479     QCOMPARE(tabs->currentIndex(), 0);
0480     KFileItem item(QUrl(QStringLiteral("data:text/html, hello")), QStringLiteral("text/html"), S_IFREG);
0481     mainWindow.prepareForPopupMenu(KFileItemList() << item, KParts::OpenUrlArguments(), BrowserArguments());
0482     QMetaObject::invokeMethod(&mainWindow, "slotPopupNewTab");
0483     QTest::qWait(1000);
0484     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[FF].")); // mainWindow, tab widget, two tabs
0485     QCOMPARE(KMainWindow::memberList().count(), 1);
0486     QCOMPARE(mainWindow.linkableViewsCount(), 1);
0487 
0488     if (KonqSettings::newTabsInFront()) {
0489         QCOMPARE(tabs->currentIndex(), 1);
0490     }
0491 }
0492 
0493 static void checkSecondWindowHasOneTab(bool fromPopup) // and delete it.
0494 {
0495     QTRY_COMPARE(KMainWindow::memberList().count(), 2);
0496     QScopedPointer<KonqMainWindow> newWindow(qobject_cast<KonqMainWindow *>(KMainWindow::memberList().last()));
0497     QVERIFY(newWindow.data());
0498     QTRY_COMPARE(DebugFrameVisitor::inspect(newWindow.data()), QString("MT[F].")); // mainWindow, tab widget, one tab
0499     QTabWidget *tabWidget = newWindow->findChild<QTabWidget *>();
0500     QVERIFY(tabWidget);
0501     // The location bar shouldn't get focus (#208821)
0502     QTRY_VERIFY(newWindow->focusWidget());
0503     QTRY_VERIFY_WITH_TIMEOUT(tabWidget->focusWidget(), 200);
0504     QCOMPARE(newWindow->focusWidget()->metaObject()->className(), tabWidget->focusWidget()->metaObject()->className());
0505 }
0506 
0507 void ViewMgrTest::testPopupNewWindow() // RMB, "Open new window"
0508 {
0509     KonqMainWindow mainWindow;
0510     openHtmlWithLink(mainWindow);
0511     KFileItem item(QUrl(QStringLiteral("data:text/html, hello")), QStringLiteral("text/html"), S_IFREG);
0512     mainWindow.prepareForPopupMenu(KFileItemList() << item, KParts::OpenUrlArguments(), BrowserArguments());
0513     QMetaObject::invokeMethod(&mainWindow, "slotPopupNewWindow");
0514     QTRY_COMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[F].")); // mainWindow, tab widget, one tab
0515     QVERIFY(KMainWindow::memberList().last() != &mainWindow);
0516     checkSecondWindowHasOneTab(true);
0517 }
0518 
0519 void ViewMgrTest::testCtrlClickOnLink()
0520 {
0521     KonqMainWindow mainWindow;
0522     openHtmlWithLink(mainWindow);
0523     KonqFrameTabs *tabs = mainWindow.viewManager()->tabContainer();
0524     KonqView *view = mainWindow.currentView();
0525     mainWindow.show();
0526     qDebug() << "CLICKING NOW";
0527     QTest::mouseClick(partWidget(view), Qt::LeftButton, Qt::ControlModifier, QPoint(10, 10));
0528     QTest::qWait(100);
0529     KonqView *newView = nullptr;
0530     // Expected behavior for Ctrl+click:
0531     //  new tab, if mmbOpensTab
0532     //  new window, if !mmbOpensTab
0533     //  (this code is called for both cases)
0534     if (KonqSettings::mmbOpensTab()) {
0535         QCOMPARE(KMainWindow::memberList().count(), 1);
0536         QTRY_COMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[FF].")); // mainWindow, tab widget, two tabs
0537         if (KonqSettings::newTabsInFront()) { // when called by sameTestsWithNewTabsInFront
0538             QCOMPARE(tabs->currentIndex(), 1);
0539             QVERIFY(mainWindow.currentView() != view);
0540             QVERIFY(mainWindow.viewManager()->activePart() != view->part());
0541         } else {                              // the default case
0542             QCOMPARE(tabs->currentIndex(), 0);
0543             QCOMPARE(mainWindow.currentView(), view);
0544             QCOMPARE(mainWindow.viewManager()->activePart(), view->part());
0545         }
0546         KonqFrame *newFrame = dynamic_cast<KonqFrame *>(mainWindow.viewManager()->tabContainer()->tabAt(1));
0547         QVERIFY(newFrame);
0548         newView = newFrame->activeChildView();
0549         QVERIFY(newView);
0550         //QVERIFY(newView->supportsMimeType("text/plain"));
0551     } else {
0552         QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[F].")); // mainWindow, tab widget, one tab
0553         checkSecondWindowHasOneTab(false);
0554     }
0555 }
0556 
0557 void ViewMgrTest::sameTestsWithNewTabsInFront()
0558 {
0559     // Redo testCtrlClickOnLink,
0560     // but with the option "NewTabsInFront" set to true.
0561     QVERIFY(!KonqSettings::newTabsInFront()); // default setting = false
0562     KonqSettings::setNewTabsInFront(true);
0563     testPopupNewTab();
0564     testCtrlClickOnLink();
0565     KonqSettings::setNewTabsInFront(false);
0566 }
0567 
0568 void ViewMgrTest::sameTestsWithMmbOpenTabsFalse()
0569 {
0570     // Redo testPopupNewTab, testPopupNewWindow and testCtrlClickOnLink,
0571     // but as if the user (e.g. Pino) had disabled the setting "Open links in new tabs".
0572     KonqSettings::setMmbOpensTab(false);
0573     testPopupNewTab();
0574     testPopupNewWindow();
0575     testCtrlClickOnLink();
0576     KonqSettings::setMmbOpensTab(true);
0577 }
0578 
0579 static void openTabWithTitle(KonqMainWindow &mainWindow, const QString &title, KonqView *&view)
0580 {
0581     KonqViewManager *viewManager = mainWindow.viewManager();
0582     view = viewManager->addTab(QStringLiteral("text/html"));
0583     QVERIFY(view);
0584     QVERIFY(view->supportsMimeType("text/html"));
0585     QVERIFY(!view->supportsMimeType("text/plain"));
0586     // correct since it's a subclass of text/html, khtml can display it
0587     QVERIFY(view->supportsMimeType("application/x-netscape-bookmarks"));
0588     // Tab caption test
0589     view->openUrl(QUrl(QStringLiteral("data:text/html, <title>") + title + QStringLiteral("</title>")), QStringLiteral("http://loc.bar.url"));
0590     QSignalSpy spyCompleted(view, &KonqView::viewCompleted);
0591     QVERIFY(spyCompleted.wait(10000));
0592     QCOMPARE(view->caption(), title);
0593     QCOMPARE(view->locationBarURL(), QString("http://loc.bar.url"));
0594 }
0595 
0596 void ViewMgrTest::testAddTabs()
0597 {
0598     KonqMainWindow mainWindow;
0599     KonqViewManager *viewManager = mainWindow.viewManager();
0600 
0601     KonqView *view = viewManager->createFirstView(QStringLiteral("text/html"), QStringLiteral("webenginepart"));
0602     QVERIFY(view);
0603     // The testcase was "konqueror www.kde.org www.google.fr bugs.kde.org www.cuil.com www.davidfaure.fr"
0604     const QStringList titles {
0605         "K Desktop Environment - Be free",
0606         "Google",
0607         "KDE Bug Tracking System",
0608         "Cuil",
0609         "http://www.davidfaure.fr/" };
0610     view->setCaption(titles.at(0));
0611 
0612     KTabWidget *tabWidget = mainWindow.findChild<KTabWidget *>();
0613     QVERIFY(tabWidget);
0614     KonqView *viewTab1, *viewTab2, *viewTab3, *viewTab4;
0615     openTabWithTitle(mainWindow, titles.at(1), viewTab1);
0616     openTabWithTitle(mainWindow, titles.at(2), viewTab2);
0617     openTabWithTitle(mainWindow, titles.at(3), viewTab3);
0618     openTabWithTitle(mainWindow, titles.at(4), viewTab4);
0619     for (int i = 0; i < titles.count(); ++i) {
0620         QCOMPARE(tabWidget->tabText(i), QString(titles.at(i)));
0621     }
0622     QPointer<KonqView> viewTab2Pointer(viewTab2);
0623     QPointer<KParts::ReadOnlyPart> tab2PartPointer(viewTab2->part());
0624 
0625     // Ensure tabwidget has a nice size
0626     mainWindow.resize(1000, 699);
0627     sendAllPendingResizeEvents(&mainWindow);
0628 
0629     // Remove active tab (#170470)
0630     tabWidget->setCurrentIndex(2);
0631     KonqFrameBase *frame = dynamic_cast<KonqFrameBase *>(viewManager->tabContainer()->currentWidget());
0632     QVERIFY(frame);
0633     viewManager->removeTab(frame);
0634     QVERIFY(viewTab2Pointer.isNull()); // check the view got deleted
0635     QVERIFY(tab2PartPointer.isNull()); // check the part got deleted too, since pino is a non-believer :)
0636     QList<int> expectedTitles{0, 1, 3, 4};
0637     for (int i = 0; i < expectedTitles.count(); ++i) {
0638         QCOMPARE(tabWidget->tabText(i), titles.at(expectedTitles[i]));
0639     }
0640     for (int i = 0; i < expectedTitles.count(); ++i) {
0641         QCOMPARE(tabWidget->QTabWidget::tabText(i).left(10), titles.at(expectedTitles[i]).left(10));
0642     }
0643 
0644     tabWidget->removeTab(0);
0645     expectedTitles.removeAt(0);
0646     for (int i = 0; i < expectedTitles.count(); ++i) {
0647         QCOMPARE(tabWidget->tabText(i), QString(titles.at(expectedTitles[i])));
0648     }
0649 }
0650 
0651 void ViewMgrTest::testDuplicateTab()
0652 {
0653     KonqMainWindow mainWindow;
0654     KonqViewManager *viewManager = mainWindow.viewManager();
0655     /*KonqView* view =*/ viewManager->createFirstView(QStringLiteral("text/html"), QStringLiteral("webenginepart"));
0656     viewManager->duplicateTab(0); // should return a KonqFrameBase?
0657 
0658     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[FF]."));   // mainWindow, tab widget, two tabs
0659     // TODO check serviceType and serviceName of the new view
0660 }
0661 
0662 void ViewMgrTest::testDuplicateSplittedTab()
0663 {
0664     KonqMainWindow mainWindow;
0665     KonqViewManager *viewManager = mainWindow.viewManager();
0666     KonqView *view = viewManager->createFirstView(QStringLiteral("text/html"), QStringLiteral("webenginepart"));
0667     KonqView *view2 = viewManager->splitView(view, Qt::Vertical);
0668     QVERIFY(view2);
0669     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[C(FF)]."));   // mainWindow, tab widget, one splitter, two frames
0670 
0671     KonqFrameContainer *container = static_cast<KonqFrameContainer *>(view->frame()->parentContainer());
0672     QVERIFY(container);
0673     QCOMPARE(container->parentContainer()->frameType(), KonqFrameBase::Tabs);
0674 
0675     viewManager->duplicateTab(0); // TODO shouldn't it return a KonqFrameBase?
0676     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[C(FF)C(FF)]."));   // mainWindow, tab widget, two tabs
0677     QCOMPARE(mainWindow.linkableViewsCount(), 2);
0678 
0679     // While we're here, let's test Ctrl+Tab navigation
0680     view->setProperty("num", 0);
0681     view2->setProperty("num", 1);
0682     KonqFrameTabs *tabs = viewManager->tabContainer();
0683     KonqFrameBase *tab2base = tabs->tabAt(1);
0684     QVERIFY(tab2base->isContainer());
0685     KonqFrameContainer *tab2 = dynamic_cast<KonqFrameContainer *>(tab2base);
0686     QVERIFY(tab2);
0687     KonqView *view3 = tab2->firstChild()->activeChildView();
0688     QVERIFY(view3);
0689     KonqView *view4 = tab2->secondChild()->activeChildView();
0690     QVERIFY(view4);
0691     QVERIFY(view3 != view);
0692     QVERIFY(view4 != view2);
0693     view3->setProperty("num", 2);
0694     view4->setProperty("num", 3);
0695     QCOMPARE(mainWindow.currentView()->property("num").toInt(), 3);
0696     QCOMPARE(tabs->currentIndex(), 1);
0697     QVERIFY(mainWindow.focusWidget());
0698     QTest::keyClick(mainWindow.focusWidget(), Qt::Key_Tab, Qt::ControlModifier);
0699     QCOMPARE(mainWindow.currentView()->property("num").toInt(), 0);
0700     QCOMPARE(tabs->currentIndex(), 0);
0701     QTest::keyClick(mainWindow.focusWidget(), Qt::Key_Tab, Qt::ControlModifier);
0702     QCOMPARE(mainWindow.currentView()->property("num").toInt(), 1);
0703     QCOMPARE(tabs->currentIndex(), 0);
0704     QTest::keyClick(mainWindow.focusWidget(), Qt::Key_Tab, Qt::ControlModifier);
0705     QCOMPARE(mainWindow.currentView()->property("num").toInt(), 2);
0706     QCOMPARE(tabs->currentIndex(), 1);
0707     QTest::keyClick(mainWindow.focusWidget(), Qt::Key_Tab, Qt::ControlModifier);
0708     QCOMPARE(mainWindow.currentView()->property("num").toInt(), 3);
0709     QCOMPARE(tabs->currentIndex(), 1);
0710 
0711     viewManager->removeTab(container);
0712     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[C(FF)]."));   // mainWindow, tab widget, one tab
0713     QCOMPARE(mainWindow.linkableViewsCount(), 2);
0714 }
0715 
0716 // Like in https://bugs.kde.org/show_bug.cgi?id=153533,
0717 // where the part deletes itself.
0718 void ViewMgrTest::testDeletePartInTab()
0719 {
0720     QPointer<KonqMainWindow> mainWindow = new KonqMainWindow;
0721     QVERIFY(mainWindow->testAttribute(Qt::WA_DeleteOnClose));
0722     KonqViewManager *viewManager = mainWindow->viewManager();
0723     QPointer<KonqView> view = viewManager->createFirstView(QStringLiteral("text/html"), QStringLiteral("webenginepart"));
0724     QVERIFY(!view.isNull());
0725     QPointer<QWidget> partWidget = view->part()->widget();
0726 
0727     QPointer<KonqView> viewTab2 = viewManager->addTab(QStringLiteral("text/html"));
0728     QPointer<QWidget> partWidget2 = viewTab2->part()->widget();
0729     QVERIFY(!viewTab2.isNull());
0730     QCOMPARE(DebugFrameVisitor::inspect(mainWindow), QString("MT[FF]."));   // mainWindow, tab widget, two tabs
0731 
0732     delete viewTab2->part();
0733     QVERIFY(viewTab2.isNull());
0734     QVERIFY(partWidget2.isNull());
0735     QCOMPARE(DebugFrameVisitor::inspect(mainWindow), QString("MT[F]."));   // mainWindow, tab widget, one tab
0736 
0737     delete view->part();
0738     QVERIFY(view.isNull());
0739     QVERIFY(partWidget.isNull());
0740     qApp->sendPostedEvents(nullptr, QEvent::DeferredDelete);
0741     QVERIFY(mainWindow.isNull());
0742 }
0743 
0744 void ViewMgrTest::testSaveProfile()
0745 {
0746     KonqMainWindow mainWindow;
0747     const QUrl url(QStringLiteral("data:text/html, <p>Hello World</p>"));
0748     mainWindow.openUrl(nullptr, url, QStringLiteral("text/html"));
0749     KonqViewManager *viewManager = mainWindow.viewManager();
0750     KonqView *view2 = viewManager->addTab(QStringLiteral("text/html"));
0751     const QUrl url2(QStringLiteral("data:text/html, <p>view2</p>"));
0752     view2->openUrl(url2, QStringLiteral("2"));
0753     QTabWidget *tabWidget = mainWindow.findChild<QTabWidget *>();
0754     QVERIFY(tabWidget);
0755 
0756     // Save a profile with two tabs (via KonqSessionManager)
0757     KonqSessionManager *sessionMgr = KonqSessionManager::self();
0758     const QString filePath = QDir::currentPath() + "unittest_profile";
0759     sessionMgr->saveCurrentSessionToFile(filePath);
0760     QVERIFY(QFile::exists(filePath));
0761 
0762     {
0763         KConfig cfg(filePath, KConfig::SimpleConfig);
0764         KConfigGroup profileGroup(&cfg, "Window0");
0765         QCOMPARE(profileGroup.readEntry("RootItem"), QString("Tabs0"));
0766         QCOMPARE(profileGroup.readEntry("Tabs0_Children"), QString("ViewT0,ViewT1"));
0767         QCOMPARE(profileGroup.readEntry("HistoryItemViewT0_0Url"), url.url());
0768         QCOMPARE(profileGroup.readEntry("HistoryItemViewT1_0Url"), url2.url());
0769     }
0770 
0771     // Now close a tab and save again - to check that the stuff from the old
0772     // tab isn't lying around.
0773     viewManager->removeTab(view2->frame());
0774     sessionMgr->saveCurrentSessionToFile(filePath);
0775     {
0776         KConfig cfg(filePath, KConfig::SimpleConfig);
0777         KConfigGroup profileGroup(&cfg, "Window0");
0778         QCOMPARE(profileGroup.readEntry("RootItem"), QString("Tabs0"));
0779         QCOMPARE(profileGroup.readEntry("Tabs0_Children"), QString("ViewT0"));
0780         QCOMPARE(profileGroup.readEntry("HistoryItemViewT0_0Url"), url.url());
0781         QVERIFY(!profileGroup.hasKey("HistoryItemViewT1_0Url"));
0782     }
0783     QFile::remove(filePath);
0784 }
0785 
0786 void ViewMgrTest::testDuplicateWindow()
0787 {
0788     KonqMainWindow mainWindow;
0789     mainWindow.openUrl(nullptr, QUrl(QStringLiteral("data:text/html, <p>Hello World</p>")), QStringLiteral("text/html"));
0790     KonqViewManager *viewManager = mainWindow.viewManager();
0791     KonqView *viewTab2 = viewManager->addTab(QStringLiteral("text/html"));
0792     KonqView *splitted = viewManager->splitView(viewTab2, Qt::Horizontal);
0793     Q_UNUSED(splitted);
0794     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[FC(FF)]."));   // mainWindow, tab widget, first tab = one frame, second tab = splitter with two frames
0795     QScopedPointer<KonqMainWindow> secondWindow(viewManager->duplicateWindow());
0796     QCOMPARE(DebugFrameVisitor::inspect(secondWindow.data()), QString("MT[FC(FF)]."));   // mainWindow, tab widget, first tab = one frame, second tab = splitter with two frames
0797 }
0798 
0799 void ViewMgrTest::testCloseOtherTabs()
0800 {
0801     KonqMainWindow mainWindow;
0802     mainWindow.openUrl(nullptr, QUrl(QStringLiteral("data:text/html, <p>Hello World</p>")), QStringLiteral("text/html"));
0803     KonqViewManager *viewManager = mainWindow.viewManager();
0804     QTabWidget *tabWidget = mainWindow.findChild<QTabWidget *>();
0805     QVERIFY(tabWidget);
0806     QVERIFY(tabWidget->focusWidget());
0807     QCOMPARE(mainWindow.focusWidget()->metaObject()->className(), tabWidget->focusWidget()->metaObject()->className());
0808     viewManager->addTab(QStringLiteral("text/html"));
0809     KonqView *viewTab2 = viewManager->addTab(QStringLiteral("text/html"));
0810     viewManager->splitView(viewTab2, Qt::Horizontal);
0811     viewManager->addTab(QStringLiteral("text/html"));
0812     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[FFC(FF)F]."));   // mainWindow, tab widget, first tab = one frame, second tab = one frame, third tab = splitter with two frames, fourth tab = one frame
0813     QCOMPARE(tabWidget->count(), 4);
0814     tabWidget->setCurrentIndex(2);
0815     QCOMPARE(mainWindow.linkableViewsCount(), 2);
0816     tabWidget->setCurrentIndex(3);
0817     QCOMPARE(mainWindow.linkableViewsCount(), 1);
0818     // Switching to an empty tab -> focus goes to location bar (#84867)
0819     QEXPECT_FAIL("", "Known bug with unknown causes. Worked around it with commit 78f47b4d4ce97f7ff0278b16c04182e7d80c8dba", Continue);
0820     QCOMPARE(mainWindow.focusWidget()->metaObject()->className(), "KonqCombo");
0821 
0822     // Check that removeOtherTabs deals with split views correctly
0823     mainWindow.viewManager()->removeOtherTabs(2);
0824     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[C(FF)]."));   // mainWindow, tab widget, first tab = splitter with two frames
0825 }
0826 
0827 void ViewMgrTest::testCloseTabsFast() // #210551/#150162
0828 {
0829     KonqMainWindow mainWindow;
0830     mainWindow.openUrl(nullptr, QUrl(QStringLiteral("data:text/html, <p>Hello World</p>")), QStringLiteral("text/html"));
0831     KonqViewManager *viewManager = mainWindow.viewManager();
0832     viewManager->addTab(QStringLiteral("text/html"));
0833     viewManager->addTab(QStringLiteral("text/html"));
0834     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[FFF]."));   // mainWindow, tab widget, 3 simple tabs
0835     QTabWidget *tabWidget = mainWindow.findChild<QTabWidget *>();
0836     tabWidget->setCurrentIndex(2);
0837 
0838     mainWindow.setWorkingTab(1);
0839     mainWindow.slotRemoveTabPopup();
0840     mainWindow.slotRemoveTabPopup();
0841     QTest::qWait(100); // process the delayed invocations
0842     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[F]."));   // mainWindow, tab widget, 1 tab left
0843 }
0844 
0845 void ViewMgrTest::testBrowserArgumentsNewTab()
0846 {
0847     KonqMainWindow mainWindow;
0848     mainWindow.openUrl(nullptr, QUrl(QStringLiteral("data:text/html, <p>Hello World</p>")), QStringLiteral("text/html"));
0849     KParts::OpenUrlArguments urlArgs;
0850     BrowserArguments browserArgs;
0851     browserArgs.setNewTab(true);
0852     KonqView *view = mainWindow.currentView();
0853     BrowserExtension *ext = qobject_cast<BrowserExtension *>(view->browserExtension());
0854     QVERIFY(ext);
0855 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0856     emit ext->openUrlRequest(QUrl(QStringLiteral("data:text/html, <p>Second tab test</p>")), urlArgs, browserArgs);
0857 #else
0858     emit ext->browserOpenUrlRequest(QUrl(QStringLiteral("data:text/html, <p>Second tab test</p>")), urlArgs, browserArgs);
0859 #endif
0860     QTest::qWait(5000);
0861     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[FF].")); // mainWindow, tab widget, two tabs
0862     QCOMPARE(view->url(), QUrl("data:text/html, <p>Hello World</p>"));
0863 
0864     // compare the url of the new view... how to?
0865 //    QCOMPARE(view->url(), QUrl("data:text/html, <p>Second tab test</p>"));
0866 }
0867 
0868 void ViewMgrTest::testBreakOffTab()
0869 {
0870     KonqMainWindow mainWindow;
0871     KonqViewManager *viewManager = mainWindow.viewManager();
0872     /*KonqView* firstView =*/ viewManager->createFirstView(QStringLiteral("text/html"), QStringLiteral("webenginepart"));
0873 
0874     //KonqFrameBase* tab = firstView->frame();
0875     viewManager->duplicateTab(0);
0876     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[FF]."));   // mainWindow, tab widget, two tabs
0877 
0878     // Break off a tab
0879 
0880     KonqMainWindow *mainWindow2 = viewManager->breakOffTab(0, mainWindow.size());
0881     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[F]."));   // mainWindow, one tab, one frame
0882     QCOMPARE(DebugFrameVisitor::inspect(mainWindow2), QString("MT[F]."));   // mainWindow, one tab, one frame
0883 
0884     // Verify that the new tab container has an active child and that duplicating the tab in the new window does not crash (bug 203069)
0885 
0886     QVERIFY(mainWindow2->viewManager()->tabContainer()->activeChild());
0887     mainWindow2->viewManager()->duplicateTab(0);
0888     QCOMPARE(DebugFrameVisitor::inspect(mainWindow2), QString("MT[FF]."));   // mainWindow, tab widget, two tabs
0889 
0890     delete mainWindow2;
0891 
0892     // Now split the remaining view, duplicate the tab and verify that breaking off a split tab does not crash (bug 174292).
0893     // Also check that the tab container of the new main window has an active child.
0894 
0895     KonqView *view = mainWindow.activeChildView();
0896     viewManager->splitView(view, Qt::Vertical);
0897     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[C(FF)]."));   // mainWindow, tab widget, one splitter, two frames
0898     // KonqFrameContainerBase* container = view->frame()->parentContainer();
0899     viewManager->duplicateTab(0);
0900     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[C(FF)C(FF)]."));   // mainWindow, tab widget, two tabs with split views
0901     mainWindow2 = viewManager->breakOffTab(0, mainWindow.size());
0902     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[C(FF)]."));   // mainWindow, tab widget, one splitter, two frames
0903     QCOMPARE(DebugFrameVisitor::inspect(mainWindow2), QString("MT[C(FF)]."));   // mainWindow, tab widget, one splitter, two frames
0904     QVERIFY(mainWindow2->viewManager()->tabContainer()->activeChild());
0905 
0906     delete mainWindow2;
0907 }
0908 
0909 void ViewMgrTest::moveTabLeft()
0910 {
0911     KonqMainWindow mainWindow;
0912     mainWindow.openUrl(nullptr, QUrl(QStringLiteral("data:text/html, <p>Hello World</p>")), QStringLiteral("text/html"));
0913     KonqViewManager *viewManager = mainWindow.viewManager();
0914     KonqView *view1 = viewManager->addTab(QStringLiteral("text/html"));
0915     view1->openUrl(QUrl(QStringLiteral("data:text/html, <p>view1</p>")), QStringLiteral("1"));
0916     KonqView *view2 = viewManager->addTab(QStringLiteral("text/html"));
0917     view2->openUrl(QUrl(QStringLiteral("data:text/html, <p>view2</p>")), QStringLiteral("2"));
0918     QCOMPARE(DebugFrameVisitor::inspect(&mainWindow), QString("MT[FFF]."));   // mainWindow, tab widget, 3 simple tabs
0919     QTabWidget *tabWidget = mainWindow.findChild<QTabWidget *>();
0920     tabWidget->setCurrentIndex(2);
0921     view2->part()->widget()->setFocus();
0922     //qDebug() << mainWindow.focusWidget() << view2->part()->widget()->focusWidget();
0923     QCOMPARE(mainWindow.focusWidget(), view2->part()->widget()->focusWidget());
0924     viewManager->moveTabBackward();
0925     // Now we should have the views (tabs) in the order 0, 2, 1
0926     QList<KonqView *> views = KonqViewCollector::collect(&mainWindow);
0927     QCOMPARE(views[1], view2);
0928     QCOMPARE(views[2], view1);
0929     QCOMPARE(tabWidget->currentIndex(), 1);
0930     QCOMPARE(mainWindow.currentView(), view2);
0931     qDebug() << mainWindow.focusWidget() << view2->part()->widget()->focusWidget();
0932     // the focus should stay with that view (#208821)
0933     QCOMPARE(mainWindow.focusWidget()->metaObject()->className(), view2->part()->widget()->focusWidget()->metaObject()->className());
0934     QCOMPARE(mainWindow.focusWidget(), view2->part()->widget()->focusWidget());
0935 }
0936