diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/dolphiniconsview.cpp | 14 | ||||
| -rw-r--r-- | src/dolphinitemcategorizer.cpp | 187 | ||||
| -rw-r--r-- | src/dolphinitemcategorizer.h | 5 | ||||
| -rw-r--r-- | src/kitemcategorizer.cpp | 100 | ||||
| -rw-r--r-- | src/kitemcategorizer.h | 43 | ||||
| -rw-r--r-- | src/klistview.cpp | 352 | ||||
| -rw-r--r-- | src/klistview.h | 18 | ||||
| -rw-r--r-- | src/klistview_p.h | 11 | ||||
| -rw-r--r-- | src/ksortfilterproxymodel.h | 7 |
10 files changed, 593 insertions, 145 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9bc0665c2..6b3b5e9ee 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,6 +17,7 @@ set(dolphinprivate_LIB_SRCS dolphinitemcategorizer.cpp klistview.cpp ksortfilterproxymodel.cpp + kitemcategorizer.cpp dolphinsettings.cpp viewproperties.cpp dolphinsortfilterproxymodel.cpp diff --git a/src/dolphiniconsview.cpp b/src/dolphiniconsview.cpp index bac7b5e4b..968d7c94c 100644 --- a/src/dolphiniconsview.cpp +++ b/src/dolphiniconsview.cpp @@ -147,12 +147,14 @@ void DolphinIconsView::dragMoveEvent(QDragMoveEvent* event) void DolphinIconsView::dropEvent(QDropEvent* event) { - const KUrl::List urls = KUrl::List::fromMimeData(event->mimeData()); - if (!urls.isEmpty()) { - m_controller->indicateDroppedUrls(urls, - indexAt(event->pos()), - event->source()); - event->acceptProposedAction(); + if (!selectionModel()->isSelected(indexAt(event->pos()))) { + const KUrl::List urls = KUrl::List::fromMimeData(event->mimeData()); + if (!urls.isEmpty()) { + m_controller->indicateDroppedUrls(urls, + indexAt(event->pos()), + event->source()); + event->acceptProposedAction(); + } } KListView::dropEvent(event); m_dragging = false; diff --git a/src/dolphinitemcategorizer.cpp b/src/dolphinitemcategorizer.cpp index dfb384062..a4c84736a 100644 --- a/src/dolphinitemcategorizer.cpp +++ b/src/dolphinitemcategorizer.cpp @@ -32,11 +32,18 @@ #include <kdatetime.h> #include <kdirmodel.h> #include <kfileitem.h> +#include <kiconloader.h> #include <klocale.h> #include <kurl.h> +#include <kuser.h> +#include <kmimetype.h> +#include <kstandarddirs.h> +#include <kpixmapeffect.h> #include <QList> #include <QSortFilterProxyModel> +#include <QPainter> +#include <QDir> DolphinItemCategorizer::DolphinItemCategorizer() : KItemCategorizer() @@ -48,7 +55,7 @@ DolphinItemCategorizer::~DolphinItemCategorizer() } QString DolphinItemCategorizer::categoryForItem(const QModelIndex& index, - int sortRole) + int sortRole) const { QString retString; @@ -167,11 +174,8 @@ QString DolphinItemCategorizer::categoryForItem(const QModelIndex& index, #ifdef HAVE_NEPOMUK case DolphinView::SortByRating: { const quint32 rating = DolphinSortFilterProxyModel::ratingForIndex(index); - if (rating) { - retString = i18np("1 star", "%1 stars", rating); - } else { - retString = i18n("Not yet rated"); - } + + retString = QString::number(rating); break; } @@ -188,3 +192,174 @@ QString DolphinItemCategorizer::categoryForItem(const QModelIndex& index, return retString; } + +void DolphinItemCategorizer::drawCategory(const QModelIndex &index, + int sortRole, + const QStyleOption &option, + QPainter *painter) const +{ + QRect starRect = option.rect; + int iconSize = KIconLoader::global()->theme()->defaultSize(K3Icon::Small); + + const QString category = categoryForItem(index, sortRole); + + QColor color = option.palette.color(QPalette::Text); + + painter->save(); + painter->setRenderHint(QPainter::Antialiasing); + + QStyleOptionButton opt; + + opt.rect = option.rect; + opt.palette = option.palette; + opt.direction = option.direction; + opt.text = category; + + if (option.state & QStyle::State_MouseOver) + { + const QPalette::ColorGroup group = + option.state & QStyle::State_Enabled ? + QPalette::Normal : QPalette::Disabled; + + QLinearGradient gradient(option.rect.topLeft(), + option.rect.bottomRight()); + gradient.setColorAt(0, + option.palette.color(group, + QPalette::Highlight).light()); + gradient.setColorAt(1, Qt::transparent); + + painter->fillRect(option.rect, gradient); + } + + QFont painterFont = painter->font(); + painterFont.setWeight(QFont::Bold); + QFontMetrics metrics(painterFont); + painter->setFont(painterFont); + + QPainterPath path; + path.addRect(option.rect.left(), + option.rect.bottom() - 2, + option.rect.width(), + 2); + + QLinearGradient gradient(option.rect.topLeft(), + option.rect.bottomRight()); + gradient.setColorAt(0, color); + gradient.setColorAt(1, Qt::transparent); + + painter->setBrush(gradient); + painter->fillPath(path, gradient); + + opt.rect.setLeft(opt.rect.left() + (iconSize / 4)); + starRect.setLeft(starRect.left() + (iconSize / 4)); + starRect.setRight(starRect.right() + (iconSize / 4)); + + bool paintIcon = true; + bool paintText = true; + + QPixmap icon; + switch (sortRole) { + case DolphinView::SortByName: + paintIcon = false; + break; + + case DolphinView::SortByDate: + paintIcon = false; + break; + + case DolphinView::SortByPermissions: + paintIcon = false; // FIXME: let's think about how to represent permissions + break; + + case DolphinView::SortByOwner: { + opt.rect.setTop(option.rect.top() + (iconSize / 4)); + KUser user(category); + icon = QPixmap::fromImage(QImage(user.homeDir() + QDir::separator() + ".face.icon")).scaled(iconSize, iconSize); + break; + } + + case DolphinView::SortByGroup: + paintIcon = false; + break; + + case DolphinView::SortBySize: + paintIcon = false; + break; + + case DolphinView::SortByType: { + opt.rect.setTop(option.rect.top() + (option.rect.height() / 2) - (iconSize / 2)); + const KDirModel *model = static_cast<const KDirModel*>(index.model()); + KFileItem *item = model->itemForIndex(index); + icon = KIconLoader::global()->loadIcon(KMimeType::iconNameForUrl(item->url()), + K3Icon::Small); + break; + } + +#ifdef HAVE_NEPOMUK + case DolphinView::SortByRating: { + paintText = false; + paintIcon = false; + + starRect.setTop(option.rect.top() + (option.rect.height() / 2) - (iconSize / 2)); + starRect.setSize(QSize(iconSize, iconSize)); + + QPixmap pixmap = KIconLoader::global()->loadIcon("rating", K3Icon::Small); + QPixmap smallPixmap = KIconLoader::global()->loadIcon("rating", K3Icon::NoGroup, iconSize / 2); + QPixmap disabledPixmap = KIconLoader::global()->loadIcon("rating", K3Icon::Small); + + KPixmapEffect::toGray(disabledPixmap, false); + + int rating = category.toInt(); + + for (int i = 0; i < rating - (rating % 2); i += 2) { + painter->drawPixmap(starRect, pixmap); + starRect.setLeft(starRect.left() + iconSize + (iconSize / 4) /* separator between stars */); + } + + if (rating && rating % 2) { + starRect.setTop(option.rect.top() + (option.rect.height() / 2) - (iconSize / 4)); + starRect.setSize(QSize(iconSize / 2, iconSize / 2)); + painter->drawPixmap(starRect, smallPixmap); + starRect.setTop(opt.rect.top() + (option.rect.height() / 2) - (iconSize / 2)); + starRect.setSize(QSize(iconSize / 2, iconSize / 2)); + starRect.setLeft(starRect.left() + (iconSize / 2) + (iconSize / 4)); + starRect.setSize(QSize(iconSize, iconSize)); + } + + for (int i = rating; i < 9; i += 2) { + painter->drawPixmap(starRect, disabledPixmap); + starRect.setLeft(starRect.left() + iconSize + (iconSize / 4)); + } + + break; + } + + case DolphinView::SortByTags: + paintIcon = false; + break; +#endif + } + + if (paintIcon) { + painter->drawPixmap(QRect(opt.rect.left(), opt.rect.top(), iconSize, iconSize), icon); + opt.rect.setLeft(opt.rect.left() + iconSize + (iconSize / 4)); + } + + if (paintText) { + opt.rect.setTop(option.rect.top() + (iconSize / 4)); + opt.rect.setBottom(opt.rect.bottom() - 2); + painter->setPen(color); + + painter->drawText(opt.rect, Qt::AlignVCenter | Qt::AlignLeft, + metrics.elidedText(category, Qt::ElideRight, opt.rect.width())); + } + + painter->restore(); +} + +int DolphinItemCategorizer::categoryHeight(const QStyleOption &option) const +{ + int iconSize = KIconLoader::global()->theme()->defaultSize(K3Icon::Small); + + return qMax(option.fontMetrics.height() + (iconSize / 4) * 2 + 2, iconSize + (iconSize / 4) * 2 + 2) /* 2 gradient */; +} diff --git a/src/dolphinitemcategorizer.h b/src/dolphinitemcategorizer.h index 6be060bd0..65a7340ac 100644 --- a/src/dolphinitemcategorizer.h +++ b/src/dolphinitemcategorizer.h @@ -31,7 +31,10 @@ class LIBDOLPHINPRIVATE_EXPORT DolphinItemCategorizer : public KItemCategorizer public: DolphinItemCategorizer(); virtual ~DolphinItemCategorizer(); - virtual QString categoryForItem(const QModelIndex &index, int sortRole); + virtual QString categoryForItem(const QModelIndex &index, int sortRole) const; + virtual void drawCategory(const QModelIndex &index, int sortRole, + const QStyleOption &option, QPainter *painter) const; + virtual int categoryHeight(const QStyleOption &option) const; }; #endif // DOLPHINITEMCATEGORIZER_H diff --git a/src/kitemcategorizer.cpp b/src/kitemcategorizer.cpp new file mode 100644 index 000000000..93969c3a8 --- /dev/null +++ b/src/kitemcategorizer.cpp @@ -0,0 +1,100 @@ +/** + * This file is part of the KDE project + * Copyright (C) 2007 Rafael Fernández López <[email protected]> + * + * 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 "kitemcategorizer.h" + +#include <QPainter> +#include <QStyleOption> + +KItemCategorizer::KItemCategorizer() +{ +} + +KItemCategorizer::~KItemCategorizer() +{ +} + +void KItemCategorizer::drawCategory(const QModelIndex &index, + int sortRole, + const QStyleOption &option, + QPainter *painter) const +{ + const QString category = categoryForItem(index, sortRole); + + QColor color = option.palette.color(QPalette::Text); + + painter->save(); + painter->setRenderHint(QPainter::Antialiasing); + + QStyleOptionButton opt; + + opt.rect = option.rect; + opt.palette = option.palette; + opt.direction = option.direction; + opt.text = category; + + if (option.state & QStyle::State_MouseOver) + { + const QPalette::ColorGroup group = + option.state & QStyle::State_Enabled ? + QPalette::Normal : QPalette::Disabled; + + QLinearGradient gradient(option.rect.topLeft(), + option.rect.bottomRight()); + gradient.setColorAt(0, + option.palette.color(group, + QPalette::Highlight).light()); + gradient.setColorAt(1, Qt::transparent); + + painter->fillRect(option.rect, gradient); + } + + QFont painterFont = painter->font(); + painterFont.setWeight(QFont::Bold); + painterFont.setPointSize(painterFont.pointSize() + 2); + QFontMetrics metrics(painterFont); + painter->setFont(painterFont); + + QPainterPath path; + path.addRect(option.rect.left(), + option.rect.bottom() - 2, + option.rect.width(), + 2); + + QLinearGradient gradient(option.rect.topLeft(), + option.rect.bottomRight()); + gradient.setColorAt(0, color); + gradient.setColorAt(1, Qt::transparent); + + painter->setBrush(gradient); + painter->fillPath(path, gradient); + + painter->setPen(color); + + painter->drawText(option.rect, Qt::AlignVCenter | Qt::AlignLeft, + metrics.elidedText(category, Qt::ElideRight, option.rect.width())); + + painter->restore(); +} + +int KItemCategorizer::categoryHeight(const QStyleOption &option) const +{ + return option.fontMetrics.height() + 6 /* 4 separator; 2 gradient */; +} diff --git a/src/kitemcategorizer.h b/src/kitemcategorizer.h index 5c6531a1d..aff048e29 100644 --- a/src/kitemcategorizer.h +++ b/src/kitemcategorizer.h @@ -24,20 +24,49 @@ #include <libdolphin_export.h> class QString; +class QPainter; class QModelIndex; +class QStyleOption; +/** + * @short Class for item categorizing on KListView + * + * This class is meant to be used with KListView class. Its purpose is + * to decide to which category belongs a given index with the given role. + * Additionally it will let you to customize the way categories are drawn, + * only in the case that you want to do so + * + * @see KListView + * + * @author Rafael Fernández López <[email protected]> + */ class LIBDOLPHINPRIVATE_EXPORT KItemCategorizer { public: - KItemCategorizer() - { - } + KItemCategorizer(); + + virtual ~KItemCategorizer(); + + /** + * This method will return the category where @param index fit on with the + * given @param sortRole role + */ + virtual QString categoryForItem(const QModelIndex &index, + int sortRole) const = 0; - virtual ~KItemCategorizer() - { - } + /** + * This method purpose is to draw a category represented by the given + * @param index with the given @param sortRole sorting role + * + * @note This method will be called one time per category, always with the + * first element in that category + */ + virtual void drawCategory(const QModelIndex &index, + int sortRole, + const QStyleOption &option, + QPainter *painter) const; - virtual QString categoryForItem(const QModelIndex &index, int sortRole) = 0; + virtual int categoryHeight(const QStyleOption &option) const; }; #endif // KITEMCATEGORIZER_H diff --git a/src/klistview.cpp b/src/klistview.cpp index e3ea89e41..4db18e1f4 100644 --- a/src/klistview.cpp +++ b/src/klistview.cpp @@ -146,7 +146,7 @@ QRect KListView::Private::visualRectInViewport(const QModelIndex &index) const QString curCategory = elementsInfo[index].category; QRect retRect(listView->spacing(), listView->spacing() * 2 + - 30 /* categoryHeight */, 0, 0); + itemCategorizer->categoryHeight(listView->viewOptions()), 0, 0); int viewportWidth = listView->viewport()->width() - listView->spacing(); @@ -183,7 +183,7 @@ QRect KListView::Private::visualRectInViewport(const QModelIndex &index) const retRect.setTop(retRect.top() + (rowsInt * listView->spacing()) + (rowsInt * itemHeight) + - 30 /* categoryHeight */ + + itemCategorizer->categoryHeight(listView->viewOptions()) + listView->spacing() * 2); } @@ -238,11 +238,11 @@ QRect KListView::Private::visualCategoryRectInViewport(const QString &category) retRect.setTop(retRect.top() + (rowsInt * listView->spacing()) + (rowsInt * itemHeight) + - 30 /* categoryHeight */ + + itemCategorizer->categoryHeight(listView->viewOptions()) + listView->spacing() * 2); } - retRect.setHeight(30 /* categoryHeight */); + retRect.setHeight(itemCategorizer->categoryHeight(listView->viewOptions())); return retRect; } @@ -311,69 +311,23 @@ QRect KListView::Private::categoryVisualRect(const QString &category) return retRect; } -void KListView::Private::drawNewCategory(const QString &category, +void KListView::Private::drawNewCategory(const QModelIndex &index, + int sortRole, const QStyleOption &option, QPainter *painter) { - QColor color = option.palette.color(QPalette::Text); - - painter->save(); - painter->setRenderHint(QPainter::Antialiasing); - - QStyleOptionButton opt; - - opt.rect = option.rect; - opt.palette = option.palette; - opt.direction = option.direction; - opt.text = category; + QStyleOption optionCopy = option; + const QString category = itemCategorizer->categoryForItem(index, sortRole); if ((category == hoveredCategory) && !mouseButtonPressed) { - const QPalette::ColorGroup group = - option.state & QStyle::State_Enabled ? - QPalette::Normal : QPalette::Disabled; - - QLinearGradient gradient(option.rect.topLeft(), - option.rect.bottomRight()); - gradient.setColorAt(0, - option.palette.color(group, - QPalette::Highlight).light()); - gradient.setColorAt(1, Qt::transparent); - - painter->fillRect(option.rect, gradient); + optionCopy.state |= QStyle::State_MouseOver; } - /*if (const KStyle *style = dynamic_cast<const KStyle*>(QApplication::style())) - { - style->drawControl(KStyle::CE_Category, &opt, painter, this); - } - else - {*/ - QFont painterFont = painter->font(); - painterFont.setWeight(QFont::Bold); - QFontMetrics metrics(painterFont); - painter->setFont(painterFont); - - QPainterPath path; - path.addRect(option.rect.left(), - option.rect.bottom() - 2, - option.rect.width(), - 2); - - QLinearGradient gradient(option.rect.topLeft(), - option.rect.bottomRight()); - gradient.setColorAt(0, color); - gradient.setColorAt(1, Qt::transparent); - - painter->setBrush(gradient); - painter->fillPath(path, gradient); - - painter->setPen(color); - - painter->drawText(option.rect, Qt::AlignVCenter | Qt::AlignLeft, - metrics.elidedText(category, Qt::ElideRight, option.rect.width())); - //} - painter->restore(); + itemCategorizer->drawCategory(index, + sortRole, + optionCopy, + painter); } @@ -424,11 +378,9 @@ void KListView::Private::drawDraggedItems() } } - listView->viewport()->update(lastDraggedItemsRect); + listView->viewport()->update(lastDraggedItemsRect.united(rectToUpdate)); lastDraggedItemsRect = rectToUpdate; - - listView->viewport()->update(rectToUpdate); } @@ -448,6 +400,21 @@ KListView::~KListView() void KListView::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->hovered = QModelIndex(); + d->mouseButtonPressed = false; + if (d->proxyModel) { QObject::disconnect(d->proxyModel, @@ -498,6 +465,21 @@ KItemCategorizer *KListView::itemCategorizer() const void KListView::setItemCategorizer(KItemCategorizer *itemCategorizer) { + 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->hovered = QModelIndex(); + d->mouseButtonPressed = false; + if (!itemCategorizer && d->proxyModel) { QObject::disconnect(d->proxyModel, @@ -557,15 +539,13 @@ void KListView::reset() { QListView::reset(); - if ((viewMode() != KListView::IconMode) || !d->proxyModel || - !d->itemCategorizer) - { - return; - } - + 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(); @@ -635,6 +615,22 @@ void KListView::paintEvent(QPaintEvent *event) itemDelegate(index)->paint(&painter, option, index); } + // Redraw categories + int i = 0; + QStyleOptionViewItem otherOption; + foreach (const QString &category, d->categories) + { + otherOption = option; + otherOption.rect = d->categoryVisualRect(category); + otherOption.state &= ~QStyle::State_MouseOver; + + if (otherOption.rect.intersects(area)) + { + d->drawNewCategory(d->categoriesIndexes[category][0], + d->proxyModel->sortRole(), otherOption, &painter); + } + } + if (d->mouseButtonPressed && !d->isDragging) { QPoint start, end, initialPressPosition; @@ -666,19 +662,6 @@ void KListView::paintEvent(QPaintEvent *event) painter.restore(); } - // Redraw categories - QStyleOptionViewItem otherOption; - foreach (const QString &category, d->categories) - { - otherOption = option; - otherOption.rect = d->categoryVisualRect(category); - - if (otherOption.rect.intersects(area)) - { - d->drawNewCategory(category, otherOption, &painter); - } - } - if (d->isDragging && !d->dragLeftViewport) { painter.setOpacity(0.5); @@ -692,16 +675,17 @@ void KListView::resizeEvent(QResizeEvent *event) { QListView::resizeEvent(event); + // Clear the items positions cache + d->elementsPosition.clear(); + d->categoriesPosition.clear(); + d->forcedSelectionPosition = 0; + if ((viewMode() != KListView::IconMode) || !d->proxyModel || !d->itemCategorizer) { return; } - // Clear the items positions cache - d->elementsPosition.clear(); - d->categoriesPosition.clear(); - d->updateScrollbars(); } @@ -726,6 +710,7 @@ void KListView::setSelection(const QRect &rect, } QModelIndexList dirtyIndexes = d->intersectionSet(rect); + QItemSelection selection; if (!dirtyIndexes.count()) @@ -741,6 +726,7 @@ void KListView::setSelection(const QRect &rect, if (!d->mouseButtonPressed) { selection = QItemSelection(dirtyIndexes[0], dirtyIndexes[0]); + d->currentViewIndex = dirtyIndexes[0]; } else { @@ -786,6 +772,8 @@ void KListView::mouseMoveEvent(QMouseEvent *event) return; } + const QString previousHoveredCategory = d->hoveredCategory; + d->mousePosition = event->pos(); d->hoveredCategory = QString(); @@ -795,9 +783,13 @@ void KListView::mouseMoveEvent(QMouseEvent *event) if (d->categoryVisualRect(category).intersects(QRect(event->pos(), event->pos()))) { d->hoveredCategory = category; + viewport()->update(d->categoryVisualRect(category)); + } + else if ((category == previousHoveredCategory) && + (!d->categoryVisualRect(previousHoveredCategory).intersects(QRect(event->pos(), event->pos())))) + { + viewport()->update(d->categoryVisualRect(category)); } - - viewport()->update(d->categoryVisualRect(category)); } QRect rect; @@ -822,11 +814,9 @@ void KListView::mouseMoveEvent(QMouseEvent *event) end = d->mousePosition; } - viewport()->update(d->lastSelectionRect); - rect = QRect(start, end).intersected(viewport()->rect().adjusted(-16, -16, 16, 16)); - viewport()->update(rect); + //viewport()->update(rect.united(d->lastSelectionRect)); d->lastSelectionRect = rect; } @@ -834,14 +824,6 @@ void KListView::mouseMoveEvent(QMouseEvent *event) void KListView::mousePressEvent(QMouseEvent *event) { - QListView::mousePressEvent(event); - - if ((viewMode() != KListView::IconMode) || !d->proxyModel || - !d->itemCategorizer) - { - return; - } - d->dragLeftViewport = false; if (event->button() == Qt::LeftButton) @@ -854,10 +836,14 @@ void KListView::mousePressEvent(QMouseEvent *event) d->initialPressPosition.setX(d->initialPressPosition.x() + horizontalOffset()); } + + QListView::mousePressEvent(event); } void KListView::mouseReleaseEvent(QMouseEvent *event) { + d->mouseButtonPressed = false; + QListView::mouseReleaseEvent(event); if ((viewMode() != KListView::IconMode) || !d->proxyModel || @@ -866,8 +852,6 @@ void KListView::mouseReleaseEvent(QMouseEvent *event) return; } - d->mouseButtonPressed = false; - QPoint initialPressPosition = viewport()->mapFromGlobal(QCursor::pos()); initialPressPosition.setY(initialPressPosition.y() + verticalOffset()); initialPressPosition.setX(initialPressPosition.x() + horizontalOffset()); @@ -902,16 +886,10 @@ void KListView::mouseReleaseEvent(QMouseEvent *event) void KListView::leaveEvent(QEvent *event) { - QListView::leaveEvent(event); - - if ((viewMode() != KListView::IconMode) || !d->proxyModel || - !d->itemCategorizer) - { - return; - } - d->hovered = QModelIndex(); d->hoveredCategory = QString(); + + QListView::leaveEvent(event); } void KListView::startDrag(Qt::DropActions supportedActions) @@ -920,17 +898,12 @@ void KListView::startDrag(Qt::DropActions supportedActions) d->isDragging = false; d->mouseButtonPressed = false; + + viewport()->update(d->lastDraggedItemsRect); } void KListView::dragMoveEvent(QDragMoveEvent *event) { - if ((viewMode() != KListView::IconMode) || !d->proxyModel || - !d->itemCategorizer) - { - QListView::dragMoveEvent(event); - return; - } - d->mousePosition = event->pos(); if (d->mouseButtonPressed) @@ -944,20 +917,21 @@ void KListView::dragMoveEvent(QDragMoveEvent *event) d->dragLeftViewport = false; - d->drawDraggedItems(); -} - -void KListView::dragLeaveEvent(QDragLeaveEvent *event) -{ - QListView::dragLeaveEvent(event); - if ((viewMode() != KListView::IconMode) || !d->proxyModel || !d->itemCategorizer) { + QListView::dragMoveEvent(event); return; } + d->drawDraggedItems(); +} + +void KListView::dragLeaveEvent(QDragLeaveEvent *event) +{ d->dragLeftViewport = true; + + QListView::dragLeaveEvent(event); } QModelIndex KListView::moveCursor(CursorAction cursorAction, @@ -969,6 +943,119 @@ QModelIndex KListView::moveCursor(CursorAction cursorAction, return QListView::moveCursor(cursorAction, modifiers); } + const QModelIndex current = selectionModel()->currentIndex(); + + int viewportWidth = viewport()->width() - spacing(); + // We really need all items to be of same size. Otherwise we cannot do this + // (ereslibre) + // QSize itemSize = listView->sizeHintForIndex(index); + // int itemHeight = itemSize.height(); + // int itemWidth = itemSize.width(); + int itemHeight = 107; + int itemWidth = 130; + int itemWidthPlusSeparation = spacing() + itemWidth; + int elementsPerRow = viewportWidth / itemWidthPlusSeparation; + + QString lastCategory = d->categories[0]; + QString theCategory = d->categories[0]; + QString afterCategory = d->categories[0]; + bool hasToBreak = false; + foreach (const QString &category, d->categories) + { + if (hasToBreak) + { + afterCategory = category; + + break; + } + + if (category == d->elementsInfo[d->proxyModel->mapToSource(current)].category) + { + theCategory = category; + + hasToBreak = true; + } + + if (!hasToBreak) + { + lastCategory = category; + } + } + + switch (cursorAction) + { + case QAbstractItemView::MoveUp: { + if (d->elementsInfo[d->proxyModel->mapToSource(current)].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)); + + return d->elementDictionary[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; + + if (d->forcedSelectionPosition >= lastCategoryLastRow) + { + indexToMove -= 1; + } + else + { + indexToMove -= qMin((lastCategoryLastRow - d->forcedSelectionPosition + 1), d->forcedSelectionPosition + elementsPerRow + 1); + } + + return d->elementDictionary[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))) + { + int indexToMove = d->invertedElementDictionary[current].row(); + indexToMove += qMin(elementsPerRow, d->categoriesIndexes[theCategory].count() - 1 - d->elementsInfo[d->proxyModel->mapToSource(current)].relativeOffsetToCategory); + + return d->elementDictionary[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); + + if (d->forcedSelectionPosition >= afterCategoryLastRow) + { + indexToMove += afterCategoryLastRow - 1; + } + else + { + indexToMove += qMin(d->forcedSelectionPosition, elementsPerRow); + } + + return d->elementDictionary[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 (d->forcedSelectionPosition < 0) + d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow; + + return d->elementDictionary[d->proxyModel->index(d->invertedElementDictionary[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 (d->forcedSelectionPosition < 0) + d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow; + + return d->elementDictionary[d->proxyModel->index(d->invertedElementDictionary[current].row() + 1, 0)]; + + default: + break; + } + return QListView::moveCursor(cursorAction, modifiers); } @@ -981,6 +1068,21 @@ void KListView::rowsInserted(const QModelIndex &parent, if ((viewMode() != KListView::IconMode) || !d->proxyModel || !d->itemCategorizer) { + 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->hovered = QModelIndex(); + d->mouseButtonPressed = false; + return; } @@ -994,9 +1096,12 @@ void KListView::rowsInsertedArtifficial(const QModelIndex &parent, 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(); @@ -1083,6 +1188,9 @@ void KListView::rowsInsertedArtifficial(const QModelIndex &parent, 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++; } diff --git a/src/klistview.h b/src/klistview.h index 6626db3d5..57a414c2f 100644 --- a/src/klistview.h +++ b/src/klistview.h @@ -27,6 +27,17 @@ class KItemCategorizer; +/** + * @short Item view for listing items + * + * KListView allows you to use it as it were a QListView. You can add an + * itemCategorizer to it, so your items became categorized depending on the + * KItemCategorizer inherited class rules. + * + * @see KItemCategorizer, KSortFilterProxyModel + * + * @author Rafael Fernández López <[email protected]> + */ class LIBDOLPHINPRIVATE_EXPORT KListView : public QListView { @@ -41,8 +52,15 @@ public: virtual QRect visualRect(const QModelIndex &index) const; + /** + * Will return the current categorizer. If none set, this method will + * return 0 + */ KItemCategorizer *itemCategorizer() const; + /** + * Sets the categorizer to be used. Causes the item view to repaint + */ void setItemCategorizer(KItemCategorizer *itemCategorizer); virtual QModelIndex indexAt(const QPoint &point) const; diff --git a/src/klistview_p.h b/src/klistview_p.h index b590b2307..4d0cec138 100644 --- a/src/klistview_p.h +++ b/src/klistview_p.h @@ -85,10 +85,12 @@ public: QRect categoryVisualRect(const QString &category); /** - * This method will draw a new category with name @p category on the rect - * specified by @p option.rect, with painter @p painter + * This method will draw a new category represented by index + * @param index on the rect specified by @p option.rect, with + * painter @p painter */ - void drawNewCategory(const QString &category, + void drawNewCategory(const QModelIndex &index, + int sortRole, const QStyleOption &option, QPainter *painter); @@ -131,6 +133,8 @@ public: QPoint initialPressPosition; QPoint mousePosition; QItemSelection lastSelection; + QModelIndex currentViewIndex; + int forcedSelectionPosition; // Cache data // We cannot merge some of them into structs because it would affect @@ -138,6 +142,7 @@ public: QHash<QModelIndex, struct ElementInfo> elementsInfo; // in source model QHash<QModelIndex, QRect> elementsPosition; // in source model QHash<QModelIndex, QModelIndex> elementDictionary; // mapped indexes + QHash<QModelIndex, QModelIndex> invertedElementDictionary; // mapped indexes QHash<QString, QModelIndexList> categoriesIndexes; QHash<QString, QRect> categoriesPosition; QStringList categories; diff --git a/src/ksortfilterproxymodel.h b/src/ksortfilterproxymodel.h index 2748c64ec..1c653f67c 100644 --- a/src/ksortfilterproxymodel.h +++ b/src/ksortfilterproxymodel.h @@ -25,6 +25,13 @@ #include <libdolphin_export.h> +/** + * @internal + * + * This class is meant to be used with KListView class + * + * @see KListView + */ class LIBDOLPHINPRIVATE_EXPORT KSortFilterProxyModel : public QSortFilterProxyModel { |
