diff options
author | Thierry Bastian <thierry.bastian@nokia.com> | 2009-08-19 15:24:48 (GMT) |
---|---|---|
committer | Thierry Bastian <thierry.bastian@nokia.com> | 2009-08-20 12:27:38 (GMT) |
commit | 18eccf4189f4a093fb7d2418a1f3518da971aefa (patch) | |
tree | 7b11a7e44dfa85678b42a79920472fc7a4892dd4 /src/gui/itemviews | |
parent | 26932652ac38f64fee86b50a72c709dfba81647a (diff) | |
download | Qt-18eccf4189f4a093fb7d2418a1f3518da971aefa.zip Qt-18eccf4189f4a093fb7d2418a1f3518da971aefa.tar.gz Qt-18eccf4189f4a093fb7d2418a1f3518da971aefa.tar.bz2 |
QListView refactor: we now have an interface for the 2 view modes
Now we have 2 real implementations for listviews and iconviews
This is a big refactor but the behaviour is kept.
It also fixes a crash that could occur in setPositionForIndex
while in ListMode.
Acknowledged-By: ogoffart
Diffstat (limited to 'src/gui/itemviews')
-rw-r--r-- | src/gui/itemviews/qabstractitemview.cpp | 10 | ||||
-rw-r--r-- | src/gui/itemviews/qabstractitemview_p.h | 9 | ||||
-rw-r--r-- | src/gui/itemviews/qlistview.cpp | 986 | ||||
-rw-r--r-- | src/gui/itemviews/qlistview_p.h | 209 |
4 files changed, 586 insertions, 628 deletions
diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp index 9eb71b7..d79a378 100644 --- a/src/gui/itemviews/qabstractitemview.cpp +++ b/src/gui/itemviews/qabstractitemview.cpp @@ -3378,11 +3378,7 @@ QPoint QAbstractItemView::dirtyRegionOffset() const */ void QAbstractItemView::startAutoScroll() { - Q_D(QAbstractItemView); - // ### it would be nice to make this into a style hint one day - int scrollInterval = (verticalScrollMode() == QAbstractItemView::ScrollPerItem) ? 150 : 50; - d->autoScrollTimer.start(scrollInterval, this); - d->autoScrollCount = 0; + d_func()->startAutoScroll(); } /*! @@ -3390,9 +3386,7 @@ void QAbstractItemView::startAutoScroll() */ void QAbstractItemView::stopAutoScroll() { - Q_D(QAbstractItemView); - d->autoScrollTimer.stop(); - d->autoScrollCount = 0; + d_func()->stopAutoScroll(); } /*! diff --git a/src/gui/itemviews/qabstractitemview_p.h b/src/gui/itemviews/qabstractitemview_p.h index 2ba027d..e7991d2 100644 --- a/src/gui/itemviews/qabstractitemview_p.h +++ b/src/gui/itemviews/qabstractitemview_p.h @@ -126,6 +126,15 @@ public: void doDelayedItemsLayout(int delay = 0); void interruptDelayedItemsLayout() const; + void startAutoScroll() + { // ### it would be nice to make this into a style hint one day + int scrollInterval = (verticalScrollMode == QAbstractItemView::ScrollPerItem) ? 150 : 50; + autoScrollTimer.start(scrollInterval, q_func()); + autoScrollCount = 0; + } + void stopAutoScroll() { autoScrollTimer.stop(); autoScrollCount = 0;} + + bool dropOn(QDropEvent *event, int *row, int *col, QModelIndex *index); bool droppingOnItself(QDropEvent *event, const QModelIndex &index); diff --git a/src/gui/itemviews/qlistview.cpp b/src/gui/itemviews/qlistview.cpp index cc9d643..3e9db3b 100644 --- a/src/gui/itemviews/qlistview.cpp +++ b/src/gui/itemviews/qlistview.cpp @@ -458,15 +458,13 @@ QSize QListView::gridSize() const void QListView::setViewMode(ViewMode mode) { Q_D(QListView); - if (d->viewMode == mode) + if (d->commonListView && d->viewMode == mode) return; d->viewMode = mode; + delete d->commonListView; if (mode == ListMode) { - delete d->dynamicListView; - d->dynamicListView = 0; - if (!d->staticListView) - d->staticListView = new QStaticListViewBase(this, d); + d->commonListView = new QListModeViewBase(this, d); if (!(d->modeProperties & QListViewPrivate::Wrap)) d->setWrapping(false); if (!(d->modeProperties & QListViewPrivate::Spacing)) @@ -482,10 +480,7 @@ void QListView::setViewMode(ViewMode mode) if (!(d->modeProperties & QListViewPrivate::SelectionRectVisible)) d->showElasticBand = false; } else { - delete d->staticListView; - d->staticListView = 0; - if (!d->dynamicListView) - d->dynamicListView = new QDynamicListViewBase(this, d); + d->commonListView = new QIconModeViewBase(this, d); if (!(d->modeProperties & QListViewPrivate::Wrap)) d->setWrapping(true); if (!(d->modeProperties & QListViewPrivate::Spacing)) @@ -549,24 +544,12 @@ void QListView::setRowHidden(int row, bool hide) { Q_D(QListView); const bool hidden = d->isHidden(row); - if (d->viewMode == ListMode) { - if (hide && !hidden) - d->hiddenRows.append(d->model->index(row, 0)); - else if (!hide && hidden) - d->hiddenRows.remove(d->hiddenRows.indexOf(d->model->index(row, 0))); - d->doDelayedItemsLayout(); - } else { - if (hide && !hidden) { - d->dynamicListView->removeItem(row); - d->hiddenRows.append(d->model->index(row, 0)); - } else if (!hide && hidden) { - d->hiddenRows.remove(d->hiddenRows.indexOf(d->model->index(row, 0))); - d->dynamicListView->insertItem(row); - } - if (d->resizeMode == Adjust) - d->doDelayedItemsLayout(); - d->viewport->update(); - } + if (hide && !hidden) + d->commonListView->appendHiddenRow(row); + else if (!hide && hidden) + d->commonListView->removeHiddenRow(row); + d->doDelayedItemsLayout(); + d->viewport->update(); } /*! @@ -575,7 +558,7 @@ void QListView::setRowHidden(int row, bool hide) QRect QListView::visualRect(const QModelIndex &index) const { Q_D(const QListView); - return d->mapToViewport(rectForIndex(index), d->viewMode == QListView::ListMode); + return d->mapToViewport(rectForIndex(index)); } /*! @@ -612,69 +595,17 @@ int QListViewPrivate::horizontalScrollToValue(const QModelIndex &index, const QR const bool rightOf = q->isRightToLeft() ? rect.right() > area.right() : (rect.right() > area.right()) && (rect.left() > area.left()); - int horizontalValue = hbar->value(); - - // ScrollPerItem - if (q->horizontalScrollMode() == QAbstractItemView::ScrollPerItem && viewMode == QListView::ListMode) { - const QListViewItem item = indexToListViewItem(index); - const QRect rect = q->visualRect(index); - horizontalValue = staticListView->horizontalPerItemValue(itemIndex(item), - horizontalValue, area.width(), - leftOf, rightOf, isWrapping(), hint, rect.width()); - } else { // ScrollPerPixel - if (q->isRightToLeft()) { - if (hint == QListView::PositionAtCenter) { - horizontalValue += ((area.width() - rect.width()) / 2) - rect.left(); - } else { - if (leftOf) - horizontalValue -= rect.left(); - else if (rightOf) - horizontalValue += qMin(rect.left(), area.width() - rect.right()); - } - } else { - if (hint == QListView::PositionAtCenter) { - horizontalValue += rect.left() - ((area.width()- rect.width()) / 2); - } else { - if (leftOf) - horizontalValue += rect.left(); - else if (rightOf) - horizontalValue += qMin(rect.left(), rect.right() - area.width()); - } - } - } - return horizontalValue; + return commonListView->horizontalScrollToValue(q->visualIndex(index), hint, leftOf, rightOf, area, rect); } int QListViewPrivate::verticalScrollToValue(const QModelIndex &index, const QRect &rect, QListView::ScrollHint hint) const { Q_Q(const QListView); - const QRect area = viewport->rect(); const bool above = (hint == QListView::EnsureVisible && rect.top() < area.top()); const bool below = (hint == QListView::EnsureVisible && rect.bottom() > area.bottom()); - - int verticalValue = vbar->value(); - - // ScrollPerItem - if (verticalScrollMode == QAbstractItemView::ScrollPerItem && viewMode == QListView::ListMode) { - const QListViewItem item = indexToListViewItem(index); - const QRect rect = q->visualRect(index); - verticalValue = staticListView->verticalPerItemValue(itemIndex(item), - verticalValue, area.height(), - above, below, isWrapping(), hint, rect.height()); - - } else { // ScrollPerPixel - QRect adjusted = rect.adjusted(-spacing(), -spacing(), spacing(), spacing()); - if (hint == QListView::PositionAtTop || above) - verticalValue += adjusted.top(); - else if (hint == QListView::PositionAtBottom || below) - verticalValue += qMin(adjusted.top(), adjusted.bottom() - area.height() + 1); - else if (hint == QListView::PositionAtCenter) - verticalValue += adjusted.top() - ((area.height() - adjusted.height()) / 2); - } - - return verticalValue; + return commonListView->verticalScrollToValue(q->visualIndex(index), hint, above, below, area, rect); } void QListViewPrivate::selectAll(QItemSelectionModel::SelectionFlags command) @@ -766,23 +697,12 @@ void QListView::setRootIndex(const QModelIndex &index) Scroll the view contents by \a dx and \a dy. */ + void QListView::scrollContentsBy(int dx, int dy) { Q_D(QListView); - d->delayedAutoScroll.stop(); // auto scroll was canceled by the user scrolling - - if (d->viewMode == ListMode) - d->staticListView->scrollContentsBy(dx, dy); - else if (state() == DragSelectingState) - d->scrollElasticBandBy(isRightToLeft() ? -dx : dx, dy); - - d->scrollContentsBy(isRightToLeft() ? -dx : dx, dy); - - // update the dragged items - if (d->viewMode == IconMode) // ### move to dynamic class - if (!d->dynamicListView->draggedItems.isEmpty()) - d->viewport->update(d->dynamicListView->draggedItemsRect().translated(dx, dy)); + d->commonListView->scrollContentsBy(dx, dy, d->state == QListView::DragSelectingState); } /*! @@ -811,9 +731,7 @@ QSize QListView::contentsSize() const */ void QListView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { - Q_D(QListView); - if (d->viewMode == IconMode) - d->dynamicListView->dataChanged(topLeft, bottomRight); + d_func()->commonListView->dataChanged(topLeft, bottomRight); QAbstractItemView::dataChanged(topLeft, bottomRight); } @@ -864,7 +782,7 @@ void QListView::mouseMoveEvent(QMouseEvent *e) && d->selectionMode != NoSelection) { QRect rect(d->pressedPosition, e->pos() + QPoint(horizontalOffset(), verticalOffset())); rect = rect.normalized(); - d->viewport->update(d->mapToViewport(rect.united(d->elasticBand), d->viewMode == QListView::ListMode)); + d->viewport->update(d->mapToViewport(rect.united(d->elasticBand))); d->elasticBand = rect; } } @@ -878,7 +796,7 @@ void QListView::mouseReleaseEvent(QMouseEvent *e) QAbstractItemView::mouseReleaseEvent(e); // #### move this implementation into a dynamic class if (d->showElasticBand && d->elasticBand.isValid()) { - d->viewport->update(d->mapToViewport(d->elasticBand, d->viewMode == QListView::ListMode)); + d->viewport->update(d->mapToViewport(d->elasticBand)); d->elasticBand = QRect(); } } @@ -935,69 +853,27 @@ void QListView::resizeEvent(QResizeEvent *e) */ void QListView::dragMoveEvent(QDragMoveEvent *e) { - // ### move implementation to dynamic - Q_D(QListView); - if (e->source() == this && d->viewMode == IconMode) { - // the ignore by default - e->ignore(); - if (d->canDecode(e)) { - // get old dragged items rect - QRect itemsRect = d->dynamicListView->itemsRect(d->dynamicListView->draggedItems); - d->viewport->update(itemsRect.translated(d->dynamicListView->draggedItemsDelta())); - // update position - d->dynamicListView->draggedItemsPos = e->pos(); - // get new items rect - d->viewport->update(itemsRect.translated(d->dynamicListView->draggedItemsDelta())); - // set the item under the cursor to current - QModelIndex index; - if (d->movement == Snap) { - QRect rect(d->dynamicListView->snapToGrid(e->pos() + d->offset()), d->gridSize()); - const QVector<QModelIndex> intersectVector = d->intersectingSet(rect); - index = intersectVector.count() > 0 - ? intersectVector.last() : QModelIndex(); - } else { - index = indexAt(e->pos()); - } - // check if we allow drops here - if (e->source() == this && d->dynamicListView->draggedItems.contains(index)) - e->accept(); // allow changing item position - else if (d->model->flags(index) & Qt::ItemIsDropEnabled) - e->accept(); // allow dropping on dropenabled items - else if (!index.isValid()) - e->accept(); // allow dropping in empty areas - } - // do autoscrolling - if (d->shouldAutoScroll(e->pos())) - startAutoScroll(); - } else { // not internal + if (!d_func()->commonListView->filterDragMoveEvent(e)) QAbstractItemView::dragMoveEvent(e); - } } + /*! \reimp */ void QListView::dragLeaveEvent(QDragLeaveEvent *e) { - // ### move implementation to dynamic - Q_D(QListView); - if (d->viewMode == IconMode) { - d->viewport->update(d->dynamicListView->draggedItemsRect()); // erase the area - d->dynamicListView->draggedItemsPos = QPoint(-1, -1); // don't draw the dragged items - } - QAbstractItemView::dragLeaveEvent(e); + if (!d_func()->commonListView->filterDragLeaveEvent(e)) + QAbstractItemView::dragLeaveEvent(e); } /*! \reimp */ -void QListView::dropEvent(QDropEvent *event) +void QListView::dropEvent(QDropEvent *e) { - Q_D(QListView); - if (event->source() == this && d->viewMode == IconMode) - internalDrop(event); // ### move to dynamic - else - QAbstractItemView::dropEvent(event); + if (!d_func()->commonListView->filterDropEvent(e)) + QAbstractItemView::dropEvent(e); } /*! @@ -1005,10 +881,7 @@ void QListView::dropEvent(QDropEvent *event) */ void QListView::startDrag(Qt::DropActions supportedActions) { - Q_D(QListView); - if (d->viewMode == IconMode) // ### move to dynamic - internalDrag(supportedActions); - else + if (!d_func()->commonListView->filterStartDrag(supportedActions)) QAbstractItemView::startDrag(supportedActions); } @@ -1020,41 +893,8 @@ void QListView::startDrag(Qt::DropActions supportedActions) */ void QListView::internalDrop(QDropEvent *event) { - Q_D(QListView); - if (d->viewMode == QListView::ListMode) - return; - - // ### move to dynamic class - QPoint offset(horizontalOffset(), verticalOffset()); - QPoint end = event->pos() + offset; - QPoint start = d->pressedPosition; - QPoint delta = (d->movement == Snap ? - d->dynamicListView->snapToGrid(end) - - d->dynamicListView->snapToGrid(start) : end - start); - QSize contents = d->contentsSize(); - QList<QModelIndex> indexes = d->selectionModel->selectedIndexes(); - for (int i = 0; i < indexes.count(); ++i) { - QModelIndex index = indexes.at(i); - QRect rect = rectForIndex(index); - d->viewport->update(d->mapToViewport(rect, d->viewMode == QListView::ListMode)); - QPoint dest = rect.topLeft() + delta; - if (isRightToLeft()) - dest.setX(d->flipX(dest.x()) - rect.width()); - d->dynamicListView->moveItem(index.row(), dest); - update(index); - } - stopAutoScroll(); - d->dynamicListView->draggedItems.clear(); - emit indexesMoved(indexes); - event->accept(); // we have handled the event - // if the size has not grown, we need to check if it has shrinked - if (d->dynamicListView - && (d->contentsSize().width() <= contents.width() - || d->contentsSize().height() <= contents.height())) { - d->dynamicListView->updateContentsSize(); - } - if (d->contentsSize() != contents) - updateGeometries(); + // ### Qt5: remove that function + Q_UNUSED(event); } /*! @@ -1065,31 +905,8 @@ void QListView::internalDrop(QDropEvent *event) */ void QListView::internalDrag(Qt::DropActions supportedActions) { - Q_D(QListView); - if (d->viewMode == QListView::ListMode) - return; - - // #### move to dynamic class - - // This function does the same thing as in QAbstractItemView::startDrag(), - // plus adding viewitems to the draggedItems list. - // We need these items to draw the drag items - QModelIndexList indexes = d->selectionModel->selectedIndexes(); - if (indexes.count() > 0 ) { - if (d->viewport->acceptDrops()) { - QModelIndexList::ConstIterator it = indexes.constBegin(); - for (; it != indexes.constEnd(); ++it) - if (d->model->flags(*it) & Qt::ItemIsDragEnabled - && (*it).column() == d->column) - d->dynamicListView->draggedItems.push_back(*it); - } - QDrag *drag = new QDrag(this); - drag->setMimeData(d->model->mimeData(indexes)); - Qt::DropAction action = drag->exec(supportedActions, Qt::CopyAction); - d->dynamicListView->draggedItems.clear(); - if (action == Qt::MoveAction) - d->clearOrRemove(); - } + // ### Qt5: remove that function + Q_UNUSED(supportedActions); } #endif // QT_NO_DRAGANDDROP @@ -1117,6 +934,7 @@ QStyleOptionViewItem QListView::viewOptions() const return option; } + /*! \reimp */ @@ -1213,18 +1031,7 @@ void QListView::paintEvent(QPaintEvent *e) } #ifndef QT_NO_DRAGANDDROP - // #### move this implementation into a dynamic class - if (d->viewMode == IconMode) - if (!d->dynamicListView->draggedItems.isEmpty() - && d->viewport->rect().contains(d->dynamicListView->draggedItemsPos)) { - QPoint delta = d->dynamicListView->draggedItemsDelta(); - painter.translate(delta.x(), delta.y()); - d->dynamicListView->drawItems(&painter, d->dynamicListView->draggedItems); - } - // FIXME: Until the we can provide a proper drop indicator - // in IconMode, it makes no sense to show it - if (d->viewMode == ListMode) - d->paintDropIndicator(&painter); + d->commonListView->paintDragDrop(&painter); #endif #ifndef QT_NO_RUBBERBAND @@ -1263,31 +1070,7 @@ QModelIndex QListView::indexAt(const QPoint &p) const */ int QListView::horizontalOffset() const { - Q_D(const QListView); - // ### split into static and dynamic - if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem && d->viewMode == ListMode) { - if (d->isWrapping()) { - if (d->flow == TopToBottom && !d->staticListView->segmentPositions.isEmpty()) { - const int max = d->staticListView->segmentPositions.count() - 1; - int currentValue = qBound(0, horizontalScrollBar()->value(), max); - int position = d->staticListView->segmentPositions.at(currentValue); - int maximumValue = qBound(0, horizontalScrollBar()->maximum(), max); - int maximum = d->staticListView->segmentPositions.at(maximumValue); - return (isRightToLeft() ? maximum - position : position); - } - //return 0; - } else { - if (d->flow == LeftToRight && !d->staticListView->flowPositions.isEmpty()) { - int position = d->staticListView->flowPositions.at(horizontalScrollBar()->value()); - int maximum = d->staticListView->flowPositions.at(horizontalScrollBar()->maximum()); - return (isRightToLeft() ? maximum - position : position); - } - //return 0; - } - } - return (isRightToLeft() - ? horizontalScrollBar()->maximum() - horizontalScrollBar()->value() - : horizontalScrollBar()->value()); + return d_func()->commonListView->horizontalOffset(); } /*! @@ -1295,30 +1078,7 @@ int QListView::horizontalOffset() const */ int QListView::verticalOffset() const { - // ## split into static and dynamic - Q_D(const QListView); - if (verticalScrollMode() == QAbstractItemView::ScrollPerItem && d->viewMode == ListMode) { - if (d->isWrapping()) { - if (d->flow == LeftToRight && !d->staticListView->segmentPositions.isEmpty()) { - int value = verticalScrollBar()->value(); - if (value >= d->staticListView->segmentPositions.count()) { - //qWarning("QListView: Vertical scroll bar is out of bounds"); - return 0; - } - return d->staticListView->segmentPositions.at(value); - } - } else { - if (d->flow == TopToBottom && !d->staticListView->flowPositions.isEmpty()) { - int value = verticalScrollBar()->value(); - if (value > d->staticListView->flowPositions.count()) { - //qWarning("QListView: Vertical scroll bar is out of bounds"); - return 0; - } - return d->staticListView->flowPositions.at(value) - d->spacing(); - } - } - } - return verticalScrollBar()->value(); + return d_func()->commonListView->verticalOffset(); } /*! @@ -1444,15 +1204,7 @@ QModelIndex QListView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifie */ QRect QListView::rectForIndex(const QModelIndex &index) const { - Q_D(const QListView); - if (!d->isIndexValid(index) - || index.parent() != d->root - || index.column() != d->column - || isIndexHidden(index)) - return QRect(); - d->executePostedLayout(); - QListViewItem item = d->indexToListViewItem(index); - return d->viewItemRect(item); + return d_func()->rectForIndex(index); } /*! @@ -1460,8 +1212,8 @@ QRect QListView::rectForIndex(const QModelIndex &index) const Sets the contents position of the item at \a index in the model to the given \a position. - If the list view's movement mode is Static, this function will have no - effect. + If the list view's movement mode is Static or its view mode is ListView, + this function will have no effect. */ void QListView::setPositionForIndex(const QPoint &position, const QModelIndex &index) { @@ -1473,15 +1225,7 @@ void QListView::setPositionForIndex(const QPoint &position, const QModelIndex &i return; d->executePostedLayout(); - if (index.row() >= d->dynamicListView->items.count()) - return; - const QSize oldContents = d->contentsSize(); - update(index); // update old position - d->dynamicListView->moveItem(index.row(), position); - update(index); // update new position - - if (d->contentsSize() != oldContents) - updateGeometries(); // update the scroll bars + d->commonListView->setPositionForIndex(position, index); } /*! @@ -1717,99 +1461,8 @@ void QListView::updateGeometries() QModelIndex index = d->model->index(0, d->column, d->root); QStyleOptionViewItemV4 option = d->viewOptionsV4(); QSize step = d->itemSize(option, index); - - QSize csize = d->contentsSize(); - QSize vsize = d->viewport->size(); - QSize max = maximumViewportSize(); - if (max.width() >= d->contentsSize().width() && max.height() >= d->contentsSize().height()) - vsize = max; - - // ### reorder the logic - - // ### split into static and dynamic - - const bool vertical = verticalScrollMode() == QAbstractItemView::ScrollPerItem; - const bool horizontal = horizontalScrollMode() == QAbstractItemView::ScrollPerItem; - - if (d->flow == TopToBottom) { - if (horizontal && d->isWrapping() && d->viewMode == ListMode) { - const QVector<int> segmentPositions = d->staticListView->segmentPositions; - const int steps = segmentPositions.count() - 1; - if (steps > 0) { - int pageSteps = d->staticListView->perItemScrollingPageSteps(vsize.width(), - csize.width(), - isWrapping()); - horizontalScrollBar()->setSingleStep(1); - horizontalScrollBar()->setPageStep(pageSteps); - horizontalScrollBar()->setRange(0, steps - pageSteps); - } else { - horizontalScrollBar()->setRange(0, 0); - } - } else { - horizontalScrollBar()->setSingleStep(step.width() + d->spacing()); - horizontalScrollBar()->setPageStep(vsize.width()); - horizontalScrollBar()->setRange(0, d->contentsSize().width() - vsize.width()); - } - if (vertical && !d->isWrapping() && d->viewMode == ListMode) { - const QVector<int> flowPositions = d->staticListView->flowPositions; - const int steps = flowPositions.count() - 1; - if (steps > 0) { - int pageSteps = d->staticListView->perItemScrollingPageSteps(vsize.height(), - csize.height(), - isWrapping()); - verticalScrollBar()->setSingleStep(1); - verticalScrollBar()->setPageStep(pageSteps); - verticalScrollBar()->setRange(0, steps - pageSteps); - } else { - verticalScrollBar()->setRange(0, 0); - } - // } else if (vertical && d->isWrapping() && d->movement == Static) { - // ### wrapped scrolling in flow direction - } else { - verticalScrollBar()->setSingleStep(step.height() + d->spacing()); - verticalScrollBar()->setPageStep(vsize.height()); - verticalScrollBar()->setRange(0, d->contentsSize().height() - vsize.height()); - } - } else { // LeftToRight - if (horizontal && !d->isWrapping() && d->viewMode == ListMode) { - const QVector<int> flowPositions = d->staticListView->flowPositions; - int steps = flowPositions.count() - 1; - if (steps > 0) { - int pageSteps = d->staticListView->perItemScrollingPageSteps(vsize.width(), - csize.width(), - isWrapping()); - horizontalScrollBar()->setSingleStep(1); - horizontalScrollBar()->setPageStep(pageSteps); - horizontalScrollBar()->setRange(0, steps - pageSteps); - } else { - horizontalScrollBar()->setRange(0, 0); - } - // } else if (horizontal && d->isWrapping() && d->movement == Static) { - // ### wrapped scrolling in flow direction - } else { - horizontalScrollBar()->setSingleStep(step.width() + d->spacing()); - horizontalScrollBar()->setPageStep(vsize.width()); - horizontalScrollBar()->setRange(0, d->contentsSize().width() - vsize.width()); - } - if (vertical && d->isWrapping() && d->viewMode == ListMode) { - const QVector<int> segmentPositions = d->staticListView->segmentPositions; - int steps = segmentPositions.count() - 1; - if (steps > 0) { - int pageSteps = d->staticListView->perItemScrollingPageSteps(vsize.height(), - csize.height(), - isWrapping()); - verticalScrollBar()->setSingleStep(1); - verticalScrollBar()->setPageStep(pageSteps); - verticalScrollBar()->setRange(0, steps - pageSteps); - } else { - verticalScrollBar()->setRange(0, 0); - } - } else { - verticalScrollBar()->setSingleStep(step.height() + d->spacing()); - verticalScrollBar()->setPageStep(vsize.height()); - verticalScrollBar()->setRange(0, d->contentsSize().height() - vsize.height()); - } - } + d->commonListView->updateHorizontalScrollBar(step); + d->commonListView->updateVerticalScrollBar(step); } QAbstractItemView::updateGeometries(); @@ -1958,14 +1611,14 @@ bool QListView::event(QEvent *e) QListViewPrivate::QListViewPrivate() : QAbstractItemViewPrivate(), - dynamicListView(0), + commonListView(0), wrap(false), space(0), flow(QListView::TopToBottom), movement(QListView::Static), resizeMode(QListView::Fixed), layoutMode(QListView::SinglePass), - viewMode(QListView::IconMode), //this will ensure the first initialization to ListView + viewMode(QListView::ListMode), modeProperties(0), column(0), uniformItemSizes(false), @@ -1976,21 +1629,14 @@ QListViewPrivate::QListViewPrivate() QListViewPrivate::~QListViewPrivate() { - if (viewMode == QListView::ListMode) - delete staticListView; - else - delete dynamicListView; + delete commonListView; } void QListViewPrivate::clear() { - // ### split into dynamic and static // initialization of data structs cachedItemSize = QSize(); - if (viewMode == QListView::ListMode) - staticListView->clear(); - else - dynamicListView->clear(); + commonListView->clear(); } void QListViewPrivate::prepareItemsLayout() @@ -1999,7 +1645,7 @@ void QListViewPrivate::prepareItemsLayout() clear(); //take the size as if there were scrollbar in order to prevent scrollbar to blink - layoutBounds = QRect(QPoint(0,0), q->maximumViewportSize()); + layoutBounds = QRect(QPoint(), q->maximumViewportSize()); int frameAroundContents = 0; if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents)) @@ -2017,15 +1663,8 @@ void QListViewPrivate::prepareItemsLayout() layoutBounds.adjust(0, 0, -verticalMargin, -horizontalMargin); - int rowCount = model->rowCount(root); - int colCount = model->columnCount(root); - if (colCount <= 0) - rowCount = 0; // no contents - if (viewMode == QListView::ListMode) { - staticListView->flowPositions.resize(rowCount); - } else { - dynamicListView->tree.create(qMax(rowCount - hiddenRows.count(), 0)); - } + int rowCount = model->columnCount(root) <= 0 ? 0 : model->rowCount(root); + commonListView->setRowCount(rowCount); } /*! @@ -2033,7 +1672,6 @@ void QListViewPrivate::prepareItemsLayout() */ bool QListViewPrivate::doItemsLayout(int delta) { - // ### split into static and dynamic int max = model->rowCount(root) - 1; int first = batchStartRow(); int last = qMin(first + delta - 1, max); @@ -2057,9 +1695,7 @@ bool QListViewPrivate::doItemsLayout(int delta) info.flow = flow; info.max = max; - if (viewMode == QListView::ListMode) - return staticListView->doBatchedItemLayout(info, max); - return dynamicListView->doBatchedItemLayout(info, max); + return commonListView->doBatchedItemLayout(info, max); } QListViewItem QListViewPrivate::indexToListViewItem(const QModelIndex &index) const @@ -2067,29 +1703,16 @@ QListViewItem QListViewPrivate::indexToListViewItem(const QModelIndex &index) co if (!index.isValid() || isHidden(index.row())) return QListViewItem(); - if (viewMode == QListView::ListMode) - return staticListView->indexToListViewItem(index); - return dynamicListView->indexToListViewItem(index); + return commonListView->indexToListViewItem(index); } - -int QListViewPrivate::itemIndex(const QListViewItem &item) const -{ - if (viewMode == QListView::ListMode) - return staticListView->itemIndex(item); - return dynamicListView->itemIndex(item); -} - -QRect QListViewPrivate::mapToViewport(const QRect &rect, bool greedy) const +QRect QListViewPrivate::mapToViewport(const QRect &rect, bool extend) const { Q_Q(const QListView); if (!rect.isValid()) return rect; - QRect result = rect; - if (greedy) - result = staticListView->mapToViewport(rect); - + QRect result = extend ? commonListView->mapToViewport(rect) : rect; int dx = -q->horizontalOffset(); int dy = -q->verticalOffset(); result.adjust(dx, dy, dx, dy); @@ -2177,46 +1800,217 @@ QItemSelection QListViewPrivate::selection(const QRect &rect) const } /* - * Static ListView Implementation + * Common ListView Implementation */ -int QStaticListViewBase::verticalPerItemValue(int itemIndex, int verticalValue, int areaHeight, - bool above, bool below, bool wrap, - QListView::ScrollHint hint, int itemHeight) const +void QCommonListViewBase::appendHiddenRow(int row) +{ + dd->hiddenRows.append(dd->model->index(row, 0)); +} + +void QCommonListViewBase::removeHiddenRow(int row) { - int value = qBound(0, verticalValue, flowPositions.count() - 1); - if (above) - return perItemScrollToValue(itemIndex, value, areaHeight, QListView::PositionAtTop, - Qt::Vertical,wrap, itemHeight); - else if (below) - return perItemScrollToValue(itemIndex, value, areaHeight, QListView::PositionAtBottom, - Qt::Vertical, wrap, itemHeight); - else if (hint != QListView::EnsureVisible) - return perItemScrollToValue(itemIndex, value, areaHeight, hint, Qt::Vertical, wrap, itemHeight); - return value; + dd->hiddenRows.remove(dd->hiddenRows.indexOf(dd->model->index(row, 0))); } -int QStaticListViewBase::horizontalPerItemValue(int itemIndex, int horizontalValue, int areaWidth, - bool leftOf, bool rightOf, bool wrap, - QListView::ScrollHint hint, int itemWidth) const +void QCommonListViewBase::updateHorizontalScrollBar(const QSize &step) { - int value = qBound(0, horizontalValue, flowPositions.count() - 1); + horizontalScrollBar()->setSingleStep(step.width() + spacing()); + horizontalScrollBar()->setPageStep(viewport()->width()); + horizontalScrollBar()->setRange(0, contentsSize.width() - viewport()->width()); +} + +void QCommonListViewBase::updateVerticalScrollBar(const QSize &step) +{ + verticalScrollBar()->setSingleStep(step.height() + spacing()); + verticalScrollBar()->setPageStep(viewport()->height()); + verticalScrollBar()->setRange(0, contentsSize.height() - viewport()->height()); +} + +void QCommonListViewBase::scrollContentsBy(int dx, int dy, bool /*scrollElasticBand*/) +{ + dd->scrollContentsBy(isRightToLeft() ? -dx : dx, dy); +} + +int QCommonListViewBase::verticalScrollToValue(int /*index*/, QListView::ScrollHint hint, + bool above, bool below, const QRect &area, const QRect &rect) const +{ + int verticalValue = verticalScrollBar()->value(); + QRect adjusted = rect.adjusted(-spacing(), -spacing(), spacing(), spacing()); + if (hint == QListView::PositionAtTop || above) + verticalValue += adjusted.top(); + else if (hint == QListView::PositionAtBottom || below) + verticalValue += qMin(adjusted.top(), adjusted.bottom() - area.height() + 1); + else if (hint == QListView::PositionAtCenter) + verticalValue += adjusted.top() - ((area.height() - adjusted.height()) / 2); + return verticalValue; +} + +int QCommonListViewBase::horizontalOffset() const +{ + return (isRightToLeft() ? horizontalScrollBar()->maximum() - horizontalScrollBar()->value() : horizontalScrollBar()->value()); +} + +int QCommonListViewBase::horizontalScrollToValue(const int /*index*/, QListView::ScrollHint hint, + bool leftOf, bool rightOf, const QRect &area, const QRect &rect) const +{ + int horizontalValue = horizontalScrollBar()->value(); + if (isRightToLeft()) { + if (hint == QListView::PositionAtCenter) { + horizontalValue += ((area.width() - rect.width()) / 2) - rect.left(); + } else { + if (leftOf) + horizontalValue -= rect.left(); + else if (rightOf) + horizontalValue += qMin(rect.left(), area.width() - rect.right()); + } + } else { + if (hint == QListView::PositionAtCenter) { + horizontalValue += rect.left() - ((area.width()- rect.width()) / 2); + } else { + if (leftOf) + horizontalValue += rect.left(); + else if (rightOf) + horizontalValue += qMin(rect.left(), rect.right() - area.width()); + } + } + return horizontalValue; +} + +/* + * ListMode ListView Implementation +*/ + +#ifndef QT_NO_DRAGANDDROP +void QListModeViewBase::paintDragDrop(QPainter *painter) +{ + // FIXME: Until the we can provide a proper drop indicator + // in IconMode, it makes no sense to show it + dd->paintDropIndicator(painter); +} +#endif //QT_NO_DRAGANDDROP + +void QListModeViewBase::updateVerticalScrollBar(const QSize &step) +{ + if (verticalScrollMode() == QAbstractItemView::ScrollPerItem + && ((flow() == QListView::TopToBottom && !isWrapping()) + || (flow() == QListView::LeftToRight && isWrapping()))) { + const int steps = (flow() == QListView::TopToBottom ? flowPositions : segmentPositions).count() - 1; + if (steps > 0) { + const int pageSteps = perItemScrollingPageSteps(viewport()->height(), contentsSize.height(), isWrapping()); + verticalScrollBar()->setSingleStep(1); + verticalScrollBar()->setPageStep(pageSteps); + verticalScrollBar()->setRange(0, steps - pageSteps); + } else { + verticalScrollBar()->setRange(0, 0); + } + // } else if (vertical && d->isWrapping() && d->movement == Static) { + // ### wrapped scrolling in flow direction + } else { + QCommonListViewBase::updateVerticalScrollBar(step); + } +} + +void QListModeViewBase::updateHorizontalScrollBar(const QSize &step) +{ + if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem + && ((flow() == QListView::TopToBottom && isWrapping()) + || (flow() == QListView::LeftToRight && !isWrapping()))) { + int steps = (flow() == QListView::TopToBottom ? segmentPositions : flowPositions).count() - 1; + if (steps > 0) { + const int pageSteps = perItemScrollingPageSteps(viewport()->width(), contentsSize.width(), isWrapping()); + horizontalScrollBar()->setSingleStep(1); + horizontalScrollBar()->setPageStep(pageSteps); + horizontalScrollBar()->setRange(0, steps - pageSteps); + } else { + horizontalScrollBar()->setRange(0, 0); + } + } else { + QCommonListViewBase::updateHorizontalScrollBar(step); + } +} + +int QListModeViewBase::verticalScrollToValue(int index, QListView::ScrollHint hint, + bool above, bool below, const QRect &area, const QRect &rect) const +{ + if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) { + int value = qBound(0, verticalScrollBar()->value(), flowPositions.count() - 1); + if (above) + hint = QListView::PositionAtTop; + else if (below) + hint = QListView::PositionAtBottom; + if (hint == QListView::EnsureVisible) + return value; + + return perItemScrollToValue(index, value, area.height(), hint, Qt::Vertical, isWrapping(), rect.height()); + } + + return QCommonListViewBase::verticalScrollToValue(index, hint, above, below, area, rect); +} + +int QListModeViewBase::horizontalOffset() const +{ + if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) { + if (isWrapping()) { + if (flow() == QListView::TopToBottom && !segmentPositions.isEmpty()) { + const int max = segmentPositions.count() - 1; + int currentValue = qBound(0, horizontalScrollBar()->value(), max); + int position = segmentPositions.at(currentValue); + int maximumValue = qBound(0, horizontalScrollBar()->maximum(), max); + int maximum = segmentPositions.at(maximumValue); + return (isRightToLeft() ? maximum - position : position); + } + } else if (flow() == QListView::LeftToRight && !flowPositions.isEmpty()) { + int position = flowPositions.at(horizontalScrollBar()->value()); + int maximum = flowPositions.at(horizontalScrollBar()->maximum()); + return (isRightToLeft() ? maximum - position : position); + } + } + return QCommonListViewBase::horizontalOffset(); +} + +int QListModeViewBase::verticalOffset() const +{ + if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) { + if (isWrapping()) { + if (flow() == QListView::LeftToRight && !segmentPositions.isEmpty()) { + int value = verticalScrollBar()->value(); + if (value >= segmentPositions.count()) + return 0; + return segmentPositions.at(value); + } + } else if (flow() == QListView::TopToBottom && !flowPositions.isEmpty()) { + int value = verticalScrollBar()->value(); + if (value > flowPositions.count()) + return 0; + return flowPositions.at(value) - spacing(); + } + } + return QCommonListViewBase::verticalOffset(); +} + +int QListModeViewBase::horizontalScrollToValue(int index, QListView::ScrollHint hint, + bool leftOf, bool rightOf, const QRect &area, const QRect &rect) const +{ + if (horizontalScrollMode() != QAbstractItemView::ScrollPerItem) + return QCommonListViewBase::horizontalScrollToValue(index, hint, leftOf, rightOf, area, rect); + + int value = qBound(0, horizontalScrollBar()->value(), flowPositions.count() - 1); if (leftOf) - return perItemScrollToValue(itemIndex, value, areaWidth, QListView::PositionAtTop, - Qt::Horizontal, wrap, itemWidth); + hint = QListView::PositionAtTop; else if (rightOf) - return perItemScrollToValue(itemIndex, value, areaWidth, QListView::PositionAtBottom, - Qt::Horizontal, wrap, itemWidth); - else if (hint != QListView::EnsureVisible) - return perItemScrollToValue(itemIndex, value, areaWidth, hint, Qt::Horizontal, wrap, itemWidth); - return value; + hint = QListView::PositionAtBottom; + if (hint == QListView::EnsureVisible) + return value; + + return perItemScrollToValue(index, value, area.width(), hint, Qt::Horizontal, isWrapping(), rect.width()); } -void QStaticListViewBase::scrollContentsBy(int &dx, int &dy) +void QListModeViewBase::scrollContentsBy(int dx, int dy, bool scrollElasticBand) { // ### reorder this logic - const int verticalValue = verticalScrollBarValue(); - const int horizontalValue = horizontalScrollBarValue(); + const int verticalValue = verticalScrollBar()->value(); + const int horizontalValue = horizontalScrollBar()->value(); const bool vertical = (verticalScrollMode() == QAbstractItemView::ScrollPerItem); const bool horizontal = (horizontalScrollMode() == QAbstractItemView::ScrollPerItem); @@ -2255,9 +2049,10 @@ void QStaticListViewBase::scrollContentsBy(int &dx, int &dy) dx = previousCoordinate - currentCoordinate; } } + QCommonListViewBase::scrollContentsBy(dx, dy, scrollElasticBand); } -bool QStaticListViewBase::doBatchedItemLayout(const QListViewLayoutInfo &info, int max) +bool QListModeViewBase::doBatchedItemLayout(const QListViewLayoutInfo &info, int max) { doStaticLayout(info); if (batchStartRow > max) { // stop items layout @@ -2269,7 +2064,7 @@ bool QStaticListViewBase::doBatchedItemLayout(const QListViewLayoutInfo &info, i return false; // not done } -QListViewItem QStaticListViewBase::indexToListViewItem(const QModelIndex &index) const +QListViewItem QListModeViewBase::indexToListViewItem(const QModelIndex &index) const { if (flowPositions.isEmpty() || segmentPositions.isEmpty() @@ -2305,7 +2100,7 @@ QListViewItem QStaticListViewBase::indexToListViewItem(const QModelIndex &index) return QListViewItem(QRect(pos, size), index.row()); } -QPoint QStaticListViewBase::initStaticLayout(const QListViewLayoutInfo &info) +QPoint QListModeViewBase::initStaticLayout(const QListViewLayoutInfo &info) { int x, y; if (info.first == 0) { @@ -2340,7 +2135,7 @@ QPoint QStaticListViewBase::initStaticLayout(const QListViewLayoutInfo &info) /*! \internal */ -void QStaticListViewBase::doStaticLayout(const QListViewLayoutInfo &info) +void QListModeViewBase::doStaticLayout(const QListViewLayoutInfo &info) { const bool useItemSize = !info.grid.isValid(); const QPoint topLeft = initStaticLayout(info); @@ -2443,7 +2238,7 @@ void QStaticListViewBase::doStaticLayout(const QListViewLayoutInfo &info) Finds the set of items intersecting with \a area. In this function, itemsize is counted from topleft to the start of the next item. */ -QVector<QModelIndex> QStaticListViewBase::intersectingStaticSet(const QRect &area) const +QVector<QModelIndex> QListModeViewBase::intersectingSet(const QRect &area) const { QVector<QModelIndex> ret; int segStartPosition; @@ -2480,19 +2275,14 @@ QVector<QModelIndex> QStaticListViewBase::intersectingStaticSet(const QRect &are ret += index; #if 0 // for debugging else - qWarning("intersectingStaticSet: row %d was invalid", row); + qWarning("intersectingSet: row %d was invalid", row); #endif } } return ret; } -int QStaticListViewBase::itemIndex(const QListViewItem &item) const -{ - return item.indexHint; -} - -QRect QStaticListViewBase::mapToViewport(const QRect &rect) const +QRect QListModeViewBase::mapToViewport(const QRect &rect) const { if (isWrapping()) return rect; @@ -2510,7 +2300,7 @@ QRect QStaticListViewBase::mapToViewport(const QRect &rect) const return result; } -int QStaticListViewBase::perItemScrollingPageSteps(int length, int bounds, bool wrap) const +int QListModeViewBase::perItemScrollingPageSteps(int length, int bounds, bool wrap) const { const QVector<int> positions = (wrap ? segmentPositions : flowPositions); if (positions.isEmpty() || bounds <= length) @@ -2538,7 +2328,7 @@ int QStaticListViewBase::perItemScrollingPageSteps(int length, int bounds, bool return qMax(pageSteps, 1); } -int QStaticListViewBase::perItemScrollToValue(int index, int scrollValue, int viewportSize, +int QListModeViewBase::perItemScrollToValue(int index, int scrollValue, int viewportSize, QAbstractItemView::ScrollHint hint, Qt::Orientation orientation, bool wrap, int itemExtent) const { @@ -2598,7 +2388,7 @@ int QStaticListViewBase::perItemScrollToValue(int index, int scrollValue, int vi return scrollValue; } -void QStaticListViewBase::clear() +void QListModeViewBase::clear() { flowPositions.clear(); segmentPositions.clear(); @@ -2610,10 +2400,175 @@ void QStaticListViewBase::clear() } /* - * Dynamic ListView Implementation + * IconMode ListView Implementation */ -void QDynamicListViewBase::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) +void QIconModeViewBase::setPositionForIndex(const QPoint &position, const QModelIndex &index) +{ + if (index.row() >= items.count()) + return; + const QSize oldContents = contentsSize; + qq->update(index); // update old position + moveItem(index.row(), position); + qq->update(index); // update new position + + if (contentsSize != oldContents) + dd->viewUpdateGeometries(); // update the scroll bars +} + +void QIconModeViewBase::appendHiddenRow(int row) +{ + if (row >= 0 && row < items.count()) //remove item + tree.removeLeaf(items.at(row).rect(), row); + QCommonListViewBase::appendHiddenRow(row); +} + +void QIconModeViewBase::removeHiddenRow(int row) +{ + QCommonListViewBase::appendHiddenRow(row); + if (row >= 0 && row < items.count()) //insert item + tree.insertLeaf(items.at(row).rect(), row); +} + +#ifndef QT_NO_DRAGANDDROP +void QIconModeViewBase::paintDragDrop(QPainter *painter) +{ + if (!draggedItems.isEmpty() && viewport()->rect().contains(draggedItemsPos)) { + //we need to draw the items that arre dragged + painter->translate(draggedItemsDelta()); + QStyleOptionViewItemV4 option = viewOptions(); + option.state &= ~QStyle::State_MouseOver; + QVector<QModelIndex>::const_iterator it = draggedItems.begin(); + QListViewItem item = indexToListViewItem(*it); + for (; it != draggedItems.end(); ++it) { + item = indexToListViewItem(*it); + option.rect = viewItemRect(item); + delegate(*it)->paint(painter, option, *it); + } + } +} + +bool QIconModeViewBase::filterStartDrag(Qt::DropActions supportedActions) +{ + // This function does the same thing as in QAbstractItemView::startDrag(), + // plus adding viewitems to the draggedItems list. + // We need these items to draw the drag items + QModelIndexList indexes = dd->selectionModel->selectedIndexes(); + if (indexes.count() > 0 ) { + if (viewport()->acceptDrops()) { + QModelIndexList::ConstIterator it = indexes.constBegin(); + for (; it != indexes.constEnd(); ++it) + if (dd->model->flags(*it) & Qt::ItemIsDragEnabled + && (*it).column() == dd->column) + draggedItems.push_back(*it); + } + QDrag *drag = new QDrag(qq); + drag->setMimeData(dd->model->mimeData(indexes)); + Qt::DropAction action = drag->exec(supportedActions, Qt::CopyAction); + draggedItems.clear(); + if (action == Qt::MoveAction) + dd->clearOrRemove(); + } + return true; +} + +bool QIconModeViewBase::filterDropEvent(QDropEvent *e) +{ + if (e->source() != qq) + return false; + + const QSize contents = contentsSize; + QPoint offset(horizontalOffset(), verticalOffset()); + QPoint end = e->pos() + offset; + QPoint start = dd->pressedPosition; + QPoint delta = (dd->movement == QListView::Snap ? snapToGrid(end) - snapToGrid(start) : end - start); + QList<QModelIndex> indexes = dd->selectionModel->selectedIndexes(); + for (int i = 0; i < indexes.count(); ++i) { + QModelIndex index = indexes.at(i); + QRect rect = dd->rectForIndex(index); + viewport()->update(mapToViewport(rect)); + QPoint dest = rect.topLeft() + delta; + if (qq->isRightToLeft()) + dest.setX(dd->flipX(dest.x()) - rect.width()); + moveItem(index.row(), dest); + qq->update(index); + } + dd->stopAutoScroll(); + draggedItems.clear(); + dd->emitIndexesMoved(indexes); + e->accept(); // we have handled the event + // if the size has not grown, we need to check if it has shrinked + if (contentsSize != contents) { + if ((contentsSize.width() <= contents.width() + || contentsSize.height() <= contents.height())) { + updateContentsSize(); + } + dd->viewUpdateGeometries(); + } + return true; +} + +bool QIconModeViewBase::filterDragLeaveEvent(QDragLeaveEvent *e) +{ + viewport()->update(draggedItemsRect()); // erase the area + draggedItemsPos = QPoint(-1, -1); // don't draw the dragged items + return QCommonListViewBase::filterDragLeaveEvent(e); +} + +bool QIconModeViewBase::filterDragMoveEvent(QDragMoveEvent *e) +{ + if (e->source() != qq || !dd->canDecode(e)) + return false; + + // ignore by default + e->ignore(); + // get old dragged items rect + QRect itemsRect = this->itemsRect(draggedItems); + viewport()->update(itemsRect.translated(draggedItemsDelta())); + // update position + draggedItemsPos = e->pos(); + // get new items rect + viewport()->update(itemsRect.translated(draggedItemsDelta())); + // set the item under the cursor to current + QModelIndex index; + if (movement() == QListView::Snap) { + QRect rect(snapToGrid(e->pos() + offset()), gridSize()); + const QVector<QModelIndex> intersectVector = intersectingSet(rect); + index = intersectVector.count() > 0 ? intersectVector.last() : QModelIndex(); + } else { + index = qq->indexAt(e->pos()); + } + // check if we allow drops here + if (draggedItems.contains(index)) + e->accept(); // allow changing item position + else if (dd->model->flags(index) & Qt::ItemIsDropEnabled) + e->accept(); // allow dropping on dropenabled items + else if (!index.isValid()) + e->accept(); // allow dropping in empty areas + + // the event was treated. do autoscrolling + if (dd->shouldAutoScroll(e->pos())) + dd->startAutoScroll(); + return true; +} +#endif // QT_NO_DRAGANDDROP + +void QIconModeViewBase::setRowCount(int rowCount) +{ + tree.create(qMax(rowCount - hiddenCount(), 0)); +} + +void QIconModeViewBase::scrollContentsBy(int dx, int dy, bool scrollElasticBand) +{ + if (scrollElasticBand) + dd->scrollElasticBandBy(isRightToLeft() ? -dx : dx, dy); + + QCommonListViewBase::scrollContentsBy(dx, dy, scrollElasticBand); + if (!draggedItems.isEmpty()) + viewport()->update(draggedItemsRect().translated(dx, dy)); +} + +void QIconModeViewBase::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { if (column() >= topLeft.column() && column() <= bottomRight.column()) { QStyleOptionViewItemV4 option = viewOptions(); @@ -2623,23 +2578,29 @@ void QDynamicListViewBase::dataChanged(const QModelIndex &topLeft, const QModelI } } -bool QDynamicListViewBase::doBatchedItemLayout(const QListViewLayoutInfo &info, int max) +bool QIconModeViewBase::doBatchedItemLayout(const QListViewLayoutInfo &info, int max) { if (info.last >= items.count()) { - createItems(info.last + 1); + //first we create the items + QStyleOptionViewItemV4 option = viewOptions(); + for (int row = items.count(); row <= info.last; ++row) { + QSize size = itemSize(option, modelIndex(row)); + QListViewItem item(QRect(0, 0, size.width(), size.height()), row); // default pos + items.append(item); + } doDynamicLayout(info); } return (batchStartRow > max); // done } -QListViewItem QDynamicListViewBase::indexToListViewItem(const QModelIndex &index) const +QListViewItem QIconModeViewBase::indexToListViewItem(const QModelIndex &index) const { if (index.isValid() && index.row() < items.count()) return items.at(index.row()); return QListViewItem(); } -void QDynamicListViewBase::initBspTree(const QSize &contents) +void QIconModeViewBase::initBspTree(const QSize &contents) { // remove all items from the tree int leafCount = tree.leafCount(); @@ -2656,7 +2617,7 @@ void QDynamicListViewBase::initBspTree(const QSize &contents) tree.init(QRect(0, 0, contents.width(), contents.height()), type); } -QPoint QDynamicListViewBase::initDynamicLayout(const QListViewLayoutInfo &info) +QPoint QIconModeViewBase::initDynamicLayout(const QListViewLayoutInfo &info) { int x, y; if (info.first == 0) { @@ -2678,7 +2639,7 @@ QPoint QDynamicListViewBase::initDynamicLayout(const QListViewLayoutInfo &info) /*! \internal */ -void QDynamicListViewBase::doDynamicLayout(const QListViewLayoutInfo &info) +void QIconModeViewBase::doDynamicLayout(const QListViewLayoutInfo &info) { const bool useItemSize = !info.grid.isValid(); const QPoint topLeft = initDynamicLayout(info); @@ -2712,7 +2673,7 @@ void QDynamicListViewBase::doDynamicLayout(const QListViewLayoutInfo &info) if (moved.count() != items.count()) moved.resize(items.count()); - QRect rect(QPoint(0, 0), topLeft); + QRect rect(QPoint(), topLeft); QListViewItem *item = 0; for (int row = info.first; row <= info.last; ++row) { item = &items[row]; @@ -2805,43 +2766,18 @@ void QDynamicListViewBase::doDynamicLayout(const QListViewLayoutInfo &info) viewport()->update(); } -QVector<QModelIndex> QDynamicListViewBase::intersectingDynamicSet(const QRect &area) const +QVector<QModelIndex> QIconModeViewBase::intersectingSet(const QRect &area) const { - QDynamicListViewBase *that = const_cast<QDynamicListViewBase*>(this); + QIconModeViewBase *that = const_cast<QIconModeViewBase*>(this); QBspTree::Data data(static_cast<void*>(that)); QVector<QModelIndex> res; that->interSectingVector = &res; - that->tree.climbTree(area, &QDynamicListViewBase::addLeaf, data); + that->tree.climbTree(area, &QIconModeViewBase::addLeaf, data); that->interSectingVector = 0; return res; } -void QDynamicListViewBase::createItems(int to) -{ - int count = items.count(); - QSize size; - QStyleOptionViewItemV4 option = viewOptions(); - for (int row = count; row < to; ++row) { - size = itemSize(option, modelIndex(row)); - QListViewItem item(QRect(0, 0, size.width(), size.height()), row); // default pos - items.append(item); - } -} - -void QDynamicListViewBase::drawItems(QPainter *painter, const QVector<QModelIndex> &indexes) const -{ - QStyleOptionViewItemV4 option = viewOptions(); - option.state &= ~QStyle::State_MouseOver; - QVector<QModelIndex>::const_iterator it = indexes.begin(); - QListViewItem item = indexToListViewItem(*it); - for (; it != indexes.end(); ++it) { - item = indexToListViewItem(*it); - option.rect = viewItemRect(item); - delegate(*it)->paint(painter, option, *it); - } -} - -QRect QDynamicListViewBase::itemsRect(const QVector<QModelIndex> &indexes) const +QRect QIconModeViewBase::itemsRect(const QVector<QModelIndex> &indexes) const { QVector<QModelIndex>::const_iterator it = indexes.begin(); QListViewItem item = indexToListViewItem(*it); @@ -2853,7 +2789,7 @@ QRect QDynamicListViewBase::itemsRect(const QVector<QModelIndex> &indexes) const return rect; } -int QDynamicListViewBase::itemIndex(const QListViewItem &item) const +int QIconModeViewBase::itemIndex(const QListViewItem &item) const { if (!item.isValid()) return -1; @@ -2889,11 +2825,11 @@ int QDynamicListViewBase::itemIndex(const QListViewItem &item) const return -1; } -void QDynamicListViewBase::addLeaf(QVector<int> &leaf, const QRect &area, +void QIconModeViewBase::addLeaf(QVector<int> &leaf, const QRect &area, uint visited, QBspTree::Data data) { QListViewItem *vi; - QDynamicListViewBase *_this = static_cast<QDynamicListViewBase *>(data.ptr); + QIconModeViewBase *_this = static_cast<QIconModeViewBase *>(data.ptr); for (int i = 0; i < leaf.count(); ++i) { int idx = leaf.at(i); if (idx < 0 || idx >= _this->items.count()) @@ -2909,19 +2845,7 @@ void QDynamicListViewBase::addLeaf(QVector<int> &leaf, const QRect &area, } } -void QDynamicListViewBase::insertItem(int index) -{ - if (index >= 0 && index < items.count()) - tree.insertLeaf(items.at(index).rect(), index); -} - -void QDynamicListViewBase::removeItem(int index) -{ - if (index >= 0 && index < items.count()) - tree.removeLeaf(items.at(index).rect(), index); -} - -void QDynamicListViewBase::moveItem(int index, const QPoint &dest) +void QIconModeViewBase::moveItem(int index, const QPoint &dest) { // does not impact on the bintree itself or the contents rect QListViewItem *item = &items[index]; @@ -2941,14 +2865,14 @@ void QDynamicListViewBase::moveItem(int index, const QPoint &dest) moved.setBit(index, true); } -QPoint QDynamicListViewBase::snapToGrid(const QPoint &pos) const +QPoint QIconModeViewBase::snapToGrid(const QPoint &pos) const { int x = pos.x() - (pos.x() % gridSize().width()); int y = pos.y() - (pos.y() % gridSize().height()); return QPoint(x, y); } -QPoint QDynamicListViewBase::draggedItemsDelta() const +QPoint QIconModeViewBase::draggedItemsDelta() const { if (movement() == QListView::Snap) { QPoint snapdelta = QPoint((offset().x() % gridSize().width()), @@ -2958,7 +2882,7 @@ QPoint QDynamicListViewBase::draggedItemsDelta() const return draggedItemsPos - pressedPosition(); } -QRect QDynamicListViewBase::draggedItemsRect() const +QRect QIconModeViewBase::draggedItemsRect() const { QRect rect = itemsRect(draggedItems); rect.translate(draggedItemsDelta()); @@ -2977,7 +2901,7 @@ void QListViewPrivate::scrollElasticBandBy(int dx, int dy) elasticBand.moveTop(elasticBand.top() - dy); } -void QDynamicListViewBase::clear() +void QIconModeViewBase::clear() { tree.destroy(); items.clear(); @@ -2986,7 +2910,7 @@ void QDynamicListViewBase::clear() batchSavedDeltaSeg = 0; } -void QDynamicListViewBase::updateContentsSize() +void QIconModeViewBase::updateContentsSize() { QRect bounding; for (int i = 0; i < items.count(); ++i) @@ -3039,7 +2963,7 @@ int QListView::visualIndex(const QModelIndex &index) const Q_D(const QListView); d->executePostedLayout(); QListViewItem itm = d->indexToListViewItem(index); - return d->itemIndex(itm); + return d->commonListView->itemIndex(itm); } QT_END_NAMESPACE diff --git a/src/gui/itemviews/qlistview_p.h b/src/gui/itemviews/qlistview_p.h index 6c8d324..db9eb59 100644 --- a/src/gui/itemviews/qlistview_p.h +++ b/src/gui/itemviews/qlistview_p.h @@ -67,8 +67,8 @@ QT_BEGIN_NAMESPACE class QListViewItem { friend class QListViewPrivate; - friend class QStaticListViewBase; - friend class QDynamicListViewBase; + friend class QListModeViewBase; + friend class QIconModeViewBase; public: inline QListViewItem() : x(-1), y(-1), w(0), h(0), indexHint(-1), visited(0xffff) {} @@ -120,8 +120,42 @@ class QListViewPrivate; class QCommonListViewBase { public: - inline QCommonListViewBase(QListView *q, QListViewPrivate *d) : dd(d), qq(q) {} - + inline QCommonListViewBase(QListView *q, QListViewPrivate *d) : dd(d), qq(q), batchStartRow(0), batchSavedDeltaSeg(0) {} + virtual ~QCommonListViewBase() {} + + //common interface + virtual int itemIndex(const QListViewItem &item) const = 0; + virtual QListViewItem indexToListViewItem(const QModelIndex &index) const = 0; + virtual bool doBatchedItemLayout(const QListViewLayoutInfo &info, int max) = 0; + virtual void clear() = 0; + virtual void setRowCount(int) = 0; + virtual QVector<QModelIndex> intersectingSet(const QRect &area) const = 0; + + virtual int horizontalScrollToValue(int index, QListView::ScrollHint hint, + bool leftOf, bool rightOf, const QRect &area, const QRect &rect) const; + virtual int verticalScrollToValue(int index, QListView::ScrollHint hint, + bool above, bool below, const QRect &area, const QRect &rect) const; + virtual void scrollContentsBy(int dx, int dy, bool scrollElasticBand); + virtual QRect mapToViewport(const QRect &rect) const {return rect;} + virtual int horizontalOffset() const; + virtual int verticalOffset() const { return verticalScrollBar()->value(); } + virtual void updateHorizontalScrollBar(const QSize &step); + virtual void updateVerticalScrollBar(const QSize &step); + virtual void dataChanged(const QModelIndex &, const QModelIndex &) { } + virtual void appendHiddenRow(int row); + virtual void removeHiddenRow(int row); + virtual void setPositionForIndex(const QPoint &, const QModelIndex &) { } + +#ifndef QT_NO_DRAGANDDROP + virtual void paintDragDrop(QPainter *painter) = 0; + virtual bool filterDragMoveEvent(QDragMoveEvent *) { return false; } + virtual bool filterDragLeaveEvent(QDragLeaveEvent *) { return false; } + virtual bool filterDropEvent(QDropEvent *) { return false; } + virtual bool filterStartDrag(Qt::DropActions) { return false; } +#endif + + + //other inline members inline int spacing() const; inline bool isWrapping() const; inline QSize gridSize() const; @@ -133,8 +167,8 @@ public: inline bool uniformItemSizes() const; inline int column() const; - inline int verticalScrollBarValue() const; - inline int horizontalScrollBarValue() const; + inline QScrollBar *verticalScrollBar() const; + inline QScrollBar *horizontalScrollBar() const; inline QListView::ScrollMode verticalScrollMode() const; inline QListView::ScrollMode horizontalScrollMode() const; @@ -157,110 +191,107 @@ public: QListViewPrivate *dd; QListView *qq; + QSize contentsSize; + int batchStartRow; + int batchSavedDeltaSeg; }; -// ### rename to QListModeViewBase -class QStaticListViewBase : public QCommonListViewBase +class QListModeViewBase : public QCommonListViewBase { - friend class QListViewPrivate; public: - QStaticListViewBase(QListView *q, QListViewPrivate *d) : QCommonListViewBase(q, d), - batchStartRow(0), batchSavedDeltaSeg(0), batchSavedPosition(0) {} + QListModeViewBase(QListView *q, QListViewPrivate *d) : QCommonListViewBase(q, d) {} QVector<int> flowPositions; QVector<int> segmentPositions; QVector<int> segmentStartRows; QVector<int> segmentExtents; - QSize contentsSize; - // used when laying out in batches - int batchStartRow; - int batchSavedDeltaSeg; int batchSavedPosition; + //reimplementations + int itemIndex(const QListViewItem &item) const { return item.indexHint; } + QListViewItem indexToListViewItem(const QModelIndex &index) const; bool doBatchedItemLayout(const QListViewLayoutInfo &info, int max); + void clear(); + void setRowCount(int rowCount) { flowPositions.resize(rowCount); } + QVector<QModelIndex> intersectingSet(const QRect &area) const; + + int horizontalScrollToValue(int index, QListView::ScrollHint hint, + bool leftOf, bool rightOf,const QRect &area, const QRect &rect) const; + int verticalScrollToValue(int index, QListView::ScrollHint hint, + bool above, bool below, const QRect &area, const QRect &rect) const; + void scrollContentsBy(int dx, int dy, bool scrollElasticBand); + QRect mapToViewport(const QRect &rect) const; + int horizontalOffset() const; + int verticalOffset() const; + void updateHorizontalScrollBar(const QSize &step); + void updateVerticalScrollBar(const QSize &step); + +#ifndef QT_NO_DRAGANDDROP + void paintDragDrop(QPainter *painter); +#endif +private: QPoint initStaticLayout(const QListViewLayoutInfo &info); void doStaticLayout(const QListViewLayoutInfo &info); - QVector<QModelIndex> intersectingStaticSet(const QRect &area) const; - - int itemIndex(const QListViewItem &item) const; - - int perItemScrollingPageSteps(int length, int bounds, bool wrap) const; - int perItemScrollToValue(int index, int value, int height, QAbstractItemView::ScrollHint hint, Qt::Orientation orientation, bool wrap, int extent) const; - - QRect mapToViewport(const QRect &rect) const; - - QListViewItem indexToListViewItem(const QModelIndex &index) const; - - void scrollContentsBy(int &dx, int &dy); - - int verticalPerItemValue(int itemIndex, int verticalValue, int areaHeight, - bool above, bool below, bool wrap, QListView::ScrollHint hint, int itemHeight) const; - int horizontalPerItemValue(int itemIndex, int horizontalValue, int areaWidth, - bool leftOf, bool rightOf, bool wrap, QListView::ScrollHint hint, int itemWidth) const; - - void clear(); + int perItemScrollingPageSteps(int length, int bounds, bool wrap) const; }; -// ### rename to QIconModeViewBase -class QDynamicListViewBase : public QCommonListViewBase +class QIconModeViewBase : public QCommonListViewBase { - friend class QListViewPrivate; public: - QDynamicListViewBase(QListView *q, QListViewPrivate *d) : QCommonListViewBase(q, d), - batchStartRow(0), batchSavedDeltaSeg(0), interSectingVector(0) {} + QIconModeViewBase(QListView *q, QListViewPrivate *d) : QCommonListViewBase(q, d), interSectingVector(0) {} QBspTree tree; QVector<QListViewItem> items; QBitArray moved; - QSize contentsSize; - QVector<QModelIndex> draggedItems; // indices to the tree.itemVector mutable QPoint draggedItemsPos; // used when laying out in batches - int batchStartRow; - int batchSavedDeltaSeg; - QVector<QModelIndex> *interSectingVector; //used from within intersectingDynamicSet + QVector<QModelIndex> *interSectingVector; //used from within intersectingSet - void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + //reimplementations + int itemIndex(const QListViewItem &item) const; + QListViewItem indexToListViewItem(const QModelIndex &index) const; bool doBatchedItemLayout(const QListViewLayoutInfo &info, int max); + void clear(); + void setRowCount(int rowCount); + QVector<QModelIndex> intersectingSet(const QRect &area) const; + + void scrollContentsBy(int dx, int dy, bool scrollElasticBand); + void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + void appendHiddenRow(int row); + void removeHiddenRow(int row); + void setPositionForIndex(const QPoint &position, const QModelIndex &index); + +#ifndef QT_NO_DRAGANDDROP + void paintDragDrop(QPainter *painter); + bool filterDragMoveEvent(QDragMoveEvent *); + bool filterDragLeaveEvent(QDragLeaveEvent *); + bool filterDropEvent(QDropEvent *e); + bool filterStartDrag(Qt::DropActions); +#endif +private: void initBspTree(const QSize &contents); QPoint initDynamicLayout(const QListViewLayoutInfo &info); void doDynamicLayout(const QListViewLayoutInfo &info); - QVector<QModelIndex> intersectingDynamicSet(const QRect &area) const; - static void addLeaf(QVector<int> &leaf, const QRect &area, uint visited, QBspTree::Data data); - - void insertItem(int index); - void removeItem(int index); - void moveItem(int index, const QPoint &dest); - - int itemIndex(const QListViewItem &item) const; - - void createItems(int to); - void drawItems(QPainter *painter, const QVector<QModelIndex> &indexes) const; QRect itemsRect(const QVector<QModelIndex> &indexes) const; - - QPoint draggedItemsDelta() const; QRect draggedItemsRect() const; - QPoint snapToGrid(const QPoint &pos) const; - - void scrollElasticBandBy(int dx, int dy); - - QListViewItem indexToListViewItem(const QModelIndex &index) const; - - void clear(); void updateContentsSize(); + QPoint draggedItemsDelta() const; + void drawItems(QPainter *painter, const QVector<QModelIndex> &indexes) const; + void moveItem(int index, const QPoint &dest); + }; class QListViewPrivate: public QAbstractItemViewPrivate @@ -278,23 +309,13 @@ public: inline QVector<QModelIndex> intersectingSet(const QRect &area, bool doLayout = true) const { if (doLayout) executePostedLayout(); QRect a = (q_func()->isRightToLeft() ? flipX(area.normalized()) : area.normalized()); - return (viewMode == QListView::ListMode) ? staticListView->intersectingStaticSet(a) - : dynamicListView->intersectingDynamicSet(a); + return commonListView->intersectingSet(a); } - // ### FIXME: - inline void resetBatchStartRow() - { if (viewMode == QListView::ListMode) staticListView->batchStartRow = 0; - else dynamicListView->batchStartRow = 0; } - inline int batchStartRow() const - { return (viewMode == QListView::ListMode - ? staticListView->batchStartRow : dynamicListView->batchStartRow); } - inline QSize contentsSize() const - { return (viewMode == QListView::ListMode - ? staticListView->contentsSize : dynamicListView->contentsSize); } - inline void setContentsSize(int w, int h) - { if (viewMode == QListView::ListMode) staticListView->contentsSize = QSize(w, h); - else dynamicListView->contentsSize = QSize(w, h); } + inline void resetBatchStartRow() { commonListView->batchStartRow = 0; } + inline int batchStartRow() const { return commonListView->batchStartRow; } + inline QSize contentsSize() const { return commonListView->contentsSize; } + inline void setContentsSize(int w, int h) { commonListView->contentsSize = QSize(w, h); } inline int flipX(int x) const { return qMax(viewport->width(), contentsSize().width()) - x; } @@ -305,12 +326,22 @@ public: inline QRect viewItemRect(const QListViewItem &item) const { if (q_func()->isRightToLeft()) return flipX(item.rect()); return item.rect(); } - int itemIndex(const QListViewItem &item) const; QListViewItem indexToListViewItem(const QModelIndex &index) const; inline QModelIndex listViewItemToIndex(const QListViewItem &item) const - { return model->index(itemIndex(item), column, root); } + { return model->index(commonListView->itemIndex(item), column, root); } + + QRect rectForIndex(const QModelIndex &index) const + { + if (!isIndexValid(index) || index.parent() != root || index.column() != column || isHidden(index.row())) + return QRect(); + executePostedLayout(); + return viewItemRect(indexToListViewItem(index)); + } + + void viewUpdateGeometries() { q_func()->updateGeometries(); } - QRect mapToViewport(const QRect &rect, bool greedy = false) const; + + QRect mapToViewport(const QRect &rect, bool extend = true) const; QModelIndex closestIndex(const QRect &target, const QVector<QModelIndex> &candidates) const; QSize itemSize(const QStyleOptionViewItem &option, const QModelIndex &index) const; @@ -351,10 +382,10 @@ public: QItemViewPaintPairs draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const; - union { - QDynamicListViewBase *dynamicListView; - QStaticListViewBase *staticListView; - }; + void emitIndexesMoved(const QModelIndexList &indexes) { emit q_func()->indexesMoved(indexes); } + + + QCommonListViewBase *commonListView; // ### FIXME: see if we can move the members into the dynamic/static classes @@ -412,8 +443,8 @@ inline QPoint QCommonListViewBase::pressedPosition() const { return dd->pressedP inline bool QCommonListViewBase::uniformItemSizes() const { return dd->uniformItemSizes; } inline int QCommonListViewBase::column() const { return dd->column; } -inline int QCommonListViewBase::verticalScrollBarValue() const { return qq->verticalScrollBar()->value(); } -inline int QCommonListViewBase::horizontalScrollBarValue() const { return qq->horizontalScrollBar()->value(); } +inline QScrollBar *QCommonListViewBase::verticalScrollBar() const { return qq->verticalScrollBar(); } +inline QScrollBar *QCommonListViewBase::horizontalScrollBar() const { return qq->horizontalScrollBar(); } inline QListView::ScrollMode QCommonListViewBase::verticalScrollMode() const { return qq->verticalScrollMode(); } inline QListView::ScrollMode QCommonListViewBase::horizontalScrollMode() const { return qq->horizontalScrollMode(); } |