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