source: trunk/src/gui/itemviews/qtreewidgetitemiterator.cpp@ 651

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

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