]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Added Rafael López's item categorizer into Dolphin (it's currently deactivated in...
authorPeter Penz <peter.penz19@gmail.com>
Tue, 10 Apr 2007 08:46:21 +0000 (08:46 +0000)
committerPeter Penz <peter.penz19@gmail.com>
Tue, 10 Apr 2007 08:46:21 +0000 (08:46 +0000)
svn path=/trunk/KDE/kdebase/apps/; revision=652156

src/CMakeLists.txt
src/dolphiniconsview.cpp
src/dolphiniconsview.h
src/dolphinitemcategorizer.cpp [new file with mode: 0644]
src/dolphinitemcategorizer.h [new file with mode: 0644]
src/kitemcategorizer.h [new file with mode: 0644]
src/klistview.cpp [new file with mode: 0644]
src/klistview.h [new file with mode: 0644]
src/klistview_p.h [new file with mode: 0644]

index c94968e11f9e951879d6002b5460cb8f038d0ede..2d855532c594313a9136febaec3fb79d91d18be0 100644 (file)
@@ -9,20 +9,22 @@ add_definitions (-DQT3_SUPPORT)
 ########### next target ###############
 
 set(dolphinprivate_LIB_SRCS
-       dolphincontroller.cpp
-       dolphindetailsview.cpp
-       dolphiniconsview.cpp
-       dolphinsettings.cpp
-       viewproperties.cpp
-       dolphinsortfilterproxymodel.cpp
-       )
+    dolphincontroller.cpp
+    dolphindetailsview.cpp
+    dolphiniconsview.cpp
+    dolphinitemcategorizer.cpp
+    klistview.cpp
+    dolphinsettings.cpp
+    viewproperties.cpp
+    dolphinsortfilterproxymodel.cpp
+    )
 
 kde4_add_kcfg_files(dolphinprivate_LIB_SRCS
-   dolphin_columnmodesettings.kcfgc
-   dolphin_directoryviewpropertysettings.kcfgc
-   dolphin_detailsmodesettings.kcfgc
-   dolphin_iconsmodesettings.kcfgc
-   dolphin_generalsettings.kcfgc)
+    dolphin_columnmodesettings.kcfgc
+    dolphin_directoryviewpropertysettings.kcfgc
+    dolphin_detailsmodesettings.kcfgc
+    dolphin_iconsmodesettings.kcfgc
+    dolphin_generalsettings.kcfgc)
 
 
 kde4_automoc(${dolphinprivate_LIB_SRCS})
@@ -101,5 +103,9 @@ install(TARGETS dolphin DESTINATION ${BIN_INSTALL_DIR})
 install( FILES  dolphin.desktop DESTINATION ${XDG_APPS_DIR} )
 install( FILES  dolphin_directoryviewpropertysettings.kcfg dolphin_generalsettings.kcfg dolphin_columnmodesettings.kcfg dolphin_iconsmodesettings.kcfg dolphin_detailsmodesettings.kcfg DESTINATION ${KCFG_INSTALL_DIR} )
 install( FILES  dolphinui.rc DESTINATION ${DATA_INSTALL_DIR}/dolphin )
+install( FILES
+    klistview.h
+    kitemcategorizer.h
+    DESTINATION ${INCLUDE_INSTALL_DIR})
 
 kde4_install_icons( ${ICON_INSTALL_DIR} )
index 63989a30dcf4485a8596ed82767711aad9e465be..de66613bec9894afdf8c4fca99dbd89eb7a2d94d 100644 (file)
 
 #include "dolphiniconsview.h"
 
+#include "dolphinitemcategorizer.h"
 #include "dolphincontroller.h"
 #include "dolphinsettings.h"
+#include "dolphinitemcategorizer.h"
 
 #include "dolphin_iconsmodesettings.h"
 
@@ -32,8 +34,9 @@
 #include <QPoint>
 
 DolphinIconsView::DolphinIconsView(QWidget* parent, DolphinController* controller) :
