kitemlistcontroller.h 13 KB
Newer Older
1 2 3 4 5 6 7
/*
 * SPDX-FileCopyrightText: 2011 Peter Penz <peter.penz19@gmail.com>
 *
 * Based on the Itemviews NG project from Trolltech Labs
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */
8 9 10 11

#ifndef KITEMLISTCONTROLLER_H
#define KITEMLISTCONTROLLER_H

12
#include "dolphin_export.h"
13 14
#include "kitemset.h"

15
#include <QObject>
16
#include <QPointF>
Steffen Hartleib's avatar
Steffen Hartleib committed
17
#include <QScroller>
Roman Inflianskas's avatar
Roman Inflianskas committed
18

Laurent Montel's avatar
Laurent Montel committed
19
class QTimer;
20
class KItemModelBase;
21
class KItemListKeyboardSearchManager;
22 23
class KItemListSelectionManager;
class KItemListView;
Peter Penz's avatar
Peter Penz committed
24
class KItemListWidget;
Steffen Hartleib's avatar
Steffen Hartleib committed
25
class QGestureEvent;
26 27 28 29 30 31 32
class QGraphicsSceneHoverEvent;
class QGraphicsSceneDragDropEvent;
class QGraphicsSceneMouseEvent;
class QGraphicsSceneResizeEvent;
class QGraphicsSceneWheelEvent;
class QInputMethodEvent;
class QKeyEvent;
Steffen Hartleib's avatar
Steffen Hartleib committed
33
class QTapGesture;
34 35 36 37 38 39 40 41 42 43 44 45
class QTransform;

/**
 * @brief Controls the view, model and selection of an item-list.
 *
 * For a working item-list it is mandatory to set a compatible view and model
 * with KItemListController::setView() and KItemListController::setModel().
 *
 * @see KItemListView
 * @see KItemModelBase
 * @see KItemListSelectionManager
 */
