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; |
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) |
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; |
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. |
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 |
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 |