KD Chart API Documentation  3.1
kdganttconstraintmodel.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** This file is part of the KD Chart library.
4 **
5 ** SPDX-FileCopyrightText: 2001 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
6 **
7 ** SPDX-License-Identifier: MIT
8 **
9 ****************************************************************************/
10 
11 #include "kdganttconstraintmodel.h"
12 #include "kdganttconstraintmodel_p.h"
13 
14 #include <QDebug>
15 
16 #include <algorithm>
17 #include <cassert>
18 #include <functional>
19 
20 using namespace KDGantt;
21 
30 ConstraintModel::Private::Private()
31 {
32 }
33 
34 void ConstraintModel::Private::addConstraintToIndex(const QModelIndex &idx, const Constraint &c)
35 {
36  IndexType::iterator it = indexMap.find(idx);
37  while (it != indexMap.end() && it.key() == idx) {
38  // Check if we already have this
39  if (*it == c)
40  return;
41  ++it;
42  }
43 
44  indexMap.insert(idx, c);
45 }
46 
47 void ConstraintModel::Private::removeConstraintFromIndex(const QModelIndex &idx, const Constraint &c)
48 {
49  IndexType::iterator it = indexMap.find(idx);
50  while (it != indexMap.end() && it.key() == idx) {
51  if (c.compareIndexes(*it)) {
52  it = indexMap.erase(it);
53  } else {
54  ++it;
55  }
56  }
57 }
58 
62  : QObject(parent)
63  , _d(new Private)
64 {
65  init();
66 }
67 
69 ConstraintModel::ConstraintModel(Private *d_ptr, QObject *parent)
70  : QObject(parent)
71  , _d(d_ptr)
72 {
73  init();
74 }
75 
78 {
79  delete _d;
80 }
81 
82 #define d d_func()
83 
84 void ConstraintModel::init()
85 {
86 }
87 
88 namespace {
89 struct compare_constraint_indexes_to
90 {
91  compare_constraint_indexes_to(const Constraint &c)
92  : m_c(c)
93  {
94  }
95  bool operator()(const Constraint &c) const
96  {
97  return m_c.compareIndexes(c);
98  }
99 
100  const Constraint &m_c;
101 };
102 }
103 
109 {
110  // qDebug() << "ConstraintModel::addConstraint("<<c<<") (this="<<this<<") items=" << d->constraints.size();
111  QList<Constraint>::iterator it = std::find_if(d->constraints.begin(),
112  d->constraints.end(),
113  compare_constraint_indexes_to(c));
114 
115  if (it == d->constraints.end()) {
116  d->constraints.push_back(c);
117  d->addConstraintToIndex(c.startIndex(), c);
118  d->addConstraintToIndex(c.endIndex(), c);
119  Q_EMIT constraintAdded(c);
120  } else if ((*it).dataMap() != c.dataMap()) {
121  Constraint tmp(*it); // save to avoid re-entrancy issues
122  removeConstraint(tmp);
123  d->constraints.push_back(c);
124  d->addConstraintToIndex(c.startIndex(), c);
125  d->addConstraintToIndex(c.endIndex(), c);
126  Q_EMIT constraintAdded(c);
127  }
128 }
129 
138 {
139  bool rc = false;
140 
141  for (int i = 0; i < d->constraints.count(); i++) {
142  if (c.compareIndexes(d->constraints.at(i))) {
143  d->constraints.removeAt(i);
144  rc = true;
145  }
146  }
147 
148  if (rc) {
149  d->removeConstraintFromIndex(c.startIndex(), c);
150  d->removeConstraintFromIndex(c.endIndex(), c);
151  Q_EMIT constraintRemoved(c);
152  }
153 
154  return rc;
155 }
156 
162 {
163  const QList<Constraint> lst = constraints();
164  for (const Constraint &c : lst) {
165  removeConstraint(c);
166  }
167 }
168 
171 {
172 #if 0
173  QSet<Constraint> orphans;
174  for (const Constraint& c, qAsConst(d->constraints)) {
175  if ( !c.startIndex().isValid() || !c.endIndex().isValid() ) orphans.insert( c );
176  }
177  //qDebug() << "Constraint::cleanup() found" << orphans << "orphans";
178  d->constraints.subtract( orphans );
179 #endif
180 }
181 
185 QList<Constraint> ConstraintModel::constraints() const
186 {
187  // return d->constraints.toList();
188  return d->constraints;
189 }
190 
194 QList<Constraint> ConstraintModel::constraintsForIndex(const QModelIndex &idx) const
195 {
196  // TODO: @Steffen: Please comment on this assert, it's long and not obvious (Johannes)
197  assert(!idx.isValid() || d->indexMap.isEmpty() || !d->indexMap.keys().front().model() || idx.model() == d->indexMap.keys().front().model());
198  if (!idx.isValid()) {
199  // Because of a Qt bug we need to treat this as a special case
200  QSet<Constraint> result;
201  for (const Constraint &c : d->constraints) {
202  if (!c.startIndex().isValid() || !c.endIndex().isValid())
203  result.insert(c);
204  }
205  return result.values();
206  } else {
207  QList<Constraint> result;
208  for (const Constraint &c : d->constraints) {
209  if (c.startIndex() == idx || c.endIndex() == idx)
210  result.push_back(c);
211  }
212  return result;
213  }
214 
215  // return d->indexMap.values( idx );
216 }
217 
222 {
223  /*
224  // Because of a Qt bug we have to search like this
225  const auto constraints = model.constraints();
226  for ( Constraint c2 : constraints ) {
227  if ( c==c2 ) return true;
228  }
229  return false;
230  */
231  bool hc = false;
232 
233  for (int i = 0; i < d->constraints.count(); i++)
234  if (c.compareIndexes(d->constraints.at(i)))
235  hc = true;
236 
237  return hc;
238 }
239 
240 #ifndef QT_NO_DEBUG_STREAM
241 
242 QDebug operator<<(QDebug dbg, const KDGantt::ConstraintModel &model)
243 {
244  dbg << "KDGantt::ConstraintModel[ " << static_cast<const QObject *>(&model) << ": [\n";
245  const auto constraints = model.constraints();
246  for (const Constraint &c : constraints) {
247  dbg << "\t" << c << "\n";
248  }
249  dbg << "]\n";
250  return dbg;
251 }
252 
253 #endif /* QT_NO_DEBUG_STREAM */
254 
255 #undef d
256 
257 #ifndef KDAB_NO_UNIT_TESTS
258 
259 #include <QStandardItemModel>
260 
261 #include "unittest/test.h"
262 
263 std::ostream &operator<<(std::ostream &os, const QModelIndex &idx)
264 {
265  QString str;
266  QDebug(&str) << idx;
267 #ifdef QT_NO_STL
268  os << str.toLatin1().constData();
269 #else
270  os << str.toStdString();
271 #endif
272  return os;
273 }
274 
276 {
277  QStandardItemModel dummyModel(100, 100);
278  ConstraintModel model;
279 
280  QModelIndex invalidIndex;
281  assertEqual(invalidIndex, invalidIndex);
282 
283  assertEqual(model.constraints().count(), 0);
284 
285  model.addConstraint(Constraint(QModelIndex(), QModelIndex()));
286  assertEqual(model.constraints().count(), 1);
287 
288  model.addConstraint(Constraint(QModelIndex(), QModelIndex()));
289  assertEqual(model.constraints().count(), 1);
290 
291  QPersistentModelIndex idx1 = dummyModel.index(7, 17, QModelIndex());
292  QPersistentModelIndex idx2 = dummyModel.index(42, 17, QModelIndex());
293 
294  model.addConstraint(Constraint(idx1, idx2));
295  assertEqual(model.constraints().count(), 2);
296  assertTrue(model.hasConstraint(Constraint(idx1, idx2)));
297 
298  assertEqual(model.constraintsForIndex(QModelIndex()).count(), 1);
299 
300  assertEqual(model.constraints().count(), 2);
301  model.removeConstraint(Constraint(QModelIndex(), QModelIndex()));
302  assertEqual(model.constraints().count(), 1);
303  assertFalse(model.hasConstraint(Constraint(QModelIndex(), QModelIndex())));
304 
305  model.removeConstraint(Constraint(QModelIndex(), QModelIndex()));
306  assertEqual(model.constraints().count(), 1);
307 
308  model.removeConstraint(Constraint(idx1, idx2));
309  assertEqual(model.constraints().count(), 0);
310  assertFalse(model.hasConstraint(Constraint(idx1, idx2)));
311 
312  model.addConstraint(Constraint(idx1, idx2));
313  assertTrue(model.hasConstraint(Constraint(idx1, idx2)));
314  dummyModel.removeRow(8);
315  assertTrue(model.hasConstraint(Constraint(idx1, idx2)));
316  dummyModel.removeRow(7);
317  assertTrue(model.hasConstraint(Constraint(idx1, idx2)));
318 }
319 
320 #endif /* KDAB_NO_UNIT_TESTS */
321 
322 #include "moc_kdganttconstraintmodel.cpp"
The ConstraintModel keeps track of the interdependencies between gantt items in a View.
virtual void addConstraint(const Constraint &c)
Adds the constraint c to this ConstraintModel If the Constraint c is already in this ConstraintModel,...
void clear()
Removes all Constraints from this model The signal constraintRemoved(const Constraint&) is emitted fo...
~ConstraintModel() override
Destroys this ConstraintModel.
QList< Constraint > constraintsForIndex(const QModelIndex &) const
QList< Constraint > constraints() const
ConstraintModel(QObject *parent=nullptr)
Constructor.
bool hasConstraint(const Constraint &c) const
Returns true if a Constraint with start s and end e exists, otherwise false.
void constraintRemoved(const KDGantt::Constraint &)
virtual bool removeConstraint(const Constraint &c)
Removes the Constraint c from this ConstraintModel.
void constraintAdded(const KDGantt::Constraint &)
A class used to represent a dependency.
QModelIndex endIndex() const
bool compareIndexes(const Constraint &other) const
QModelIndex startIndex() const
QMap< int, QVariant > dataMap() const
#define d
QDebug operator<<(QDebug dbg, const KDGantt::ConstraintModel &model)
KDAB_SCOPED_UNITTEST_SIMPLE(KDGantt, ConstraintModel, "test")

© 2001 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/
Generated by doxygen 1.9.1