46
class DOLPHIN_EXPORT KItemListController : public QObject
47 48 49 50 51
{
    Q_OBJECT
    Q_PROPERTY(KItemModelBase* model READ model WRITE setModel)
    Q_PROPERTY(KItemListView *view READ view WRITE setView)
    Q_PROPERTY(SelectionBehavior selectionBehavior READ selectionBehavior WRITE setSelectionBehavior)
52
    Q_PROPERTY(AutoActivationBehavior autoActivationBehavior READ autoActivationBehavior WRITE setAutoActivationBehavior)
53
    Q_PROPERTY(MouseDoubleClickAction mouseDoubleClickAction READ mouseDoubleClickAction WRITE setMouseDoubleClickAction)
54 55 56 57 58 59 60

public:
    enum SelectionBehavior {
        NoSelection,
        SingleSelection,
        MultiSelection
    };
Spencer Brown's avatar
Spencer Brown committed
61
    Q_ENUM(SelectionBehavior)
62

63 64 65 66 67
    enum AutoActivationBehavior {
        ActivationAndExpansion,
        ExpansionOnly
    };

68 69 70 71 72
    enum MouseDoubleClickAction {
        ActivateAndExpandItem,
        ActivateItemOnly
    };

73 74 75 76 77
    /**
     * @param model  Model of the controller. The ownership is passed to the controller.
     * @param view   View of the controller. The ownership is passed to the controller.
     * @param parent Optional parent object.
     */
Kevin Funk's avatar
Kevin Funk committed
78
    KItemListController(KItemModelBase* model, KItemListView* view, QObject* parent = nullptr);
79
    ~KItemListController() override;
80 81 82 83 84 85 86 87 88 89 90 91

    void setModel(KItemModelBase* model);
    KItemModelBase* model() const;

    void setView(KItemListView* view);
    KItemListView* view() const;

    KItemListSelectionManager* selectionManager() const;

    void setSelectionBehavior(SelectionBehavior behavior);
    SelectionBehavior selectionBehavior() const;

92 93 94
    void setAutoActivationBehavior(AutoActivationBehavior behavior);
    AutoActivationBehavior autoActivationBehavior() const;

95 96 97
    void setMouseDoubleClickAction(MouseDoubleClickAction action);
    MouseDoubleClickAction mouseDoubleClickAction() const;

98 99
    int indexCloseToMousePressedPosition() const;

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
    /**
     * Sets the delay in milliseconds when dragging an object above an item
     * until the item gets activated automatically. A value of -1 indicates
     * that no automatic activation will be done at all (= default value).
     *
     * The hovered item must support dropping (see KItemModelBase::supportsDropping()),
     * otherwise the automatic activation is not available.
     *
     * After activating the item the signal itemActivated() will be
     * emitted. If the view supports the expanding of items
     * (KItemListView::supportsItemExpanding() returns true) and the item
     * itself is expandable (see KItemModelBase::isExpandable()) then instead
     * of activating the item it gets expanded instead (see
     * KItemModelBase::setExpanded()).
     */
    void setAutoActivationDelay(int delay);
    int autoActivationDelay() const;

118 119
    /**
     * If set to true, the signals itemActivated() and itemsActivated() are emitted
120
     * after a single-click of the left mouse button. If set to false (the default),
121
     * the setting from style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick) is used.
122
     */
123 124
    void setSingleClickActivationEnforced(bool singleClick);
    bool singleClickActivationEnforced() const;
125

126
    bool processEvent(QEvent* event, const QTransform& transform);
127 128

signals:
129 130 131 132
    /**
     * Is emitted if exactly one item has been activated by e.g. a mouse-click
     * or by pressing Return/Enter.
     */
133
    void itemActivated(int index);
134 135 136 137 138

    /**
     * Is emitted if more than one item has been activated by pressing Return/Enter
     * when having a selection.
     */
139
    void itemsActivated(const KItemSet& indexes);
140

141
    void itemMiddleClicked(int index);
Peter Penz's avatar
Peter Penz committed
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157

    /**
     * Emitted if a context-menu is requested for the item with
     * the index \a index. It is assured that the index is valid.
     */
    void itemContextMenuRequested(int index, const QPointF& pos);

    /**
     * Emitted if a context-menu is requested for the KItemListView.
     */
    void viewContextMenuRequested(const QPointF& pos);

    /**
     * Emitted if a context-menu is requested for the header of the KItemListView.
     */
    void headerContextMenuRequested(const QPointF& pos);
158 159 160 161 162

    /**
     * Is emitted if the item with the index \p index gets hovered.
     */
    void itemHovered(int index);
Peter Penz's avatar
Peter Penz committed
163

164 165 166 167 168 169 170
    /**
     * Is emitted if the item with the index \p index gets unhovered.
     * It is assured that the signal itemHovered() for this index
     * has been emitted before.
     */
    void itemUnhovered(int index);

Peter Penz's avatar
Peter Penz committed
171 172
    /**
     * Is emitted if a mouse-button has been pressed above an item.
173 174
     * If the index is smaller than 0, the mouse-button has been pressed
     * above the viewport.
Peter Penz's avatar
Peter Penz committed
175
     */
176
    void mouseButtonPressed(int itemIndex, Qt::MouseButtons buttons);
Peter Penz's avatar
Peter Penz committed
177 178 179

    /**
     * Is emitted if a mouse-button has been released above an item.
180 181 182
     * It is assured that the signal mouseButtonPressed() has been emitted before.
     * If the index is smaller than 0, the mouse-button has been pressed
     * above the viewport.
Peter Penz's avatar
Peter Penz committed
183
     */
184
    void mouseButtonReleased(int itemIndex, Qt::MouseButtons buttons);
Peter Penz's avatar
Peter Penz committed
185

186 187
    void itemExpansionToggleClicked(int index);

Peter Penz's avatar
Peter Penz committed
188 189 190 191
    /**
     * Is emitted if a drop event is done above the item with the index
     * \a index. If \a index is < 0 the drop event is done above an
     * empty area of the view.
192 193 194
     * TODO: Introduce a new signal viewDropEvent(QGraphicsSceneDragDropEvent),
     *       which is emitted if the drop event occurs on an empty area in
     *       the view, and make sure that index is always >= 0 in itemDropEvent().
Peter Penz's avatar
Peter Penz committed
195 196 197
     */
    void itemDropEvent(int index, QGraphicsSceneDragDropEvent* event);

198 199 200 201 202 203
    /**
     * Is emitted if a drop event is done between the item with the index
     * \a index and the previous item.
     */
    void aboveItemDropEvent(int index, QGraphicsSceneDragDropEvent* event);

204 205 206 207 208
    /**
     * Is emitted if the Escape key is pressed.
     */
    void escapePressed();

209 210 211
    void modelChanged(KItemModelBase* current, KItemModelBase* previous);
    void viewChanged(KItemListView* current, KItemListView* previous);

212 213
    void selectedItemTextPressed(int index);

Steffen Hartleib's avatar
Steffen Hartleib committed
214 215 216 217 218 219 220 221
    void scrollerStop();
    void increaseZoom();
    void decreaseZoom();
    void swipeUp();

public slots:
    void slotStateChanged(QScroller::State newState);

222
private slots:
Peter Penz's avatar
Peter Penz committed
223
    void slotViewScrollOffsetChanged(qreal current, qreal previous);
224

225 226 227 228 229 230
    /**
     * Is invoked when the rubberband boundaries have been changed and will select
     * all items that are touched by the rubberband.
     */
    void slotRubberBandChanged();

231
    void slotChangeCurrentItem(const QString& text, bool searchFromNextItem);
232

233 234
    void slotAutoActivationTimeout();

235
private:
236
    /**
Peter Penz's avatar
Peter Penz committed
237
     * Creates a QDrag object and initiates a drag-operation.
238
     */
Peter Penz's avatar
Peter Penz committed
239
    void startDragging();
240

Peter Penz's avatar
Peter Penz committed
241 242 243 244 245 246 247 248 249 250 251 252
    /**
     * @return Widget that is currently in the hovered state. 0 is returned
     *         if no widget is marked as hovered.
     */
    KItemListWidget* hoveredWidget() const;

    /**
     * @return Widget that is below the position \a pos. 0 is returned
     *         if no widget is below the position.
     */
    KItemListWidget* widgetForPos(const QPointF& pos) const;

253 254 255 256 257 258 259 260 261
    /**
     * Updates m_keyboardAnchorIndex and m_keyboardAnchorPos. If no anchor is
     * set, it will be adjusted to the current item. If it is set it will be
     * checked whether it is still valid, otherwise it will be reset to the
     * current item.
     */
    void updateKeyboardAnchor();

    /**
262 263
     * @return Index for the next row based on \a index.
     *         If there is no next row \a index will be returned.
264
     */
265
    int nextRowIndex(int index) const;
266 267

    /**
268 269
     * @return Index for the previous row based on  \a index.
     *         If there is no previous row \a index will be returned.
270
     */
271
    int previousRowIndex(int index) const;
272 273 274 275 276 277 278 279 280

    /**
     * Helper method for updateKeyboardAnchor(), previousRowIndex() and nextRowIndex().
     * @return The position of the keyboard anchor for the item with the index \a index.
     *         If a horizontal scrolling is used the y-position of the item will be returned,
     *         for the vertical scrolling the x-position will be returned.
     */
    qreal keyboardAnchorPos(int index) const;

281 282 283 284 285 286 287
    /**
     * Dependent on the selection-behavior the extendedSelectionRegion-property
     * of the KItemListStyleOption from the view should be adjusted: If no
     * rubberband selection is used the property should be enabled.
     */
    void updateExtendedSelectionRegion();

288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
    bool keyPressEvent(QKeyEvent* event);
    bool inputMethodEvent(QInputMethodEvent* event);
    bool mousePressEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform);
    bool mouseMoveEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform);
    bool mouseReleaseEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform);
    bool mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event, const QTransform& transform);
    bool dragEnterEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform);
    bool dragLeaveEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform);
    bool dragMoveEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform);
    bool dropEvent(QGraphicsSceneDragDropEvent* event, const QTransform& transform);
    bool hoverEnterEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform);
    bool hoverMoveEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform);
    bool hoverLeaveEvent(QGraphicsSceneHoverEvent* event, const QTransform& transform);
    bool wheelEvent(QGraphicsSceneWheelEvent* event, const QTransform& transform);
    bool resizeEvent(QGraphicsSceneResizeEvent* event, const QTransform& transform);
