]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/kcategorizedview.cpp
The drag&drop helper did not make the difference between the different kind of views...
[dolphin.git] / src / kcategorizedview.cpp
index 72936113c5b3dbd999c3d3a5e05195e095862a3a..42ee7b1adc36c77d110816b8bded0f49e57f165d 100644 (file)
@@ -44,6 +44,7 @@ KCategorizedView::Private::Private(KCategorizedView *listView)
     , categoryDrawer(0)
     , biggestItemSize(QSize(0, 0))
     , mouseButtonPressed(false)
+    , rightMouseButtonPressed(false)
     , isDragging(false)
     , dragLeftViewport(false)
     , proxyModel(0)
@@ -499,7 +500,6 @@ void KCategorizedView::setGridSize(const QSize &size)
 void KCategorizedView::setModel(QAbstractItemModel *model)
 {
     d->lastSelection = QItemSelection();
-    d->currentViewIndex = QModelIndex();
     d->forcedSelectionPosition = 0;
     d->elementsInfo.clear();
     d->elementsPosition.clear();
@@ -510,6 +510,7 @@ void KCategorizedView::setModel(QAbstractItemModel *model)
     d->modelIndexList.clear();
     d->hovered = QModelIndex();
     d->mouseButtonPressed = false;
+    d->rightMouseButtonPressed = false;
 
     if (d->proxyModel)
     {
@@ -585,7 +586,6 @@ KCategoryDrawer *KCategorizedView::categoryDrawer() const
 void KCategorizedView::setCategoryDrawer(KCategoryDrawer *categoryDrawer)
 {
     d->lastSelection = QItemSelection();
-    d->currentViewIndex = QModelIndex();
     d->forcedSelectionPosition = 0;
     d->elementsInfo.clear();
     d->elementsPosition.clear();
@@ -596,6 +596,7 @@ void KCategorizedView::setCategoryDrawer(KCategoryDrawer *categoryDrawer)
     d->modelIndexList.clear();
     d->hovered = QModelIndex();
     d->mouseButtonPressed = false;
+    d->rightMouseButtonPressed = false;
 
     if (!categoryDrawer && d->proxyModel)
     {
@@ -661,8 +662,6 @@ QModelIndex KCategorizedView::indexAt(const QPoint &point) const
         index = item[0];
     }
 
-    d->hovered = index;
-
     return index;
 }
 
@@ -671,7 +670,6 @@ void KCategorizedView::reset()
     QListView::reset();
 
     d->lastSelection = QItemSelection();
-    d->currentViewIndex = QModelIndex();
     d->forcedSelectionPosition = 0;
     d->elementsInfo.clear();
     d->elementsPosition.clear();
@@ -683,6 +681,7 @@ void KCategorizedView::reset()
     d->hovered = QModelIndex();
     d->biggestItemSize = QSize(0, 0);
     d->mouseButtonPressed = false;
+    d->rightMouseButtonPressed = false;
 }
 
 void KCategorizedView::paintEvent(QPaintEvent *event)
@@ -743,7 +742,10 @@ void KCategorizedView::paintEvent(QPaintEvent *event)
                 option.state |= QStyle::State_Editing;
         }
 
-        if ((index == d->hovered) && !d->mouseButtonPressed)
+        // we are only interested to give the mouse over feedback when no
+        // dragging is happening (ereslibre)
+        if ((index == d->hovered) && !d->mouseButtonPressed &&
+            (this->state() == QAbstractItemView::NoState))
             option.state |= QStyle::State_MouseOver;
         else
             option.state &= ~QStyle::State_MouseOver;
