KD Chart 2  [rev.2.7]
kdganttconstraintmodel.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 ** Copyright (C) 2001-2020 Klaralvdalens Datakonsult AB. All rights reserved.
3 **
4 ** This file is part of the KD Chart library.
5 **
6 ** Licensees holding valid commercial KD Chart licenses may use this file in
7 ** accordance with the KD Chart Commercial License Agreement provided with
8 ** the Software.
9 **
10 **
11 ** This file may be distributed and/or modified under the terms of the
12 ** GNU General Public License version 2 and version 3 as published by the
13 ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included.
14 **
15 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 **
18 ** Contact info@kdab.com if any conditions of this licensing are not
19 ** clear to you.
20 **
21 **********************************************************************/
22 
23 #include "kdganttconstraintmodel.h"
24 #include "kdganttconstraintmodel_p.h"
25 
26 #include <QDebug>
27 
28 #include <cassert>
29 #include <algorithm>
30 #include <functional>
31 
32 using namespace KDGantt;
33 
42 ConstraintModel::Private::Private()
43 {
44 }
45 
46 void ConstraintModel::Private::addConstraintToIndex( const QModelIndex& idx, const Constraint& c )
47 {
48  IndexType::iterator it = indexMap.find(idx);
49  while (it != indexMap.end() && it.key() == idx) {
50  // Check if we already have this
51  if ( *it == c ) return;
52  ++it;
53  }
54 
55  indexMap.insert( idx, c );
56 }
57 
58 void ConstraintModel::Private::removeConstraintFromIndex( const QModelIndex& idx, const Constraint& c )
59 {
60  IndexType::iterator it = indexMap.find(idx);
61  while (it != indexMap.end() && it.key() == idx) {
62  if ( c.compareIndexes(*it) ) {
63  it =indexMap.erase( it );
64  } else {
65  ++it;
66  }
67  }
68 }
69 
73  : QObject( parent ), _d( new Private )
74 {
75  init();
76 }
77 
79 ConstraintModel::ConstraintModel( Private* d_ptr, QObject* parent )
80  : QObject( parent ), _d( d_ptr )
81 {
82  init();
83 }
84 
87 {
88  delete _d;
89 }
90 
91 #define d d_func()
92 
93 void ConstraintModel::init()
94 {
95 }
96 
97 namespace {
98  struct compare_constraint_indexes_to : public std::unary_function<bool,Constraint> {
99  compare_constraint_indexes_to( const Constraint& c )
100  : m_c( c ) {
101  }
102  bool operator()( const Constraint& c ) const
103  {
104  return m_c.compareIndexes( c );
105  }
106 
107  const Constraint& m_c;
108  };
109 }
110 
116 {
117  //qDebug() << "ConstraintModel::addConstraint("<<c<<") (this="<<this<<") items=" << d->constraints.size();
118  QList<Constraint>::iterator it = std::find_if ( d->constraints.begin(),
119  d->constraints.end(),
120  compare_constraint_indexes_to(c) );
121 
122  if ( it == d->constraints.end() ) {
123  d->constraints.push_back( c );
124  d->addConstraintToIndex( c.startIndex(), c );
125  d->addConstraintToIndex( c.endIndex(), c );
126  emit constraintAdded( c );
127  } else if ( ( *it ).dataMap() != c.dataMap() ) {
128  Constraint tmp( *it ); // save to avoid re-entrancy issues
129  removeConstraint( tmp );
130  d->constraints.push_back( c );
131  d->addConstraintToIndex( c.startIndex(), c );
132  d->addConstraintToIndex( c.endIndex(), c );
133  emit constraintAdded( c );
134  }
135 }
136 
145 {
146  bool rc = false;
147 
148  for (int i = 0; i < d->constraints.count(); i++)
149  {
150  if (c.compareIndexes(d->constraints.at(i)))
151  {
152  d->constraints.removeAt(i);
153  rc = true;
154  }
155  }
156 
157  if ( rc ) {
158  d->removeConstraintFromIndex( c.startIndex(), c );
159  d->removeConstraintFromIndex( c.endIndex(), c );
160  emit constraintRemoved( c );
161  }
162 
163  return rc;
164 }
165 
171 {
173  Q_FOREACH( const Constraint& c, lst ) {
174  removeConstraint( c );
175  }
176 }
177 
180 {
181 #if 0
182  QSet<Constraint> orphans;
183  Q_FOREACH( const Constraint& c, d->constraints ) {
184  if ( !c.startIndex().isValid() || !c.endIndex().isValid() ) orphans.insert( c );
185  }
186  //qDebug() << "Constraint::cleanup() found" << orphans << "orphans";
187  d->constraints.subtract( orphans );
188 #endif
189 }
190 
195 {
196  //return d->constraints.toList();
197  return d->constraints;
198 }
199 
204 {
205  // TODO: @Steffen: Please comment on this assert, it's long and not obvious (Johannes)
206  assert( !idx.isValid() || d->indexMap.isEmpty() || !d->indexMap.keys().front().model() || idx.model() == d->indexMap.keys().front().model() );
207  if ( !idx.isValid() ) {
208  // Because of a Qt bug we need to treat this as a special case
209  QSet<Constraint> result;
210  Q_FOREACH( const Constraint& c, d->constraints ) {
211  if ( !c.startIndex().isValid() || !c.endIndex().isValid() ) result.insert( c );
212  }
213  return result.toList();
214  } else {
215  QList<Constraint> result;
216  Q_FOREACH( const Constraint& c, d->constraints ) {
217  if ( c.startIndex() == idx || c.endIndex() == idx ) result.push_back( c );
218  }
219  return result;
220  }
221 
222  //return d->indexMap.values( idx );
223 }
224 
229 {
230  /*
231  // Because of a Qt bug we have to search like this
232  Q_FOREACH( Constraint c2, d->constraints ) {
233  if ( c==c2 ) return true;
234  }
235  return false;
236  */
237  bool hc = false;
238 
239  for (int i = 0; i < d->constraints.count(); i++)
240  if (c.compareIndexes(d->constraints.at(i)))
241  hc = true;
242 
243  return hc;
244 }
245 
246 #ifndef QT_NO_DEBUG_STREAM
247 
248 QDebug operator<<( QDebug dbg, const KDGantt::ConstraintModel& model )
249 {
250  dbg << "KDGantt::ConstraintModel[ " << static_cast<const QObject*>( &model ) << ": [\n";
251  Q_FOREACH( const Constraint& c, model.constraints() ) {
252  dbg << "\t" << c << "\n";
253  }
254  dbg << "]\n";
255  return dbg;
256 }
257 
258 #endif /* QT_NO_DEBUG_STREAM */
259 
260 #undef d
261 
262 #ifndef KDAB_NO_UNIT_TESTS
263 
264 #include <QStandardItemModel>
265 
266 #include "unittest/test.h"
267 
268 std::ostream& operator<<( std::ostream& os, const QModelIndex& idx )
269 {
270  QString str;
271  QDebug( &str )<<idx;
272 #ifdef QT_NO_STL
273  os<<str.toLatin1().constData();
274 #else
275  os<<str.toStdString();
276 #endif
277  return os;
278 }
279 
281 {
282  QStandardItemModel dummyModel( 100, 100 );
283  ConstraintModel model;
284 
285  QModelIndex invalidIndex;
286  assertEqual( invalidIndex, invalidIndex );
287 
288  assertEqual( model.constraints().count(), 0 );
289 
290  model.addConstraint( Constraint( QModelIndex(), QModelIndex() ) );
291  assertEqual( model.constraints().count(), 1 );
292 
293  model.addConstraint( Constraint( QModelIndex(), QModelIndex() ) );
294  assertEqual( model.constraints().count(), 1 );
295 
296  QPersistentModelIndex idx1 = dummyModel.index( 7, 17, QModelIndex() );
297  QPersistentModelIndex idx2 = dummyModel.index( 42, 17, QModelIndex() );
298 
299  model.addConstraint( Constraint( idx1, idx2 ) );
300  assertEqual( model.constraints().count(), 2 );
301  assertTrue( model.hasConstraint( Constraint( idx1, idx2 ) ) );
302 
303  assertEqual( model.constraintsForIndex( QModelIndex() ).count(), 1 );
304 
305  assertEqual( model.constraints().count(), 2 );
306  model.removeConstraint( Constraint( QModelIndex(), QModelIndex() ) );
307  assertEqual( model.constraints().count(), 1 );
308  assertFalse( model.hasConstraint( Constraint( QModelIndex(), QModelIndex() ) ) );
309 
310  model.removeConstraint( Constraint( QModelIndex(), QModelIndex() ) );
311  assertEqual( model.constraints().count(), 1 );
312 
313  model.removeConstraint( Constraint( idx1, idx2 ) );
314  assertEqual( model.constraints().count(), 0 );
315  assertFalse( model.hasConstraint( Constraint( idx1, idx2 ) ) );
316 
317  model.addConstraint( Constraint( idx1, idx2 ) );
318  assertTrue( model.hasConstraint( Constraint( idx1, idx2 ) ) );
319  dummyModel.removeRow( 8 );
320  assertTrue( model.hasConstraint( Constraint( idx1, idx2 ) ) );
321  dummyModel.removeRow( 7 );
322  assertTrue( model.hasConstraint( Constraint( idx1, idx2 ) ) );
323 }
324 
325 #endif /* KDAB_NO_UNIT_TESTS */
326 
327 #include "moc_kdganttconstraintmodel.cpp"
bool hasConstraint(const Constraint &c) const
A class used to represent a dependency.
virtual bool removeConstraint(const Constraint &c)
virtual void addConstraint(const Constraint &c)
Subclassing ConstraintModel and overriding addConstraint() and removeConstraint() can provide re-entr...
void constraintAdded(const KDGantt::Constraint &)
QList< Constraint > constraintsForIndex(const QModelIndex &) const
KDAB_SCOPED_UNITTEST_SIMPLE(KDGantt, ConstraintModel,"test")
QDebug operator<<(QDebug dbg, const KDGantt::ConstraintModel &model)
QList< Constraint > constraints() const
QModelIndex endIndex() const
void constraintRemoved(const KDGantt::Constraint &)
Class only listed here to document inheritance of some KDChart classes.
#define d
#define assertFalse(x)
Definition: test.h:42
QMap< int, QVariant > dataMap() const
bool compareIndexes(const Constraint &other) const
QModelIndex startIndex() const
#define assertTrue(x)
Definition: test.h:41
#define assertEqual(x, y)
Definition: test.h:43

Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/

https://www.kdab.com/development-resources/qt-tools/kd-chart/