1 /* 2 * SPDX-FileCopyrightText: 2011 Peter Penz <peter.penz19@gmail.com> 3 * 4 * Based on the Itemviews NG project from Trolltech Labs 5 * 6 * SPDX-License-Identifier: GPL-2.0-or-later 7 */ 8 9 #ifndef KITEMLISTCONTROLLER_H 10 #define KITEMLISTCONTROLLER_H 11 12 #include "dolphin_export.h" 13 #include "kitemset.h" 14 15 #include <QObject> 16 #include <QPointF> 17 #include <QScroller> 18 19 class QTimer; 20 class KItemModelBase; 21 class KItemListKeyboardSearchManager; 22 class KItemListSelectionManager; 23 class KItemListView; 24 class KItemListWidget; 25 class QGestureEvent; 26 class QGraphicsSceneHoverEvent; 27 class QGraphicsSceneDragDropEvent; 28 class QGraphicsSceneMouseEvent; 29 class QGraphicsSceneResizeEvent; 30 class QGraphicsSceneWheelEvent; 31 class QInputMethodEvent; 32 class QKeyEvent; 33 class QTapGesture; 34 class QTransform; 35 class QTouchEvent; 36 37 /** 38 * @brief Controls the view, model and selection of an item-list. 39 * 40 * For a working item-list it is mandatory to set a compatible view and model 41 * with KItemListController::setView() and KItemListController::setModel(). 42 * 43 * @see KItemListView 44 * @see KItemModelBase 45 * @see KItemListSelectionManager 46 */ 47 class DOLPHIN_EXPORT KItemListController : public QObject 48 { 49 Q_OBJECT 50 Q_PROPERTY(KItemModelBase* model READ model WRITE setModel) 51 Q_PROPERTY(KItemListView *view READ view WRITE setView) 52 Q_PROPERTY(SelectionBehavior selectionBehavior READ selectionBehavior WRITE setSelectionBehavior) 53 Q_PROPERTY(AutoActivationBehavior autoActivationBehavior READ autoActivationBehavior WRITE setAutoActivationBehavior) 54 Q_PROPERTY(MouseDoubleClickAction mouseDoubleClickAction READ mouseDoubleClickAction WRITE setMouseDoubleClickAction) 55 56 public: 57 enum SelectionBehavior { 58 NoSelection, 59 SingleSelection, 60 MultiSelection 61 }; 62 Q_ENUM(SelectionBehavior) 63 64 enum AutoActivationBehavior { 65 ActivationAndExpansion, 66 ExpansionOnly 67 }; 68 69 enum MouseDoubleClickAction { 70 ActivateAndExpandItem, 71 ActivateItemOnly 72 }; 73 74 /** 75 * @param model Model of the controller. The ownership is passed to the controller. 76 * @param view View of the controller. The ownership is passed to the controller. 77 * @param parent Optional parent object. 78 */ 79 KItemListController(KItemModelBase* model, KItemListView* view, QObject* parent = nullptr); 80 ~KItemListController() override; 81 82 void setModel(KItemModelBase* model); 83 KItemModelBase* model() const; 84 85 void setView(KItemListView* view); 86 KItemListView* view() const; 87 88 KItemListSelectionManager* selectionManager() const; 89 90 void setSelectionBehavior(SelectionBehavior behavior); 91 SelectionBehavior selectionBehavior() const; 92 93 void setAutoActivationBehavior(AutoActivationBehavior behavior); 94 AutoActivationBehavior autoActivationBehavior() const; 95 96 void setMouseDoubleClickAction(MouseDoubleClickAction action); 97 MouseDoubleClickAction mouseDoubleClickAction() const; 98 99 int indexCloseToMousePressedPosition() const; 100 101 /** 102 * Sets the delay in milliseconds when dragging an object above an item 103 * until the item gets activated automatically. A value of -1 indicates 104 * that no automatic activation will be done at all (= default value). 105 * 106 * The hovered item must support dropping (see KItemModelBase::supportsDropping()), 107 * otherwise the automatic activation is not available. 108 * 109 * After activating the item the signal itemActivated() will be 110 * emitted. If the view supports the expanding of items 111 * (KItemListView::supportsItemExpanding() returns true) and the item 112 * itself is expandable (see KItemModelBase::isExpandable()) then instead 113 * of activating the item it gets expanded instead (see 114 * KItemModelBase::setExpanded()). 115 */ 116 void setAutoActivationDelay(int delay); 117 int autoActivationDelay() const; 118 119 /** 120 * If set to true, the signals itemActivated() and itemsActivated() are emitted 121 * after a single-click of the left mouse button. If set to false (the default), 122 * the setting from style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) is used. 123 */ 124 void setSingleClickActivationEnforced(bool singleClick); 125 bool singleClickActivationEnforced() const; 126 127 bool processEvent(QEvent* event, const QTransform& transform); 128 129 Q_SIGNALS: 130 /** 131 * Is emitted if exactly one item has been activated by e.g. a mouse-click 132 * or by pressing Return/Enter. 133 */ 134 void itemActivated(int index); 135 136 /** 137 * Is emitted if more than one item has been activated by pressing Return/Enter 138 * when having a selection. 139 */ 140 void itemsActivated(const KItemSet& indexes); 141 142 void itemMiddleClicked(int index); 143 144 /** 145 * Emitted if a context-menu is requested for the item with 146 * the index \a index. It is assured that the index is valid. 147 */ 148 void itemContextMenuRequested(int index, const QPointF& pos); 149 150 /** 151 * Emitted if a context-menu is requested for the KItemListView. 152 */ 153 void viewContextMenuRequested(const QPointF& pos); 154 155 /** 156 * Emitted if a context-menu is requested for the header of the KItemListView. 157 */ 158 void headerContextMenuRequested(const QPointF& pos); 159 160 /** 161 * Is emitted if the item with the index \p index gets hovered. 162 */ 163 void itemHovered(int index); 164 165 /** 166 * Is emitted if the item with the index \p index gets unhovered. 167 * It is assured that the signal itemHovered() for this index 168 * has been emitted before. 169 */ 170 void itemUnhovered(int index); 171 172 /** 173 * Is emitted if a mouse-button has been pressed above an item. 174 * If the index is smaller than 0, the mouse-button has been pressed 175 * above the viewport. 176 */ 177 void mouseButtonPressed(int itemIndex, Qt::MouseButtons buttons); 178 179 /** 180 * Is emitted if a mouse-button has been released above an item. 181 * It is assured that the signal mouseButtonPressed() has been emitted before. 182 * If the index is smaller than 0, the mouse-button has been pressed 183 * above the viewport. 184 */ 185 void mouseButtonReleased(int itemIndex, Qt::MouseButtons buttons); 186 187 void itemExpansionToggleClicked(int index); 188 189 /** 190 * Is emitted if a drop event is done above the item with the index 191 * \a index. If \a index is < 0 the drop event is done above an 192 * empty area of the view. 193 * TODO: Introduce a new signal viewDropEvent(QGraphicsSceneDragDropEvent), 194 * which is emitted if the drop event occurs on an empty area in 195 * the view, and make sure that index is always >= 0 in itemDropEvent(). 196 */ 197 void itemDropEvent(int index, QGraphicsSceneDragDropEvent* event); 198 199 /** 200 * Is emitted if a drop event is done between the item with the index 201 * \a index and the previous item. 202 */ 203 void aboveItemDropEvent(int index, QGraphicsSceneDragDropEvent* event); 204 205 /** 206 * Is emitted if the Escape key is pressed. 207 */ 208 void escapePressed(); 209 210 void modelChanged(KItemModelBase* current, KItemModelBase* previous); 211 void viewChanged(KItemListView* current, KItemListView* previous); 212 213 void selectedItemTextPressed(int index); 214 215 void scrollerStop(); 216 void increaseZoom(); 217 void decreaseZoom(); 218 void swipeUp(); 219 220 public Q_SLOTS: 221 void slotStateChanged(QScroller::State newState); 222 223 private Q_SLOTS: 224 void slotViewScrollOffsetChanged(qreal current, qreal previous); 225 226 /** 227 * Is invoked when the rubberband boundaries have been changed and will select 228 * all items that are touched by the rubberband. 229 */ 230 void slotRubberBandChanged(); 231 232 void slotChangeCurrentItem(const QString& text, bool searchFromNextItem); 233 234 void slotAutoActivationTimeout(); 235 236 private: 237 /** 238 * Creates a QDrag object and initiates a drag-operation. 239 */ 240 void startDragging(); 241 242 /** 243 * @return Widget that is currently in the hovered state. 0 is returned 244 * if no widget is marked as hovered. 245 */ 246 KItemListWidget* hoveredWidget() const; 247 248 /** 249 * @return Widget that is below the position \a pos. 0 is returned 250 * if no widget is below the position. 251 */ 252 KItemListWidget* widgetForPos(const QPointF& pos) const; 253 254 /** 255 * Updates m_keyboardAnchorIndex and m_keyboardAnchorPos. If no anchor is 256 * set, it will be adjusted to the current item. If it is set it will be 257 * checked whether it is still valid, otherwise it will be reset to the 258 * current item. 259 */ 260 void updateKeyboardAnchor(); 261 262 /** 263 * @return Index for the next row based on \a index. 264 * If there is no next row \a index will be returned. 265 */ 266 int nextRowIndex(int index) const; 267 268 /** 269 * @return Index for the previous row based on \a index. 270 * If there is no previous row \a index will be returned. 271 */ 272 int previousRowIndex(int index) const; 273 274 /** 275 * Helper method for updateKeyboardAnchor(), previousRowIndex() and nextRowIndex(). 276 * @return The position of the keyboard anchor for the item with the index \a index. 277 * If a horizontal scrolling is used the y-position of the item will be returned, 278 * for the vertical scrolling the x-position will be returned. 279 */ 280 qreal keyboardAnchorPos(int index) const; 281 282 /** 283 * Dependent on the selection-behavior the extendedSelectionRegion-property 284 * of the KItemListStyleOption from the view should be adjusted: If no 285 * rubberband selection is used the property should be enabled. 286 */ 287 void updateExtendedSelectionRegion(); 288 289 bool keyPressEvent(QKeyEvent* event); 290 bool inputMethodEvent(QInputMethodEvent* event); 291 bool mousePressEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform); 292 bool mouseMoveEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform); 293 bool mouseReleaseEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform); 294 bool mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform); 295 bool dragEnterEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform); 296 bool dragLeaveEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform); 297 bool dragMoveEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform); 298 bool dropEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform); 299 bool hoverEnterEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform); 300 bool hoverMoveEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform); 301 bool hoverLeaveEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform); 302 bool wheelEvent(QGraphicsSceneWheelEvent* event, const QTransform& transform); 303 bool resizeEvent(QGraphicsSceneResizeEvent* event, const QTransform& transform); 304 bool gestureEvent(QGestureEvent* event, const QTransform& transform); 305 bool touchBeginEvent(QTouchEvent* event, const QTransform& transform); 306 void tapTriggered(QTapGesture* tap, const QTransform& transform); 307 void tapAndHoldTriggered(QGestureEvent* event, const QTransform& transform); 308 void pinchTriggered(QGestureEvent* event, const QTransform& transform); 309 void swipeTriggered(QGestureEvent* event, const QTransform& transform); 310 void twoFingerTapTriggered(QGestureEvent* event, const QTransform& transform); 311 bool onPress(const QPoint& screenPos, const QPointF& pos, const Qt::KeyboardModifiers modifiers, const Qt::MouseButtons buttons); 312 bool onRelease(const QPointF& pos, const Qt::KeyboardModifiers modifiers, const Qt::MouseButtons buttons, bool touch); 313 void startRubberBand(); 314 315 private: 316 bool m_singleClickActivationEnforced; 317 bool m_selectionTogglePressed; 318 bool m_clearSelectionIfItemsAreNotDragged; 319 bool m_isSwipeGesture; 320 bool m_dragActionOrRightClick; 321 bool m_scrollerIsScrolling; 322 bool m_pinchGestureInProgress; 323 bool m_mousePress; 324 bool m_isTouchEvent; 325 SelectionBehavior m_selectionBehavior; 326 AutoActivationBehavior m_autoActivationBehavior; 327 MouseDoubleClickAction m_mouseDoubleClickAction; 328 KItemModelBase* m_model; 329 KItemListView* m_view; 330 KItemListSelectionManager* m_selectionManager; 331 KItemListKeyboardSearchManager* m_keyboardManager; 332 int m_pressedIndex; 333 QPointF m_pressedMousePos; 334 335 QTimer* m_autoActivationTimer; 336 337 Qt::GestureType m_swipeGesture; 338 Qt::GestureType m_twoFingerTapGesture; 339 340 /** 341 * When starting a rubberband selection during a Shift- or Control-key has been 342 * pressed the current selection should never be deleted. To be able to restore 343 * the current selection it is remembered in m_oldSelection before the 344 * rubberband gets activated. 345 */ 346 KItemSet m_oldSelection; 347 348 /** 349 * Assuming a view is given with a vertical scroll-orientation, grouped items and 350 * a maximum of 4 columns: 351 * 352 * 1 2 3 4 353 * 5 6 7 354 * 8 9 10 11 355 * 12 13 14 356 * 357 * If the current index is on 4 and key-down is pressed, then item 7 gets the current 358 * item. Now when pressing key-down again item 11 should get the current item and not 359 * item 10. This makes it necessary to keep track of the requested column to have a 360 * similar behavior like in a text editor: 361 */ 362 int m_keyboardAnchorIndex; 363 qreal m_keyboardAnchorPos; 364 }; 365 366 #endif 367 368 369