@@ -849,88 +851,130 @@ void KCategorizedView::setSelection(const QRect &rect,
 
     if (flags & QItemSelectionModel::Clear)
     {
-        if (!rect.intersects(d->categoryVisualRect(d->hoveredCategory)))
-        {
-            d->lastSelection = QItemSelection();
-        }
+        selectionModel()->clear();
+        d->lastSelection.clear();
     }
 
-    selectionModel()->clear();
-
     QModelIndexList dirtyIndexes = d->intersectionSet(rect);
 
+    // no items affected, just leave
     if (!dirtyIndexes.count())
     {
-        if (!d->lastSelection.isEmpty() &&
-            (rect.intersects(d->categoryVisualRect(d->hoveredCategory)) || d->mouseButtonPressed))
-        {
-            selectionModel()->select(d->lastSelection, flags);
-        }
+        selectionModel()->select(d->lastSelection, QItemSelectionModel::SelectCurrent);
 
         return;
     }
 
-    int viewportWidth = viewport()->width() - spacing();
-    int itemWidth;
+    QModelIndex topLeft;
+    QModelIndex bottomRight;
 
-    if (gridSize().isEmpty())
-    {
-        itemWidth = d->biggestItemSize.width();
-    }
-    else
+    if (d->mouseButtonPressed || d->rightMouseButtonPressed) // selection with click + drag
     {
-        itemWidth = gridSize().width();
-    }
+        QItemSelection selection;
 
-    int itemWidthPlusSeparation = spacing() + itemWidth;
-    int elementsPerRow = viewportWidth / itemWidthPlusSeparation;
-
-    QItemSelection selection;
-
-    if (!d->mouseButtonPressed)
-    {
-        selection = QItemSelection(dirtyIndexes[0], dirtyIndexes[0]);
-        d->currentViewIndex = dirtyIndexes[0];
-        selectionModel()->setCurrentIndex(d->currentViewIndex, flags);
-        d->forcedSelectionPosition = d->elementsInfo[d->currentViewIndex.row()].relativeOffsetToCategory % elementsPerRow;
-    }
-    else
-    {
-        QModelIndex first = dirtyIndexes[0];
-        QModelIndex last;
+        QModelIndex prev = dirtyIndexes[0];
+        QModelIndex first = prev;
         foreach (const QModelIndex &index, dirtyIndexes)
         {
-            if (last.isValid() && last.row() + 1 != index.row())
-            {
-                QItemSelectionRange range(first, last);
-
-                selection << range;
+            // we have a different interval. non-contiguous items
+            if ((index.row() - prev.row()) > 1) {
+                selection << QItemSelectionRange(first, prev);
 
                 first = index;
             }
 
-            last = index;
+            prev = index;
         }
 
-        if (last.isValid())
-            selection << QItemSelectionRange(first, last);
+        selection << QItemSelectionRange(first, prev);
 
-        if (first == last)
+        if (flags & QItemSelectionModel::Current)
         {
-            selectionModel()->setCurrentIndex(first, QItemSelectionModel::SelectCurrent);
-            d->forcedSelectionPosition = d->elementsInfo[first.row()].relativeOffsetToCategory % elementsPerRow;
-        }
-    }
+            if (rect.topLeft() == rect.bottomRight())
+            {
+                selectionModel()->setCurrentIndex(indexAt(rect.topLeft()), QItemSelectionModel::NoUpdate);
+            }
 
-    if (d->lastSelection.count())
-    {
-        if ((selection.count() == 1) && (selection[0].indexes().count() == 1))
             selection.merge(d->lastSelection, flags);
+        }
         else
-            selection.merge(d->lastSelection, QItemSelectionModel::Select);
+        {
+            selection.merge(selectionModel()->selection(), flags);
+
+            selectionModel()->select(selection, QItemSelectionModel::SelectCurrent);
+
+            return;
+        }
+
+        selectionModel()->select(selection, flags);
     }
+    else // selection with click + keyboard keys
+    {
+        QModelIndex topLeftIndex = indexAt(QPoint(rect.topLeft().x(),
+                                                  rect.topLeft().y()));
+        QModelIndex bottomRightIndex = indexAt(QPoint(rect.bottomRight().x(),
+                                                      rect.bottomRight().y()));
+
+        // keyboard selection comes "upside down". Let's normalize it
+        if (topLeftIndex.row() > bottomRightIndex.row())
+        {
+            QModelIndex auxIndex = topLeftIndex;
+            topLeftIndex = bottomRightIndex;
+            bottomRightIndex = auxIndex;
+        }
+
+        int viewportWidth = viewport()->width() - spacing();
+        int itemWidth;
+
+        if (gridSize().isEmpty())
+        {
+            itemWidth = d->biggestItemSize.width();
+        }
+        else
+        {
+            itemWidth = gridSize().width();
+        }
+
+        int itemWidthPlusSeparation = spacing() + itemWidth;
+        int elementsPerRow = viewportWidth / itemWidthPlusSeparation;
+        if (!elementsPerRow)
+            elementsPerRow++;
+
+        QModelIndexList theoricDirty(dirtyIndexes);
+        dirtyIndexes.clear();
+        int first = model()->rowCount();
+        int last = 0;
+
+        foreach (const QModelIndex &index, theoricDirty)
+        {
+            if ((index.row() < first) &&
+                ((((topLeftIndex.row() / elementsPerRow) == (index.row() / elementsPerRow)) &&
+                  ((topLeftIndex.row() % elementsPerRow) <= (index.row() % elementsPerRow))) ||
+                 (topLeftIndex.row() / elementsPerRow) != (index.row() / elementsPerRow)))
+            {
+                first = index.row();
+                topLeft = index;
+            }
+
+            if ((index.row() > last) &&
+                ((((bottomRightIndex.row() / elementsPerRow) == (index.row() / elementsPerRow)) &&
+                  ((bottomRightIndex.row() % elementsPerRow) >= (index.row() % elementsPerRow))) ||
+                 (bottomRightIndex.row() / elementsPerRow) != (index.row() / elementsPerRow)))
+            {
+                last = index.row();
+                bottomRight = index;
+            }
+        }
+
+        for (int i = first; i <= last; i++)
+        {
+            dirtyIndexes << model()->index(i, theoricDirty[0].column(), theoricDirty[0].parent());
+        }
+
+        QItemSelection selection(topLeft, bottomRight);
 
-    selectionModel()->select(selection, flags);
+        selectionModel()->select(selection, flags);
+    }
 }
 
 void KCategorizedView::mouseMoveEvent(QMouseEvent *event)
