File indexing completed on 2024-05-12 04:20:36
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 KCHARTMODELDATACACHE_H 0010 #define KCHARTMODELDATACACHE_H 0011 0012 #include <limits> 0013 0014 #include <QObject> 0015 #include <QModelIndex> 0016 #include <QVector> 0017 0018 #include "kchart_export.h" 0019 0020 QT_BEGIN_NAMESPACE 0021 class QAbstractItemModel; 0022 QT_END_NAMESPACE 0023 0024 namespace KChart 0025 { 0026 namespace ModelDataCachePrivate 0027 { 0028 class ModelSignalMapper 0029 { 0030 protected: 0031 ModelSignalMapper() {} 0032 public: 0033 virtual ~ModelSignalMapper() {} 0034 virtual void resetModel() = 0; 0035 virtual void columnsInserted( const QModelIndex&, int, int ) = 0; 0036 virtual void columnsRemoved( const QModelIndex&, int, int ) = 0; 0037 virtual void dataChanged( const QModelIndex&, const QModelIndex& ) = 0; 0038 virtual void layoutChanged() = 0; 0039 virtual void modelReset() = 0; 0040 virtual void rowsInserted( const QModelIndex&, int, int ) = 0; 0041 virtual void rowsRemoved( const QModelIndex&, int, int ) = 0; 0042 }; 0043 0044 // this class maps slots to a non-QObject instantiating ModelSignalMapper 0045 class KCHART_EXPORT ModelSignalMapperConnector : public QObject 0046 { 0047 Q_OBJECT 0048 public: 0049 explicit ModelSignalMapperConnector( ModelSignalMapper& mapper ); 0050 ~ModelSignalMapperConnector() override; 0051 0052 void connectSignals( QAbstractItemModel* model ); 0053 void disconnectSignals( QAbstractItemModel* model ); 0054 0055 protected Q_SLOTS: 0056 void resetModel(); 0057 void columnsInserted( const QModelIndex&, int, int ); 0058 void columnsRemoved( const QModelIndex&, int, int ); 0059 void dataChanged( const QModelIndex&, const QModelIndex& ); 0060 void layoutChanged(); 0061 void modelReset(); 0062 void rowsInserted( const QModelIndex&, int, int ); 0063 void rowsRemoved( const QModelIndex&, int, int ); 0064 0065 private: 0066 ModelSignalMapper& m_mapper; 0067 }; 0068 0069 template< class T> 0070 T nan() 0071 { 0072 return T(); 0073 } 0074 0075 template<> 0076 inline qreal nan< qreal >() 0077 { 0078 return std::numeric_limits< qreal >::quiet_NaN(); 0079 } 0080 } 0081 0082 template< class T, int ROLE > 0083 class ModelDataCache : public ModelDataCachePrivate::ModelSignalMapper 0084 { 0085 public: 0086 ModelDataCache() 0087 : m_model( nullptr ), 0088 m_connector( *this ) 0089 { 0090 } 0091 0092 ~ModelDataCache() override 0093 { 0094 } 0095 0096 T data( const QModelIndex& index ) const 0097 { 0098 if ( !index.isValid() || index.parent() != m_rootIndex || index.row() >= m_model->rowCount(m_rootIndex) || index.column() >= m_model->columnCount(m_rootIndex) ) 0099 return ModelDataCachePrivate::nan< T >(); 0100 0101 if ( index.row() >= m_data.count() ) 0102 { 0103 qWarning( "KChart didn't receive signal rowsInserted, resetModel or layoutChanged, " 0104 "but an index with a row outside of the known bounds." ); 0105 0106 // apparently, data were added behind our back (w/o signals) 0107 const_cast< ModelDataCache< T, ROLE >* >( this )->rowsInserted( m_rootIndex, 0108 m_data.count(), 0109 m_model->rowCount( m_rootIndex ) - 1 ); 0110 Q_ASSERT( index.row() < m_data.count() ); 0111 } 0112 0113 if ( index.column() >= m_data.first().count() ) 0114 { 0115 qWarning( "KChart didn't got signal columnsInserted, resetModel or layoutChanged, " 0116 "but an index with a column outside of the known bounds." ); 0117 0118 // apparently, data were added behind our back (w/o signals) 0119 const_cast< ModelDataCache< T, ROLE >* >( this )->columnsInserted( m_rootIndex, 0120 m_data.first().count(), 0121 m_model->columnCount( m_rootIndex ) - 1 ); 0122 Q_ASSERT( index.column() < m_data.first().count() ); 0123 } 0124 0125 return data( index.row(), index.column() ); 0126 } 0127 0128 T data( int row, int column ) const 0129 { 0130 if ( row < 0 || column < 0 ) 0131 return ModelDataCachePrivate::nan< T >(); 0132 0133 Q_ASSERT( row < m_model->rowCount(m_rootIndex) ); 0134 Q_ASSERT( column < m_model->columnCount(m_rootIndex) ); 0135 0136 Q_ASSERT( row < m_data.count() ); 0137 Q_ASSERT( column < m_data.first().count() ); 0138 0139 if ( isCached( row, column ) ) 0140 return m_data.at( row ).at( column ); 0141 0142 return fetchFromModel( row, column, ROLE ); 0143 } 0144 0145 void setModel( QAbstractItemModel* model ) 0146 { 0147 if ( m_model != nullptr ) 0148 m_connector.disconnectSignals( m_model ); 0149 0150 m_model = model; 0151 0152 if ( m_model != nullptr ) 0153 m_connector.connectSignals( m_model ); 0154 0155 modelReset(); 0156 } 0157 0158 QAbstractItemModel* model() const 0159 { 0160 return m_model; 0161 } 0162 0163 void setRootIndex( const QModelIndex& rootIndex ) 0164 { 0165 Q_ASSERT( rootIndex.model() == m_model || !rootIndex.isValid() ); 0166 m_rootIndex = rootIndex; 0167 modelReset(); 0168 } 0169 0170 QModelIndex rootIndex() const 0171 { 0172 return m_rootIndex; 0173 } 0174 0175 protected: 0176 bool isCached( int row, int column ) const 0177 { 0178 return m_cacheValid.at( row ).at( column ); 0179 } 0180 0181 T fetchFromModel( int row, int column, int role ) const 0182 { 0183 Q_ASSERT( m_model != nullptr ); 0184 0185 const QModelIndex index = m_model->index( row, column, m_rootIndex ); 0186 const QVariant data = index.data( role ); 0187 const T value = data.isNull() ? ModelDataCachePrivate::nan< T >() 0188 : ( data.value< T >() ); 0189 0190 m_data[ row ][ column ] = value; 0191 m_cacheValid[ row ][ column ] = true; 0192 0193 return value; 0194 } 0195 0196 void columnsInserted( const QModelIndex& parent, int start, int end ) override 0197 { 0198 Q_ASSERT( m_model != nullptr ); 0199 Q_ASSERT( parent.model() == m_model || !parent.isValid() ); 0200 0201 if ( parent != m_rootIndex ) 0202 return; 0203 0204 Q_ASSERT( start <= end ); 0205 Q_ASSERT( start <= m_model->columnCount(m_rootIndex) ); 0206 0207 const int rowCount = m_data.count(); 0208 for ( int row = 0; row < rowCount; ++row ) 0209 { 0210 m_data[ row ].insert( start, end - start + 1, T() ); 0211 m_cacheValid[ row ].insert( start, end - start + 1, false ); 0212 Q_ASSERT( m_data.at( row ).count() == m_model->columnCount( m_rootIndex ) ); 0213 Q_ASSERT( m_cacheValid.at( row ).count() == m_model->columnCount( m_rootIndex ) ); 0214 } 0215 } 0216 0217 void columnsRemoved( const QModelIndex& parent, int start, int end ) override 0218 { 0219 Q_ASSERT( m_model != nullptr ); 0220 Q_ASSERT( parent.model() == m_model || !parent.isValid() ); 0221 0222 if ( parent != m_rootIndex ) 0223 return; 0224 0225 Q_ASSERT( start <= end ); 0226 0227 const int rowCount = m_data.count(); 0228 for ( int row = 0; row < rowCount; ++row ) 0229 { 0230 m_data[ row ].remove( start, end - start + 1 ); 0231 m_cacheValid[ row ].remove( start, end - start + 1 ); 0232 Q_ASSERT( m_data.at( row ).count() == m_model->columnCount( m_rootIndex ) ); 0233 Q_ASSERT( m_cacheValid.at( row ).count() == m_model->columnCount( m_rootIndex ) ); 0234 } 0235 } 0236 0237 void dataChanged( const QModelIndex& topLeft, const QModelIndex& bottomRight ) override 0238 { 0239 if ( !m_model ) 0240 return; 0241 Q_ASSERT( m_model != nullptr ); 0242 Q_ASSERT( topLeft.parent() == bottomRight.parent() ); 0243 0244 if ( !topLeft.isValid() || !bottomRight.isValid() || topLeft.parent() != m_rootIndex ) 0245 return; 0246 0247 Q_ASSERT( topLeft.model() == m_model && bottomRight.model() == m_model ); 0248 0249 const int minRow = qMax( 0, topLeft.row() ); 0250 const int maxRow = bottomRight.row(); 0251 const int minCol = qMax( 0, topLeft.column() ); 0252 const int maxCol = bottomRight.column(); 0253 0254 Q_ASSERT( minRow <= maxRow ); 0255 Q_ASSERT( minCol <= maxCol ); 0256 Q_ASSERT( maxRow < m_model->rowCount( m_rootIndex ) ); 0257 Q_ASSERT( maxCol < m_model->columnCount( m_rootIndex ) ); 0258 0259 for ( int row = minRow; row <= maxRow; ++row ) 0260 { 0261 for ( int col = minCol; col <= maxCol; ++col ) 0262 { 0263 m_cacheValid[ row ][ col ] = false; 0264 Q_ASSERT( !isCached( row, col ) ); 0265 } 0266 } 0267 } 0268 0269 void layoutChanged() override 0270 { 0271 modelReset(); 0272 } 0273 0274 void modelReset() override 0275 { 0276 m_data.clear(); 0277 m_cacheValid.clear(); 0278 0279 if ( m_model == nullptr ) 0280 return; 0281 0282 m_data.fill( QVector< T >( m_model->columnCount( m_rootIndex ) ), m_model->rowCount( m_rootIndex ) ); 0283 m_cacheValid.fill( QVector< bool >( m_model->columnCount( m_rootIndex ), false ), m_model->rowCount( m_rootIndex ) ); 0284 0285 Q_ASSERT( m_data.count() == m_model->rowCount( m_rootIndex ) ); 0286 Q_ASSERT( m_cacheValid.count() == m_model->rowCount( m_rootIndex ) ); 0287 } 0288 0289 void rowsInserted( const QModelIndex& parent, int start, int end ) override 0290 { 0291 Q_ASSERT( m_model != nullptr ); 0292 Q_ASSERT( parent.model() == m_model || !parent.isValid() ); 0293 0294 if ( parent != m_rootIndex || start >= m_model->rowCount(m_rootIndex) ) 0295 return; 0296 0297 Q_ASSERT( start <= end ); 0298 Q_ASSERT( end - start + 1 <= m_model->rowCount(m_rootIndex) ); 0299 0300 m_data.insert( start, end - start + 1, QVector< T >( m_model->columnCount( m_rootIndex ) ) ); 0301 m_cacheValid.insert( start, end - start + 1, QVector< bool >( m_model->columnCount( m_rootIndex ), false ) ); 0302 0303 Q_ASSERT( m_data.count() == m_model->rowCount( m_rootIndex ) ); 0304 Q_ASSERT( m_cacheValid.count() == m_model->rowCount( m_rootIndex ) ); 0305 } 0306 0307 void rowsRemoved( const QModelIndex& parent, int start, int end ) override 0308 { 0309 Q_ASSERT( m_model != nullptr ); 0310 Q_ASSERT( parent.model() == m_model || !parent.isValid() ); 0311 0312 if ( parent != m_rootIndex || start >= m_data.count() ) 0313 return; 0314 0315 Q_ASSERT( start <= end ); 0316 0317 m_data.remove( start, end - start + 1 ); 0318 m_cacheValid.remove( start, end - start + 1 ); 0319 0320 Q_ASSERT( m_data.count() == m_model->rowCount( m_rootIndex ) ); 0321 Q_ASSERT( m_cacheValid.count() == m_model->rowCount( m_rootIndex ) ); 0322 } 0323 0324 void resetModel() override 0325 { 0326 // no need to disconnect, this is a response to SIGNAL( destroyed() ) 0327 m_model = nullptr; 0328 modelReset(); 0329 } 0330 0331 private: 0332 QAbstractItemModel* m_model; 0333 QModelIndex m_rootIndex; 0334 ModelDataCachePrivate::ModelSignalMapperConnector m_connector; 0335 mutable QVector< QVector< T > > m_data; 0336 mutable QVector< QVector< bool > > m_cacheValid; 0337 }; 0338 } 0339 0340 #endif