src/gui/itemviews/qtreewidgetitemiterator.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    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 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    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.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 
       
   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 }
       
   154 
       
   155 /*!
       
   156     Assignment. Makes a copy of \a it and returns a reference to its
       
   157     iterator.
       
   158 */
       
   159 
       
   160 QTreeWidgetItemIterator &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 
       
   179 QTreeWidgetItemIterator &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 
       
   194 QTreeWidgetItemIterator &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 */
       
   206 bool 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  */
       
   269 QTreeWidgetItem* 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 
       
   284 QTreeWidgetItem *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 
       
   311 QTreeWidgetItem *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 
       
   335 void 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 
       
   456 QT_END_NAMESPACE
       
   457 
       
   458 #endif // QT_NO_TREEWIDGET