KGantt

kganttconstraintmodel.cpp
1/*
2 * SPDX-FileCopyrightText: 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved.
3 *
4 * This file is part of the KGantt library.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9#include "kganttconstraintmodel.h"
10#include "kganttconstraintmodel_p.h"
11
12
13#include <cassert>
14#include <algorithm>
15#include <functional>
16
17using namespace KGantt;
18
19
20
21ConstraintModel::Private::Private()
22{
23}
24
25void ConstraintModel::Private::addConstraintToIndex( const QModelIndex& idx, const Constraint& c )
26{
27 IndexType::iterator it = indexMap.find(idx);
28 while (it != indexMap.end() && it.key() == idx) {
29 // Check if we already have this
30 if ( *it == c ) return;
31 ++it;
32 }
33
34 indexMap.insert( idx, c );
35}
36
37void ConstraintModel::Private::removeConstraintFromIndex( const QModelIndex& idx, const Constraint& c )
38{
39 IndexType::iterator it = indexMap.find(idx);
40 while (it != indexMap.end() && it.key() == idx) {
41 if ( c.compareIndexes(*it) ) {
42 it =indexMap.erase( it );
43 } else {
44 ++it;
45 }
46 }
47}
48
49
51 : QObject( parent ), _d( new Private )
52{
53 init();
54}
55
56
57ConstraintModel::ConstraintModel( Private* d_ptr, QObject* parent )
58 : QObject( parent ), _d( d_ptr )
59{
60 init();
61}
62
63
65{
66 delete _d;
67}
68
69#define d d_func()
70
71void ConstraintModel::init()
72{
73}
74
75namespace {
76 struct compare_constraint_indexes_to {
77 compare_constraint_indexes_to( const Constraint& c )
78 : m_c( c ) {
79 }
80 bool operator()( const Constraint& c ) const
81 {
82 return m_c.compareIndexes( c );
83 }
84
85 const Constraint& m_c;
86 };
87}
88
90{
91 //qDebug() << "ConstraintModel::addConstraint("<<c<<") (this="<<this<<") items=" << d->constraints.size();
92 QList<Constraint>::iterator it = std::find_if ( d->constraints.begin(),
93 d->constraints.end(),
94 compare_constraint_indexes_to(c) );
95
96 if ( it == d->constraints.end() ) {
97 d->constraints.push_back( c );
98 d->addConstraintToIndex( c.startIndex(), c );
99 d->addConstraintToIndex( c.endIndex(), c );
100 Q_EMIT constraintAdded( c );
101 } else if ( ( *it ).dataMap() != c.dataMap() || ( *it ).type() != c.type() || ( *it ).relationType() != c.relationType() ) {
102 Constraint tmp( *it ); // save to avoid re-entrancy issues
104 d->constraints.push_back( c );
105 d->addConstraintToIndex( c.startIndex(), c );
106 d->addConstraintToIndex( c.endIndex(), c );
107 Q_EMIT constraintAdded( c );
108 }
109}
110
112{
113 bool rc = false;
114
115 for (int i = 0; i < d->constraints.count(); i++)
116 {
117 if (c.compareIndexes(d->constraints.at(i)))
118 {
119 d->constraints.removeAt(i);
120 rc = true;
121 }
122 }
123
124 if ( rc ) {
125 d->removeConstraintFromIndex( c.startIndex(), c );
126 d->removeConstraintFromIndex( c.endIndex(), c );
127 Q_EMIT constraintRemoved( c );
128 }
129
130 return rc;
131}
132
134{
135 const QList<Constraint> lst = constraints();
136 for ( const Constraint& c : lst ) {
137 removeConstraint( c );
138 }
139}
140
142{
143#if 0
145 for ( const Constraint& c : qAsConst(d->constraints) ) {
146 if ( !c.startIndex().isValid() || !c.endIndex().isValid() ) orphans.insert( c );
147 }
148 //qDebug() << "Constraint::cleanup() found" << orphans << "orphans";
149 d->constraints.subtract( orphans );
150#endif
151}
152
154{
155 //return d->constraints.toList();
156 return d->constraints;
157}
158
160{
161 // TODO: @Steffen: Please comment on this assert, it's long and not obvious (Johannes)
162 // TODO: Afaics indexMap is not used anymore, so remove it (danders)
163 //assert( !idx.isValid() || d->indexMap.isEmpty() || !d->indexMap.keys().front().model() || idx.model() == d->indexMap.keys().front().model() );
164 if ( !idx.isValid() ) {
165 // Because of a Qt bug we need to treat this as a special case
166 QSet<Constraint> result;
167 for ( const Constraint& c : qAsConst(d->constraints) ) {
168 if ( !c.startIndex().isValid() || !c.endIndex().isValid() ) result.insert( c );
169 }
170 return result.values();
171 } else {
172 QList<Constraint> result;
173 for ( const Constraint& c : qAsConst(d->constraints) ) {
174 if ( c.startIndex() == idx || c.endIndex() == idx ) result.push_back( c );
175 }
176 return result;
177 }
178
179 //return d->indexMap.values( idx );
180}
181
183{
184 /*
185 // Because of a Qt bug we have to search like this
186 for ( Constraint c2 : qAsConst(d->constraints) ) {
187 if ( c==c2 ) return true;
188 }
189 return false;
190 */
191 bool hc = false;
192
193 for (int i = 0; i < d->constraints.count(); i++)
194 if (c.compareIndexes(d->constraints.at(i)))
195 hc = true;
196
197 return hc;
198}
199
200#ifndef QT_NO_DEBUG_STREAM
201
202QDebug operator<<( QDebug dbg, const KGantt::ConstraintModel& model )
203{
204 dbg << "KGantt::ConstraintModel[ " << static_cast<const QObject*>( &model ) << ": [\n";
205 const auto constraints = model.constraints();
206 for ( const Constraint& c : constraints ) {
207 dbg << "\t" << c << "\n";
208 }
209 dbg << "]\n";
210 return dbg;
211}
212
213#endif /* QT_NO_DEBUG_STREAM */
214
215#undef d
216
217#ifndef KDAB_NO_UNIT_TESTS
218
219#include <QStandardItemModel>
220
221#include "unittest/test.h"
222
223std::ostream& operator<<( std::ostream& os, const QModelIndex& idx )
224{
225 QString str;
226 QDebug( &str )<<idx;
227#ifdef QT_NO_STL
228 os<<str.toLatin1().constData();
229#else
230 os<<str.toStdString();
231#endif
232 return os;
233}
234
235KDAB_SCOPED_UNITTEST_SIMPLE( KGantt, ConstraintModel, "test" )
236{
237 QStandardItemModel dummyModel( 100, 100 );
238 ConstraintModel model;
239
240 QModelIndex invalidIndex;
241 assertEqual( invalidIndex, invalidIndex );
242
243 assertEqual( model.constraints().count(), 0 );
244
246 assertEqual( model.constraints().count(), 1 );
247
249 assertEqual( model.constraints().count(), 1 );
250
251 QPersistentModelIndex idx1 = dummyModel.index( 7, 17, QModelIndex() );
252 QPersistentModelIndex idx2 = dummyModel.index( 42, 17, QModelIndex() );
253
254 model.addConstraint( Constraint( idx1, idx2 ) );
255 assertEqual( model.constraints().count(), 2 );
256 assertTrue( model.hasConstraint( Constraint( idx1, idx2 ) ) );
257
258 assertEqual( model.constraintsForIndex( QModelIndex() ).count(), 1 );
259
260 assertEqual( model.constraints().count(), 2 );
262 assertEqual( model.constraints().count(), 1 );
263 assertFalse( model.hasConstraint( Constraint( QModelIndex(), QModelIndex() ) ) );
264
266 assertEqual( model.constraints().count(), 1 );
267
268 model.removeConstraint( Constraint( idx1, idx2 ) );
269 assertEqual( model.constraints().count(), 0 );
270 assertFalse( model.hasConstraint( Constraint( idx1, idx2 ) ) );
271
272 model.addConstraint( Constraint( idx1, idx2 ) );
273 assertTrue( model.hasConstraint( Constraint( idx1, idx2 ) ) );
274 dummyModel.removeRow( 8 );
275 assertTrue( model.hasConstraint( Constraint( idx1, idx2 ) ) );
276 dummyModel.removeRow( 7 );
277 assertTrue( model.hasConstraint( Constraint( idx1, idx2 ) ) );
278}
279
280#endif /* KDAB_NO_UNIT_TESTS */
281
282#include "moc_kganttconstraintmodel.cpp"
virtual void addConstraint(const Constraint &c)
QList< Constraint > constraintsForIndex(const QModelIndex &) const
QList< Constraint > constraints() const
ConstraintModel(QObject *parent=nullptr)
bool hasConstraint(const Constraint &c) const
virtual bool removeConstraint(const Constraint &c)
A class used to represent a dependency.
QModelIndex endIndex() const
RelationType relationType() const
QModelIndex startIndex() const
QMap< int, QVariant > dataMap() const
Global namespace.
QDebug operator<<(QDebug dbg, const PerceptualColor::LchaDouble &value)
const char * constData() const const
void push_back(const T &value)
bool isValid() const const
Q_EMITQ_EMIT
T qobject_cast(QObject *object)
QSet::iterator insert(const T &value)
QList< T > values() const const
QByteArray toLatin1() const const
std::string toStdString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sun Feb 25 2024 18:39:56 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.