00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "kdganttconstraintmodel.h"
00024 #include "kdganttconstraintmodel_p.h"
00025
00026 #include <QDebug>
00027
00028 #include <cassert>
00029 #include <algorithm>
00030 #include <functional>
00031
00032 using namespace KDGantt;
00033
00042 ConstraintModel::Private::Private()
00043 {
00044 }
00045
00046 void ConstraintModel::Private::addConstraintToIndex( const QModelIndex& idx, const Constraint& c )
00047 {
00048 IndexType::iterator it = indexMap.find(idx);
00049 while (it != indexMap.end() && it.key() == idx) {
00050
00051 if ( *it == c ) return;
00052 ++it;
00053 }
00054
00055 indexMap.insert( idx, c );
00056 }
00057
00058 void ConstraintModel::Private::removeConstraintFromIndex( const QModelIndex& idx, const Constraint& c )
00059 {
00060 IndexType::iterator it = indexMap.find(idx);
00061 while (it != indexMap.end() && it.key() == idx) {
00062 if ( c.compareIndexes(*it) ) {
00063 it =indexMap.erase( it );
00064 } else {
00065 ++it;
00066 }
00067 }
00068 }
00069
00072 ConstraintModel::ConstraintModel( QObject* parent )
00073 : QObject( parent ), _d( new Private )
00074 {
00075 init();
00076 }
00077
00079 ConstraintModel::ConstraintModel( Private* d_ptr, QObject* parent )
00080 : QObject( parent ), _d( d_ptr )
00081 {
00082 init();
00083 }
00084
00086 ConstraintModel::~ConstraintModel()
00087 {
00088 delete _d;
00089 }
00090
00091 #define d d_func()
00092
00093 void ConstraintModel::init()
00094 {
00095 }
00096
00097 namespace {
00098 struct compare_constraint_indexes_to : public std::unary_function<bool,Constraint> {
00099 compare_constraint_indexes_to( const Constraint& c )
00100 : m_c( c ) {
00101 }
00102 bool operator()( const Constraint& c ) const
00103 {
00104 return m_c.compareIndexes( c );
00105 }
00106
00107 const Constraint& m_c;
00108 };
00109 }
00110
00115 void ConstraintModel::addConstraint( const Constraint& c )
00116 {
00117
00118 QList<Constraint>::iterator it = std::find_if ( d->constraints.begin(),
00119 d->constraints.end(),
00120 compare_constraint_indexes_to(c) );
00121
00122 if ( it == d->constraints.end() ) {
00123 d->constraints.push_back( c );
00124 d->addConstraintToIndex( c.startIndex(), c );
00125 d->addConstraintToIndex( c.endIndex(), c );
00126 emit constraintAdded( c );
00127 } else if ( ( *it ).dataMap() != c.dataMap() ) {
00128 Constraint tmp( *it );
00129 removeConstraint( tmp );
00130 d->constraints.push_back( c );
00131 d->addConstraintToIndex( c.startIndex(), c );
00132 d->addConstraintToIndex( c.endIndex(), c );
00133 emit constraintAdded( c );
00134 }
00135 }
00136
00144 bool ConstraintModel::removeConstraint( const Constraint& c )
00145 {
00146 bool rc = false;
00147
00148 for(int i = 0; i < d->constraints.count(); i++)
00149 {
00150 if(c.compareIndexes(d->constraints.at(i)))
00151 {
00152 d->constraints.removeAt(i);
00153 rc = true;
00154 }
00155 }
00156
00157 if ( rc ) {
00158 d->removeConstraintFromIndex( c.startIndex(), c );
00159 d->removeConstraintFromIndex( c.endIndex(), c );
00160 emit constraintRemoved( c );
00161 }
00162
00163 return rc;
00164 }
00165
00170 void ConstraintModel::clear()
00171 {
00172 QList<Constraint> lst = constraints();
00173 Q_FOREACH( const Constraint& c, lst ) {
00174 removeConstraint( c );
00175 }
00176 }
00177
00179 void ConstraintModel::cleanup()
00180 {
00181 #if 0
00182 QSet<Constraint> orphans;
00183 Q_FOREACH( const Constraint& c, d->constraints ) {
00184 if ( !c.startIndex().isValid() || !c.endIndex().isValid() ) orphans.insert( c );
00185 }
00186
00187 d->constraints.subtract( orphans );
00188 #endif
00189 }
00190
00194 QList<Constraint> ConstraintModel::constraints() const
00195 {
00196
00197 return d->constraints;
00198 }
00199
00203 QList<Constraint> ConstraintModel::constraintsForIndex( const QModelIndex& idx ) const
00204 {
00205
00206 assert( !idx.isValid() || d->indexMap.isEmpty() || !d->indexMap.keys().front().model() || idx.model() == d->indexMap.keys().front().model() );
00207 if ( !idx.isValid() ) {
00208
00209 QSet<Constraint> result;
00210 Q_FOREACH( Constraint c, d->constraints ) {
00211 if ( !c.startIndex().isValid() || !c.endIndex().isValid() ) result.insert( c );
00212 }
00213 return result.toList();
00214 } else {
00215 QList<Constraint> result;
00216 Q_FOREACH( Constraint c, d->constraints ) {
00217 if ( c.startIndex() == idx || c.endIndex() == idx ) result.push_back( c );
00218 }
00219 return result;
00220 }
00221
00222
00223 }
00224
00228 bool ConstraintModel::hasConstraint( const Constraint& c ) const
00229 {
00230
00231
00232
00233
00234
00235
00236
00237 bool hc = false;
00238
00239 for(int i = 0; i < d->constraints.count(); i++)
00240 if(c.compareIndexes(d->constraints.at(i)))
00241 hc = true;
00242
00243 return hc;
00244 }
00245
00246 #ifndef QT_NO_DEBUG_STREAM
00247
00248 QDebug operator<<( QDebug dbg, const KDGantt::ConstraintModel& model )
00249 {
00250 dbg << "KDGantt::ConstraintModel[ " << static_cast<const QObject*>( &model ) << ": [\n";
00251 Q_FOREACH( const Constraint& c, model.constraints() ) {
00252 dbg << "\t" << c << "\n";
00253 }
00254 dbg << "]\n";
00255 return dbg;
00256 }
00257
00258 #endif
00259
00260 #undef d
00261
00262 #ifndef KDAB_NO_UNIT_TESTS
00263
00264 #include <QStandardItemModel>
00265
00266 #include "unittest/test.h"
00267
00268 std::ostream& operator<<( std::ostream& os, const QModelIndex& idx )
00269 {
00270 QString str;
00271 QDebug( &str )<<idx;
00272 #ifdef QT_NO_STL
00273 os<<str.toLatin1().constData();
00274 #else
00275 os<<str.toStdString();
00276 #endif
00277 return os;
00278 }
00279
00280 KDAB_SCOPED_UNITTEST_SIMPLE( KDGantt, ConstraintModel, "test" )
00281 {
00282 QStandardItemModel dummyModel( 100, 100 );
00283 ConstraintModel model;
00284
00285 QModelIndex invalidIndex;
00286 assertEqual( invalidIndex, invalidIndex );
00287
00288 assertEqual( model.constraints().count(), 0 );
00289
00290 model.addConstraint( Constraint( QModelIndex(), QModelIndex() ) );
00291 assertEqual( model.constraints().count(), 1 );
00292
00293 model.addConstraint( Constraint( QModelIndex(), QModelIndex() ) );
00294 assertEqual( model.constraints().count(), 1 );
00295
00296 QPersistentModelIndex idx1 = dummyModel.index( 7, 17, QModelIndex() );
00297 QPersistentModelIndex idx2 = dummyModel.index( 42, 17, QModelIndex() );
00298
00299 model.addConstraint( Constraint( idx1, idx2 ) );
00300 assertEqual( model.constraints().count(), 2 );
00301 assertTrue( model.hasConstraint( Constraint( idx1, idx2 ) ) );
00302
00303 assertEqual( model.constraintsForIndex( QModelIndex() ).count(), 1 );
00304
00305 assertEqual( model.constraints().count(), 2 );
00306 model.removeConstraint( Constraint( QModelIndex(), QModelIndex() ) );
00307 assertEqual( model.constraints().count(), 1 );
00308 assertFalse( model.hasConstraint( Constraint( QModelIndex(), QModelIndex() ) ) );
00309
00310 model.removeConstraint( Constraint( QModelIndex(), QModelIndex() ) );
00311 assertEqual( model.constraints().count(), 1 );
00312
00313 model.removeConstraint( Constraint( idx1, idx2 ) );
00314 assertEqual( model.constraints().count(), 0 );
00315 assertFalse( model.hasConstraint( Constraint( idx1, idx2 ) ) );
00316
00317 model.addConstraint( Constraint( idx1, idx2 ) );
00318 assertTrue( model.hasConstraint( Constraint( idx1, idx2 ) ) );
00319 dummyModel.removeRow( 8 );
00320 assertTrue( model.hasConstraint( Constraint( idx1, idx2 ) ) );
00321 dummyModel.removeRow( 7 );
00322 assertTrue( model.hasConstraint( Constraint( idx1, idx2 ) ) );
00323 }
00324
00325 #endif
00326
00327 #include "moc_kdganttconstraintmodel.cpp"