]> 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 d250c42c90d585c4094b5423f0964da260bad3d9..648a712a5373cc1c168cc24e2757c961b24ff16d 100644 (file)
@@ -1,6 +1,6 @@
 /**
   * This file is part of the KDE project
-  * Copyright (C) 2007 Rafael Fernández López <ereslibre@gmail.com>
+  * Copyright (C) 2007 Rafael Fernández López <ereslibre@kde.org>
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Library General Public
 #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 <kdebug.h>
 #include <kstyle.h>
 
-#include "kitemcategorizer.h"
-#include "ksortfilterproxymodel.h"
-
-class LessThan
-{
-public:
-    enum Purpose
-    {
-        GeneralPurpose = 0,
-        CategoryPurpose
-    };
-
-    inline LessThan(const KSortFilterProxyModel *proxyModel,
-                    Purpose purpose)
-        : proxyModel(proxyModel)
-        , purpose(purpose)
-    {
-    }
-
-    inline bool operator()(const QModelIndex &left,
-                           const QModelIndex &right) const
-    {
-        if (purpose == GeneralPurpose)
-        {
-            return proxyModel->sortOrder() == Qt::AscendingOrder ?
-                   proxyModel->lessThanGeneralPurpose(left, right) :
-                   !proxyModel->lessThanGeneralPurpose(left, right);
-        }
-
-        return proxyModel->sortOrder() == Qt::AscendingOrder ?
-               proxyModel->lessThanCategoryPurpose(left, right) :
-               !proxyModel->lessThanCategoryPurpose(left, right);
-    }
-
-private:
-    const KSortFilterProxyModel *proxyModel;
-    const Purpose purpose;
-};
-
-
-//==============================================================================
+#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)
-    , itemCategorizer(0)
+    , categoryDrawer(0)
     , biggestItemSize(QSize(0, 0))
     , mouseButtonPressed(false)
+    , rightMouseButtonPressed(false)
     , isDragging(false)
     , dragLeftViewport(false)
     , proxyModel(0)
-    , lastIndex(QModelIndex())
 {
 }
 
@@ -117,7 +81,7 @@ const QModelIndexList &KCategorizedView::Private::intersectionSet(const QRect &r
     {
         middle = (top + bottom) / 2;
 
-        index = elementDictionary[proxyModel->index(middle, 0)];
+        index = proxyModel->index(middle, 0);
         indexVisualRect = visualRect(index);
         // We need the whole height (not only the visualRect). This will help us to update
         // all needed indexes correctly (ereslibre)
@@ -137,7 +101,7 @@ const QModelIndexList &KCategorizedView::Private::intersectionSet(const QRect &r
 
     for (int i = middle; i < proxyModel->rowCount(); i++)
     {
-        index = elementDictionary[proxyModel->index(i, 0)];
+        index = proxyModel->index(i, 0);
         indexVisualRect = visualRect(index);
 
         if (rect.intersects(indexVisualRect))
@@ -158,10 +122,20 @@ QRect KCategorizedView::Private::visualRectInViewport(const QModelIndex &index)
     if (!index.isValid())
         return QRect();
 
-    QString curCategory = elementsInfo[index].category;
+    QString curCategory = elementsInfo[index.row()].category;
 
-    QRect retRect(listView->spacing(), listView->spacing() * 2 +
-                  itemCategorizer->categoryHeight(listView->viewOptions()), 0, 0);
+    QRect retRect;
+
+    if (listView->layoutDirection() == Qt::LeftToRight)
+    {
+        retRect = QRect(listView->spacing(), listView->spacing() * 2 +
+                        categoryDrawer->categoryHeight(index, listView->viewOptions()), 0, 0);
+    }
+    else
+    {
+        retRect = QRect(listView->viewport()->width() - listView->spacing(), listView->spacing() * 2 +
+                        categoryDrawer->categoryHeight(index, listView->viewOptions()), 0, 0);
+    }
 
     int viewportWidth = listView->viewport()->width() - listView->spacing();
 
@@ -184,11 +158,22 @@ QRect KCategorizedView::Private::visualRectInViewport(const QModelIndex &index)
     if (!elementsPerRow)
         elementsPerRow++;
 
-    int column = elementsInfo[index].relativeOffsetToCategory % elementsPerRow;
-    int row = elementsInfo[index].relativeOffsetToCategory / elementsPerRow;
+    int column = elementsInfo[index.row()].relativeOffsetToCategory % elementsPerRow;
+    int row = elementsInfo[index.row()].relativeOffsetToCategory / elementsPerRow;
+
+    if (listView->layoutDirection() == Qt::LeftToRight)
+    {
+        retRect.setLeft(retRect.left() + column * listView->spacing() +
+                        column * itemWidth);
+    }
+    else
+    {
+        retRect.setLeft(retRect.right() - column * listView->spacing() -
+                         column * itemWidth - itemWidth);
 
-    retRect.setLeft(retRect.left() + column * listView->spacing() +
-                    column * itemWidth);
+        retRect.setRight(retRect.right() - column * listView->spacing() -
+                         column * itemWidth);
+    }
 
     foreach (const QString &category, categories)
     {
@@ -197,13 +182,14 @@ QRect KCategorizedView::Private::visualRectInViewport(const QModelIndex &index)
 
         float rows = (float) ((float) categoriesIndexes[category].count() /
                               (float) elementsPerRow);
+
         int rowsInt = categoriesIndexes[category].count() / elementsPerRow;
 
         if (rows - trunc(rows)) rowsInt++;
 
         retRect.setTop(retRect.top() +
                        (rowsInt * itemHeight) +
-                       itemCategorizer->categoryHeight(listView->viewOptions()) +
+                       categoryDrawer->categoryHeight(index, listView->viewOptions()) +
                        listView->spacing() * 2);
 
         if (listView->gridSize().isEmpty())
@@ -213,7 +199,6 @@ QRect KCategorizedView::Private::visualRectInViewport(const QModelIndex &index)
         }
     }
 
-
     if (listView->gridSize().isEmpty())
     {
         retRect.setTop(retRect.top() + row * listView->spacing() +
@@ -226,13 +211,14 @@ QRect KCategorizedView::Private::visualRectInViewport(const QModelIndex &index)
 
     retRect.setWidth(itemWidth);
 
+    QModelIndex heightIndex = proxyModel->index(index.row(), 0);
     if (listView->gridSize().isEmpty())
     {
-        retRect.setHeight(listView->sizeHintForIndex(proxyModel->mapFromSource(index)).height());
+        retRect.setHeight(listView->sizeHintForIndex(heightIndex).height());
     }
     else
     {
-        retRect.setHeight(qMin(listView->sizeHintForIndex(proxyModel->mapFromSource(index)).height(),
+        retRect.setHeight(qMin(listView->sizeHintForIndex(heightIndex).height(),
                                listView->gridSize().height()));
     }
 
@@ -287,7 +273,7 @@ QRect KCategorizedView::Private::visualCategoryRectInViewport(const QString &cat
 
         retRect.setTop(retRect.top() +
                        (rowsInt * itemHeight) +
-                       itemCategorizer->categoryHeight(listView->viewOptions()) +
+                       categoryDrawer->categoryHeight(index, listView->viewOptions()) +
                        listView->spacing() * 2);
 
         if (listView->gridSize().isEmpty())
@@ -297,7 +283,7 @@ QRect KCategorizedView::Private::visualCategoryRectInViewport(const QString &cat
         }
     }
 
-    retRect.setHeight(itemCategorizer->categoryHeight(listView->viewOptions()));
+    retRect.setHeight(categoryDrawer->categoryHeight(index, listView->viewOptions()));
 
     return retRect;
 }
@@ -306,9 +292,9 @@ QRect KCategorizedView::Private::visualCategoryRectInViewport(const QString &cat
 const QRect &KCategorizedView::Private::cacheIndex(const QModelIndex &index)
 {
     QRect rect = visualRectInViewport(index);
-    elementsPosition[index] = rect;
+    elementsPosition[index.row()] = rect;
 
-    return elementsPosition[index];
+    return elementsPosition[index.row()];
 }
 
 // We're sure categoriesPosition doesn't contain category
@@ -322,9 +308,9 @@ const QRect &KCategorizedView::Private::cacheCategory(const QString &category)
 
 const QRect &KCategorizedView::Private::cachedRectIndex(const QModelIndex &index)
 {
-    if (elementsPosition.contains(index)) // If we have it cached
+    if (elementsPosition.contains(index.row())) // If we have it cached
     {                                        // return it
-        return elementsPosition[index];
+        return elementsPosition[index.row()];
     }
     else                                     // Otherwise, cache it
     {                                        // and return it
@@ -346,9 +332,7 @@ const QRect &KCategorizedView::Private::cachedRectCategory(const QString &catego
 
 QRect KCategorizedView::Private::visualRect(const QModelIndex &index)
 {
-    QModelIndex mappedIndex = proxyModel->mapToSource(index);
-
-    QRect retRect = cachedRectIndex(mappedIndex);
+    QRect retRect = cachedRectIndex(index);
     int dx = -listView->horizontalOffset();
     int dy = -listView->verticalOffset();
     retRect.adjust(dx, dy, dx, dy);
@@ -367,29 +351,54 @@ QRect KCategorizedView::Private::categoryVisualRect(const QString &category)
 }
 
 void KCategorizedView::Private::drawNewCategory(const QModelIndex &index,
-                                         int sortRole,
-                                         const QStyleOption &option,
-                                         QPainter *painter)
+                                                int sortRole,
+                                                const QStyleOption &option,
+                                                QPainter *painter)
 {
+    if (!index.isValid())
+    {
+        return;
+    }
+
     QStyleOption optionCopy = option;
-    const QString category = itemCategorizer->categoryForItem(index, sortRole);
+    const QString category = proxyModel->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
 
-    if ((category == hoveredCategory) && !mouseButtonPressed)
-    {
-        optionCopy.state |= QStyle::State_MouseOver;
+    optionCopy.state &= ~QStyle::State_Selected;
+
+    if ((listView->selectionMode() != SingleSelection) && (listView->selectionMode() != NoSelection)) {
+        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)
+            {
+                optionCopy.state |= QStyle::State_Selected;
+            }
+        }
     }
 
-    itemCategorizer->drawCategory(index,
-                                  sortRole,
-                                  optionCopy,
-                                  painter);
+    categoryDrawer->drawCategory(index,
+                                 sortRole,
+                                 optionCopy,
+                                 painter);
 }
 
 
 void KCategorizedView::Private::updateScrollbars()
 {
+    // find the last index in the last category
+    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);
 
     listView->verticalScrollBar()->setSingleStep(listView->viewport()->height() / 10);
     listView->verticalScrollBar()->setPageStep(listView->viewport()->height());
@@ -415,6 +424,36 @@ void KCategorizedView::Private::drawDraggedItems(QPainter *painter)
     }
 }
 
+void KCategorizedView::Private::layoutChanged(bool forceItemReload)
+{
+    if ((listView->viewMode() == KCategorizedView::IconMode) && proxyModel &&
+        categoryDrawer && proxyModel->isCategorizedModel() &&
+        ((forceItemReload ||
+          (modelSortRole != proxyModel->sortRole()) ||
+          (modelSortColumn != proxyModel->sortColumn()) ||
+          (modelSortOrder != proxyModel->sortOrder()) ||
+          (modelLastRowCount != proxyModel->rowCount()) ||
+          (modelCategorized != proxyModel->isCategorizedModel()))))
+    {
+        // Force the view to update all elements
+        listView->rowsInsertedArtifficial(QModelIndex(), 0, proxyModel->rowCount() - 1);
+
+        if (!forceItemReload)
+        {
+            modelSortRole = proxyModel->sortRole();
+            modelSortColumn = proxyModel->sortColumn();
+            modelSortOrder = proxyModel->sortOrder();
+            modelLastRowCount = proxyModel->rowCount();
+            modelCategorized = proxyModel->isCategorizedModel();
+        }
+    }
+    else if ((listView->viewMode() == KCategorizedView::IconMode) && proxyModel &&
+             categoryDrawer && proxyModel->isCategorizedModel())
+    {
+        updateScrollbars();
+    }
+}
+
 void KCategorizedView::Private::drawDraggedItems()
 {
     QRect rectToUpdate;
@@ -453,54 +492,82 @@ KCategorizedView::~KCategorizedView()
     delete d;
 }
 
+void KCategorizedView::setGridSize(const QSize &size)
+{
+    QListView::setGridSize(size);
+
+    d->layoutChanged(true);
+}
+
 void KCategorizedView::setModel(QAbstractItemModel *model)
 {
     d->lastSelection = QItemSelection();
-    d->currentViewIndex = QModelIndex();
     d->forcedSelectionPosition = 0;
     d->elementsInfo.clear();
     d->elementsPosition.clear();
-    d->elementDictionary.clear();
-    d->invertedElementDictionary.clear();
     d->categoriesIndexes.clear();
     d->categoriesPosition.clear();
     d->categories.clear();
     d->intersectedIndexes.clear();
-    d->sourceModelIndexList.clear();
+    d->modelIndexList.clear();
     d->hovered = QModelIndex();
     d->mouseButtonPressed = false;
+    d->rightMouseButtonPressed = false;
 
     if (d->proxyModel)
     {
         QObject::disconnect(d->proxyModel,
-                            SIGNAL(rowsRemoved(QModelIndex,int,int)),
-                            this, SLOT(rowsRemoved(QModelIndex,int,int)));
+                            SIGNAL(layoutChanged()),
+                            this, SLOT(slotLayoutChanged()));
 
         QObject::disconnect(d->proxyModel,
-                            SIGNAL(sortingRoleChanged()),
-                            this, SLOT(slotSortingRoleChanged()));
+                            SIGNAL(dataChanged(QModelIndex,QModelIndex)),
+                            this, SLOT(slotLayoutChanged()));
+
+        QObject::disconnect(d->proxyModel,
+                            SIGNAL(rowsRemoved(QModelIndex,int,int)),
+                            this, SLOT(rowsRemoved(QModelIndex,int,int)));
     }
 
     QListView::setModel(model);
 
-    d->proxyModel = dynamic_cast<KSortFilterProxyModel*>(model);
+    d->proxyModel = dynamic_cast<KCategorizedSortFilterProxyModel*>(model);
 
     if (d->proxyModel)
     {
+        d->modelSortRole = d->proxyModel->sortRole();
+        d->modelSortColumn = d->proxyModel->sortColumn();
+        d->modelSortOrder = d->proxyModel->sortOrder();
+        d->modelLastRowCount = d->proxyModel->rowCount();
+        d->modelCategorized = d->proxyModel->isCategorizedModel();
+
+        QObject::connect(d->proxyModel,
+                         SIGNAL(layoutChanged()),
+                         this, SLOT(slotLayoutChanged()));
+
+        QObject::connect(d->proxyModel,
+                         SIGNAL(dataChanged(QModelIndex,QModelIndex)),
+                         this, SLOT(slotLayoutChanged()));
+
         QObject::connect(d->proxyModel,
                          SIGNAL(rowsRemoved(QModelIndex,int,int)),
                          this, SLOT(rowsRemoved(QModelIndex,int,int)));
 
-        QObject::connect(d->proxyModel,
-                         SIGNAL(sortingRoleChanged()),
-                         this, SLOT(slotSortingRoleChanged()));
+        if (d->proxyModel->rowCount())
+        {
+            d->layoutChanged(true);
+        }
+    }
+    else
+    {
+        d->modelCategorized = false;
     }
 }
 
 QRect KCategorizedView::visualRect(const QModelIndex &index) const
 {
     if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
-        !d->itemCategorizer)
+        !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
     {
         return QListView::visualRect(index);
     }
@@ -513,54 +580,66 @@ QRect KCategorizedView::visualRect(const QModelIndex &index) const
     return d->visualRect(index);
 }
 
-KItemCategorizer *KCategorizedView::itemCategorizer() const
+KCategoryDrawer *KCategorizedView::categoryDrawer() const
 {
-    return d->itemCategorizer;
+    return d->categoryDrawer;
 }
 
-void KCategorizedView::setItemCategorizer(KItemCategorizer *itemCategorizer)
+void KCategorizedView::setCategoryDrawer(KCategoryDrawer *categoryDrawer)
 {
     d->lastSelection = QItemSelection();
-    d->currentViewIndex = QModelIndex();
     d->forcedSelectionPosition = 0;
     d->elementsInfo.clear();
     d->elementsPosition.clear();
-    d->elementDictionary.clear();
-    d->invertedElementDictionary.clear();
     d->categoriesIndexes.clear();
     d->categoriesPosition.clear();
     d->categories.clear();
     d->intersectedIndexes.clear();
-    d->sourceModelIndexList.clear();
+    d->modelIndexList.clear();
     d->hovered = QModelIndex();
     d->mouseButtonPressed = false;
+    d->rightMouseButtonPressed = false;
 
-    if (!itemCategorizer && d->proxyModel)
+    if (!categoryDrawer && d->proxyModel)
     {
         QObject::disconnect(d->proxyModel,
-                            SIGNAL(rowsRemoved(QModelIndex,int,int)),
-                            this, SLOT(rowsRemoved(QModelIndex,int,int)));
+                            SIGNAL(layoutChanged()),
+                            this, SLOT(slotLayoutChanged()));
+
+        QObject::disconnect(d->proxyModel,
+                            SIGNAL(dataChanged(QModelIndex,QModelIndex)),
+                            this, SLOT(slotLayoutChanged()));
 
         QObject::disconnect(d->proxyModel,
-                            SIGNAL(sortingRoleChanged()),
-                            this, SLOT(slotSortingRoleChanged()));
+                            SIGNAL(rowsRemoved(QModelIndex,int,int)),
+                            this, SLOT(rowsRemoved(QModelIndex,int,int)));
     }
-    else if (itemCategorizer && d->proxyModel)
+    else if (categoryDrawer && d->proxyModel)
     {
         QObject::connect(d->proxyModel,
-                         SIGNAL(rowsRemoved(QModelIndex,int,int)),
-                         this, SLOT(rowsRemoved(QModelIndex,int,int)));
+                         SIGNAL(layoutChanged()),
+                         this, SLOT(slotLayoutChanged()));
+
+        QObject::connect(d->proxyModel,
+                         SIGNAL(dataChanged(QModelIndex,QModelIndex)),
+                         this, SLOT(slotLayoutChanged()));
 
         QObject::connect(d->proxyModel,
-                         SIGNAL(sortingRoleChanged()),
-                         this, SLOT(slotSortingRoleChanged()));
+                         SIGNAL(rowsRemoved(QModelIndex,int,int)),
+                         this, SLOT(rowsRemoved(QModelIndex,int,int)));
     }
 
-    d->itemCategorizer = itemCategorizer;
+    d->categoryDrawer = categoryDrawer;
 
-    if (itemCategorizer)
+    if (categoryDrawer)
     {
-        rowsInserted(QModelIndex(), 0, d->proxyModel->rowCount() - 1);
+        if (d->proxyModel)
+        {
+            if (d->proxyModel->rowCount())
+            {
+                d->layoutChanged(true);
+            }
+        }
     }
     else
     {
@@ -571,7 +650,7 @@ void KCategorizedView::setItemCategorizer(KItemCategorizer *itemCategorizer)
 QModelIndex KCategorizedView::indexAt(const QPoint &point) const
 {
     if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
-        !d->itemCategorizer)
+        !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
     {
         return QListView::indexAt(point);
     }
@@ -585,8 +664,6 @@ QModelIndex KCategorizedView::indexAt(const QPoint &point) const
         index = item[0];
     }
 
-    d->hovered = index;
-
     return index;
 }
 
@@ -595,26 +672,24 @@ void KCategorizedView::reset()
     QListView::reset();
 
     d->lastSelection = QItemSelection();
-    d->currentViewIndex = QModelIndex();
     d->forcedSelectionPosition = 0;
     d->elementsInfo.clear();
     d->elementsPosition.clear();
-    d->elementDictionary.clear();
-    d->invertedElementDictionary.clear();
     d->categoriesIndexes.clear();
     d->categoriesPosition.clear();
     d->categories.clear();
     d->intersectedIndexes.clear();
-    d->sourceModelIndexList.clear();
+    d->modelIndexList.clear();
     d->hovered = QModelIndex();
     d->biggestItemSize = QSize(0, 0);
     d->mouseButtonPressed = false;
+    d->rightMouseButtonPressed = false;
 }
 
 void KCategorizedView::paintEvent(QPaintEvent *event)
 {
     if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
-        !d->itemCategorizer)
+        !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
     {
         QListView::paintEvent(event);
         return;
@@ -669,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;
@@ -679,6 +757,7 @@ void KCategorizedView::paintEvent(QPaintEvent *event)
 
     // Redraw categories
     QStyleOptionViewItem otherOption;
+    bool intersectedInThePast = false;
     foreach (const QString &category, d->categories)
     {
         otherOption = option;
@@ -687,40 +766,52 @@ void KCategorizedView::paintEvent(QPaintEvent *event)
 
         if (otherOption.rect.intersects(area))
         {
-            d->drawNewCategory(d->categoriesIndexes[category][0],
+            intersectedInThePast = true;
+
+            QModelIndex indexToDraw = d->proxyModel->index(d->categoriesIndexes[category][0].row(), d->proxyModel->sortColumn());
+
+            d->drawNewCategory(indexToDraw,
                                d->proxyModel->sortRole(), otherOption, &painter);
         }
+        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
+        }
     }
 
-    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)
@@ -742,7 +833,7 @@ void KCategorizedView::resizeEvent(QResizeEvent *event)
     d->forcedSelectionPosition = 0;
 
     if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
-        !d->itemCategorizer)
+        !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
     {
         return;
     }
@@ -754,7 +845,7 @@ void KCategorizedView::setSelection(const QRect &rect,
                                     QItemSelectionModel::SelectionFlags flags)
 {
     if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
-        !d->itemCategorizer)
+        !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
     {
         QListView::setSelection(rect, flags);
         return;
@@ -763,64 +854,132 @@ void KCategorizedView::setSelection(const QRect &rect,
     if (!flags)
         return;
 
-    selectionModel()->clear();
-
     if (flags & QItemSelectionModel::Clear)
     {
-        d->lastSelection = QItemSelection();
+        selectionModel()->clear();
+        d->lastSelection.clear();
     }
 
     QModelIndexList dirtyIndexes = d->intersectionSet(rect);
 
-    QItemSelection selection;
-
+    // no items affected, just leave
     if (!dirtyIndexes.count())
     {
-        if (d->lastSelection.count())
-        {
-            selectionModel()->select(d->lastSelection, flags);
-        }
+        selectionModel()->select(d->lastSelection, QItemSelectionModel::SelectCurrent);
 
         return;
     }
 
-    if (!d->mouseButtonPressed)
-    {
-        selection = QItemSelection(dirtyIndexes[0], dirtyIndexes[0]);
-        d->currentViewIndex = dirtyIndexes[0];
-    }
-    else
+    QModelIndex topLeft;
+    QModelIndex bottomRight;
+
+    if (d->mouseButtonPressed || d->rightMouseButtonPressed) // selection with click + drag
     {
-        QModelIndex first = dirtyIndexes[0];
-        QModelIndex last;
+        QItemSelection selection;
+
+        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 (d->lastSelection.count() && !d->mouseButtonPressed)
-    {
-        selection.merge(d->lastSelection, flags);
+        if (flags & QItemSelectionModel::Current)
+        {
+            if (rect.topLeft() == rect.bottomRight())
+            {
+                selectionModel()->setCurrentIndex(indexAt(rect.topLeft()), QItemSelectionModel::NoUpdate);
+            }
+
+            selection.merge(d->lastSelection, flags);
+        }
+        else
+        {
+            selection.merge(selectionModel()->selection(), flags);
+
+            selectionModel()->select(selection, QItemSelectionModel::SelectCurrent);
+
+            return;
+        }
+
+        selectionModel()->select(selection, flags);
     }
-    else if (d->lastSelection.count())
+    else // selection with click + keyboard keys
     {
-        selection.merge(d->lastSelection, QItemSelectionModel::Select);
-    }
+        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;
+        }
 
-    selectionModel()->select(selection, flags);
+        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);
+    }
 }
 
 void KCategorizedView::mouseMoveEvent(QMouseEvent *event)
@@ -828,11 +987,22 @@ void KCategorizedView::mouseMoveEvent(QMouseEvent *event)
     QListView::mouseMoveEvent(event);
 
     if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
-        !d->itemCategorizer)
+        !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
     {
         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();
@@ -875,11 +1045,10 @@ void KCategorizedView::mouseMoveEvent(QMouseEvent *event)
             end = d->mousePosition;
         }
 
-        rect = QRect(start, end).intersected(viewport()->rect().adjusted(-16, -16, 16, 16));
-
-        //viewport()->update(rect.united(d->lastSelectionRect));
+        rect = QRect(start, end).adjusted(-16, -16, 16, 16);
+        rect = rect.united(QRect(start, end).adjusted(16, 16, -16, -16)).intersected(viewport()->rect());
 
-        d->lastSelectionRect = rect;
+        viewport()->update(rect);
     }
 }
 
@@ -897,18 +1066,27 @@ 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);
 
     if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
-        !d->itemCategorizer)
+        !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
     {
         return;
     }
@@ -917,27 +1095,57 @@ void KCategorizedView::mouseReleaseEvent(QMouseEvent *event)
     initialPressPosition.setY(initialPressPosition.y() + verticalOffset());
     initialPressPosition.setX(initialPressPosition.x() + horizontalOffset());
 
-    QItemSelection selection;
-
-    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)
                 {
-                    selection << QItemSelectionRange(d->proxyModel->mapFromSource(index));
+                    QModelIndex selectIndex = index.model()->index(index.row(), 0);
+
+                    selection << QItemSelectionRange(selectIndex);
                 }
 
-                selectionModel()->select(selection, QItemSelectionModel::Select);
+                selectionModel()->select(selection, QItemSelectionModel::SelectCurrent);
 
                 break;
             }
         }
     }
 
-    d->lastSelection = selectionModel()->selection();
+    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));
@@ -955,10 +1163,18 @@ void KCategorizedView::leaveEvent(QEvent *event)
 
 void KCategorizedView::startDrag(Qt::DropActions supportedActions)
 {
+    // FIXME: QAbstractItemView does far better here since it sets the
+    //        pixmap of selected icons to the dragging cursor, but it sets a non
+    //        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;
+    d->rightMouseButtonPressed = false;
 
     viewport()->update(d->lastDraggedItemsRect);
 }
@@ -978,10 +1194,15 @@ void KCategorizedView::dragMoveEvent(QDragMoveEvent *event)
 
     d->dragLeftViewport = false;
 
+#if defined(DOLPHIN_DRAGANDDROP)
+    QAbstractItemView::dragMoveEvent(event);
+#else
+    QListView::dragMoveEvent(event);
+#endif
+
     if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
-        !d->itemCategorizer)
+        !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
     {
-        QListView::dragMoveEvent(event);
         return;
     }
 
@@ -992,20 +1213,35 @@ 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,
-                                  Qt::KeyboardModifiers modifiers)
+                                         Qt::KeyboardModifiers modifiers)
 {
-    if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
-        !d->itemCategorizer)
+    if ((viewMode() != KCategorizedView::IconMode) ||
+         !d->proxyModel ||
+         !d->categoryDrawer ||
+          d->categories.isEmpty() ||
+         !d->proxyModel->isCategorizedModel()
+       )
     {
         return QListView::moveCursor(cursorAction, modifiers);
     }
 
-    const QModelIndex current = selectionModel()->currentIndex();
-
     int viewportWidth = viewport()->width() - spacing();
     int itemWidth;
 
@@ -1020,10 +1256,35 @@ QModelIndex KCategorizedView::moveCursor(CursorAction cursorAction,
 
     int itemWidthPlusSeparation = spacing() + itemWidth;
     int elementsPerRow = viewportWidth / itemWidthPlusSeparation;
+    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();
 
-    QString lastCategory = d->categories[0];
-    QString theCategory = d->categories[0];
-    QString afterCategory = d->categories[0];
     bool hasToBreak = false;
     foreach (const QString &category, d->categories)
     {
@@ -1034,7 +1295,7 @@ QModelIndex KCategorizedView::moveCursor(CursorAction cursorAction,
             break;
         }
 
-        if (category == d->elementsInfo[d->proxyModel->mapToSource(current)].category)
+        if (category == d->elementsInfo[current.row()].category)
         {
             theCategory = category;
 
@@ -1050,17 +1311,17 @@ QModelIndex KCategorizedView::moveCursor(CursorAction cursorAction,
     switch (cursorAction)
     {
         case QAbstractItemView::MoveUp: {
-            if (d->elementsInfo[d->proxyModel->mapToSource(current)].relativeOffsetToCategory >= elementsPerRow)
+            if (d->elementsInfo[current.row()].relativeOffsetToCategory >= elementsPerRow)
             {
-                int indexToMove = d->invertedElementDictionary[current].row();
-                indexToMove -= qMin(((d->elementsInfo[d->proxyModel->mapToSource(current)].relativeOffsetToCategory) + d->forcedSelectionPosition), elementsPerRow - d->forcedSelectionPosition + (d->elementsInfo[d->proxyModel->mapToSource(current)].relativeOffsetToCategory % elementsPerRow));
+                int indexToMove = current.row();
+                indexToMove -= qMin(((d->elementsInfo[current.row()].relativeOffsetToCategory) + d->forcedSelectionPosition), elementsPerRow - d->forcedSelectionPosition + (d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow));
 
-                return d->elementDictionary[d->proxyModel->index(indexToMove, 0)];
+                return d->proxyModel->index(indexToMove, 0);
             }
             else
             {
                 int lastCategoryLastRow = (d->categoriesIndexes[lastCategory].count() - 1) % elementsPerRow;
-                int indexToMove = d->invertedElementDictionary[current].row() - d->elementsInfo[d->proxyModel->mapToSource(current)].relativeOffsetToCategory;
+                int indexToMove = current.row() - d->elementsInfo[current.row()].relativeOffsetToCategory;
 
                 if (d->forcedSelectionPosition >= lastCategoryLastRow)
                 {
@@ -1071,22 +1332,22 @@ QModelIndex KCategorizedView::moveCursor(CursorAction cursorAction,
                     indexToMove -= qMin((lastCategoryLastRow - d->forcedSelectionPosition + 1), d->forcedSelectionPosition + elementsPerRow + 1);
                 }
 
-                return d->elementDictionary[d->proxyModel->index(indexToMove, 0)];
+                return d->proxyModel->index(indexToMove, 0);
             }
         }
 
         case QAbstractItemView::MoveDown: {
-            if (d->elementsInfo[d->proxyModel->mapToSource(current)].relativeOffsetToCategory < (d->categoriesIndexes[theCategory].count() - 1 - ((d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow)))
+            if (d->elementsInfo[current.row()].relativeOffsetToCategory < (d->categoriesIndexes[theCategory].count() - 1 - ((d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow)))
             {
-                int indexToMove = d->invertedElementDictionary[current].row();
-                indexToMove += qMin(elementsPerRow, d->categoriesIndexes[theCategory].count() - 1 - d->elementsInfo[d->proxyModel->mapToSource(current)].relativeOffsetToCategory);
+                int indexToMove = current.row();
+                indexToMove += qMin(elementsPerRow, d->categoriesIndexes[theCategory].count() - 1 - d->elementsInfo[current.row()].relativeOffsetToCategory);
 
-                return d->elementDictionary[d->proxyModel->index(indexToMove, 0)];
+                return d->proxyModel->index(indexToMove, 0);
             }
             else
             {
                 int afterCategoryLastRow = qMin(elementsPerRow, d->categoriesIndexes[afterCategory].count());
-                int indexToMove = d->invertedElementDictionary[current].row() + (d->categoriesIndexes[theCategory].count() - d->elementsInfo[d->proxyModel->mapToSource(current)].relativeOffsetToCategory);
+                int indexToMove = current.row() + (d->categoriesIndexes[theCategory].count() - d->elementsInfo[current.row()].relativeOffsetToCategory);
 
                 if (d->forcedSelectionPosition >= afterCategoryLastRow)
                 {
@@ -1097,25 +1358,65 @@ QModelIndex KCategorizedView::moveCursor(CursorAction cursorAction,
                     indexToMove += qMin(d->forcedSelectionPosition, elementsPerRow);
                 }
 
-                return d->elementDictionary[d->proxyModel->index(indexToMove, 0)];
+                return d->proxyModel->index(indexToMove, 0);
             }
         }
 
         case QAbstractItemView::MoveLeft:
-            d->forcedSelectionPosition = d->elementsInfo[d->proxyModel->mapToSource(d->elementDictionary[d->proxyModel->index(d->invertedElementDictionary[current].row() - 1, 0)])].relativeOffsetToCategory % elementsPerRow;
+            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->elementDictionary[d->proxyModel->index(d->invertedElementDictionary[current].row() - 1, 0)];
+            return d->proxyModel->index(current.row() - 1, 0);
 
         case QAbstractItemView::MoveRight:
-            d->forcedSelectionPosition = d->elementsInfo[d->proxyModel->mapToSource(d->elementDictionary[d->proxyModel->index(d->invertedElementDictionary[current].row() + 1, 0)])].relativeOffsetToCategory % elementsPerRow;
+            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->elementDictionary[d->proxyModel->index(d->invertedElementDictionary[current].row() + 1, 0)];
+            return d->proxyModel->index(current.row() + 1, 0);
 
         default:
             break;
@@ -1125,29 +1426,26 @@ QModelIndex KCategorizedView::moveCursor(CursorAction cursorAction,
 }
 
 void KCategorizedView::rowsInserted(const QModelIndex &parent,
-                             int start,
-                             int end)
+                                    int start,
+                                    int end)
 {
     QListView::rowsInserted(parent, start, end);
 
     if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
-        !d->itemCategorizer)
+        !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
     {
-        d->lastSelection = QItemSelection();
-        d->currentViewIndex = QModelIndex();
         d->forcedSelectionPosition = 0;
         d->elementsInfo.clear();
         d->elementsPosition.clear();
-        d->elementDictionary.clear();
-        d->invertedElementDictionary.clear();
         d->categoriesIndexes.clear();
         d->categoriesPosition.clear();
         d->categories.clear();
         d->intersectedIndexes.clear();
-        d->sourceModelIndexList.clear();
+        d->modelIndexList.clear();
         d->hovered = QModelIndex();
         d->biggestItemSize = QSize(0, 0);
         d->mouseButtonPressed = false;
+        d->rightMouseButtonPressed = false;
 
         return;
     }
@@ -1156,139 +1454,97 @@ void KCategorizedView::rowsInserted(const QModelIndex &parent,
 }
 
 void KCategorizedView::rowsInsertedArtifficial(const QModelIndex &parent,
-                                        int start,
-                                        int end)
+                                               int start,
+                                               int end)
 {
     Q_UNUSED(parent);
 
-    d->lastSelection = QItemSelection();
-    d->currentViewIndex = QModelIndex();
     d->forcedSelectionPosition = 0;
     d->elementsInfo.clear();
     d->elementsPosition.clear();
-    d->elementDictionary.clear();
-    d->invertedElementDictionary.clear();
     d->categoriesIndexes.clear();
     d->categoriesPosition.clear();
     d->categories.clear();
     d->intersectedIndexes.clear();
-    d->sourceModelIndexList.clear();
+    d->modelIndexList.clear();
     d->hovered = QModelIndex();
     d->biggestItemSize = QSize(0, 0);
     d->mouseButtonPressed = false;
+    d->rightMouseButtonPressed = false;
 
     if (start > end || end < 0 || start < 0 || !d->proxyModel->rowCount())
     {
         return;
     }
 
-    // Add all elements mapped to the source model
-    for (int k = 0; k < d->proxyModel->rowCount(); k++)
+    // Add all elements mapped to the source model and explore categories
+    QString prevCategory = d->proxyModel->data(d->proxyModel->index(0, d->proxyModel->sortColumn()), KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
+    QString lastCategory = prevCategory;
+    QModelIndexList modelIndexList;
+    struct Private::ElementInfo elementInfo;
+    int offset = -1;
+    for (int k = 0; k < d->proxyModel->rowCount(); ++k)
     {
-        d->biggestItemSize = QSize(qMax(sizeHintForIndex(d->proxyModel->index(k, 0)).width(),
+        QModelIndex index = d->proxyModel->index(k, d->proxyModel->sortColumn());
+        QModelIndex indexSize = d->proxyModel->index(k, 0);
+
+        d->biggestItemSize = QSize(qMax(sizeHintForIndex(indexSize).width(),
                                         d->biggestItemSize.width()),
-                                   qMax(sizeHintForIndex(d->proxyModel->index(k, 0)).height(),
+                                   qMax(sizeHintForIndex(indexSize).height(),
                                         d->biggestItemSize.height()));
 
-        d->sourceModelIndexList <<
-                         d->proxyModel->mapToSource(d->proxyModel->index(k, 0));
-    }
-
-    // Sort them with the general purpose lessThan method
-    LessThan generalLessThan(d->proxyModel,
-                             LessThan::GeneralPurpose);
-
-    qStableSort(d->sourceModelIndexList.begin(), d->sourceModelIndexList.end(),
-                generalLessThan);
+        d->modelIndexList << index;
 
-    // Explore categories
-    QString prevCategory =
-                 d->itemCategorizer->categoryForItem(d->sourceModelIndexList[0],
-                                                     d->proxyModel->sortRole());
-    QString lastCategory = prevCategory;
-    QModelIndexList modelIndexList;
-    struct Private::ElementInfo elementInfo;
-    foreach (const QModelIndex &index, d->sourceModelIndexList)
-    {
-        lastCategory = d->itemCategorizer->categoryForItem(index,
-                                                     d->proxyModel->sortRole());
+        lastCategory = d->proxyModel->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
 
         elementInfo.category = lastCategory;
 
         if (prevCategory != lastCategory)
         {
+            offset = 0;
             d->categoriesIndexes.insert(prevCategory, modelIndexList);
             d->categories << prevCategory;
             modelIndexList.clear();
         }
+        else
+        {
+            offset++;
+        }
+
+        elementInfo.relativeOffsetToCategory = offset;
 
         modelIndexList << index;
         prevCategory = lastCategory;
 
-        d->elementsInfo.insert(index, elementInfo);
+        d->elementsInfo.insert(index.row(), elementInfo);
     }
 
     d->categoriesIndexes.insert(prevCategory, modelIndexList);
     d->categories << prevCategory;
 
-    // Sort items locally in their respective categories with the category
-    // purpose lessThan
-    LessThan categoryLessThan(d->proxyModel,
-                              LessThan::CategoryPurpose);
-
-    foreach (const QString &key, d->categories)
-    {
-        QModelIndexList &indexList = d->categoriesIndexes[key];
-
-        qStableSort(indexList.begin(), indexList.end(), categoryLessThan);
-    }
-
-    d->lastIndex = d->categoriesIndexes[d->categories[d->categories.count() - 1]][d->categoriesIndexes[d->categories[d->categories.count() - 1]].count() - 1];
-
-    // Finally, fill data information of items situation. This will help when
-    // trying to compute an item place in the viewport
-    int i = 0; // position relative to the category beginning
-    int j = 0; // number of elements before current
-    foreach (const QString &key, d->categories)
-    {
-        foreach (const QModelIndex &index, d->categoriesIndexes[key])
-        {
-            struct Private::ElementInfo &elementInfo = d->elementsInfo[index];
-
-            elementInfo.relativeOffsetToCategory = i;
-
-            d->elementDictionary.insert(d->proxyModel->index(j, 0),
-                                        d->proxyModel->mapFromSource(index));
-
-            d->invertedElementDictionary.insert(d->proxyModel->mapFromSource(index),
-                                                d->proxyModel->index(j, 0));
-
-            i++;
-            j++;
-        }
-
-        i = 0;
-    }
-
     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,
-                            int start,
-                            int end)
+                                   int start,
+                                   int end)
 {
     if ((viewMode() == KCategorizedView::IconMode) && d->proxyModel &&
-        d->itemCategorizer)
+        d->categoryDrawer && d->proxyModel->isCategorizedModel())
     {
         // Force the view to update all elements
-        rowsInsertedArtifficial(parent, start, end);
+        rowsInsertedArtifficial(QModelIndex(), 0, d->proxyModel->rowCount() - 1);
     }
 }
 
 void KCategorizedView::updateGeometries()
 {
     if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
-        !d->itemCategorizer)
+        !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
     {
         QListView::updateGeometries();
         return;
@@ -1299,14 +1555,42 @@ void KCategorizedView::updateGeometries()
     QAbstractItemView::updateGeometries();
 }
 
-void KCategorizedView::slotSortingRoleChanged()
+void KCategorizedView::slotLayoutChanged()
 {
-    if ((viewMode() == KCategorizedView::IconMode) && d->proxyModel &&
-        d->itemCategorizer)
+    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())
     {
-        // Force the view to update all elements
-        rowsInsertedArtifficial(QModelIndex(), 0, d->proxyModel->rowCount() - 1);
+        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"