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