]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/kcategorizedview.cpp
No need to export that yet
[dolphin.git] / src / kcategorizedview.cpp
index 4f542f9c7fc0e12849f0633d1dbe0a27f316b4f1..6590c4b2ac99095147add4275863abb12945d921 100644 (file)
@@ -24,7 +24,6 @@
 #include <math.h> // trunc on C99 compliant systems
 #include <kdefakes.h> // trunc for not C99 compliant systems
 
-#include <QApplication>
 #include <QPainter>
 #include <QScrollBar>
 #include <QPaintEvent>
 #include "kcategorydrawer.h"
 #include "kcategorizedsortfilterproxymodel.h"
 
+// By defining DOLPHIN_DRAGANDDROP the custom drag and drop implementation of
+// KCategorizedView is bypassed to have a consistent drag and drop look for all
+// views. Hopefully transparent pixmaps for drag objects will be supported in
+// Qt 4.4, so that this workaround can be skipped.
+#define DOLPHIN_DRAGANDDROP
+
 KCategorizedView::Private::Private(KCategorizedView *listView)
     : listView(listView)
     , categoryDrawer(0)
@@ -355,7 +360,7 @@ void KCategorizedView::Private::drawNewCategory(const QModelIndex &index,
     }
 
     QStyleOption optionCopy = option;
-    const QString category = proxyModel->data(index, KCategorizedSortFilterProxyModel::CategoryRole).toString();
+    const QString category = proxyModel->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
 
     optionCopy.state &= ~QStyle::State_Selected;
 
@@ -844,65 +849,122 @@ void KCategorizedView::setSelection(const QRect &rect,
 
     if (flags & QItemSelectionModel::Clear)
     {
-        if (!rect.intersects(d->categoryVisualRect(d->hoveredCategory)))
-        {
-            d->lastSelection = QItemSelection();
-        }
+        selectionModel()->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, flags);
+
+        d->lastSelection.clear();
 
         return;
     }
 
-    QItemSelection selection;
+    d->lastSelection.clear();
 
-    if (!d->mouseButtonPressed)
+    if (!(flags & QItemSelectionModel::Current))
     {
-        selection = QItemSelection(dirtyIndexes[0], dirtyIndexes[0]);
-        d->currentViewIndex = dirtyIndexes[0];
+        Q_ASSERT(dirtyIndexes.count() == 1);
+
+        selectionModel()->select(dirtyIndexes[0], flags);
+
+        return;
     }
-    else
+
+    QModelIndex topLeft;
+    QModelIndex bottomRight;
+
+    if (d->mouseButtonPressed) // selection with click + drag
     {
-        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;
+            if ((index.row() - prev.row()) > 1) {
+                d->lastSelection << QItemSelectionRange(first, prev);
 
                 first = index;
             }
 
-            last = index;
+            prev = index;
         }
 
-        if (last.isValid())
-            selection << QItemSelectionRange(first, last);
-    }
+        d->lastSelection << QItemSelectionRange(first, prev);
 
-    if (d->lastSelection.count())
+        selectionModel()->select(d->lastSelection, flags);
+    }
+    else // selection with click + keyboard keys
     {
-        if ((selection.count() == 1) && (selection[0].indexes().count() == 1))
-            selection.merge(d->lastSelection, flags);
+        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
-            selection.merge(d->lastSelection, QItemSelectionModel::Select);
-    }
+        {
+            itemWidth = gridSize().width();
+        }
+
+        int itemWidthPlusSeparation = spacing() + itemWidth;
+        int elementsPerRow = viewportWidth / itemWidthPlusSeparation;
+        if (!elementsPerRow)
+            elementsPerRow++;
 
-    selectionModel()->select(selection, flags);
+        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());
+        }
+
+        // our current selection will result modified
+        d->lastSelection = QItemSelection(topLeft, bottomRight);
+
+        selectionModel()->select(d->lastSelection, flags);
+    }
 }
 
 void KCategorizedView::mouseMoveEvent(QMouseEvent *event)
@@ -958,10 +1020,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;
     }
 }
 
@@ -1001,39 +1059,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);
+                selectionModel()->select(selection, QItemSelectionModel::SelectCurrent);
 
                 break;
             }
         }
     }
 
-    d->lastSelection = selectionModel()->selection();
-
     if (d->hovered.isValid())
         viewport()->update(visualRect(d->hovered));
     else if (!d->hoveredCategory.isEmpty())
@@ -1055,7 +1103,9 @@ void KCategorizedView::startDrag(Qt::DropActions supportedActions)
     //        ARGB window so it is no transparent. Use QAbstractItemView when
     //        this is fixed on Qt.
     // QAbstractItemView::startDrag(supportedActions);
+#if !defined(DOLPHIN_DRAGANDDROP)
     QListView::startDrag(supportedActions);
+#endif
 
     d->isDragging = false;
     d->mouseButtonPressed = false;
@@ -1081,7 +1131,11 @@ void KCategorizedView::dragMoveEvent(QDragMoveEvent *event)
     if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
         !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
     {
+#if defined(DOLPHIN_DRAGANDDROP)
+        QAbstractItemView::dragMoveEvent(event);
+#else
         QListView::dragMoveEvent(event);
+#endif
         return;
     }
 
@@ -1092,7 +1146,20 @@ void KCategorizedView::dragLeaveEvent(QDragLeaveEvent *event)
 {
     d->dragLeftViewport = true;
 
+#if defined(DOLPHIN_DRAGANDDROP)
+    QAbstractItemView::dragLeaveEvent(event);
+#else
     QListView::dragLeaveEvent(event);
+#endif
+}
+
+void KCategorizedView::dropEvent(QDropEvent *event)
+{
+#if defined(DOLPHIN_DRAGANDDROP)
+    QAbstractItemView::dropEvent(event);
+#else
+    QListView::dropEvent(event);
+#endif
 }
 
 QModelIndex KCategorizedView::moveCursor(CursorAction cursorAction,
@@ -1108,7 +1175,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());
+        setCurrentIndex(current);
+        d->forcedSelectionPosition = 0;
+
+        return current;
+    }
 
     int viewportWidth = viewport()->width() - spacing();
     int itemWidth;
@@ -1124,6 +1200,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();
@@ -1209,36 +1287,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);
 
@@ -1304,7 +1402,7 @@ void KCategorizedView::rowsInsertedArtifficial(const QModelIndex &parent,
     }
 
     // Add all elements mapped to the source model and explore categories
-    QString prevCategory = d->proxyModel->data(d->proxyModel->index(0, d->proxyModel->sortColumn()), KCategorizedSortFilterProxyModel::CategoryRole).toString();
+    QString prevCategory = d->proxyModel->data(d->proxyModel->index(0, d->proxyModel->sortColumn()), KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
     QString lastCategory = prevCategory;
     QModelIndexList modelIndexList;
     struct Private::ElementInfo elementInfo;
@@ -1321,7 +1419,7 @@ void KCategorizedView::rowsInsertedArtifficial(const QModelIndex &parent,
 
         d->modelIndexList << index;
 
-        lastCategory = d->proxyModel->data(index, KCategorizedSortFilterProxyModel::CategoryRole).toString();
+        lastCategory = d->proxyModel->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
 
         elementInfo.category = lastCategory;