Steffen Hartleib's avatar
Steffen Hartleib committed
303 304 305 306 307 308 309 310 311
    bool gestureEvent(QGestureEvent* event, const QTransform& transform);
    void tapTriggered(QTapGesture* tap, const QTransform& transform);
    void tapAndHoldTriggered(QGestureEvent* event, const QTransform& transform);
    void pinchTriggered(QGestureEvent* event, const QTransform& transform);
    void swipeTriggered(QGestureEvent* event, const QTransform& transform);
    void twoFingerTapTriggered(QGestureEvent* event, const QTransform& transform);
    bool onPress(const QPoint& screenPos, const QPointF& pos, const Qt::KeyboardModifiers modifiers, const Qt::MouseButtons buttons);
    bool onRelease(const QPointF& pos, const Qt::KeyboardModifiers modifiers, const Qt::MouseButtons buttons, bool touch);
    void startRubberBand();
312

313
private:
314
    bool m_singleClickActivationEnforced;
Peter Penz's avatar
Peter Penz committed
315
    bool m_selectionTogglePressed;
316
    bool m_clearSelectionIfItemsAreNotDragged;
Steffen Hartleib's avatar
Steffen Hartleib committed
317 318 319 320 321
    bool m_isSwipeGesture;
    bool m_dragActionOrRightClick;
    bool m_scrollerIsScrolling;
    bool m_pinchGestureInProgress;
    bool m_mousePress;
