File indexing completed on 2024-04-28 05:45:07
0001 /* 0002 * SPDX-FileCopyrightText: 2011 Peter Penz <peter.penz19@gmail.com> 0003 * 0004 * Based on the Itemviews NG project from Trolltech Labs 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #ifndef KITEMLISTCONTROLLER_H 0010 #define KITEMLISTCONTROLLER_H 0011 0012 #include <optional> 0013 0014 #include "dolphin_export.h" 0015 #include "kitemset.h" 0016 0017 #include <QObject> 0018 #include <QPointF> 0019 #include <QScroller> 0020 0021 class QTimer; 0022 class KItemModelBase; 0023 class KItemListKeyboardSearchManager; 0024 class KItemListSelectionManager; 0025 class KItemListView; 0026 class KItemListWidget; 0027 class QContextMenuEvent; 0028 class QGestureEvent; 0029 class QGraphicsSceneHoverEvent; 0030 class QGraphicsSceneDragDropEvent; 0031 class QGraphicsSceneMouseEvent; 0032 class QGraphicsSceneResizeEvent; 0033 class QGraphicsSceneWheelEvent; 0034 class QInputMethodEvent; 0035 class QKeyEvent; 0036 class QTapGesture; 0037 class QTransform; 0038 class QTouchEvent; 0039 0040 /** 0041 * @brief Controls the view, model and selection of an item-list. 0042 * 0043 * For a working item-list it is mandatory to set a compatible view and model 0044 * with KItemListController::setView() and KItemListController::setModel(). 0045 * 0046 * @see KItemListView 0047 * @see KItemModelBase 0048 * @see KItemListSelectionManager 0049 */ 0050 class DOLPHIN_EXPORT KItemListController : public QObject 0051 { 0052 Q_OBJECT 0053 Q_PROPERTY(KItemModelBase *model READ model WRITE setModel NOTIFY modelChanged) 0054 Q_PROPERTY(KItemListView *view READ view WRITE setView NOTIFY viewChanged) 0055 0056 public: 0057 enum SelectionBehavior { NoSelection, SingleSelection, MultiSelection }; 0058 Q_ENUM(SelectionBehavior) 0059 0060 enum AutoActivationBehavior { ActivationAndExpansion, ExpansionOnly }; 0061 0062 enum MouseDoubleClickAction { ActivateAndExpandItem, ActivateItemOnly }; 0063 0064 /** 0065 * @param model Model of the controller. The ownership is passed to the controller. 0066 * @param view View of the controller. The ownership is passed to the controller. 0067 * @param parent Optional parent object. 0068 */ 0069 KItemListController(KItemModelBase *model, KItemListView *view, QObject *parent = nullptr); 0070 ~KItemListController() override; 0071 0072 void setModel(KItemModelBase *model); 0073 KItemModelBase *model() const; 0074 0075 void setView(KItemListView *view); 0076 KItemListView *view() const; 0077 0078 KItemListSelectionManager *selectionManager() const; 0079 0080 void setSelectionBehavior(SelectionBehavior behavior); 0081 SelectionBehavior selectionBehavior() const; 0082 0083 void setAutoActivationBehavior(AutoActivationBehavior behavior); 0084 AutoActivationBehavior autoActivationBehavior() const; 0085 0086 void setMouseDoubleClickAction(MouseDoubleClickAction action); 0087 MouseDoubleClickAction mouseDoubleClickAction() const; 0088 0089 int indexCloseToMousePressedPosition() const; 0090 0091 /** 0092 * Sets the delay in milliseconds when dragging an object above an item 0093 * until the item gets activated automatically. A value of -1 indicates 0094 * that no automatic activation will be done at all (= default value). 0095 * 0096 * The hovered item must support dropping (see KItemModelBase::supportsDropping()), 0097 * otherwise the automatic activation is not available. 0098 * 0099 * After activating the item the signal itemActivated() will be 0100 * emitted. If the view supports the expanding of items 0101 * (KItemListView::supportsItemExpanding() returns true) and the item 0102 * itself is expandable (see KItemModelBase::isExpandable()) then instead 0103 * of activating the item it gets expanded instead (see 0104 * KItemModelBase::setExpanded()). 0105 */ 0106 void setAutoActivationDelay(int delay); 0107 int autoActivationDelay() const; 0108 0109 /** 0110 * If set to true, the signals itemActivated() and itemsActivated() are emitted 0111 * after a single-click of the left mouse button. If set to false (the default), 0112 * the setting from style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) is used. 0113 */ 0114 void setSingleClickActivationEnforced(bool singleClick); 0115 bool singleClickActivationEnforced() const; 0116 0117 /** 0118 * Setting the selection mode to enabled will make selecting and deselecting easier by acting 0119 * kind of similar to when the Control Key is held down. 0120 */ 0121 void setSelectionModeEnabled(bool enabled); 0122 bool selectionMode() const; 0123 0124 /** 0125 * @return \c true if search as you type is active, or \c false otherwise. 0126 */ 0127 bool isSearchAsYouTypeActive() const; 0128 0129 bool processEvent(QEvent *event, const QTransform &transform); 0130 0131 Q_SIGNALS: 0132 /** 0133 * Is emitted if exactly one item has been activated by e.g. a mouse-click 0134 * or by pressing Return/Enter. 0135 */ 0136 void itemActivated(int index); 0137 0138 /** 0139 * Is emitted if more than one item has been activated by pressing Return/Enter 0140 * when having a selection. 0141 */ 0142 void itemsActivated(const KItemSet &indexes); 0143 0144 void itemMiddleClicked(int index); 0145 0146 /** 0147 * Emitted if a context-menu is requested for the item with 0148 * the index \a index. It is assured that the index is valid. 0149 */ 0150 void itemContextMenuRequested(int index, const QPointF &pos); 0151 0152 /** 0153 * Emitted if a context-menu is requested for the KItemListView. 0154 */ 0155 void viewContextMenuRequested(const QPointF &pos); 0156 0157 /** 0158 * Emitted if a context-menu is requested for the header of the KItemListView. 0159 */ 0160 void headerContextMenuRequested(const QPointF &pos); 0161 0162 /** 0163 * Is emitted if the item with the index \p index gets hovered. 0164 */ 0165 void itemHovered(int index); 0166 0167 /** 0168 * Is emitted if the item with the index \p index gets unhovered. 0169 * It is assured that the signal itemHovered() for this index 0170 * has been emitted before. 0171 */ 0172 void itemUnhovered(int index); 0173 0174 /** 0175 * Is emitted if a mouse-button has been pressed above an item. 0176 * If the index is smaller than 0, the mouse-button has been pressed 0177 * above the viewport. 0178 */ 0179 void mouseButtonPressed(int itemIndex, Qt::MouseButtons buttons); 0180 0181 /** 0182 * Is emitted if a mouse-button has been released above an item. 0183 * It is assured that the signal mouseButtonPressed() has been emitted before. 0184 * If the index is smaller than 0, the mouse-button has been pressed 0185 * above the viewport. 0186 */ 0187 void mouseButtonReleased(int itemIndex, Qt::MouseButtons buttons); 0188 0189 void itemExpansionToggleClicked(int index); 0190 0191 /** 0192 * Is emitted if a drop event is done above the item with the index 0193 * \a index. If \a index is < 0 the drop event is done above an 0194 * empty area of the view. 0195 * TODO: Introduce a new signal viewDropEvent(QGraphicsSceneDragDropEvent), 0196 * which is emitted if the drop event occurs on an empty area in 0197 * the view, and make sure that index is always >= 0 in itemDropEvent(). 0198 */ 0199 void itemDropEvent(int index, QGraphicsSceneDragDropEvent *event); 0200 0201 /** 0202 * Is emitted if a drop event is done between the item with the index 0203 * \a index and the previous item. 0204 */ 0205 void aboveItemDropEvent(int index, QGraphicsSceneDragDropEvent *event); 0206 0207 /** 0208 * Is emitted if the Escape key is pressed. 0209 */ 0210 void escapePressed(); 0211 0212 /** 0213 * Used to request either entering or leaving of selection mode 0214 * Leaving is requested by pressing Escape when no item is selected. 0215 * 0216 * Entering is requested if left click is pressed down for a long time without moving the cursor too much. 0217 * Moving the cursor would either trigger an item drag if the click was initiated on top of an item 0218 * or a selection rectangle if the click was not initiated on top of an item. 0219 * So long press is only emitted if there wasn't a lot of cursor movement. 0220 */ 0221 void selectionModeChangeRequested(bool enabled); 0222 0223 void modelChanged(KItemModelBase *current, KItemModelBase *previous); 0224 void viewChanged(KItemListView *current, KItemListView *previous); 0225 0226 void selectedItemTextPressed(int index); 0227 0228 void scrollerStop(); 0229 void increaseZoom(); 0230 void decreaseZoom(); 0231 void swipeUp(); 0232 0233 public Q_SLOTS: 0234 void slotStateChanged(QScroller::State newState); 0235 0236 private Q_SLOTS: 0237 void slotViewScrollOffsetChanged(qreal current, qreal previous); 0238 0239 /** 0240 * Is invoked when the rubberband boundaries have been changed and will select 0241 * all items that are touched by the rubberband. 0242 */ 0243 void slotRubberBandChanged(); 0244 0245 void slotChangeCurrentItem(const QString &text, bool searchFromNextItem); 0246 0247 void slotAutoActivationTimeout(); 0248 0249 private: 0250 /** 0251 * Creates a QDrag object and initiates a drag-operation. 0252 */ 0253 void startDragging(); 0254 0255 /** 0256 * @return Widget that is currently in the hovered state. 0 is returned 0257 * if no widget is marked as hovered. 0258 */ 0259 KItemListWidget *hoveredWidget() const; 0260 0261 /** 0262 * @return Widget that is below the position \a pos. 0 is returned 0263 * if no widget is below the position. 0264 */ 0265 KItemListWidget *widgetForPos(const QPointF &pos) const; 0266 0267 /** 0268 * @return Widget that should receive a drop event if an item is dropped at \a pos. 0 is returned 0269 * if no widget should receive a drop event at the position. 0270 * 0271 * While widgetForPos() returns a widget if \a pos is anywhere inside the hover highlight area of the widget, 0272 * widgetForDropPos() only returns a widget if \a pos is directly above the widget (widget->contains(pos) == true). 0273 */ 0274 KItemListWidget *widgetForDropPos(const QPointF &pos) const; 0275 0276 /** 0277 * Updates m_keyboardAnchorIndex and m_keyboardAnchorPos. If no anchor is 0278 * set, it will be adjusted to the current item. If it is set it will be 0279 * checked whether it is still valid, otherwise it will be reset to the 0280 * current item. 0281 */ 0282 void updateKeyboardAnchor(); 0283 0284 /** 0285 * @return Index for the next row based on \a index. 0286 * If there is no next row \a index will be returned. 0287 */ 0288 int nextRowIndex(int index) const; 0289 0290 /** 0291 * @return Index for the previous row based on \a index. 0292 * If there is no previous row \a index will be returned. 0293 */ 0294 int previousRowIndex(int index) const; 0295 0296 /** 0297 * Helper method for updateKeyboardAnchor(), previousRowIndex() and nextRowIndex(). 0298 * @return The position of the keyboard anchor for the item with the index \a index. 0299 * If a horizontal scrolling is used the y-position of the item will be returned, 0300 * for the vertical scrolling the x-position will be returned. 0301 */ 0302 qreal keyboardAnchorPos(int index) const; 0303 0304 /** 0305 * Dependent on the selection-behavior the extendedSelectionRegion-property 0306 * of the KItemListStyleOption from the view should be adjusted: If no 0307 * rubberband selection is used the property should be enabled. 0308 */ 0309 void updateExtendedSelectionRegion(); 0310 0311 bool keyPressEvent(QKeyEvent *event); 0312 bool inputMethodEvent(QInputMethodEvent *event); 0313 bool mousePressEvent(QGraphicsSceneMouseEvent *event, const QTransform &transform); 0314 bool mouseMoveEvent(QGraphicsSceneMouseEvent *event, const QTransform &transform); 0315 bool mouseReleaseEvent(QGraphicsSceneMouseEvent *event, const QTransform &transform); 0316 bool mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event, const QTransform &transform); 0317 bool contextMenuEvent(QContextMenuEvent *event); 0318 bool dragEnterEvent(QGraphicsSceneDragDropEvent *event, const QTransform &transform); 0319 bool dragLeaveEvent(QGraphicsSceneDragDropEvent *event, const QTransform &transform); 0320 bool dragMoveEvent(QGraphicsSceneDragDropEvent *event, const QTransform &transform); 0321 bool dropEvent(QGraphicsSceneDragDropEvent *event, const QTransform &transform); 0322 bool hoverEnterEvent(QGraphicsSceneHoverEvent *event, const QTransform &transform); 0323 bool hoverMoveEvent(QGraphicsSceneHoverEvent *event, const QTransform &transform); 0324 bool hoverLeaveEvent(QGraphicsSceneHoverEvent *event, const QTransform &transform); 0325 bool wheelEvent(QGraphicsSceneWheelEvent *event, const QTransform &transform); 0326 bool resizeEvent(QGraphicsSceneResizeEvent *event, const QTransform &transform); 0327 bool gestureEvent(QGestureEvent *event, const QTransform &transform); 0328 bool touchBeginEvent(QTouchEvent *event, const QTransform &transform); 0329 void tapTriggered(QTapGesture *tap, const QTransform &transform); 0330 void tapAndHoldTriggered(QGestureEvent *event, const QTransform &transform); 0331 void pinchTriggered(QGestureEvent *event, const QTransform &transform); 0332 void swipeTriggered(QGestureEvent *event, const QTransform &transform); 0333 void twoFingerTapTriggered(QGestureEvent *event, const QTransform &transform); 0334 bool onPress(const QPoint &screenPos, const QPointF &pos, const Qt::KeyboardModifiers modifiers, const Qt::MouseButtons buttons); 0335 bool onRelease(const QPointF &pos, const Qt::KeyboardModifiers modifiers, const Qt::MouseButtons buttons, bool touch); 0336 void startRubberBand(); 0337 0338 private: 0339 bool m_singleClickActivationEnforced; 0340 bool m_selectionMode; 0341 bool m_selectionTogglePressed; 0342 bool m_clearSelectionIfItemsAreNotDragged; 0343 bool m_isSwipeGesture; 0344 bool m_dragActionOrRightClick; 0345 bool m_scrollerIsScrolling; 0346 bool m_pinchGestureInProgress; 0347 bool m_mousePress; 0348 bool m_isTouchEvent; 0349 SelectionBehavior m_selectionBehavior; 0350 AutoActivationBehavior m_autoActivationBehavior; 0351 MouseDoubleClickAction m_mouseDoubleClickAction; 0352 KItemModelBase *m_model; 0353 KItemListView *m_view; 0354 KItemListSelectionManager *m_selectionManager; 0355 KItemListKeyboardSearchManager *m_keyboardManager; 0356 std::optional<int> m_pressedIndex; 0357 QPointF m_pressedMouseGlobalPos; 0358 0359 QTimer *m_autoActivationTimer; 0360 0361 Qt::GestureType m_swipeGesture; 0362 Qt::GestureType m_twoFingerTapGesture; 0363 0364 /** 0365 * When starting a rubberband selection during a Shift- or Control-key has been 0366 * pressed the current selection should never be deleted. To be able to restore 0367 * the current selection it is remembered in m_oldSelection before the 0368 * rubberband gets activated. 0369 */ 0370 KItemSet m_oldSelection; 0371 0372 /** 0373 * Assuming a view is given with a vertical scroll-orientation, grouped items and 0374 * a maximum of 4 columns: 0375 * 0376 * 1 2 3 4 0377 * 5 6 7 0378 * 8 9 10 11 0379 * 12 13 14 0380 * 0381 * If the current index is on 4 and key-down is pressed, then item 7 gets the current 0382 * item. Now when pressing key-down again item 11 should get the current item and not 0383 * item 10. This makes it necessary to keep track of the requested column to have a 0384 * similar behavior like in a text editor: 0385 */ 0386 int m_keyboardAnchorIndex; 0387 qreal m_keyboardAnchorPos; 0388 }; 0389 0390 #endif