src/gui/itemviews/qlistview.cpp
changeset 3 41300fa6a67c
parent 0 1918ee327afb
child 4 3b1da2848fc7
child 7 f7bc934e204c
--- a/src/gui/itemviews/qlistview.cpp	Tue Jan 26 12:42:25 2010 +0200
+++ b/src/gui/itemviews/qlistview.cpp	Tue Feb 02 00:43:10 2010 +0200
@@ -357,7 +357,7 @@
 
 /*!
     \property QListView::spacing
-    \brief the space between items in the layout
+    \brief the space around the items in the layout
 
     This property is the size of the empty space that is padded around
     an item in the layout.
@@ -773,7 +773,7 @@
 void QListView::mouseMoveEvent(QMouseEvent *e)
 {
     if (!isVisible())
-	return;
+        return;
     Q_D(QListView);
     QAbstractItemView::mouseMoveEvent(e);
     if (state() == DragSelectingState
@@ -832,16 +832,16 @@
       return;
 
     bool listWrap = (d->viewMode == ListMode) && d->wrapItemText;
-    bool flowDimensionChanged = (d->flow == LeftToRight && delta.width() != 0) 
-				|| (d->flow == TopToBottom && delta.height() != 0);
+    bool flowDimensionChanged = (d->flow == LeftToRight && delta.width() != 0)
+                                || (d->flow == TopToBottom && delta.height() != 0);
 
     // We post a delayed relayout in the following cases :
     // - we're wrapping
     // - the state is NoState, we're adjusting and the size has changed in the flowing direction
-    if (listWrap 
+    if (listWrap
         || (state() == NoState && d->resizeMode == Adjust && flowDimensionChanged)) {
-	d->doDelayedItemsLayout(100); // wait 1/10 sec before starting the layout
-    } else {	
+        d->doDelayedItemsLayout(100); // wait 1/10 sec before starting the layout
+    } else {
         QAbstractItemView::resizeEvent(e);
     }
 }
@@ -853,8 +853,13 @@
 */
 void QListView::dragMoveEvent(QDragMoveEvent *e)
 {
-    if (!d_func()->commonListView->filterDragMoveEvent(e))
-        QAbstractItemView::dragMoveEvent(e);
+    Q_D(QListView);
+    if (!d->commonListView->filterDragMoveEvent(e)) {
+        if (viewMode() == QListView::ListMode && flow() == QListView::LeftToRight)
+            static_cast<QListModeViewBase *>(d->commonListView)->dragMoveEvent(e);
+        else
+            QAbstractItemView::dragMoveEvent(e);
+    }
 }
 
 
@@ -961,15 +966,19 @@
     bool alternateBase = false;
     int previousRow = -2; // trigger the alternateBase adjustment on first pass
 
+    int maxSize = (flow() == TopToBottom)
+        ? qMax(viewport()->size().width(), d->contentsSize().width()) - 2 * d->spacing()
+        : qMax(viewport()->size().height(), d->contentsSize().height()) - 2 * d->spacing();
+
     QVector<QModelIndex>::const_iterator end = toBeRendered.constEnd();
     for (QVector<QModelIndex>::const_iterator it = toBeRendered.constBegin(); it != end; ++it) {
         Q_ASSERT((*it).isValid());
         option.rect = visualRect(*it);
 
         if (flow() == TopToBottom)
-            option.rect.setWidth(qMin(viewport()->size().width(), option.rect.width()));
+            option.rect.setWidth(qMin(maxSize, option.rect.width()));
         else
-            option.rect.setHeight(qMin(viewport()->size().height(), option.rect.height()));
+            option.rect.setHeight(qMin(maxSize, option.rect.height()));
 
         option.state = state;
         if (selections && selections->isSelected(*it))
@@ -1142,7 +1151,9 @@
         }
         return d->closestIndex(initialRect, intersectVector);
     case MovePageUp:
-        rect.moveTop(rect.top() - d->viewport->height());
+        // move current by (visibileRowCount - 1) items.
+        // rect.translate(0, -rect.height()); will happen in the switch fallthrough for MoveUp.
+        rect.moveTop(rect.top() - d->viewport->height() + 2 * rect.height());
         if (rect.top() < rect.height())
             rect.moveTop(rect.height());
     case MovePrevious:
@@ -1168,7 +1179,9 @@
         }
         return d->closestIndex(initialRect, intersectVector);
     case MovePageDown:
-        rect.moveTop(rect.top() + d->viewport->height());
+        // move current by (visibileRowCount - 1) items.
+        // rect.translate(0, rect.height()); will happen in the switch fallthrough for MoveDown.
+        rect.moveTop(rect.top() + d->viewport->height() - 2 * rect.height());
         if (rect.bottom() > contents.height() - rect.height())
             rect.moveBottom(contents.height() - rect.height());
     case MoveNext:
@@ -1440,7 +1453,7 @@
     // so we set the state to expanding to avoid
     // triggering another layout
     QAbstractItemView::State oldState = state();
-    setState(ExpandingState); 
+    setState(ExpandingState);
     if (d->model->columnCount(d->root) > 0) { // no columns means no contents
         d->resetBatchStartRow();
         if (layoutMode() == SinglePass)
@@ -1804,6 +1817,16 @@
     return selection;
 }
 
