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

KDE's Doxygen guidelines are available online.