X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/ce3f4e5d74ce4eeb70d2c61b9a21ca43c0e9228b..0cb23c8cfa1049cbd5ef98368ff1c200978b8ac7:/src/kcategorizedview.cpp diff --git a/src/kcategorizedview.cpp b/src/kcategorizedview.cpp index 622fe7b60..6fa7632f2 100644 --- a/src/kcategorizedview.cpp +++ b/src/kcategorizedview.cpp @@ -1,6 +1,6 @@ /** * This file is part of the KDE project - * Copyright (C) 2007 Rafael Fernández López + * Copyright (C) 2007 Rafael Fernández López * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,66 +24,30 @@ #include // trunc on C99 compliant systems #include // trunc for not C99 compliant systems -#include #include #include #include -#include #include -#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()) { } @@ -98,6 +62,17 @@ const QModelIndexList &KCategorizedView::Private::intersectionSet(const QRect &r intersectedIndexes.clear(); + int itemHeight; + + if (listView->gridSize().isEmpty()) + { + itemHeight = biggestItemSize.height(); + } + else + { + itemHeight = listView->gridSize().height(); + } + // Lets find out where we should start int top = proxyModel->rowCount() - 1; int bottom = 0; @@ -106,12 +81,15 @@ 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) + indexVisualRect.setHeight(indexVisualRect.height() + (itemHeight - indexVisualRect.height())); if (qMax(indexVisualRect.topLeft().y(), indexVisualRect.bottomRight().y()) < qMin(rect.topLeft().y(), - rect.bottomRight().y())) + rect.bottomRight().y())) { bottom = middle + 1; } @@ -123,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)) @@ -144,25 +122,58 @@ 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(listView->viewOptions()), 0, 0); + } + else + { + retRect = QRect(listView->viewport()->width() - listView->spacing(), listView->spacing() * 2 + + categoryDrawer->categoryHeight(listView->viewOptions()), 0, 0); + } int viewportWidth = listView->viewport()->width() - listView->spacing(); - int itemHeight = biggestItemSize.height(); - int itemWidth = biggestItemSize.width(); + int itemHeight; + int itemWidth; + + if (listView->gridSize().isEmpty()) + { + itemHeight = biggestItemSize.height(); + itemWidth = biggestItemSize.width(); + } + else + { + itemHeight = listView->gridSize().height(); + itemWidth = listView->gridSize().width(); + } + int itemWidthPlusSeparation = listView->spacing() + itemWidth; int elementsPerRow = viewportWidth / itemWidthPlusSeparation; 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) { @@ -171,22 +182,45 @@ 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 * listView->spacing()) + (rowsInt * itemHeight) + - itemCategorizer->categoryHeight(listView->viewOptions()) + + categoryDrawer->categoryHeight(listView->viewOptions()) + listView->spacing() * 2); + + if (listView->gridSize().isEmpty()) + { + retRect.setTop(retRect.top() + + (rowsInt * listView->spacing())); + } } - retRect.setTop(retRect.top() + row * listView->spacing() + - row * itemHeight); + if (listView->gridSize().isEmpty()) + { + retRect.setTop(retRect.top() + row * listView->spacing() + + (row * itemHeight)); + } + else + { + retRect.setTop(retRect.top() + (row * itemHeight)); + } retRect.setWidth(itemWidth); - retRect.setHeight(itemHeight); + + QModelIndex heightIndex = proxyModel->index(index.row(), 0); + if (listView->gridSize().isEmpty()) + { + retRect.setHeight(listView->sizeHintForIndex(heightIndex).height()); + } + else + { + retRect.setHeight(qMin(listView->sizeHintForIndex(heightIndex).height(), + listView->gridSize().height())); + } return retRect; } @@ -206,8 +240,20 @@ QRect KCategorizedView::Private::visualCategoryRectInViewport(const QString &cat int viewportWidth = listView->viewport()->width() - listView->spacing(); - int itemHeight = biggestItemSize.height(); - int itemWidth = biggestItemSize.width(); + int itemHeight; + int itemWidth; + + if (listView->gridSize().isEmpty()) + { + itemHeight = biggestItemSize.height(); + itemWidth = biggestItemSize.width(); + } + else + { + itemHeight = listView->gridSize().height(); + itemWidth = listView->gridSize().width(); + } + int itemWidthPlusSeparation = listView->spacing() + itemWidth; int elementsPerRow = viewportWidth / itemWidthPlusSeparation; @@ -226,13 +272,18 @@ QRect KCategorizedView::Private::visualCategoryRectInViewport(const QString &cat if (rows - trunc(rows)) rowsInt++; retRect.setTop(retRect.top() + - (rowsInt * listView->spacing()) + (rowsInt * itemHeight) + - itemCategorizer->categoryHeight(listView->viewOptions()) + + categoryDrawer->categoryHeight(listView->viewOptions()) + listView->spacing() * 2); + + if (listView->gridSize().isEmpty()) + { + retRect.setTop(retRect.top() + + (rowsInt * listView->spacing())); + } } - retRect.setHeight(itemCategorizer->categoryHeight(listView->viewOptions())); + retRect.setHeight(categoryDrawer->categoryHeight(listView->viewOptions())); return retRect; } @@ -241,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 @@ -257,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 @@ -281,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); @@ -302,29 +351,52 @@ 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(); + + optionCopy.state &= ~QStyle::State_Selected; if ((category == hoveredCategory) && !mouseButtonPressed) { optionCopy.state |= QStyle::State_MouseOver; } + else if ((category == hoveredCategory) && mouseButtonPressed) + { + QPoint initialPressPosition = listView->viewport()->mapFromGlobal(QCursor::pos()); + initialPressPosition.setY(initialPressPosition.y() + listView->verticalOffset()); + initialPressPosition.setX(initialPressPosition.x() + listView->horizontalOffset()); + + if (initialPressPosition == this->initialPressPosition) + { + optionCopy.state |= QStyle::State_Selected; + } + } - itemCategorizer->drawCategory(index, - sortRole, - optionCopy, - painter); + categoryDrawer->drawCategory(index, + sortRole, + optionCopy, + painter); } void KCategorizedView::Private::updateScrollbars() { - int lastItemBottom = cachedRectIndex(lastIndex).bottom() + - listView->spacing() - listView->viewport()->height(); + // 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->horizontalScrollBar()->setRange(0, 0); listView->verticalScrollBar()->setSingleStep(listView->viewport()->height() / 10); listView->verticalScrollBar()->setPageStep(listView->viewport()->height()); @@ -350,6 +422,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; @@ -388,54 +490,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(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))); } QListView::setModel(model); - d->proxyModel = dynamic_cast(model); + d->proxyModel = dynamic_cast(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); } @@ -448,54 +578,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(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))); } - 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 { @@ -506,7 +648,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); } @@ -520,8 +662,6 @@ QModelIndex KCategorizedView::indexAt(const QPoint &point) const index = item[0]; } - d->hovered = index; - return index; } @@ -530,26 +670,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; @@ -557,6 +695,11 @@ void KCategorizedView::paintEvent(QPaintEvent *event) QStyleOptionViewItemV3 option = viewOptions(); option.widget = this; + if (wordWrap()) + { + option.features |= QStyleOptionViewItemV2::WrapText; + } + QPainter painter(viewport()); QRect area = event->rect(); const bool focus = (hasFocus() || viewport()->hasFocus()) && @@ -570,7 +713,7 @@ void KCategorizedView::paintEvent(QPaintEvent *event) foreach (const QModelIndex &index, dirtyIndexes) { option.state = state; - option.rect = d->visualRect(index); + option.rect = visualRect(index); if (selectionModel() && selectionModel()->isSelected(index)) { @@ -599,7 +742,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; @@ -609,6 +755,7 @@ void KCategorizedView::paintEvent(QPaintEvent *event) // Redraw categories QStyleOptionViewItem otherOption; + bool intersectedInThePast = false; foreach (const QString &category, d->categories) { otherOption = option; @@ -617,9 +764,18 @@ 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) @@ -672,7 +828,7 @@ void KCategorizedView::resizeEvent(QResizeEvent *event) d->forcedSelectionPosition = 0; if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel || - !d->itemCategorizer) + !d->categoryDrawer || !d->proxyModel->isCategorizedModel()) { return; } @@ -684,7 +840,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; @@ -693,64 +849,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; + } + + 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; + } - selectionModel()->select(selection, flags); + 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) @@ -758,11 +982,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(); @@ -805,11 +1040,10 @@ void KCategorizedView::mouseMoveEvent(QMouseEvent *event) end = d->mousePosition; } - rect = QRect(start, end).intersected(viewport()->rect().adjusted(-16, -16, 16, 16)); + rect = QRect(start, end).adjusted(-16, -16, 16, 16); + rect = rect.united(QRect(start, end).adjusted(16, 16, -16, -16)).intersected(viewport()->rect()); - //viewport()->update(rect.united(d->lastSelectionRect)); - - d->lastSelectionRect = rect; + viewport()->update(rect); } } @@ -827,18 +1061,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; } @@ -847,17 +1090,20 @@ void KCategorizedView::mouseReleaseEvent(QMouseEvent *event) initialPressPosition.setY(initialPressPosition.y() + verticalOffset()); initialPressPosition.setX(initialPressPosition.x() + horizontalOffset()); - QItemSelection selection; - if (initialPressPosition == d->initialPressPosition) { foreach(const QString &category, d->categories) { if (d->categoryVisualRect(category).contains(event->pos())) { - foreach (const QModelIndex &index, d->categoriesIndexes[category]) + QItemSelection selection; + QModelIndexList indexList = d->categoriesIndexes[category]; + + foreach (const QModelIndex &index, indexList) { - selection << QItemSelectionRange(d->proxyModel->mapFromSource(index)); + QModelIndex selectIndex = index.model()->index(index.row(), 0); + + selection << QItemSelectionRange(selectIndex); } selectionModel()->select(selection, QItemSelectionModel::Select); @@ -867,10 +1113,36 @@ void KCategorizedView::mouseReleaseEvent(QMouseEvent *event) } } - 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(d->visualRect(d->hovered)); + viewport()->update(visualRect(d->hovered)); else if (!d->hoveredCategory.isEmpty()) viewport()->update(d->categoryVisualRect(d->hoveredCategory)); } @@ -885,10 +1157,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); } @@ -908,10 +1188,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; } @@ -922,28 +1207,67 @@ 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(); + QModelIndex current = selectionModel()->currentIndex(); + + if (!current.isValid()) + { + current = model()->index(0, 0, QModelIndex()); + selectionModel()->select(current, QItemSelectionModel::NoUpdate); + d->forcedSelectionPosition = 0; + + return current; + } int viewportWidth = viewport()->width() - spacing(); - int itemWidth = d->biggestItemSize.width(); + int itemWidth; + + if (gridSize().isEmpty()) + { + itemWidth = d->biggestItemSize.width(); + } + else + { + itemWidth = gridSize().width(); + } + int itemWidthPlusSeparation = spacing() + itemWidth; int elementsPerRow = viewportWidth / itemWidthPlusSeparation; + if (!elementsPerRow) + elementsPerRow++; + + 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) { @@ -954,7 +1278,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; @@ -970,17 +1294,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) { @@ -991,22 +1315,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) { @@ -1017,25 +1341,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; @@ -1045,29 +1409,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; } @@ -1076,139 +1437,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; @@ -1219,14 +1538,41 @@ 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 ¤t, + 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++; + + d->forcedSelectionPosition = d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow; + + QListView::currentChanged(current, previous); } #include "kcategorizedview.moc"