+#ifndef QT_NO_DRAGANDDROP
+QAbstractItemView::DropIndicatorPosition QListViewPrivate::position(const QPoint &pos, const QRect &rect, const QModelIndex &idx) const
+{
+    if (viewMode == QListView::ListMode && flow == QListView::LeftToRight)
+        return static_cast<QListModeViewBase *>(commonListView)->position(pos, rect, idx);
+    else
+        return QAbstractItemViewPrivate::position(pos, rect, idx);
+}
+#endif
+
 /*
  * Common ListView Implementation
 */
@@ -1822,14 +1845,14 @@
 {
     horizontalScrollBar()->setSingleStep(step.width() + spacing());
     horizontalScrollBar()->setPageStep(viewport()->width());
-    horizontalScrollBar()->setRange(0, contentsSize.width() - viewport()->width());
+    horizontalScrollBar()->setRange(0, contentsSize.width() - viewport()->width() - 2 * spacing());
 }
 
 void QCommonListViewBase::updateVerticalScrollBar(const QSize &step)
 {
     verticalScrollBar()->setSingleStep(step.height() + spacing());
     verticalScrollBar()->setPageStep(viewport()->height());
-    verticalScrollBar()->setRange(0, contentsSize.height() - viewport()->height());
+    verticalScrollBar()->setRange(0, contentsSize.height() - viewport()->height() - 2 * spacing());
 }
 
 void QCommonListViewBase::scrollContentsBy(int dx, int dy, bool /*scrollElasticBand*/)
@@ -1893,6 +1916,96 @@
     // in IconMode, it makes no sense to show it
     dd->paintDropIndicator(painter);
 }
+
+QAbstractItemView::DropIndicatorPosition QListModeViewBase::position(const QPoint &pos, const QRect &rect, const QModelIndex &index) const
+{
+    QAbstractItemView::DropIndicatorPosition r = QAbstractItemView::OnViewport;
+    if (!dd->overwrite) {
+        const int margin = 2;
+        if (pos.x() - rect.left() < margin) {
+            r = QAbstractItemView::AboveItem;   // Visually, on the left
+        } else if (rect.right() - pos.x() < margin) {
+            r = QAbstractItemView::BelowItem;   // Visually, on the right
+        } else if (rect.contains(pos, true)) {
+            r = QAbstractItemView::OnItem;
+        }
+    } else {
+        QRect touchingRect = rect;
+        touchingRect.adjust(-1, -1, 1, 1);
+        if (touchingRect.contains(pos, false)) {
+            r = QAbstractItemView::OnItem;
+        }
+    }
+
+    if (r == QAbstractItemView::OnItem && (!(dd->model->flags(index) & Qt::ItemIsDropEnabled)))
+        r = pos.x() < rect.center().x() ? QAbstractItemView::AboveItem : QAbstractItemView::BelowItem;
+
+    return r;
+}
+
+void QListModeViewBase::dragMoveEvent(QDragMoveEvent *event)
+{
+    if (qq->dragDropMode() == QAbstractItemView::InternalMove
+        && (event->source() != qq || !(event->possibleActions() & Qt::MoveAction)))
+        return;
+
+    // ignore by default
+    event->ignore();
+
+    QModelIndex index = qq->indexAt(event->pos());
+    dd->hover = index;
+    if (!dd->droppingOnItself(event, index)
+        && dd->canDecode(event)) {
+
+        if (index.isValid() && dd->showDropIndicator) {
+            QRect rect = qq->visualRect(index);
+            dd->dropIndicatorPosition = position(event->pos(), rect, index);
+            switch (dd->dropIndicatorPosition) {
+            case QAbstractItemView::AboveItem:
+                if (dd->isIndexDropEnabled(index.parent())) {
+                    dd->dropIndicatorRect = QRect(rect.left(), rect.top(), 0, rect.height());
+                    event->accept();
+                } else {
+                    dd->dropIndicatorRect = QRect();
+                }
+                break;
+            case QAbstractItemView::BelowItem:
+                if (dd->isIndexDropEnabled(index.parent())) {
+                    dd->dropIndicatorRect = QRect(rect.right(), rect.top(), 0, rect.height());
+                    event->accept();
+                } else {
+                    dd->dropIndicatorRect = QRect();
+                }
+                break;
+            case QAbstractItemView::OnItem:
+                if (dd->isIndexDropEnabled(index)) {
+                    dd->dropIndicatorRect = rect;
+                    event->accept();
+                } else {
+                    dd->dropIndicatorRect = QRect();
+                }
+                break;
+            case QAbstractItemView::OnViewport:
+                dd->dropIndicatorRect = QRect();
+                if (dd->isIndexDropEnabled(qq->rootIndex())) {
+                    event->accept(); // allow dropping in empty areas
+                }
+                break;
+            }
+        } else {
+            dd->dropIndicatorRect = QRect();
+            dd->dropIndicatorPosition = QAbstractItemView::OnViewport;
+            if (dd->isIndexDropEnabled(qq->rootIndex())) {
+                event->accept(); // allow dropping in empty areas
+            }
+        }
+        dd->viewport->update();
+    } // can decode
+
+    if (dd->shouldAutoScroll(event->pos()))
+        qq->startAutoScroll();
+}
+
 #endif //QT_NO_DRAGANDDROP
 
 void QListModeViewBase::updateVerticalScrollBar(const QSize &step)
@@ -2298,6 +2411,12 @@
     return ret;
 }
 
+void QListModeViewBase::dataChanged(const QModelIndex &, const QModelIndex &)
+{
+    dd->doDelayedItemsLayout();
+}
+
+
 QRect QListModeViewBase::mapToViewport(const QRect &rect) const
 {
     if (isWrapping())