kdganttsummaryhandlingproxymodel.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002  ** Copyright (C) 2001-2006 Klarälvdalens Datakonsult AB.  All rights reserved.
00003  **
00004  ** This file is part of the KD Gantt library.
00005  **
00006  ** This file may be distributed and/or modified under the terms of the
00007  ** GNU General Public License version 2 as published by the Free Software
00008  ** Foundation and appearing in the file LICENSE.GPL included in the
00009  ** packaging of this file.
00010  **
00011  ** Licensees holding valid commercial KD Gantt licenses may use this file in
00012  ** accordance with the KD Gantt Commercial License Agreement provided with
00013  ** the Software.
00014  **
00015  ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00016  ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00017  **
00018  ** See http://www.kdab.net/kdgantt for
00019  **   information about KD Gantt Commercial License Agreements.
00020  **
00021  ** Contact info@kdab.net if any conditions of this
00022  ** licensing are not clear to you.
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     //qDebug() << "cacheLookup("<<idx<<"), cache has " << cached_summary_items.count() << "items";
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         /* The probably results in recursive calls here */
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         // check for valid datetimes
00086         if( tmpsv.type() == QVariant::DateTime && !qVariantValue<QDateTime>(tmpsv).isValid()) continue;
00087         if( tmpev.type() == QVariant::DateTime && !qVariantValue<QDateTime>(tmpev).isValid()) continue;
00088 
00089         // We need to test for empty strings to
00090         // avoid a stupid Qt warning
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     // Think this is ugly? Well, it's not from me, it comes from QProxyModel
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             //qDebug() << "removing " << parentIdx << "from cache";
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   //qDebug() << "SummaryHandlingProxyModel::data("<<proxyIndex<<role<<")";
00232     const QModelIndex sidx = mapToSource( proxyIndex );
00233     const QAbstractItemModel* model = sourceModel();
00234     if ( d->isSummary(sidx) && ( role==StartTimeRole || role==EndTimeRole )) {
00235       //qDebug() << "requested summary";
00236         QPair<QDateTime,QDateTime> result;
00237         if ( d->cacheLookup( sidx, &result ) ) {
00238           //qDebug() << "SummaryHandlingProxyModel::data(): Looking up summary for " << proxyIndex << role;
00239             switch( role ) {
00240             case StartTimeRole: return result.first;
00241             case EndTimeRole: return result.second;
00242             default: /* fall thru */;
00243             }
00244         } else {
00245             d->insertInCache( this, sidx );
00246             return data( proxyIndex, role ); /* TODO: Optimise */
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               //qDebug() << "removing " << parentIdx << "from cache";
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 /* KDAB_NO_UNIT_TESTS */
00332 
00333 #include "moc_kdganttsummaryhandlingproxymodel.cpp"

Generated on Thu Mar 4 23:19:13 2010 for KD Chart 2 by  doxygen 1.5.4