]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/kcategorizedview.cpp
Factorize all the view-related action handling to DolphinViewActionHandler, to remove...
[dolphin.git] / src / kcategorizedview.cpp
index 03002d30378280b8df37734f161685d973d9aa19..648a712a5373cc1c168cc24e2757c961b24ff16d 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)
@@ -128,12 +129,12 @@ QRect KCategorizedView::Private::visualRectInViewport(const QModelIndex &index)
     if (listView->layoutDirection() == Qt::LeftToRight)
     {
         retRect = QRect(listView->spacing(), listView->spacing() * 2 +
-                        categoryDrawer->categoryHeight(listView->viewOptions()), 0, 0);
+                        categoryDrawer->categoryHeight(index, listView->viewOptions()), 0, 0);
     }
     else
     {
         retRect = QRect(listView->viewport()->width() - listView->spacing(), listView->spacing() * 2 +
-                        categoryDrawer->categoryHeight(listView->viewOptions()), 0, 0);
+                        categoryDrawer->categoryHeight(index, listView->viewOptions()), 0, 0);
     }
 
     int viewportWidth = listView->viewport()->width() - listView->spacing();
@@ -188,7 +189,7 @@ QRect KCategorizedView::Private::visualRectInViewport(const QModelIndex &index)
 
         retRect.setTop(retRect.top() +
                        (rowsInt * itemHeight) +
-                       categoryDrawer->categoryHeight(listView->viewOptions()) +
+                       categoryDrawer->categoryHeight(index, listView->viewOptions()) +
                        listView->spacing() * 2);
 
         if (listView->gridSize().isEmpty())
@@ -272,7 +273,7 @@ QRect KCategorizedView::Private::visualCategoryRectInViewport(const QString &cat
 
         retRect.setTop(retRect.top() +
                        (rowsInt * itemHeight) +
-                       categoryDrawer->categoryHeight(listView->viewOptions()) +
+                       categoryDrawer->categoryHeight(index, listView->viewOptions()) +
                        listView->spacing() * 2);
 
         if (listView->gridSize().isEmpty())
@@ -282,7 +283,7 @@ QRect KCategorizedView::Private::visualCategoryRectInViewport(const QString &cat
         }
     }
 
-    retRect.setHeight(categoryDrawer->categoryHeight(listView->viewOptions()));
+    retRect.setHeight(categoryDrawer->categoryHeight(index, listView->viewOptions()));
 
     return retRect;
 }
