1 /*
2  * Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB.  All rights reserved.
3  *
4  * This file is part of the KD Chart library.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef KCHARTDATASETPROXYMODEL_H
21 #define KCHARTDATASETPROXYMODEL_H
22 
23 #include <QVector>
24 #include <QSortFilterProxyModel>
25 
26 #include "kchart_export.h"
27 
28 namespace KChart {
29 
30     class IndexOutOfBoundsException;
31 
32     typedef QVector<int> DatasetDescriptionVector;
33 
34     /** DatasetProxyModel takes a KChart dataset configuration and translates
35         it into a filtering proxy model.
36 
37         The resulting model will only contain the part of the model that is
38         selected by the dataset, and the according row and column header
39         data.
40 
41         Currently, this model is implemented for table models only. The way it
42         would work with models representing a tree is to be decided.
43 
44         The column selection is configured by passing a dataset description
45         vector to the model. This vector (of integers) is supposed to have one
46         value for each column of the original model. If the value at position
47         x is -1, column x of the original model is not included in the
48         dataset. If it is between 0 and (columnCount() -1), it is the column
49         the source column is mapped to in the resulting model. Any other value
50         is an error.
51     */
52     class KCHART_EXPORT DatasetProxyModel : public QSortFilterProxyModel
53     {
54         Q_OBJECT
55     public:
56         /** Create a DatasetProxyModel.
57             Without further configuration, this model is invalid.
58             @see setDatasetDescriptionVector
59         */
60         explicit DatasetProxyModel ( QObject* parent = nullptr );
61 
62         QModelIndex buddy( const QModelIndex& index ) const override;
63 
64         Qt::ItemFlags flags( const QModelIndex& index ) const override;
65 
66         QModelIndex index( int row, int column,
67                            const QModelIndex &parent = QModelIndex() ) const override;
68         QModelIndex parent(const QModelIndex &child ) const override;
69 
70         /** Implements the mapping from the source to the proxy indexes. */
71         QModelIndex mapFromSource ( const QModelIndex & sourceIndex ) const override;
72 
73         /** Implements the mapping from the proxy to the source indexes. */
74         QModelIndex mapToSource ( const QModelIndex& proxyIndex ) const override;
75 
76         /** Overloaded from base class. */
77         QVariant data(const QModelIndex &index, int role) const override;
78 
79         /** Overloaded from base class. */
80         bool setData( const QModelIndex& index, const QVariant& value, int role ) override;
81 
82         /** Overloaded from base class. */
83         QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const override;
84 
85         /** Overloaded from base class. */
86         void setSourceModel(QAbstractItemModel *sourceModel) override;
87 
88         /** Set the root index of the table in
89 	    the source model */
90         void setSourceRootIndex(const QModelIndex& rootIdx);
91 
92 
93     public Q_SLOTS:
94         /** Reset all dataset description.
95             After that, the result of the proxying is an empty model (a new
96             dataset description needs to be set to achieve a non-empty result).
97         */
98         void resetDatasetDescriptions();
99 
100         /** Configure the dataset selection for the columns.
101             Every call to this method resets the previous dataset
102             description.
103         */
104         void setDatasetColumnDescriptionVector ( const DatasetDescriptionVector& columnConfig );
105 
106         /** Configure the dataset selection for the rows.
107             Every call to this method resets the previous dataset
108             description.
109         */
110         void setDatasetRowDescriptionVector ( const DatasetDescriptionVector& rowConfig );
111 
112         /** Convenience method to configure rows and columns in one step. */
113         void setDatasetDescriptionVectors (
114             const DatasetDescriptionVector& rowConfig,
115             const DatasetDescriptionVector& columnConfig );
116 
117         // FIXME: add convenience methods to configure common dataset
118         // selections (like rectangular areas etc)
119 
120     protected:
121         /** Decide whether the column is accepted. */
122         bool filterAcceptsColumn ( int sourceColumn,
123                                    const QModelIndex & ) const override;
124 
125 
126         /** Decide whether the row is accepted. */
127         bool filterAcceptsRow ( int source_row, const QModelIndex & source_parent ) const override;
128 
129     private:
130 
131         /** Map a proxy column to a source column. */
132         int mapProxyColumnToSource ( const int& proxyColumn ) const;
133 
134         /** Map a source column to a proxy column. */
135         int mapSourceColumnToProxy ( const int& sourceColumn ) const;
136 
137         /** Map a proxy row to a source row. */
138         int mapProxyRowToSource ( const int& proxyRow ) const;
139 
140         /** Map a source row to a proxy row. */
141         int mapSourceRowToProxy ( const int& sourceRow ) const;
142 
143         /** Initialize the transformation vectors from the dataset
144             description.
145 
146             The input parameter "Configuration" is a vector that specifies
147             what srce column will be mapped to what proxy column. Example:
148 
149             position: [0][1][2]
150             value:    [2][0][1]
151 
152             This will map the source column 2 to proxy column 0, source 0 to
153             proxy 1, and source 1 to proxy 2. Source needs to have at least 2
154             column. The source-to-proxy mapping looks the same, except that it
155             may contain values of -1, which means this column is not part of
156             the resulting model. The values in the configuration vector must
157             be unique (otherwise, a 1-to-1 mapping in both directions is
158             impossible).
159 
160             sourceCount is the number of columns in the source model. The proxy-to-source map has
161             as many elements as the proxy has columns, the source-to-proxy map
162             has as many elements as the source has columns. Same goes for rows
163             (the mapping logic is the same).
164 
165          */
166         void initializeDatasetDecriptors (
167             const DatasetDescriptionVector& inConfiguration,
168             int sourceCount,
169             DatasetDescriptionVector& outSourceToProxyMap,
170             DatasetDescriptionVector& outProxyToSourceMap );
171 
172         DatasetDescriptionVector mColSrcToProxyMap;
173         DatasetDescriptionVector mColProxyToSrcMap;
174         DatasetDescriptionVector mRowSrcToProxyMap;
175         DatasetDescriptionVector mRowProxyToSrcMap;
176 
177         int mProxyRowCount;
178         int mProxyColumnCount;
179         QModelIndex mRootIndex;
180     };
181 
182 }
183 
184 
185 #endif
186