00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "qtreeview.h"
00024
00025 #ifndef QT_NO_TREEVIEW
00026 #include <qheaderview.h>
00027 #include <qitemdelegate.h>
00028 #include <qapplication.h>
00029 #include <qscrollbar.h>
00030 #include <qpainter.h>
00031 #include <qstack.h>
00032 #include <qstyle.h>
00033 #include <qstyleoption.h>
00034 #include <qevent.h>
00035 #include <qpen.h>
00036 #include <qdebug.h>
00037
00038 #include <private/qtreeview_p.h>
00039
00156 QTreeView::QTreeView(QWidget *parent)
00157 : QAbstractItemView(*new QTreeViewPrivate, parent)
00158 {
00159 Q_D(QTreeView);
00160 d->initialize();
00161 }
00162
00166 QTreeView::QTreeView(QTreeViewPrivate &dd, QWidget *parent)
00167 : QAbstractItemView(dd, parent)
00168 {
00169 Q_D(QTreeView);
00170 d->initialize();
00171 }
00172
00176 QTreeView::~QTreeView()
00177 {
00178 }
00179
00183 void QTreeView::setModel(QAbstractItemModel *model)
00184 {
00185 Q_D(QTreeView);
00186 if (d->selectionModel) {
00187 disconnect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
00188 d->model, SLOT(submit()));
00189 disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
00190 this, SLOT(rowsRemoved(QModelIndex,int,int)));
00191 }
00192 d->viewItems.clear();
00193 d->expandedIndexes.clear();
00194 d->hiddenIndexes.clear();
00195 d->header->setModel(model);
00196 QAbstractItemView::setModel(model);
00197
00198
00199 disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
00200 this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
00201
00202 disconnect(d->model, SIGNAL(layoutChanged()),
00203 d->header, SLOT(doItemsLayout()));
00204
00205 connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
00206 this, SLOT(rowsRemoved(QModelIndex,int,int)));
00207
00208 if (d->sortingEnabled)
00209 sortByColumn(header()->sortIndicatorSection());
00210 }
00211
00215 void QTreeView::setRootIndex(const QModelIndex &index)
00216 {
00217 Q_D(QTreeView);
00218 d->header->setRootIndex(index);
00219 QAbstractItemView::setRootIndex(index);
00220 }
00221
00225 void QTreeView::setSelectionModel(QItemSelectionModel *selectionModel)
00226 {
00227 Q_D(QTreeView);
00228 Q_ASSERT(selectionModel);
00229 if (d->selectionModel) {
00230 if (d->allColumnsShowFocus) {
00231 QObject::disconnect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
00232 this, SLOT(_q_currentChanged(QModelIndex,QModelIndex)));
00233 }
00234
00235 disconnect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
00236 d->model, SLOT(submit()));
00237 }
00238
00239 d->header->setSelectionModel(selectionModel);
00240 QAbstractItemView::setSelectionModel(selectionModel);
00241
00242 if (d->selectionModel) {
00243 if (d->allColumnsShowFocus) {
00244 QObject::connect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
00245 this, SLOT(_q_currentChanged(QModelIndex,QModelIndex)));
00246 }
00247
00248 connect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
00249 d->model, SLOT(submit()));
00250 }
00251 }
00252
00258 QHeaderView *QTreeView::header() const
00259 {
00260 Q_D(const QTreeView);
00261 return d->header;
00262 }
00263
00272 void QTreeView::setHeader(QHeaderView *header)
00273 {
00274 Q_D(QTreeView);
00275 if (header == d->header || !header)
00276 return;
00277 if (d->header && d->header->parent() == this)
00278 delete d->header;
00279 d->header = header;
00280 d->header->setParent(this);
00281
00282 if (!d->header->model())
00283 d->header->setModel(d->model);
00284
00285 connect(d->header, SIGNAL(sectionResized(int,int,int)),
00286 this, SLOT(columnResized(int,int,int)));
00287 connect(d->header, SIGNAL(sectionMoved(int,int,int)),
00288 this, SLOT(columnMoved()));
00289 connect(d->header, SIGNAL(sectionCountChanged(int,int)),
00290 this, SLOT(columnCountChanged(int,int)));
00291 connect(d->header, SIGNAL(sectionHandleDoubleClicked(int)),
00292 this, SLOT(resizeColumnToContents(int)));
00293 connect(d->header, SIGNAL(geometriesChanged()),
00294 this, SLOT(updateGeometries()));
00295 d->header->setFocusProxy(this);
00296
00297 setSortingEnabled(d->sortingEnabled);
00298 }
00299
00309 int QTreeView::indentation() const
00310 {
00311 Q_D(const QTreeView);
00312 return d->indent;
00313 }
00314
00315 void QTreeView::setIndentation(int i)
00316 {
00317 Q_D(QTreeView);
00318 if (i != d->indent) {
00319 d->indent = i;
00320 d->viewport->update();
00321 }
00322 }
00323
00335 bool QTreeView::rootIsDecorated() const
00336 {
00337 Q_D(const QTreeView);
00338 return d->rootDecoration;
00339 }
00340
00341 void QTreeView::setRootIsDecorated(bool show)
00342 {
00343 Q_D(QTreeView);
00344 if (show != d->rootDecoration) {
00345 d->rootDecoration = show;
00346 d->viewport->update();
00347 }
00348 }
00349
00358 bool QTreeView::uniformRowHeights() const
00359 {
00360 Q_D(const QTreeView);
00361 return d->uniformRowHeights;
00362 }
00363
00364 void QTreeView::setUniformRowHeights(bool uniform)
00365 {
00366 Q_D(QTreeView);
00367 d->uniformRowHeights = uniform;
00368 }
00369
00378 bool QTreeView::itemsExpandable() const
00379 {
00380 Q_D(const QTreeView);
00381 return d->itemsExpandable;
00382 }
00383
00384 void QTreeView::setItemsExpandable(bool enable)
00385 {
00386 Q_D(QTreeView);
00387 d->itemsExpandable = enable;
00388 }
00389
00393 int QTreeView::columnViewportPosition(int column) const
00394 {
00395 Q_D(const QTreeView);
00396 return d->header->sectionViewportPosition(column);
00397 }
00398
00404 int QTreeView::columnWidth(int column) const
00405 {
00406 Q_D(const QTreeView);
00407 return d->header->sectionSize(column);
00408 }
00409
00417 void QTreeView::setColumnWidth(int column, int width)
00418 {
00419 Q_D(QTreeView);
00420 d->header->resizeSection(column, width);
00421 }
00422
00427 int QTreeView::columnAt(int x) const
00428 {
00429 Q_D(const QTreeView);
00430 return d->header->logicalIndexAt(x);
00431 }
00432
00438 bool QTreeView::isColumnHidden(int column) const
00439 {
00440 Q_D(const QTreeView);
00441 return d->header->isSectionHidden(column);
00442 }
00443
00449 void QTreeView::setColumnHidden(int column, bool hide)
00450 {
00451 Q_D(QTreeView);
00452 if (column < 0 || column >= d->header->count())
00453 return;
00454 d->header->setSectionHidden(column, hide);
00455 }
00456
00463 bool QTreeView::isRowHidden(int row, const QModelIndex &parent) const
00464 {
00465 Q_D(const QTreeView);
00466 if (d->hiddenIndexes.isEmpty() || !d->model)
00467 return false;
00468 QModelIndex index = d->model->index(row, 0, parent);
00469 for (int i = 0; i < d->hiddenIndexes.count(); ++i)
00470 if (d->hiddenIndexes.at(i) == index)
00471 return true;
00472 return false;
00473 }
00474
00480 void QTreeView::setRowHidden(int row, const QModelIndex &parent, bool hide)
00481 {
00482 Q_D(QTreeView);
00483 if (!d->model)
00484 return;
00485 QModelIndex index = d->model->index(row, 0, parent);
00486 if (!index.isValid())
00487 return;
00488
00489 if (hide) {
00490 QPersistentModelIndex persistent(index);
00491 if (!d->hiddenIndexes.contains(persistent)) d->hiddenIndexes.append(persistent);
00492 } else {
00493 QPersistentModelIndex persistent(index);
00494 int i = d->hiddenIndexes.indexOf(persistent);
00495 if (i >= 0) d->hiddenIndexes.remove(i);
00496 }
00497
00498 if (hide && isVisible()) {
00499 int p = d->viewIndex(parent);
00500 if (p >= 0) {
00501 const int first = p + 1;
00502 const int last = first + d->viewItems.at(p).total - 1;
00503 for (int i = first; i <= last; ) {
00504 const int count = d->viewItems.at(i).total + 1;
00505 if (d->viewItems.at(i).index == index) {
00506
00507 d->viewItems.remove(i, count);
00508
00509 int level = d->viewItems.at(p).level;
00510 do {
00511 for ( ; int(d->viewItems.at(p).level) != level; --p) ;
00512 d->viewItems[p].total -= count;
00513 --level;
00514 } while (level >= 0);
00515 break;
00516 } else {
00517 i += count;
00518 }
00519 }
00520 updateGeometries();
00521 d->viewport->update();
00522 }
00523 else
00524 d->doDelayedItemsLayout();
00525 } else {
00526 d->doDelayedItemsLayout();
00527 }
00528 }
00529
00533 void QTreeView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
00534 {
00535 Q_D(QTreeView);
00536
00537
00538 if (d->delayedLayout.isActive())
00539 return;
00540
00541
00542
00543
00544 QModelIndex top = (topLeft.column() == 0) ? topLeft
00545 : d->model->sibling(topLeft.row(), 0, topLeft);
00546 int topViewIndex = d->viewIndex(top);
00547 bool sizeChanged = false;
00548 if (topViewIndex != -1) {
00549 if (topLeft == bottomRight) {
00550 int oldHeight = d->itemHeight(topViewIndex);
00551 d->invalidateHeightCache(topViewIndex);
00552 sizeChanged = (oldHeight != d->itemHeight(topViewIndex));
00553 } else {
00554 QModelIndex bottom = (bottomRight.column() == 0) ? bottomRight
00555 : d->model->sibling(bottomRight.row(), 0, bottomRight);
00556 int bottomViewIndex = d->viewIndex(bottom);
00557 for (int i = topViewIndex; i <= bottomViewIndex; ++i) {
00558 int oldHeight = d->itemHeight(i);
00559 d->invalidateHeightCache(i);
00560 sizeChanged |= (oldHeight != d->itemHeight(i));
00561 }
00562 }
00563 }
00564
00565 if (sizeChanged) {
00566 d->updateScrollBars();
00567 d->viewport->update();
00568 }
00569 QAbstractItemView::dataChanged(topLeft, bottomRight);
00570 }
00571
00577 void QTreeView::hideColumn(int column)
00578 {
00579 Q_D(QTreeView);
00580 d->header->hideSection(column);
00581 }
00582
00588 void QTreeView::showColumn(int column)
00589 {
00590 Q_D(QTreeView);
00591 d->header->showSection(column);
00592 }
00593
00601 void QTreeView::expand(const QModelIndex &index)
00602 {
00603 Q_D(QTreeView);
00604 if (!d->isIndexValid(index))
00605 return;
00606 int i = d->viewIndex(index);
00607 if (i != -1) {
00608 d->expand(i, true);
00609 if (!d->isAnimating()) {
00610 updateGeometries();
00611 d->viewport->update();
00612 }
00613 } else if (!d->expandedIndexes.contains(index)) {
00614 d->expandedIndexes.append(index);
00615 emit expanded(index);
00616 }
00617 }
00618
00626 void QTreeView::collapse(const QModelIndex &index)
00627 {
00628 Q_D(QTreeView);
00629 if (!d->isIndexValid(index))
00630 return;
00631 int i = d->viewIndex(index);
00632 if (i != -1) {
00633 d->collapse(i, true);
00634 if (!d->isAnimating()) {
00635 updateGeometries();
00636 viewport()->update();
00637 }
00638 } else {
00639 int i = d->expandedIndexes.indexOf(index);
00640 if (i != -1) {
00641 d->expandedIndexes.remove(i);
00642 emit collapsed(index);
00643 }
00644 }
00645 }
00646
00655 bool QTreeView::isExpanded(const QModelIndex &index) const
00656 {
00657 Q_D(const QTreeView);
00658 int i = d->viewIndex(index);
00659 if (i != -1)
00660 return d->viewItems.at(i).expanded;
00661 return d->expandedIndexes.contains(index);
00662 }
00663
00670 void QTreeView::setExpanded(const QModelIndex &index, bool expanded)
00671 {
00672 if (expanded)
00673 this->expand(index);
00674 else
00675 this->collapse(index);
00676 }
00677
00689 void QTreeView::setSortingEnabled(bool enable)
00690 {
00691 Q_D(QTreeView);
00692 d->sortingEnabled = enable;
00693 header()->setSortIndicatorShown(enable);
00694 header()->setClickable(enable);
00695 if (enable) {
00696 connect(header(), SIGNAL(sectionClicked(int)), this, SLOT(sortByColumn(int)));
00697 sortByColumn(header()->sortIndicatorSection());
00698 } else {
00699 disconnect(header(), SIGNAL(sectionClicked(int)), this, SLOT(sortByColumn(int)));
00700 }
00701 }
00702
00703 bool QTreeView::isSortingEnabled() const
00704 {
00705 Q_D(const QTreeView);
00706 return d->sortingEnabled;
00707 }
00708
00720 void QTreeView::setAnimated(bool animate)
00721 {
00722 Q_D(QTreeView);
00723 d->animationsEnabled = animate;
00724 }
00725
00726 bool QTreeView::isAnimated() const
00727 {
00728 Q_D(const QTreeView);
00729 return d->animationsEnabled;
00730 }
00731
00743 void QTreeView::setAllColumnsShowFocus(bool enable)
00744 {
00745 Q_D(QTreeView);
00746 if (d->allColumnsShowFocus == enable)
00747 return;
00748 if (d->selectionModel) {
00749 if (enable) {
00750 QObject::connect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
00751 this, SLOT(_q_currentChanged(QModelIndex,QModelIndex)));
00752 } else {
00753 QObject::disconnect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
00754 this, SLOT(_q_currentChanged(QModelIndex,QModelIndex)));
00755 }
00756 }
00757 d->allColumnsShowFocus = enable;
00758 d->viewport->update();
00759 }
00760
00761 bool QTreeView::allColumnsShowFocus() const
00762 {
00763 Q_D(const QTreeView);
00764 return d->allColumnsShowFocus;
00765 }
00766
00770 void QTreeView::keyboardSearch(const QString &search)
00771 {
00772 Q_D(QTreeView);
00773 if (!d->model->rowCount(d->root) || !d->model->columnCount(d->root))
00774 return;
00775
00776 QModelIndex start;
00777 if (currentIndex().isValid())
00778 start = currentIndex();
00779 else
00780 start = d->model->index(0, 0, d->root);
00781
00782 QTime now(QTime::currentTime());
00783 bool skipRow = false;
00784 if (search.isEmpty()
00785 || (d->keyboardInputTime.msecsTo(now) > QApplication::keyboardInputInterval())) {
00786 d->keyboardInput = search;
00787 skipRow = true;
00788 } else {
00789 d->keyboardInput += search;
00790 }
00791 d->keyboardInputTime = now;
00792
00793
00794 bool sameKey = false;
00795 if (d->keyboardInput.length() > 1) {
00796 int c = d->keyboardInput.count(d->keyboardInput.at(d->keyboardInput.length() - 1));
00797 sameKey = (c == d->keyboardInput.length());
00798 if (sameKey)
00799 skipRow = true;
00800 }
00801
00802
00803 if (skipRow) {
00804 if (indexBelow(start).isValid())
00805 start = indexBelow(start);
00806 else
00807 start = d->model->index(0, start.column(), d->root);
00808 }
00809
00810 int startIndex = d->viewIndex(start);
00811 if (startIndex <= -1)
00812 return;
00813
00814 int previousLevel = -1;
00815 int bestAbove = -1;
00816 int bestBelow = -1;
00817 QString searchString = sameKey ? QString(d->keyboardInput.at(0)) : d->keyboardInput;
00818 for (int i = 0; i < d->viewItems.count(); ++i) {
00819 if ((int)d->viewItems.at(i).level > previousLevel) {
00820 QModelIndex searchFrom = d->viewItems.at(i).index;
00821 if (searchFrom.parent() == start.parent())
00822 searchFrom = start;
00823 QModelIndexList match = d->model->match(searchFrom, Qt::DisplayRole, searchString);
00824 if (match.count()) {
00825 int hitIndex = d->viewIndex(match.at(0));
00826 if (hitIndex >= 0 && hitIndex < startIndex)
00827 bestAbove = bestAbove == -1 ? hitIndex : qMin(hitIndex, bestAbove);
00828 else if (hitIndex >= startIndex)
00829 bestBelow = bestBelow == -1 ? hitIndex : qMin(hitIndex, bestBelow);
00830 }
00831 }
00832 previousLevel = d->viewItems.at(i).level;
00833 }
00834
00835 QModelIndex index;
00836 if (bestBelow > -1)
00837 index = d->viewItems.at(bestBelow).index;
00838 else if (bestAbove > -1)
00839 index = d->viewItems.at(bestAbove).index;
00840
00841 if (index.isValid()) {
00842 QItemSelectionModel::SelectionFlags flags = (d->selectionMode == SingleSelection
00843 ? QItemSelectionModel::SelectionFlags(
00844 QItemSelectionModel::ClearAndSelect
00845 |d->selectionBehaviorFlags())
00846 : QItemSelectionModel::SelectionFlags(
00847 QItemSelectionModel::NoUpdate));
00848 selectionModel()->setCurrentIndex(index, flags);
00849 }
00850 }
00851
00856 QRect QTreeView::visualRect(const QModelIndex &index) const
00857 {
00858 Q_D(const QTreeView);
00859
00860 if (!d->isIndexValid(index) || isIndexHidden(index))
00861 return QRect();
00862
00863 d->executePostedLayout();
00864
00865 int vi = d->viewIndex(index);
00866 if (vi < 0)
00867 return QRect();
00868
00869 int x = columnViewportPosition(index.column());
00870 int w = columnWidth(index.column());
00871
00872 if (index.column() == 0) {
00873 int i = d->indentationForItem(vi);
00874 x += i;
00875 w -= i;
00876 }
00877 int y = d->coordinateForItem(vi);
00878 int h = d->itemHeight(vi);
00879 return QRect(x, y, w, h);
00880 }
00881
00890 void QTreeView::scrollTo(const QModelIndex &index, ScrollHint hint)
00891 {
00892 Q_D(QTreeView);
00893
00894 if (!d->isIndexValid(index))
00895 return;
00896
00897 d->executePostedLayout();
00898 d->updateScrollBars();
00899
00900
00901 QModelIndex parent = index.parent();
00902 while (parent.isValid() && state() == NoState && d->itemsExpandable) {
00903 if (!isExpanded(parent))
00904 expand(parent);
00905 parent = d->model->parent(parent);
00906 }
00907
00908 int item = d->viewIndex(index);
00909 if (item < 0)
00910 return;
00911 QRect rect(columnViewportPosition(index.column()),
00912 d->coordinateForItem(item),
00913 columnWidth(index.column()),
00914 d->itemHeight(item));
00915
00916 if (rect.isEmpty())
00917 return;
00918
00919
00920 QRect area = d->viewport->rect();
00921 if (hint == EnsureVisible && area.contains(rect)) {
00922 d->setDirtyRegion(rect);
00923 return;
00924 }
00925
00926
00927 bool above = (hint == EnsureVisible && (rect.top() < area.top() || area.height() < rect.height()));
00928 bool below = (hint == EnsureVisible && rect.bottom() > area.bottom() && rect.height() < area.height());
00929 if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
00930 if (hint == PositionAtTop || above) {
00931 verticalScrollBar()->setValue(item);
00932 } else if (hint == PositionAtCenter || hint == PositionAtBottom || below) {
00933 int y = area.height();
00934 if (hint == PositionAtCenter)
00935 y = y / 2;
00936 while (y > 0 && item > 0)
00937 y -= d->itemHeight(item--);
00938 item += 1 + ((y < 0) ? 1 : 0);
00939 verticalScrollBar()->setValue(item);
00940 }
00941 } else {
00942 int verticalValue = verticalScrollBar()->value();
00943 if (hint == PositionAtTop || above)
00944 verticalValue += rect.top();
00945 else if (hint == PositionAtBottom || below)
00946 verticalValue += rect.bottom() - area.height();
00947 else if (hint == PositionAtCenter)
00948 verticalValue += rect.top() - ((area.height() - rect.height()) / 2);
00949 verticalScrollBar()->setValue(verticalValue);
00950 }
00951
00952
00953 int viewportWidth = d->viewport->width();
00954 int horizontalOffset = d->header->offset();
00955 int horizontalPosition = d->header->sectionPosition(index.column());
00956 int cellWidth = d->header->sectionSize(index.column());
00957
00958 if (hint == PositionAtCenter) {
00959 horizontalScrollBar()->setValue(horizontalPosition - ((viewportWidth - cellWidth) / 2));
00960 } else {
00961 if (horizontalPosition - horizontalOffset < 0 || cellWidth > viewportWidth)
00962 horizontalScrollBar()->setValue(horizontalPosition);
00963 else if (horizontalPosition - horizontalOffset + cellWidth > viewportWidth)
00964 horizontalScrollBar()->setValue(horizontalPosition - viewportWidth + cellWidth);
00965 }
00966 }
00967
00971 void QTreeView::timerEvent(QTimerEvent *event)
00972 {
00973 Q_D(QTreeView);
00974 if (event->timerId() == d->columnResizeTimerID) {
00975 updateGeometries();
00976 killTimer(d->columnResizeTimerID);
00977 d->columnResizeTimerID = 0;
00978 QRect rect;
00979 int viewportHeight = d->viewport->height();
00980 int viewportWidth = d->viewport->width();
00981 for (int i = d->columnsToUpdate.size() - 1; i >= 0; --i) {
00982 int column = d->columnsToUpdate.at(i);
00983 int x = columnViewportPosition(column);
00984 if (isRightToLeft())
00985 rect |= QRect(0, 0, x + columnWidth(column), viewportHeight);
00986 else
00987 rect |= QRect(x, 0, viewportWidth - x, viewportHeight);
00988 }
00989 d->viewport->update(rect.normalized());
00990 d->columnsToUpdate.clear();
00991 }
00992 QAbstractItemView::timerEvent(event);
00993 }
00994
00998 void QTreeView::paintEvent(QPaintEvent *event)
00999 {
01000 Q_D(QTreeView);
01001 bool layout = d->delayedLayout.isActive();
01002 d->delayedLayout.stop();
01003 QPainter painter(viewport());
01004 if (d->isAnimating()) {
01005 drawTree(&painter, event->region() - d->animationRect());
01006 d->drawAnimatedOperation(&painter);
01007 } else {
01008 drawTree(&painter, event->region());
01009 #ifndef QT_NO_DRAGANDDROP
01010 d->paintDropIndicator(&painter);
01011 #endif
01012 }
01013 if (layout)
01014 d->doDelayedItemsLayout();
01015 }
01016
01024 void QTreeView::drawTree(QPainter *painter, const QRegion ®ion) const
01025 {
01026 Q_D(const QTreeView);
01027 const QVector<QTreeViewItem> viewItems = d->viewItems;
01028
01029 if (viewItems.count() == 0 || d->header->count() == 0 || !d->itemDelegate) {
01030 painter->fillRect(region.boundingRect(), palette().brush(QPalette::Base));
01031 return;
01032 }
01033
01034 QStyleOptionViewItemV2 option = d->viewOptionsV2();
01035 const QStyle::State state = option.state;
01036 const int deviceWidth = painter->device()->width();
01037 const int headerLength = d->header->length();
01038
01039 int firstVisibleItemOffset = 0;
01040 const int firstVisibleItem = d->firstVisibleItem(&firstVisibleItemOffset);
01041 if (firstVisibleItem < 0)
01042 return;
01043
01044 QVector<QRect> rects = region.rects();
01045 for (int a = 0; a < rects.size(); ++a) {
01046
01047 const QRect area = rects.at(a);
01048 d->leftAndRight = d->startAndEndColumns(area);
01049
01050 int i = firstVisibleItem;
01051 int y = firstVisibleItemOffset;
01052
01053
01054 for (; i < viewItems.count(); ++i) {
01055 const int itemHeight = d->itemHeight(i);
01056 if (y + itemHeight >= area.top())
01057 break;
01058 y += itemHeight;
01059 }
01060
01061
01062 for (; i < viewItems.count() && y <= area.bottom(); ++i) {
01063 const int itemHeight = d->itemHeight(i);
01064 option.rect.setRect(0, y, 0, itemHeight);
01065 option.state = state | (viewItems.at(i).expanded
01066 ? QStyle::State_Open : QStyle::State_None);
01067 d->current = i;
01068 drawRow(painter, option, viewItems.at(i).index);
01069 y += itemHeight;
01070 }
01071
01072 if (y <= area.bottom()) {
01073 QRect bottomArea(0, y, deviceWidth, area.bottom() - y + 1);
01074 if (area.intersects(bottomArea))
01075 painter->fillRect(bottomArea, palette().brush(QPalette::Base));
01076 }
01077 if (isRightToLeft()) {
01078 QRect rightArea(0, 0, deviceWidth - headerLength, area.height());
01079 if (headerLength < deviceWidth && area.intersects(rightArea))
01080 painter->fillRect(rightArea, palette().brush(QPalette::Base));
01081 } else {
01082 QRect leftArea(headerLength, 0, deviceWidth - headerLength, area.height());
01083 if (headerLength < deviceWidth && area.intersects(leftArea))
01084 painter->fillRect(leftArea, palette().brush(QPalette::Base));
01085 }
01086 }
01087 }
01088
01090 static inline bool ancestorOf(QObject *widget, QObject *other)
01091 {
01092 for (QObject *parent = other; parent != 0; parent = parent->parent()) {
01093 if (parent == widget)
01094 return true;
01095 }
01096 return false;
01097 }
01098
01106 void QTreeView::drawRow(QPainter *painter, const QStyleOptionViewItem &option,
01107 const QModelIndex &index) const
01108 {
01109 Q_D(const QTreeView);
01110 QStyleOptionViewItemV2 opt = option;
01111 const QPoint offset = d->scrollDelayOffset;
01112 const int y = option.rect.y() + offset.y();
01113 const QModelIndex parent = index.parent();
01114 const QHeaderView *header = d->header;
01115 const QModelIndex current = currentIndex();
01116 const QModelIndex hover = d->hover;
01117 const bool reverse = isRightToLeft();
01118 const QStyle::State state = opt.state;
01119 const int left = d->leftAndRight.first;
01120 const int right = d->leftAndRight.second;
01121 const bool alternate = d->alternatingColors;
01122 const bool enabled = (state & QStyle::State_Enabled) != 0;
01123 const bool allColumnsShowFocus = d->allColumnsShowFocus;
01124
01125
01126
01127 bool indexWidgetHasFocus = false;
01128 if ((current.row() == index.row()) && !d->editors.isEmpty()) {
01129 const int r = index.row();
01130 QWidget *fw = QApplication::focusWidget();
01131 for (int c = 0; c < header->count(); ++c) {
01132 if (QWidget *editor = indexWidget(index.sibling(r, c))) {
01133 if (ancestorOf(editor, fw)) {
01134 indexWidgetHasFocus = true;
01135 break;
01136 }
01137 }
01138 }
01139 }
01140
01141 bool currentRowHasFocus = false;
01142 if (allColumnsShowFocus && current.isValid()) {
01143 const int r = index.row();
01144 for (int c = 0; c < left && !currentRowHasFocus; ++c)
01145 currentRowHasFocus = (index.sibling(r, c) == current);
01146 for (int c = right; c < header->count() && !currentRowHasFocus; ++c)
01147 currentRowHasFocus = (index.sibling(r, c) == current);
01148 }
01149
01150
01151
01152 opt.showDecorationSelected = (d->selectionBehavior & SelectRows)
01153 || option.showDecorationSelected;
01154
01155 int width, height = option.rect.height();
01156 int position;
01157 int headerSection;
01158 QModelIndex modelIndex;
01159
01160 QBrush fill;
01161 for (int headerIndex = left; headerIndex <= right; ++headerIndex) {
01162 headerSection = header->logicalIndex(headerIndex);
01163 if (header->isSectionHidden(headerSection))
01164 continue;
01165 position = columnViewportPosition(headerSection) + offset.x();
01166 width = header->sectionSize(headerSection);
01167 modelIndex = d->model->index(index.row(), headerSection, parent);
01168 opt.state = state;
01169 if (!modelIndex.isValid()) {
01170 opt.rect.setRect(position, y, width, height);
01171 painter->fillRect(opt.rect, palette().brush(QPalette::Base));
01172 continue;
01173 }
01174
01175
01176 if (indexWidgetHasFocus)
01177 opt.state |= QStyle::State_Active;
01178
01179 if (d->selectionModel->isSelected(modelIndex))
01180 opt.state |= QStyle::State_Selected;
01181 if ((current == modelIndex) && hasFocus()) {
01182 if (allColumnsShowFocus)
01183 currentRowHasFocus = true;
01184 else
01185 opt.state |= QStyle::State_HasFocus;
01186 }
01187 if (modelIndex == hover)
01188 opt.state |= QStyle::State_MouseOver;
01189 else
01190 opt.state &= ~QStyle::State_MouseOver;
01191
01192 if (enabled) {
01193 QPalette::ColorGroup cg;
01194 if ((d->model->flags(index) & Qt::ItemIsEnabled) == 0) {
01195 opt.state &= ~QStyle::State_Enabled;
01196 cg = QPalette::Disabled;
01197 } else {
01198 cg = QPalette::Active;
01199 }
01200 opt.palette.setCurrentColorGroup(cg);
01201 }
01202
01203 if (alternate) {
01204 if (d->current & 1) {
01205 opt.features |= QStyleOptionViewItemV2::Alternate;
01206 fill = opt.palette.brush(QPalette::AlternateBase);
01207 } else {
01208 opt.features &= ~QStyleOptionViewItemV2::Alternate;
01209 fill = opt.palette.brush(QPalette::Base);
01210 }
01211 } else {
01212 fill = opt.palette.brush(QPalette::Base);
01213 }
01214
01215 if (headerSection == 0) {
01216 const int i = d->indentationForItem(d->current);
01217 opt.rect.setRect(reverse ? position : i + position, y, width - i, height);
01218 painter->fillRect(opt.rect, fill);
01219 QRect branches(reverse ? position + width - i : position, y, i, height);
01220 QPalette::ColorGroup cg = opt.state & QStyle::State_Enabled
01221 ? QPalette::Active : QPalette::Disabled;
01222 if (cg == QPalette::Active && !(opt.state & QStyle::State_Active))
01223 cg = QPalette::Inactive;
01224
01225 if ((opt.state & QStyle::State_Selected) && option.showDecorationSelected)
01226 painter->fillRect(branches, opt.palette.brush(cg, QPalette::Highlight));
01227 else
01228 painter->fillRect(branches, fill);
01229 drawBranches(painter, branches, index);
01230 } else {
01231 opt.rect.setRect(position, y, width, height);
01232 painter->fillRect(opt.rect, fill);
01233 }
01234 itemDelegate()->paint(painter, opt, modelIndex);
01235 }
01236
01237 if (currentRowHasFocus) {
01238 const int x = (option.showDecorationSelected ? 0 : d->indentationForItem(d->current));
01239 const int width = header->length() - x;
01240 QStyleOptionFocusRect o;
01241 o.QStyleOption::operator=(option);
01242 o.rect.setRect(x - header->offset(), y, width, height);
01243 o.state |= QStyle::State_KeyboardFocusChange;
01244 QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled)
01245 ? QPalette::Normal : QPalette::Disabled;
01246 o.backgroundColor = option.palette.color(cg, d->selectionModel->isSelected(index)
01247 ? QPalette::Highlight : QPalette::Background);
01248 style()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter);
01249 }
01250 }
01251
01257 void QTreeView::drawBranches(QPainter *painter, const QRect &rect,
01258 const QModelIndex &index) const
01259 {
01260 Q_D(const QTreeView);
01261 const bool reverse = isRightToLeft();
01262 const int indent = d->indent;
01263 const int outer = d->rootDecoration ? 0 : 1;
01264 const int item = d->current;
01265 const QTreeViewItem &viewItem = d->viewItems.at(item);
01266 int level = viewItem.level;
01267 QRect primitive(reverse ? rect.left() : rect.right(), rect.top(), indent, rect.height());
01268
01269 QModelIndex parent = index.parent();
01270 QModelIndex current = parent;
01271 QModelIndex ancestor = current.parent();
01272
01273 QStyleOption opt;
01274 opt.initFrom(this);
01275 QStyle::State extraFlags = QStyle::State_None;
01276 if (isEnabled())
01277 extraFlags |= QStyle::State_Enabled;
01278 if (window()->isActiveWindow())
01279 extraFlags |= QStyle::State_Active;
01280
01281 QPoint oldBO = painter->brushOrigin();
01282 if (verticalScrollMode() == QAbstractItemView::ScrollPerPixel)
01283 painter->setBrushOrigin(QPoint(0, verticalOffset()));
01284
01285 if (level >= outer) {
01286
01287 primitive.moveLeft(reverse ? primitive.left() : primitive.left() - indent);
01288 opt.rect = primitive;
01289
01290 const bool expanded = viewItem.expanded;
01291 const bool children = (((expanded && viewItem.total > 0))
01292 || d->hasVisibleChildren(index));
01293 bool moreSiblings = false;
01294 if (d->hiddenIndexes.isEmpty())
01295 moreSiblings = (d->model->rowCount(parent) - 1 > index.row());
01296 else
01297 moreSiblings = ((d->viewItems.size() > item +1)
01298 && (d->viewItems.at(item + 1).index.parent() == parent));
01299
01300 opt.state = QStyle::State_Item | extraFlags
01301 | (moreSiblings ? QStyle::State_Sibling : QStyle::State_None)
01302 | (children ? QStyle::State_Children : QStyle::State_None)
01303 | (expanded ? QStyle::State_Open : QStyle::State_None);
01304 style()->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painter, this);
01305 }
01306
01307 for (--level; level >= outer; --level) {
01308 primitive.moveLeft(reverse ? primitive.left() + indent : primitive.left() - indent);
01309 opt.rect = primitive;
01310 opt.state = extraFlags;
01311 bool moreSiblings = false;
01312 if (d->hiddenIndexes.isEmpty()) {
01313 moreSiblings = (d->model->rowCount(ancestor) - 1 > current.row());
01314 } else {
01315 int successor = item + viewItem.total + 1;
01316 while (successor < d->viewItems.size()
01317 && d->viewItems.at(successor).level >= uint(level)) {
01318 const QTreeViewItem &successorItem = d->viewItems.at(successor);
01319 if (successorItem.level == uint(level)) {
01320 moreSiblings = true;
01321 break;
01322 }
01323 successor += successorItem.total + 1;
01324 }
01325 }
01326 if (moreSiblings)
01327 opt.state |= QStyle::State_Sibling;
01328 style()->drawPrimitive(QStyle::PE_IndicatorBranch, &opt, painter, this);
01329 current = ancestor;
01330 ancestor = current.parent();
01331 }
01332 painter->setBrushOrigin(oldBO);
01333 }
01334
01338 void QTreeView::mousePressEvent(QMouseEvent *event)
01339 {
01340 Q_D(QTreeView);
01341
01342 if ((state() != NoState && state() != EditingState) || !d->viewport->rect().contains(event->pos())) {
01343 return;
01344 }
01345 int i = d->itemDecorationAt(event->pos());
01346 if (i == -1) {
01347 QAbstractItemView::mousePressEvent(event);
01348 } else if (itemsExpandable() && d->hasVisibleChildren(d->viewItems.at(i).index)) {
01349 if (d->viewItems.at(i).expanded)
01350 d->collapse(i, true);
01351 else
01352 d->expand(i, true);
01353 if (!d->isAnimating()) {
01354 updateGeometries();
01355 viewport()->update();
01356 }
01357 }
01358 }
01359
01363 void QTreeView::mouseReleaseEvent(QMouseEvent *event)
01364 {
01365 Q_D(QTreeView);
01366 if (d->itemDecorationAt(event->pos()) == -1) {
01367 QAbstractItemView::mouseReleaseEvent(event);
01368 } else {
01369 if (state() == QAbstractItemView::DragSelectingState)
01370 setState(QAbstractItemView::NoState);
01371 }
01372 }
01373
01377 void QTreeView::mouseDoubleClickEvent(QMouseEvent *event)
01378 {
01379 Q_D(QTreeView);
01380 if (state() != NoState || !d->viewport->rect().contains(event->pos()))
01381 return;
01382
01383 int i = d->itemDecorationAt(event->pos());
01384 if (i == -1) {
01385 i = d->itemAtCoordinate(event->y());
01386 if (i == -1)
01387 return;
01388
01389
01390 const QModelIndex &index = d->viewItems.at(i).index;
01391 int column = d->header->logicalIndexAt(event->x());
01392 QPersistentModelIndex persistent = index.sibling(index.row(), column);
01393 emit doubleClicked(persistent);
01394
01395 if (!persistent.isValid())
01396 return;
01397
01398 if (edit(persistent, DoubleClicked, event) || state() != NoState)
01399 return;
01400
01401 if (!style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, 0, this))
01402 emit activated(persistent);
01403
01404 d->executePostedLayout();
01405 if (d->itemsExpandable && d->hasVisibleChildren(persistent)) {
01406 if (!((i < d->viewItems.count()) && (d->viewItems.at(i).index == persistent))) {
01407
01408 for (i = 0; i < d->viewItems.count(); ++i) {
01409 if (d->viewItems.at(i).index == persistent)
01410 break;
01411 }
01412 if (i == d->viewItems.count())
01413 return;
01414 }
01415 if (d->viewItems.at(i).expanded)
01416 d->collapse(i, true);
01417 else
01418 d->expand(i, true);
01419 updateGeometries();
01420 viewport()->update();
01421 }
01422 }
01423 }
01424
01428 void QTreeView::mouseMoveEvent(QMouseEvent *event)
01429 {
01430 Q_D(QTreeView);
01431 if (d->itemDecorationAt(event->pos()) == -1)
01432 QAbstractItemView::mouseMoveEvent(event);
01433 }
01434
01438 void QTreeView::keyPressEvent(QKeyEvent *event)
01439 {
01440 Q_D(QTreeView);
01441 QModelIndex current = currentIndex();
01442 if (d->isIndexValid(current) && d->model) {
01443 switch (event->key()) {
01444 case Qt::Key_Asterisk: {
01445 QStack<QModelIndex> parents;
01446 parents.push(current);
01447 if (d->itemsExpandable) {
01448 while (!parents.isEmpty()) {
01449 QModelIndex parent = parents.pop();
01450 for (int row = 0; row < d->model->rowCount(parent); ++row) {
01451 QModelIndex child = d->model->index(row, 0, parent);
01452 if (!d->isIndexValid(child))
01453 break;
01454 parents.push(child);
01455 expand(child);
01456 }
01457 }
01458 expand(current);
01459 }
01460 break; }
01461 case Qt::Key_Plus:
01462 expand(current);
01463 break;
01464 case Qt::Key_Minus:
01465 collapse(current);
01466 break;
01467 }
01468 }
01469
01470 QAbstractItemView::keyPressEvent(event);
01471 }
01472
01476 QModelIndex QTreeView::indexAt(const QPoint &point) const
01477 {
01478 Q_D(const QTreeView);
01479 d->executePostedLayout();
01480
01481 int visualIndex = d->itemAtCoordinate(point.y());
01482 QModelIndex idx = d->modelIndex(visualIndex);
01483 int column = d->columnAt(point.x());
01484 if (idx.isValid() && column >= 0)
01485 return d->model->sibling(idx.row(), column, idx);
01486 return idx;
01487 }
01488
01492 QModelIndex QTreeView::indexAbove(const QModelIndex &index) const
01493 {
01494 Q_D(const QTreeView);
01495 if (!d->isIndexValid(index))
01496 return QModelIndex();
01497 d->executePostedLayout();
01498 int i = d->viewIndex(index);
01499 if (--i < 0)
01500 return QModelIndex();
01501 return d->viewItems.at(i).index;
01502 }
01503
01507 QModelIndex QTreeView::indexBelow(const QModelIndex &index) const
01508 {
01509 Q_D(const QTreeView);
01510 if (!d->isIndexValid(index))
01511 return QModelIndex();
01512 d->executePostedLayout();
01513 int i = d->viewIndex(index);
01514 if (++i >= d->viewItems.count())
01515 return QModelIndex();
01516 return d->viewItems.at(i).index;
01517 }
01518
01524 void QTreeView::doItemsLayout()
01525 {
01526 Q_D(QTreeView);
01527 d->viewItems.clear();
01528 QModelIndex parent = d->root;
01529 if (d->model->hasChildren(parent)) {
01530 QModelIndex index = d->model->index(0, 0, parent);
01531 d->defaultItemHeight = indexRowSizeHint(index);
01532 d->layout(-1);
01533 d->reexpandChildren(parent);
01534 }
01535 QAbstractItemView::doItemsLayout();
01536 d->header->doItemsLayout();
01537 }
01538
01542 void QTreeView::reset()
01543 {
01544 Q_D(QTreeView);
01545 d->expandedIndexes.clear();
01546 d->hiddenIndexes.clear();
01547 d->viewItems.clear();
01548 QAbstractItemView::reset();
01549 }
01550
01559 int QTreeView::horizontalOffset() const
01560 {
01561 Q_D(const QTreeView);
01562 return d->header->offset();
01563 }
01564
01570 int QTreeView::verticalOffset() const
01571 {
01572 Q_D(const QTreeView);
01573 if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
01574 if (uniformRowHeights())
01575 return verticalScrollBar()->value() * d->defaultItemHeight;
01576
01577
01578
01579 int offset = 0;
01580 for (int i = 0; i < d->viewItems.count(); ++i) {
01581 if (i == verticalScrollBar()->value())
01582 return offset;
01583 offset += d->itemHeight(i);
01584 }
01585 return 0;
01586 }
01587
01588 return verticalScrollBar()->value();
01589 }
01590
01595 QModelIndex QTreeView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
01596 {
01597 Q_D(QTreeView);
01598 Q_UNUSED(modifiers);
01599
01600 d->executePostedLayout();
01601
01602 QModelIndex current = currentIndex();
01603 if (!current.isValid()) {
01604 int i = 0;
01605 while (i < d->viewItems.count() && d->hiddenIndexes.contains(d->viewItems.at(i).index))
01606 ++i;
01607 return d->viewItems.value(i).index;
01608 }
01609 int vi = qMax(0, d->viewIndex(current));
01610 switch (cursorAction) {
01611 case MoveNext:
01612 case MoveDown:
01613 #ifdef QT_KEYPAD_NAVIGATION
01614 if (vi == d->viewItems.count()-1 && QApplication::keypadNavigationEnabled())
01615 return d->model->index(0, 0, d->root);
01616 #endif
01617 return d->modelIndex(d->below(vi));
01618 case MovePrevious:
01619 case MoveUp:
01620 #ifdef QT_KEYPAD_NAVIGATION
01621 if (vi == 0 && QApplication::keypadNavigationEnabled())
01622 return d->modelIndex(d->viewItems.count() - 1);
01623 #endif
01624 return d->modelIndex(d->above(vi));
01625 case MoveLeft: {
01626 QScrollBar *sb = horizontalScrollBar();
01627 if (d->viewItems.at(vi).expanded && d->itemsExpandable && sb->value() == sb->minimum())
01628 d->collapse(vi, true);
01629 else
01630 sb->setValue(sb->value() - sb->singleStep());
01631 updateGeometries();
01632 viewport()->update();
01633 break;
01634 }
01635 case MoveRight:
01636 if (!d->viewItems.at(vi).expanded && d->itemsExpandable) {
01637 d->expand(vi, true);
01638 }
01639 else {
01640 QScrollBar *sb = horizontalScrollBar();
01641 sb->setValue(sb->value() + sb->singleStep());
01642 }
01643 updateGeometries();
01644 viewport()->update();
01645 break;
01646 case MovePageUp:
01647 return d->modelIndex(d->pageUp(vi));
01648 case MovePageDown:
01649 return d->modelIndex(d->pageDown(vi));
01650 case MoveHome:
01651 return d->model->index(0, 0, d->root);
01652 case MoveEnd:
01653 return d->modelIndex(d->viewItems.count() - 1);
01654 }
01655 return current;
01656 }
01657
01664 void QTreeView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
01665 {
01666 Q_D(QTreeView);
01667 if (!selectionModel())
01668 return;
01669
01670 QPoint tl(isRightToLeft() ? qMax(rect.left(), rect.right())
01671 : qMin(rect.left(), rect.right()), qMin(rect.top(), rect.bottom()));
01672 QPoint br(isRightToLeft() ? qMin(rect.left(), rect.right()) :
01673 qMax(rect.left(), rect.right()), qMax(rect.top(), rect.bottom()));
01674 QModelIndex topLeft = indexAt(tl);
01675 QModelIndex bottomRight = indexAt(br);
01676 if (selectionBehavior() != SelectRows) {
01677 QItemSelection selection;
01678 if (topLeft.isValid() && bottomRight.isValid()) {
01679 selection.append(QItemSelectionRange(topLeft, bottomRight));
01680 selectionModel()->select(selection, command);
01681 }
01682 } else {
01683 d->select(d->viewIndex(topLeft), d->viewIndex(bottomRight), command);
01684 }
01685 }
01686
01691 QRegion QTreeView::visualRegionForSelection(const QItemSelection &selection) const
01692 {
01693 Q_D(const QTreeView);
01694 if (selection.isEmpty())
01695 return QRegion();
01696
01697 QRegion selectionRegion;
01698 for (int i = 0; i < selection.count(); ++i) {
01699 QItemSelectionRange range = selection.at(i);
01700 if (!range.isValid())
01701 continue;
01702 QModelIndex parent = range.parent();
01703 QModelIndex leftIndex = range.topLeft();
01704 int columnCount = d->model->columnCount(parent);
01705 while (leftIndex.isValid() && isIndexHidden(leftIndex)) {
01706 if (leftIndex.column() + 1 < columnCount)
01707 leftIndex = d->model->index(leftIndex.row(), leftIndex.column() + 1, parent);
01708 else
01709 leftIndex = QModelIndex();
01710 }
01711 if (!leftIndex.isValid())
01712 continue;
01713 int top = visualRect(leftIndex).top();
01714 QModelIndex rightIndex = range.bottomRight();
01715 while (rightIndex.isValid() && isIndexHidden(rightIndex)) {
01716 if (rightIndex.column() - 1 >= 0)
01717 rightIndex = d->model->index(rightIndex.row(), rightIndex.column() - 1, parent);
01718 else
01719 rightIndex = QModelIndex();
01720 }
01721 if (!rightIndex.isValid())
01722 continue;
01723 int bottom = visualRect(rightIndex).bottom();
01724 if (top > bottom)
01725 qSwap<int>(top, bottom);
01726 int height = bottom - top + 1;
01727 for (int c = range.left(); c <= range.right(); ++c)
01728 selectionRegion += QRegion(QRect(columnViewportPosition(c), top,
01729 columnWidth(c), height));
01730 }
01731 return selectionRegion;
01732 }
01733
01737 QModelIndexList QTreeView::selectedIndexes() const
01738 {
01739 QModelIndexList viewSelected;
01740 QModelIndexList modelSelected;
01741 if (selectionModel())
01742 modelSelected = selectionModel()->selectedIndexes();
01743 for (int i = 0; i < modelSelected.count(); ++i) {
01744
01745 QModelIndex index = modelSelected.at(i);
01746 while (index.isValid() && !isIndexHidden(index))
01747 index = index.parent();
01748 if (index.isValid())
01749 continue;
01750 viewSelected.append(modelSelected.at(i));
01751 }
01752 return viewSelected;
01753 }
01754
01758 void QTreeView::scrollContentsBy(int dx, int dy)
01759 {
01760 Q_D(QTreeView);
01761 dx = isRightToLeft() ? -dx : dx;
01762 if (dx) {
01763 if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) {
01764 int currentScrollbarValue = horizontalScrollBar()->value();
01765 int previousScrollbarValue = currentScrollbarValue + dx;
01766 d->header->setOffsetToSectionPosition(currentScrollbarValue);
01767 dx = 0;
01768 if (previousScrollbarValue < currentScrollbarValue) {
01769 for (int c = previousScrollbarValue; c < currentScrollbarValue; ++c) {
01770 int l = d->header->logicalIndex(c);
01771 dx -= d->header->sectionSize(l);
01772 }
01773 } else if (previousScrollbarValue > currentScrollbarValue) {
01774 for (int c = previousScrollbarValue; c >= currentScrollbarValue; --c) {
01775 int l = d->header->logicalIndex(c);
01776 dx += d->header->sectionSize(l);
01777 }
01778 }
01779 } else {
01780 d->header->setOffset(horizontalScrollBar()->value());
01781 }
01782 }
01783
01784 if (d->viewItems.isEmpty() || d->defaultItemHeight == 0)
01785 return;
01786
01787
01788 int viewCount = d->viewport->height() / d->defaultItemHeight;
01789 int maxDeltaY = qMin(d->viewItems.count(), viewCount);
01790
01791 if (qAbs(dy) > qAbs(maxDeltaY) && d->editors.isEmpty()) {
01792 verticalScrollBar()->repaint();
01793 d->viewport->update();
01794 return;
01795 }
01796
01797 if (dy && verticalScrollMode() == QAbstractItemView::ScrollPerItem) {
01798 int currentScrollbarValue = verticalScrollBar()->value();
01799 int previousScrollbarValue = currentScrollbarValue + dy;
01800 int currentViewIndex = currentScrollbarValue;
01801 int previousViewIndex = previousScrollbarValue;
01802 const QVector<QTreeViewItem> viewItems = d->viewItems;
01803 dy = 0;
01804 if (previousViewIndex < currentViewIndex) {
01805 for (int i = previousViewIndex; i < currentViewIndex; ++i) {
01806 if (i < d->viewItems.count())
01807 dy -= d->itemHeight(i);
01808 }
01809 } else if (previousViewIndex > currentViewIndex) {
01810 for (int i = previousViewIndex - 1; i >= currentViewIndex; --i) {
01811 if (i < d->viewItems.count())
01812 dy += d->itemHeight(i);
01813 }
01814 }
01815 }
01816
01817 d->scrollContentsBy(dx, dy);
01818 }
01819
01823 void QTreeView::columnMoved()
01824 {
01825 QAbstractItemView::dataChanged(QModelIndex(), QModelIndex());
01826 }
01827
01831 void QTreeView::reexpand()
01832 {
01833
01834 }
01835
01840 void QTreeView::rowsInserted(const QModelIndex &parent, int start, int end)
01841 {
01842 Q_D(QTreeView);
01843 d->doDelayedItemsLayout();
01844 QAbstractItemView::rowsInserted(parent, start, end);
01845 }
01846
01851 void QTreeView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
01852 {
01853 Q_D(QTreeView);
01854 if (d->viewItems.isEmpty()) {
01855 QAbstractItemView::rowsAboutToBeRemoved(parent, start, end);
01856 return;
01857 }
01858
01859 if (parent == d->root) {
01860 d->viewItems.clear();
01861 d->doDelayedItemsLayout();
01862 QAbstractItemView::rowsAboutToBeRemoved(parent, start, end);
01863 return;
01864 }
01865
01866 d->executePostedLayout();
01867 setState(CollapsingState);
01868
01869
01870 bool expanded = isExpanded(parent);
01871 d->expandParent.push(expanded);
01872 if (expanded) {
01873 int p = d->viewIndex(parent);
01874 if (p != -1)
01875 d->collapse(p, false);
01876 }
01877
01878 QAbstractItemView::rowsAboutToBeRemoved(parent, start, end);
01879 }
01880
01887 void QTreeView::rowsRemoved(const QModelIndex &parent, int start, int end)
01888 {
01889 Q_UNUSED(start);
01890 Q_UNUSED(end);
01891 Q_D(QTreeView);
01892
01893 if (d->viewItems.isEmpty()) {
01894 d->_q_rowsRemoved(parent, start, end);
01895 return;
01896 }
01897 if (parent == d->root) {
01898 d->viewItems.clear();
01899 d->doDelayedItemsLayout();
01900 d->_q_rowsRemoved(parent, start, end);
01901 return;
01902 }
01903
01904 bool expanded = d->expandParent.pop();
01905 if (expanded) {
01906 int p = d->viewIndex(parent);
01907 if (p != -1) {
01908 d->expand(p, false);
01909 d->viewport->update();
01910 } else if (!d->expandedIndexes.contains(parent)) {
01911 d->expandedIndexes.append(parent);
01912 }
01913 }
01914 if (d->expandParent.isEmpty()) {
01915 setState(NoState);
01916 d->updateScrollBars();
01917 }
01918 }
01919
01924 void QTreeView::columnCountChanged(int, int)
01925 {
01926 if (isVisible())
01927 updateGeometries();
01928 viewport()->update();
01929 }
01930
01936 void QTreeView::resizeColumnToContents(int column)
01937 {
01938 Q_D(QTreeView);
01939 d->executePostedLayout();
01940 if (column < 0 || column >= d->header->count())
01941 return;
01942 int contents = sizeHintForColumn(column);
01943 int header = d->header->isHidden() ? 0 : d->header->sectionSizeHint(column);
01944 d->header->resizeSection(column, qMax(contents, header));
01945 }
01946
01953 void QTreeView::sortByColumn(int column)
01954 {
01955 Q_D(QTreeView);
01956 if (column == -1)
01957 return;
01958 d->model->sort(column, d->header->sortIndicatorOrder());
01959 }
01960
01968 void QTreeView::sortByColumn(int column, Qt::SortOrder order)
01969 {
01970 Q_D(QTreeView);
01971 d->header->setSortIndicator(column, order);
01972 sortByColumn(column);
01973 }
01974
01978 void QTreeView::selectAll()
01979 {
01980 Q_D(QTreeView);
01981 if (!selectionModel())
01982 return;
01983 d->select(0, d->viewItems.count() - 1,
01984 QItemSelectionModel::ClearAndSelect
01985 |QItemSelectionModel::Rows);
01986 }
01987
01994 void QTreeView::expandAll()
01995 {
01996 Q_D(QTreeView);
01997 d->executePostedLayout();
01998 d->expandedIndexes.clear();
01999 for (int i = 0; i < d->viewItems.count(); ++i)
02000 if (!d->viewItems.at(i).expanded)
02001 d->expand(i, false);
02002 updateGeometries();
02003 d->viewport->update();
02004 }
02005
02013 void QTreeView::collapseAll()
02014 {
02015 Q_D(QTreeView);
02016 d->expandedIndexes.clear();
02017 doItemsLayout();
02018 }
02019
02027 void QTreeView::columnResized(int column, int , int )
02028 {
02029 Q_D(QTreeView);
02030 d->columnsToUpdate.append(column);
02031 if (d->columnResizeTimerID == 0)
02032 d->columnResizeTimerID = startTimer(0);
02033 }
02034
02039 void QTreeView::updateGeometries()
02040 {
02041 Q_D(QTreeView);
02042 if (d->header) {
02043 QSize hint = d->header->isHidden() ? QSize(0, 0) : d->header->sizeHint();
02044 setViewportMargins(0, hint.height(), 0, 0);
02045 QRect vg = d->viewport->geometry();
02046 QRect geometryRect(vg.left(), vg.top() - hint.height(), vg.width(), hint.height());
02047 d->header->setGeometry(geometryRect);
02048 d->header->setOffset(horizontalScrollBar()->value());
02049 if (d->header->isHidden())
02050 QMetaObject::invokeMethod(d->header, "updateGeometries");
02051 d->updateScrollBars();
02052 }
02053 QAbstractItemView::updateGeometries();
02054 }
02055
02070 int QTreeView::sizeHintForColumn(int column) const
02071 {
02072 Q_D(const QTreeView);
02073 d->executePostedLayout();
02074 if (d->viewItems.isEmpty())
02075 return -1;
02076 int w = 0;
02077 QStyleOptionViewItemV2 option = d->viewOptionsV2();
02078 const QVector<QTreeViewItem> viewItems = d->viewItems;
02079 for (int i = 0; i < viewItems.count(); ++i) {
02080 QModelIndex index = viewItems.at(i).index;
02081 if (index.column() != column)
02082 index = index.sibling(index.row(), column);
02083 int width = d->delegateForIndex(index)->sizeHint(option, index).width();
02084 w = qMax(w, width + (column == 0 ? d->indentationForItem(i) : 0));
02085 }
02086 return w;
02087 }
02088
02094 int QTreeView::indexRowSizeHint(const QModelIndex &index) const
02095 {
02096 Q_D(const QTreeView);
02097 if (!d->isIndexValid(index) || !d->itemDelegate)
02098 return 0;
02099
02100 int start = -1;
02101 int end = -1;
02102 int count = d->header->count();
02103 if (count) {
02104
02105 start = d->header->logicalIndexAt(0);
02106 end = d->header->logicalIndexAt(viewport()->width());
02107 } else {
02108
02109 count = d->model->columnCount(index.parent());
02110 }
02111
02112 if (isRightToLeft()) {
02113 start = (start == -1 ? count - 1 : start);
02114 end = (end == -1 ? 0 : end);
02115 } else {
02116 start = (start == -1 ? 0 : start);
02117 end = (end == -1 ? count - 1 : end);
02118 }
02119
02120 int tmp = start;
02121 start = qMin(start, end);
02122 end = qMax(tmp, end);
02123
02124 int height = -1;
02125 QStyleOptionViewItemV2 option = d->viewOptionsV2();
02126
02127
02128
02129
02130
02131 option.rect.setWidth(-1);
02132 for (int column = start; column <= end; ++column) {
02133 QModelIndex idx = index.sibling(index.row(), column);
02134 if (idx.isValid()) {
02135 if (QWidget *editor = d->editorForIndex(idx))
02136 height = qMax(height, editor->size().height());
02137 int hint = d->delegateForIndex(idx)->sizeHint(option, idx).height();
02138 height = qMax(height, hint);
02139 }
02140 }
02141
02142 return height;
02143 }
02144
02148 void QTreeView::horizontalScrollbarAction(int action)
02149 {
02150 QAbstractItemView::horizontalScrollbarAction(action);
02151 }
02152
02156 bool QTreeView::isIndexHidden(const QModelIndex &index) const
02157 {
02158 return (isColumnHidden(index.column()) || isRowHidden(index.row(), index.parent()));
02159 }
02160
02161
02162
02163
02164 void QTreeViewPrivate::initialize()
02165 {
02166 Q_Q(QTreeView);
02167 q->setSelectionBehavior(QAbstractItemView::SelectRows);
02168 q->setSelectionMode(QAbstractItemView::SingleSelection);
02169 q->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
02170
02171 QHeaderView *header = new QHeaderView(Qt::Horizontal, q);
02172 header->setMovable(true);
02173 header->setStretchLastSection(true);
02174 q->setHeader(header);
02175
02176
02177 QObject::connect(&timeline, SIGNAL(frameChanged(int)), viewport, SLOT(update()));
02178 QObject::connect(&timeline, SIGNAL(finished()), q, SLOT(_q_endAnimatedOperation()));
02179 }
02180
02181 void QTreeViewPrivate::expand(int item, bool emitSignal)
02182 {
02183 Q_Q(QTreeView);
02184
02185 if (item == -1 || viewItems.at(item).expanded)
02186 return;
02187
02188 if (emitSignal && animationsEnabled)
02189 prepareAnimatedOperation(item, AnimatedOperation::Expand);
02190
02191 q->setState(QAbstractItemView::ExpandingState);
02192 const QModelIndex index = viewItems.at(item).index;
02193 expandedIndexes.append(index);
02194 viewItems[item].expanded = true;
02195 layout(item);
02196 if (model->hasChildren(index))
02197 reexpandChildren(index);
02198 q->setState(QAbstractItemView::NoState);
02199
02200 if (emitSignal) {
02201 if (animationsEnabled)
02202 beginAnimatedOperation();
02203 else
02204 emit q->expanded(index);
02205 }
02206 if (model->canFetchMore(index))
02207 model->fetchMore(index);
02208 }
02209
02210 void QTreeViewPrivate::collapse(int item, bool emitSignal)
02211 {
02212 Q_Q(QTreeView);
02213
02214 if (item == -1 || expandedIndexes.isEmpty())
02215 return;
02216
02217 int total = viewItems.at(item).total;
02218 const QModelIndex &modelIndex = viewItems.at(item).index;
02219 int index = expandedIndexes.indexOf(modelIndex);
02220 if (index == -1 || viewItems.at(item).expanded == false)
02221 return;
02222
02223 if (emitSignal && animationsEnabled)
02224 prepareAnimatedOperation(item, AnimatedOperation::Collapse);
02225
02226 q->setState(QAbstractItemView::CollapsingState);
02227 expandedIndexes.remove(index);
02228 viewItems[item].expanded = false;
02229 index = item;
02230 QModelIndex parent = modelIndex;
02231 while (parent.isValid() && parent != root) {
02232 Q_ASSERT(index > -1);
02233 viewItems[index].total -= total;
02234 parent = parent.parent();
02235 index = viewIndex(parent);
02236 }
02237 viewItems.remove(item + 1, total);
02238 q->setState(QAbstractItemView::NoState);
02239
02240 if (emitSignal) {
02241 if (animationsEnabled)
02242 beginAnimatedOperation();
02243 else
02244 emit q->collapsed(modelIndex);
02245 }
02246 }
02247
02248 void QTreeViewPrivate::prepareAnimatedOperation(int item, AnimatedOperation::Type type)
02249 {
02250 animatedOperation.item = item;
02251 animatedOperation.type = type;
02252
02253 int top = coordinateForItem(item) + itemHeight(item);
02254 QRect rect = viewport->rect();
02255 if (type == AnimatedOperation::Collapse) {
02256 int h = 0;
02257 int c = item + viewItems.at(item).total + 1;
02258 for (int i = item + 1; i < c; ++i)
02259 h += itemHeight(i);
02260 rect.setHeight(h);
02261 animatedOperation.duration = h;
02262 }
02263 rect.moveTop(top);
02264 animatedOperation.top = top;
02265 animatedOperation.before = renderTreeToPixmap(rect);
02266 }
02267
02268 void QTreeViewPrivate::beginAnimatedOperation()
02269 {
02270 Q_Q(QTreeView);
02271
02272 QRect rect = viewport->rect();
02273 if (animatedOperation.type == AnimatedOperation::Expand) {
02274 int h = 0;
02275 int c = animatedOperation.item + viewItems.at(animatedOperation.item).total + 1;
02276 for (int i = animatedOperation.item + 1; i < c; ++i)
02277 h += itemHeight(i);
02278 rect.setHeight(h);
02279 animatedOperation.duration = h;
02280 }
02281 rect.moveTop(animatedOperation.top);
02282
02283 animatedOperation.after = renderTreeToPixmap(rect);
02284
02285 timeline.stop();
02286 timeline.setDuration(1000);
02287 timeline.setFrameRange(animatedOperation.top, animatedOperation.top + animatedOperation.duration);
02288 timeline.start();
02289
02290 q->setState(QAbstractItemView::AnimatingState);
02291 }
02292
02293 void QTreeViewPrivate::_q_endAnimatedOperation()
02294 {
02295 Q_Q(QTreeView);
02296 animatedOperation.before = QPixmap();
02297 animatedOperation.after = QPixmap();
02298 q->setState(QAbstractItemView::NoState);
02299 if (animatedOperation.type == AnimatedOperation::Expand)
02300 emit q->expanded(viewItems.at(animatedOperation.item).index);
02301 else
02302 emit q->collapse(viewItems.at(animatedOperation.item).index);
02303 q->updateGeometries();
02304 viewport->update();
02305 }
02306
02307 void QTreeViewPrivate::drawAnimatedOperation(QPainter *painter) const
02308 {
02309 int start = timeline.startFrame();
02310 int end = timeline.endFrame();
02311 bool collapsing = animatedOperation.type == AnimatedOperation::Collapse;
02312 int current = collapsing ? end - timeline.currentFrame() + start : timeline.currentFrame();
02313 const QPixmap top = collapsing ? animatedOperation.before : animatedOperation.after;
02314 painter->drawPixmap(0, start, top, 0, end - current - 1, top.width(), top.height());
02315 const QPixmap bottom = collapsing ? animatedOperation.after : animatedOperation.before;
02316 painter->drawPixmap(0, current, bottom);
02317 }
02318
02319 QPixmap QTreeViewPrivate::renderTreeToPixmap(const QRect &rect) const
02320 {
02321 Q_Q(const QTreeView);
02322 QPixmap pixmap(rect.size());
02323 QPainter painter(&pixmap);
02324 painter.translate(0, -rect.top());
02325 q->drawTree(&painter, QRegion(rect));
02326 painter.end();
02327 return pixmap;
02328 }
02329
02330 void QTreeViewPrivate::_q_currentChanged(const QModelIndex ¤t, const QModelIndex &previous)
02331 {
02332 Q_Q(QTreeView);
02333 if (previous.isValid()) {
02334 QRect previousRect = q->visualRect(previous);
02335 if (allColumnsShowFocus) {
02336 previousRect.setX(0);
02337 previousRect.setWidth(viewport->width());
02338 }
02339 viewport->update(previousRect);
02340 }
02341 if (current.isValid()) {
02342 QRect currentRect = q->visualRect(current);
02343 if (allColumnsShowFocus) {
02344 currentRect.setX(0);
02345 currentRect.setWidth(viewport->width());
02346 }
02347 viewport->update(currentRect);
02348 }
02349 }
02350
02351 void QTreeViewPrivate::layout(int i)
02352 {
02353 Q_Q(QTreeView);
02354 QModelIndex current;
02355 QModelIndex parent = (i < 0) ? (QModelIndex)root : modelIndex(i);
02356
02357
02358 if (parent != root)
02359 parent = model->index(parent.row(), 0, parent.parent());
02360
02361 int count = 0;
02362 if (model->hasChildren(parent))
02363 count = model->rowCount(parent);
02364
02365 if (i == -1) {
02366 viewItems.resize(count);
02367 } else {
02368 if (viewItems[i].total != (uint)count)
02369 viewItems.insert(i + 1, count, QTreeViewItem());
02370 }
02371
02372 int first = i + 1;
02373 int level = (i >= 0 ? viewItems.at(i).level + 1 : 0);
02374 int hidden = 0;
02375 int last = 0;
02376
02377 int firstColumn = 0;
02378 while (q->isColumnHidden(firstColumn) && firstColumn < q->header()->count())
02379 ++firstColumn;
02380
02381 for (int j = first; j < first + count; ++j) {
02382 current = model->index(j - first, firstColumn, parent);
02383 if (q->isRowHidden(current.row(), parent)) {
02384 ++hidden;
02385 last = j - hidden;
02386 } else {
02387 last = j - hidden;
02388 viewItems[last].index = current;
02389 viewItems[last].level = level;
02390 }
02391 }
02392
02393
02394 if (hidden > 0)
02395 viewItems.remove(last + 1, hidden);
02396
02397 while (parent != root) {
02398 Q_ASSERT(i > -1);
02399 viewItems[i].total += count - hidden;
02400 parent = parent.parent();
02401 i = viewIndex(parent);
02402 }
02403 }
02404
02405 int QTreeViewPrivate::pageUp(int i) const
02406 {
02407 int index = itemAtCoordinate(coordinateForItem(i) - viewport->height());
02408 return index == -1 ? 0 : index;
02409 }
02410
02411 int QTreeViewPrivate::pageDown(int i) const
02412 {
02413 int index = itemAtCoordinate(coordinateForItem(i) + viewport->height());
02414 return index == -1 ? viewItems.count() - 1 : index;
02415 }
02416
02417 int QTreeViewPrivate::indentationForItem(int item) const
02418 {
02419 if (item < 0 || item >= viewItems.count())
02420 return 0;
02421 int level = viewItems.at(item).level;
02422 if (rootDecoration)
02423 ++level;
02424 return level * indent;
02425 }
02426
02427 int QTreeViewPrivate::itemHeight(int item) const
02428 {
02429 if (uniformRowHeights)
02430 return defaultItemHeight;
02431 if (viewItems.isEmpty())
02432 return 0;
02433 const QModelIndex &index = viewItems.at(item).index;
02434 int height = viewItems.at(item).height;
02435 if (height <= 0 && index.isValid()) {
02436 height = q_func()->indexRowSizeHint(index);
02437 viewItems[item].height = height;
02438 }
02439 if (!index.isValid() || height < 0)
02440 return 0;
02441 return height;
02442 }
02443
02444
02449 int QTreeViewPrivate::coordinateForItem(int item) const
02450 {
02451 Q_Q(const QTreeView);
02452 if (verticalScrollMode == QAbstractItemView::ScrollPerPixel) {
02453 if (uniformRowHeights)
02454 return (item * defaultItemHeight) - q->verticalScrollBar()->value();
02455
02456 int y = 0;
02457 for (int i = 0; i < viewItems.count(); ++i) {
02458 if (i == item)
02459 return y - q->verticalScrollBar()->value();
02460 y += itemHeight(i);
02461 }
02462 } else {
02463 int topViewItemIndex = q->verticalScrollBar()->value();
02464
02465
02466
02467
02468
02469 if (uniformRowHeights)
02470 return defaultItemHeight * (item - topViewItemIndex);
02471 if (item >= topViewItemIndex) {
02472
02473 int viewItemCoordinate = 0;
02474 int viewItemIndex = topViewItemIndex;
02475 while (viewItemIndex < viewItems.count()) {
02476 if (viewItemIndex == item)
02477 return viewItemCoordinate;
02478 viewItemCoordinate += itemHeight(viewItemIndex);
02479 ++viewItemIndex;
02480 }
02481
02482 Q_ASSERT(false);
02483 return viewItemCoordinate;
02484 } else {
02485
02486 int viewItemCoordinate = 0;
02487 for (int viewItemIndex = topViewItemIndex; viewItemIndex >= 0; --viewItemIndex) {
02488 if (viewItemIndex == item)
02489 return viewItemCoordinate;
02490 viewItemCoordinate -= itemHeight(viewItemIndex);
02491 }
02492
02493 Q_ASSERT(false);
02494 return viewItemCoordinate;
02495 }
02496 }
02497 return 0;
02498 }
02499
02507 int QTreeViewPrivate::itemAtCoordinate(int coordinate) const
02508 {
02509 Q_Q(const QTreeView);
02510 const int itemCount = viewItems.count();
02511 if (itemCount == 0)
02512 return -1;
02513 if (uniformRowHeights && defaultItemHeight <= 0)
02514 return -1;
02515 if (verticalScrollMode == QAbstractItemView::ScrollPerPixel) {
02516 if (uniformRowHeights) {
02517 const int viewItemIndex = (coordinate + q->verticalScrollBar()->value()) / defaultItemHeight;
02518 return (viewItemIndex >= itemCount ? -1 : viewItemIndex);
02519 }
02520
02521 int viewItemCoordinate = 0;
02522 const int contentsCoordinate = coordinate + q->verticalScrollBar()->value();
02523 for (int viewItemIndex = 0; viewItemIndex < viewItems.count(); ++viewItemIndex) {
02524 viewItemCoordinate += itemHeight(viewItemIndex);
02525 if (viewItemCoordinate >= contentsCoordinate)
02526 return (viewItemIndex >= itemCount ? -1 : viewItemIndex);
02527 }
02528 } else {
02529 int topViewItemIndex = q->verticalScrollBar()->value();
02530 if (uniformRowHeights) {
02531 const int viewItemIndex = topViewItemIndex + (coordinate / defaultItemHeight);
02532 return (viewItemIndex >= itemCount ? -1 : viewItemIndex);
02533 }
02534 if (coordinate >= 0) {
02535
02536 int viewItemCoordinate = 0;
02537 for (int viewItemIndex = topViewItemIndex; viewItemIndex < viewItems.count(); ++viewItemIndex) {
02538 viewItemCoordinate += itemHeight(viewItemIndex);
02539 if (viewItemCoordinate > coordinate)
02540 return (viewItemIndex >= itemCount ? -1 : viewItemIndex);
02541 }
02542 } else {
02543
02544 int viewItemCoordinate = 0;
02545 for (int viewItemIndex = topViewItemIndex; viewItemIndex >= 0; --viewItemIndex) {
02546 if (viewItemCoordinate <= coordinate)
02547 return (viewItemIndex >= itemCount ? -1 : viewItemIndex);
02548 viewItemCoordinate -= itemHeight(viewItemIndex);
02549 }
02550 }
02551 }
02552 return -1;
02553 }
02554
02555 int QTreeViewPrivate::viewIndex(const QModelIndex &index) const
02556 {
02557 if (!index.isValid())
02558 return -1;
02559
02560 int totalCount = viewItems.count();
02561 QModelIndex parent = index.parent();
02562
02563
02564 int start = lastViewedItem > 2 ? lastViewedItem - 2 : 0;
02565 int end = lastViewedItem < totalCount - 2 ? lastViewedItem + 2 : totalCount;
02566 for (int i = start; i < end; ++i) {
02567 const QModelIndex &idx = viewItems.at(i).index;
02568 if (idx.row() == index.row()) {
02569 if (idx.internalId() == index.internalId() || idx.parent() == parent) {
02570 lastViewedItem = i;
02571 return i;
02572 }
02573 }
02574 }
02575
02576
02577
02578 int t = firstVisibleItem();
02579 t = t > 100 ? t - 100 : 0;
02580
02581 for (int i = t; i < totalCount; ++i) {
02582 const QModelIndex &idx = viewItems.at(i).index;
02583 if (idx.row() == index.row()) {
02584 if (idx.internalId() == index.internalId() || idx.parent() == parent) {
02585 lastViewedItem = i;
02586 return i;
02587 }
02588 }
02589 }
02590
02591 for (int j = 0; j < t; ++j) {
02592 const QModelIndex &idx = viewItems.at(j).index;
02593 if (idx.row() == index.row()) {
02594 if (idx.internalId() == index.internalId() || idx.parent() == parent) {
02595 lastViewedItem = j;
02596 return j;
02597 }
02598 }
02599 }
02600
02601 return -1;
02602 }
02603
02604 QModelIndex QTreeViewPrivate::modelIndex(int i) const
02605 {
02606 return ((i < 0 || i >= viewItems.count())
02607 ? QModelIndex() : viewItems.at(i).index);
02608 }
02609
02610 int QTreeViewPrivate::firstVisibleItem(int *offset) const
02611 {
02612 Q_Q(const QTreeView);
02613 const int value = q->verticalScrollBar()->value();
02614 if (verticalScrollMode == QAbstractItemView::ScrollPerItem) {
02615 if (offset)
02616 *offset = 0;
02617 return (value < 0 || value >= viewItems.count()) ? -1 : value;
02618 }
02619
02620 if (uniformRowHeights) {
02621 if (offset)
02622 *offset = -(value % defaultItemHeight);
02623 return value / defaultItemHeight;
02624 }
02625 int y = 0;
02626 for (int i = 0; i < viewItems.count(); ++i) {
02627 y += itemHeight(i);
02628 if (y > value) {
02629 if (offset)
02630 *offset = y - value - itemHeight(i);
02631 return i;
02632 }
02633 }
02634 return -1;
02635 }
02636
02637 int QTreeViewPrivate::columnAt(int x) const
02638 {
02639 return header->logicalIndexAt(x);
02640 }
02641
02642 void QTreeViewPrivate::relayout(const QModelIndex &parent)
02643 {
02644 Q_Q(QTreeView);
02645
02646 if (parent.isValid()) {
02647 int parentViewIndex = viewIndex(parent);
02648 if (parentViewIndex > -1 && viewItems.at(parentViewIndex).expanded) {
02649 collapse(parentViewIndex, false);
02650 expand(parentViewIndex, false);
02651 q->updateGeometries();
02652 viewport->update();
02653 }
02654 } else {
02655 viewItems.clear();
02656 q->doItemsLayout();
02657 }
02658 }
02659
02660 void QTreeViewPrivate::reexpandChildren(const QModelIndex &parent)
02661 {
02662 if (!model)
02663 return;
02664
02665 QVector<int> toBeExpanded;
02666 QVector<QPersistentModelIndex>::iterator it;
02667 for (it = expandedIndexes.begin(); it != expandedIndexes.end(); ) {
02668 QModelIndex index = *it;
02669 if (!index.isValid()) {
02670 it = expandedIndexes.erase(it);
02671 } else if (model->parent(index) == parent) {
02672 int v = viewIndex(index);
02673 if (v >= 0) {
02674 toBeExpanded.append(v);
02675 it = expandedIndexes.erase(it);
02676 } else {
02677 ++it;
02678 }
02679 } else {
02680 ++it;
02681 }
02682 }
02683 qSort(toBeExpanded.begin(), toBeExpanded.end(), qGreater<int>());
02684 for (int i = 0; i < toBeExpanded.count(); ++i)
02685 expand(toBeExpanded.at(i), false);
02686 }
02687
02688 void QTreeViewPrivate::updateScrollBars()
02689 {
02690 Q_Q(QTreeView);
02691 QSize viewportSize = viewport->size();
02692 if (!viewportSize.isValid())
02693 viewportSize = QSize(0, 0);
02694
02695 if (verticalScrollMode == QAbstractItemView::ScrollPerItem) {
02696 int itemsInViewport = 0;
02697 if (uniformRowHeights) {
02698 if (defaultItemHeight == 0)
02699 itemsInViewport = viewItems.count();
02700 else
02701 itemsInViewport = viewportSize.height() / defaultItemHeight;
02702 } else {
02703 const int itemsCount = viewItems.count();
02704 const int viewportHeight = viewportSize.height();
02705 for (int height = 0, item = itemsCount - 1; item >= 0; --item) {
02706 height += itemHeight(item);
02707 if (height > viewportHeight)
02708 break;
02709 ++itemsInViewport;
02710 }
02711 }
02712 if (!viewItems.isEmpty())
02713 itemsInViewport = qMax(1, itemsInViewport);
02714 q->verticalScrollBar()->setRange(0, viewItems.count() - itemsInViewport);
02715 q->verticalScrollBar()->setPageStep(itemsInViewport);
02716 } else {
02717 int contentsHeight = 0;
02718 if (uniformRowHeights) {
02719 contentsHeight = defaultItemHeight * viewItems.count();
02720 } else {
02721 for (int i = 0; i < viewItems.count(); ++i)
02722 contentsHeight += itemHeight(i);
02723 }
02724 q->verticalScrollBar()->setRange(0, contentsHeight - viewportSize.height());
02725 q->verticalScrollBar()->setPageStep(viewportSize.height());
02726 }
02727
02728 if (horizontalScrollMode == QAbstractItemView::ScrollPerItem) {
02729 const int columnCount = header->count();
02730 const int viewportWidth = viewportSize.width();
02731 int columnsInViewport = 0;
02732 for (int width = 0, column = columnCount - 1; column >= 0; --column) {
02733 int logical = header->logicalIndex(column);
02734 width += header->sectionSize(logical);
02735 if (width > viewportWidth)
02736 break;
02737 ++columnsInViewport;
02738 }
02739 if (columnCount > 0)
02740 columnsInViewport = qMax(1, columnsInViewport);
02741 q->horizontalScrollBar()->setRange(0, columnCount - columnsInViewport);
02742 q->horizontalScrollBar()->setPageStep(columnsInViewport);
02743 } else {
02744 const int horizontalLength = header->length();
02745 const QSize maxSize = q->maximumViewportSize();
02746 if (maxSize.width() >= horizontalLength && q->verticalScrollBar()->maximum() <= 0)
02747 viewportSize = maxSize;
02748 q->horizontalScrollBar()->setPageStep(viewportSize.width());
02749 q->horizontalScrollBar()->setRange(0, qMax(horizontalLength - viewportSize.width(), 0));
02750 }
02751 }
02752
02753 int QTreeViewPrivate::itemDecorationAt(const QPoint &pos) const
02754 {
02755 Q_Q(const QTreeView);
02756 int x = pos.x();
02757 int column = header->logicalIndexAt(x);
02758 if (column == -1)
02759 return -1;
02760 int position = header->sectionViewportPosition(column);
02761 int size = header->sectionSize(column);
02762 int cx = (q->isRightToLeft() ? size - x + position : x - position);
02763 int viewItemIndex = itemAtCoordinate(pos.y());
02764 int itemIndentation = indentationForItem(viewItemIndex);
02765 QModelIndex index = modelIndex(viewItemIndex);
02766
02767 if (!index.isValid() || column != 0
02768 || cx < (itemIndentation - indent) || cx > itemIndentation)
02769 return -1;
02770
02771 if (!rootDecoration && index.parent() == root)
02772 return -1;
02773
02774 QRect rect;
02775 if (q->isRightToLeft())
02776 rect = QRect(position + size - itemIndentation, coordinateForItem(viewItemIndex),
02777 indent, itemHeight(viewItemIndex));
02778 else
02779 rect = QRect(position + itemIndentation - indent, coordinateForItem(viewItemIndex),
02780 indent, itemHeight(viewItemIndex));
02781 QStyleOption opt;
02782 opt.initFrom(q);
02783 opt.rect = rect;
02784 QRect returning = q->style()->subElementRect(QStyle::SE_TreeViewDisclosureItem, &opt, q);
02785 if (!returning.contains(pos))
02786 return -1;
02787
02788 return viewItemIndex;
02789 }
02790
02791 void QTreeViewPrivate::select(int top, int bottom,
02792 QItemSelectionModel::SelectionFlags command)
02793 {
02794 Q_Q(QTreeView);
02795 QModelIndex previous;
02796 QItemSelectionRange currentRange;
02797 QStack<QItemSelectionRange> rangeStack;
02798 QItemSelection selection;
02799 for (int i = top; i <= bottom; ++i) {
02800 QModelIndex index = modelIndex(i);
02801 QModelIndex parent = index.parent();
02802 if (previous.isValid() && parent == previous.parent()) {
02803
02804 QModelIndex tl = model->index(currentRange.top(), currentRange.left(),
02805 currentRange.parent());
02806 currentRange = QItemSelectionRange(tl, index);
02807 } else if (previous.isValid() && parent == model->sibling(previous.row(), 0, previous)) {
02808
02809 rangeStack.push(currentRange);
02810 currentRange = QItemSelectionRange(index);
02811 } else {
02812 if (currentRange.isValid())
02813 selection.append(currentRange);
02814 if (rangeStack.isEmpty()) {
02815 currentRange = QItemSelectionRange(index);
02816 } else {
02817 currentRange = rangeStack.pop();
02818 if (parent == currentRange.parent()) {
02819 QModelIndex tl = model->index(currentRange.top(),
02820 currentRange.left(),
02821 currentRange.parent());
02822 currentRange = QItemSelectionRange(tl, index);
02823 } else {
02824 selection.append(currentRange);
02825 currentRange = QItemSelectionRange(index);
02826 }
02827 }
02828 }
02829 previous = index;
02830 }
02831 if (currentRange.isValid())
02832 selection.append(currentRange);
02833 for (int i = 0; i < rangeStack.count(); ++i)
02834 selection.append(rangeStack.at(i));
02835 q->selectionModel()->select(selection, command);
02836 }
02837
02838 QPair<int,int> QTreeViewPrivate::startAndEndColumns(const QRect &rect) const
02839 {
02840 Q_Q(const QTreeView);
02841 int start = header->visualIndexAt(rect.left());
02842 int end = header->visualIndexAt(rect.right());
02843 if (q->isRightToLeft()) {
02844 start = (start == -1 ? header->count() - 1 : start);
02845 end = (end == -1 ? 0 : end);
02846 } else {
02847 start = (start == -1 ? 0 : start);
02848 end = (end == -1 ? header->count() - 1 : end);
02849 }
02850 return qMakePair<int,int>(qMin(start, end), qMax(start, end));
02851 }
02852
02853 bool QTreeViewPrivate::hasVisibleChildren(const QModelIndex& parent) const
02854 {
02855 Q_Q(const QTreeView);
02856 if (model->hasChildren(parent)) {
02857 if (hiddenIndexes.isEmpty())
02858 return true;
02859 if (q->isIndexHidden(parent))
02860 return false;
02861 int rowCount = model->rowCount(parent);
02862 for (int i = 0; i < rowCount; ++i) {
02863 if (!q->isRowHidden(i, parent))
02864 return true;
02865 }
02866 if (rowCount == 0)
02867 return true;
02868 }
02869 return false;
02870 }
02871
02872 QStyleOptionViewItemV2 QTreeViewPrivate::viewOptionsV2() const
02873 {
02874 Q_Q(const QTreeView);
02875 QStyleOptionViewItemV2 option = q->viewOptions();
02876
02877
02878 return option;
02879 }
02880
02881 #include "moc_qtreeview.cpp"
02882
02883 #endif // QT_NO_TREEVIEW