322
    SelectionBehavior m_selectionBehavior;
323
    AutoActivationBehavior m_autoActivationBehavior;
324
    MouseDoubleClickAction m_mouseDoubleClickAction;
325 326 327
    KItemModelBase* m_model;
    KItemListView* m_view;
    KItemListSelectionManager* m_selectionManager;
328
    KItemListKeyboardSearchManager* m_keyboardManager;
329
    int m_pressedIndex;
330
    QPointF m_pressedMousePos;
331

332 333
    QTimer* m_autoActivationTimer;

Steffen Hartleib's avatar
Steffen Hartleib committed
334 335 336 337
    Qt::GestureType m_swipeGesture;
    Qt::GestureType m_twoFingerTapGesture;
    Qt::MouseEventSource m_lastSource;

338 339 340
    /**
     * When starting a rubberband selection during a Shift- or Control-key has been
     * pressed the current selection should never be deleted. To be able to restore
341
     * the current selection it is remembered in m_oldSelection before the
342 343
     * rubberband gets activated.
     */
344
    KItemSet m_oldSelection;
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360

    /**
     * Assuming a view is given with a vertical scroll-orientation, grouped items and
     * a maximum of 4 columns:
     *
     *  1  2  3  4
     *  5  6  7
     *  8  9 10 11
     * 12 13 14
     *
     * If the current index is on 4 and key-down is pressed, then item 7 gets the current
     * item. Now when pressing key-down again item 11 should get the current item and not
     * item 10. This makes it necessary to keep track of the requested column to have a
     * similar behavior like in a text editor:
     */
    int m_keyboardAnchorIndex;
361
    qreal m_keyboardAnchorPos;
362 363 364 365 366
};

#endif