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 #include "KChartAttributesModel.h"
21 
22 #include "KChartPalette.h"
23 #include "KChartGlobal.h"
24 #include "KChartMath_p.h"
25 
26 #include <QDebug>
27 #include <QPen>
28 #include <QPointer>
29 
30 #include <KChartTextAttributes.h>
31 #include <KChartFrameAttributes.h>
32 #include <KChartBackgroundAttributes.h>
33 #include <KChartDataValueAttributes.h>
34 #include <KChartMarkerAttributes.h>
35 #include <KChartBarAttributes.h>
36 #include <KChartStockBarAttributes.h>
37 #include <KChartLineAttributes.h>
38 #include <KChartPieAttributes.h>
39 #include <KChartAbstractThreeDAttributes.h>
40 #include <KChartThreeDBarAttributes.h>
41 #include <KChartThreeDLineAttributes.h>
42 #include <KChartThreeDPieAttributes.h>
43 #include <KChartGridAttributes.h>
44 #include <KChartValueTrackerAttributes.h>
45 
46 
47 using namespace KChart;
48 
49 
50 class Q_DECL_HIDDEN AttributesModel::Private
51 {
52 public:
53     Private();
54 
55     QMap< int, QMap< int, QMap< int, QVariant > > > dataMap;
56     QMap< int, QMap< int, QVariant > > horizontalHeaderDataMap;
57     QMap< int, QMap< int, QVariant > > verticalHeaderDataMap;
58     QMap< int, QVariant > modelDataMap;
59     QMap< int, QVariant > defaultsMap;
60     int dataDimension;
61     AttributesModel::PaletteType paletteType;
62     Palette palette;
63 };
64 
Private()65 AttributesModel::Private::Private()
66   : dataDimension( 1 ),
67     paletteType( AttributesModel::PaletteTypeDefault ),
68     palette( Palette::defaultPalette() )
69 {
70 }
71 
72 #define d d_func()
73 
AttributesModel(QAbstractItemModel * model,QObject * parent)74 AttributesModel::AttributesModel( QAbstractItemModel* model, QObject * parent/* = 0 */ )
75   : AbstractProxyModel( parent ),
76     _d( new Private )
77 {
78     setSourceModel( model );
79     setDefaultForRole( KChart::DataValueLabelAttributesRole,
80                        DataValueAttributes::defaultAttributesAsVariant() );
81 }
82 
~AttributesModel()83 AttributesModel::~AttributesModel()
84 {
85     delete _d;
86     _d = nullptr;
87 }
88 
initFrom(const AttributesModel * other)89 void AttributesModel::initFrom( const AttributesModel* other )
90 {
91     *d = *other->d;
92 }
93 
compareHeaderDataMaps(const QMap<int,QMap<int,QVariant>> & mapA,const QMap<int,QMap<int,QVariant>> & mapB) const94 bool AttributesModel::compareHeaderDataMaps( const QMap< int, QMap< int, QVariant > >& mapA,
95                                              const QMap< int, QMap< int, QVariant > >& mapB ) const
96 {
97     if ( mapA.count() != mapB.count() ) {
98         return false;
99     }
100     QMap< int, QMap< int, QVariant > >::const_iterator itA = mapA.constBegin();
101     QMap< int, QMap< int, QVariant > >::const_iterator itB = mapB.constBegin();
102     for ( ; itA != mapA.constEnd(); ++itA, ++itB ) {
103         if ( itA->count() != itB->count() ) {
104             return false;
105         }
106         QMap< int, QVariant >::const_iterator it2A = itA->constBegin();
107         QMap< int, QVariant >::const_iterator it2B = itB->constBegin();
108         for ( ; it2A != itA->constEnd(); ++it2A, ++it2B ) {
109             if ( it2A.key() != it2B.key() ) {
110                 return false;
111             }
112             if ( !compareAttributes( it2A.key(), it2A.value(), it2B.value() ) ) {
113                 return false;
114             }
115         }
116     }
117     return true;
118 }
119 
compare(const AttributesModel * other) const120 bool AttributesModel::compare( const AttributesModel* other ) const
121 {
122     if ( other == this ) {
123         return true;
124     }
125     if ( !other || d->paletteType != other->d->paletteType ) {
126         return false;
127     }
128 
129     {
130         if ( d->dataMap.count() != other->d->dataMap.count() ) {
131             return false;
132         }
133         QMap< int, QMap< int, QMap<int, QVariant > > >::const_iterator itA = d->dataMap.constBegin();
134         QMap< int, QMap< int, QMap<int, QVariant > > >::const_iterator itB = other->d->dataMap.constBegin();
135         for ( ; itA != d->dataMap.constEnd(); ++itA, ++itB ) {
136             if ( itA->count() != itB->count() ) {
137                 return false;
138             }
139             QMap< int, QMap< int, QVariant > >::const_iterator it2A = itA->constBegin();
140             QMap< int, QMap< int, QVariant > >::const_iterator it2B = itB->constBegin();
141             for ( ; it2A != itA->constEnd(); ++it2A, ++it2B ) {
142                 if ( it2A->count() != it2B->count() ) {
143                     return false;
144                 }
145                 QMap< int, QVariant >::const_iterator it3A = it2A->constBegin();
146                 QMap< int, QVariant >::const_iterator it3B = it2B->constBegin();
147                 for ( ; it3A != it2A->constEnd(); ++it3A, ++it3B ) {
148                     if ( it3A.key() != it3B.key() ) {
149                         return false;
150                     }
151                     if ( !compareAttributes( it3A.key(), it3A.value(), it3B.value() ) ) {
152                         return false;
153                     }
154                 }
155             }
156         }
157     }
158 
159     if ( !compareHeaderDataMaps( d->horizontalHeaderDataMap, other->d->horizontalHeaderDataMap ) ||
160          !compareHeaderDataMaps( d->verticalHeaderDataMap, other->d->verticalHeaderDataMap ) ) {
161         return false;
162     }
163 
164     {
165         if ( d->modelDataMap.count() != other->d->modelDataMap.count() ) {
166             return false;
167         }
168         QMap< int, QVariant >::const_iterator itA = d->modelDataMap.constBegin();
169         QMap< int, QVariant >::const_iterator itB = other->d->modelDataMap.constBegin();
170         for ( ; itA != d->modelDataMap.constEnd(); ++itA, ++itB ) {
171             if ( itA.key() != itB.key() ) {
172                 return false;
173             }
174             if ( !compareAttributes( itA.key(), itA.value(), itB.value() ) ) {
175                 return false;
176             }
177         }
178     }
179     return true;
180 }
181 
compareAttributes(int role,const QVariant & a,const QVariant & b) const182 bool AttributesModel::compareAttributes(
183         int role, const QVariant& a, const QVariant& b ) const
184 {
185     if ( isKnownAttributesRole( role ) ) {
186         switch ( role ) {
187             case DataValueLabelAttributesRole:
188                 return (a.value<DataValueAttributes>() ==
189                         b.value<DataValueAttributes>());
190             case DatasetBrushRole:
191                 return (a.value<QBrush>() ==
192                         b.value<QBrush>());
193             case DatasetPenRole:
194                 return (a.value<QPen>() ==
195                         b.value<QPen>());
196             case ThreeDAttributesRole:
197                 // As of yet there is no ThreeDAttributes class,
198                 // and the AbstractThreeDAttributes class is pure virtual,
199                 // so we ignore this role for now.
200                 // (khz, 04.04.2007)
201                 /*
202                 return (qVariantValue<ThreeDAttributes>( a ) ==
203                         qVariantValue<ThreeDAttributes>( b ));
204                 */
205                 break;
206             case LineAttributesRole:
207                 return (a.value<LineAttributes>() ==
208                         b.value<LineAttributes>());
209             case ThreeDLineAttributesRole:
210                 return (a.value<ThreeDLineAttributes>() ==
211                         b.value<ThreeDLineAttributes>());
212             case BarAttributesRole:
213                 return (a.value<BarAttributes>() ==
214                         b.value<BarAttributes>());
215             case StockBarAttributesRole:
216                 return (a.value<StockBarAttributes>() ==
217                         b.value<StockBarAttributes>());
218             case ThreeDBarAttributesRole:
219                 return (a.value<ThreeDBarAttributes>() ==
220                         b.value<ThreeDBarAttributes>());
221             case PieAttributesRole:
222                 return (a.value<PieAttributes>() ==
223                         b.value<PieAttributes>());
224             case ThreeDPieAttributesRole:
225                 return (a.value<ThreeDPieAttributes>() ==
226                         b.value<ThreeDPieAttributes>());
227             case ValueTrackerAttributesRole:
228                 return (a.value<ValueTrackerAttributes>() ==
229                         b.value<ValueTrackerAttributes>());
230             case DataHiddenRole:
231                 return (a.value<bool>() ==
232                         b.value<bool>());
233             default:
234                 Q_ASSERT( false ); // all of our own roles need to be handled
235                 break;
236         }
237     } else {
238         return (a == b);
239     }
240     return true;
241 }
242 
243 
headerData(int section,Qt::Orientation orientation,int role) const244 QVariant AttributesModel::headerData( int section, Qt::Orientation orientation,
245                                       int role/* = Qt::DisplayRole */ ) const
246 {
247     if ( sourceModel() ) {
248         const QVariant sourceData = sourceModel()->headerData( section, orientation, role );
249         if ( sourceData.isValid() ) {
250             return sourceData;
251         }
252     }
253 
254     // the source model didn't have data set, let's use our stored values
255     const QMap< int, QMap< int, QVariant> >& map = orientation == Qt::Horizontal ?
256                                                    d->horizontalHeaderDataMap : d->verticalHeaderDataMap;
257     QMap< int, QMap< int, QVariant > >::const_iterator mapIt = map.find( section );
258     if ( mapIt != map.constEnd() ) {
259         const QMap< int, QVariant >& dataMap = mapIt.value();
260         QMap< int, QVariant >::const_iterator dataMapIt = dataMap.find( role );
261         if ( dataMapIt != dataMap.constEnd() ) {
262             return dataMapIt.value();
263         }
264     }
265 
266     return defaultHeaderData( section, orientation, role );
267 }
268 
269 
defaultHeaderData(int section,Qt::Orientation orientation,int role) const270 QVariant AttributesModel::defaultHeaderData( int section, Qt::Orientation orientation, int role ) const
271 {
272     // Default values if nothing else matches
273 
274     const int dataset = section / d->dataDimension;
275 
276     switch ( role ) {
277     case Qt::DisplayRole:
278         //TODO for KChart 3.0: return QString::number( dataset + 1 );
279         return QVariant( (orientation == Qt::Vertical ? QStringLiteral("Series ") : QStringLiteral("Item ")) + QString::number( dataset )) ;
280     case KChart::DatasetBrushRole:
281         return d->palette.getBrush( dataset );
282     case KChart::DatasetPenRole:
283         // if no per model override was set, use the (possibly default) color set for the brush
284         if ( !modelData( role ).isValid() ) {
285             QBrush brush = headerData( section, orientation, DatasetBrushRole ).value< QBrush >();
286             return QPen( brush.color() );
287         }
288     default:
289         break;
290     }
291 
292     return QVariant();
293 }
294 
295 
data(int role) const296 QVariant AttributesModel::data( int role ) const
297 {
298   if ( isKnownAttributesRole( role ) ) {
299       // check if there is something set at global level
300       QVariant v = modelData( role );
301 
302       // else return the default setting, if any
303       if ( !v.isValid() )
304           v = defaultsForRole( role );
305       return v;
306   }
307   return QVariant();
308 }
309 
310 
data(int column,int role) const311 QVariant AttributesModel::data( int column, int role ) const
312 {
313   if ( isKnownAttributesRole( role ) ) {
314       // check if there is something set for the column (dataset)
315       QVariant v;
316       v = headerData( column, Qt::Horizontal, role );
317 
318       // check if there is something set at global level
319       if ( !v.isValid() )
320           v = data( role ); // includes automatic fallback to default
321       return v;
322   }
323   return QVariant();
324 }
325 
326 
data(const QModelIndex & index,int role) const327 QVariant AttributesModel::data( const QModelIndex& index, int role ) const
328 {
329     if ( index.isValid() ) {
330         Q_ASSERT( index.model() == this );
331     }
332     if ( !sourceModel() ) {
333         return QVariant();
334     }
335 
336     if ( index.isValid() ) {
337         const QVariant sourceData = sourceModel()->data( mapToSource( index ), role );
338         if ( sourceData.isValid() ) {
339             return sourceData;
340         }
341     }
342 
343     // check if we are storing a value for this role at this cell index
344     if ( d->dataMap.contains( index.column() ) ) {
345         const QMap< int,  QMap< int, QVariant > >& colDataMap = d->dataMap[ index.column() ];
346         if ( colDataMap.contains( index.row() ) ) {
347             const QMap< int, QVariant >& dataMap = colDataMap[ index.row() ];
348             if ( dataMap.contains( role ) ) {
349                 const QVariant v = dataMap[ role ];
350                 if ( v.isValid() ) {
351                     return v;
352                 }
353             }
354         }
355     }
356     // check if there is something set for the column (dataset), or at global level
357     if ( index.isValid() ) {
358         return data( index.column(), role ); // includes automatic fallback to default
359     }
360 
361     return QVariant();
362 }
363 
364 
isKnownAttributesRole(int role) const365 bool AttributesModel::isKnownAttributesRole( int role ) const
366 {
367     switch ( role ) {
368         // fallthrough intended
369     case DataValueLabelAttributesRole:
370     case DatasetBrushRole:
371     case DatasetPenRole:
372     case ThreeDAttributesRole:
373     case LineAttributesRole:
374     case ThreeDLineAttributesRole:
375     case BarAttributesRole:
376     case StockBarAttributesRole:
377     case ThreeDBarAttributesRole:
378     case PieAttributesRole:
379     case ThreeDPieAttributesRole:
380     case ValueTrackerAttributesRole:
381     case DataHiddenRole:
382         return true;
383     default:
384         return false;
385     }
386 }
387 
defaultsForRole(int role) const388 QVariant AttributesModel::defaultsForRole( int role ) const
389 {
390     // returns default-constructed QVariant if not found
391     return d->defaultsMap.value( role );
392 }
393 
setData(const QModelIndex & index,const QVariant & value,int role)394 bool AttributesModel::setData ( const QModelIndex & index, const QVariant & value, int role )
395 {
396     if ( !isKnownAttributesRole( role ) ) {
397         return sourceModel()->setData( mapToSource(index), value, role );
398     } else {
399         QMap< int,  QMap< int, QVariant> > &colDataMap = d->dataMap[ index.column() ];
400         QMap< int, QVariant > &dataMap = colDataMap[ index.row() ];
401         dataMap.insert( role, value );
402         Q_EMIT attributesChanged( index, index );
403         return true;
404     }
405 }
406 
resetData(const QModelIndex & index,int role)407 bool AttributesModel::resetData ( const QModelIndex & index, int role )
408 {
409     return setData( index, QVariant(), role );
410 }
411 
setHeaderData(int section,Qt::Orientation orientation,const QVariant & value,int role)412 bool AttributesModel::setHeaderData ( int section, Qt::Orientation orientation,
413                                       const QVariant & value, int role )
414 {
415     if ( sourceModel() && headerData( section, orientation, role ) == value ) {
416         return true;
417     }
418 
419     if ( !isKnownAttributesRole( role ) ) {
420         return sourceModel()->setHeaderData( section, orientation, value, role );
421     } else {
422         QMap< int,  QMap<int, QVariant > > &sectionDataMap
423             = orientation == Qt::Horizontal ? d->horizontalHeaderDataMap : d->verticalHeaderDataMap;
424 
425         QMap< int, QVariant > &dataMap = sectionDataMap[ section ];
426         dataMap.insert( role, value );
427         if ( sourceModel() ) {
428             int numRows = rowCount( QModelIndex() );
429             int numCols = columnCount( QModelIndex() );
430             if ( orientation == Qt::Horizontal && numRows > 0 )
431                 Q_EMIT attributesChanged( index( 0, section, QModelIndex() ),
432                                         index( numRows - 1, section, QModelIndex() ) );
433             else if ( orientation == Qt::Vertical && numCols > 0 )
434                 Q_EMIT attributesChanged( index( section, 0, QModelIndex() ),
435                                         index( section, numCols - 1, QModelIndex() ) );
436             Q_EMIT headerDataChanged( orientation, section, section );
437 
438             // FIXME: This only makes sense for orientation == Qt::Horizontal,
439             // but what if orientation == Qt::Vertical?
440             if ( section != -1 && numRows > 0 )
441                 Q_EMIT dataChanged( index( 0, section, QModelIndex() ),
442                                   index( numRows - 1, section, QModelIndex() ) );
443         }
444         return true;
445     }
446 }
447 
resetHeaderData(int section,Qt::Orientation orientation,int role)448 bool AttributesModel::resetHeaderData ( int section, Qt::Orientation orientation, int role )
449 {
450     return setHeaderData ( section, orientation, QVariant(), role );
451 }
452 
setPaletteType(AttributesModel::PaletteType type)453 void AttributesModel::setPaletteType( AttributesModel::PaletteType type )
454 {
455     if ( d->paletteType == type ) {
456         return;
457     }
458     d->paletteType = type;
459     switch ( type ) {
460     case PaletteTypeDefault:
461         d->palette = Palette::defaultPalette();
462         break;
463     case PaletteTypeSubdued:
464         d->palette = Palette::subduedPalette();
465         break;
466     case PaletteTypeRainbow:
467         d->palette = Palette::rainbowPalette();
468         break;
469     default:
470         qWarning( "Unknown palette type!" );
471     }
472 }
473 
paletteType() const474 AttributesModel::PaletteType AttributesModel::paletteType() const
475 {
476     return d->paletteType;
477 }
478 
setModelData(const QVariant value,int role)479 bool KChart::AttributesModel::setModelData( const QVariant value, int role )
480 {
481     d->modelDataMap.insert( role, value );
482     int numRows = rowCount( QModelIndex() );
483     int numCols = columnCount( QModelIndex() );
484     if ( sourceModel() && numRows > 0 && numCols > 0 ) {
485         Q_EMIT attributesChanged( index( 0, 0, QModelIndex() ),
486                                 index( numRows - 1, numCols - 1, QModelIndex() ) );
487         beginResetModel();
488 	endResetModel();
489     }
490     return true;
491 }
492 
modelData(int role) const493 QVariant KChart::AttributesModel::modelData( int role ) const
494 {
495     return d->modelDataMap.value( role, QVariant() );
496 }
497 
rowCount(const QModelIndex & index) const498 int AttributesModel::rowCount( const QModelIndex& index ) const
499 {
500     if ( sourceModel() ) {
501         return sourceModel()->rowCount( mapToSource(index) );
502     } else {
503         return 0;
504     }
505 }
506 
columnCount(const QModelIndex & index) const507 int AttributesModel::columnCount( const QModelIndex& index ) const
508 {
509     if ( sourceModel() ) {
510         return sourceModel()->columnCount( mapToSource(index) );
511     } else {
512         return 0;
513     }
514 }
515 
setSourceModel(QAbstractItemModel * sourceModel)516 void AttributesModel::setSourceModel( QAbstractItemModel* sourceModel )
517 {
518     if ( this->sourceModel() != nullptr )
519     {
520         disconnect( this->sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
521                                    this, SLOT(slotDataChanged(QModelIndex,QModelIndex)));
522         disconnect( this->sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
523                                    this, SLOT(slotRowsInserted(QModelIndex,int,int)) );
524         disconnect( this->sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
525                                    this, SLOT(slotRowsRemoved(QModelIndex,int,int)) );
526         disconnect( this->sourceModel(), SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
527                                    this, SLOT(slotRowsAboutToBeInserted(QModelIndex,int,int)) );
528         disconnect( this->sourceModel(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
529                                    this, SLOT(slotRowsAboutToBeRemoved(QModelIndex,int,int)) );
530         disconnect( this->sourceModel(), SIGNAL(columnsInserted(QModelIndex,int,int)),
531                                    this, SLOT(slotColumnsInserted(QModelIndex,int,int)) );
532         disconnect( this->sourceModel(), SIGNAL(columnsRemoved(QModelIndex,int,int)),
533                                    this, SLOT(slotColumnsRemoved(QModelIndex,int,int)) );
534         disconnect( this->sourceModel(), SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
535                                    this, SLOT(slotColumnsAboutToBeInserted(QModelIndex,int,int)) );
536         disconnect( this->sourceModel(), SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
537                                    this, SLOT(slotColumnsAboutToBeRemoved(QModelIndex,int,int)) );
538         disconnect( this->sourceModel(), SIGNAL(modelReset()),
539                                    this, SIGNAL(modelReset()) );
540         disconnect( this->sourceModel(), SIGNAL(layoutChanged()),
541                                    this, SIGNAL(layoutChanged()) );
542     }
543     QAbstractProxyModel::setSourceModel( sourceModel );
544     if ( this->sourceModel() != nullptr )
545     {
546         connect( this->sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
547                                 this, SLOT(slotDataChanged(QModelIndex,QModelIndex)));
548         connect( this->sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
549                                 this, SLOT(slotRowsInserted(QModelIndex,int,int)) );
550         connect( this->sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
551                                 this, SLOT(slotRowsRemoved(QModelIndex,int,int)) );
552         connect( this->sourceModel(), SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
553                                 this, SLOT(slotRowsAboutToBeInserted(QModelIndex,int,int)) );
554         connect( this->sourceModel(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
555                                 this, SLOT(slotRowsAboutToBeRemoved(QModelIndex,int,int)) );
556         connect( this->sourceModel(), SIGNAL(columnsInserted(QModelIndex,int,int)),
557                                 this, SLOT(slotColumnsInserted(QModelIndex,int,int)) );
558         connect( this->sourceModel(), SIGNAL(columnsRemoved(QModelIndex,int,int)),
559                                 this, SLOT(slotColumnsRemoved(QModelIndex,int,int)) );
560         connect( this->sourceModel(), SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
561                                 this, SLOT(slotColumnsAboutToBeInserted(QModelIndex,int,int)) );
562         connect( this->sourceModel(), SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
563                                 this, SLOT(slotColumnsAboutToBeRemoved(QModelIndex,int,int)) );
564         connect( this->sourceModel(), SIGNAL(modelReset()),
565                                 this, SIGNAL(modelReset()) );
566         connect( this->sourceModel(), SIGNAL(layoutChanged()),
567                                 this, SIGNAL(layoutChanged()) );
568     }
569 }
570 
slotRowsAboutToBeInserted(const QModelIndex & parent,int start,int end)571 void AttributesModel::slotRowsAboutToBeInserted( const QModelIndex& parent, int start, int end )
572 {
573     beginInsertRows( mapFromSource( parent ), start, end );
574 }
575 
slotColumnsAboutToBeInserted(const QModelIndex & parent,int start,int end)576 void AttributesModel::slotColumnsAboutToBeInserted( const QModelIndex& parent, int start, int end )
577 {
578     beginInsertColumns( mapFromSource( parent ), start, end );
579 }
580 
slotRowsInserted(const QModelIndex & parent,int start,int end)581 void AttributesModel::slotRowsInserted( const QModelIndex& parent, int start, int end )
582 {
583     Q_UNUSED( parent );
584     Q_UNUSED( start );
585     Q_UNUSED( end );
586     endInsertRows();
587 }
588 
slotColumnsInserted(const QModelIndex & parent,int start,int end)589 void AttributesModel::slotColumnsInserted( const QModelIndex& parent, int start, int end )
590 {
591     Q_UNUSED( parent );
592     Q_UNUSED( start );
593     Q_UNUSED( end );
594     endInsertColumns();
595 }
596 
slotRowsAboutToBeRemoved(const QModelIndex & parent,int start,int end)597 void AttributesModel::slotRowsAboutToBeRemoved( const QModelIndex& parent, int start, int end )
598 {
599     beginRemoveRows( mapFromSource( parent ), start, end );
600 }
601 
slotColumnsAboutToBeRemoved(const QModelIndex & parent,int start,int end)602 void AttributesModel::slotColumnsAboutToBeRemoved( const QModelIndex& parent, int start, int end )
603 {
604     beginRemoveColumns( mapFromSource( parent ), start, end );
605 }
606 
slotRowsRemoved(const QModelIndex & parent,int start,int end)607 void AttributesModel::slotRowsRemoved( const QModelIndex& parent, int start, int end )
608 {
609     Q_UNUSED( parent );
610     Q_UNUSED( start );
611     Q_UNUSED( end );
612     endRemoveRows();
613 }
614 
removeEntriesFromDataMap(int start,int end)615 void AttributesModel::removeEntriesFromDataMap( int start, int end )
616 {
617     QMap< int, QMap< int, QMap< int, QVariant > > >::iterator it = d->dataMap.find( end );
618     // check that the element was found
619     if ( it != d->dataMap.end() ) {
620         ++it;
621         QVector< int > indexesToDel;
622         for ( int i = start; i < end && it != d->dataMap.end(); ++i ) {
623             d->dataMap[ i ] = it.value();
624             indexesToDel << it.key();
625             ++it;
626         }
627         if ( indexesToDel.isEmpty() ) {
628             for ( int i = start; i < end; ++i ) {
629                 indexesToDel << i;
630             }
631         }
632         for ( int i  = 0; i < indexesToDel.count(); ++i ) {
633             d->dataMap.remove( indexesToDel[ i ] );
634         }
635     }
636 }
637 
removeEntriesFromDirectionDataMaps(Qt::Orientation dir,int start,int end)638 void AttributesModel::removeEntriesFromDirectionDataMaps( Qt::Orientation dir, int start, int end )
639 {
640     QMap<int,  QMap<int, QVariant> > &sectionDataMap
641         = dir == Qt::Horizontal ? d->horizontalHeaderDataMap : d->verticalHeaderDataMap;
642     QMap<int, QMap<int, QVariant> >::iterator it = sectionDataMap.upperBound( end );
643     // check that the element was found
644     if ( it != sectionDataMap.end() )
645     {
646         QVector< int > indexesToDel;
647         for ( int i = start; i < end && it != sectionDataMap.end(); ++i )
648         {
649             sectionDataMap[ i ] = it.value();
650             indexesToDel << it.key();
651             ++it;
652         }
653         if ( indexesToDel.isEmpty() )
654         {
655             for ( int i = start; i < end; ++i )
656             {
657                 indexesToDel << i;
658             }
659         }
660         for ( int i  = 0; i < indexesToDel.count(); ++i )
661         {
662             sectionDataMap.remove( indexesToDel[ i ] );
663         }
664     }
665 }
666 
slotColumnsRemoved(const QModelIndex & parent,int start,int end)667 void AttributesModel::slotColumnsRemoved( const QModelIndex& parent, int start, int end )
668 {
669     Q_UNUSED( parent );
670     Q_UNUSED( start );
671     Q_UNUSED( end );
672     Q_ASSERT_X( sourceModel(), "removeColumn", "This should only be triggered if a valid source Model exists!" );
673     for ( int i = start; i <= end; ++i ) {
674         d->verticalHeaderDataMap.remove( start );
675     }
676     removeEntriesFromDataMap( start, end );
677     removeEntriesFromDirectionDataMaps( Qt::Horizontal, start, end );
678     removeEntriesFromDirectionDataMaps( Qt::Vertical, start, end );
679 
680     endRemoveColumns();
681 }
682 
slotDataChanged(const QModelIndex & topLeft,const QModelIndex & bottomRight)683 void AttributesModel::slotDataChanged( const QModelIndex& topLeft, const QModelIndex& bottomRight )
684 {
685     Q_EMIT dataChanged( mapFromSource( topLeft ), mapFromSource( bottomRight ) );
686 }
687 
setDefaultForRole(int role,const QVariant & value)688 void AttributesModel::setDefaultForRole( int role, const QVariant& value )
689 {
690     if ( value.isValid() ) {
691         d->defaultsMap.insert( role, value );
692     } else {
693         // erase the possibily existing value to not let the map grow:
694         QMap<int, QVariant>::iterator it = d->defaultsMap.find( role );
695         if ( it != d->defaultsMap.end() ) {
696             d->defaultsMap.erase( it );
697         }
698     }
699 
700     Q_ASSERT( defaultsForRole( role ).value<KChart::DataValueAttributes>()  == value.value<KChart::DataValueAttributes>() );
701 }
702 
setDatasetDimension(int dimension)703 void AttributesModel::setDatasetDimension( int dimension )
704 {
705     //### need to "reformat" or throw away internal data?
706     d->dataDimension = dimension;
707 }
708 
datasetDimension() const709 int AttributesModel::datasetDimension() const
710 {
711     return d->dataDimension;
712 }
713