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