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

Last change on this file since 104 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 15.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department 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 = 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 delete d_ptr;
154}
155
156/*!
157 Assignment. Makes a copy of \a it and returns a reference to its
158 iterator.
159*/
160
161QTreeWidgetItemIterator &QTreeWidgetItemIterator::operator=(const QTreeWidgetItemIterator &it)
162{
163 Q_D(QTreeWidgetItemIterator);
164 if (d_func()->m_model != it.d_func()->m_model) {
165 d_func()->m_model->iterators.removeAll(this);
166 it.d_func()->m_model->iterators.append(this);
167 }
168 current = it.current;
169 flags = it.flags;
170 d->operator=(*it.d_func());
171 return *this;
172}
173
174/*!
175 The prefix ++ operator (++it) advances the iterator to the next matching item
176 and returns a reference to the resulting iterator.
177 Sets the current pointer to 0 if the current item is the last matching item.
178*/
179
180QTreeWidgetItemIterator &QTreeWidgetItemIterator::operator++()
181{
182 if (current)
183 do {
184 current = d_func()->next(current);
185 } while (current && !matchesFlags(current));
186 return *this;
187}
188
189/*!
190 The prefix -- operator (--it) advances the iterator to the previous matching item
191 and returns a reference to the resulting iterator.
192 Sets the current pointer to 0 if the current item is the first matching item.
193*/
194
195QTreeWidgetItemIterator &QTreeWidgetItemIterator::operator--()
196{
197 if (current)
198 do {
199 current = d_func()->previous(current);
200 } while (current && !matchesFlags(current));
201 return *this;
202}
203
204/*!
205 \internal
206*/
207bool QTreeWidgetItemIterator::matchesFlags(const QTreeWidgetItem *item) const
208{
209 if (!item)
210 return false;
211
212 if (flags == All)
213 return true;
214
215 {
216 Qt::ItemFlags itemFlags = item->flags();
217 if ((flags & Selectable) && !(itemFlags & Qt::ItemIsSelectable))
218 return false;
219 if ((flags & NotSelectable) && (itemFlags & Qt::ItemIsSelectable))
220 return false;
221 if ((flags & DragEnabled) && !(itemFlags & Qt::ItemIsDragEnabled))
222 return false;
223 if ((flags & DragDisabled) && (itemFlags & Qt::ItemIsDragEnabled))
224 return false;
225 if ((flags & DropEnabled) && !(itemFlags & Qt::ItemIsDropEnabled))
226 return false;
227 if ((flags & DropDisabled) && (itemFlags & Qt::ItemIsDropEnabled))
228 return false;
229 if ((flags & Enabled) && !(itemFlags & Qt::ItemIsEnabled))
230 return false;
231 if ((flags & Disabled) && (itemFlags & Qt::ItemIsEnabled))
232 return false;
233 if ((flags & Editable) && !(itemFlags & Qt::ItemIsEditable))
234 return false;
235 if ((flags & NotEditable) && (itemFlags & Qt::ItemIsEditable))
236 return false;
237 }
238
239 if (flags & (Checked|NotChecked)) {
240 // ### We only test the check state for column 0
241 Qt::CheckState check = item->checkState(0);
242 // PartiallyChecked matches as Checked.
243 if ((flags & Checked) && (check == Qt::Unchecked))
244 return false;
245 if ((flags & NotChecked) && (check != Qt::Unchecked))
246 return false;
247 }
248
249 if ((flags & HasChildren) && !item->childCount())
250 return false;
251 if ((flags & NoChildren) && item->childCount())
252 return false;
253
254 if ((flags & Hidden) && !item->isHidden())
255 return false;
256 if ((flags & NotHidden) && item->isHidden())
257 return false;
258
259 if ((flags & Selected) && !item->isSelected())
260 return false;
261 if ((flags & Unselected) && item->isSelected())
262 return false;
263
264 return true;
265}
266
267/*
268 * Implementation of QTreeWidgetItemIteratorPrivate
269 */
270QTreeWidgetItem* QTreeWidgetItemIteratorPrivate::nextSibling(const QTreeWidgetItem* item) const
271{
272 Q_ASSERT(item);
273 QTreeWidgetItem *next = 0;
274 if (QTreeWidgetItem *par = item->parent()) {
275 int i = par->indexOfChild(const_cast<QTreeWidgetItem*>(item));
276 next = par->child(i + 1);
277 } else {
278 QTreeWidget *tw = item->treeWidget();
279 int i = tw->indexOfTopLevelItem(const_cast<QTreeWidgetItem*>(item));
280 next = tw->topLevelItem(i + 1);
281 }
282 return next;
283}
284
285QTreeWidgetItem *QTreeWidgetItemIteratorPrivate::next(const QTreeWidgetItem *current)
286{
287 if (!current) return 0;
288
289 QTreeWidgetItem *next = 0;
290 if (current->childCount()) {
291 // walk the child
292 m_parentIndex.push(m_currentIndex);
293 m_currentIndex = 0;
294 next = current->child(0);
295 } else {
296 // walk the sibling
297 QTreeWidgetItem *parent = current->parent();
298 next = parent ? parent->child(m_currentIndex + 1)
299 : m_model->rootItem->child(m_currentIndex + 1);
300 while (!next && parent) {
301 // if we had no sibling walk up the parent and try the sibling of that
302 parent = parent->parent();
303 m_currentIndex = m_parentIndex.pop();
304 next = parent ? parent->child(m_currentIndex + 1)
305 : m_model->rootItem->child(m_currentIndex + 1);
306 }
307 if (next) ++(m_currentIndex);
308 }
309 return next;
310}
311
312QTreeWidgetItem *QTreeWidgetItemIteratorPrivate::previous(const QTreeWidgetItem *current)
313{
314 if (!current) return 0;
315
316 QTreeWidgetItem *prev = 0;
317 // walk the previous sibling
318 QTreeWidgetItem *parent = current->parent();
319 prev = parent ? parent->child(m_currentIndex - 1)
320 : m_model->rootItem->child(m_currentIndex - 1);
321 if (prev) {
322 // Yes, we had a previous sibling but we need go down to the last leafnode.
323 --m_currentIndex;
324 while (prev && prev->childCount()) {
325 m_parentIndex.push(m_currentIndex);
326 m_currentIndex = prev->childCount() - 1;
327 prev = prev->child(m_currentIndex);
328 }
329 } else if (parent) {
330 m_currentIndex = m_parentIndex.pop();
331 prev = parent;
332 }
333 return prev;
334}
335
336void QTreeWidgetItemIteratorPrivate::ensureValidIterator(const QTreeWidgetItem *itemToBeRemoved)
337{
338 Q_Q(QTreeWidgetItemIterator);
339 Q_ASSERT(itemToBeRemoved);
340
341 if (!q->current) return;
342 QTreeWidgetItem *nextItem = q->current;
343
344 // Do not walk to the ancestor to find the other item if they have the same parent.
345 if (nextItem->parent() != itemToBeRemoved->parent()) {
346 while (nextItem->parent() && nextItem != itemToBeRemoved) {
347 nextItem = nextItem->parent();
348 }
349 }
350 // If the item to be removed is an ancestor of the current iterator item,
351 // we need to adjust the iterator.
352 if (nextItem == itemToBeRemoved) {
353 QTreeWidgetItem *parent = nextItem;
354 nextItem = 0;
355 while (parent && !nextItem) {
356 nextItem = nextSibling(parent);
357 parent = parent->parent();
358 }
359 if (nextItem) {
360 // Ooooh... Set the iterator to the next valid item
361 *q = QTreeWidgetItemIterator(nextItem, q->flags);
362 if (!(q->matchesFlags(nextItem))) ++(*q);
363 } else {
364 // set it to null.
365 q->current = 0;
366 m_parentIndex.clear();
367 return;
368 }
369 }
370 if (nextItem->parent() == itemToBeRemoved->parent()) {
371 // They have the same parent, i.e. we have to adjust the m_currentIndex member of the iterator
372 // if the deleted item is to the left of the nextItem.
373
374 QTreeWidgetItem *par = itemToBeRemoved->parent(); // We know they both have the same parent.
375 QTreeWidget *tw = itemToBeRemoved->treeWidget(); // ..and widget
376 int indexOfItemToBeRemoved = par ? par->indexOfChild(const_cast<QTreeWidgetItem *>(itemToBeRemoved))
377 : tw->indexOfTopLevelItem(const_cast<QTreeWidgetItem *>(itemToBeRemoved));
378 int indexOfNextItem = par ? par->indexOfChild(nextItem) : tw->indexOfTopLevelItem(nextItem);
379
380 if (indexOfItemToBeRemoved <= indexOfNextItem) {
381 // A sibling to the left of us was deleted, adjust the m_currentIndex member of the iterator.
382 // Note that the m_currentIndex will be wrong until the item is actually removed!
383 m_currentIndex--;
384 }
385 }
386}
387
388/*!
389 \fn const QTreeWidgetItemIterator QTreeWidgetItemIterator::operator++(int)
390
391 The postfix ++ operator (it++) advances the iterator to the next matching item
392 and returns an iterator to the previously current item.
393*/
394
395/*!
396 \fn QTreeWidgetItemIterator &QTreeWidgetItemIterator::operator+=(int n)
397
398 Makes the iterator go forward by \a n matching items. (If n is negative, the
399 iterator goes backward.)
400
401 If the current item is beyond the last item, the current item pointer is
402 set to 0. Returns the resulting iterator.
403*/
404
405/*!
406 \fn const QTreeWidgetItemIterator QTreeWidgetItemIterator::operator--(int)
407
408 The postfix -- operator (it--) makes the preceding matching item current and returns an iterator to the previously current item.
409*/
410
411/*!
412 \fn QTreeWidgetItemIterator &QTreeWidgetItemIterator::operator-=(int n)
413
414 Makes the iterator go backward by \a n matching items. (If n is negative, the
415 iterator goes forward.)
416
417 If the current item is ahead of the last item, the current item pointer is
418 set to 0. Returns the resulting iterator.
419*/
420
421/*!
422 \fn QTreeWidgetItem *QTreeWidgetItemIterator::operator*() const
423
424 Dereference operator. Returns a pointer to the current item.
425*/
426
427
428/*!
429 \enum QTreeWidgetItemIterator::IteratorFlag
430
431 These flags can be passed to a QTreeWidgetItemIterator constructor
432 (OR-ed together if more than one is used), so that the iterator
433 will only iterate over items that match the given flags.
434
435 \value All
436 \value Hidden
437 \value NotHidden
438 \value Selected
439 \value Unselected
440 \value Selectable
441 \value NotSelectable
442 \value DragEnabled
443 \value DragDisabled
444 \value DropEnabled
445 \value DropDisabled
446 \value HasChildren
447 \value NoChildren
448 \value Checked
449 \value NotChecked
450 \value Enabled
451 \value Disabled
452 \value Editable
453 \value NotEditable
454 \value UserFlag
455*/
456
457QT_END_NAMESPACE
458
459#endif // QT_NO_TREEWIDGET
Note: See TracBrowser for help on using the repository browser.