@@ -364,19 +365,21 @@ void KCategorizedView::Private::drawNewCategory(const QModelIndex &index,
 
     optionCopy.state &= ~QStyle::State_Selected;
 
-    if ((category == hoveredCategory) && !mouseButtonPressed)
-    {
-        optionCopy.state |= QStyle::State_MouseOver;
-    }
-    else if ((category == hoveredCategory) && mouseButtonPressed)
-    {
-        QPoint initialPressPosition = listView->viewport()->mapFromGlobal(QCursor::pos());
-        initialPressPosition.setY(initialPressPosition.y() + listView->verticalOffset());
-        initialPressPosition.setX(initialPressPosition.x() + listView->horizontalOffset());
-
-        if (initialPressPosition == this->initialPressPosition)
+    if ((listView->selectionMode() != SingleSelection) && (listView->selectionMode() != NoSelection)) {
+        if ((category == hoveredCategory) && !mouseButtonPressed)
+        {
+            optionCopy.state |= QStyle::State_MouseOver;
+        }
+        else if ((category == hoveredCategory) && mouseButtonPressed)
         {
-            optionCopy.state |= QStyle::State_Selected;
+            QPoint initialPressPosition = listView->viewport()->mapFromGlobal(QCursor::pos());
+            initialPressPosition.setY(initialPressPosition.y() + listView->verticalOffset());
+            initialPressPosition.setX(initialPressPosition.x() + listView->horizontalOffset());
+
+            if (initialPressPosition == this->initialPressPosition)
+            {
+                optionCopy.state |= QStyle::State_Selected;
+            }
         }
     }
 
@@ -393,7 +396,7 @@ void KCategorizedView::Private::updateScrollbars()
     QModelIndex lastIndex = categoriesIndexes.isEmpty() ? QModelIndex() : categoriesIndexes[categories.last()].last();
 
     int lastItemBottom = cachedRectIndex(lastIndex).top() +
-                         listView->spacing() + (listView->gridSize().isEmpty() ? 0 : listView->gridSize().height()) - listView->viewport()->height();
+                         listView->spacing() + (listView->gridSize().isEmpty() ? biggestItemSize.height() : listView->gridSize().height()) - listView->viewport()->height();
 
     listView->horizontalScrollBar()->setRange(0, 0);
 
@@ -499,7 +502,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 +512,7 @@ void KCategorizedView::setModel(QAbstractItemModel *model)
     d->modelIndexList.clear();
     d->hovered = QModelIndex();
     d->mouseButtonPressed = false;
+    d->rightMouseButtonPressed = false;
 
     if (d->proxyModel)
     {
@@ -585,7 +588,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 +598,7 @@ void KCategorizedView::setCategoryDrawer(KCategoryDrawer *categoryDrawer)
     d->modelIndexList.clear();
     d->hovered = QModelIndex();
     d->mouseButtonPressed = false;
+    d->rightMouseButtonPressed = false;
 
     if (!categoryDrawer && d->proxyModel)
     {
@@ -661,8 +664,6 @@ QModelIndex KCategorizedView::indexAt(const QPoint &point) const
         index = item[0];
     }
 
-    d->hovered = index;
-
     return index;
 }
 
@@ -671,7 +672,6 @@ void KCategorizedView::reset()
     QListView::reset();
 
     d->lastSelection = QItemSelection();
-    d->currentViewIndex = QModelIndex();
     d->forcedSelectionPosition = 0;
     d->elementsInfo.clear();
     d->elementsPosition.clear();
@@ -683,6 +683,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 +744,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;
@@ -772,39 +776,42 @@ void KCategorizedView::paintEvent(QPaintEvent *event)
         else if (intersectedInThePast)
         {
             break; // the visible area has been finished, we don't need to keep asking, the rest won't intersect
-                   // this is doable because we know that categories are correctly ordered on the list
+                // this is doable because we know that categories are correctly ordered on the list
         }
     }
 
-    if (d->mouseButtonPressed && !d->isDragging)
+    if ((selectionMode() != SingleSelection) && (selectionMode() != NoSelection))
     {
-        QPoint start, end, initialPressPosition;
+        if (d->mouseButtonPressed && !d->isDragging)
+        {
+            QPoint start, end, initialPressPosition;
 
-        initialPressPosition = d->initialPressPosition;
+            initialPressPosition = d->initialPressPosition;
 
-        initialPressPosition.setY(initialPressPosition.y() - verticalOffset());
-        initialPressPosition.setX(initialPressPosition.x() - horizontalOffset());
+            initialPressPosition.setY(initialPressPosition.y() - verticalOffset());
+            initialPressPosition.setX(initialPressPosition.x() - horizontalOffset());
 
-        if (d->initialPressPosition.x() > d->mousePosition.x() ||
-            d->initialPressPosition.y() > d->mousePosition.y())
-        {
-            start = d->mousePosition;
-            end = initialPressPosition;
-        }
-        else
-        {
-            start = initialPressPosition;
-            end = d->mousePosition;
-        }
+            if (d->initialPressPosition.x() > d->mousePosition.x() ||
+                d->initialPressPosition.y() > d->mousePosition.y())
+            {
+                start = d->mousePosition;
+                end = initialPressPosition;
+            }
+            else
+            {
+                start = initialPressPosition;
+                end = d->mousePosition;
+            }
 
-        QStyleOptionRubberBand yetAnotherOption;
-        yetAnotherOption.initFrom(this);
-        yetAnotherOption.shape = QRubberBand::Rectangle;
-        yetAnotherOption.opaque = false;
-        yetAnotherOption.rect = QRect(start, end).intersected(viewport()->rect().adjusted(-16, -16, 16, 16));
-        painter.save();
-        style()->drawControl(QStyle::CE_RubberBand, &yetAnotherOption, &painter);
-        painter.restore();
+            QStyleOptionRubberBand yetAnotherOption;
+            yetAnotherOption.initFrom(this);
+            yetAnotherOption.shape = QRubberBand::Rectangle;
+            yetAnotherOption.opaque = false;
+            yetAnotherOption.rect = QRect(start, end).intersected(viewport()->rect().adjusted(-16, -16, 16, 16));
+            painter.save();
+            style()->drawControl(QStyle::CE_RubberBand, &yetAnotherOption, &painter);
+            painter.restore();
+        }
     }
 
     if (d->isDragging && !d->dragLeftViewport)
@@ -850,6 +857,7 @@ void KCategorizedView::setSelection(const QRect &rect,
     if (flags & QItemSelectionModel::Clear)
     {
         selectionModel()->clear();
+        d->lastSelection.clear();
     }
 
     QModelIndexList dirtyIndexes = d->intersectionSet(rect);
@@ -857,20 +865,7 @@ void KCategorizedView::setSelection(const QRect &rect,
     // no items affected, just leave
     if (!dirtyIndexes.count())
     {
-        selectionModel()->select(d->lastSelection, flags);
-
-        d->lastSelection.clear();
-
-        return;
-    }
-
-    d->lastSelection.clear();
-
-    if (!(flags & QItemSelectionModel::Current))
-    {
-        Q_ASSERT(dirtyIndexes.count() == 1);
-
-        selectionModel()->select(dirtyIndexes[0], flags);
+        selectionModel()->select(d->lastSelection, QItemSelectionModel::SelectCurrent);
 
         return;
     }
@@ -878,14 +873,17 @@ void KCategorizedView::setSelection(const QRect &rect,
     QModelIndex topLeft;
     QModelIndex bottomRight;
 
-    if (d->mouseButtonPressed) // selection with click + drag
+    if (d->mouseButtonPressed || d->rightMouseButtonPressed) // selection with click + drag
     {
+        QItemSelection selection;
+
         QModelIndex prev = dirtyIndexes[0];
         QModelIndex first = prev;
         foreach (const QModelIndex &index, dirtyIndexes)
         {
+            // we have a different interval. non-contiguous items
             if ((index.row() - prev.row()) > 1) {
-                d->lastSelection << QItemSelectionRange(first, prev);
+                selection << QItemSelectionRange(first, prev);
 
                 first = index;
             }
@@ -893,9 +891,27 @@ void KCategorizedView::setSelection(const QRect &rect,
             prev = index;
         }
 
-        d->lastSelection << QItemSelectionRange(first, prev);
+        selection << QItemSelectionRange(first, prev);
+
+        if (flags & QItemSelectionModel::Current)
+        {
+            if (rect.topLeft() == rect.bottomRight())
+            {
+                selectionModel()->setCurrentIndex(indexAt(rect.topLeft()), QItemSelectionModel::NoUpdate);
+            }
 
-        selectionModel()->select(d->lastSelection, flags);
+            selection.merge(d->lastSelection, flags);
+        }
+        else
+        {
+            selection.merge(selectionModel()->selection(), flags);
+
+            selectionModel()->select(selection, QItemSelectionModel::SelectCurrent);
+
+            return;
+        }
+
+        selectionModel()->select(selection, flags);
     }
     else // selection with click + keyboard keys
     {
@@ -960,10 +976,9 @@ void KCategorizedView::setSelection(const QRect &rect,
             dirtyIndexes << model()->index(i, theoricDirty[0].column(), theoricDirty[0].parent());
         }
 
-        // our current selection will result modified
-        d->lastSelection = QItemSelection(topLeft, bottomRight);
+        QItemSelection selection(topLeft, bottomRight);
 
-        selectionModel()->select(d->lastSelection, flags);
+        selectionModel()->select(selection, flags);
     }
 }
 
@@ -977,6 +992,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();
@@ -1019,7 +1045,10 @@ void KCategorizedView::mouseMoveEvent(QMouseEvent *event)
             end = d->mousePosition;
         }
 
-        rect = QRect(start, end).intersected(viewport()->rect().adjusted(-16, -16, 16, 16));
+        rect = QRect(start, end).adjusted(-16, -16, 16, 16);
+        rect = rect.united(QRect(start, end).adjusted(16, 16, -16, -16)).intersected(viewport()->rect());
+
+        viewport()->update(rect);
     }
 }
 
@@ -1037,15 +1066,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);
 
