1 | /*************************************************************************** |
2 | * Copyright (C) 2005-2014 by the Quassel Project * |
3 | * devel@quassel-irc.org * |
4 | * * |
5 | * This program is free software; you can redistribute it and/or modify * |
6 | * it under the terms of the GNU General Public License as published by * |
7 | * the Free Software Foundation; either version 2 of the License, or * |
8 | * (at your option) version 3. * |
9 | * * |
10 | * This program is distributed in the hope that it will be useful, * |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
13 | * GNU General Public License for more details. * |
14 | * * |
15 | * You should have received a copy of the GNU General Public License * |
16 | * along with this program; if not, write to the * |
17 | * Free Software Foundation, Inc., * |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * |
19 | ***************************************************************************/ |
20 | |
21 | #include "treemodel.h" |
22 | |
23 | #include <QCoreApplication> |
24 | #include <QDebug> |
25 | |
26 | #include "quassel.h" |
27 | |
28 | class RemoveChildLaterEvent : public QEvent |
29 | { |
30 | public: |
31 | RemoveChildLaterEvent(AbstractTreeItem *child) : QEvent(QEvent::User), _child(child) {}; |
32 | inline AbstractTreeItem *child() { return _child; } |
33 | private: |
34 | AbstractTreeItem *_child; |
35 | }; |
36 | |
37 | |
38 | /***************************************** |
39 | * Abstract Items of a TreeModel |
40 | *****************************************/ |
41 | AbstractTreeItem::AbstractTreeItem(AbstractTreeItem *parent) |
42 | : QObject(parent), |
43 | _flags(Qt::ItemIsSelectable | Qt::ItemIsEnabled), |
44 | _treeItemFlags(0) |
45 | { |
46 | } |
47 | |
48 | |
49 | bool AbstractTreeItem::newChild(AbstractTreeItem *item) |
50 | { |
51 | int newRow = childCount(); |
52 | emit beginAppendChilds(newRow, newRow); |
53 | _childItems.append(item); |
54 | emit endAppendChilds(); |
55 | return true; |
56 | } |
57 | |
58 | |
59 | bool AbstractTreeItem::newChilds(const QList<AbstractTreeItem *> &items) |
60 | { |
61 | if (items.isEmpty()) |
62 | return false; |
63 | |
64 | int nextRow = childCount(); |
65 | int lastRow = nextRow + items.count() - 1; |
66 | |
67 | emit beginAppendChilds(nextRow, lastRow); |
68 | _childItems << items; |
69 | emit endAppendChilds(); |
70 | |
71 | return true; |
72 | } |
73 | |
74 | |
75 | bool AbstractTreeItem::removeChild(int row) |
76 | { |
77 | if (row < 0 || childCount() <= row) |
78 | return false; |
79 | |
80 | child(row)->removeAllChilds(); |
81 | emit beginRemoveChilds(row, row); |
82 | AbstractTreeItem *treeitem = _childItems.takeAt(row); |
83 | delete treeitem; |
84 | emit endRemoveChilds(); |
85 | |
86 | checkForDeletion(); |
87 | |
88 | return true; |
89 | } |
90 | |
91 | |
92 | void AbstractTreeItem::removeAllChilds() |
93 | { |
94 | const int numChilds = childCount(); |
95 | |
96 | if (numChilds == 0) |
97 | return; |
98 | |
99 | AbstractTreeItem *child; |
100 | |
101 | QList<AbstractTreeItem *>::iterator childIter; |
102 | |
103 | childIter = _childItems.begin(); |
104 | while (childIter != _childItems.end()) { |
105 | child = *childIter; |
106 | child->setTreeItemFlags(0); // disable self deletion, as this would only fuck up consitency and the child gets deleted anyways |
107 | child->removeAllChilds(); |
108 | childIter++; |
109 | } |
110 | |
111 | emit beginRemoveChilds(0, numChilds - 1); |
112 | childIter = _childItems.begin(); |
113 | while (childIter != _childItems.end()) { |
114 | child = *childIter; |
115 | childIter = _childItems.erase(childIter); |
116 | delete child; |
117 | } |
118 | emit endRemoveChilds(); |
119 | |
120 | checkForDeletion(); |
121 | } |
122 | |
123 | |
124 | void AbstractTreeItem::removeChildLater(AbstractTreeItem *child) |
125 | { |
126 | Q_ASSERT(child); |
127 | QCoreApplication::postEvent(this, new RemoveChildLaterEvent(child)); |
128 | } |
129 | |
130 | |
131 | void AbstractTreeItem::customEvent(QEvent *event) |
132 | { |
133 | if (event->type() != QEvent::User) |
134 | return; |
135 | |
136 | event->accept(); |
137 | |
138 | RemoveChildLaterEvent *removeEvent = static_cast<RemoveChildLaterEvent *>(event); |
139 | int childRow = _childItems.indexOf(removeEvent->child()); |
140 | if (childRow == -1) |
141 | return; |
142 | |
143 | // since we are called asynchronously we have to recheck if the item in question still has no childs |
144 | if (removeEvent->child()->childCount()) |
145 | return; |
146 | |
147 | removeChild(childRow); |
148 | } |
149 | |
150 | |
151 | bool AbstractTreeItem::reParent(AbstractTreeItem *newParent) |
152 | { |
153 | // currently we support only re parenting if the child that's about to be |
154 | // adopted does not have any children itself. |
155 | if (childCount() != 0) { |
156 | qDebug() << "AbstractTreeItem::reParent(): cannot reparent" << this << "with children." ; |
157 | return false; |
158 | } |
159 | |
160 | int oldRow = row(); |
161 | if (oldRow == -1) |
162 | return false; |
163 | |
164 | emit parent()->beginRemoveChilds(oldRow, oldRow); |
165 | parent()->_childItems.removeAt(oldRow); |
166 | emit parent()->endRemoveChilds(); |
167 | |
168 | AbstractTreeItem *oldParent = parent(); |
169 | setParent(newParent); |
170 | |
171 | bool success = newParent->newChild(this); |
172 | if (!success) |
173 | qWarning() << "AbstractTreeItem::reParent(): failed to attach to new parent after removing from old parent! this:" << this << "new parent:" << newParent; |
174 | |
175 | if (oldParent) |
176 | oldParent->checkForDeletion(); |
177 | |
178 | return success; |
179 | } |
180 | |
181 | |
182 | AbstractTreeItem *AbstractTreeItem::child(int row) const |
183 | { |
184 | if (childCount() <= row) |
185 | return 0; |
186 | else |
187 | return _childItems[row]; |
188 | } |
189 | |
190 | |
191 | int AbstractTreeItem::childCount(int column) const |
192 | { |
193 | if (column > 0) |
194 | return 0; |
195 | else |
196 | return _childItems.count(); |
197 | } |
198 | |
199 | |
200 | int AbstractTreeItem::row() const |
201 | { |
202 | if (!parent()) { |
203 | qWarning() << "AbstractTreeItem::row():" << this << "has no parent AbstractTreeItem as it's parent! parent is" << QObject::parent(); |
204 | return -1; |
205 | } |
206 | |
207 | int row_ = parent()->_childItems.indexOf(const_cast<AbstractTreeItem *>(this)); |
208 | if (row_ == -1) |
209 | qWarning() << "AbstractTreeItem::row():" << this << "is not in the child list of" << QObject::parent(); |
210 | return row_; |
211 | } |
212 | |
213 | |
214 | void AbstractTreeItem::dumpChildList() |
215 | { |
216 | qDebug() << "==== Childlist for Item:" << this << "====" ; |
217 | if (childCount() > 0) { |
218 | AbstractTreeItem *child; |
219 | QList<AbstractTreeItem *>::const_iterator childIter = _childItems.constBegin(); |
220 | while (childIter != _childItems.constEnd()) { |
221 | child = *childIter; |
222 | qDebug() << "Row:" << child->row() << child << child->data(0, Qt::DisplayRole); |
223 | childIter++; |
224 | } |
225 | } |
226 | qDebug() << "==== End Of Childlist ====" ; |
227 | } |
228 | |
229 | |
230 | /***************************************** |
231 | * SimpleTreeItem |
232 | *****************************************/ |
233 | SimpleTreeItem::SimpleTreeItem(const QList<QVariant> &data, AbstractTreeItem *parent) |
234 | : AbstractTreeItem(parent), |
235 | _itemData(data) |
236 | { |
237 | } |
238 | |
239 | |
240 | SimpleTreeItem::~SimpleTreeItem() |
241 | { |
242 | } |
243 | |
244 | |
245 | QVariant SimpleTreeItem::data(int column, int role) const |
246 | { |
247 | if (column >= columnCount() || role != Qt::DisplayRole) |
248 | return QVariant(); |
249 | else |
250 | return _itemData[column]; |
251 | } |
252 | |
253 | |
254 | bool SimpleTreeItem::setData(int column, const QVariant &value, int role) |
255 | { |
256 | if (column > columnCount() || role != Qt::DisplayRole) |
257 | return false; |
258 | |
259 | if (column == columnCount()) |
260 | _itemData.append(value); |
261 | else |
262 | _itemData[column] = value; |
263 | |
264 | emit dataChanged(column); |
265 | return true; |
266 | } |
267 | |
268 | |
269 | int SimpleTreeItem::columnCount() const |
270 | { |
271 | return _itemData.count(); |
272 | } |
273 | |
274 | |
275 | /***************************************** |
276 | * PropertyMapItem |
277 | *****************************************/ |
278 | PropertyMapItem::PropertyMapItem(const QStringList &propertyOrder, AbstractTreeItem *parent) |
279 | : AbstractTreeItem(parent), |
280 | _propertyOrder(propertyOrder) |
281 | { |
282 | } |
283 | |
284 | |
285 | PropertyMapItem::PropertyMapItem(AbstractTreeItem *parent) |
286 | : AbstractTreeItem(parent), |
287 | _propertyOrder(QStringList()) |
288 | { |
289 | } |
290 | |
291 | |
292 | PropertyMapItem::~PropertyMapItem() |
293 | { |
294 | } |
295 | |
296 | |
297 | QVariant PropertyMapItem::data(int column, int role) const |
298 | { |
299 | if (column >= columnCount()) |
300 | return QVariant(); |
301 | |
302 | switch (role) { |
303 | case Qt::ToolTipRole: |
304 | return toolTip(column); |
305 | case Qt::DisplayRole: |
306 | case TreeModel::SortRole: // fallthrough, since SortRole should default to DisplayRole |
307 | return property(_propertyOrder[column].toLatin1()); |
308 | default: |
309 | return QVariant(); |
310 | } |
311 | } |
312 | |
313 | |
314 | bool PropertyMapItem::setData(int column, const QVariant &value, int role) |
315 | { |
316 | if (column >= columnCount() || role != Qt::DisplayRole) |
317 | return false; |
318 | |
319 | emit dataChanged(column); |
320 | return setProperty(_propertyOrder[column].toLatin1(), value); |
321 | } |
322 | |
323 | |
324 | int PropertyMapItem::columnCount() const |
325 | { |
326 | return _propertyOrder.count(); |
327 | } |
328 | |
329 | |
330 | void PropertyMapItem::appendProperty(const QString &property) |
331 | { |
332 | _propertyOrder << property; |
333 | } |
334 | |
335 | |
336 | /***************************************** |
337 | * TreeModel |
338 | *****************************************/ |
339 | TreeModel::TreeModel(const QList<QVariant> &data, QObject *parent) |
340 | : QAbstractItemModel(parent), |
341 | _childStatus(QModelIndex(), 0, 0, 0), |
342 | _aboutToRemoveOrInsert(false) |
343 | { |
344 | rootItem = new SimpleTreeItem(data, 0); |
345 | connectItem(rootItem); |
346 | |
347 | if (Quassel::isOptionSet("debugmodel" )) { |
348 | connect(this, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), |
349 | this, SLOT(debug_rowsAboutToBeInserted(const QModelIndex &, int, int))); |
350 | connect(this, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), |
351 | this, SLOT(debug_rowsAboutToBeRemoved(const QModelIndex &, int, int))); |
352 | connect(this, SIGNAL(rowsInserted(const QModelIndex &, int, int)), |
353 | this, SLOT(debug_rowsInserted(const QModelIndex &, int, int))); |
354 | connect(this, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), |
355 | this, SLOT(debug_rowsRemoved(const QModelIndex &, int, int))); |
356 | connect(this, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), |
357 | this, SLOT(debug_dataChanged(const QModelIndex &, const QModelIndex &))); |
358 | } |
359 | } |
360 | |
361 | |
362 | TreeModel::~TreeModel() |
363 | { |
364 | delete rootItem; |
365 | } |
366 | |
367 | |
368 | QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const |
369 | { |
370 | if (row < 0 || row >= rowCount(parent) || column < 0 || column >= columnCount(parent)) |
371 | return QModelIndex(); |
372 | |
373 | AbstractTreeItem *parentItem; |
374 | |
375 | if (!parent.isValid()) |
376 | parentItem = rootItem; |
377 | else |
378 | parentItem = static_cast<AbstractTreeItem *>(parent.internalPointer()); |
379 | |
380 | AbstractTreeItem *childItem = parentItem->child(row); |
381 | |
382 | if (childItem) |
383 | return createIndex(row, column, childItem); |
384 | else |
385 | return QModelIndex(); |
386 | } |
387 | |
388 | |
389 | QModelIndex TreeModel::indexByItem(AbstractTreeItem *item) const |
390 | { |
391 | if (item == 0) { |
392 | qWarning() << "TreeModel::indexByItem(AbstractTreeItem *item) received NULL-Pointer" ; |
393 | return QModelIndex(); |
394 | } |
395 | |
396 | if (item == rootItem) |
397 | return QModelIndex(); |
398 | else |
399 | return createIndex(item->row(), 0, item); |
400 | } |
401 | |
402 | |
403 | QModelIndex TreeModel::parent(const QModelIndex &index) const |
404 | { |
405 | if (!index.isValid()) { |
406 | // ModelTest does this |
407 | // qWarning() << "TreeModel::parent(): has been asked for the rootItems Parent!"; |
408 | return QModelIndex(); |
409 | } |
410 | |
411 | AbstractTreeItem *childItem = static_cast<AbstractTreeItem *>(index.internalPointer()); |
412 | AbstractTreeItem *parentItem = childItem->parent(); |
413 | |
414 | Q_ASSERT(parentItem); |
415 | if (parentItem == rootItem) |
416 | return QModelIndex(); |
417 | |
418 | return createIndex(parentItem->row(), 0, parentItem); |
419 | } |
420 | |
421 | |
422 | int TreeModel::rowCount(const QModelIndex &parent) const |
423 | { |
424 | AbstractTreeItem *parentItem; |
425 | if (!parent.isValid()) |
426 | parentItem = rootItem; |
427 | else |
428 | parentItem = static_cast<AbstractTreeItem *>(parent.internalPointer()); |
429 | |
430 | return parentItem->childCount(parent.column()); |
431 | } |
432 | |
433 | |
434 | int TreeModel::columnCount(const QModelIndex &parent) const |
435 | { |
436 | Q_UNUSED(parent) |
437 | return rootItem->columnCount(); |
438 | // since there the Qt Views don't draw more columns than the header has columns |
439 | // we can be lazy and simply return the count of header columns |
440 | // actually this gives us more freedom cause we don't have to ensure that a rows parent |
441 | // has equal or more columns than that row |
442 | |
443 | // AbstractTreeItem *parentItem; |
444 | // if(!parent.isValid()) |
445 | // parentItem = rootItem; |
446 | // else |
447 | // parentItem = static_cast<AbstractTreeItem*>(parent.internalPointer()); |
448 | // return parentItem->columnCount(); |
449 | } |
450 | |
451 | |
452 | QVariant TreeModel::data(const QModelIndex &index, int role) const |
453 | { |
454 | if (!index.isValid()) |
455 | return QVariant(); |
456 | |
457 | AbstractTreeItem *item = static_cast<AbstractTreeItem *>(index.internalPointer()); |
458 | return item->data(index.column(), role); |
459 | } |
460 | |
461 | |
462 | bool TreeModel::setData(const QModelIndex &index, const QVariant &value, int role) |
463 | { |
464 | if (!index.isValid()) |
465 | return false; |
466 | |
467 | AbstractTreeItem *item = static_cast<AbstractTreeItem *>(index.internalPointer()); |
468 | return item->setData(index.column(), value, role); |
469 | } |
470 | |
471 | |
472 | Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const |
473 | { |
474 | if (!index.isValid()) { |
475 | return rootItem->flags() & Qt::ItemIsDropEnabled; |
476 | } |
477 | else { |
478 | AbstractTreeItem *item = static_cast<AbstractTreeItem *>(index.internalPointer()); |
479 | return item->flags(); |
480 | } |
481 | } |
482 | |
483 | |
484 | QVariant TreeModel::(int section, Qt::Orientation orientation, int role) const |
485 | { |
486 | if (orientation == Qt::Horizontal && role == Qt::DisplayRole) |
487 | return rootItem->data(section, role); |
488 | else |
489 | return QVariant(); |
490 | } |
491 | |
492 | |
493 | void TreeModel::itemDataChanged(int column) |
494 | { |
495 | AbstractTreeItem *item = qobject_cast<AbstractTreeItem *>(sender()); |
496 | QModelIndex leftIndex, rightIndex; |
497 | |
498 | if (item == rootItem) |
499 | return; |
500 | |
501 | if (column == -1) { |
502 | leftIndex = createIndex(item->row(), 0, item); |
503 | rightIndex = createIndex(item->row(), item->columnCount() - 1, item); |
504 | } |
505 | else { |
506 | leftIndex = createIndex(item->row(), column, item); |
507 | rightIndex = leftIndex; |
508 | } |
509 | |
510 | emit dataChanged(leftIndex, rightIndex); |
511 | } |
512 | |
513 | |
514 | void TreeModel::connectItem(AbstractTreeItem *item) |
515 | { |
516 | connect(item, SIGNAL(dataChanged(int)), |
517 | this, SLOT(itemDataChanged(int))); |
518 | |
519 | connect(item, SIGNAL(beginAppendChilds(int, int)), |
520 | this, SLOT(beginAppendChilds(int, int))); |
521 | connect(item, SIGNAL(endAppendChilds()), |
522 | this, SLOT(endAppendChilds())); |
523 | |
524 | connect(item, SIGNAL(beginRemoveChilds(int, int)), |
525 | this, SLOT(beginRemoveChilds(int, int))); |
526 | connect(item, SIGNAL(endRemoveChilds()), |
527 | this, SLOT(endRemoveChilds())); |
528 | } |
529 | |
530 | |
531 | void TreeModel::beginAppendChilds(int firstRow, int lastRow) |
532 | { |
533 | AbstractTreeItem *parentItem = qobject_cast<AbstractTreeItem *>(sender()); |
534 | if (!parentItem) { |
535 | qWarning() << "TreeModel::beginAppendChilds(): cannot append Children to unknown parent" ; |
536 | return; |
537 | } |
538 | |
539 | QModelIndex parent = indexByItem(parentItem); |
540 | Q_ASSERT(!_aboutToRemoveOrInsert); |
541 | |
542 | _aboutToRemoveOrInsert = true; |
543 | _childStatus = ChildStatus(parent, rowCount(parent), firstRow, lastRow); |
544 | beginInsertRows(parent, firstRow, lastRow); |
545 | } |
546 | |
547 | |
548 | void TreeModel::endAppendChilds() |
549 | { |
550 | AbstractTreeItem *parentItem = qobject_cast<AbstractTreeItem *>(sender()); |
551 | if (!parentItem) { |
552 | qWarning() << "TreeModel::endAppendChilds(): cannot append Children to unknown parent" ; |
553 | return; |
554 | } |
555 | Q_ASSERT(_aboutToRemoveOrInsert); |
556 | ChildStatus cs = _childStatus; |
557 | #ifndef QT_NO_DEBUG |
558 | QModelIndex parent = indexByItem(parentItem); |
559 | #endif |
560 | Q_ASSERT(cs.parent == parent); |
561 | Q_ASSERT(rowCount(parent) == cs.childCount + cs.end - cs.start + 1); |
562 | |
563 | _aboutToRemoveOrInsert = false; |
564 | for (int i = cs.start; i <= cs.end; i++) { |
565 | connectItem(parentItem->child(i)); |
566 | } |
567 | endInsertRows(); |
568 | } |
569 | |
570 | |
571 | void TreeModel::beginRemoveChilds(int firstRow, int lastRow) |
572 | { |
573 | AbstractTreeItem *parentItem = qobject_cast<AbstractTreeItem *>(sender()); |
574 | if (!parentItem) { |
575 | qWarning() << "TreeModel::beginRemoveChilds(): cannot append Children to unknown parent" ; |
576 | return; |
577 | } |
578 | |
579 | for (int i = firstRow; i <= lastRow; i++) { |
580 | disconnect(parentItem->child(i), 0, this, 0); |
581 | } |
582 | |
583 | // consitency checks |
584 | QModelIndex parent = indexByItem(parentItem); |
585 | Q_ASSERT(firstRow <= lastRow); |
586 | Q_ASSERT(parentItem->childCount() > lastRow); |
587 | Q_ASSERT(!_aboutToRemoveOrInsert); |
588 | _aboutToRemoveOrInsert = true; |
589 | _childStatus = ChildStatus(parent, rowCount(parent), firstRow, lastRow); |
590 | |
591 | beginRemoveRows(parent, firstRow, lastRow); |
592 | } |
593 | |
594 | |
595 | void TreeModel::endRemoveChilds() |
596 | { |
597 | AbstractTreeItem *parentItem = qobject_cast<AbstractTreeItem *>(sender()); |
598 | if (!parentItem) { |
599 | qWarning() << "TreeModel::endRemoveChilds(): cannot remove Children from unknown parent" ; |
600 | return; |
601 | } |
602 | |
603 | // concistency checks |
604 | Q_ASSERT(_aboutToRemoveOrInsert); |
605 | #ifndef QT_NO_DEBUG |
606 | ChildStatus cs = _childStatus; |
607 | QModelIndex parent = indexByItem(parentItem); |
608 | #endif |
609 | Q_ASSERT(cs.parent == parent); |
610 | Q_ASSERT(rowCount(parent) == cs.childCount - cs.end + cs.start - 1); |
611 | _aboutToRemoveOrInsert = false; |
612 | |
613 | endRemoveRows(); |
614 | } |
615 | |
616 | |
617 | void TreeModel::clear() |
618 | { |
619 | rootItem->removeAllChilds(); |
620 | } |
621 | |
622 | |
623 | void TreeModel::debug_rowsAboutToBeInserted(const QModelIndex &parent, int start, int end) |
624 | { |
625 | qDebug() << "debug_rowsAboutToBeInserted" << parent << parent.internalPointer() << parent.data().toString() << rowCount(parent) << start << end; |
626 | } |
627 | |
628 | |
629 | void TreeModel::debug_rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) |
630 | { |
631 | AbstractTreeItem *parentItem; |
632 | parentItem = static_cast<AbstractTreeItem *>(parent.internalPointer()); |
633 | if (!parentItem) |
634 | parentItem = rootItem; |
635 | qDebug() << "debug_rowsAboutToBeRemoved" << parent << parentItem << parent.data().toString() << rowCount(parent) << start << end; |
636 | |
637 | QModelIndex child; |
638 | for (int i = end; i >= start; i--) { |
639 | child = parent.child(i, 0); |
640 | Q_ASSERT(parentItem->child(i)); |
641 | qDebug() << ">>>" << i << child << child.data().toString(); |
642 | } |
643 | } |
644 | |
645 | |
646 | void TreeModel::debug_rowsInserted(const QModelIndex &parent, int start, int end) |
647 | { |
648 | AbstractTreeItem *parentItem; |
649 | parentItem = static_cast<AbstractTreeItem *>(parent.internalPointer()); |
650 | if (!parentItem) |
651 | parentItem = rootItem; |
652 | qDebug() << "debug_rowsInserted:" << parent << parentItem << parent.data().toString() << rowCount(parent) << start << end; |
653 | |
654 | QModelIndex child; |
655 | for (int i = start; i <= end; i++) { |
656 | child = parent.child(i, 0); |
657 | Q_ASSERT(parentItem->child(i)); |
658 | qDebug() << "<<<" << i << child << child.data().toString(); |
659 | } |
660 | } |
661 | |
662 | |
663 | void TreeModel::debug_rowsRemoved(const QModelIndex &parent, int start, int end) |
664 | { |
665 | qDebug() << "debug_rowsRemoved" << parent << parent.internalPointer() << parent.data().toString() << rowCount(parent) << start << end; |
666 | } |
667 | |
668 | |
669 | void TreeModel::debug_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) |
670 | { |
671 | qDebug() << "debug_dataChanged" << topLeft << bottomRight; |
672 | QStringList displayData; |
673 | for (int row = topLeft.row(); row <= bottomRight.row(); row++) { |
674 | displayData = QStringList(); |
675 | for (int column = topLeft.column(); column <= bottomRight.column(); column++) { |
676 | displayData << data(topLeft.sibling(row, column), Qt::DisplayRole).toString(); |
677 | } |
678 | qDebug() << " row:" << row << displayData; |
679 | } |
680 | } |
681 | |