00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "kdganttsummaryhandlingproxymodel.h"
00024 #include "kdganttsummaryhandlingproxymodel_p.h"
00025
00026 #include <QDebug>
00027
00028 #include <cassert>
00029
00030 using namespace KDGantt;
00031
00048 typedef ForwardingProxyModel BASE;
00049
00050 bool SummaryHandlingProxyModel::Private::cacheLookup( const QModelIndex& idx,
00051 QPair<QDateTime,QDateTime>* result ) const
00052 {
00053
00054 QHash<QModelIndex,QPair<QDateTime,QDateTime> >::const_iterator it =
00055 cached_summary_items.find( idx );
00056 if ( it != cached_summary_items.constEnd() ) {
00057 *result = *it;
00058 return true;
00059 } else {
00060 return false;
00061 }
00062 }
00063
00064 void SummaryHandlingProxyModel::Private::insertInCache( const SummaryHandlingProxyModel* model,
00065 const QModelIndex& sourceIdx ) const
00066 {
00067 QAbstractItemModel* sourceModel = model->sourceModel();
00068 const QModelIndex& mainIdx = sourceIdx;
00069 QDateTime st;
00070 QDateTime et;
00071
00072 for ( int r = 0; r < sourceModel->rowCount( mainIdx ); ++r ) {
00073 QModelIndex pdIdx = model->mapFromSource( sourceModel->index( r, 0, mainIdx ) );
00074
00075 QVariant tmpsv = model->data( pdIdx, StartTimeRole );
00076 QVariant tmpev = model->data( pdIdx, EndTimeRole );
00077 if( !qVariantCanConvert<QDateTime>(tmpsv) ||
00078 !qVariantCanConvert<QDateTime>(tmpev) ) {
00079 qDebug() << "Skipping item " << sourceIdx << " because it doesn't contain QDateTime";
00080 continue;
00081 }
00082
00083
00084
00085 if( tmpsv.type() == QVariant::String && qVariantValue<QString>(tmpsv).isEmpty()) continue;
00086 if( tmpev.type() == QVariant::String && qVariantValue<QString>(tmpev).isEmpty()) continue;
00087 QDateTime tmpst = tmpsv.toDateTime();
00088 QDateTime tmpet = tmpev.toDateTime();
00089 if ( st.isNull() || st > tmpst ) st = tmpst;
00090 if ( et.isNull() || et < tmpet ) et = tmpet;
00091 }
00092 QVariant tmpssv = sourceModel->data( mainIdx, StartTimeRole );
00093 QVariant tmpsev = sourceModel->data( mainIdx, EndTimeRole );
00094 if ( qVariantCanConvert<QDateTime>( tmpssv )
00095 && !( qVariantCanConvert<QString>( tmpssv ) && qVariantValue<QString>( tmpssv ).isEmpty() )
00096 && qVariantValue<QDateTime>( tmpssv ) != st )
00097 sourceModel->setData( mainIdx, st, StartTimeRole );
00098 if ( qVariantCanConvert<QDateTime>( tmpsev )
00099 && !( qVariantCanConvert<QString>( tmpsev ) && qVariantValue<QString>( tmpsev ).isEmpty() )
00100 && qVariantValue<QDateTime>( tmpsev ) != et )
00101 sourceModel->setData( mainIdx, et, EndTimeRole );
00102 cached_summary_items[sourceIdx]=qMakePair( st, et );
00103 }
00104
00105 void SummaryHandlingProxyModel::Private::removeFromCache( const QModelIndex& idx ) const
00106 {
00107 cached_summary_items.remove( idx );
00108 }
00109
00110 void SummaryHandlingProxyModel::Private::clearCache() const
00111 {
00112 cached_summary_items.clear();
00113 }
00114
00118 SummaryHandlingProxyModel::SummaryHandlingProxyModel( QObject* parent )
00119 : BASE( parent ), _d( new Private )
00120 {
00121 init();
00122 }
00123
00124 #define d d_func()
00125 SummaryHandlingProxyModel::~SummaryHandlingProxyModel()
00126 {
00127 }
00128
00129 void SummaryHandlingProxyModel::init()
00130 {
00131 }
00132
00133 namespace {
00134
00135
00136 struct KDPrivateModelIndex {
00137 int r, c;
00138 void *p;
00139 const QAbstractItemModel *m;
00140 };
00141 }
00142
00147 void SummaryHandlingProxyModel::setSourceModel( QAbstractItemModel* model )
00148 {
00149 BASE::setSourceModel( model );
00150 d->clearCache();
00151 }
00152
00153 void SummaryHandlingProxyModel::sourceModelReset()
00154 {
00155 d->clearCache();
00156 BASE::sourceModelReset();
00157 }
00158
00159 void SummaryHandlingProxyModel::sourceLayoutChanged()
00160 {
00161 d->clearCache();
00162 BASE::sourceLayoutChanged();
00163 }
00164
00165 void SummaryHandlingProxyModel::sourceDataChanged( const QModelIndex& from, const QModelIndex& to )
00166 {
00167 QAbstractItemModel* model = sourceModel();
00168 QModelIndex parentIdx = from;
00169 do {
00170 const QModelIndex& dataIdx = parentIdx;
00171 if ( model->data( dataIdx, ItemTypeRole )==TypeSummary ) {
00172
00173 d->removeFromCache( dataIdx );
00174 QModelIndex proxyDataIdx = mapFromSource( dataIdx );
00175 emit dataChanged( proxyDataIdx, proxyDataIdx );
00176 }
00177 } while ( ( parentIdx=model->parent( parentIdx ) ) != QModelIndex() );
00178
00179 BASE::sourceDataChanged( from, to );
00180 }
00181
00182 void SummaryHandlingProxyModel::sourceColumnsAboutToBeInserted( const QModelIndex& parentIdx,
00183 int start,
00184 int end )
00185 {
00186 BASE::sourceColumnsAboutToBeInserted( parentIdx, start, end );
00187 d->clearCache();
00188 }
00189
00190 void SummaryHandlingProxyModel::sourceColumnsAboutToBeRemoved( const QModelIndex& parentIdx,
00191 int start,
00192 int end )
00193 {
00194 BASE::sourceColumnsAboutToBeRemoved( parentIdx, start, end );
00195 d->clearCache();
00196 }
00197
00198 void SummaryHandlingProxyModel::sourceRowsAboutToBeInserted( const QModelIndex & parentIdx, int start, int end )
00199 {
00200 BASE::sourceRowsAboutToBeInserted( parentIdx, start, end );
00201 d->clearCache();
00202 }
00203
00204 void SummaryHandlingProxyModel::sourceRowsAboutToBeRemoved( const QModelIndex & parentIdx, int start, int end )
00205 {
00206 BASE::sourceRowsAboutToBeRemoved( parentIdx, start, end );
00207 d->clearCache();
00208 }
00209
00211 Qt::ItemFlags SummaryHandlingProxyModel::flags( const QModelIndex& idx ) const
00212 {
00213 const QModelIndex sidx = mapToSource( idx );
00214 const QAbstractItemModel* model = sourceModel();
00215 Qt::ItemFlags f = model->flags( sidx );
00216 if ( d->isSummary(sidx) ) {
00217 f &= !Qt::ItemIsEditable;
00218 }
00219 return f;
00220 }
00221
00223 QVariant SummaryHandlingProxyModel::data( const QModelIndex& proxyIndex, int role) const
00224 {
00225
00226 const QModelIndex sidx = mapToSource( proxyIndex );
00227 const QAbstractItemModel* model = sourceModel();
00228 if ( d->isSummary(sidx) && ( role==StartTimeRole || role==EndTimeRole )) {
00229
00230 QPair<QDateTime,QDateTime> result;
00231 if ( d->cacheLookup( sidx, &result ) ) {
00232
00233 switch( role ) {
00234 case StartTimeRole: return result.first;
00235 case EndTimeRole: return result.second;
00236 default: ;
00237 }
00238 } else {
00239 d->insertInCache( this, sidx );
00240 return data( proxyIndex, role );
00241 }
00242 }
00243 return model->data( sidx, role );
00244 }
00245
00247 bool SummaryHandlingProxyModel::setData( const QModelIndex& index, const QVariant& value, int role )
00248 {
00249 QAbstractItemModel* model = sourceModel();
00250 if ( role==StartTimeRole || role==EndTimeRole ) {
00251 QModelIndex parentIdx = mapToSource( index );
00252 do {
00253 if ( d->isSummary(parentIdx) ) {
00254
00255 d->removeFromCache( parentIdx );
00256 QModelIndex proxyParentIdx = mapFromSource( parentIdx );
00257 emit dataChanged( proxyParentIdx, proxyParentIdx );
00258 }
00259 } while ( ( parentIdx=model->parent( parentIdx ) ) != QModelIndex() );
00260 }
00261 return BASE::setData( index, value, role );
00262 }
00263
00264 #undef d
00265
00266 #ifndef KDAB_NO_UNIT_TESTS
00267
00268 #include "unittest/test.h"
00269
00270 #include <QStandardItemModel>
00271
00272 namespace {
00273 std::ostream& operator<<( std::ostream& os, const QDateTime& dt )
00274 {
00275 os << dt.toString().toStdString();
00276 return os;
00277 }
00278 }
00279
00280 KDAB_SCOPED_UNITTEST_SIMPLE( KDGantt, SummaryHandlingProxyModel, "test" ) {
00281 SummaryHandlingProxyModel model;
00282 QStandardItemModel sourceModel;
00283
00284 model.setSourceModel( &sourceModel );
00285
00286 QStandardItem* topitem = new QStandardItem( QString::fromLatin1( "Summary" ) );
00287 topitem->setData( KDGantt::TypeSummary, KDGantt::ItemTypeRole );
00288 sourceModel.appendRow( topitem );
00289
00290 QStandardItem* task1 = new QStandardItem( QString::fromLatin1( "Task1" ) );
00291 task1->setData( KDGantt::TypeTask, KDGantt::ItemTypeRole );
00292 QStandardItem* task2 = new QStandardItem( QString::fromLatin1( "Task2" ) );
00293 task2->setData( KDGantt::TypeTask, KDGantt::ItemTypeRole );
00294 topitem->appendRow( task1 );
00295 topitem->appendRow( task2 );
00296
00297
00298 QDateTime startdt = QDateTime::currentDateTime();
00299 QDateTime enddt = startdt.addDays( 1 );
00300
00301
00302 task1->setData( startdt, KDGantt::StartTimeRole );
00303 task1->setData( enddt, KDGantt::EndTimeRole );
00304 task2->setData( startdt, KDGantt::StartTimeRole );
00305 task2->setData( enddt, KDGantt::EndTimeRole );
00306
00307 const QModelIndex topidx = model.index( 0, 0, QModelIndex() );
00308
00309 assertEqual( model.data( topidx, KDGantt::ItemTypeRole ).toInt(), KDGantt::TypeSummary );
00310 assertEqual( model.data( model.index( 0, 0, topidx ), KDGantt::ItemTypeRole ).toInt(), KDGantt::TypeTask );
00311
00312 QDateTime task1startdt = model.data( model.index( 0, 0, topidx ), KDGantt::StartTimeRole ).toDateTime();
00313 assertEqual( task1startdt, startdt );
00314
00315 QDateTime summarystartdt = model.data( topidx, KDGantt::StartTimeRole ).toDateTime();
00316 assertEqual( summarystartdt, startdt );
00317 assertTrue( model.flags( model.index( 0, 0, topidx ) ) & Qt::ItemIsEditable );
00318 assertFalse( model.flags( topidx ) & Qt::ItemIsEditable );
00319 }
00320
00321 #endif
00322
00323 #include "moc_kdganttsummaryhandlingproxymodel.cpp"