mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-23 10:22:50 +00:00
285 lines
8.2 KiB
C++
285 lines
8.2 KiB
C++
/****************************************************************************
|
|
** Copyright (C) 2001-2006 Klarälvdalens Datakonsult AB. All rights reserved.
|
|
**
|
|
** This file is part of the KD Gantt library.
|
|
**
|
|
** This file may be distributed and/or modified under the terms of the
|
|
** GNU General Public License version 2 as published by the Free Software
|
|
** Foundation and appearing in the file LICENSE.GPL included in the
|
|
** packaging of this file.
|
|
**
|
|
** Licensees holding valid commercial KD Gantt licenses may use this file in
|
|
** accordance with the KD Gantt Commercial License Agreement provided with
|
|
** the Software.
|
|
**
|
|
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
|
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
**
|
|
** See http://www.kdab.net/kdgantt for
|
|
** information about KD Gantt Commercial License Agreements.
|
|
**
|
|
** Contact info@kdab.net if any conditions of this
|
|
** licensing are not clear to you.
|
|
**
|
|
**********************************************************************/
|
|
#include "kdganttconstraintmodel.h"
|
|
#include "kdganttconstraintmodel_p.h"
|
|
|
|
#include <QDebug>
|
|
|
|
#include <cassert>
|
|
|
|
using namespace KDGantt;
|
|
|
|
/*!\class KDGantt::ConstraintModel
|
|
*\ingroup KDGantt
|
|
* The ConstraintModel keeps track of the
|
|
* interdependencies between gantt items in
|
|
* a View.
|
|
*
|
|
*/
|
|
|
|
ConstraintModel::Private::Private()
|
|
{
|
|
}
|
|
|
|
void ConstraintModel::Private::addConstraintToIndex( const QModelIndex& idx, const Constraint& c )
|
|
{
|
|
IndexType::iterator it = indexMap.find(idx);
|
|
while (it != indexMap.end() && it.key() == idx) {
|
|
// Check if we already have this
|
|
if ( *it == c ) return;
|
|
++it;
|
|
}
|
|
|
|
indexMap.insert( idx, c );
|
|
}
|
|
|
|
void ConstraintModel::Private::removeConstraintFromIndex( const QModelIndex& idx, const Constraint& c )
|
|
{
|
|
IndexType::iterator it = indexMap.find(idx);
|
|
while (it != indexMap.end() && it.key() == idx) {
|
|
if ( *it == c ) {
|
|
it =indexMap.erase( it );
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*! Constructor. Creates an empty ConstraintModel with parent \a parent
|
|
*/
|
|
ConstraintModel::ConstraintModel( QObject* parent )
|
|
: QObject( parent ), _d( new Private )
|
|
{
|
|
init();
|
|
}
|
|
|
|
/*!\internal*/
|
|
ConstraintModel::ConstraintModel( Private* d_ptr, QObject* parent )
|
|
: QObject( parent ), _d( d_ptr )
|
|
{
|
|
init();
|
|
}
|
|
|
|
/*! Destroys this ConstraintModel */
|
|
ConstraintModel::~ConstraintModel()
|
|
{
|
|
delete _d;
|
|
}
|
|
|
|
#define d d_func()
|
|
|
|
void ConstraintModel::init()
|
|
{
|
|
}
|
|
|
|
/*! Adds the constraint \a c to this ConstraintModel
|
|
* If the Constraint \a c is already in this ConstraintModel,
|
|
* nothing happens.
|
|
*/
|
|
void ConstraintModel::addConstraint( const Constraint& c )
|
|
{
|
|
//int size = d->constraints.size();
|
|
bool hasConstraint = d->constraints.contains( c );
|
|
//d->constraints.insert( c );
|
|
//if ( size != d->constraints.size() ) {
|
|
if ( !hasConstraint ) {
|
|
d->constraints.push_back( c );
|
|
d->addConstraintToIndex( c.startIndex(), c );
|
|
d->addConstraintToIndex( c.endIndex(), c );
|
|
emit constraintAdded( c );
|
|
}
|
|
}
|
|
|
|
/*! Removes the Constraint \a c from this
|
|
* ConstraintModel. If \a c was found and removed,
|
|
* the signal constraintRemoved(const Constraint&) is emitted.
|
|
*
|
|
* \returns If \a c was found and removed, it returns true,
|
|
* otherwise it returns false.
|
|
*/
|
|
bool ConstraintModel::removeConstraint( const Constraint& c )
|
|
{
|
|
//qDebug() << "ConstraintModel::removeConstraint("<<c<<") from "<< d->constraints;
|
|
bool rc = d->constraints.removeAll( c );
|
|
//bool rc = d->constraints.remove( c );
|
|
if ( rc ) {
|
|
d->removeConstraintFromIndex( c.startIndex(), c );
|
|
d->removeConstraintFromIndex( c.endIndex(), c );
|
|
emit constraintRemoved( c );
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/*! Removes all Constraints from this model
|
|
* The signal constraintRemoved(const Constraint&) is emitted
|
|
* for every Constraint that is removed.
|
|
*/
|
|
void ConstraintModel::clear()
|
|
{
|
|
QList<Constraint> lst = constraints();
|
|
Q_FOREACH( const Constraint& c, lst ) {
|
|
removeConstraint( c );
|
|
}
|
|
}
|
|
|
|
/*! Not used */
|
|
void ConstraintModel::cleanup()
|
|
{
|
|
#if 0
|
|
QSet<Constraint> orphans;
|
|
Q_FOREACH( const Constraint& c, d->constraints ) {
|
|
if ( !c.startIndex().isValid() || !c.endIndex().isValid() ) orphans.insert( c );
|
|
}
|
|
//qDebug() << "Constraint::cleanup() found" << orphans << "orphans";
|
|
d->constraints.subtract( orphans );
|
|
#endif
|
|
}
|
|
|
|
/*! \returns A list of all Constraints in this
|
|
* ConstraintModel.
|
|
*/
|
|
QList<Constraint> ConstraintModel::constraints() const
|
|
{
|
|
//return d->constraints.toList();
|
|
return d->constraints;
|
|
}
|
|
|
|
/*! \returns A list of all Constraints in this ConstraintModel
|
|
* that have an endpoint at \a idx.
|
|
*/
|
|
QList<Constraint> ConstraintModel::constraintsForIndex( const QModelIndex& idx ) const
|
|
{
|
|
assert( !idx.isValid() || d->indexMap.isEmpty() || !d->indexMap.keys().front().model() || idx.model() == d->indexMap.keys().front().model() );
|
|
if ( !idx.isValid() ) {
|
|
// Because of a Qt bug we need to treat this as a special case
|
|
QSet<Constraint> result;
|
|
Q_FOREACH( Constraint c, d->constraints ) {
|
|
if ( !c.startIndex().isValid() || !c.endIndex().isValid() ) result.insert( c );
|
|
}
|
|
return result.toList();
|
|
} else {
|
|
QList<Constraint> result;
|
|
Q_FOREACH( Constraint c, d->constraints ) {
|
|
if ( c.startIndex() == idx || c.endIndex() == idx ) result.push_back( c );
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//return d->indexMap.values( idx );
|
|
}
|
|
|
|
/*! Returns true if a Constraint with start \a s and end \a e
|
|
* exists, otherwise false.
|
|
*/
|
|
bool ConstraintModel::hasConstraint( const Constraint& c ) const
|
|
{
|
|
/*
|
|
// Because of a Qt bug we have to search like this
|
|
Q_FOREACH( Constraint c2, d->constraints ) {
|
|
if ( c==c2 ) return true;
|
|
}
|
|
return false;
|
|
*/
|
|
return d->constraints.contains( c );
|
|
}
|
|
|
|
#ifndef QT_NO_DEBUG_STREAM
|
|
|
|
QDebug operator<<( QDebug dbg, const KDGantt::ConstraintModel& model )
|
|
{
|
|
dbg << "KDGantt::ConstraintModel[ " << static_cast<const QObject*>( &model ) << ":"
|
|
<< model.constraints() << "]";
|
|
return dbg;
|
|
}
|
|
|
|
#endif /* QT_NO_DEBUG_STREAM */
|
|
|
|
#undef d
|
|
|
|
#ifndef KDAB_NO_UNIT_TESTS
|
|
|
|
#include <QStandardItemModel>
|
|
|
|
#include "unittest/test.h"
|
|
|
|
std::ostream& operator<<( std::ostream& os, const QModelIndex& idx )
|
|
{
|
|
QString str;
|
|
QDebug( &str )<<idx;
|
|
#ifdef QT_NO_STL
|
|
os<<str.toLatin1().constData();
|
|
#else
|
|
os<<str.toStdString();
|
|
#endif
|
|
return os;
|
|
}
|
|
|
|
KDAB_SCOPED_UNITTEST_SIMPLE( KDGantt, ConstraintModel, "test" )
|
|
{
|
|
QStandardItemModel dummyModel( 100, 100 );
|
|
ConstraintModel model;
|
|
|
|
QModelIndex invalidIndex;
|
|
assertEqual( invalidIndex, invalidIndex );
|
|
|
|
assertEqual( model.constraints().count(), 0 );
|
|
|
|
model.addConstraint( Constraint( QModelIndex(), QModelIndex() ) );
|
|
assertEqual( model.constraints().count(), 1 );
|
|
|
|
model.addConstraint( Constraint( QModelIndex(), QModelIndex() ) );
|
|
assertEqual( model.constraints().count(), 1 );
|
|
|
|
QPersistentModelIndex idx1 = dummyModel.index( 7, 17, QModelIndex() );
|
|
QPersistentModelIndex idx2 = dummyModel.index( 42, 17, QModelIndex() );
|
|
|
|
model.addConstraint( Constraint( idx1, idx2 ) );
|
|
assertEqual( model.constraints().count(), 2 );
|
|
assertTrue( model.hasConstraint( Constraint( idx1, idx2 ) ) );
|
|
|
|
assertEqual( model.constraintsForIndex( QModelIndex() ).count(), 1 );
|
|
|
|
assertEqual( model.constraints().count(), 2 );
|
|
model.removeConstraint( Constraint( QModelIndex(), QModelIndex() ) );
|
|
assertEqual( model.constraints().count(), 1 );
|
|
assertFalse( model.hasConstraint( Constraint( QModelIndex(), QModelIndex() ) ) );
|
|
|
|
model.removeConstraint( Constraint( QModelIndex(), QModelIndex() ) );
|
|
assertEqual( model.constraints().count(), 1 );
|
|
|
|
model.removeConstraint( Constraint( idx1, idx2 ) );
|
|
assertEqual( model.constraints().count(), 0 );
|
|
assertFalse( model.hasConstraint( Constraint( idx1, idx2 ) ) );
|
|
|
|
model.addConstraint( Constraint( idx1, idx2 ) );
|
|
assertTrue( model.hasConstraint( Constraint( idx1, idx2 ) ) );
|
|
dummyModel.removeRow( 8 );
|
|
assertTrue( model.hasConstraint( Constraint( idx1, idx2 ) ) );
|
|
dummyModel.removeRow( 7 );
|
|
assertTrue( model.hasConstraint( Constraint( idx1, idx2 ) ) );
|
|
}
|
|
|
|
#endif /* KDAB_NO_UNIT_TESTS */
|
|
|