@@ -943,6 +987,17 @@ void KCategorizedView::mouseMoveEvent(QMouseEvent *event)
         return;
     }
 
+    QModelIndexList item = d->intersectionSet(QRect(event->pos(), event->pos()));
+
+    if (item.count() == 1)
+    {
+        d->hovered = item[0];
+    }
+    else
+    {
+        d->hovered = QModelIndex();
+    }
+
     const QString previousHoveredCategory = d->hoveredCategory;
 
     d->mousePosition = event->pos();
@@ -986,10 +1041,6 @@ void KCategorizedView::mouseMoveEvent(QMouseEvent *event)
         }
 
         rect = QRect(start, end).intersected(viewport()->rect().adjusted(-16, -16, 16, 16));
-
-        //viewport()->update(rect.united(d->lastSelectionRect));
-
-        d->lastSelectionRect = rect;
     }
 }
 
@@ -1007,15 +1058,22 @@ void KCategorizedView::mousePressEvent(QMouseEvent *event)
         d->initialPressPosition.setX(d->initialPressPosition.x() +
                                                             horizontalOffset());
     }
+    else if (event->button() == Qt::RightButton)
+    {
+        d->rightMouseButtonPressed = true;
+    }
 
     QListView::mousePressEvent(event);
 
+    d->lastSelection = selectionModel()->selection();
+
     viewport()->update(d->categoryVisualRect(d->hoveredCategory));
 }
 
 void KCategorizedView::mouseReleaseEvent(QMouseEvent *event)
 {
     d->mouseButtonPressed = false;
+    d->rightMouseButtonPressed = false;
 
     QListView::mouseReleaseEvent(event);
 
@@ -1029,39 +1087,29 @@ void KCategorizedView::mouseReleaseEvent(QMouseEvent *event)
     initialPressPosition.setY(initialPressPosition.y() + verticalOffset());
     initialPressPosition.setX(initialPressPosition.x() + horizontalOffset());
 
-    QItemSelection selection;
-    QItemSelection deselection;
-
     if (initialPressPosition == d->initialPressPosition)
     {
         foreach(const QString &category, d->categories)
         {
             if (d->categoryVisualRect(category).contains(event->pos()))
             {
-                foreach (const QModelIndex &index, d->categoriesIndexes[category])
+                QItemSelection selection;
+                QModelIndexList indexList = d->categoriesIndexes[category];
+
+                foreach (const QModelIndex &index, indexList)
                 {
                     QModelIndex selectIndex = index.model()->index(index.row(), 0);
 
-                    if (!d->lastSelection.contains(selectIndex))
-                    {
-                        selection << QItemSelectionRange(selectIndex);
-                    }
-                    else
-                    {
-                        deselection << QItemSelectionRange(selectIndex);
-                    }
+                    selection << QItemSelectionRange(selectIndex);
                 }
 
                 selectionModel()->select(selection, QItemSelectionModel::Select);
-                selectionModel()->select(deselection, QItemSelectionModel::Deselect);
 
                 break;
             }
         }
     }
 
-    d->lastSelection = selectionModel()->selection();
-
     if (d->hovered.isValid())
         viewport()->update(visualRect(d->hovered));
     else if (!d->hoveredCategory.isEmpty())
@@ -1089,6 +1137,7 @@ void KCategorizedView::startDrag(Qt::DropActions supportedActions)
 
     d->isDragging = false;
     d->mouseButtonPressed = false;
+    d->rightMouseButtonPressed = false;
 
     viewport()->update(d->lastDraggedItemsRect);
 }
