File indexing completed on 2024-05-12 09:51:11
0001 /* 0002 * SPDX-FileCopyrightText: 2012 Frank Reininghaus <frank78ac@googlemail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kitemviews/kitemlistcontroller.h" 0008 #include "kitemviews/kfileitemlistview.h" 0009 #include "kitemviews/kfileitemmodel.h" 0010 #include "kitemviews/kitemlistcontainer.h" 0011 #include "kitemviews/kitemlistselectionmanager.h" 0012 #include "kitemviews/private/kitemlistviewlayouter.h" 0013 #include "testdir.h" 0014 0015 #include <QGraphicsSceneMouseEvent> 0016 #include <QProxyStyle> 0017 #include <QSignalSpy> 0018 #include <QStandardPaths> 0019 #include <QTest> 0020 0021 /** 0022 * \class KItemListControllerTestStyle is a proxy style for testing the 0023 * KItemListController with different style hint options, e.g. single/double 0024 * click activation. 0025 */ 0026 class KItemListControllerTestStyle : public QProxyStyle 0027 { 0028 Q_OBJECT 0029 public: 0030 KItemListControllerTestStyle(QStyle *style) 0031 : QProxyStyle(style) 0032 , m_activateItemOnSingleClick((bool)style->styleHint(SH_ItemView_ActivateItemOnSingleClick)) 0033 { 0034 } 0035 0036 void setActivateItemOnSingleClick(bool activateItemOnSingleClick) 0037 { 0038 m_activateItemOnSingleClick = activateItemOnSingleClick; 0039 } 0040 0041 bool activateItemOnSingleClick() const 0042 { 0043 return m_activateItemOnSingleClick; 0044 } 0045 0046 int styleHint(StyleHint hint, const QStyleOption *option = nullptr, const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const override 0047 { 0048 switch (hint) { 0049 case QStyle::SH_ItemView_ActivateItemOnSingleClick: 0050 return (int)activateItemOnSingleClick(); 0051 default: 0052 return QProxyStyle::styleHint(hint, option, widget, returnData); 0053 } 0054 } 0055 0056 private: 0057 bool m_activateItemOnSingleClick; 0058 }; 0059 0060 Q_DECLARE_METATYPE(KFileItemListView::ItemLayout) 0061 Q_DECLARE_METATYPE(Qt::Orientation) 0062 Q_DECLARE_METATYPE(KItemListController::SelectionBehavior) 0063 Q_DECLARE_METATYPE(KItemSet) 0064 0065 class KItemListControllerTest : public QObject 0066 { 0067 Q_OBJECT 0068 0069 private Q_SLOTS: 0070 void initTestCase(); 0071 void cleanupTestCase(); 0072 0073 void init(); 0074 void cleanup(); 0075 0076 void testKeyboardNavigation_data(); 0077 void testKeyboardNavigation(); 0078 void testMouseClickActivation(); 0079 0080 private: 0081 /** 0082 * Make sure that the number of columns in the view is equal to \a count 0083 * by changing the geometry of the container. 0084 */ 0085 void adjustGeometryForColumnCount(int count); 0086 0087 private: 0088 KFileItemListView *m_view; 0089 KItemListController *m_controller; 0090 KItemListSelectionManager *m_selectionManager; 0091 KFileItemModel *m_model; 0092 TestDir *m_testDir; 0093 KItemListContainer *m_container; 0094 KItemListControllerTestStyle *m_testStyle; 0095 }; 0096 0097 /** 0098 * This function initializes the member objects, creates the temporary files, and 0099 * shows the view on the screen on startup. This could also be done before every 0100 * single test, but this would make the time needed to run the test much larger. 0101 */ 0102 void KItemListControllerTest::initTestCase() 0103 { 0104 QStandardPaths::setTestModeEnabled(true); 0105 qRegisterMetaType<KItemSet>("KItemSet"); 0106 0107 m_testDir = new TestDir(); 0108 m_model = new KFileItemModel(); 0109 m_view = new KFileItemListView(); 0110 m_controller = new KItemListController(m_model, m_view, this); 0111 m_container = new KItemListContainer(m_controller); 0112 #ifndef QT_NO_ACCESSIBILITY 0113 m_view->setAccessibleParentsObject(m_container); 0114 #endif 0115 m_controller = m_container->controller(); 0116 m_controller->setSelectionBehavior(KItemListController::MultiSelection); 0117 m_selectionManager = m_controller->selectionManager(); 0118 m_testStyle = new KItemListControllerTestStyle(m_view->style()); 0119 m_view->setStyle(m_testStyle); 0120 0121 QStringList files; 0122 files << "a1" 0123 << "a2" 0124 << "a3" 0125 << "b1" 0126 << "c1" 0127 << "c2" 0128 << "c3" 0129 << "c4" 0130 << "c5" 0131 << "d1" 0132 << "d2" 0133 << "d3" 0134 << "d4" 0135 << "e" 0136 << "e 2" 0137 << "e 3" 0138 << "e 4" 0139 << "e 5" 0140 << "e 6" 0141 << "e 7"; 0142 0143 m_testDir->createFiles(files); 0144 m_model->loadDirectory(m_testDir->url()); 0145 QSignalSpy spyDirectoryLoadingCompleted(m_model, &KFileItemModel::directoryLoadingCompleted); 0146 QVERIFY(spyDirectoryLoadingCompleted.wait()); 0147 0148 m_container->show(); 0149 QVERIFY(QTest::qWaitForWindowExposed(m_container)); 0150 } 0151 0152 void KItemListControllerTest::cleanupTestCase() 0153 { 0154 delete m_container; 0155 m_container = nullptr; 0156 0157 delete m_testDir; 0158 m_testDir = nullptr; 0159 } 0160 0161 /** Before each test, the current item, selection, and item size are reset to the defaults. */ 0162 void KItemListControllerTest::init() 0163 { 0164 m_selectionManager->setCurrentItem(0); 0165 QCOMPARE(m_selectionManager->currentItem(), 0); 0166 0167 m_selectionManager->clearSelection(); 0168 QVERIFY(!m_selectionManager->hasSelection()); 0169 0170 const QSizeF itemSize(50, 50); 0171 m_view->setItemSize(itemSize); 0172 QCOMPARE(m_view->itemSize(), itemSize); 0173 } 0174 0175 void KItemListControllerTest::cleanup() 0176 { 0177 } 0178 0179 /** 0180 * \class KeyPress is a small helper struct that represents a key press event, 0181 * including the key and the keyboard modifiers. 0182 */ 0183 struct KeyPress { 0184 KeyPress(Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier) 0185 : m_key(key) 0186 , m_modifier(modifier) 0187 { 0188 } 0189 0190 Qt::Key m_key; 0191 Qt::KeyboardModifiers m_modifier; 0192 }; 0193 0194 /** 0195 * \class ViewState is a small helper struct that represents a certain state 0196 * of the view, including the current item, the selected items in MultiSelection 0197 * mode (in the other modes, the selection is either empty or equal to the 0198 * current item), and the information whether items were activated by the last 0199 * key press. 0200 */ 0201 struct ViewState { 0202 ViewState(int current, const KItemSet &selection, bool activated = false) 0203 : m_current(current) 0204 , m_selection(selection) 0205 , m_activated(activated) 0206 { 0207 } 0208 0209 int m_current; 0210 KItemSet m_selection; 0211 bool m_activated; 0212 }; 0213 0214 // We have to define a typedef for the pair in order to make the test compile. 0215 typedef QPair<KeyPress, ViewState> keyPressViewStatePair; 0216 Q_DECLARE_METATYPE(QList<keyPressViewStatePair>) 0217 0218 /** 0219 * This function provides the data for the actual test function 0220 * KItemListControllerTest::testKeyboardNavigation(). 0221 * It tests all possible combinations of view layouts, selection behaviors, 0222 * and enabled/disabled groupings for different column counts, and 0223 * provides a list of key presses and the states that the view should be in 0224 * after the key press event. 0225 */ 0226 void KItemListControllerTest::testKeyboardNavigation_data() 0227 { 0228 QTest::addColumn<KFileItemListView::ItemLayout>("layout"); 0229 QTest::addColumn<Qt::Orientation>("scrollOrientation"); 0230 QTest::addColumn<int>("columnCount"); 0231 QTest::addColumn<KItemListController::SelectionBehavior>("selectionBehavior"); 0232 QTest::addColumn<bool>("groupingEnabled"); 0233 QTest::addColumn<QList<QPair<KeyPress, ViewState>>>("testList"); 0234 0235 QList<KFileItemListView::ItemLayout> layoutList; 0236 QHash<KFileItemListView::ItemLayout, QString> layoutNames; 0237 layoutList.append(KFileItemListView::IconsLayout); 0238 layoutNames[KFileItemListView::IconsLayout] = "Icons"; 0239 layoutList.append(KFileItemListView::CompactLayout); 0240 layoutNames[KFileItemListView::CompactLayout] = "Compact"; 0241 layoutList.append(KFileItemListView::DetailsLayout); 0242 layoutNames[KFileItemListView::DetailsLayout] = "Details"; 0243 0244 QList<KItemListController::SelectionBehavior> selectionBehaviorList; 0245 QHash<KItemListController::SelectionBehavior, QString> selectionBehaviorNames; 0246 selectionBehaviorList.append(KItemListController::NoSelection); 0247 selectionBehaviorNames[KItemListController::NoSelection] = "NoSelection"; 0248 selectionBehaviorList.append(KItemListController::SingleSelection); 0249 selectionBehaviorNames[KItemListController::SingleSelection] = "SingleSelection"; 0250 selectionBehaviorList.append(KItemListController::MultiSelection); 0251 selectionBehaviorNames[KItemListController::MultiSelection] = "MultiSelection"; 0252 0253 QList<bool> groupingEnabledList; 0254 QHash<bool, QString> groupingEnabledNames; 0255 groupingEnabledList.append(false); 0256 groupingEnabledNames[false] = "ungrouped"; 0257 groupingEnabledList.append(true); 0258 groupingEnabledNames[true] = "grouping enabled"; 0259 0260 for (const KFileItemListView::ItemLayout &layout : layoutList) { 0261 // The following settings depend on the layout. 0262 // Note that 'columns' are actually 'rows' in 0263 // Compact layout. 0264 Qt::Orientation scrollOrientation; 0265 QList<int> columnCountList; 0266 Qt::Key nextItemKey; 0267 Qt::Key previousItemKey; 0268 Qt::Key nextRowKey; 0269 Qt::Key previousRowKey; 0270 0271 switch (layout) { 0272 case KFileItemListView::IconsLayout: 0273 scrollOrientation = Qt::Vertical; 0274 columnCountList << 1 << 3 << 5; 0275 nextItemKey = Qt::Key_Right; 0276 previousItemKey = Qt::Key_Left; 0277 nextRowKey = Qt::Key_Down; 0278 previousRowKey = Qt::Key_Up; 0279 break; 0280 case KFileItemListView::CompactLayout: 0281 scrollOrientation = Qt::Horizontal; 0282 columnCountList << 1 << 3 << 5; 0283 nextItemKey = Qt::Key_Down; 0284 previousItemKey = Qt::Key_Up; 0285 nextRowKey = Qt::Key_Right; 0286 previousRowKey = Qt::Key_Left; 0287 break; 0288 case KFileItemListView::DetailsLayout: 0289 scrollOrientation = Qt::Vertical; 0290 columnCountList << 1; 0291 nextItemKey = Qt::Key_Down; 0292 previousItemKey = Qt::Key_Up; 0293 nextRowKey = Qt::Key_Down; 0294 previousRowKey = Qt::Key_Up; 0295 break; 0296 } 0297 0298 for (int columnCount : std::as_const(columnCountList)) { 0299 for (const KItemListController::SelectionBehavior &selectionBehavior : std::as_const(selectionBehaviorList)) { 0300 for (bool groupingEnabled : std::as_const(groupingEnabledList)) { 0301 QList<QPair<KeyPress, ViewState>> testList; 0302 0303 // First, key presses which should have the same effect 0304 // for any layout and any number of columns. 0305 testList << qMakePair(KeyPress(nextItemKey), ViewState(1, KItemSet() << 1)) 0306 << qMakePair(KeyPress(Qt::Key_Return), ViewState(1, KItemSet() << 1, true)) 0307 << qMakePair(KeyPress(Qt::Key_Enter), ViewState(1, KItemSet() << 1, true)) 0308 << qMakePair(KeyPress(nextItemKey), ViewState(2, KItemSet() << 2)) 0309 << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(3, KItemSet() << 2 << 3)) 0310 << qMakePair(KeyPress(Qt::Key_Return), ViewState(3, KItemSet() << 2 << 3, true)) 0311 << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(2, KItemSet() << 2)) 0312 << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(3, KItemSet() << 2 << 3)) 0313 << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(4, KItemSet() << 2 << 3)) 0314 << qMakePair(KeyPress(Qt::Key_Return), ViewState(4, KItemSet() << 2 << 3, true)) 0315 << qMakePair(KeyPress(previousItemKey), ViewState(3, KItemSet() << 3)) 0316 << qMakePair(KeyPress(Qt::Key_Home, Qt::ShiftModifier), ViewState(0, KItemSet() << 0 << 1 << 2 << 3)) 0317 << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(1, KItemSet() << 0 << 1 << 2 << 3)) 0318 << qMakePair(KeyPress(Qt::Key_Space, Qt::ControlModifier), ViewState(1, KItemSet() << 0 << 2 << 3)) 0319 << qMakePair(KeyPress(Qt::Key_Space, Qt::ControlModifier), ViewState(1, KItemSet() << 0 << 1 << 2 << 3)) 0320 << qMakePair(KeyPress(Qt::Key_End), ViewState(19, KItemSet() << 19)) 0321 << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(18, KItemSet() << 18 << 19)) 0322 << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, KItemSet() << 0)) 0323 << qMakePair(KeyPress(Qt::Key_Space, Qt::ControlModifier), ViewState(0, KItemSet())) 0324 << qMakePair(KeyPress(Qt::Key_Enter), ViewState(0, KItemSet(), true)) 0325 << qMakePair(KeyPress(Qt::Key_Space, Qt::ControlModifier), ViewState(0, KItemSet() << 0)) 0326 << qMakePair(KeyPress(Qt::Key_Space, Qt::ControlModifier), ViewState(0, KItemSet())) 0327 << qMakePair(KeyPress(Qt::Key_Space), ViewState(0, KItemSet() << 0)) 0328 << qMakePair(KeyPress(Qt::Key_E), ViewState(13, KItemSet() << 13)) 0329 << qMakePair(KeyPress(Qt::Key_Space), ViewState(14, KItemSet() << 14)) 0330 << qMakePair(KeyPress(Qt::Key_3), ViewState(15, KItemSet() << 15)) 0331 << qMakePair(KeyPress(Qt::Key_Escape), ViewState(15, KItemSet())) 0332 << qMakePair(KeyPress(Qt::Key_E), ViewState(13, KItemSet() << 13)) 0333 << qMakePair(KeyPress(Qt::Key_E), ViewState(14, KItemSet() << 14)) 0334 << qMakePair(KeyPress(Qt::Key_E), ViewState(15, KItemSet() << 15)) 0335 << qMakePair(KeyPress(Qt::Key_Escape), ViewState(15, KItemSet())) 0336 << qMakePair(KeyPress(Qt::Key_E), ViewState(13, KItemSet() << 13)) 0337 << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, KItemSet() << 0)) 0338 << qMakePair(KeyPress(Qt::Key_Escape), ViewState(0, KItemSet())); 0339 0340 // Next, we test combinations of key presses which only work for a 0341 // particular number of columns and either enabled or disabled grouping. 0342 0343 // One column. 0344 if (columnCount == 1) { 0345 testList << qMakePair(KeyPress(nextRowKey), ViewState(1, KItemSet() << 1)) 0346 << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(2, KItemSet() << 1 << 2)) 0347 << qMakePair(KeyPress(nextRowKey, Qt::ControlModifier), ViewState(3, KItemSet() << 1 << 2)) 0348 << qMakePair(KeyPress(previousRowKey), ViewState(2, KItemSet() << 2)) 0349 << qMakePair(KeyPress(previousItemKey), ViewState(1, KItemSet() << 1)) 0350 << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, KItemSet() << 0)); 0351 } 0352 0353 // Multiple columns: we test both 3 and 5 columns with grouping 0354 // enabled or disabled. For each case, the layout of the items 0355 // in the view is shown (both using file names and indices) to 0356 // make it easier to understand what the tests do. 0357 0358 if (columnCount == 3 && !groupingEnabled) { 0359 // 3 columns, no grouping: 0360 // 0361 // a1 a2 a3 | 0 1 2 0362 // b1 c1 c2 | 3 4 5 0363 // c3 c4 c5 | 6 7 8 0364 // d1 d2 d3 | 9 10 11 0365 // d4 e1 e2 | 12 13 14 0366 // e3 e4 e5 | 15 16 17 0367 // e6 e7 | 18 19 0368 testList << qMakePair(KeyPress(nextRowKey), ViewState(3, KItemSet() << 3)) 0369 << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(4, KItemSet() << 3)) 0370 << qMakePair(KeyPress(nextRowKey), ViewState(7, KItemSet() << 7)) 0371 << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(8, KItemSet() << 7 << 8)) 0372 << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(9, KItemSet() << 7 << 8 << 9)) 0373 << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(8, KItemSet() << 7 << 8)) 0374 << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(7, KItemSet() << 7)) 0375 << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(6, KItemSet() << 6 << 7)) 0376 << qMakePair(KeyPress(previousItemKey, Qt::ShiftModifier), ViewState(5, KItemSet() << 5 << 6 << 7)) 0377 << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(6, KItemSet() << 6 << 7)) 0378 << qMakePair(KeyPress(nextItemKey, Qt::ShiftModifier), ViewState(7, KItemSet() << 7)) 0379 << qMakePair(KeyPress(nextRowKey), ViewState(10, KItemSet() << 10)) 0380 << qMakePair(KeyPress(nextItemKey), ViewState(11, KItemSet() << 11)) 0381 << qMakePair(KeyPress(nextRowKey), ViewState(14, KItemSet() << 14)) 0382 << qMakePair(KeyPress(nextRowKey), ViewState(17, KItemSet() << 17)) 0383 << qMakePair(KeyPress(nextRowKey), ViewState(19, KItemSet() << 19)) 0384 << qMakePair(KeyPress(previousRowKey), ViewState(17, KItemSet() << 17)) 0385 << qMakePair(KeyPress(Qt::Key_End), ViewState(19, KItemSet() << 19)) 0386 << qMakePair(KeyPress(previousRowKey), ViewState(16, KItemSet() << 16)) 0387 << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, KItemSet() << 0)); 0388 } 0389 0390 if (columnCount == 5 && !groupingEnabled) { 0391 // 5 columns, no grouping: 0392 // 0393 // a1 a2 a3 b1 c1 | 0 1 2 3 4 0394 // c2 c3 c4 c5 d1 | 5 6 7 8 9 0395 // d2 d3 d4 e1 e2 | 10 11 12 13 14 0396 // e3 e4 e5 e6 e7 | 15 16 17 18 19 0397 testList << qMakePair(KeyPress(nextRowKey), ViewState(5, KItemSet() << 5)) 0398 << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(6, KItemSet() << 5)) 0399 << qMakePair(KeyPress(nextRowKey), ViewState(11, KItemSet() << 11)) 0400 << qMakePair(KeyPress(nextItemKey), ViewState(12, KItemSet() << 12)) 0401 << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(17, KItemSet() << 12 << 13 << 14 << 15 << 16 << 17)) 0402 << qMakePair(KeyPress(previousRowKey, Qt::ShiftModifier), ViewState(12, KItemSet() << 12)) 0403 << qMakePair(KeyPress(previousRowKey, Qt::ShiftModifier), ViewState(7, KItemSet() << 7 << 8 << 9 << 10 << 11 << 12)) 0404 << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(12, KItemSet() << 12)) 0405 << qMakePair(KeyPress(Qt::Key_End, Qt::ControlModifier), ViewState(19, KItemSet() << 12)) 0406 << qMakePair(KeyPress(previousRowKey), ViewState(14, KItemSet() << 14)) 0407 << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, KItemSet() << 0)); 0408 } 0409 0410 if (columnCount == 3 && groupingEnabled) { 0411 // 3 columns, with grouping: 0412 // 0413 // a1 a2 a3 | 0 1 2 0414 // b1 | 3 0415 // c1 c2 c3 | 4 5 6 0416 // c4 c5 | 7 8 0417 // d1 d2 d3 | 9 10 11 0418 // d4 | 12 0419 // e1 e2 e3 | 13 14 15 0420 // e4 e5 e6 | 16 17 18 0421 // e7 | 19 0422 testList << qMakePair(KeyPress(nextItemKey), ViewState(1, KItemSet() << 1)) 0423 << qMakePair(KeyPress(nextItemKey), ViewState(2, KItemSet() << 2)) 0424 << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(3, KItemSet() << 2 << 3)) 0425 << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(6, KItemSet() << 2 << 3 << 4 << 5 << 6)) 0426 << qMakePair(KeyPress(nextRowKey), ViewState(8, KItemSet() << 8)) 0427 << qMakePair(KeyPress(nextRowKey), ViewState(11, KItemSet() << 11)) 0428 << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(12, KItemSet() << 11)) 0429 << qMakePair(KeyPress(nextRowKey), ViewState(13, KItemSet() << 13)) 0430 << qMakePair(KeyPress(nextRowKey), ViewState(16, KItemSet() << 16)) 0431 << qMakePair(KeyPress(nextItemKey), ViewState(17, KItemSet() << 17)) 0432 << qMakePair(KeyPress(nextRowKey), ViewState(19, KItemSet() << 19)) 0433 << qMakePair(KeyPress(previousRowKey), ViewState(17, KItemSet() << 17)) 0434 << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, KItemSet() << 0)); 0435 } 0436 0437 if (columnCount == 5 && groupingEnabled) { 0438 // 5 columns, with grouping: 0439 // 0440 // a1 a2 a3 | 0 1 2 0441 // b1 | 3 0442 // c1 c2 c3 c4 c5 | 4 5 6 7 8 0443 // d1 d2 d3 d4 | 9 10 11 12 0444 // e1 e2 e3 e4 e5 | 13 14 15 16 17 0445 // e6 e7 | 18 19 0446 testList << qMakePair(KeyPress(nextItemKey), ViewState(1, KItemSet() << 1)) 0447 << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(3, KItemSet() << 1 << 2 << 3)) 0448 << qMakePair(KeyPress(nextRowKey, Qt::ShiftModifier), ViewState(5, KItemSet() << 1 << 2 << 3 << 4 << 5)) 0449 << qMakePair(KeyPress(nextItemKey), ViewState(6, KItemSet() << 6)) 0450 << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(7, KItemSet() << 6)) 0451 << qMakePair(KeyPress(nextItemKey, Qt::ControlModifier), ViewState(8, KItemSet() << 6)) 0452 << qMakePair(KeyPress(nextRowKey), ViewState(12, KItemSet() << 12)) 0453 << qMakePair(KeyPress(nextRowKey), ViewState(17, KItemSet() << 17)) 0454 << qMakePair(KeyPress(nextRowKey), ViewState(19, KItemSet() << 19)) 0455 << qMakePair(KeyPress(previousRowKey), ViewState(17, KItemSet() << 17)) 0456 << qMakePair(KeyPress(Qt::Key_End, Qt::ShiftModifier), ViewState(19, KItemSet() << 17 << 18 << 19)) 0457 << qMakePair(KeyPress(previousRowKey, Qt::ShiftModifier), ViewState(14, KItemSet() << 14 << 15 << 16 << 17)) 0458 << qMakePair(KeyPress(Qt::Key_Home), ViewState(0, KItemSet() << 0)); 0459 } 0460 0461 const QString testName = layoutNames[layout] + ", " + QString("%1 columns, ").arg(columnCount) + selectionBehaviorNames[selectionBehavior] 0462 + ", " + groupingEnabledNames[groupingEnabled]; 0463 0464 const QByteArray testNameAscii = testName.toLatin1(); 0465 0466 QTest::newRow(testNameAscii.data()) << layout << scrollOrientation << columnCount << selectionBehavior << groupingEnabled << testList; 0467 } 0468 } 0469 } 0470 } 0471 } 0472 0473 /** 0474 * This function sets the view's properties according to the data provided by 0475 * KItemListControllerTest::testKeyboardNavigation_data(). 0476 * 0477 * The list \a testList contains pairs of key presses, which are sent to the 0478 * container, and expected view states, which are verified then. 0479 */ 0480 void KItemListControllerTest::testKeyboardNavigation() 0481 { 0482 QFETCH(KFileItemListView::ItemLayout, layout); 0483 QFETCH(Qt::Orientation, scrollOrientation); 0484 QFETCH(int, columnCount); 0485 QFETCH(KItemListController::SelectionBehavior, selectionBehavior); 0486 QFETCH(bool, groupingEnabled); 0487 QFETCH(QList<keyPressViewStatePair>, testList); 0488 0489 m_view->setItemLayout(layout); 0490 QCOMPARE(m_view->itemLayout(), layout); 0491 0492 m_view->setScrollOrientation(scrollOrientation); 0493 QCOMPARE(m_view->scrollOrientation(), scrollOrientation); 0494 0495 m_controller->setSelectionBehavior(selectionBehavior); 0496 QCOMPARE(m_controller->selectionBehavior(), selectionBehavior); 0497 0498 m_model->setGroupedSorting(groupingEnabled); 0499 QCOMPARE(m_model->groupedSorting(), groupingEnabled); 0500 0501 adjustGeometryForColumnCount(columnCount); 0502 QCOMPARE(m_view->m_layouter->m_columnCount, columnCount); 0503 0504 QSignalSpy spySingleItemActivated(m_controller, &KItemListController::itemActivated); 0505 QSignalSpy spyMultipleItemsActivated(m_controller, &KItemListController::itemsActivated); 0506 0507 while (!testList.isEmpty()) { 0508 const QPair<KeyPress, ViewState> test = testList.takeFirst(); 0509 const Qt::Key key = test.first.m_key; 0510 const Qt::KeyboardModifiers modifier = test.first.m_modifier; 0511 const int current = test.second.m_current; 0512 const KItemSet selection = test.second.m_selection; 0513 const bool activated = test.second.m_activated; 0514 0515 QTest::keyClick(m_container, key, modifier); 0516 0517 QCOMPARE(m_selectionManager->currentItem(), current); 0518 switch (selectionBehavior) { 0519 case KItemListController::NoSelection: 0520 QVERIFY(m_selectionManager->selectedItems().isEmpty()); 0521 break; 0522 case KItemListController::SingleSelection: 0523 QCOMPARE(m_selectionManager->selectedItems(), KItemSet() << current); 0524 break; 0525 case KItemListController::MultiSelection: 0526 QCOMPARE(m_selectionManager->selectedItems(), selection); 0527 break; 0528 } 0529 0530 if (activated) { 0531 switch (selectionBehavior) { 0532 case KItemListController::MultiSelection: 0533 if (!selection.isEmpty()) { 0534 // The selected items should be activated. 0535 if (selection.count() == 1) { 0536 QVERIFY(!spySingleItemActivated.isEmpty()); 0537 QCOMPARE(qvariant_cast<int>(spySingleItemActivated.takeFirst().at(0)), selection.first()); 0538 QVERIFY(spyMultipleItemsActivated.isEmpty()); 0539 } else { 0540 QVERIFY(spySingleItemActivated.isEmpty()); 0541 QVERIFY(!spyMultipleItemsActivated.isEmpty()); 0542 QCOMPARE(qvariant_cast<KItemSet>(spyMultipleItemsActivated.takeFirst().at(0)), selection); 0543 } 0544 break; 0545 } 0546 // No items are selected. Therefore, the current item should be activated. 0547 // This is handled by falling through to the NoSelection/SingleSelection case. 0548 Q_FALLTHROUGH(); 0549 case KItemListController::NoSelection: 0550 case KItemListController::SingleSelection: 0551 // In NoSelection and SingleSelection mode, the current item should be activated. 0552 QVERIFY(!spySingleItemActivated.isEmpty()); 0553 QCOMPARE(qvariant_cast<int>(spySingleItemActivated.takeFirst().at(0)), current); 0554 QVERIFY(spyMultipleItemsActivated.isEmpty()); 0555 break; 0556 } 0557 } 0558 } 0559 } 0560 0561 void KItemListControllerTest::testMouseClickActivation() 0562 { 0563 m_view->setItemLayout(KFileItemListView::IconsLayout); 0564 0565 // Make sure that we have a large window, such that 0566 // the items are visible and clickable. 0567 adjustGeometryForColumnCount(5); 0568 0569 // Make sure that the first item is visible in the view. 0570 m_view->setScrollOffset(0); 0571 QCOMPARE(m_view->firstVisibleIndex(), 0); 0572 0573 const QPointF pos = m_view->itemContextRect(0).center(); 0574 0575 // Save the "single click" setting. 0576 const bool restoreSettingsSingleClick = m_testStyle->activateItemOnSingleClick(); 0577 0578 QGraphicsSceneMouseEvent mousePressEvent(QEvent::GraphicsSceneMousePress); 0579 mousePressEvent.setPos(pos); 0580 mousePressEvent.setButton(Qt::LeftButton); 0581 mousePressEvent.setButtons(Qt::LeftButton); 0582 0583 QGraphicsSceneMouseEvent mouseReleaseEvent(QEvent::GraphicsSceneMouseRelease); 0584 mouseReleaseEvent.setPos(pos); 0585 mouseReleaseEvent.setButton(Qt::LeftButton); 0586 mouseReleaseEvent.setButtons(Qt::NoButton); 0587 0588 QSignalSpy spyItemActivated(m_controller, &KItemListController::itemActivated); 0589 0590 // Default setting: single click activation. 0591 m_testStyle->setActivateItemOnSingleClick(true); 0592 m_view->event(&mousePressEvent); 0593 m_view->event(&mouseReleaseEvent); 0594 QCOMPARE(spyItemActivated.count(), 1); 0595 spyItemActivated.clear(); 0596 0597 // Set the global setting to "double click activation". 0598 m_testStyle->setActivateItemOnSingleClick(false); 0599 m_view->event(&mousePressEvent); 0600 m_view->event(&mouseReleaseEvent); 0601 QCOMPARE(spyItemActivated.count(), 0); 0602 spyItemActivated.clear(); 0603 0604 // Enforce single click activation in the controller. 0605 m_controller->setSingleClickActivationEnforced(true); 0606 m_view->event(&mousePressEvent); 0607 m_view->event(&mouseReleaseEvent); 0608 QCOMPARE(spyItemActivated.count(), 1); 0609 spyItemActivated.clear(); 0610 0611 // Do not enforce single click activation in the controller. 0612 m_controller->setSingleClickActivationEnforced(false); 0613 m_view->event(&mousePressEvent); 0614 m_view->event(&mouseReleaseEvent); 0615 QCOMPARE(spyItemActivated.count(), 0); 0616 spyItemActivated.clear(); 0617 0618 // Set the global setting back to "single click activation". 0619 m_testStyle->setActivateItemOnSingleClick(true); 0620 m_view->event(&mousePressEvent); 0621 m_view->event(&mouseReleaseEvent); 0622 QCOMPARE(spyItemActivated.count(), 1); 0623 spyItemActivated.clear(); 0624 0625 // Enforce single click activation in the controller. 0626 m_controller->setSingleClickActivationEnforced(true); 0627 m_view->event(&mousePressEvent); 0628 m_view->event(&mouseReleaseEvent); 0629 QCOMPARE(spyItemActivated.count(), 1); 0630 spyItemActivated.clear(); 0631 0632 // Restore previous settings. 0633 m_controller->setSingleClickActivationEnforced(true); 0634 m_testStyle->setActivateItemOnSingleClick(restoreSettingsSingleClick); 0635 } 0636 0637 void KItemListControllerTest::adjustGeometryForColumnCount(int count) 0638 { 0639 const QSize size = m_view->itemSize().toSize(); 0640 0641 QRect rect = m_container->geometry(); 0642 rect.setSize(size * count); 0643 m_container->setGeometry(rect); 0644 0645 // Increase the size of the container until the correct column count is reached. 0646 while (m_view->m_layouter->m_columnCount < count) { 0647 rect = m_container->geometry(); 0648 rect.setSize(rect.size() + size); 0649 m_container->setGeometry(rect); 0650 } 0651 } 0652 0653 QTEST_MAIN(KItemListControllerTest) 0654 0655 #include "kitemlistcontrollertest.moc"