File indexing completed on 2024-05-12 09:51:09
0001 /* 0002 * SPDX-FileCopyrightText: 2017 Elvis Angelaccio <elvis.angelaccio@kde.org> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "dolphinmainwindow.h" 0008 #include "dolphinnewfilemenu.h" 0009 #include "dolphintabpage.h" 0010 #include "dolphintabwidget.h" 0011 #include "dolphinviewcontainer.h" 0012 #include "kitemviews/kitemlistcontainer.h" 0013 #include "testdir.h" 0014 0015 #include <KActionCollection> 0016 0017 #include <QAccessible> 0018 #include <QScopedPointer> 0019 #include <QSignalSpy> 0020 #include <QStandardPaths> 0021 #include <QTest> 0022 0023 #include <set> 0024 0025 class DolphinMainWindowTest : public QObject 0026 { 0027 Q_OBJECT 0028 0029 private Q_SLOTS: 0030 void initTestCase(); 0031 void init(); 0032 void testClosingTabsWithSearchBoxVisible(); 0033 void testActiveViewAfterClosingSplitView_data(); 0034 void testActiveViewAfterClosingSplitView(); 0035 void testUpdateWindowTitleAfterClosingSplitView(); 0036 void testUpdateWindowTitleAfterChangingSplitView(); 0037 void testOpenInNewTabTitle(); 0038 void testNewFileMenuEnabled_data(); 0039 void testNewFileMenuEnabled(); 0040 void testWindowTitle_data(); 0041 void testWindowTitle(); 0042 void testPlacesPanelWidthResistance(); 0043 void testGoActions(); 0044 void testOpenFiles(); 0045 void testAccessibilityAncestorTree(); 0046 void cleanupTestCase(); 0047 0048 private: 0049 QScopedPointer<DolphinMainWindow> m_mainWindow; 0050 }; 0051 0052 void DolphinMainWindowTest::initTestCase() 0053 { 0054 QStandardPaths::setTestModeEnabled(true); 0055 } 0056 0057 void DolphinMainWindowTest::init() 0058 { 0059 m_mainWindow.reset(new DolphinMainWindow()); 0060 } 0061 0062 // See https://bugs.kde.org/show_bug.cgi?id=379135 0063 void DolphinMainWindowTest::testClosingTabsWithSearchBoxVisible() 0064 { 0065 m_mainWindow->openDirectories({QUrl::fromLocalFile(QDir::homePath())}, false); 0066 m_mainWindow->show(); 0067 // Without this call the searchbox doesn't get FocusIn events. 0068 QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data())); 0069 QVERIFY(m_mainWindow->isVisible()); 0070 0071 auto tabWidget = m_mainWindow->findChild<DolphinTabWidget *>("tabWidget"); 0072 QVERIFY(tabWidget); 0073 0074 // Show search box on first tab. 0075 tabWidget->currentTabPage()->activeViewContainer()->setSearchModeEnabled(true); 0076 0077 tabWidget->openNewActivatedTab(QUrl::fromLocalFile(QDir::homePath())); 0078 QCOMPARE(tabWidget->count(), 2); 0079 0080 // Triggers the crash in bug #379135. 0081 tabWidget->closeTab(); 0082 QCOMPARE(tabWidget->count(), 1); 0083 } 0084 0085 void DolphinMainWindowTest::testActiveViewAfterClosingSplitView_data() 0086 { 0087 QTest::addColumn<bool>("closeLeftView"); 0088 0089 QTest::newRow("close left view") << true; 0090 QTest::newRow("close right view") << false; 0091 } 0092 0093 void DolphinMainWindowTest::testActiveViewAfterClosingSplitView() 0094 { 0095 m_mainWindow->openDirectories({QUrl::fromLocalFile(QDir::homePath())}, false); 0096 m_mainWindow->show(); 0097 QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data())); 0098 QVERIFY(m_mainWindow->isVisible()); 0099 0100 auto tabWidget = m_mainWindow->findChild<DolphinTabWidget *>("tabWidget"); 0101 QVERIFY(tabWidget); 0102 QVERIFY(tabWidget->currentTabPage()->primaryViewContainer()); 0103 QVERIFY(!tabWidget->currentTabPage()->secondaryViewContainer()); 0104 0105 // Open split view. 0106 m_mainWindow->actionCollection()->action(QStringLiteral("split_view"))->trigger(); 0107 QVERIFY(tabWidget->currentTabPage()->splitViewEnabled()); 0108 QVERIFY(tabWidget->currentTabPage()->secondaryViewContainer()); 0109 0110 // Make sure the right view is the active one. 0111 auto leftViewContainer = tabWidget->currentTabPage()->primaryViewContainer(); 0112 auto rightViewContainer = tabWidget->currentTabPage()->secondaryViewContainer(); 0113 QVERIFY(!leftViewContainer->isActive()); 0114 QVERIFY(rightViewContainer->isActive()); 0115 0116 QFETCH(bool, closeLeftView); 0117 if (closeLeftView) { 0118 // Activate left view. 0119 leftViewContainer->setActive(true); 0120 QVERIFY(leftViewContainer->isActive()); 0121 QVERIFY(!rightViewContainer->isActive()); 0122 0123 // Close left view. The secondary view (which was on the right) will become the primary one and must be active. 0124 m_mainWindow->actionCollection()->action(QStringLiteral("split_view"))->trigger(); 0125 QVERIFY(!leftViewContainer->isActive()); 0126 QVERIFY(rightViewContainer->isActive()); 0127 QCOMPARE(rightViewContainer, tabWidget->currentTabPage()->activeViewContainer()); 0128 } else { 0129 // Close right view. The left view will become active. 0130 m_mainWindow->actionCollection()->action(QStringLiteral("split_view"))->trigger(); 0131 QVERIFY(leftViewContainer->isActive()); 0132 QVERIFY(!rightViewContainer->isActive()); 0133 QCOMPARE(leftViewContainer, tabWidget->currentTabPage()->activeViewContainer()); 0134 } 0135 } 0136 0137 // Test case for bug #385111 0138 void DolphinMainWindowTest::testUpdateWindowTitleAfterClosingSplitView() 0139 { 0140 m_mainWindow->openDirectories({QUrl::fromLocalFile(QDir::homePath())}, false); 0141 m_mainWindow->show(); 0142 QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data())); 0143 QVERIFY(m_mainWindow->isVisible()); 0144 0145 auto tabWidget = m_mainWindow->findChild<DolphinTabWidget *>("tabWidget"); 0146 QVERIFY(tabWidget); 0147 QVERIFY(tabWidget->currentTabPage()->primaryViewContainer()); 0148 QVERIFY(!tabWidget->currentTabPage()->secondaryViewContainer()); 0149 0150 // Open split view. 0151 m_mainWindow->actionCollection()->action(QStringLiteral("split_view"))->trigger(); 0152 QVERIFY(tabWidget->currentTabPage()->splitViewEnabled()); 0153 QVERIFY(tabWidget->currentTabPage()->secondaryViewContainer()); 0154 0155 // Make sure the right view is the active one. 0156 auto leftViewContainer = tabWidget->currentTabPage()->primaryViewContainer(); 0157 auto rightViewContainer = tabWidget->currentTabPage()->secondaryViewContainer(); 0158 QVERIFY(!leftViewContainer->isActive()); 0159 QVERIFY(rightViewContainer->isActive()); 0160 0161 // Activate left view. 0162 leftViewContainer->setActive(true); 0163 QVERIFY(leftViewContainer->isActive()); 0164 QVERIFY(!rightViewContainer->isActive()); 0165 0166 // Close split view. The secondary view (which was on the right) will become the primary one and must be active. 0167 m_mainWindow->actionCollection()->action(QStringLiteral("split_view"))->trigger(); 0168 QVERIFY(!leftViewContainer->isActive()); 0169 QVERIFY(rightViewContainer->isActive()); 0170 QCOMPARE(rightViewContainer, tabWidget->currentTabPage()->activeViewContainer()); 0171 0172 // Change URL and make sure we emit the currentUrlChanged signal (which triggers the window title update). 0173 QSignalSpy currentUrlChangedSpy(tabWidget, &DolphinTabWidget::currentUrlChanged); 0174 tabWidget->currentTabPage()->activeViewContainer()->setUrl(QUrl::fromLocalFile(QDir::rootPath())); 0175 QCOMPARE(currentUrlChangedSpy.count(), 1); 0176 } 0177 0178 // Test case for bug #402641 0179 void DolphinMainWindowTest::testUpdateWindowTitleAfterChangingSplitView() 0180 { 0181 m_mainWindow->openDirectories({QUrl::fromLocalFile(QDir::homePath())}, false); 0182 m_mainWindow->show(); 0183 QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data())); 0184 QVERIFY(m_mainWindow->isVisible()); 0185 0186 auto tabWidget = m_mainWindow->findChild<DolphinTabWidget *>("tabWidget"); 0187 QVERIFY(tabWidget); 0188 0189 // Open split view. 0190 m_mainWindow->actionCollection()->action(QStringLiteral("split_view"))->trigger(); 0191 QVERIFY(tabWidget->currentTabPage()->splitViewEnabled()); 0192 0193 auto leftViewContainer = tabWidget->currentTabPage()->primaryViewContainer(); 0194 auto rightViewContainer = tabWidget->currentTabPage()->secondaryViewContainer(); 0195 0196 // Store old window title. 0197 const auto oldTitle = m_mainWindow->windowTitle(); 0198 0199 // Change URL in the right view and make sure the title gets updated. 0200 rightViewContainer->setUrl(QUrl::fromLocalFile(QDir::rootPath())); 0201 QVERIFY(m_mainWindow->windowTitle() != oldTitle); 0202 0203 // Activate back the left view and check whether the old title gets restored. 0204 leftViewContainer->setActive(true); 0205 QCOMPARE(m_mainWindow->windowTitle(), oldTitle); 0206 } 0207 0208 // Test case for bug #397910 0209 void DolphinMainWindowTest::testOpenInNewTabTitle() 0210 { 0211 m_mainWindow->openDirectories({QUrl::fromLocalFile(QDir::homePath())}, false); 0212 m_mainWindow->show(); 0213 QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data())); 0214 QVERIFY(m_mainWindow->isVisible()); 0215 0216 auto tabWidget = m_mainWindow->findChild<DolphinTabWidget *>("tabWidget"); 0217 QVERIFY(tabWidget); 0218 0219 tabWidget->openNewTab(QUrl::fromLocalFile(QDir::tempPath())); 0220 QCOMPARE(tabWidget->count(), 2); 0221 QVERIFY(tabWidget->tabText(0) != tabWidget->tabText(1)); 0222 if (!tabWidget->tabIcon(0).isNull() && !tabWidget->tabIcon(1).isNull()) { 0223 QCOMPARE(QStringLiteral("inode-directory"), tabWidget->tabIcon(0).name()); 0224 QCOMPARE(QStringLiteral("inode-directory"), tabWidget->tabIcon(1).name()); 0225 } 0226 } 0227 0228 void DolphinMainWindowTest::testNewFileMenuEnabled_data() 0229 { 0230 QTest::addColumn<QUrl>("activeViewUrl"); 0231 QTest::addColumn<bool>("expectedEnabled"); 0232 0233 QTest::newRow("home") << QUrl::fromLocalFile(QDir::homePath()) << true; 0234 QTest::newRow("root") << QUrl::fromLocalFile(QDir::rootPath()) << false; 0235 QTest::newRow("trash") << QUrl::fromUserInput(QStringLiteral("trash:/")) << false; 0236 } 0237 0238 void DolphinMainWindowTest::testNewFileMenuEnabled() 0239 { 0240 QFETCH(QUrl, activeViewUrl); 0241 m_mainWindow->openDirectories({activeViewUrl}, false); 0242 m_mainWindow->show(); 0243 QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data())); 0244 QVERIFY(m_mainWindow->isVisible()); 0245 0246 auto newFileMenu = m_mainWindow->findChild<DolphinNewFileMenu *>("new_menu"); 0247 QVERIFY(newFileMenu); 0248 0249 QFETCH(bool, expectedEnabled); 0250 QTRY_COMPARE(newFileMenu->isEnabled(), expectedEnabled); 0251 } 0252 0253 void DolphinMainWindowTest::testWindowTitle_data() 0254 { 0255 QTest::addColumn<QUrl>("activeViewUrl"); 0256 QTest::addColumn<QString>("expectedWindowTitle"); 0257 0258 // TODO: this test should enforce the english locale. 0259 QTest::newRow("home") << QUrl::fromLocalFile(QDir::homePath()) << QStringLiteral("Home"); 0260 QTest::newRow("home with trailing slash") << QUrl::fromLocalFile(QStringLiteral("%1/").arg(QDir::homePath())) << QStringLiteral("Home"); 0261 QTest::newRow("trash") << QUrl::fromUserInput(QStringLiteral("trash:/")) << QStringLiteral("Trash"); 0262 } 0263 0264 void DolphinMainWindowTest::testWindowTitle() 0265 { 0266 QFETCH(QUrl, activeViewUrl); 0267 m_mainWindow->openDirectories({activeViewUrl}, false); 0268 m_mainWindow->show(); 0269 QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data())); 0270 QVERIFY(m_mainWindow->isVisible()); 0271 0272 QFETCH(QString, expectedWindowTitle); 0273 QCOMPARE(m_mainWindow->windowTitle(), expectedWindowTitle); 0274 } 0275 0276 /** 0277 * The places panel will resize itself if any of the other widgets requires too much horizontal space 0278 * but a user never wants the size of the places panel to change unless they resized it themselves explicitly. 0279 */ 0280 void DolphinMainWindowTest::testPlacesPanelWidthResistance() 0281 { 0282 m_mainWindow->openDirectories({QUrl::fromLocalFile(QDir::homePath())}, false); 0283 m_mainWindow->show(); 0284 m_mainWindow->resize(800, m_mainWindow->height()); // make sure the size is sufficient so a places panel resize shouldn't be necessary. 0285 QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data())); 0286 QVERIFY(m_mainWindow->isVisible()); 0287 0288 QWidget *placesPanel = reinterpret_cast<QWidget *>(m_mainWindow->m_placesPanel); 0289 QVERIFY2(QTest::qWaitFor( 0290 [&]() { 0291 return placesPanel && placesPanel->isVisible() && placesPanel->width() > 0; 0292 }, 0293 5000), 0294 "The test couldn't be initialised properly. The places panel should be visible."); 0295 QTest::qWait(100); 0296 const int initialPlacesPanelWidth = placesPanel->width(); 0297 0298 m_mainWindow->actionCollection()->action(QStringLiteral("split_view"))->trigger(); // enable split view (starts animation) 0299 QTest::qWait(300); // wait for animation 0300 QCOMPARE(placesPanel->width(), initialPlacesPanelWidth); 0301 0302 m_mainWindow->actionCollection()->action(QStringLiteral("show_filter_bar"))->trigger(); 0303 QCOMPARE(placesPanel->width(), initialPlacesPanelWidth); 0304 0305 // Make all selection mode bars appear and test for each that this doesn't affect the places panel's width. 0306 // One of the bottom bars (SelectionMode::BottomBar::GeneralContents) only shows up when at least one item is selected so we do that before we begin iterating. 0307 m_mainWindow->actionCollection()->action(KStandardAction::name(KStandardAction::SelectAll))->trigger(); 0308 for (int selectionModeStates = SelectionMode::BottomBar::CopyContents; selectionModeStates != SelectionMode::BottomBar::RenameContents; 0309 selectionModeStates++) { 0310 const auto contents = static_cast<SelectionMode::BottomBar::Contents>(selectionModeStates); 0311 m_mainWindow->slotSetSelectionMode(true, contents); 0312 QTest::qWait(20); // give time for a paint/resize 0313 QCOMPARE(placesPanel->width(), initialPlacesPanelWidth); 0314 } 0315 0316 m_mainWindow->actionCollection()->action(KStandardAction::name(KStandardAction::Find))->trigger(); 0317 QCOMPARE(placesPanel->width(), initialPlacesPanelWidth); 0318 0319 #if HAVE_BALOO 0320 m_mainWindow->actionCollection()->action(QStringLiteral("show_information_panel"))->setChecked(true); // toggle visible 0321 QCOMPARE(placesPanel->width(), initialPlacesPanelWidth); 0322 #endif 0323 0324 #if HAVE_TERMINAL 0325 m_mainWindow->actionCollection()->action(QStringLiteral("show_terminal_panel"))->setChecked(true); // toggle visible 0326 QCOMPARE(placesPanel->width(), initialPlacesPanelWidth); 0327 #endif 0328 0329 m_mainWindow->actionCollection()->action(QStringLiteral("split_view"))->trigger(); // disable split view (starts animation) 0330 QCOMPARE(placesPanel->width(), initialPlacesPanelWidth); 0331 0332 #if HAVE_BALOO 0333 m_mainWindow->actionCollection()->action(QStringLiteral("show_information_panel"))->trigger(); // toggle invisible 0334 QCOMPARE(placesPanel->width(), initialPlacesPanelWidth); 0335 #endif 0336 0337 #if HAVE_TERMINAL 0338 m_mainWindow->actionCollection()->action(QStringLiteral("show_terminal_panel"))->trigger(); // toggle invisible 0339 QCOMPARE(placesPanel->width(), initialPlacesPanelWidth); 0340 #endif 0341 0342 m_mainWindow->showMaximized(); 0343 QCOMPARE(placesPanel->width(), initialPlacesPanelWidth); 0344 0345 QTest::qWait(300); // wait for split view closing animation 0346 QCOMPARE(placesPanel->width(), initialPlacesPanelWidth); 0347 } 0348 0349 void DolphinMainWindowTest::testGoActions() 0350 { 0351 QScopedPointer<TestDir> testDir{new TestDir()}; 0352 testDir->createDir("a"); 0353 testDir->createDir("b"); 0354 testDir->createDir("b/b-1"); 0355 testDir->createFile("b/b-2"); 0356 testDir->createDir("c"); 0357 QUrl childDirUrl(QDir::cleanPath(testDir->url().toString() + "/b")); 0358 m_mainWindow->openDirectories({childDirUrl}, false); // Open "b" dir 0359 m_mainWindow->show(); 0360 QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data())); 0361 QVERIFY(m_mainWindow->isVisible()); 0362 QVERIFY(!m_mainWindow->actionCollection()->action(KStandardAction::name(KStandardAction::Forward))->isEnabled()); 0363 0364 m_mainWindow->actionCollection()->action(KStandardAction::name(KStandardAction::Up))->trigger(); 0365 /** 0366 * Now, after going "up" in the file hierarchy (to "testDir"), the folder one has emerged from ("b") should have keyboard focus. 0367 * This is especially important when a user wants to peek into multiple folders in quick succession. 0368 */ 0369 QSignalSpy spyDirectoryLoadingCompleted(m_mainWindow->m_activeViewContainer->view(), &DolphinView::directoryLoadingCompleted); 0370 QVERIFY(spyDirectoryLoadingCompleted.wait()); 0371 QVERIFY(QTest::qWaitFor([&]() { 0372 return !m_mainWindow->actionCollection()->action(QStringLiteral("stop"))->isEnabled(); 0373 })); // "Stop" command should be disabled because it finished loading 0374 QTest::qWait(500); // Somehow the item we emerged from doesn't have keyboard focus yet if we don't wait a split second. 0375 const QUrl parentDirUrl = m_mainWindow->activeViewContainer()->url(); 0376 QVERIFY(parentDirUrl != childDirUrl); 0377 0378 // The item we just emerged from should now have keyboard focus but this doesn't necessarily mean that it is selected. 0379 // To test if it has keyboard focus, we press "Down" to select "c" below and then "Up" so the folder "b" we just emerged from is actually selected. 0380 m_mainWindow->actionCollection()->action(QStringLiteral("compact"))->trigger(); 0381 QTest::keyClick(m_mainWindow->activeViewContainer()->view()->m_container, Qt::Key::Key_Down, Qt::NoModifier); 0382 QCOMPARE(m_mainWindow->m_activeViewContainer->view()->selectedItems().count(), 1); 0383 QTest::keyClick(m_mainWindow->activeViewContainer()->view()->m_container, Qt::Key::Key_Up, Qt::NoModifier); 0384 QCOMPARE(m_mainWindow->m_activeViewContainer->view()->selectedItems().count(), 1); 0385 QTest::keyClick(m_mainWindow->activeViewContainer()->view()->m_container, Qt::Key::Key_Enter, Qt::NoModifier); 0386 QVERIFY(spyDirectoryLoadingCompleted.wait()); 0387 QCOMPARE(m_mainWindow->activeViewContainer()->url(), childDirUrl); 0388 QVERIFY(m_mainWindow->isUrlOpen(childDirUrl.toString())); 0389 0390 // Go back to the parent folder 0391 m_mainWindow->actionCollection()->action(KStandardAction::name(KStandardAction::Back))->trigger(); 0392 QVERIFY(spyDirectoryLoadingCompleted.wait()); 0393 QTest::qWait(100); // Somehow the item we emerged from doesn't have keyboard focus yet if we don't wait a split second. 0394 QCOMPARE(m_mainWindow->activeViewContainer()->url(), parentDirUrl); 0395 QVERIFY(m_mainWindow->isUrlOpen(parentDirUrl.toString())); 0396 0397 // Open a new tab for the "b" child dir and verify that this doesn't interfere with anything. 0398 QTest::keyClick(m_mainWindow->activeViewContainer()->view()->m_container, Qt::Key::Key_Enter, Qt::ControlModifier); // Open new inactive tab 0399 QVERIFY(m_mainWindow->m_tabWidget->count() == 2); 0400 QCOMPARE(m_mainWindow->activeViewContainer()->url(), parentDirUrl); 0401 QVERIFY(m_mainWindow->isUrlOpen(parentDirUrl.toString())); 0402 QVERIFY(!m_mainWindow->actionCollection()->action(QStringLiteral("undo_close_tab"))->isEnabled()); 0403 0404 // Go forward to the child folder. 0405 m_mainWindow->actionCollection()->action(KStandardAction::name(KStandardAction::Forward))->trigger(); 0406 QVERIFY(spyDirectoryLoadingCompleted.wait()); 0407 QCOMPARE(m_mainWindow->activeViewContainer()->url(), childDirUrl); 0408 QCOMPARE(m_mainWindow->m_activeViewContainer->view()->selectedItems().count(), 0); // There was no action in this view yet that would warrant a selection. 0409 0410 // Go back to the parent folder. 0411 m_mainWindow->actionCollection()->action(KStandardAction::name(KStandardAction::Back))->trigger(); 0412 QVERIFY(spyDirectoryLoadingCompleted.wait()); 0413 QTest::qWait(100); // Somehow the item we emerged from doesn't have keyboard focus yet if we don't wait a split second. 0414 QCOMPARE(m_mainWindow->activeViewContainer()->url(), parentDirUrl); 0415 QVERIFY(m_mainWindow->isUrlOpen(parentDirUrl.toString())); 0416 0417 // Close current tab and see if the "go" actions are correctly disabled in the remaining tab that was never active until now and shows the "b" dir 0418 m_mainWindow->actionCollection()->action(KStandardAction::name(KStandardAction::Close))->trigger(); // Close current tab 0419 QVERIFY(m_mainWindow->m_tabWidget->count() == 1); 0420 QCOMPARE(m_mainWindow->activeViewContainer()->url(), childDirUrl); 0421 QCOMPARE(m_mainWindow->m_activeViewContainer->view()->selectedItems().count(), 0); // There was no action in this tab yet that would warrant a selection. 0422 QVERIFY(!m_mainWindow->actionCollection()->action(KStandardAction::name(KStandardAction::Back))->isEnabled()); 0423 QVERIFY(!m_mainWindow->actionCollection()->action(KStandardAction::name(KStandardAction::Forward))->isEnabled()); 0424 QVERIFY(m_mainWindow->actionCollection()->action(QStringLiteral("undo_close_tab"))->isEnabled()); 0425 } 0426 0427 void DolphinMainWindowTest::testOpenFiles() 0428 { 0429 QScopedPointer<TestDir> testDir{new TestDir()}; 0430 QString testDirUrl(QDir::cleanPath(testDir->url().toString())); 0431 testDir->createDir("a"); 0432 testDir->createDir("a/b"); 0433 testDir->createDir("a/b/c"); 0434 testDir->createDir("a/b/c/d"); 0435 m_mainWindow->openDirectories({testDirUrl}, false); 0436 m_mainWindow->show(); 0437 0438 // We only see the unselected "a" folder in the test dir. There are no other tabs. 0439 QVERIFY(m_mainWindow->isUrlOpen(testDirUrl)); 0440 QVERIFY(m_mainWindow->isItemVisibleInAnyView(testDirUrl + "/a")); 0441 QVERIFY(!m_mainWindow->isUrlOpen(testDirUrl + "/a")); 0442 QVERIFY(!m_mainWindow->isItemVisibleInAnyView(testDirUrl + "/a/b")); 0443 QCOMPARE(m_mainWindow->m_tabWidget->count(), 1); 0444 QCOMPARE(m_mainWindow->m_tabWidget->currentIndex(), 0); 0445 QCOMPARE(m_mainWindow->m_activeViewContainer->view()->selectedItems().count(), 0); 0446 0447 // "a" is already in view, so "opening" "a" should simply select it without opening a new tab. 0448 m_mainWindow->openFiles({testDirUrl + "/a"}, false); 0449 QTRY_COMPARE(m_mainWindow->m_activeViewContainer->view()->selectedItems().count(), 1); 0450 QCOMPARE(m_mainWindow->m_tabWidget->count(), 1); 0451 QVERIFY(m_mainWindow->isItemVisibleInAnyView(testDirUrl + "/a")); 0452 0453 // "b" is not in view, so "opening" "b" should open a new active tab of the parent folder "a" and select "b" there. 0454 m_mainWindow->openFiles({testDirUrl + "/a/b"}, false); 0455 QTRY_VERIFY(m_mainWindow->isUrlOpen(testDirUrl + "/a")); 0456 QCOMPARE(m_mainWindow->m_tabWidget->count(), 2); 0457 QCOMPARE(m_mainWindow->m_tabWidget->currentIndex(), 1); 0458 QTRY_VERIFY(m_mainWindow->isItemVisibleInAnyView(testDirUrl + "/a/b")); 0459 QVERIFY2(!m_mainWindow->isUrlOpen(testDirUrl + "/a/b"), "The directory b is supposed to be visible but not open in its own tab."); 0460 QTRY_COMPARE(m_mainWindow->m_activeViewContainer->view()->selectedItems().count(), 1); 0461 0462 QVERIFY(m_mainWindow->isUrlOpen(testDirUrl)); 0463 QVERIFY(m_mainWindow->isItemVisibleInAnyView(testDirUrl + "/a")); 0464 // "a" is still in view in the first tab, so "opening" "a" should switch to the first tab and select "a" there. 0465 m_mainWindow->openFiles({testDirUrl + "/a"}, false); 0466 QCOMPARE(m_mainWindow->m_tabWidget->count(), 2); 0467 QCOMPARE(m_mainWindow->m_tabWidget->currentIndex(), 0); 0468 QVERIFY(m_mainWindow->isUrlOpen(testDirUrl)); 0469 QVERIFY(m_mainWindow->isUrlOpen(testDirUrl + "/a")); 0470 0471 // Directory "a" is already open in the second tab in which "b" is selected, so opening the directory "a" should switch to that tab. 0472 m_mainWindow->openDirectories({testDirUrl + "/a"}, false); 0473 QCOMPARE(m_mainWindow->m_tabWidget->count(), 2); 0474 QCOMPARE(m_mainWindow->m_tabWidget->currentIndex(), 1); 0475 0476 // In the details view mode directories can be expanded, which changes if openFiles() needs to open a new tab or not to open a file. 0477 m_mainWindow->actionCollection()->action(QStringLiteral("details"))->trigger(); 0478 QTRY_VERIFY(m_mainWindow->activeViewContainer()->view()->itemsExpandable()); 0479 0480 // Expand the already selected "b" with the right arrow key. This should make "c" visible. 0481 QVERIFY2(!m_mainWindow->isItemVisibleInAnyView(testDirUrl + "/a/b/c"), "The parent folder wasn't expanded yet, so c shouldn't be visible."); 0482 QTest::keyClick(m_mainWindow->activeViewContainer()->view()->m_container, Qt::Key::Key_Right); 0483 QTRY_VERIFY(m_mainWindow->isItemVisibleInAnyView(testDirUrl + "/a/b/c")); 0484 QVERIFY2(!m_mainWindow->isUrlOpen(testDirUrl + "/a/b"), "b is supposed to be expanded, however it shouldn't be open in its own tab."); 0485 QVERIFY(m_mainWindow->isUrlOpen(testDirUrl + "/a")); 0486 0487 // Switch to first tab by opening it even though it is already open. 0488 m_mainWindow->openDirectories({testDirUrl}, false); 0489 QCOMPARE(m_mainWindow->m_tabWidget->count(), 2); 0490 QCOMPARE(m_mainWindow->m_tabWidget->currentIndex(), 0); 0491 0492 // "c" is in view in the second tab because "b" is expanded there, so "opening" "c" should switch to that tab and select "c" there. 0493 m_mainWindow->openFiles({testDirUrl + "/a/b/c"}, false); 0494 QCOMPARE(m_mainWindow->m_tabWidget->count(), 2); 0495 QCOMPARE(m_mainWindow->m_tabWidget->currentIndex(), 1); 0496 QTRY_COMPARE(m_mainWindow->m_activeViewContainer->view()->selectedItems().count(), 1); 0497 QVERIFY(m_mainWindow->isUrlOpen(testDirUrl)); 0498 QVERIFY(m_mainWindow->isUrlOpen(testDirUrl + "/a")); 0499 0500 // Opening the directory "c" on the other hand will open it in a new tab even though it is already visible in the view 0501 // because openDirecories() and openFiles() serve different purposes. One opens views at urls, the other selects files within views. 0502 m_mainWindow->openDirectories({testDirUrl + "/a/b/c/d", testDirUrl + "/a/b/c"}, true); 0503 QCOMPARE(m_mainWindow->m_tabWidget->count(), 3); 0504 QCOMPARE(m_mainWindow->m_tabWidget->currentIndex(), 2); 0505 QVERIFY(m_mainWindow->m_tabWidget->currentTabPage()->splitViewEnabled()); 0506 QVERIFY(m_mainWindow->isItemVisibleInAnyView(testDirUrl + "/a/b/c")); // It should still be visible in the second tab. 0507 QTRY_COMPARE(m_mainWindow->m_activeViewContainer->view()->selectedItems().count(), 0); 0508 QVERIFY(m_mainWindow->isUrlOpen(testDirUrl + "/a/b/c/d")); 0509 QVERIFY(m_mainWindow->isUrlOpen(testDirUrl + "/a/b/c")); 0510 0511 // "c" is in view in the second tab because "b" is expanded there, 0512 // so "opening" "c" should switch to that tab even though "c" as a directory is open in the current tab. 0513 m_mainWindow->openFiles({testDirUrl + "/a/b/c"}, false); 0514 QCOMPARE(m_mainWindow->m_tabWidget->count(), 3); 0515 QCOMPARE(m_mainWindow->m_tabWidget->currentIndex(), 1); 0516 QVERIFY2(m_mainWindow->isItemVisibleInAnyView(testDirUrl + "/a/b/c/d"), "It should be visible in the secondary view of the third tab."); 0517 0518 // Select "b" and un-expand it with the left arrow key. This should make "c" invisible. 0519 m_mainWindow->openFiles({testDirUrl + "/a/b"}, false); 0520 QTest::keyClick(m_mainWindow->activeViewContainer()->view()->m_container, Qt::Key::Key_Left); 0521 QTRY_VERIFY(!m_mainWindow->isItemVisibleInAnyView(testDirUrl + "/a/b/c")); 0522 0523 // "d" is in view in the third tab in the secondary view, so "opening" "d" should select that view. 0524 m_mainWindow->openFiles({testDirUrl + "/a/b/c/d"}, false); 0525 QCOMPARE(m_mainWindow->m_tabWidget->count(), 3); 0526 QCOMPARE(m_mainWindow->m_tabWidget->currentIndex(), 2); 0527 QVERIFY(m_mainWindow->m_tabWidget->currentTabPage()->secondaryViewContainer()->isActive()); 0528 QTRY_COMPARE(m_mainWindow->m_activeViewContainer->view()->selectedItems().count(), 1); 0529 } 0530 0531 void DolphinMainWindowTest::testAccessibilityAncestorTree() 0532 { 0533 m_mainWindow->openDirectories({QUrl::fromLocalFile(QDir::homePath())}, false); 0534 m_mainWindow->show(); 0535 QVERIFY(QTest::qWaitForWindowExposed(m_mainWindow.data())); 0536 QVERIFY(m_mainWindow->isVisible()); 0537 0538 std::set<const QObject *> testedObjects; // Makes sure we stop testing if we arrive at an item that was already tested. 0539 QAccessibleInterface *accessibleInterfaceOfMainWindow = QAccessible::queryAccessibleInterface(m_mainWindow.get()); 0540 Q_CHECK_PTR(accessibleInterfaceOfMainWindow); 0541 0542 // We will do accessibility checks for every object that gets focus. Focus will be changed using the Tab key. 0543 while (qApp->focusObject() && !testedObjects.count(qApp->focusObject())) { 0544 const auto currentlyFocusedObject = qApp->focusObject(); 0545 QAccessibleInterface *accessibleInterface = QAccessible::queryAccessibleInterface(currentlyFocusedObject); 0546 0547 // The accessibleInterfaces of focused objects might themselves have children. 0548 // We go down that hierarchy as far as possible and then test the ancestor tree from there. 0549 while (accessibleInterface->childCount() > 0) { 0550 accessibleInterface = accessibleInterface->child(0); 0551 } 0552 while (accessibleInterface != accessibleInterfaceOfMainWindow) { 0553 QVERIFY2(accessibleInterface, 0554 qPrintable(QString("%1's accessibleInterface or one of its accessible children doesn't have the main window as an ancestor.") 0555 .arg(currentlyFocusedObject->metaObject()->className()))); 0556 accessibleInterface = accessibleInterface->parent(); 0557 } 0558 0559 testedObjects.insert(currentlyFocusedObject); // Add it to testedObjects so we won't test it again later. 0560 QTest::keyClick(m_mainWindow.get(), Qt::Key::Key_Tab, Qt::ShiftModifier); // ShiftModifier because the Tab cycle is currently broken going forward. 0561 } 0562 } 0563 0564 void DolphinMainWindowTest::cleanupTestCase() 0565 { 0566 m_mainWindow->showNormal(); 0567 m_mainWindow->actionCollection()->action(QStringLiteral("split_view"))->setChecked(false); // disable split view (starts animation) 0568 0569 #if HAVE_BALOO 0570 m_mainWindow->actionCollection()->action(QStringLiteral("show_information_panel"))->setChecked(false); // hide panel 0571 #endif 0572 0573 #if HAVE_TERMINAL 0574 m_mainWindow->actionCollection()->action(QStringLiteral("show_terminal_panel"))->setChecked(false); // hide panel 0575 #endif 0576 0577 // Quit Dolphin to save the hiding of panels and make sure that normal Quit doesn't crash. 0578 m_mainWindow->actionCollection()->action(KStandardAction::name(KStandardAction::Quit))->trigger(); 0579 } 0580 0581 QTEST_MAIN(DolphinMainWindowTest) 0582 0583 #include "dolphinmainwindowtest.moc"