@@ -1155,7 +1204,16 @@ QModelIndex KCategorizedView::moveCursor(CursorAction cursorAction,
         return QListView::moveCursor(cursorAction, modifiers);
     }
 
-    const QModelIndex current = selectionModel()->currentIndex();
+    QModelIndex current = selectionModel()->currentIndex();
+
+    if (!current.isValid())
+    {
+        current = model()->index(0, 0, QModelIndex());
+        selectionModel()->select(current, QItemSelectionModel::NoUpdate);
+        d->forcedSelectionPosition = 0;
+
+        return current;
+    }
 
     int viewportWidth = viewport()->width() - spacing();
     int itemWidth;
@@ -1171,6 +1229,8 @@ QModelIndex KCategorizedView::moveCursor(CursorAction cursorAction,
 
     int itemWidthPlusSeparation = spacing() + itemWidth;
     int elementsPerRow = viewportWidth / itemWidthPlusSeparation;
+    if (!elementsPerRow)
+        elementsPerRow++;
 
     QString lastCategory = d->categories.first();
     QString theCategory = d->categories.first();
@@ -1256,36 +1316,56 @@ QModelIndex KCategorizedView::moveCursor(CursorAction cursorAction,
         case QAbstractItemView::MoveLeft:
             if (layoutDirection() == Qt::RightToLeft)
             {
+                if (!(d->elementsInfo[current.row() + 1].relativeOffsetToCategory % elementsPerRow))
+                    return current;
+
                 d->forcedSelectionPosition = d->elementsInfo[current.row() + 1].relativeOffsetToCategory % elementsPerRow;
 
+#if 0 //follow qt view behavior. lateral movements won't change visual row
                 if (d->forcedSelectionPosition < 0)
                     d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow;
+#endif
 
                 return d->proxyModel->index(current.row() + 1, 0);
             }
 
+            if (!(d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow))
+                return current;
+
             d->forcedSelectionPosition = d->elementsInfo[current.row() - 1].relativeOffsetToCategory % elementsPerRow;
 
+#if 0 //follow qt view behavior. lateral movements won't change visual row
             if (d->forcedSelectionPosition < 0)
                 d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow;
+#endif
 
             return d->proxyModel->index(current.row() - 1, 0);
 
         case QAbstractItemView::MoveRight:
             if (layoutDirection() == Qt::RightToLeft)
             {
+                if (!(d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow))
+                    return current;
+
                 d->forcedSelectionPosition = d->elementsInfo[current.row() - 1].relativeOffsetToCategory % elementsPerRow;
 
+#if 0 //follow qt view behavior. lateral movements won't change visual row
                 if (d->forcedSelectionPosition < 0)
                     d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow;
+#endif
 
                 return d->proxyModel->index(current.row() - 1, 0);
             }
 
+            if (!(d->elementsInfo[current.row() + 1].relativeOffsetToCategory % elementsPerRow))
+                return current;
+
             d->forcedSelectionPosition = d->elementsInfo[current.row() + 1].relativeOffsetToCategory % elementsPerRow;
 
+#if 0 //follow qt view behavior. lateral movements won't change visual row
             if (d->forcedSelectionPosition < 0)
                 d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow;
+#endif
 
             return d->proxyModel->index(current.row() + 1, 0);
 
@@ -1305,8 +1385,6 @@ void KCategorizedView::rowsInserted(const QModelIndex &parent,
     if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
         !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
     {
-        d->lastSelection = QItemSelection();
-        d->currentViewIndex = QModelIndex();
         d->forcedSelectionPosition = 0;
         d->elementsInfo.clear();
         d->elementsPosition.clear();
@@ -1318,6 +1396,7 @@ void KCategorizedView::rowsInserted(const QModelIndex &parent,
         d->hovered = QModelIndex();
         d->biggestItemSize = QSize(0, 0);
         d->mouseButtonPressed = false;
+        d->rightMouseButtonPressed = false;
 
         return;
     }
@@ -1331,8 +1410,6 @@ void KCategorizedView::rowsInsertedArtifficial(const QModelIndex &parent,
 {
     Q_UNUSED(parent);
 
-    d->lastSelection = QItemSelection();
-    d->currentViewIndex = QModelIndex();
     d->forcedSelectionPosition = 0;
     d->elementsInfo.clear();
     d->elementsPosition.clear();
@@ -1344,6 +1421,7 @@ void KCategorizedView::rowsInsertedArtifficial(const QModelIndex &parent,
     d->hovered = QModelIndex();
     d->biggestItemSize = QSize(0, 0);
     d->mouseButtonPressed = false;
+    d->rightMouseButtonPressed = false;
 
     if (start > end || end < 0 || start < 0 || !d->proxyModel->rowCount())
     {
@@ -1396,6 +1474,10 @@ void KCategorizedView::rowsInsertedArtifficial(const QModelIndex &parent,
     d->categories << prevCategory;
 
     d->updateScrollbars();
+
+    // FIXME: We need to safely save the last selection. This is on my TODO
+    // list (ereslibre).
+    selectionModel()->clear();
 }
 
 void KCategorizedView::rowsRemoved(const QModelIndex &parent,
@@ -1429,4 +1511,36 @@ void KCategorizedView::slotLayoutChanged()
     d->layoutChanged();
 }
 
+void KCategorizedView::currentChanged(const QModelIndex &current,
+                                      const QModelIndex &previous)
+{
+    // We need to update the forcedSelectionPosition property in order to correctly
+    // navigate after with keyboard using up & down keys
+
+    int viewportWidth = viewport()->width() - spacing();
+
+    int itemHeight;
+    int itemWidth;
+
+    if (gridSize().isEmpty())
+    {
+        itemHeight = d->biggestItemSize.height();
+        itemWidth = d->biggestItemSize.width();
+    }
+    else
+    {
+        itemHeight = gridSize().height();
+        itemWidth = gridSize().width();
+    }
+
+    int itemWidthPlusSeparation = spacing() + itemWidth;
+    int elementsPerRow = viewportWidth / itemWidthPlusSeparation;
+    if (!elementsPerRow)
+        elementsPerRow++;
+
+    d->forcedSelectionPosition = d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow;
+
+    QListView::currentChanged(current, previous);
+}
+
 #include "kcategorizedview.moc"