-        QListView(parent),
-        m_controller(controller)
+        KListView(parent),
+        m_controller(controller),
+        m_itemCategorizer(0)
 {
     Q_ASSERT(controller != 0);
     setViewMode(QListView::IconMode);
@@ -56,7 +59,7 @@ DolphinIconsView::DolphinIconsView(QWidget* parent, DolphinController* controlle
     const IconsModeSettings* settings = DolphinSettings::instance().iconsModeSettings();
     Q_ASSERT(settings != 0);
 
-    m_viewOptions = QListView::viewOptions();
+    m_viewOptions = KListView::viewOptions();
 
     QFont font(settings->fontFamily(), settings->fontSize());
     font.setItalic(settings->italicFont());
@@ -72,10 +75,17 @@ DolphinIconsView::DolphinIconsView(QWidget* parent, DolphinController* controlle
         setFlow(QListView::TopToBottom);
         m_viewOptions.decorationPosition = QStyleOptionViewItem::Left;
     }
+
+    m_itemCategorizer = new DolphinItemCategorizer();
+    // setItemCategorizer(m_itemCategorizer);
 }
 
 DolphinIconsView::~DolphinIconsView()
-{}
+{
+    setItemCategorizer(0);
+    delete m_itemCategorizer;
+    m_itemCategorizer = 0;
+}
 
 QStyleOptionViewItem DolphinIconsView::viewOptions() const
 {
@@ -84,13 +94,13 @@ QStyleOptionViewItem DolphinIconsView::viewOptions() const
 
 void DolphinIconsView::contextMenuEvent(QContextMenuEvent* event)
 {
-    QListView::contextMenuEvent(event);
+    KListView::contextMenuEvent(event);
     m_controller->triggerContextMenuRequest(event->pos());
 }
 
 void DolphinIconsView::mouseReleaseEvent(QMouseEvent* event)
 {
-    QListView::mouseReleaseEvent(event);
+    KListView::mouseReleaseEvent(event);
     m_controller->triggerActivation();
 }
 
@@ -110,7 +120,7 @@ void DolphinIconsView::dropEvent(QDropEvent* event)
                                           event->source());
         event->acceptProposedAction();
     }
-    QListView::dropEvent(event);
+    KListView::dropEvent(event);
 }
 
 void DolphinIconsView::updateGridSize(bool showPreview)
index 45206053400042b25c66bff2521cf24e154db307..f0d0abc1a6acac47a2d6350032ad098fd8e64bbb 100644 (file)
 #ifndef DOLPHINICONSVIEW_H
 #define DOLPHINICONSVIEW_H
 
-#include <QListView>
+#include <klistview.h>
+#include <kitemcategorizer.h>
 #include <QStyleOptionViewItem>
 #include <libdolphin_export.h>
 
 class DolphinController;
+class DolphinItemCategorizer;
 class DolphinView;
 
 /**
@@ -33,7 +35,7 @@ class DolphinView;
  * It is also possible that instead of the icon a preview of the item
  * content is shown.
  */
-class LIBDOLPHINPRIVATE_EXPORT DolphinIconsView : public QListView
+class LIBDOLPHINPRIVATE_EXPORT DolphinIconsView : public KListView
 {
     Q_OBJECT
 
@@ -71,6 +73,7 @@ private:
 private:
     DolphinController* m_controller;
     QStyleOptionViewItem m_viewOptions;
+    DolphinItemCategorizer* m_itemCategorizer;
 };
 
 #endif
