KD Chart 2
[rev.2.5]
|
00001 /**************************************************************************** 00002 ** Copyright (C) 2001-2012 Klaralvdalens Datakonsult AB. All rights reserved. 00003 ** 00004 ** This file is part of the KD Chart library. 00005 ** 00006 ** Licensees holding valid commercial KD Chart licenses may use this file in 00007 ** accordance with the KD Chart Commercial License Agreement provided with 00008 ** the Software. 00009 ** 00010 ** 00011 ** This file may be distributed and/or modified under the terms of the 00012 ** GNU General Public License version 2 and version 3 as published by the 00013 ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included. 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 ** Contact info@kdab.com if any conditions of this licensing are not 00019 ** clear to you. 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 // Check if we already have this 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 //qDebug() << "ConstraintModel::addConstraint("<<c<<") (this="<<this<<") items=" << d->constraints.size(); 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 ); // save to avoid re-entrancy issues 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 //qDebug() << "Constraint::cleanup() found" << orphans << "orphans"; 00187 d->constraints.subtract( orphans ); 00188 #endif 00189 } 00190 00194 QList<Constraint> ConstraintModel::constraints() const 00195 { 00196 //return d->constraints.toList(); 00197 return d->constraints; 00198 } 00199 00203 QList<Constraint> ConstraintModel::constraintsForIndex( const QModelIndex& idx ) const 00204 { 00205 // TODO: @Steffen: Please comment on this assert, it's long and not obvious (Johannes) 00206 assert( !idx.isValid() || d->indexMap.isEmpty() || !d->indexMap.keys().front().model() || idx.model() == d->indexMap.keys().front().model() ); 00207 if ( !idx.isValid() ) { 00208 // Because of a Qt bug we need to treat this as a special case 00209 QSet<Constraint> result; 00210 Q_FOREACH( const 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( const Constraint& c, d->constraints ) { 00217 if ( c.startIndex() == idx || c.endIndex() == idx ) result.push_back( c ); 00218 } 00219 return result; 00220 } 00221 00222 //return d->indexMap.values( idx ); 00223 } 00224 00228 bool ConstraintModel::hasConstraint( const Constraint& c ) const 00229 { 00230 /* 00231 // Because of a Qt bug we have to search like this 00232 Q_FOREACH( Constraint c2, d->constraints ) { 00233 if ( c==c2 ) return true; 00234 } 00235 return false; 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 /* QT_NO_DEBUG_STREAM */ 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 /* KDAB_NO_UNIT_TESTS */ 00326 00327 #include "moc_kdganttconstraintmodel.cpp"