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 |
|
---|
49 | QT_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 |
|
---|
76 | QTreeWidgetItemIterator::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 |
|
---|
94 | QTreeWidgetItemIterator::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 |
|
---|
116 | QTreeWidgetItemIterator::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 |
|
---|
150 | QTreeWidgetItemIterator::~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 |
|
---|
161 | QTreeWidgetItemIterator &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 |
|
---|
180 | QTreeWidgetItemIterator &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 |
|
---|
195 | QTreeWidgetItemIterator &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 | */
|
---|
207 | bool 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 | */
|
---|
270 | QTreeWidgetItem* 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 |
|
---|
285 | QTreeWidgetItem *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 |
|
---|
312 | QTreeWidgetItem *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 |
|
---|
336 | void 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 |
|
---|
457 | QT_END_NAMESPACE
|
---|
458 |
|
---|
459 | #endif // QT_NO_TREEWIDGET
|
---|