1/*
2 SPDX-FileCopyrightText: 2015 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
3 SPDX-FileContributor: David Faure <david.faure@kdab.com>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#ifndef KEXTRACOLUMNSPROXYMODEL_H
9#define KEXTRACOLUMNSPROXYMODEL_H
10
11#include "kitemmodels_export.h"
12#include <QIdentityProxyModel>
13
14#include <memory>
15
16class KExtraColumnsProxyModelPrivate;
17
18/*!
19 * \class KExtraColumnsProxyModel
20 * \inmodule KItemModels
21 * \brief This proxy appends extra columns (after all existing columns).
22 *
23 * The proxy supports source models that have a tree structure.
24 * It also supports editing, and propagating changes from the source model.
25 * Row insertion/removal, column insertion/removal in the source model are supported.
26 *
27 * Not supported: adding/removing extra columns at runtime; having a different number of columns in subtrees;
28 * drag-n-drop support in the extra columns; moving columns.
29 *
30 * Derive from KExtraColumnsProxyModel, call appendColumn() (typically in the constructor) for each extra column,
31 * and reimplement extraColumnData() to allow KExtraColumnsProxyModel to retrieve the data to show in the extra columns.
32 *
33 * If you want your new column(s) to be somewhere else than at the right of the existing columns, you can
34 * use a KRearrangeColumnsProxyModel on top.
35 *
36 * \since 5.13
37 */
38class KITEMMODELS_EXPORT KExtraColumnsProxyModel : public QIdentityProxyModel
39{
40 Q_OBJECT
41public:
42 /*!
43 * Base class constructor.
44 * Remember to call setSourceModel afterwards, and appendColumn.
45 */
46 explicit KExtraColumnsProxyModel(QObject *parent = nullptr);
47 ~KExtraColumnsProxyModel() override;
48
49 // API
50
51 /*!
52 * Appends an extra column.
53 *
54 * \a header an optional text for the horizontal header
55 *
56 * This does not emit any signals - do it in the initial setup phase
57 */
58 void appendColumn(const QString &header = QString());
59
60 /*!
61 * Removes an extra column.
62 *
63 * \a idx index of the extra column (starting from 0).
64 *
65 * This does not emit any signals - do it in the initial setup phase
66 * \since 5.24
67 */
68 void removeExtraColumn(int idx);
69
70 /*!
71 * This method is called by data() for extra columns.
72 * Reimplement this method to return the data for the extra columns.
73 *
74 * \a parent the parent model index in the proxy model (only useful in tree models)
75 *
76 * \a row the row number for which the proxy model is querying for data (child of \a parent, if set)
77 *
78 * \a extraColumn the number of the extra column, starting at 0 (this doesn't require knowing how many columns the source model has)
79 *
80 * \a role the role being queried
81 *
82 * Returns the data at \a row and \a extraColumn
83 */
84 virtual QVariant extraColumnData(const QModelIndex &parent, int row, int extraColumn, int role = Qt::DisplayRole) const = 0;
85
86 // KF6 TODO: add extraColumnFlags() virtual method
87
88 /*!
89 * This method is called by setData() for extra columns.
90 * Reimplement this method to set the data for the extra columns, if editing is supported.
91 * Remember to call extraColumnDataChanged() after changing the data storage.
92 * The default implementation returns false.
93 */
94 virtual bool setExtraColumnData(const QModelIndex &parent, int row, int extraColumn, const QVariant &data, int role = Qt::EditRole);
95
96 /*!
97 * This method can be called by your derived class when the data in an extra column has changed.
98 * The use case is data that changes "by itself", unrelated to setData().
99 */
100 void extraColumnDataChanged(const QModelIndex &parent, int row, int extraColumn, const QList<int> &roles);
101
102 /*!
103 * Returns the extra column number (0, 1, ...) for a given column number of the proxymodel.
104 * This basically means subtracting the amount of columns in the source model.
105 */
106 int extraColumnForProxyColumn(int proxyColumn) const;
107 /*!
108 * Returns the proxy column number for a given extra column number (starting at 0).
109 * This basically means adding the amount of columns in the source model.
110 */
111 int proxyColumnForExtraColumn(int extraColumn) const;
112
113 // Implementation
114 void setSourceModel(QAbstractItemModel *model) override;
115 QModelIndex mapToSource(const QModelIndex &proxyIndex) const override;
116 QItemSelection mapSelectionToSource(const QItemSelection &selection) const override;
117 int columnCount(const QModelIndex &parent = QModelIndex()) const override;
118 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
119 bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
120 QModelIndex sibling(int row, int column, const QModelIndex &idx) const override;
121 QModelIndex buddy(const QModelIndex &index) const override;
122 Qt::ItemFlags flags(const QModelIndex &index) const override;
123 bool hasChildren(const QModelIndex &index) const override;
124 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
125 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
126 QModelIndex parent(const QModelIndex &child) const override;
127
128private:
129 Q_DECLARE_PRIVATE(KExtraColumnsProxyModel)
130 Q_PRIVATE_SLOT(d_func(), void _ec_sourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &, QAbstractItemModel::LayoutChangeHint))
131 Q_PRIVATE_SLOT(d_func(), void _ec_sourceLayoutChanged(const QList<QPersistentModelIndex> &, QAbstractItemModel::LayoutChangeHint))
132 std::unique_ptr<KExtraColumnsProxyModelPrivate> const d_ptr;
133};
134
135#endif
136

source code of kitemmodels/src/core/kextracolumnsproxymodel.h