KD Chart 2  [rev.2.5]
kdganttconstraintmodel.cpp
Go to the documentation of this file.
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"
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Defines

Klarälvdalens Datakonsult AB (KDAB)
Qt-related services and products
http://www.kdab.com/
http://www.kdab.com/products/kd-chart/