1 | /* |
2 | This file is part of the KDE libraries |
3 | SPDX-FileCopyrightText: 2006, 2007 Andreas Hartmetz <ahartmetz@gmail.com> |
4 | SPDX-FileCopyrightText: 2008 Urs Wolfer <uwolfer@kde.org> |
5 | |
6 | SPDX-License-Identifier: LGPL-2.0-or-later |
7 | */ |
8 | |
9 | #ifndef KEXTENDABLEITEMDELEGATE_H |
10 | #define KEXTENDABLEITEMDELEGATE_H |
11 | |
12 | #include <QStyledItemDelegate> |
13 | #include <memory> |
14 | |
15 | #include <kitemviews_export.h> |
16 | |
17 | class QAbstractItemView; |
18 | |
19 | /** |
20 | * @class KExtendableItemDelegate kextendableitemdelegate.h KExtendableItemDelegate |
21 | * |
22 | * This delegate makes it possible to display an arbitrary QWidget ("extender") that spans all columns below a line of items. |
23 | * The extender will logically belong to a column in the row above it. |
24 | * |
25 | * It is your responsibility to devise a way to trigger extension and contraction of items, by calling |
26 | * extendItem() and contractItem(). You can e.g. reimplement itemActivated() and similar functions. |
27 | * |
28 | * @warning extendItem() reparents the provided widget @a extender to the |
29 | * viewport of the itemview it belongs to. The @a extender is destroyed when |
30 | * you call contractItem() for the associated index. If you fail to do that |
31 | * and the associated item gets deleted you're in trouble. It remains as a |
32 | * visible artefact in your treeview. Additionally when closing your |
33 | * application you get an assertion failure from KExtendableItemDelegate. Make |
34 | * sure that you always call contractItem for indices before you delete them. |
35 | * |
36 | * @author Andreas Hartmetz <ahartmetz@gmail.com> |
37 | * |
38 | * @since 4.1 |
39 | */ |
40 | class KITEMVIEWS_EXPORT KExtendableItemDelegate : public QStyledItemDelegate |
41 | { |
42 | Q_OBJECT |
43 | |
44 | public: |
45 | enum auxDataRoles { |
46 | ShowExtensionIndicatorRole = Qt::UserRole + 200, |
47 | }; |
48 | |
49 | /** |
50 | * Create a new KExtendableItemDelegate that belongs to @p parent. In contrast to generic |
51 | * QAbstractItemDelegates, an instance of this class can only ever be the delegate for one |
52 | * instance of af QAbstractItemView subclass. |
53 | */ |
54 | KExtendableItemDelegate(QAbstractItemView *parent); |
55 | ~KExtendableItemDelegate() override; |
56 | |
57 | /** |
58 | * Re-implemented for internal reasons. API not affected. |
59 | */ |
60 | QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; |
61 | |
62 | /** |
63 | * Re-implemented for internal reasons. API not affected. |
64 | */ |
65 | void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; |
66 | |
67 | /** |
68 | * Insert the @p extender for item at @p index into the view. |
69 | * If you need a parent for the extender at construction time, use the itemview's viewport(). |
70 | * The delegate takes ownership of the extender; the extender will also be reparented and |
71 | * resized to the viewport. |
72 | */ |
73 | void extendItem(QWidget *extender, const QModelIndex &index); |
74 | |
75 | /** |
76 | * Remove the extender of item at @p index from the view. The extender widget |
77 | * will be deleted. |
78 | */ |
79 | void contractItem(const QModelIndex &index); |
80 | |
81 | /** |
82 | * Close all extenders and delete all extender widgets. |
83 | */ |
84 | void contractAll(); |
85 | |
86 | /** |
87 | * Return whether there is an extender that belongs to @p index. |
88 | */ |
89 | bool isExtended(const QModelIndex &index) const; |
90 | |
91 | /** |
92 | * Reimplement this function to adjust the internal geometry of the extender. |
93 | * The external geometry of the extender will be set by the delegate. |
94 | */ |
95 | virtual void updateExtenderGeometry(QWidget *extender, const QStyleOptionViewItem &option, const QModelIndex &index) const; |
96 | |
97 | Q_SIGNALS: |
98 | /** |
99 | * This signal indicates that the item at @p index was extended with @p extender. |
100 | */ |
101 | void extenderCreated(QWidget *extender, const QModelIndex &index); |
102 | |
103 | /** |
104 | * This signal indicates that the @p extender belonging to @p index has emitted the destroyed() signal. |
105 | */ |
106 | void extenderDestroyed(QWidget *extender, const QModelIndex &index); |
107 | |
108 | protected: |
109 | /** |
110 | * Reimplement this function to fine-tune the position of the extender. @p option.rect will be a rectangle |
111 | * that is as wide as the viewport and as high as the usual item height plus the extender size hint's height. |
112 | * Its upper left corner will be at the upper left corner of the usual item. |
113 | * You can place the returned rectangle of this function anywhere inside that area. |
114 | */ |
115 | QRect extenderRect(QWidget *extender, const QStyleOptionViewItem &option, const QModelIndex &index) const; |
116 | |
117 | /** |
118 | * The pixmap that is displayed to extend an item. @p pixmap must have the same size as the pixmap in setContractPixmap. |
119 | */ |
120 | void setExtendPixmap(const QPixmap &pixmap); |
121 | |
122 | /** |
123 | * The pixmap that is displayed to contract an item. @p pixmap must have the same size as the pixmap in setExtendPixmap. |
124 | */ |
125 | void setContractPixmap(const QPixmap &pixmap); |
126 | |
127 | /** |
128 | * Return the pixmap that is displayed to extend an item. |
129 | */ |
130 | QPixmap extendPixmap(); |
131 | |
132 | /** |
133 | * Return the pixmap that is displayed to contract an item. |
134 | */ |
135 | QPixmap contractPixmap(); |
136 | |
137 | private: |
138 | friend class KExtendableItemDelegatePrivate; |
139 | std::unique_ptr<class KExtendableItemDelegatePrivate> const d; |
140 | |
141 | Q_PRIVATE_SLOT(d, void _k_extenderDestructionHandler(QObject *destroyed)) |
142 | Q_PRIVATE_SLOT(d, void _k_verticalScroll()) |
143 | }; |
144 | #endif // KEXTENDABLEITEMDELEGATE_H |
145 | |