diff --git a/src/dolphinitemcategorizer.cpp b/src/dolphinitemcategorizer.cpp
new file mode 100644 (file)
index 0000000..d599aad
--- /dev/null
@@ -0,0 +1,79 @@
+/**
+  * This file is part of the KDE project
+  * Copyright (C) 2007 Rafael Fernández López <ereslibre@gmail.com>
+  *
+  * This library is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Library General Public
+  * License as published by the Free Software Foundation; either
+  * version 2 of the License, or (at your option) any later version.
+  *
+  * This library is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * Library General Public License for more details.
+  *
+  * You should have received a copy of the GNU Library General Public License
+  * along with this library; see the file COPYING.LIB.  If not, write to
+  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  * Boston, MA 02110-1301, USA.
+  */
+
+#include "dolphinitemcategorizer.h"
+
+#include "dolphinview.h"
+
+#include <klocale.h>
+#include <kdirmodel.h>
+
+#include <QSortFilterProxyModel>
+
+DolphinItemCategorizer::DolphinItemCategorizer() :
+        KItemCategorizer()
+{}
+
+DolphinItemCategorizer::~DolphinItemCategorizer()
+{}
+
+QString DolphinItemCategorizer::categoryForItem(const QModelIndex& index,
+                                                int sortRole)
+{
+    QString retString;
+
+    if (!index.isValid()) {
+        return retString;
+    }
+
+    // KDirModel checks columns to know to which role are
+    // we talking about
+    QModelIndex theIndex = index.model()->index(index.row(),
+                           sortRole,
+                           index.parent());
+
+    const QSortFilterProxyModel* proxyModel = static_cast<const QSortFilterProxyModel*>(index.model());
+    const KDirModel* dirModel = static_cast<const KDirModel*>(proxyModel->sourceModel());
+
+    QVariant data = theIndex.model()->data(theIndex, Qt::DisplayRole);
+
+    QModelIndex mappedIndex = proxyModel->mapToSource(theIndex);
+    KFileItem* item = dirModel->itemForIndex(mappedIndex);
+
+    switch (sortRole) {
+    case DolphinView::SortByName:
+        retString = data.toString().toUpper().at(0);
+        break;
+    case DolphinView::SortBySize:
+        int fileSize = (item) ? item->size() : -1;
+        if (item && item->isDir()) {
+            retString = i18n("Unknown");
+        } else if (fileSize < 5242880) {
+            retString = i18n("Small");
+        } else if (fileSize < 10485760) {
+            retString = i18n("Medium");
+        } else {
+            retString = i18n("Big");
+        }
+        break;
+    }
+
+    return retString;
+}
diff --git a/src/dolphinitemcategorizer.h b/src/dolphinitemcategorizer.h
new file mode 100644 (file)
index 0000000..6be060b
--- /dev/null
@@ -0,0 +1,37 @@
+/**
+  * This file is part of the KDE project
+  * Copyright (C) 2007 Rafael Fernández López <ereslibre@gmail.com>
+  *
+  * This library is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Library General Public
+  * License as published by the Free Software Foundation; either
+  * version 2 of the License, or (at your option) any later version.
+  *
+  * This library is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * Library General Public License for more details.
+  *
+  * You should have received a copy of the GNU Library General Public License
+  * along with this library; see the file COPYING.LIB.  If not, write to
+  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  * Boston, MA 02110-1301, USA.
+  */
+
+#ifndef DOLPHINITEMCATEGORIZER_H
+#define DOLPHINITEMCATEGORIZER_H
+
+#include <libdolphin_export.h>
+#include <kitemcategorizer.h>
+
+class QModelIndex;
+
+class LIBDOLPHINPRIVATE_EXPORT DolphinItemCategorizer : public KItemCategorizer
+{
+public:
+    DolphinItemCategorizer();
+    virtual ~DolphinItemCategorizer();
+    virtual QString categoryForItem(const QModelIndex &index, int sortRole);
+};
+
+#endif // DOLPHINITEMCATEGORIZER_H
diff --git a/src/kitemcategorizer.h b/src/kitemcategorizer.h
new file mode 100644 (file)
index 0000000..782f625
--- /dev/null
@@ -0,0 +1,43 @@
+/**
+  * This file is part of the KDE project
+  * Copyright (C) 2007 Rafael Fernández López <ereslibre@gmail.com>
+  *
+  * This library is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Library General Public
+  * License as published by the Free Software Foundation; either
+  * version 2 of the License, or (at your option) any later version.
+  *
+  * This library is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * Library General Public License for more details.
+  *
+  * You should have received a copy of the GNU Library General Public License
+  * along with this library; see the file COPYING.LIB.  If not, write to
+  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  * Boston, MA 02110-1301, USA.
+  */
+
+#ifndef __KITEMCATEGORIZER_H__
+#define __KITEMCATEGORIZER_H__
+
+#include <kdeui_export.h>
+
+class QString;
+class QModelIndex;
+
+class KDEUI_EXPORT KItemCategorizer
+{
+public:
+    KItemCategorizer()
+    {
+    }
+
+    virtual ~KItemCategorizer()
+    {
+    }
+
+    virtual QString categoryForItem(const QModelIndex &index, int sortRole) = 0;
+};
+
+#endif
diff --git a/src/klistview.cpp b/src/klistview.cpp
new file mode 100644 (file)
index 0000000..a7244df
--- /dev/null
@@ -0,0 +1,449 @@
+/**
+  * This file is part of the KDE project
+  * Copyright (C) 2007 Rafael Fernández López <ereslibre@gmail.com>
+  *
+  * This library is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Library General Public
+  * License as published by the Free Software Foundation; either
+  * version 2 of the License, or (at your option) any later version.
+  *
+  * This library is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * Library General Public License for more details.
+  *
+  * You should have received a copy of the GNU Library General Public License
+  * along with this library; see the file COPYING.LIB.  If not, write to
+  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  * Boston, MA 02110-1301, USA.
+  */
+
+// NOTE: rectForIndex() not virtual on QListView !! relevant ?
+
+#include <QPainter>
+#include <QScrollBar>
+#include <QPaintEvent>
+#include <QSortFilterProxyModel>
+
+#include <kdebug.h>
+
+#include "klistview.h"
+#include "klistview_p.h"
+#include "kitemcategorizer.h"
+
+KListView::Private::Private(KListView *listView)
+    : listView(listView)
+    , modelSortCapable(false)
+    , itemCategorizer(0)
+    , numCategories(0)
+    , proxyModel(0)
+{
+}
+
+KListView::Private::~Private()
+{
+}
+
+QModelIndexList KListView::Private::intersectionSet(const QRect &rect) const
+{
+    // FIXME: boost me, I suck (ereslibre)
+
+    QModelIndexList modelIndexList;
+
+    QModelIndex index;
+    for (int i = 0; i < listView->model()->rowCount(); i++)
+    {
+        index = listView->model()->index(i, 0);
+
+        if (rect.intersects(listView->visualRect(index)))
+            modelIndexList.append(index);
+    }
+
+    return modelIndexList;
+}
+
+KListView::KListView(QWidget *parent)
+    : QListView(parent)
+    , d(new Private(this))
+{
+}
+
+KListView::~KListView()
+{
+    if (d->proxyModel)
+    {
+        QObject::disconnect(this->model(), SIGNAL(layoutChanged()),
+                            this         , SLOT(itemsLayoutChanged()));
+    }
+
+    delete d;
+}
+
+void KListView::setModel(QAbstractItemModel *model)
+{
+    QSortFilterProxyModel *proxyModel =
+                                    qobject_cast<QSortFilterProxyModel*>(model);
+
+    if (this->model() && this->model()->rowCount())
+    {
+        QObject::disconnect(this->model(), SIGNAL(layoutChanged()),
+                            this         , SLOT(itemsLayoutChanged()));
+
+        rowsAboutToBeRemovedArtifficial(QModelIndex(), 0,
+                                        this->model()->rowCount() - 1);
+    }
+
+    d->modelSortCapable = (proxyModel != 0);
+    d->proxyModel = proxyModel;
+
+    // If the model was initialized before applying to the view, we update
+    // internal data structure of the view with the model information
+    if (model->rowCount())
+    {
+        rowsInsertedArtifficial(QModelIndex(), 0, model->rowCount() - 1);
+    }
+
+    QListView::setModel(model);
+
+    QObject::connect(model, SIGNAL(layoutChanged()),
+                     this , SLOT(itemsLayoutChanged()));
+}
+
+QRect KListView::visualRect(const QModelIndex &index) const
+{
+    // FIXME: right to left languages (ereslibre)
+    // FIXME: drag & drop support (ereslibre)
+    // FIXME: do not forget to remove itemWidth's hard-coded values that were
+    //        only for testing purposes. We might like to calculate the best
+    //        width, but what we would really like for sure is that all items
+    //        have the same width, as well as the same height (ereslibre)
+
+    if ((viewMode() == KListView::ListMode) || !d->modelSortCapable ||
+        !d->itemCategorizer)
+    {
+        return QListView::visualRect(index);
+    }
+
+    QRect retRect(spacing(), spacing(), 0, 0);
+    int viewportWidth = viewport()->width() - spacing();
+    int dx = -horizontalOffset();
+    int dy = -verticalOffset();
+
+    if (verticalScrollBar() && !verticalScrollBar()->isHidden())
+        viewportWidth -= verticalScrollBar()->width();
+
+    int itemHeight = sizeHintForIndex(index).height();
+    int itemWidth = 130; // NOTE: ghosts in here !
+    int itemWidthPlusSeparation = spacing() + itemWidth;
+    int elementsPerRow = viewportWidth / itemWidthPlusSeparation;
+    if (!elementsPerRow)
+        elementsPerRow++;
+    QModelIndex currentIndex = d->proxyModel->index(index.row(), 0);
+    QString itemCategory = d->itemCategorizer->categoryForItem(currentIndex,
+                                                     d->proxyModel->sortRole());
+    int naturalRow = index.row() / elementsPerRow;
+    int naturalTop = naturalRow * itemHeight + naturalRow * spacing();
+
+    int rowsForCategory;
+    int lastIndexShown = -1;
+    foreach (QString category, d->categories)
+    {
+        retRect.setTop(retRect.top() + spacing());
+
+        if (category == itemCategory)
+        {
+            break;
+        }
+
+        rowsForCategory = (d->elementsPerCategory[category] / elementsPerRow);
+
+        if ((d->elementsPerCategory[category] % elementsPerRow) ||
+            !rowsForCategory)
+        {
+            rowsForCategory++;
+        }
+
+        lastIndexShown += d->elementsPerCategory[category];
+
+        retRect.setTop(retRect.top() + categoryHeight(viewOptions()) +
+                       (rowsForCategory * spacing() * 2) +
+                       (rowsForCategory * itemHeight));
+    }
+
+    int rowToPosition = (index.row() - (lastIndexShown + 1)) / elementsPerRow;
+    int columnToPosition = (index.row() - (lastIndexShown + 1)) %
+                                                                 elementsPerRow;
+
+    retRect.setTop(retRect.top() + (rowToPosition * spacing() * 2) +
+                   (rowToPosition * itemHeight));
+
+    retRect.setLeft(retRect.left() + (columnToPosition * spacing()) +
+                    (columnToPosition * itemWidth));
+
+    retRect.setWidth(130); // NOTE: ghosts in here !
+    retRect.setHeight(itemHeight);
+
+    retRect.adjust(dx, dy, dx, dy);
+
+    return retRect;
+}
+
+KItemCategorizer *KListView::itemCategorizer() const
+{
+    return d->itemCategorizer;
+}
+
+void KListView::setItemCategorizer(KItemCategorizer *itemCategorizer)
+{
+    d->itemCategorizer = itemCategorizer;
+
+    if (itemCategorizer)
+        itemsLayoutChanged();
+}
+
+QModelIndex KListView::indexAt(const QPoint &point) const
+{
+    QModelIndex index;
+
+    if ((viewMode() == KListView::ListMode) || !d->modelSortCapable ||
+        !d->itemCategorizer)
+    {
+        return QListView::indexAt(point);
+    }
+
+    QModelIndexList item = d->intersectionSet(QRect(point, point));
+
+    if (item.count() == 1)
+        index = item[0];
+
+    d->hovered = index;
+
+    return index;
+}
+
+int KListView::sizeHintForRow(int row) const
+{
+    if ((viewMode() == KListView::ListMode) || !d->modelSortCapable ||
+        !d->itemCategorizer)
+    {
+        return QListView::sizeHintForRow(row);
+    }
+
+    QModelIndex index = d->proxyModel->index(0, 0);
+
+    if (!index.isValid())
+        return 0;
+
+    return sizeHintForIndex(index).height() + categoryHeight(viewOptions()) +
+           spacing();
+}
+
+void KListView::drawNewCategory(const QString &category,
+                                const QStyleOptionViewItem &option,
+                                QPainter *painter)
+{
+    painter->drawText(option.rect.topLeft(), category);
+}
+
+int KListView::categoryHeight(const QStyleOptionViewItem &option) const
+{
+    return option.fontMetrics.height();
+}
+
+void KListView::paintEvent(QPaintEvent *event)
+{
+    if ((viewMode() == KListView::ListMode) || !d->modelSortCapable ||
+        !d->itemCategorizer)
+    {
+        QListView::paintEvent(event);
+        return;
+    }
+
+    if (!itemDelegate())
+        return;
+
+    QStyleOptionViewItemV3 option = viewOptions();
+    QPainter painter(viewport());
+    QRect area = event->rect();
+    const bool focus = (hasFocus() || viewport()->hasFocus()) &&
+                        currentIndex().isValid();
+    const QStyle::State state = option.state;
+    const bool enabled = (state & QStyle::State_Enabled) != 0;
+
+    int totalHeight = 0;
+    QModelIndex index;
+    QString prevCategory;
+    QModelIndexList dirtyIndexes = d->intersectionSet(area);
+    foreach (const QModelIndex &index, dirtyIndexes)
+    {
+        option.state = state;
+        option.rect = visualRect(index);
+        if (selectionModel() && selectionModel()->isSelected(index))
+            option.state |= QStyle::State_Selected;
+        if (enabled)
+        {
+            QPalette::ColorGroup cg;
+            if ((d->proxyModel->flags(index) & Qt::ItemIsEnabled) == 0)
+            {
+                option.state &= ~QStyle::State_Enabled;
+                cg = QPalette::Disabled;
+            }
+            else
+            {
+                cg = QPalette::Normal;
+            }
+            option.palette.setCurrentColorGroup(cg);
+        }
+        if (focus && currentIndex() == index)
+        {
+            option.state |= QStyle::State_HasFocus;
+            if (this->state() == EditingState)
+                option.state |= QStyle::State_Editing;
+        }
+
+        if (index == d->hovered)
+            option.state |= QStyle::State_MouseOver;
+        else
+            option.state &= ~QStyle::State_MouseOver;
+
+        if (prevCategory != d->itemCategorizer->categoryForItem(index,
+                                                     d->proxyModel->sortRole()))
+        {
+            prevCategory = d->itemCategorizer->categoryForItem(index,
+                                                     d->proxyModel->sortRole());
+            drawNewCategory(prevCategory, option, &painter);
+        }
+        itemDelegate(index)->paint(&painter, option, index);
+    }
+}
+
+void KListView::setSelection(const QRect &rect,
+                             QItemSelectionModel::SelectionFlags flags)
+{
+    // TODO: implement me
+
+    QListView::setSelection(rect, flags);
+
+    /*if ((viewMode() == KListView::ListMode) || !d->modelSortCapable ||
+        !d->itemCategorizer)
+    {
+        QListView::setSelection(rect, flags);
+        return;
+    }
+
+    QModelIndex index;
+    for (int i = 0; i < d->proxyModel->rowCount(); i++)
+    {
+        index = d->proxyModel->index(i, 0);
+        if (rect.intersects(visualRect(index)))
+        {
+            selectionModel()->select(index, QItemSelectionModel::Select);
+        }
+        else
+        {
+            selectionModel()->select(index, QItemSelectionModel::Deselect);
+        }
+    }*/
+
+    //selectionModel()->select(selection, flags);
+}
+
+void KListView::timerEvent(QTimerEvent *event)
+{
+    QListView::timerEvent(event);
+
+    if ((viewMode() == KListView::ListMode) || !d->modelSortCapable ||
+        !d->itemCategorizer)
+    {
+        return;
+    }
+}
+
+void KListView::rowsInserted(const QModelIndex &parent,
+                             int start,
+                             int end)
+{
+    QListView::rowsInserted(parent, start, end);
+    rowsInsertedArtifficial(parent, start, end);
+}
+
+void KListView::rowsAboutToBeRemoved(const QModelIndex &parent,
+                                     int start,
+                                     int end)
+{
+    QListView::rowsAboutToBeRemoved(parent, start, end);
+    rowsAboutToBeRemovedArtifficial(parent, start, end);
+}
+
+void KListView::rowsInsertedArtifficial(const QModelIndex &parent,
+                                        int start,
+                                        int end)
+{
+    if ((viewMode() == KListView::ListMode) || !d->modelSortCapable ||
+        !d->itemCategorizer)
+    {
+        return;
+    }
+
+    QString category;
+    QModelIndex index;
+    for (int i = start; i <= end; i++)
+    {
+        index = d->proxyModel->index(i, 0, parent);
+        category = d->itemCategorizer->categoryForItem(index,
+                                                     d->proxyModel->sortRole());
+
+        if (d->elementsPerCategory.contains(category))
+            d->elementsPerCategory[category]++;
+        else
+        {
+            d->elementsPerCategory.insert(category, 1);
+            d->categories.append(category);
+        }
+    }
+}
+
+void KListView::rowsAboutToBeRemovedArtifficial(const QModelIndex &parent,
+                                                int start,
+                                                int end)
+{
+    if ((viewMode() == KListView::ListMode) || !d->modelSortCapable ||
+        !d->itemCategorizer)
+    {
+        return;
+    }
+
+    d->hovered = QModelIndex();
+
+    QString category;
+    QModelIndex index;
+    for (int i = start; i <= end; i++)
+    {
+        index = d->proxyModel->index(i, 0, parent);
+        category = d->itemCategorizer->categoryForItem(index,
+                                                     d->proxyModel->sortRole());
+
+        if (d->elementsPerCategory.contains(category))
+        {
+            d->elementsPerCategory[category]--;
+
+            if (!d->elementsPerCategory[category])
+            {
+                d->elementsPerCategory.remove(category);
+                d->categories.removeAll(category);
+            }
+        }
+    }
+}
+
+void KListView::itemsLayoutChanged()
+{
+    d->elementsPerCategory.clear();
+    d->categories.clear();
+
+    if (d->proxyModel && d->proxyModel->rowCount())
+        rowsInsertedArtifficial(QModelIndex(), 0,
+                                                 d->proxyModel->rowCount() - 1);
+}
+
+#include "klistview.moc"
diff --git a/src/klistview.h b/src/klistview.h
new file mode 100644 (file)
index 0000000..dd5ac47
--- /dev/null
@@ -0,0 +1,93 @@
+/**
+  * This file is part of the KDE project
+  * Copyright (C) 2007 Rafael Fernández López <ereslibre@gmail.com>
+  *
+  * This library is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Library General Public
+  * License as published by the Free Software Foundation; either
+  * version 2 of the License, or (at your option) any later version.
+  *
+  * This library is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * Library General Public License for more details.
+  *
+  * You should have received a copy of the GNU Library General Public License
+  * along with this library; see the file COPYING.LIB.  If not, write to
+  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  * Boston, MA 02110-1301, USA.
+  */
+
+#ifndef __KLISTVIEW_H__
+#define __KLISTVIEW_H__
+
+#include <QListView>
+
+#include <kdeui_export.h>
+
+class KItemCategorizer;
+
+class KDEUI_EXPORT KListView
+    : public QListView
+{
+    Q_OBJECT
+
+public:
+    KListView(QWidget *parent = 0);
+
+    ~KListView();
+
+    void setModel(QAbstractItemModel *model);
+
+    QRect visualRect(const QModelIndex &index) const;
+
+    KItemCategorizer *itemCategorizer() const;
+
+    void setItemCategorizer(KItemCategorizer *itemCategorizer);
+
+    virtual QModelIndex indexAt(const QPoint &point) const;
+
+    virtual int sizeHintForRow(int row) const;
+
+
+protected:
+    virtual void drawNewCategory(const QString &category,
+                                 const QStyleOptionViewItem &option,
+                                 QPainter *painter);
+
+    virtual int categoryHeight(const QStyleOptionViewItem &option) const;
+
+    virtual void paintEvent(QPaintEvent *event);
+
+    virtual void setSelection(const QRect &rect,
+                              QItemSelectionModel::SelectionFlags flags);
+
+    virtual void timerEvent(QTimerEvent *event);
+
+
+protected Q_SLOTS:
+    virtual void rowsInserted(const QModelIndex &parent,
+                              int start,
+                              int end);
+
+    virtual void rowsAboutToBeRemoved(const QModelIndex &parent,
+                                      int start,
+                                      int end);
+
+    virtual void rowsInsertedArtifficial(const QModelIndex &parent,
+                                         int start,
+                                         int end);
+
+    virtual void rowsAboutToBeRemovedArtifficial(const QModelIndex &parent,
+                                                 int start,
+                                                 int end);
+
+    virtual void itemsLayoutChanged();
+
+
+private:
+    class Private;
+    Private *d;
+};
+
+#endif // __KLISTVIEW_H__
diff --git a/src/klistview_p.h b/src/klistview_p.h
new file mode 100644 (file)
index 0000000..629cefb
--- /dev/null
@@ -0,0 +1,42 @@
+/**
+  * This file is part of the KDE project
+  * Copyright (C) 2007 Rafael Fernández López <ereslibre@gmail.com>
+  *
+  * This library is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Library General Public
+  * License as published by the Free Software Foundation; either
+  * version 2 of the License, or (at your option) any later version.
+  *
+  * This library is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * Library General Public License for more details.
+  *
+  * You should have received a copy of the GNU Library General Public License
+  * along with this library; see the file COPYING.LIB.  If not, write to
+  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  * Boston, MA 02110-1301, USA.
+  */
+
+#ifndef __KLISTVIEW_P_H__
+#define __KLISTVIEW_P_H__
+
+class KListView::Private
+{
+public:
+    Private(KListView *listView);
+    ~Private();
+
+    QModelIndexList intersectionSet(const QRect &rect) const;
+
+    KListView *listView;
+    QModelIndex hovered;
+    bool modelSortCapable;
+    int numCategories;
+    QList<QString> categories;
+    QHash<QString, int> elementsPerCategory;
+    KItemCategorizer *itemCategorizer;
+    QSortFilterProxyModel *proxyModel;
+};
+
+#endif // __KLISTVIEW_P_H__