1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtWidgets module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <private/qtreewidgetitemiterator_p.h>
41#include "qtreewidget.h"
42#include "qtreewidget_p.h"
43#include "qwidgetitemdata_p.h"
44
45QT_BEGIN_NAMESPACE
46
47/*!
48 \class QTreeWidgetItemIterator
49 \ingroup model-view
50 \inmodule QtWidgets
51
52 \brief The QTreeWidgetItemIterator class provides a way to iterate over the
53 items in a QTreeWidget instance.
54
55 The iterator will walk the items in a pre-order traversal order, thus visiting the
56 parent node \e before it continues to the child nodes.
57
58 For example, the following code examples each item in a tree, checking the
59 text in the first column against a user-specified search string:
60
61 \snippet qtreewidgetitemiterator-using/mainwindow.cpp 0
62
63 It is also possible to filter out certain types of node by passing certain
64 \l{IteratorFlag}{flags} to the constructor of QTreeWidgetItemIterator.
65
66 \sa QTreeWidget, {Model/View Programming}, QTreeWidgetItem
67*/
68
69/*!
70 Constructs an iterator for the same QTreeWidget as \a it. The
71 current iterator item is set to point on the current item of \a it.
72*/
73
74QTreeWidgetItemIterator::QTreeWidgetItemIterator(const QTreeWidgetItemIterator &it)
75 : d_ptr(new QTreeWidgetItemIteratorPrivate(*(it.d_ptr))),
76 current(it.current), flags(it.flags)
77{
78 Q_D(QTreeWidgetItemIterator);
79 Q_ASSERT(d->m_model);
80 d->m_model->iterators.append(this);
81}
82
83/*!
84 Constructs an iterator for the given \a widget that uses the specified \a flags
85 to determine which items are found during iteration.
86 The iterator is set to point to the first top-level item contained in the widget,
87 or the next matching item if the top-level item doesn't match the flags.
88
89 \sa QTreeWidgetItemIterator::IteratorFlag
90*/
91
92QTreeWidgetItemIterator::QTreeWidgetItemIterator(QTreeWidget *widget, IteratorFlags flags)
93: current(nullptr), flags(flags)
94{
95 Q_ASSERT(widget);
96 QTreeModel *model = qobject_cast<QTreeModel*>(widget->model());
97 Q_ASSERT(model);
98 d_ptr.reset(new QTreeWidgetItemIteratorPrivate(this, model));
99 model->iterators.append(this);
100 if (!model->rootItem->children.isEmpty()) current = model->rootItem->child(0);
101 if (current && !matchesFlags(current))
102 ++(*this);
103}
104
105/*!
106 Constructs an iterator for the given \a item that uses the specified \a flags
107 to determine which items are found during iteration.
108 The iterator is set to point to \a item, or the next matching item if \a item
109 doesn't match the flags.
110
111 \sa QTreeWidgetItemIterator::IteratorFlag
112*/
113
114QTreeWidgetItemIterator::QTreeWidgetItemIterator(QTreeWidgetItem *item, IteratorFlags flags)
115 : d_ptr(new QTreeWidgetItemIteratorPrivate(
116 this, qobject_cast<QTreeModel*>(item->view->model()))),
117 current(item), flags(flags)
118{
119 Q_D(QTreeWidgetItemIterator);
120 Q_ASSERT(item);
121 QTreeModel *model = qobject_cast<QTreeModel*>(item->view->model());
122 Q_ASSERT(model);
123 model->iterators.append(this);
124
125 // Initialize m_currentIndex and m_parentIndex as it would be if we had traversed from
126 // the beginning.
127 QTreeWidgetItem *parent = item;
128 parent = parent->parent();
129 QTreeWidgetItem *root = d->m_model->rootItem;
130 d->m_currentIndex = (parent ? parent : root)->indexOfChild(item);
131
132 while (parent) {
133 QTreeWidgetItem *itm = parent;
134 parent = parent->parent();
135 const int index = (parent ? parent : root)->indexOfChild(itm);
136 d->m_parentIndex.prepend(index);
137 }
138
139 if (current && !matchesFlags(current))
140 ++(*this);
141}
142
143/*!
144 Destroys the iterator.
145*/
146
147QTreeWidgetItemIterator::~QTreeWidgetItemIterator()
148{
149 d_func()->m_model->iterators.removeAll(this);
150}
151
152/*!
153 Assignment. Makes a copy of \a it and returns a reference to its
154 iterator.
155*/
156
157QTreeWidgetItemIterator &QTreeWidgetItemIterator::operator=(const QTreeWidgetItemIterator &it)
158{
159 Q_D(QTreeWidgetItemIterator);
160 if (d_func()->m_model != it.d_func()->m_model) {
161 d_func()->m_model->iterators.removeAll(this);
162 it.d_func()->m_model->iterators.append(this);
163 }
164 current = it.current;
165 flags = it.flags;
166 d->operator=(*it.d_func());
167 return *this;
168}
169
170/*!
171 The prefix ++ operator (++it) advances the iterator to the next matching item
172 and returns a reference to the resulting iterator.
173 Sets the current pointer to \nullptr if the current item is the last matching item.
174*/
175
176QTreeWidgetItemIterator &QTreeWidgetItemIterator::operator++()
177{
178 if (current)
179 do {
180 current = d_func()->next(current);
181 } while (current && !matchesFlags(current));
182 return *this;
183}
184
185/*!
186 The prefix -- operator (--it) advances the iterator to the previous matching item
187 and returns a reference to the resulting iterator.
188 Sets the current pointer to \nullptr if the current item is the first matching item.
189*/
190
191QTreeWidgetItemIterator &QTreeWidgetItemIterator::operator--()
192{
193 if (current)
194 do {
195 current = d_func()->previous(current);
196 } while (current && !matchesFlags(current));
197 return *this;
198}
199
200/*!
201 \internal
202*/
203bool QTreeWidgetItemIterator::matchesFlags(const QTreeWidgetItem *item) const
204{
205 if (!item)
206 return false;
207
208 if (flags == All)
209 return true;
210
211 {
212 Qt::ItemFlags itemFlags = item->flags();
213 if ((flags & Selectable) && !(itemFlags & Qt::ItemIsSelectable))
214 return false;
215 if ((flags & NotSelectable) && (itemFlags & Qt::ItemIsSelectable))
216 return false;
217 if ((flags & DragEnabled) && !(itemFlags & Qt::ItemIsDragEnabled))
218 return false;
219 if ((flags & DragDisabled) && (itemFlags & Qt::ItemIsDragEnabled))
220 return false;
221 if ((flags & DropEnabled) && !(itemFlags & Qt::ItemIsDropEnabled))
222 return false;
223 if ((flags & DropDisabled) && (itemFlags & Qt::ItemIsDropEnabled))
224 return false;
225 if ((flags & Enabled) && !(itemFlags & Qt::ItemIsEnabled))
226 return false;
227 if ((flags & Disabled) && (itemFlags & Qt::ItemIsEnabled))
228 return false;
229 if ((flags & Editable) && !(itemFlags & Qt::ItemIsEditable))
230 return false;
231 if ((flags & NotEditable) && (itemFlags & Qt::ItemIsEditable))
232 return false;
233 }
234
235 if (flags & (Checked|NotChecked)) {
236 // ### We only test the check state for column 0
237 Qt::CheckState check = item->checkState(0);
238 // PartiallyChecked matches as Checked.
239 if ((flags & Checked) && (check == Qt::Unchecked))
240 return false;
241 if ((flags & NotChecked) && (check != Qt::Unchecked))
242 return false;
243 }
244
245 if ((flags & HasChildren) && !item->childCount())
246 return false;
247 if ((flags & NoChildren) && item->childCount())
248 return false;
249
250 if ((flags & Hidden) && !item->isHidden())
251 return false;
252 if ((flags & NotHidden) && item->isHidden())
253 return false;
254
255 if ((flags & Selected) && !item->isSelected())
256 return false;
257 if ((flags & Unselected) && item->isSelected())
258 return false;
259
260 return true;
261}
262
263/*
264 * Implementation of QTreeWidgetItemIteratorPrivate
265 */
266QTreeWidgetItem* QTreeWidgetItemIteratorPrivate::nextSibling(const QTreeWidgetItem* item) const
267{
268 Q_ASSERT(item);
269 QTreeWidgetItem *next = nullptr;
270 if (QTreeWidgetItem *par = item->parent()) {
271 int i = par->indexOfChild(const_cast<QTreeWidgetItem*>(item));
272 next = par->child(i + 1);
273 } else {
274 QTreeWidget *tw = item->treeWidget();
275 int i = tw->indexOfTopLevelItem(const_cast<QTreeWidgetItem*>(item));
276 next = tw->topLevelItem(i + 1);
277 }
278 return next;
279}
280
281QTreeWidgetItem *QTreeWidgetItemIteratorPrivate::next(const QTreeWidgetItem *current)
282{
283 if (!current) return nullptr;
284
285 QTreeWidgetItem *next = nullptr;
286 if (current->childCount()) {
287 // walk the child
288 m_parentIndex.push(m_currentIndex);
289 m_currentIndex = 0;
290 next = current->child(0);
291 } else {
292 // walk the sibling
293 QTreeWidgetItem *parent = current->parent();
294 next = parent ? parent->child(m_currentIndex + 1)
295 : m_model->rootItem->child(m_currentIndex + 1);
296 while (!next && parent) {
297 // if we had no sibling walk up the parent and try the sibling of that
298 parent = parent->parent();
299 m_currentIndex = m_parentIndex.pop();
300 next = parent ? parent->child(m_currentIndex + 1)
301 : m_model->rootItem->child(m_currentIndex + 1);
302 }
303 if (next) ++(m_currentIndex);
304 }
305 return next;
306}
307
308QTreeWidgetItem *QTreeWidgetItemIteratorPrivate::previous(const QTreeWidgetItem *current)
309{
310 if (!current) return nullptr;
311
312 QTreeWidgetItem *prev = nullptr;
313 // walk the previous sibling
314 QTreeWidgetItem *parent = current->parent();
315 prev = parent ? parent->child(m_currentIndex - 1)
316 : m_model->rootItem->child(m_currentIndex - 1);
317 if (prev) {
318 // Yes, we had a previous sibling but we need go down to the last leafnode.
319 --m_currentIndex;
320 while (prev && prev->childCount()) {
321 m_parentIndex.push(m_currentIndex);
322 m_currentIndex = prev->childCount() - 1;
323 prev = prev->child(m_currentIndex);
324 }
325 } else if (parent) {
326 m_currentIndex = m_parentIndex.pop();
327 prev = parent;
328 }
329 return prev;
330}
331
332void QTreeWidgetItemIteratorPrivate::ensureValidIterator(const QTreeWidgetItem *itemToBeRemoved)
333{
334 Q_Q(QTreeWidgetItemIterator);
335 Q_ASSERT(itemToBeRemoved);
336
337 if (!q->current) return;
338 QTreeWidgetItem *nextItem = q->current;
339
340 // Do not walk to the ancestor to find the other item if they have the same parent.
341 if (nextItem->parent() != itemToBeRemoved->parent()) {
342 while (nextItem->parent() && nextItem != itemToBeRemoved) {
343 nextItem = nextItem->parent();
344 }
345 }
346 // If the item to be removed is an ancestor of the current iterator item,
347 // we need to adjust the iterator.
348 if (nextItem == itemToBeRemoved) {
349 QTreeWidgetItem *parent = nextItem;
350 nextItem = nullptr;
351 while (parent && !nextItem) {
352 nextItem = nextSibling(parent);
353 parent = parent->parent();
354 }
355 if (nextItem) {
356 // Ooooh... Set the iterator to the next valid item
357 *q = QTreeWidgetItemIterator(nextItem, q->flags);
358 if (!(q->matchesFlags(nextItem))) ++(*q);
359 } else {
360 // set it to null.
361 q->current = nullptr;
362 m_parentIndex.clear();
363 return;
364 }
365 }
366 if (nextItem->parent() == itemToBeRemoved->parent()) {
367 // They have the same parent, i.e. we have to adjust the m_currentIndex member of the iterator
368 // if the deleted item is to the left of the nextItem.
369
370 QTreeWidgetItem *par = itemToBeRemoved->parent(); // We know they both have the same parent.
371 QTreeWidget *tw = itemToBeRemoved->treeWidget(); // ..and widget
372 int indexOfItemToBeRemoved = par ? par->indexOfChild(const_cast<QTreeWidgetItem *>(itemToBeRemoved))
373 : tw->indexOfTopLevelItem(const_cast<QTreeWidgetItem *>(itemToBeRemoved));
374 int indexOfNextItem = par ? par->indexOfChild(nextItem) : tw->indexOfTopLevelItem(nextItem);
375
376 if (indexOfItemToBeRemoved <= indexOfNextItem) {
377 // A sibling to the left of us was deleted, adjust the m_currentIndex member of the iterator.
378 // Note that the m_currentIndex will be wrong until the item is actually removed!
379 m_currentIndex--;
380 }
381 }
382}
383
384/*!
385 \fn const QTreeWidgetItemIterator QTreeWidgetItemIterator::operator++(int)
386
387 The postfix ++ operator (it++) advances the iterator to the next matching item
388 and returns an iterator to the previously current item.
389*/
390
391/*!
392 \fn QTreeWidgetItemIterator &QTreeWidgetItemIterator::operator+=(int n)
393
394 Makes the iterator go forward by \a n matching items. (If n is negative, the
395 iterator goes backward.)
396
397 If the current item is beyond the last item, the current item pointer is
398 set to \nullptr. Returns the resulting iterator.
399*/
400
401/*!
402 \fn const QTreeWidgetItemIterator QTreeWidgetItemIterator::operator--(int)
403
404 The postfix -- operator (it--) makes the preceding matching item current and returns an iterator to the previously current item.
405*/
406
407/*!
408 \fn QTreeWidgetItemIterator &QTreeWidgetItemIterator::operator-=(int n)
409
410 Makes the iterator go backward by \a n matching items. (If n is negative, the
411 iterator goes forward.)
412
413 If the current item is ahead of the last item, the current item pointer is
414 set to \nullptr. Returns the resulting iterator.
415*/
416
417/*!
418 \fn QTreeWidgetItem *QTreeWidgetItemIterator::operator*() const
419
420 Dereference operator. Returns a pointer to the current item.
421*/
422
423
424/*!
425 \enum QTreeWidgetItemIterator::IteratorFlag
426
427 These flags can be passed to a QTreeWidgetItemIterator constructor
428 (OR-ed together if more than one is used), so that the iterator
429 will only iterate over items that match the given flags.
430
431 \value All
432 \value Hidden
433 \value NotHidden
434 \value Selected
435 \value Unselected
436 \value Selectable
437 \value NotSelectable
438 \value DragEnabled
439 \value DragDisabled
440 \value DropEnabled
441 \value DropDisabled
442 \value HasChildren
443 \value NoChildren
444 \value Checked
445 \value NotChecked
446 \value Enabled
447 \value Disabled
448 \value Editable
449 \value NotEditable
450 \value UserFlag
451*/
452
453QT_END_NAMESPACE
454