@@ -1059,37 +1095,57 @@ void KCategorizedView::mouseReleaseEvent(QMouseEvent *event)
     initialPressPosition.setY(initialPressPosition.y() + verticalOffset());
     initialPressPosition.setX(initialPressPosition.x() + horizontalOffset());
 
-    QItemSelection selection;
-    QItemSelection deselection;
-#if 0
-    if (initialPressPosition == d->initialPressPosition)
+    if ((selectionMode() != SingleSelection) && (selectionMode() != NoSelection) &&
+        (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 = selectionModel()->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;
             }
         }
     }
-#endif
+
+    QRect rect;
+    if (!d->isDragging)
+    {
+        QPoint start, end, initialPressPosition;
+
+        initialPressPosition = d->initialPressPosition;
+
+        initialPressPosition.setY(initialPressPosition.y() - verticalOffset());
+        initialPressPosition.setX(initialPressPosition.x() - horizontalOffset());
+
+        if (d->initialPressPosition.x() > d->mousePosition.x() ||
+            d->initialPressPosition.y() > d->mousePosition.y())
+        {
+            start = d->mousePosition;
+            end = initialPressPosition;
+        }
+        else
+        {
+            start = initialPressPosition;
+            end = d->mousePosition;
+        }
+
+        rect = QRect(start, end).adjusted(-16, -16, 16, 16);
+        rect = rect.united(QRect(start, end).adjusted(16, 16, -16, -16)).intersected(viewport()->rect());
+
+        viewport()->update(rect);
+    }
 
     if (d->hovered.isValid())
         viewport()->update(visualRect(d->hovered));
