src/gui/itemviews/qtreeview.cpp
changeset 30 5dc02b23752f
parent 19 fcece45ef507
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
   672         return;
   672         return;
   673 
   673 
   674     // refresh the height cache here; we don't really lose anything by getting the size hint,
   674     // refresh the height cache here; we don't really lose anything by getting the size hint,
   675     // since QAbstractItemView::dataChanged() will get the visualRect for the items anyway
   675     // since QAbstractItemView::dataChanged() will get the visualRect for the items anyway
   676 
   676 
       
   677     bool sizeChanged = false;
   677     int topViewIndex = d->viewIndex(topLeft);
   678     int topViewIndex = d->viewIndex(topLeft);
   678     if (topViewIndex == 0)
   679     if (topViewIndex == 0) {
   679         d->defaultItemHeight = indexRowSizeHint(topLeft);
   680         int newDefaultItemHeight = indexRowSizeHint(topLeft);
   680     bool sizeChanged = false;
   681         sizeChanged = d->defaultItemHeight != newDefaultItemHeight;
       
   682         d->defaultItemHeight = newDefaultItemHeight;
       
   683     }
       
   684 
   681     if (topViewIndex != -1) {
   685     if (topViewIndex != -1) {
   682         if (topLeft == bottomRight) {
   686         if (topLeft.row() == bottomRight.row()) {
   683             int oldHeight = d->itemHeight(topViewIndex);
   687             int oldHeight = d->itemHeight(topViewIndex);
   684             d->invalidateHeightCache(topViewIndex);
   688             d->invalidateHeightCache(topViewIndex);
   685             sizeChanged = (oldHeight != d->itemHeight(topViewIndex));
   689             sizeChanged |= (oldHeight != d->itemHeight(topViewIndex));
       
   690             if (topLeft.column() == 0)
       
   691                 d->viewItems[topViewIndex].hasChildren = d->hasVisibleChildren(topLeft);
   686         } else {
   692         } else {
   687             int bottomViewIndex = d->viewIndex(bottomRight);
   693             int bottomViewIndex = d->viewIndex(bottomRight);
   688             for (int i = topViewIndex; i <= bottomViewIndex; ++i) {
   694             for (int i = topViewIndex; i <= bottomViewIndex; ++i) {
   689                 int oldHeight = d->itemHeight(i);
   695                 int oldHeight = d->itemHeight(i);
   690                 d->invalidateHeightCache(i);
   696                 d->invalidateHeightCache(i);
   691                 sizeChanged |= (oldHeight != d->itemHeight(i));
   697                 sizeChanged |= (oldHeight != d->itemHeight(i));
       
   698                 if (topLeft.column() == 0)
       
   699                     d->viewItems[i].hasChildren = d->hasVisibleChildren(d->viewItems.at(i).index);
   692             }
   700             }
   693         }
   701         }
   694     }
   702     }
   695 
   703 
   696     if (sizeChanged) {
   704     if (sizeChanged) {
   952     if (currentIndex().isValid())
   960     if (currentIndex().isValid())
   953         start = currentIndex();
   961         start = currentIndex();
   954     else
   962     else
   955         start = d->model->index(0, 0, d->root);
   963         start = d->model->index(0, 0, d->root);
   956 
   964 
   957     QTime now(QTime::currentTime());
       
   958     bool skipRow = false;
   965     bool skipRow = false;
   959     if (search.isEmpty()
   966     bool keyboardTimeWasValid = d->keyboardInputTime.isValid();
   960         || (d->keyboardInputTime.msecsTo(now) > QApplication::keyboardInputInterval())) {
   967     qint64 keyboardInputTimeElapsed = d->keyboardInputTime.restart();
       
   968     if (search.isEmpty() || !keyboardTimeWasValid
       
   969         || keyboardInputTimeElapsed > QApplication::keyboardInputInterval()) {
   961         d->keyboardInput = search;
   970         d->keyboardInput = search;
   962         skipRow = true;
   971         skipRow = currentIndex().isValid(); //if it is not valid we should really start at QModelIndex(0,0)
   963     } else {
   972     } else {
   964         d->keyboardInput += search;
   973         d->keyboardInput += search;
   965     }
   974     }
   966     d->keyboardInputTime = now;
       
   967 
   975 
   968     // special case for searches with same key like 'aaaaa'
   976     // special case for searches with same key like 'aaaaa'
   969     bool sameKey = false;
   977     bool sameKey = false;
   970     if (d->keyboardInput.length() > 1) {
   978     if (d->keyboardInput.length() > 1) {
   971         int c = d->keyboardInput.count(d->keyboardInput.at(d->keyboardInput.length() - 1));
   979         int c = d->keyboardInput.count(d->keyboardInput.at(d->keyboardInput.length() - 1));
  1226     case QEvent::HoverMove: {
  1234     case QEvent::HoverMove: {
  1227         QHoverEvent *he = static_cast<QHoverEvent*>(event);
  1235         QHoverEvent *he = static_cast<QHoverEvent*>(event);
  1228         int oldBranch = d->hoverBranch;
  1236         int oldBranch = d->hoverBranch;
  1229         d->hoverBranch = d->itemDecorationAt(he->pos());
  1237         d->hoverBranch = d->itemDecorationAt(he->pos());
  1230         if (oldBranch != d->hoverBranch) {
  1238         if (oldBranch != d->hoverBranch) {
  1231             QModelIndex oldIndex = d->modelIndex(oldBranch),
  1239             //we need to paint the whole items (including the decoration) so that when the user
  1232                 newIndex = d->modelIndex(d->hoverBranch);
  1240             //moves the mouse over those elements they are updated
  1233             if (oldIndex != newIndex) {
  1241             if (oldBranch >= 0) {
  1234                 QRect oldRect = visualRect(oldIndex);
  1242                 int y = d->coordinateForItem(oldBranch);
  1235                 QRect newRect = visualRect(newIndex);
  1243                 int h = d->itemHeight(oldBranch);
  1236                 oldRect.setLeft(oldRect.left() - d->indent);
  1244                 viewport()->update(QRect(0, y, viewport()->width(), h));
  1237                 newRect.setLeft(newRect.left() - d->indent);
  1245             }
  1238                 //we need to paint the whole items (including the decoration) so that when the user
  1246             if (d->hoverBranch >= 0) {
  1239                 //moves the mouse over those elements they are updated
  1247                 int y = d->coordinateForItem(d->hoverBranch);
  1240                 viewport()->update(oldRect);
  1248                 int h = d->itemHeight(d->hoverBranch);
  1241                 viewport()->update(newRect);
  1249                 viewport()->update(QRect(0, y, viewport()->width(), h));
  1242             }
  1250             }
  1243         }
  1251         }
  1244         break; }
  1252         break; }
  1245     default:
  1253     default:
  1246         break;
  1254         break;
  1991     Lays out the items in the tree view.
  1999     Lays out the items in the tree view.
  1992 */
  2000 */
  1993 void QTreeView::doItemsLayout()
  2001 void QTreeView::doItemsLayout()
  1994 {
  2002 {
  1995     Q_D(QTreeView);
  2003     Q_D(QTreeView);
       
  2004     if (d->hasRemovedItems) {
       
  2005         //clean the QSet that may contains old (and this invalid) indexes
       
  2006         d->hasRemovedItems = false;
       
  2007         QSet<QPersistentModelIndex>::iterator it = d->expandedIndexes.begin();
       
  2008         while (it != d->expandedIndexes.constEnd()) {
       
  2009             if (!it->isValid())
       
  2010                 it = d->expandedIndexes.erase(it);
       
  2011             else
       
  2012                 ++it;
       
  2013         }
       
  2014         it = d->hiddenIndexes.begin();
       
  2015         while (it != d->hiddenIndexes.constEnd()) {
       
  2016             if (!it->isValid())
       
  2017                 it = d->hiddenIndexes.erase(it);
       
  2018             else
       
  2019                 ++it;
       
  2020         }
       
  2021     }
  1996     d->viewItems.clear(); // prepare for new layout
  2022     d->viewItems.clear(); // prepare for new layout
  1997     QModelIndex parent = d->root;
  2023     QModelIndex parent = d->root;
  1998     if (d->model->hasChildren(parent)) {
  2024     if (d->model->hasChildren(parent)) {
  1999         d->layout(-1);
  2025         d->layout(-1);
  2000     }
  2026     }
  2132             return d->modelIndex(d->viewItems.count() - 1, current.column());
  2158             return d->modelIndex(d->viewItems.count() - 1, current.column());
  2133 #endif
  2159 #endif
  2134         return d->modelIndex(d->above(vi), current.column());
  2160         return d->modelIndex(d->above(vi), current.column());
  2135     case MoveLeft: {
  2161     case MoveLeft: {
  2136         QScrollBar *sb = horizontalScrollBar();
  2162         QScrollBar *sb = horizontalScrollBar();
  2137         if (vi < d->viewItems.count() && d->viewItems.at(vi).expanded && d->itemsExpandable && sb->value() == sb->minimum())
  2163         if (vi < d->viewItems.count() && d->viewItems.at(vi).expanded && d->itemsExpandable && sb->value() == sb->minimum()) {
  2138             d->collapse(vi, true);
  2164             d->collapse(vi, true);
  2139         else {
  2165             d->moveCursorUpdatedView = true;
       
  2166         } else {
  2140             bool descend = style()->styleHint(QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, 0, this);
  2167             bool descend = style()->styleHint(QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, 0, this);
  2141             if (descend) {
  2168             if (descend) {
  2142                 QModelIndex par = current.parent();
  2169                 QModelIndex par = current.parent();
  2143                 if (par.isValid() && par != rootIndex())
  2170                 if (par.isValid() && par != rootIndex())
  2144                     return par;
  2171                     return par;
  2154                     QModelIndex next = current.sibling(current.row(), newColumn);
  2181                     QModelIndex next = current.sibling(current.row(), newColumn);
  2155                     if (next.isValid())
  2182                     if (next.isValid())
  2156                         return next;
  2183                         return next;
  2157                 }
  2184                 }
  2158 
  2185 
       
  2186                 int oldValue = sb->value();
  2159                 sb->setValue(sb->value() - sb->singleStep());
  2187                 sb->setValue(sb->value() - sb->singleStep());
       
  2188                 if (oldValue != sb->value())
       
  2189                     d->moveCursorUpdatedView = true;
  2160             }
  2190             }
  2161 
  2191 
  2162         }
  2192         }
  2163         updateGeometries();
  2193         updateGeometries();
  2164         viewport()->update();
  2194         viewport()->update();
  2166     }
  2196     }
  2167     case MoveRight:
  2197     case MoveRight:
  2168         if (vi < d->viewItems.count() && !d->viewItems.at(vi).expanded && d->itemsExpandable
  2198         if (vi < d->viewItems.count() && !d->viewItems.at(vi).expanded && d->itemsExpandable
  2169             && d->hasVisibleChildren(d->viewItems.at(vi).index)) {
  2199             && d->hasVisibleChildren(d->viewItems.at(vi).index)) {
  2170             d->expand(vi, true);
  2200             d->expand(vi, true);
       
  2201             d->moveCursorUpdatedView = true;
  2171         } else {
  2202         } else {
  2172             bool descend = style()->styleHint(QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, 0, this);
  2203             bool descend = style()->styleHint(QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, 0, this);
  2173             if (descend) {
  2204             if (descend) {
  2174                 QModelIndex idx = d->modelIndex(d->below(vi));
  2205                 QModelIndex idx = d->modelIndex(d->below(vi));
  2175                 if (idx.parent() == current)
  2206                 if (idx.parent() == current)
  2188                         return next;
  2219                         return next;
  2189                 }
  2220                 }
  2190 
  2221 
  2191                 //last restort: we change the scrollbar value
  2222                 //last restort: we change the scrollbar value
  2192                 QScrollBar *sb = horizontalScrollBar();
  2223                 QScrollBar *sb = horizontalScrollBar();
       
  2224                 int oldValue = sb->value();
  2193                 sb->setValue(sb->value() + sb->singleStep());
  2225                 sb->setValue(sb->value() + sb->singleStep());
       
  2226                 if (oldValue != sb->value())
       
  2227                     d->moveCursorUpdatedView = true;
  2194             }
  2228             }
  2195         }
  2229         }
  2196         updateGeometries();
  2230         updateGeometries();
  2197         viewport()->update();
  2231         viewport()->update();
  2198         break;
  2232         break;
  2247 }
  2281 }
  2248 
  2282 
  2249 /*!
  2283 /*!
  2250   Returns the rectangle from the viewport of the items in the given
  2284   Returns the rectangle from the viewport of the items in the given
  2251   \a selection.
  2285   \a selection.
       
  2286 
       
  2287   Since 4.7, the returned region only contains rectangles intersecting
       
  2288   (or included in) the viewport.
  2252 */
  2289 */
  2253 QRegion QTreeView::visualRegionForSelection(const QItemSelection &selection) const
  2290 QRegion QTreeView::visualRegionForSelection(const QItemSelection &selection) const
  2254 {
  2291 {
  2255     Q_D(const QTreeView);
  2292     Q_D(const QTreeView);
  2256     if (selection.isEmpty())
  2293     if (selection.isEmpty())
  2257         return QRegion();
  2294         return QRegion();
  2258 
  2295 
  2259     QRegion selectionRegion;
  2296     QRegion selectionRegion;
       
  2297     const QRect &viewportRect = d->viewport->rect();
  2260     for (int i = 0; i < selection.count(); ++i) {
  2298     for (int i = 0; i < selection.count(); ++i) {
  2261         QItemSelectionRange range = selection.at(i);
  2299         QItemSelectionRange range = selection.at(i);
  2262         if (!range.isValid())
  2300         if (!range.isValid())
  2263             continue;
  2301             continue;
  2264         QModelIndex parent = range.parent();
  2302         QModelIndex parent = range.parent();
  2287         int bottom = rightRect.bottom();
  2325         int bottom = rightRect.bottom();
  2288         if (top > bottom)
  2326         if (top > bottom)
  2289             qSwap<int>(top, bottom);
  2327             qSwap<int>(top, bottom);
  2290         int height = bottom - top + 1;
  2328         int height = bottom - top + 1;
  2291         if (d->header->sectionsMoved()) {
  2329         if (d->header->sectionsMoved()) {
  2292             for (int c = range.left(); c <= range.right(); ++c)
  2330             for (int c = range.left(); c <= range.right(); ++c) {
  2293                 selectionRegion += QRegion(QRect(columnViewportPosition(c), top,
  2331                 const QRect rangeRect(columnViewportPosition(c), top, columnWidth(c), height);
  2294                                                  columnWidth(c), height));
  2332                 if (viewportRect.intersects(rangeRect))
       
  2333                     selectionRegion += rangeRect;
       
  2334             }
  2295         } else {
  2335         } else {
  2296             QRect combined = leftRect|rightRect;
  2336             QRect combined = leftRect|rightRect;
  2297             combined.setX(columnViewportPosition(isRightToLeft() ? range.right() : range.left()));
  2337             combined.setX(columnViewportPosition(isRightToLeft() ? range.right() : range.left()));
  2298             selectionRegion += combined;
  2338             if (viewportRect.intersects(combined))
       
  2339                 selectionRegion += combined;
  2299         }
  2340         }
  2300     }
  2341     }
  2301     return selectionRegion;
  2342     return selectionRegion;
  2302 }
  2343 }
  2303 
  2344 
  2400 {
  2441 {
  2401     // do nothing
  2442     // do nothing
  2402 }
  2443 }
  2403 
  2444 
  2404 /*!
  2445 /*!
  2405   \internal
       
  2406 */
       
  2407 static bool treeViewItemLessThan(const QTreeViewItem &left,
       
  2408                                  const QTreeViewItem &right)
       
  2409 {
       
  2410     if (left.level != right.level) {
       
  2411         Q_ASSERT(left.level > right.level);
       
  2412         QModelIndex leftParent = left.index.parent();
       
  2413         QModelIndex rightParent = right.index.parent();
       
  2414         // computer parent, don't get
       
  2415         while (leftParent.isValid() && leftParent.parent() != rightParent)
       
  2416             leftParent = leftParent.parent();
       
  2417         return (leftParent.row() < right.index.row());
       
  2418     }
       
  2419     return (left.index.row() < right.index.row());
       
  2420 }
       
  2421 
       
  2422 /*!
       
  2423   Informs the view that the rows from the \a start row to the \a end row
  2446   Informs the view that the rows from the \a start row to the \a end row
  2424   inclusive have been inserted into the \a parent model item.
  2447   inclusive have been inserted into the \a parent model item.
  2425 */
  2448 */
  2426 void QTreeView::rowsInserted(const QModelIndex &parent, int start, int end)
  2449 void QTreeView::rowsInserted(const QModelIndex &parent, int start, int end)
  2427 {
  2450 {
  2446     }
  2469     }
  2447 
  2470 
  2448     const int parentItem = d->viewIndex(parent);
  2471     const int parentItem = d->viewIndex(parent);
  2449     if (((parentItem != -1) && d->viewItems.at(parentItem).expanded && updatesEnabled())
  2472     if (((parentItem != -1) && d->viewItems.at(parentItem).expanded && updatesEnabled())
  2450         || (parent == d->root)) {
  2473         || (parent == d->root)) {
  2451         const uint childLevel = (parentItem == -1)
  2474         d->doDelayedItemsLayout();
  2452                                 ? uint(0) : d->viewItems.at(parentItem).level + 1;
       
  2453         const int firstChildItem = parentItem + 1;
       
  2454         const int lastChildItem = firstChildItem + ((parentItem == -1)
       
  2455                                                     ? d->viewItems.count()
       
  2456                                                     : d->viewItems.at(parentItem).total) - 1;
       
  2457 
       
  2458         if (parentRowCount == end + 1 && start > 0) {
       
  2459             //need to Update hasMoreSiblings
       
  2460             int previousRow = start - 1;
       
  2461             QModelIndex previousSibilingModelIndex = d->model->index(previousRow, 0, parent);
       
  2462             bool isHidden = d->isRowHidden(previousSibilingModelIndex);
       
  2463             while (isHidden && previousRow > 0) {
       
  2464                 previousRow--;
       
  2465                 previousSibilingModelIndex = d->model->index(previousRow, 0, parent);
       
  2466                 isHidden = d->isRowHidden(previousSibilingModelIndex);
       
  2467             }
       
  2468             if (!isHidden) {
       
  2469                 const int previousSibilling = d->viewIndex(previousSibilingModelIndex);
       
  2470                 if(previousSibilling != -1)
       
  2471                     d->viewItems[previousSibilling].hasMoreSiblings = true;
       
  2472             }
       
  2473         }
       
  2474 
       
  2475         QVector<QTreeViewItem> insertedItems(delta);
       
  2476         for (int i = 0; i < delta; ++i) {
       
  2477             QTreeViewItem &item = insertedItems[i];
       
  2478             item.index = d->model->index(i + start, 0, parent);
       
  2479             item.level = childLevel;
       
  2480             item.hasChildren = d->hasVisibleChildren(item.index);
       
  2481             item.hasMoreSiblings = !((i == delta - 1) && (parentRowCount == end +1));
       
  2482         }
       
  2483         if (d->viewItems.isEmpty())
       
  2484             d->defaultItemHeight = indexRowSizeHint(insertedItems[0].index);
       
  2485 
       
  2486         int insertPos;
       
  2487         if (lastChildItem < firstChildItem) { // no children
       
  2488             insertPos = firstChildItem;
       
  2489         } else {
       
  2490             // do a binary search to figure out where to insert
       
  2491             QVector<QTreeViewItem>::iterator it;
       
  2492             it = qLowerBound(d->viewItems.begin() + firstChildItem,
       
  2493                              d->viewItems.begin() + lastChildItem + 1,
       
  2494                              insertedItems.at(0), treeViewItemLessThan);
       
  2495             insertPos = it - d->viewItems.begin();
       
  2496 
       
  2497             // update stale model indexes of siblings
       
  2498             for (int item = insertPos; item <= lastChildItem; ) {
       
  2499                 Q_ASSERT(d->viewItems.at(item).level == childLevel);
       
  2500                 const QModelIndex modelIndex = d->viewItems.at(item).index;
       
  2501                 //Q_ASSERT(modelIndex.parent() == parent);
       
  2502                 d->viewItems[item].index = d->model->index(
       
  2503                     modelIndex.row() + delta, modelIndex.column(), parent);
       
  2504 
       
  2505                 if (!d->viewItems[item].index.isValid()) {
       
  2506                     // Something really bad is happening, a bad model is
       
  2507                     // often the cause.  We can't optimize in this case :(
       
  2508                     qWarning() << "QTreeView::rowsInserted internal representation of the model has been corrupted, resetting.";
       
  2509                     doItemsLayout();
       
  2510                     return;
       
  2511                 }
       
  2512 
       
  2513                 item += d->viewItems.at(item).total + 1;
       
  2514             }
       
  2515         }
       
  2516 
       
  2517         d->viewItems.insert(insertPos, delta, insertedItems.at(0));
       
  2518         if (delta > 1) {
       
  2519             qCopy(insertedItems.begin() + 1, insertedItems.end(),
       
  2520                   d->viewItems.begin() + insertPos + 1);
       
  2521         }
       
  2522 
       
  2523         if (parentItem != -1)
       
  2524             d->viewItems[parentItem].hasChildren = true;
       
  2525         d->updateChildCount(parentItem, delta);
       
  2526 
       
  2527         updateGeometries();
       
  2528         viewport()->update();
       
  2529     } else if ((parentItem != -1) && d->viewItems.at(parentItem).expanded) {
  2475     } else if ((parentItem != -1) && d->viewItems.at(parentItem).expanded) {
  2530         d->doDelayedItemsLayout();
  2476         d->doDelayedItemsLayout();
  2531     } else if (parentItem != -1 && (d->model->rowCount(parent) == end - start + 1)) {
  2477     } else if (parentItem != -1 && (d->model->rowCount(parent) == end - start + 1)) {
  2532         // the parent just went from 0 children to more. update to re-paint the decoration
  2478         // the parent just went from 0 children to more. update to re-paint the decoration
  2533         d->viewItems[parentItem].hasChildren = true;
  2479         d->viewItems[parentItem].hasChildren = true;
  2541   inclusive are about to removed from the given \a parent model item.
  2487   inclusive are about to removed from the given \a parent model item.
  2542 */
  2488 */
  2543 void QTreeView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
  2489 void QTreeView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
  2544 {
  2490 {
  2545     Q_D(QTreeView);
  2491     Q_D(QTreeView);
  2546     d->rowsRemoved(parent, start, end, false);
       
  2547     QAbstractItemView::rowsAboutToBeRemoved(parent, start, end);
  2492     QAbstractItemView::rowsAboutToBeRemoved(parent, start, end);
       
  2493     d->viewItems.clear();
  2548 }
  2494 }
  2549 
  2495 
  2550 /*!
  2496 /*!
  2551     \since 4.1
  2497     \since 4.1
  2552 
  2498 
  2554     inclusive have been removed from the given \a parent model item.
  2500     inclusive have been removed from the given \a parent model item.
  2555 */
  2501 */
  2556 void QTreeView::rowsRemoved(const QModelIndex &parent, int start, int end)
  2502 void QTreeView::rowsRemoved(const QModelIndex &parent, int start, int end)
  2557 {
  2503 {
  2558     Q_D(QTreeView);
  2504     Q_D(QTreeView);
  2559     d->rowsRemoved(parent, start, end, true);
  2505     d->viewItems.clear();
       
  2506     d->doDelayedItemsLayout();
       
  2507     d->hasRemovedItems = true;
       
  2508     d->_q_rowsRemoved(parent, start, end);
  2560 }
  2509 }
  2561 
  2510 
  2562 /*!
  2511 /*!
  2563   Informs the tree view that the number of columns in the tree view has
  2512   Informs the tree view that the number of columns in the tree view has
  2564   changed from \a oldCount to \a newCount.
  2513   changed from \a oldCount to \a newCount.
  2656 */
  2605 */
  2657 void QTreeView::expandAll()
  2606 void QTreeView::expandAll()
  2658 {
  2607 {
  2659     Q_D(QTreeView);
  2608     Q_D(QTreeView);
  2660     d->viewItems.clear();
  2609     d->viewItems.clear();
  2661     d->expandedIndexes.clear();
       
  2662     d->interruptDelayedItemsLayout();
  2610     d->interruptDelayedItemsLayout();
  2663     d->layout(-1);
  2611     d->layout(-1, true);
  2664     for (int i = 0; i < d->viewItems.count(); ++i) {
       
  2665         if (d->viewItems[i].expanded)
       
  2666             continue;
       
  2667         d->viewItems[i].expanded = true;
       
  2668         d->layout(i);
       
  2669         QModelIndex idx = d->viewItems.at(i).index;
       
  2670         d->expandedIndexes.insert(idx);
       
  2671     }
       
  2672     updateGeometries();
  2612     updateGeometries();
  2673     d->viewport->update();
  2613     d->viewport->update();
  2674 }
  2614 }
  2675 
  2615 
  2676 /*!
  2616 /*!
  2947             beginAnimatedOperation();
  2887             beginAnimatedOperation();
  2948 #endif //QT_NO_ANIMATION
  2888 #endif //QT_NO_ANIMATION
  2949     }
  2889     }
  2950 }
  2890 }
  2951 
  2891 
       
  2892 void QTreeViewPrivate::insertViewItems(int pos, int count, const QTreeViewItem &viewItem)
       
  2893 {
       
  2894     viewItems.insert(pos, count, viewItem);
       
  2895     QTreeViewItem *items = viewItems.data();
       
  2896     for (int i = pos + count; i < viewItems.count(); i++)
       
  2897         if (items[i].parentItem >= pos)
       
  2898             items[i].parentItem += count;
       
  2899 }
       
  2900 
       
  2901 void QTreeViewPrivate::removeViewItems(int pos, int count)
       
  2902 {
       
  2903     viewItems.remove(pos, count);
       
  2904     QTreeViewItem *items = viewItems.data();
       
  2905     for (int i = pos; i < viewItems.count(); i++)
       
  2906         if (items[i].parentItem >= pos)
       
  2907             items[i].parentItem -= count;
       
  2908 }
       
  2909 
       
  2910 #if 0
       
  2911 bool QTreeViewPrivate::checkViewItems() const
       
  2912 {
       
  2913     for (int i = 0; i < viewItems.count(); ++i) {
       
  2914         const QTreeViewItem &vi = viewItems.at(i);
       
  2915         if (vi.parentItem == -1) {
       
  2916             Q_ASSERT(!vi.index.parent().isValid() || vi.index.parent() == root);
       
  2917         } else {
       
  2918             Q_ASSERT(vi.index.parent() == viewItems.at(vi.parentItem).index);
       
  2919         }
       
  2920     }
       
  2921     return true;
       
  2922 }
       
  2923 #endif
       
  2924 
  2952 void QTreeViewPrivate::collapse(int item, bool emitSignal)
  2925 void QTreeViewPrivate::collapse(int item, bool emitSignal)
  2953 {
  2926 {
  2954     Q_Q(QTreeView);
  2927     Q_Q(QTreeView);
  2955 
  2928 
  2956     if (item == -1 || expandedIndexes.isEmpty())
  2929     if (item == -1 || expandedIndexes.isEmpty())
  2975     QAbstractItemView::State oldState = state;
  2948     QAbstractItemView::State oldState = state;
  2976     q->setState(QAbstractItemView::CollapsingState);
  2949     q->setState(QAbstractItemView::CollapsingState);
  2977     expandedIndexes.erase(it);
  2950     expandedIndexes.erase(it);
  2978     viewItems[item].expanded = false;
  2951     viewItems[item].expanded = false;
  2979     int index = item;
  2952     int index = item;
  2980     QModelIndex parent = modelIndex;
  2953     while (index > -1) {
  2981     while (parent.isValid() && parent != root) {
       
  2982         Q_ASSERT(index > -1);
       
  2983         viewItems[index].total -= total;
  2954         viewItems[index].total -= total;
  2984         parent = parent.parent();
  2955         index = viewItems[index].parentItem;
  2985         index = viewIndex(parent);
  2956     }
  2986     }
  2957     removeViewItems(item + 1, total); // collapse
  2987     viewItems.remove(item + 1, total); // collapse
       
  2988     q->setState(oldState);
  2958     q->setState(oldState);
  2989 
  2959 
  2990     if (emitSignal) {
  2960     if (emitSignal) {
  2991         emit q->collapsed(modelIndex);
  2961         emit q->collapsed(modelIndex);
  2992 #ifndef QT_NO_ANIMATION
  2962 #ifndef QT_NO_ANIMATION
  3119     if (start <= 0 && 0 <= end)
  3089     if (start <= 0 && 0 <= end)
  3120         doDelayedItemsLayout();
  3090         doDelayedItemsLayout();
  3121     QAbstractItemViewPrivate::_q_columnsRemoved(parent, start, end);
  3091     QAbstractItemViewPrivate::_q_columnsRemoved(parent, start, end);
  3122 }
  3092 }
  3123 
  3093 
  3124 void QTreeViewPrivate::layout(int i)
  3094 /** \internal
       
  3095     creates and initialize the viewItem structure of the children of the element \i
       
  3096 
       
  3097     set \a recursiveExpanding if the function has to expand all the children (called from expandAll)
       
  3098     \a afterIsUninitialized is when we recurse from layout(-1), it means all the items after 'i' are
       
  3099     not yet initialized and need not to be moved
       
  3100  */
       
  3101 void QTreeViewPrivate::layout(int i, bool recursiveExpanding, bool afterIsUninitialized)
  3125 {
  3102 {
  3126     Q_Q(QTreeView);
  3103     Q_Q(QTreeView);
  3127     QModelIndex current;
  3104     QModelIndex current;
  3128     QModelIndex parent = (i < 0) ? (QModelIndex)root : modelIndex(i);
  3105     QModelIndex parent = (i < 0) ? (QModelIndex)root : modelIndex(i);
  3129 
  3106 
  3146         if (uniformRowHeights) {
  3123         if (uniformRowHeights) {
  3147             QModelIndex index = model->index(0, 0, parent);
  3124             QModelIndex index = model->index(0, 0, parent);
  3148             defaultItemHeight = q->indexRowSizeHint(index);
  3125             defaultItemHeight = q->indexRowSizeHint(index);
  3149         }
  3126         }
  3150         viewItems.resize(count);
  3127         viewItems.resize(count);
       
  3128         afterIsUninitialized = true;
  3151     } else if (viewItems[i].total != (uint)count) {
  3129     } else if (viewItems[i].total != (uint)count) {
  3152             viewItems.insert(i + 1, count, QTreeViewItem()); // expand
  3130         if (!afterIsUninitialized)
       
  3131             insertViewItems(i + 1, count, QTreeViewItem()); // expand
       
  3132         else if (count > 0)
       
  3133             viewItems.resize(viewItems.count() + count);
  3153     } else {
  3134     } else {
  3154         expanding = false;
  3135         expanding = false;
  3155     }
  3136     }
  3156 
  3137 
  3157     int first = i + 1;
  3138     int first = i + 1;
  3169             last = j - hidden + children;
  3150             last = j - hidden + children;
  3170             if (item)
  3151             if (item)
  3171                 item->hasMoreSiblings = true;
  3152                 item->hasMoreSiblings = true;
  3172             item = &viewItems[last];
  3153             item = &viewItems[last];
  3173             item->index = current;
  3154             item->index = current;
       
  3155             item->parentItem = i;
  3174             item->level = level;
  3156             item->level = level;
  3175             item->height = 0;
  3157             item->height = 0;
  3176             item->spanning = q->isFirstColumnSpanned(current.row(), parent);
  3158             item->spanning = q->isFirstColumnSpanned(current.row(), parent);
  3177             item->expanded = false;
  3159             item->expanded = false;
  3178             item->total = 0;
  3160             item->total = 0;
  3179             item->hasMoreSiblings = false;
  3161             item->hasMoreSiblings = false;
  3180             if (isIndexExpanded(current)) {
  3162             if (recursiveExpanding || isIndexExpanded(current)) {
       
  3163                 if (recursiveExpanding)
       
  3164                     expandedIndexes.insert(current);
  3181                 item->expanded = true;
  3165                 item->expanded = true;
  3182                 layout(last);
  3166                 layout(last, recursiveExpanding, afterIsUninitialized);
  3183                 item = &viewItems[last];
  3167                 item = &viewItems[last];
  3184                 children += item->total;
  3168                 children += item->total;
  3185                 item->hasChildren = item->total > 0;
  3169                 item->hasChildren = item->total > 0;
  3186                 last = j - hidden + children;
  3170                 last = j - hidden + children;
  3187             } else {
  3171             } else {
  3189             }
  3173             }
  3190         }
  3174         }
  3191     }
  3175     }
  3192 
  3176 
  3193     // remove hidden items
  3177     // remove hidden items
  3194     if (hidden > 0)
  3178     if (hidden > 0) {
  3195         viewItems.remove(last + 1, hidden); // collapse
  3179         if (!afterIsUninitialized)
       
  3180             removeViewItems(last + 1, hidden);
       
  3181         else
       
  3182             viewItems.resize(viewItems.size() - hidden);
       
  3183     }
  3196 
  3184 
  3197     if (!expanding)
  3185     if (!expanding)
  3198         return; // nothing changed
  3186         return; // nothing changed
  3199 
  3187 
  3200     while (parent != root) {
  3188     while (i > -1) {
  3201         Q_ASSERT(i > -1);
       
  3202         viewItems[i].total += count - hidden;
  3189         viewItems[i].total += count - hidden;
  3203         parent = parent.parent();
  3190         i = viewItems[i].parentItem;
  3204         i = viewIndex(parent);
       
  3205     }
  3191     }
  3206 }
  3192 }
  3207 
  3193 
  3208 int QTreeViewPrivate::pageUp(int i) const
  3194 int QTreeViewPrivate::pageUp(int i) const
  3209 {
  3195 {
  3210     int index = itemAtCoordinate(coordinateForItem(i) - viewport->height());
  3196     int index = itemAtCoordinate(coordinateForItem(i) - viewport->height());
       
  3197     while (isItemHiddenOrDisabled(index))
       
  3198         index--;
  3211     return index == -1 ? 0 : index;
  3199     return index == -1 ? 0 : index;
  3212 }
  3200 }
  3213 
  3201 
  3214 int QTreeViewPrivate::pageDown(int i) const
  3202 int QTreeViewPrivate::pageDown(int i) const
  3215 {
  3203 {
  3216     int index = itemAtCoordinate(coordinateForItem(i) + viewport->height());
  3204     int index = itemAtCoordinate(coordinateForItem(i) + viewport->height());
       
  3205     while (isItemHiddenOrDisabled(index))
       
  3206         index++;
  3217     return index == -1 ? viewItems.count() - 1 : index;
  3207     return index == -1 ? viewItems.count() - 1 : index;
  3218 }
  3208 }
  3219 
  3209 
  3220 int QTreeViewPrivate::indentationForItem(int item) const
  3210 int QTreeViewPrivate::indentationForItem(int item) const
  3221 {
  3211 {
  3354     if (!_index.isValid() || viewItems.isEmpty())
  3344     if (!_index.isValid() || viewItems.isEmpty())
  3355         return -1;
  3345         return -1;
  3356 
  3346 
  3357     const int totalCount = viewItems.count();
  3347     const int totalCount = viewItems.count();
  3358     const QModelIndex index = _index.sibling(_index.row(), 0);
  3348     const QModelIndex index = _index.sibling(_index.row(), 0);
  3359 
  3349     const int row = index.row();
  3360 
  3350     const qint64 internalId = index.internalId();
  3361     // A quick check near the last item to see if we are just incrementing
  3351 
  3362     const int start = lastViewedItem > 2 ? lastViewedItem - 2 : 0;
  3352     // We start nearest to the lastViewedItem
  3363     const int end = lastViewedItem < totalCount - 2 ? lastViewedItem + 2 : totalCount;
  3353     int localCount = qMin(lastViewedItem - 1, totalCount - lastViewedItem);
  3364     int row = index.row();
  3354     for (int i = 0; i < localCount; ++i) {
  3365     for (int i = start; i < end; ++i) {
  3355         const QModelIndex &idx1 = viewItems.at(lastViewedItem + i).index;
  3366         const QModelIndex &idx = viewItems.at(i).index;
  3356         if (idx1.row() == row && idx1.internalId() == internalId) {
  3367         if (idx.row() == row) {
  3357             lastViewedItem = lastViewedItem + i;
  3368             if (idx.internalId() == index.internalId()) {
  3358             return lastViewedItem;
  3369                 lastViewedItem = i;
  3359         }
  3370                 return i;
  3360         const QModelIndex &idx2 = viewItems.at(lastViewedItem - i - 1).index;
  3371             }
  3361         if (idx2.row() == row && idx2.internalId() == internalId) {
  3372         }
  3362             lastViewedItem = lastViewedItem - i - 1;
  3373     }
  3363             return lastViewedItem;
  3374 
  3364         }
  3375     // NOTE: this function is slow if the item is outside the visible area
  3365     }
  3376     // search in visible items first and below
  3366 
  3377     int t = firstVisibleItem();
  3367     for (int j = qMax(0, lastViewedItem + localCount); j < totalCount; ++j) {
  3378     t = t > 100 ? t - 100 : 0; // start 100 items above the visible area
       
  3379 
       
  3380     for (int i = t; i < totalCount; ++i) {
       
  3381         const QModelIndex &idx = viewItems.at(i).index;
       
  3382         if (idx.row() == row) {
       
  3383             if (idx.internalId() == index.internalId()) {
       
  3384                 lastViewedItem = i;
       
  3385                 return i;
       
  3386             }
       
  3387         }
       
  3388     }
       
  3389     // search from top to first visible
       
  3390     for (int j = 0; j < t; ++j) {
       
  3391         const QModelIndex &idx = viewItems.at(j).index;
  3368         const QModelIndex &idx = viewItems.at(j).index;
  3392         if (idx.row() == row) {
  3369         if (idx.row() == row && idx.internalId() == internalId) {
  3393             if (idx.internalId() == index.internalId()) {
  3370             lastViewedItem = j;
  3394                 lastViewedItem = j;
  3371             return j;
  3395                 return j;
  3372         }
  3396             }
  3373     }
  3397         }
  3374     for (int j = qMin(totalCount, lastViewedItem - localCount) - 1; j >= 0; --j) {
  3398     }
  3375         const QModelIndex &idx = viewItems.at(j).index;
       
  3376         if (idx.row() == row && idx.internalId() == internalId) {
       
  3377             lastViewedItem = j;
       
  3378             return j;
       
  3379         }
       
  3380     }
       
  3381 
  3399     // nothing found
  3382     // nothing found
  3400     return -1;
  3383     return -1;
  3401 }
  3384 }
  3402 
  3385 
  3403 QModelIndex QTreeViewPrivate::modelIndex(int i, int column) const
  3386 QModelIndex QTreeViewPrivate::modelIndex(int i, int column) const
  3442 
  3425 
  3443 int QTreeViewPrivate::columnAt(int x) const
  3426 int QTreeViewPrivate::columnAt(int x) const
  3444 {
  3427 {
  3445     return header->logicalIndexAt(x);
  3428     return header->logicalIndexAt(x);
  3446 }
  3429 }
  3447 
       
  3448 void QTreeViewPrivate::relayout(const QModelIndex &parent)
       
  3449 {
       
  3450     Q_Q(QTreeView);
       
  3451     // do a local relayout of the items
       
  3452     if (parent.isValid()) {
       
  3453         int parentViewIndex = viewIndex(parent);
       
  3454         if (parentViewIndex > -1 && viewItems.at(parentViewIndex).expanded) {
       
  3455             collapse(parentViewIndex, false); // remove the current layout
       
  3456             expand(parentViewIndex, false); // do the relayout
       
  3457             q->updateGeometries();
       
  3458             viewport->update();
       
  3459         }
       
  3460     } else {
       
  3461         viewItems.clear();
       
  3462         q->doItemsLayout();
       
  3463     }
       
  3464 }
       
  3465 
       
  3466 
  3430 
  3467 void QTreeViewPrivate::updateScrollBars()
  3431 void QTreeViewPrivate::updateScrollBars()
  3468 {
  3432 {
  3469     Q_Q(QTreeView);
  3433     Q_Q(QTreeView);
  3470     QSize viewportSize = viewport->size();
  3434     QSize viewportSize = viewport->size();
  3715             return true;
  3679             return true;
  3716     }
  3680     }
  3717     return false;
  3681     return false;
  3718 }
  3682 }
  3719 
  3683 
  3720 void QTreeViewPrivate::rowsRemoved(const QModelIndex &parent,
       
  3721                                    int start, int end, bool after)
       
  3722 {
       
  3723     Q_Q(QTreeView);
       
  3724     // if we are going to do a complete relayout anyway, there is no need to update
       
  3725     if (delayedPendingLayout) {
       
  3726         _q_rowsRemoved(parent, start, end);
       
  3727         return;
       
  3728     }
       
  3729 
       
  3730     const int parentItem = viewIndex(parent);
       
  3731     if ((parentItem != -1) || (parent == root)) {
       
  3732 
       
  3733         const uint childLevel = (parentItem == -1)
       
  3734                                 ? uint(0) : viewItems.at(parentItem).level + 1;
       
  3735         Q_UNUSED(childLevel); // unused in release mode, used in assert below
       
  3736 
       
  3737         const int firstChildItem = parentItem + 1;
       
  3738         int lastChildItem = firstChildItem + ((parentItem == -1)
       
  3739                                               ? viewItems.count()
       
  3740                                               : viewItems.at(parentItem).total) - 1;
       
  3741 
       
  3742         const int delta = end - start + 1;
       
  3743 
       
  3744         int previousSibiling = -1;
       
  3745         int removedCount = 0;
       
  3746         for (int item = firstChildItem; item <= lastChildItem; ) {
       
  3747             Q_ASSERT(viewItems.at(item).level == childLevel);
       
  3748             const QModelIndex modelIndex = viewItems.at(item).index;
       
  3749             //Q_ASSERT(modelIndex.parent() == parent);
       
  3750             const int count = viewItems.at(item).total + 1;
       
  3751             if (modelIndex.row() < start) {
       
  3752                 previousSibiling = item;
       
  3753                 // not affected by the removal
       
  3754                 item += count;
       
  3755             } else if (modelIndex.row() <= end) {
       
  3756                 // removed
       
  3757                 viewItems.remove(item, count);
       
  3758                 removedCount += count;
       
  3759                 lastChildItem -= count;
       
  3760             } else {
       
  3761                 if (after) {
       
  3762                     // moved; update the model index
       
  3763                     viewItems[item].index = model->index(
       
  3764                         modelIndex.row() - delta, modelIndex.column(), parent);
       
  3765                 }
       
  3766                 item += count;
       
  3767             }
       
  3768         }
       
  3769 
       
  3770         if (previousSibiling != -1 && after && model->rowCount(parent) == start)
       
  3771             viewItems[previousSibiling].hasMoreSiblings = false;
       
  3772 
       
  3773         if (parentItem != -1) {
       
  3774             if (viewItems.at(parentItem).expanded) {
       
  3775                 updateChildCount(parentItem, -removedCount);
       
  3776                 if (viewItems.at(parentItem).total == 0)
       
  3777                     viewItems[parentItem].hasChildren = false; //every children have been removed;
       
  3778             } else if (viewItems[parentItem].hasChildren && !hasVisibleChildren(parent)) {
       
  3779                 viewItems[parentItem].hasChildren = false;
       
  3780             }
       
  3781         }
       
  3782         if (after) {
       
  3783             q->updateGeometries();
       
  3784             viewport->update();
       
  3785         } else {
       
  3786             //we have removed items: we should at least update the scroll bar values.
       
  3787             // They are used to determine the item geometry.
       
  3788             updateScrollBars();
       
  3789         }
       
  3790     } else {
       
  3791         // If an ancestor of root is removed then relayout
       
  3792         QModelIndex idx = root;
       
  3793         while (idx.isValid()) {
       
  3794             idx = idx.parent();
       
  3795             if (idx == parent) {
       
  3796                 doDelayedItemsLayout();
       
  3797                 break;
       
  3798             }
       
  3799         }
       
  3800     }
       
  3801     _q_rowsRemoved(parent, start, end);
       
  3802 
       
  3803     QSet<QPersistentModelIndex>::iterator it = expandedIndexes.begin();
       
  3804     while (it != expandedIndexes.constEnd()) {
       
  3805         if (!it->isValid())
       
  3806             it = expandedIndexes.erase(it);
       
  3807         else
       
  3808             ++it;
       
  3809     }
       
  3810     it = hiddenIndexes.begin();
       
  3811     while (it != hiddenIndexes.constEnd()) {
       
  3812         if (!it->isValid())
       
  3813             it = hiddenIndexes.erase(it);
       
  3814         else
       
  3815             ++it;
       
  3816     }
       
  3817 }
       
  3818 
       
  3819 void QTreeViewPrivate::updateChildCount(const int parentItem, const int delta)
       
  3820 {
       
  3821     if ((parentItem != -1) && delta) {
       
  3822         int level = viewItems.at(parentItem).level;
       
  3823         int item = parentItem;
       
  3824         do {
       
  3825             Q_ASSERT(item >= 0);
       
  3826             for ( ; int(viewItems.at(item).level) != level; --item) ;
       
  3827             viewItems[item].total += delta;
       
  3828             --level;
       
  3829         } while (level >= 0);
       
  3830     }
       
  3831 }
       
  3832 
       
  3833 
       
  3834 void QTreeViewPrivate::_q_sortIndicatorChanged(int column, Qt::SortOrder order)
  3684 void QTreeViewPrivate::_q_sortIndicatorChanged(int column, Qt::SortOrder order)
  3835 {
  3685 {
  3836     model->sort(column, order);
  3686     model->sort(column, order);
  3837 }
  3687 }
  3838 
  3688