1 /*
2  * SPDX-FileCopyrightText: 2011 Peter Penz <peter.penz19@gmail.com>
3  *
4  * SPDX-License-Identifier: GPL-2.0-or-later
5  */
6 
7 #ifndef KITEMLISTHEADERWIDGET_H
8 #define KITEMLISTHEADERWIDGET_H
9 
10 #include "dolphin_export.h"
11 
12 #include <QGraphicsWidget>
13 #include <QHash>
14 #include <QList>
15 
16 class KItemModelBase;
17 
18 /**
19  * @brief Widget the implements the header for KItemListView showing the currently used roles.
20  *
21  * The widget is an internal API, the user of KItemListView may only access the
22  * class KItemListHeader.
23  */
24 class DOLPHIN_EXPORT KItemListHeaderWidget : public QGraphicsWidget
25 {
26     Q_OBJECT
27 
28 public:
29     explicit KItemListHeaderWidget(QGraphicsWidget* parent = nullptr);
30     ~KItemListHeaderWidget() override;
31 
32     void setModel(KItemModelBase* model);
33     KItemModelBase* model() const;
34 
35     void setAutomaticColumnResizing(bool automatic);
36     bool automaticColumnResizing() const;
37 
38     void setColumns(const QList<QByteArray>& roles);
39     QList<QByteArray> columns() const;
40 
41     void setColumnWidth(const QByteArray& role, qreal width);
42     qreal columnWidth(const QByteArray& role) const;
43 
44     /**
45      * Sets the column-width that is required to show the role unclipped.
46      */
47     void setPreferredColumnWidth(const QByteArray& role, qreal width);
48     qreal preferredColumnWidth(const QByteArray& role) const;
49 
50     void setOffset(qreal offset);
51     qreal offset() const;
52 
53     qreal minimumColumnWidth() const;
54 
55     void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = nullptr) override;
56 
57 Q_SIGNALS:
58     /**
59      * Is emitted if the width of a visible role has been adjusted by the user with the mouse
60      * (no signal is emitted if KItemListHeader::setVisibleRoleWidth() is invoked).
61      */
62     void columnWidthChanged(const QByteArray& role,
63                             qreal currentWidth,
64                             qreal previousWidth);
65 
66     /**
67      * Is emitted if the user has released the mouse button after adjusting the
68      * width of a visible role.
69      */
70     void columnWidthChangeFinished(const QByteArray& role,
71                                    qreal currentWidth);
72 
73     /**
74      * Is emitted if the position of the column has been changed.
75      */
76     void columnMoved(const QByteArray& role, int currentIndex, int previousIndex);
77 
78     /**
79      * Is emitted if the user has changed the sort order by clicking on a
80      * header item. The sort order of the model has already been adjusted to
81      * the current sort order. Note that no signal will be emitted if the
82      * sort order of the model has been changed without user interaction.
83      */
84     void sortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous);
85 
86     /**
87      * Is emitted if the user has changed the sort role by clicking on a
88      * header item. The sort role of the model has already been adjusted to
89      * the current sort role. Note that no signal will be emitted if the
90      * sort role of the model has been changed without user interaction.
91      */
92     void sortRoleChanged(const QByteArray& current, const QByteArray& previous);
93 
94 protected:
95     void mousePressEvent(QGraphicsSceneMouseEvent* event) override;
96     void mouseReleaseEvent(QGraphicsSceneMouseEvent* event) override;
97     void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override;
98     void mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event) override;
99     void hoverEnterEvent(QGraphicsSceneHoverEvent* event) override;
100     void hoverLeaveEvent(QGraphicsSceneHoverEvent* event) override;
101     void hoverMoveEvent(QGraphicsSceneHoverEvent* event) override;
102 
103 private Q_SLOTS:
104     void slotSortRoleChanged(const QByteArray& current, const QByteArray& previous);
105     void slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous);
106 
107 private:
108     void paintRole(QPainter* painter,
109                    const QByteArray& role,
110                    const QRectF& rect,
111                    int orderIndex,
112                    QWidget* widget = nullptr) const;
113 
114     void updatePressedRoleIndex(const QPointF& pos);
115     void updateHoveredRoleIndex(const QPointF& pos);
116     int roleIndexAt(const QPointF& pos) const;
117     bool isAboveRoleGrip(const QPointF& pos, int roleIndex) const;
118 
119     /**
120      * Creates a pixmap of the role with the index \a roleIndex that is shown
121      * during moving a role.
122      */
123     QPixmap createRolePixmap(int roleIndex) const;
124 
125     /**
126      * @return Target index of the currently moving visible role based on the current
127      *         state of m_movingRole.
128      */
129     int targetOfMovingRole() const;
130 
131     /**
132      * @return x-position of the left border of the role \a role.
133      */
134     qreal roleXPosition(const QByteArray& role) const;
135 
136 private:
137     enum RoleOperation
138     {
139         NoRoleOperation,
140         ResizeRoleOperation,
141         MoveRoleOperation
142     };
143 
144     bool m_automaticColumnResizing;
145     KItemModelBase* m_model;
146     qreal m_offset;
147     QList<QByteArray> m_columns;
148     QHash<QByteArray, qreal> m_columnWidths;
149     QHash<QByteArray, qreal> m_preferredColumnWidths;
150 
151     int m_hoveredRoleIndex;
152     int m_pressedRoleIndex;
153     RoleOperation m_roleOperation;
154     QPointF m_pressedMousePos;
155 
156     struct MovingRole
157     {
158         QPixmap pixmap;
159         int x;
160         int xDec;
161         int index;
162     } m_movingRole;
163 };
164 
165 #endif
166 
167 
168