@@ -1118,6 +1174,7 @@ void KCategorizedView::startDrag(Qt::DropActions supportedActions)
 
     d->isDragging = false;
     d->mouseButtonPressed = false;
+    d->rightMouseButtonPressed = false;
 
     viewport()->update(d->lastDraggedItemsRect);
 }
@@ -1137,14 +1194,15 @@ void KCategorizedView::dragMoveEvent(QDragMoveEvent *event)
 
     d->dragLeftViewport = false;
 
-    if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
-        !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
-    {
 #if defined(DOLPHIN_DRAGANDDROP)
-        QAbstractItemView::dragMoveEvent(event);
+    QAbstractItemView::dragMoveEvent(event);
 #else
-        QListView::dragMoveEvent(event);
+    QListView::dragMoveEvent(event);
 #endif
+
+    if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
+        !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
+    {
         return;
     }
 
@@ -1184,17 +1242,6 @@ QModelIndex KCategorizedView::moveCursor(CursorAction cursorAction,
         return QListView::moveCursor(cursorAction, modifiers);
     }
 
-    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;
 
@@ -1212,6 +1259,28 @@ QModelIndex KCategorizedView::moveCursor(CursorAction cursorAction,
     if (!elementsPerRow)
         elementsPerRow++;
 
+    QModelIndex current = selectionModel()->currentIndex();
+
+    if (!current.isValid())
+    {
+        if (cursorAction == MoveEnd)
+        {
+            current = model()->index(model()->rowCount() - 1, 0, QModelIndex());
+            d->forcedSelectionPosition = d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow;
+        }
+        else
+        {
+            current = model()->index(0, 0, QModelIndex());
+            d->forcedSelectionPosition = 0;
+        }
+
+        return current;
+    }
+    else if (!current.isValid())
+    {
+        return QModelIndex();
+    }
+
     QString lastCategory = d->categories.first();
     QString theCategory = d->categories.first();
     QString afterCategory = d->categories.first();
@@ -1365,8 +1434,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();
@@ -1378,6 +1445,7 @@ void KCategorizedView::rowsInserted(const QModelIndex &parent,
         d->hovered = QModelIndex();
         d->biggestItemSize = QSize(0, 0);
         d->mouseButtonPressed = false;
+        d->rightMouseButtonPressed = false;
 
         return;
     }
@@ -1391,8 +1459,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();
@@ -1404,6 +1470,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())
     {
@@ -1456,6 +1523,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,
@@ -1489,4 +1560,37 @@ 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++;
+
+    if (d->mouseButtonPressed || d->rightMouseButtonPressed)
+        d->forcedSelectionPosition = d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow;
+
+    QListView::currentChanged(current, previous);
+}
+
 #include "kcategorizedview.moc"