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.constFind( 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 if( tmpsv.type() == QVariant::DateTime && !qVariantValue<QDateTime>(tmpsv).isValid()) continue;
00085 if( tmpev.type() == QVariant::DateTime && !qVariantValue<QDateTime>(tmpev).isValid()) continue;
00086
00087
00088
00089 if( tmpsv.type() == QVariant::String && qVariantValue<QString>(tmpsv).isEmpty()) continue;
00090 if( tmpev.type() == QVariant::String && qVariantValue<QString>(tmpev).isEmpty()) continue;
00091 QDateTime tmpst = tmpsv.toDateTime();
00092 QDateTime tmpet = tmpev.toDateTime();
00093 if ( st.isNull() || st > tmpst ) st = tmpst;
00094 if ( et.isNull() || et < tmpet ) et = tmpet;
00095 }
00096 QVariant tmpssv = sourceModel->data( mainIdx, StartTimeRole );
00097 QVariant tmpsev = sourceModel->data( mainIdx, EndTimeRole );
00098 if ( qVariantCanConvert<QDateTime>( tmpssv )
00099 && !( qVariantCanConvert<QString>( tmpssv ) && qVariantValue<QString>( tmpssv ).isEmpty() )
00100 && qVariantValue<QDateTime>( tmpssv ) != st )
00101 sourceModel->setData( mainIdx, st, StartTimeRole );
00102 if ( qVariantCanConvert<QDateTime>( tmpsev )
00103 && !( qVariantCanConvert<QString>( tmpsev ) && qVariantValue<QString>( tmpsev ).isEmpty() )
00104 && qVariantValue<QDateTime>( tmpsev ) != et )
00105 sourceModel->setData( mainIdx, et, EndTimeRole );
00106 cached_summary_items[sourceIdx]=qMakePair( st, et );
00107 }
00108
00109 void SummaryHandlingProxyModel::Private::removeFromCache( const QModelIndex& idx ) const
00110 {
00111 cached_summary_items.remove( idx );
00112 }
00113
00114 void SummaryHandlingProxyModel::Private::clearCache() const
00115 {
00116 cached_summary_items.clear();
00117 }
00118
00122 SummaryHandlingProxyModel::SummaryHandlingProxyModel( QObject* parent )
00123 : BASE( parent ), _d( new Private )
00124 {
00125 init();
00126 }
00127
00128 #define d d_func()
00129 SummaryHandlingProxyModel::~SummaryHandlingProxyModel()
00130 {
00131 }
00132
00133 void SummaryHandlingProxyModel::init()
00134 {
00135 }
00136
00137 namespace {
00138
00139
00140 struct KDPrivateModelIndex {
00141 int r, c;
00142 void *p;
00143 const QAbstractItemModel *m;
00144 };
00145 }
00146
00151 void SummaryHandlingProxyModel::setSourceModel( QAbstractItemModel* model )
00152 {
00153 BASE::setSourceModel( model );
00154 d->clearCache();
00155 }
00156
00157 void SummaryHandlingProxyModel::sourceModelReset()
00158 {
00159 d->clearCache();
00160 BASE::sourceModelReset();
00161 }
00162
00163 void SummaryHandlingProxyModel::sourceLayoutChanged()
00164 {
00165 d->clearCache();
00166 BASE::sourceLayoutChanged();
00167 }
00168
00169 void SummaryHandlingProxyModel::sourceDataChanged( const QModelIndex& from, const QModelIndex& to )
00170 {
00171 QAbstractItemModel* model = sourceModel();
00172 QModelIndex parentIdx = from;
00173 do {
00174 const QModelIndex& dataIdx = parentIdx;
00175 if ( model->data( dataIdx, ItemTypeRole )==TypeSummary ) {
00176
00177 d->removeFromCache( dataIdx );
00178 QModelIndex proxyDataIdx = mapFromSource( dataIdx );
00179 emit dataChanged( proxyDataIdx, proxyDataIdx );
00180 }
00181 } while ( ( parentIdx=model->parent( parentIdx ) ) != QModelIndex() );
00182
00183 BASE::sourceDataChanged( from, to );
00184 }
00185
00186 void SummaryHandlingProxyModel::sourceColumnsAboutToBeInserted( const QModelIndex& parentIdx,
00187 int start,
00188 int end )
00189 {
00190 BASE::sourceColumnsAboutToBeInserted( parentIdx, start, end );
00191 d->clearCache();
00192 }
00193
00194 void SummaryHandlingProxyModel::sourceColumnsAboutToBeRemoved( const QModelIndex& parentIdx,
00195 int start,
00196 int end )
00197 {
00198 BASE::sourceColumnsAboutToBeRemoved( parentIdx, start, end );
00199 d->clearCache();
00200 }
00201
00202 void SummaryHandlingProxyModel::sourceRowsAboutToBeInserted( const QModelIndex & parentIdx, int start, int end )
00203 {
00204 BASE::sourceRowsAboutToBeInserted( parentIdx, start, end );
00205 d->clearCache();
00206 }
00207
00208 void SummaryHandlingProxyModel::sourceRowsAboutToBeRemoved( const QModelIndex & parentIdx, int start, int end )
00209 {
00210 BASE::sourceRowsAboutToBeRemoved( parentIdx, start, end );
00211 d->clearCache();
00212 }
00213
00215 Qt::ItemFlags SummaryHandlingProxyModel::flags( const QModelIndex& idx ) const
00216 {
00217 const QModelIndex sidx = mapToSource( idx );
00218 const QAbstractItemModel* model = sourceModel();
00219 Qt::ItemFlags f = model->flags( sidx );
00220 if ( d->isSummary(sidx) ) {
00221 f &= !Qt::ItemIsEditable;
00222 }
00223 return f;
00224 }
00225
00227 QVariant SummaryHandlingProxyModel::data( const QModelIndex& proxyIndex, int role) const
00228 {
00229
00230 const QModelIndex sidx = mapToSource( proxyIndex );
00231 const QAbstractItemModel* model = sourceModel();
00232 if ( d->isSummary(sidx) && ( role==StartTimeRole || role==EndTimeRole )) {
00233
00234 QPair<QDateTime,QDateTime> result;
00235 if ( d->cacheLookup( sidx, &result ) ) {
00236
00237 switch( role ) {
00238 case StartTimeRole: return result.first;
00239 case EndTimeRole: return result.second;
00240 default: ;
00241 }
00242 } else {
00243 d->insertInCache( this, sidx );
00244 return data( proxyIndex, role );
00245 }
00246 }
00247 return model->data( sidx, role );
00248 }
00249
00251 bool SummaryHandlingProxyModel::setData( const QModelIndex& index, const QVariant& value, int role )
00252 {
00253 QAbstractItemModel* model = sourceModel();
00254 if ( role==StartTimeRole || role==EndTimeRole ) {
00255 QModelIndex parentIdx = mapToSource( index );
00256 do {
00257 if ( d->isSummary(parentIdx) ) {
00258
00259 d->removeFromCache( parentIdx );
00260 QModelIndex proxyParentIdx = mapFromSource( parentIdx );
00261 emit dataChanged( proxyParentIdx, proxyParentIdx );
00262 }
00263 } while ( ( parentIdx=model->parent( parentIdx ) ) != QModelIndex() );
00264 }
00265 return BASE::setData( index, value, role );
00266 }
00267
00268 #undef d
00269
00270 #ifndef KDAB_NO_UNIT_TESTS
00271
00272 #include "unittest/test.h"
00273
00274 #include <QStandardItemModel>
00275
00276 namespace {
00277 std::ostream& operator<<( std::ostream& os, const QDateTime& dt )
00278 {
00279 #ifdef QT_NO_STL
00280 os << dt.toString().toLatin1().constData();
00281 #else
00282 os << dt.toString().toStdString();
00283 #endif
00284 return os;
00285 }
00286 }
00287
00288 KDAB_SCOPED_UNITTEST_SIMPLE( KDGantt, SummaryHandlingProxyModel, "test" ) {
00289 SummaryHandlingProxyModel model;
00290 QStandardItemModel sourceModel;
00291
00292 model.setSourceModel( &sourceModel );
00293
00294 QStandardItem* topitem = new QStandardItem( QString::fromLatin1( "Summary" ) );
00295 topitem->setData( KDGantt::TypeSummary, KDGantt::ItemTypeRole );
00296 sourceModel.appendRow( topitem );
00297
00298 QStandardItem* task1 = new QStandardItem( QString::fromLatin1( "Task1" ) );
00299 task1->setData( KDGantt::TypeTask, KDGantt::ItemTypeRole );
00300 QStandardItem* task2 = new QStandardItem( QString::fromLatin1( "Task2" ) );
00301 task2->setData( KDGantt::TypeTask, KDGantt::ItemTypeRole );
00302 topitem->appendRow( task1 );
00303 topitem->appendRow( task2 );
00304
00305
00306 QDateTime startdt = QDateTime::currentDateTime();
00307 QDateTime enddt = startdt.addDays( 1 );
00308
00309
00310 task1->setData( startdt, KDGantt::StartTimeRole );
00311 task1->setData( enddt, KDGantt::EndTimeRole );
00312 task2->setData( startdt, KDGantt::StartTimeRole );
00313 task2->setData( enddt, KDGantt::EndTimeRole );
00314
00315 const QModelIndex topidx = model.index( 0, 0, QModelIndex() );
00316
00317 assertEqual( model.data( topidx, KDGantt::ItemTypeRole ).toInt(), KDGantt::TypeSummary );
00318 assertEqual( model.data( model.index( 0, 0, topidx ), KDGantt::ItemTypeRole ).toInt(), KDGantt::TypeTask );
00319
00320 QDateTime task1startdt = model.data( model.index( 0, 0, topidx ), KDGantt::StartTimeRole ).toDateTime();
00321 assertEqual( task1startdt, startdt );
00322
00323 QDateTime summarystartdt = model.data( topidx, KDGantt::StartTimeRole ).toDateTime();
00324 assertEqual( summarystartdt, startdt );
00325 assertTrue( model.flags( model.index( 0, 0, topidx ) ) & Qt::ItemIsEditable );
00326 assertFalse( model.flags( topidx ) & Qt::ItemIsEditable );
00327 }
00328
00329 #endif
00330
00331 #include "moc_kdganttsummaryhandlingproxymodel.cpp"