File indexing completed on 2024-12-15 04:02:30

0001 /*
0002  * SPDX-FileCopyrightText: 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
0003  *
0004  * This file is part of the KD Chart library.
0005  *
0006  * SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #ifndef KCHARTCARTESIANDIAGRAMDATACOMPRESSOR_H
0010 #define KCHARTCARTESIANDIAGRAMDATACOMPRESSOR_H
0011 
0012 //
0013 //  W A R N I N G
0014 //  -------------
0015 //
0016 // This file is not part of the KD Chart API.  It exists purely as an
0017 // implementation detail.  This header file may change from version to
0018 // version without notice, or even be removed.
0019 //
0020 // We mean it.
0021 //
0022 
0023 #include <limits>
0024 
0025 #include <QPair>
0026 #include <QVector>
0027 #include <QObject>
0028 #include <QPointer>
0029 #include <QModelIndex>
0030 
0031 #include "KChartDataValueAttributes.h"
0032 #include "KChartModelDataCache_p.h"
0033 
0034 #include "kchart_export.h"
0035 
0036 class CartesianDiagramDataCompressorTests;
0037 QT_BEGIN_NAMESPACE
0038 class QAbstractItemModel;
0039 QT_END_NAMESPACE
0040 
0041 namespace KChart {
0042 
0043     class AbstractDiagram;
0044 
0045     // - transparently compress table model data if the diagram widget
0046     // size does not allow to display all data points in an acceptable way
0047     // - the class acts much like a proxy model, but is not
0048     // implemented as one, to avoid performance penalties by QVariant
0049     // conversions
0050     // - a wanted side effect is that the compressor will deliver
0051     // more precise values for more precise media, like paper
0052     // (a) this is absolutely strictly seriously private API of KChart
0053     // (b) if possible, this class is going to be templatized for
0054     // different diagram types
0055 
0056     // KCHART_EXPORT is needed as long there's a test using
0057     // this class directly
0058     class KCHART_EXPORT CartesianDiagramDataCompressor : public QObject
0059     {
0060         Q_OBJECT
0061         friend class ::CartesianDiagramDataCompressorTests;
0062 
0063     public:
0064         class DataPoint {
0065         public:
0066             DataPoint()
0067                 : key( std::numeric_limits< qreal >::quiet_NaN() ),
0068                   value( std::numeric_limits< qreal >::quiet_NaN() ),
0069                   hidden( false )
0070                   {}
0071             qreal key;
0072             qreal value;
0073             bool hidden;
0074             QModelIndex index;
0075         };
0076         typedef QVector<DataPoint> DataPointVector;
0077         class CachePosition {
0078         public:
0079             CachePosition()
0080                 : row( -1 ),
0081                   column( -1 )
0082                   {}
0083             CachePosition( int row, int column )
0084                 : row( row ),
0085                   column( column )
0086                   {}
0087             int row;
0088             int column;
0089 
0090             bool operator==( const CachePosition& rhs ) const
0091             {
0092                 return row == rhs.row &&
0093                        column == rhs.column;
0094             }
0095             bool operator<( const CachePosition& rhs ) const
0096             {
0097                 // This function is used to topologically sort all cache positions.
0098 
0099                 // Think of them as entries in a matrix or table:
0100                 // An entry comes before another entry if it is either above the other
0101                 // entry, or in the same row and to the left of the other entry.
0102                 return row < rhs.row || ( row == rhs.row && column < rhs.column );
0103             }
0104         };
0105 
0106         typedef QMap< QModelIndex, DataValueAttributes > AggregatedDataValueAttributes;
0107         typedef QMap< CartesianDiagramDataCompressor::CachePosition, AggregatedDataValueAttributes > DataValueAttributesCache;
0108 
0109         enum ApproximationMode {
0110             // do not approximate, interpolate by averaging all
0111             // datapoints for a pixel
0112             Precise,
0113             // approximate by averaging out over prime number distances
0114             SamplingSeven
0115         };
0116 
0117         explicit CartesianDiagramDataCompressor( QObject* parent = nullptr );
0118 
0119         // input: model, chart resolution, approximation mode
0120         void setModel( QAbstractItemModel* );
0121         void setRootIndex( const QModelIndex& root );
0122         void setResolution( int x, int y );
0123         void recalcResolution();
0124         void setApproximationMode( ApproximationMode mode );
0125         void setDatasetDimension( int dimension );
0126 
0127         // output: resulting model resolution, data points
0128         // FIXME (Mirko) rather stupid naming, Mirko!
0129         int modelDataColumns() const;
0130         int modelDataRows() const;
0131         const DataPoint& data( const CachePosition& ) const;
0132 
0133         QPair< QPointF, QPointF > dataBoundaries() const;
0134 
0135         AggregatedDataValueAttributes aggregatedAttrs(
0136                 const AbstractDiagram* diagram,
0137                 const QModelIndex & index,
0138                 const CachePosition& position ) const;
0139 
0140     public Q_SLOTS:
0141         // FIXME resolution changes and root index changes should all
0142         // be catchable with this method:
0143         void slotDiagramLayoutChanged( KChart::AbstractDiagram* );
0144 
0145     private Q_SLOTS:
0146         void slotRowsAboutToBeInserted( const QModelIndex&, int, int );
0147         void slotRowsInserted( const QModelIndex&, int, int );
0148         void slotRowsAboutToBeRemoved( const QModelIndex&, int, int );
0149         void slotRowsRemoved( const QModelIndex&, int, int );
0150 
0151         void slotColumnsAboutToBeInserted( const QModelIndex&, int, int );
0152         void slotColumnsInserted( const QModelIndex&, int, int );
0153         void slotColumnsAboutToBeRemoved( const QModelIndex&, int, int );
0154         void slotColumnsRemoved( const QModelIndex&, int, int );
0155 
0156         void slotModelHeaderDataChanged( Qt::Orientation, int, int );
0157         void slotModelDataChanged( const QModelIndex&, const QModelIndex& );
0158         void slotModelLayoutChanged();
0159 
0160         // geometry has changed
0161         void rebuildCache();
0162         // reset all cached values, without changing the cache geometry
0163         void clearCache();
0164 
0165     private:
0166         // private version of setResolution() that does *not* call rebuildCache()
0167         bool setResolutionInternal( int x, int y );
0168         // forget cached data at the position
0169         void invalidate( const CachePosition& );
0170         // check if position is inside the dataset's index range
0171         bool mapsToModelIndex( const CachePosition& ) const;
0172 
0173         CachePosition mapToCache( const QModelIndex& ) const;
0174         CachePosition mapToCache( int row, int column ) const;
0175         // Note: returns only valid model indices
0176         QModelIndexList mapToModel( const CachePosition& ) const;
0177         qreal indexesPerPixel() const;
0178 
0179         // common logic for slot{Rows,Columns}[AboutToBe]{Inserted,Removed}
0180         bool prepareDataChange( const QModelIndex& parent,
0181                                 bool isRows, /* columns otherwise */
0182                                 int* start, int* end);
0183 
0184         // retrieve data from the model, put it into the cache
0185         void retrieveModelData( const CachePosition& ) const;
0186         // check if a data point is in the cache:
0187         bool isCached( const CachePosition& ) const;
0188         // set sample step width according to settings:
0189         void calculateSampleStepWidth();
0190 
0191 
0192         QPointer<QAbstractItemModel> m_model;
0193         QModelIndex m_rootIndex;
0194 
0195         ApproximationMode m_mode;
0196         int m_xResolution;
0197         int m_yResolution;
0198         unsigned int m_sampleStep;
0199 
0200         mutable QVector<DataPointVector> m_data; // one per dataset
0201         ModelDataCache< qreal, Qt::DisplayRole > m_modelCache;
0202         mutable DataValueAttributesCache m_dataValueAttributesCache;
0203         int m_datasetDimension;
0204     };
0205 }
0206 
0207 #endif