src/hbwidgets/itemviews/hbtreemodeliterator_p.cpp
changeset 0 16d8024aca5e
child 1 f7ac710697a9
equal deleted inserted replaced
-1:000000000000 0:16d8024aca5e
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (developer.feedback@nokia.com)
       
     6 **
       
     7 ** This file is part of the HbWidgets module of the UI Extensions for Mobile.
       
     8 **
       
     9 ** GNU Lesser General Public License Usage
       
    10 ** This file may be used under the terms of the GNU Lesser General Public
       
    11 ** License version 2.1 as published by the Free Software Foundation and
       
    12 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
       
    13 ** Please review the following information to ensure the GNU Lesser General
       
    14 ** Public License version 2.1 requirements will be met:
       
    15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    16 **
       
    17 ** In addition, as a special exception, Nokia gives you certain additional
       
    18 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    20 **
       
    21 ** If you have questions regarding the use of this file, please contact
       
    22 ** Nokia at developer.feedback@nokia.com.
       
    23 **
       
    24 ****************************************************************************/
       
    25 
       
    26 #include "hbtreemodeliterator_p.h"
       
    27 #include "hbtreemodeliterator_p_p.h"
       
    28 
       
    29 HbTreeModelIterator::HbTreeModelIterator(QAbstractItemModel *model,
       
    30                                          QModelIndex rootIndex, bool useCache)
       
    31     : HbModelIterator(*new HbTreeModelIteratorPrivate())
       
    32 {
       
    33     Q_D(HbTreeModelIterator);
       
    34     d->mUseCache = useCache;
       
    35     setModel(model, rootIndex);
       
    36 }
       
    37 
       
    38 HbTreeModelIterator::~HbTreeModelIterator()
       
    39 {
       
    40 }
       
    41 
       
    42 /*!
       
    43     \reimp
       
    44 
       
    45     Children of collapsed parents are not taken into account.
       
    46 */
       
    47 int HbTreeModelIterator::indexCount(const QModelIndex &parent) const
       
    48 {
       
    49     Q_D(const HbTreeModelIterator);
       
    50     int itemsCount = 0;
       
    51     if (d->mModel) {
       
    52         QModelIndex parentIndex = parent;
       
    53         if (!parentIndex.isValid()) {
       
    54             parentIndex = d->mRootIndex;
       
    55         }
       
    56         if (d->isInCountCache(parentIndex)) {
       
    57             return d->mCachedCount.count;
       
    58         }
       
    59         if (parentIndex != d->mRootIndex) {
       
    60             itemsCount = d->childIndexCount(parentIndex);
       
    61         } else {
       
    62             int rowsCount = d->mModel->rowCount(parentIndex);
       
    63             itemsCount += rowsCount;
       
    64             for (int i = 0; i < rowsCount; i++) {
       
    65                 itemsCount += d->childIndexCount(d->mModel->index(i, 0, parentIndex));
       
    66             }
       
    67         }
       
    68         d->mCachedCount.count = itemsCount;
       
    69         d->mCachedCount.index = parentIndex;
       
    70     }
       
    71     return itemsCount;
       
    72 }
       
    73 
       
    74 /*!
       
    75     \reimp
       
    76     Position depends on item state - expanded/colapsed
       
    77 */
       
    78 int HbTreeModelIterator::indexPosition(const QModelIndex &index) const
       
    79 {
       
    80     Q_D(const HbTreeModelIterator);
       
    81     int result = -1;
       
    82     if (d->mModel) {
       
    83         if (d->isInPositionCache(index)) {
       
    84             return d->mCachedPosition.count;
       
    85         } else if (d->mCachedPosition.index == d->mRootIndex
       
    86                    || lessThan(d->mCachedPosition.index, index)) {  //Cache has been reset, start from the beginning
       
    87             result = d->searchForward(index);
       
    88         } else {
       
    89             result = d->searchBackward(index);
       
    90         }
       
    91     }
       
    92     return result;
       
    93 }
       
    94 
       
    95 /*!
       
    96     \reimp
       
    97     Index is calculated from position and it depends on item state - expanded/colapsed
       
    98     Very slow - need to interate throught whole model in worst case!
       
    99 */
       
   100 QModelIndex HbTreeModelIterator::index(int pos, const QModelIndex &parent) const
       
   101 {
       
   102     Q_D(const HbTreeModelIterator);
       
   103     QModelIndex index;
       
   104     QModelIndex parentIndex = parent;
       
   105     if (!parentIndex.isValid()) {
       
   106         parentIndex = d->mRootIndex;
       
   107     }
       
   108     if (pos < 0) {
       
   109         int count = indexCount(parentIndex);
       
   110         pos = count - pos;
       
   111         if (pos > count) {
       
   112             return index;
       
   113         }
       
   114     }
       
   115     if (d->isInCountCache(parentIndex)
       
   116         && d->mCachedCount.count >= 0
       
   117         && (d->mCachedCount.count/2) < pos) {
       
   118         // is this reasonable?
       
   119         // last go through whole branch to find last
       
   120         // faster than nextIndex but...
       
   121         int i = d->mCachedCount.count - pos;
       
   122         if (i > 0) {
       
   123             index = d->last(parentIndex);
       
   124             --i;
       
   125         }
       
   126         while (i > 0) {
       
   127             index = previousIndex(index);
       
   128             if (!index.isValid()) break;
       
   129             --i;
       
   130         }
       
   131     } else {
       
   132         int i = 0;
       
   133         index = d->first(parentIndex);
       
   134         while (i < pos) {
       
   135             index = nextIndex(index);
       
   136             if (index.parent() != parentIndex) {
       
   137                 // next index must be in the same branch as parent!
       
   138                 QModelIndex temp = index.parent();
       
   139                 while (temp.isValid()
       
   140                     && temp.parent() != parentIndex) {
       
   141                     temp = temp.parent();
       
   142                 }
       
   143                 if (!temp.isValid()) {
       
   144                     index = temp;
       
   145                     break;
       
   146                 }
       
   147             }
       
   148             if (!index.isValid()) {
       
   149                 break;
       
   150             }
       
   151             ++i;
       
   152         }
       
   153     }
       
   154     return index;
       
   155 }
       
   156 
       
   157 QModelIndex HbTreeModelIterator::child(int pos, const QModelIndex &parent) const
       
   158 {
       
   159     Q_D(const HbTreeModelIterator);
       
   160     if (d->mModel) {
       
   161         return d->mModel->index(pos, 0, parent);
       
   162     }
       
   163     return QModelIndex();
       
   164 }
       
   165 
       
   166 int HbTreeModelIterator::childCount(const QModelIndex &parent) const
       
   167 {
       
   168     Q_D(const HbTreeModelIterator);
       
   169     if (d->mModel) {
       
   170         return d->mModel->rowCount(parent);
       
   171     }
       
   172     return 0;
       
   173 }
       
   174 
       
   175 /*!
       
   176     \reimp
       
   177 
       
   178     Next index for valid index is determined in following way:
       
   179     - If index is in collapsed branch QModelIndex is returned
       
   180     - If index has children and it is expanded then first child is returned
       
   181     - Otherwise if index has next sibling then that is returned
       
   182     - Otherwise next valid sibling for parent is returned
       
   183     - Otherwise QModelIndex is returned
       
   184 
       
   185     \a index must belong to mRootIndex branch, otherwise result is not determined.
       
   186 
       
   187     To get first index use nextIndex(QModelIndex()).
       
   188 */
       
   189 QModelIndex HbTreeModelIterator::nextIndex(const QModelIndex &index) const
       
   190 {
       
   191     Q_D(const HbTreeModelIterator);
       
   192     if (d->mModel) {
       
   193         QModelIndex result;
       
   194         if (!index.isValid()) {
       
   195             result = d->first(d->mRootIndex);
       
   196         } else {
       
   197             // nextIndex(d->mRootIndex) == first(d->mRootIndex)
       
   198             if (!d->isExpandedBranch(index.parent())) {
       
   199                 return QModelIndex();
       
   200             }
       
   201             QModelIndex tmpIndex = index;
       
   202 
       
   203             do {
       
   204                 if (d->isExpanded(tmpIndex)) {
       
   205                     // if expanded, take first child - going deeper
       
   206                     result = tmpIndex.child(0, 0);
       
   207                 }
       
   208                 if (!result.isValid()) {
       
   209                     // if not expanded, or expanded but without child
       
   210                     // take next on the same level
       
   211                     result = tmpIndex.sibling(tmpIndex.row()+1, 0);
       
   212                 }
       
   213                 while (!result.isValid()) {
       
   214                     // if not possible to take next on the same level, go level up
       
   215                     tmpIndex = tmpIndex.parent();
       
   216                     if (tmpIndex == d->mRootIndex
       
   217                         || !tmpIndex.isValid()) {
       
   218                         tmpIndex = QModelIndex();
       
   219                         break;
       
   220                     }
       
   221                     result = tmpIndex.sibling(tmpIndex.row()+1, 0);
       
   222                 }
       
   223             }
       
   224             while (!result.isValid() && tmpIndex.isValid());
       
   225         }
       
   226         return result;
       
   227     } // if (mModel)
       
   228     return QModelIndex();
       
   229 }
       
   230 
       
   231 /*!
       
   232     \reimp
       
   233 
       
   234     Previous index for valid index is determined in following way:
       
   235     - If index is in collapsed branch QModelIndex is returned
       
   236     - If index has previous sibling last child from it is returned
       
   237     - Otherwise previous sibling is returned
       
   238     - Otherwise parent index is returned
       
   239     - Otherwise QModelIndex is returned
       
   240     If index was invalid then last valid is returned.
       
   241 
       
   242     \a index must belong to mRootIndex branch, otherwise result is not determined.
       
   243 
       
   244     To get last index use previousIndex(QModelIndex()).
       
   245 */
       
   246 QModelIndex HbTreeModelIterator::previousIndex(const QModelIndex &index) const
       
   247 {
       
   248     Q_D(const HbTreeModelIterator);
       
   249     if (d->mModel) {
       
   250         QModelIndex result;
       
   251         if (!index.isValid()) {
       
   252             result = d->last(d->mRootIndex);
       
   253         } else if (index != d->mRootIndex) { // can't go outside mRootIndex
       
   254             if (!d->isExpandedBranch(index.parent())) {
       
   255                 return QModelIndex();
       
   256             }
       
   257             QModelIndex tmpIndex = index;
       
   258 
       
   259             // try to take previous on the same level
       
   260             result = tmpIndex.sibling(tmpIndex.row()-1, 0);
       
   261             if (result.isValid()) {
       
   262                 // take last
       
   263                 tmpIndex = d->last(result);
       
   264                 if (tmpIndex.isValid()) {
       
   265                     result = tmpIndex;
       
   266                 }
       
   267             } else {
       
   268                 result = tmpIndex.parent();
       
   269                 if (result == d->mRootIndex) {
       
   270                     result = QModelIndex();
       
   271                 }
       
   272             }
       
   273         }
       
   274         return result;
       
   275     }
       
   276     return QModelIndex();
       
   277 }
       
   278 
       
   279 void HbTreeModelIterator::setModel(QAbstractItemModel *model,
       
   280                                    QModelIndex rootIndex)
       
   281 {
       
   282     Q_D(HbTreeModelIterator);
       
   283     if (model != d->mModel) {
       
   284         d->resetCache();
       
   285         d->setModel(model, rootIndex);
       
   286         if (d->mModel) {
       
   287             connect(d->mModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
       
   288                     this, SLOT(rowsInserted(QModelIndex,int,int)));
       
   289             connect(d->mModel, SIGNAL(rowsRemoved(QModelIndex,int,int)),
       
   290                     this, SLOT(rowsRemoved(QModelIndex,int,int)));
       
   291             connect(d->mModel, SIGNAL(columnsInserted(QModelIndex,int,int)),
       
   292                     this, SLOT(columnsInserted(QModelIndex,int,int)));
       
   293             connect(d->mModel, SIGNAL(columnsRemoved(QModelIndex,int,int)),
       
   294                     this, SLOT(columnsRemoved(QModelIndex,int,int)));
       
   295         }
       
   296     } else {
       
   297         setRootIndex(rootIndex);
       
   298     }
       
   299 }
       
   300 
       
   301 void HbTreeModelIterator::setRootIndex(QModelIndex rootIndex)
       
   302 {
       
   303     if (d->mRootIndex != rootIndex) {
       
   304         Q_D(HbTreeModelIterator);
       
   305         d->setRootIndex(rootIndex);
       
   306         d->resetCache();
       
   307     }
       
   308 }
       
   309 
       
   310 void HbTreeModelIterator::setItemContainer(HbAbstractItemContainer *itemContainer,
       
   311                                            int expansionKey)
       
   312 {
       
   313     Q_D(HbTreeModelIterator);
       
   314     d->mItemContainer = itemContainer;
       
   315     d->mExpansionKey = expansionKey;
       
   316 }
       
   317 
       
   318 bool HbTreeModelIterator::lessThan(const QModelIndex &index1,
       
   319                                     const QModelIndex &index2) const
       
   320 {
       
   321     Q_D(const HbTreeModelIterator);
       
   322     if (index1 == index2) {
       
   323         return false;
       
   324     }
       
   325 
       
   326     //- Create lists from item to root so that the root will be the first item in the list (prepend...)
       
   327     QModelIndexList indexList1 = d->createParentChainList(index1);
       
   328     QModelIndexList indexList2 = d->createParentChainList(index2);
       
   329 
       
   330     int list1Count = indexList1.count();
       
   331     int list2Count = indexList2.count();
       
   332     int minCount = qMin(list1Count, list2Count);
       
   333 
       
   334     //- Loop the lists starting from the root until different item is found or if other list ends.
       
   335     //- If difference is found the comparison can be made compring the rows
       
   336     //- If no difference has been found and other list ends step out of the loop
       
   337     for (int i = 0; i < minCount; i++) {
       
   338         if (indexList1.at(i)!= indexList2.at(i)) {
       
   339             if (indexList1.at(i).row() < indexList2.at(i).row()) {
       
   340                 return true;
       
   341             } else {
       
   342                 return false;
       
   343             }
       
   344         }
       
   345     }
       
   346 
       
   347     //- Now we can be sure that the items to be compared are from the same branch.
       
   348     //- The longer list indicates lower position
       
   349     return (list1Count < list2Count);
       
   350 }
       
   351 
       
   352 void HbTreeModelIterator::itemStateChanged(const QModelIndex &index, int stateKey)
       
   353 {
       
   354     Q_UNUSED(index);
       
   355     Q_D(HbTreeModelIterator);
       
   356     if (stateKey & d->mExpansionKey) {
       
   357         d->resetCache();
       
   358     }
       
   359 }
       
   360 
       
   361 void HbTreeModelIterator::rowsInserted(const QModelIndex &parent, int start, int end)
       
   362 {
       
   363     Q_D(HbTreeModelIterator);
       
   364     Q_UNUSED(parent);
       
   365     Q_UNUSED(start);
       
   366     Q_UNUSED(end);
       
   367     d->resetCache();
       
   368 }
       
   369 
       
   370 void HbTreeModelIterator::rowsRemoved(const QModelIndex &parent, int start, int end)
       
   371 {
       
   372     Q_D(HbTreeModelIterator);
       
   373     Q_UNUSED(parent);
       
   374     Q_UNUSED(start);
       
   375     Q_UNUSED(end);
       
   376     d->resetCache();
       
   377 }
       
   378 
       
   379 void HbTreeModelIterator::columnsInserted(const QModelIndex &parent, int start, int end)
       
   380 {
       
   381     Q_D(HbTreeModelIterator);
       
   382     Q_UNUSED(parent);
       
   383     Q_UNUSED(start);
       
   384     Q_UNUSED(end);
       
   385     d->resetCache();
       
   386 }
       
   387 
       
   388 void HbTreeModelIterator::columnsRemoved(const QModelIndex &parent, int start, int end)
       
   389 {
       
   390     Q_D(HbTreeModelIterator);
       
   391     Q_UNUSED(parent);
       
   392     Q_UNUSED(start);
       
   393     Q_UNUSED(end);
       
   394     d->resetCache();
       
   395 }
       
   396 
       
   397 #include "moc_hbtreemodeliterator_p.cpp"
       
   398