1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/* ============================================================
 *
 * This file is a part of digiKam project
 * https://www.digikam.org
 *
 * Date        : 2010-01-16
 * Description : Qt item view for images
 *
 * SPDX-FileCopyrightText: 2009-2012 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
 * SPDX-FileCopyrightText: 2011-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 *
 * ============================================================ */

#ifndef DIGIKAM_ITEM_VIEW_CATEGORIZED_H
#define DIGIKAM_ITEM_VIEW_CATEGORIZED_H

// Local includes

#include "digikam_export.h"
#include "dcategorizedview.h"
#include "dragdropimplementations.h"

class QSortFilterProxyModel;

namespace Digikam
{

class DItemDelegate;
class ItemViewToolTip;

class DIGIKAM_EXPORT ItemViewCategorized : public DCategorizedView,
                                           public DragDropViewImplementation
{
    Q_OBJECT

public:

    explicit ItemViewCategorized(QWidget* const parent = nullptr);
    ~ItemViewCategorized() override;

    DItemDelegate* delegate()                                                       const;
    int            numberOfSelectedIndexes()                                        const;

    /**
     * Selects the index as current and scrolls to it
     */
    void toFirstIndex();
    void toLastIndex();
    void toNextIndex();
    void toPreviousIndex();
    void toIndex(const QModelIndex& index);
    void awayFromSelection();

    /**
     * Ensure a initial selected item.
     */
    void setInitialSelectedItem(bool enabled);

    /**
     * Scroll automatically the current index to center of the view.
     */
    void setScrollCurrentToCenter(bool enabled);

    /**
     * Like scrollTo, but only scrolls if the index is not visible, regardless of hint.
     */
    void scrollToRelaxed(const QModelIndex& index, ScrollHint hint = EnsureVisible);

    void invertSelection();
    void setSelectedIndexes(const QList<QModelIndex>& indexes);

    void setToolTipEnabled(bool enabled);
    bool isToolTipEnabled()                                                         const;

    /**
     * Sets the spacing. Does not use setSpacing()/spacing() from QListView
     */
    void setSpacing(int spacing);

    /**
     * Set if the PointingHand Cursor should be shown over the activation area
     */
    void setUsePointingHandCursor(bool useCursor);

    /**
     * Determine a step size for scrolling: The larger this number,
     * the smaller and more precise is the scrolling. Default is 10.
     */
    void setScrollStepGranularity(int factor);

    virtual QSortFilterProxyModel* filterModel()                                    const = 0;
    void scrollTo(const QModelIndex& index, ScrollHint hint = EnsureVisible)              override;

public Q_SLOTS:

    void showIndexNotification(const QModelIndex& index, const QString& message);
    void hideIndexNotification();

    void cut()   override { DragDropViewImplementation::cut();   }
    void copy()  override { DragDropViewImplementation::copy();  }
    void paste() override { DragDropViewImplementation::paste(); }

Q_SIGNALS:

    /**
     * Emitted when any selection change occurs. Any of the signals below will be emitted before.
     */
    void selectionChanged();

    /**
     * Emitted when the selection is completely cleared.
     */
    void selectionCleared();

    void zoomOutStep();
    void zoomInStep();

    /**
     * For overlays: Like the respective parent class signals, but with additional info.
     * Do not change the mouse events.
     */
    void clicked(const QMouseEvent* e, const QModelIndex& index);
    void entered(const QMouseEvent* e, const QModelIndex& index);

    /**
     * While clicked() is emitted with a valid index, this corresponds to clicking on empty space
     */
    void viewportClicked(const QMouseEvent* e);

    /**
     * Remember you may want to check if the event is accepted or ignored.
     * This signal is emitted after being handled by this widget.
     * You can accept it if ignored.
     */
    void keyPressed(QKeyEvent* e);


protected Q_SLOTS:

    void slotActivated(const QModelIndex& index);
    void slotClicked(const QModelIndex& index);
    void slotEntered(const QModelIndex& index);
    void layoutAboutToBeChanged();
    void layoutWasChanged();

    virtual void slotThemeChanged();
    virtual void slotSetupChanged();

protected:

    void encodeIsCutSelection(QMimeData* mime, bool isCutSelection);<--- Derived function 'ItemViewCategorized::encodeIsCutSelection'
    bool decodeIsCutSelection(const QMimeData* mimeData);<--- Derived function 'ItemViewCategorized::decodeIsCutSelection'

    void setToolTip(ItemViewToolTip* tip);
    void setItemDelegate(DItemDelegate* delegate);
    void updateDelegateSizes();
    void userInteraction();

    /**
     * Returns an index that is representative for the category at position pos
     */
    QModelIndex indexForCategoryAt(const QPoint& pos) const;

    /// reimplemented from parent class
    void contextMenuEvent(QContextMenuEvent* event)                                       override;
    void keyPressEvent(QKeyEvent* event)                                                  override;
    void leaveEvent(QEvent* event)                                                        override;
    void mouseMoveEvent(QMouseEvent* event)                                               override;
    void mousePressEvent(QMouseEvent* event)                                              override;
    void mouseReleaseEvent(QMouseEvent* event)                                            override;
    void resizeEvent(QResizeEvent* e)                                                     override;
    void reset()                                                                          override;
    void rowsAboutToBeRemoved(const QModelIndex& parent, int start, int end)              override;
    void rowsInserted(const QModelIndex& parent, int start, int end)                      override;
    void rowsRemoved(const QModelIndex& parent, int start, int end)                       override;
    void selectionChanged(const QItemSelection&, const QItemSelection&)                   override;
    bool viewportEvent(QEvent* event)                                                     override;
    void wheelEvent(QWheelEvent* event)                                                   override;
    QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)    override;

    /// Reimplement these in a subclass
    virtual void showContextMenuOnIndex(QContextMenuEvent* event, const QModelIndex& index);
    virtual void showContextMenu(QContextMenuEvent* event);
    virtual void indexActivated(const QModelIndex& index, Qt::KeyboardModifiers modifiers);

    /**
     * Provides default behavior, can reimplement in a subclass.
     * Returns true if a tooltip was shown.
     * The help event is optional.
     */
    virtual bool showToolTip(const QModelIndex& index,
                             QStyleOptionViewItem& option,
                             QHelpEvent* e = nullptr);

    DECLARE_VIEW_DRAG_DROP_METHODS(DCategorizedView)

    /**
     * Note: pure virtual dragDropHandler() still open from DragDropViewImplementation
     */
    QModelIndex mapIndexForDragDrop(const QModelIndex& index)                       const override;
    QPixmap     pixmapForDrag(const QList<QModelIndex>& indexes)                    const override;

    /**
     * Assuming the given indexes would be removed (hypothetically!),
     * return the index to be selected instead, starting from anchor.
     * The default implementation returns the next remaining sibling.
     */
    virtual QModelIndex nextIndexHint(const QModelIndex& indexToAnchor,
                                      const QItemSelectionRange& removed)           const;

private Q_SLOTS:

    void slotGridSizeChanged(const QSize&);

private:

    // Disable
    ItemViewCategorized(const ItemViewCategorized&)            = delete;
    ItemViewCategorized& operator=(const ItemViewCategorized&) = delete;

private:

    void ensureSelectionAfterChanges();

private:

    class Private;
    Private* const d = nullptr;
};

} // namespace Digikam

#endif // DIGIKAM_ITEM_VIEW_CATEGORIZED_H