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 kextracolumnsproxymodel.h KExtraColumnsProxyModel
20 *
21 * 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 * Author: David Faure, KDAB
37 * @since 5.13
38 */
39class KITEMMODELS_EXPORT KExtraColumnsProxyModel : public QIdentityProxyModel
40{
41 Q_OBJECT
42public:
43 /**
44 * Base class constructor.
45 * Remember to call setSourceModel afterwards, and appendColumn.
46 */
47 explicit KExtraColumnsProxyModel(QObject *parent = nullptr);
48 /**
49 * Destructor.
50 */
51 ~KExtraColumnsProxyModel() override;
52
53 // API
54
55 /**
56 * Appends an extra column.
57 * @param header an optional text for the horizontal header
58 * This does not emit any signals - do it in the initial setup phase
59 */
60 void appendColumn(const QString &header = QString());
61
62 /**
63 * Removes an extra column.
64 * @param idx index of the extra column (starting from 0).
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 * @param parent the parent model index in the proxy model (only useful in tree models)
75 * @param row the row number for which the proxy model is querying for data (child of @p parent, if set)
76 * @param extraColumn the number of the extra column, starting at 0 (this doesn't require knowing how many columns the source model has)
77 * @param role the role being queried
78 * @return the data at @p row and @p extraColumn
79 */
80 virtual QVariant extraColumnData(const QModelIndex &parent, int row, int extraColumn, int role = Qt::DisplayRole) const = 0;
81
82 // KF6 TODO: add extraColumnFlags() virtual method
83
84 /**
85 * This method is called by setData() for extra columns.
86 * Reimplement this method to set the data for the extra columns, if editing is supported.
87 * Remember to call extraColumnDataChanged() after changing the data storage.
88 * The default implementation returns false.
89 */
90 virtual bool setExtraColumnData(const QModelIndex &parent, int row, int extraColumn, const QVariant &data, int role = Qt::EditRole);
91
92 /**
93 * This method can be called by your derived class when the data in an extra column has changed.
94 * The use case is data that changes "by itself", unrelated to setData.
95 */
96 void extraColumnDataChanged(const QModelIndex &parent, int row, int extraColumn, const QList<int> &roles);
97
98 /**
99 * Returns the extra column number (0, 1, ...) for a given column number of the proxymodel.
100 * This basically means subtracting the amount of columns in the source model.
101 */
102 int extraColumnForProxyColumn(int proxyColumn) const;
103 /**
104 * Returns the proxy column number for a given extra column number (starting at 0).
105 * This basically means adding the amount of columns in the source model.
106 */
107 int proxyColumnForExtraColumn(int extraColumn) const;
108
109 // Implementation
110 /// @reimp
111 void setSourceModel(QAbstractItemModel *model) override;
112 /// @reimp
113 QModelIndex mapToSource(const QModelIndex &proxyIndex) const override;
114 /// @reimp
115 QItemSelection mapSelectionToSource(const QItemSelection &selection) const override;
116 /// @reimp
117 int columnCount(const QModelIndex &parent = QModelIndex()) const override;
118 /// @reimp
119 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
120 /// @reimp
121 bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
122 /// @reimp
123 QModelIndex sibling(int row, int column, const QModelIndex &idx) const override;
124 /// @reimp
125 QModelIndex buddy(const QModelIndex &index) const override;
126 /// @reimp
127 Qt::ItemFlags flags(const QModelIndex &index) const override;
128 /// @reimp
129 bool hasChildren(const QModelIndex &index) const override;
130 /// @reimp
131 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
132 /// @reimp
133 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
134 /// @reimp
135 QModelIndex parent(const QModelIndex &child) const override;
136
137private:
138 Q_DECLARE_PRIVATE(KExtraColumnsProxyModel)
139 Q_PRIVATE_SLOT(d_func(), void _ec_sourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &, QAbstractItemModel::LayoutChangeHint))
140 Q_PRIVATE_SLOT(d_func(), void _ec_sourceLayoutChanged(const QList<QPersistentModelIndex> &, QAbstractItemModel::LayoutChangeHint))
141 std::unique_ptr<KExtraColumnsProxyModelPrivate> const d_ptr;
142};
143
144#endif
145

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