File indexing completed on 2024-12-01 09:54:11

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2006, 2007 Andreas Hartmetz <ahartmetz@gmail.com>
0004     SPDX-FileCopyrightText: 2008 Urs Wolfer <uwolfer@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #ifndef KEXTENDABLEITEMDELEGATE_H
0010 #define KEXTENDABLEITEMDELEGATE_H
0011 
0012 #include <QStyledItemDelegate>
0013 #include <memory>
0014 
0015 #include <kitemviews_export.h>
0016 
0017 class QAbstractItemView;
0018 
0019 /**
0020  * @class KExtendableItemDelegate kextendableitemdelegate.h KExtendableItemDelegate
0021  *
0022  * This delegate makes it possible to display an arbitrary QWidget ("extender") that spans all columns below a line of items.
0023  * The extender will logically belong to a column in the row above it.
0024  *
0025  * It is your responsibility to devise a way to trigger extension and contraction of items, by calling
0026  * extendItem() and contractItem(). You can e.g. reimplement itemActivated() and similar functions.
0027  *
0028  * @warning extendItem() reparents the provided widget @a extender to the
0029  * viewport of the itemview it belongs to. The @a extender is destroyed when
0030  * you call contractItem() for the associated index. If you fail to do that
0031  * and the associated item gets deleted you're in trouble. It remains as a
0032  * visible artefact in your treeview. Additionally when closing your
0033  * application you get an assertion failure from KExtendableItemDelegate. Make
0034  * sure that you always call contractItem for indices before you delete them.
0035  *
0036  * @author Andreas Hartmetz <ahartmetz@gmail.com>
0037  *
0038  * @since 4.1
0039  */
0040 class KITEMVIEWS_EXPORT KExtendableItemDelegate : public QStyledItemDelegate
0041 {
0042     Q_OBJECT
0043 
0044 public:
0045     enum auxDataRoles {
0046         ShowExtensionIndicatorRole = Qt::UserRole + 200,
0047     };
0048 
0049     /**
0050      * Create a new KExtendableItemDelegate that belongs to @p parent. In contrast to generic
0051      * QAbstractItemDelegates, an instance of this class can only ever be the delegate for one
0052      * instance of af QAbstractItemView subclass.
0053      */
0054     KExtendableItemDelegate(QAbstractItemView *parent);
0055     ~KExtendableItemDelegate() override;
0056 
0057     /**
0058      * Re-implemented for internal reasons. API not affected.
0059      */
0060     QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
0061 
0062     /**
0063      * Re-implemented for internal reasons. API not affected.
0064      */
0065     void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
0066 
0067     /**
0068      * Insert the @p extender for item at @p index into the view.
0069      * If you need a parent for the extender at construction time, use the itemview's viewport().
0070      * The delegate takes ownership of the extender; the extender will also be reparented and
0071      * resized to the viewport.
0072      */
0073     void extendItem(QWidget *extender, const QModelIndex &index);
0074 
0075     /**
0076      * Remove the extender of item at @p index from the view. The extender widget
0077      * will be deleted.
0078      */
0079     void contractItem(const QModelIndex &index);
0080 
0081     /**
0082      * Close all extenders and delete all extender widgets.
0083      */
0084     void contractAll();
0085 
0086     /**
0087      * Return whether there is an extender that belongs to @p index.
0088      */
0089     bool isExtended(const QModelIndex &index) const;
0090 
0091     /**
0092      * Reimplement this function to adjust the internal geometry of the extender.
0093      * The external geometry of the extender will be set by the delegate.
0094      */
0095     virtual void updateExtenderGeometry(QWidget *extender, const QStyleOptionViewItem &option, const QModelIndex &index) const;
0096 
0097 Q_SIGNALS:
0098     /**
0099      * This signal indicates that the item at @p index was extended with @p extender.
0100      */
0101     void extenderCreated(QWidget *extender, const QModelIndex &index);
0102 
0103     /**
0104      * This signal indicates that the @p extender belonging to @p index has emitted the destroyed() signal.
0105      */
0106     void extenderDestroyed(QWidget *extender, const QModelIndex &index);
0107 
0108 protected:
0109     /**
0110      * Reimplement this function to fine-tune the position of the extender. @p option.rect will be a rectangle
0111      * that is as wide as the viewport and as high as the usual item height plus the extender size hint's height.
0112      * Its upper left corner will be at the upper left corner of the usual item.
0113      * You can place the returned rectangle of this function anywhere inside that area.
0114      */
0115     QRect extenderRect(QWidget *extender, const QStyleOptionViewItem &option, const QModelIndex &index) const;
0116 
0117     /**
0118      * The pixmap that is displayed to extend an item. @p pixmap must have the same size as the pixmap in setContractPixmap.
0119      */
0120     void setExtendPixmap(const QPixmap &pixmap);
0121 
0122     /**
0123      * The pixmap that is displayed to contract an item. @p pixmap must have the same size as the pixmap in setExtendPixmap.
0124      */
0125     void setContractPixmap(const QPixmap &pixmap);
0126 
0127     /**
0128      * Return the pixmap that is displayed to extend an item.
0129      */
0130     QPixmap extendPixmap();
0131 
0132     /**
0133      * Return the pixmap that is displayed to contract an item.
0134      */
0135     QPixmap contractPixmap();
0136 
0137 private:
0138     friend class KExtendableItemDelegatePrivate;
0139     std::unique_ptr<class KExtendableItemDelegatePrivate> const d;
0140 
0141     Q_PRIVATE_SLOT(d, void _k_extenderDestructionHandler(QObject *destroyed))
0142     Q_PRIVATE_SLOT(d, void _k_verticalScroll())
0143 };
0144 #endif // KEXTENDABLEITEMDELEGATE_H