X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/a24c1fce8234dc0ad0116aecc06c7151bcdd1cee..c6992dd7f898a5c92b52d54a032efd1beef40980:/src/kcategorizedview.cpp diff --git a/src/kcategorizedview.cpp b/src/kcategorizedview.cpp index 7fe806055..51b4a000b 100644 --- a/src/kcategorizedview.cpp +++ b/src/kcategorizedview.cpp @@ -24,7 +24,6 @@ #include // trunc on C99 compliant systems #include // trunc for not C99 compliant systems -#include #include #include #include @@ -34,11 +33,18 @@ #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) , categoryDrawer(0) , biggestItemSize(QSize(0, 0)) , mouseButtonPressed(false) + , rightMouseButtonPressed(false) , isDragging(false) , dragLeftViewport(false) , proxyModel(0) @@ -123,12 +129,12 @@ QRect KCategorizedView::Private::visualRectInViewport(const QModelIndex &index) if (listView->layoutDirection() == Qt::LeftToRight) { retRect = QRect(listView->spacing(), listView->spacing() * 2 + - categoryDrawer->categoryHeight(listView->viewOptions()), 0, 0); + categoryDrawer->categoryHeight(index, listView->viewOptions()), 0, 0); } else { retRect = QRect(listView->viewport()->width() - listView->spacing(), listView->spacing() * 2 + - categoryDrawer->categoryHeight(listView->viewOptions()), 0, 0); + categoryDrawer->categoryHeight(index, listView->viewOptions()), 0, 0); } int viewportWidth = listView->viewport()->width() - listView->spacing(); @@ -183,7 +189,7 @@ QRect KCategorizedView::Private::visualRectInViewport(const QModelIndex &index) retRect.setTop(retRect.top() + (rowsInt * itemHeight) + - categoryDrawer->categoryHeight(listView->viewOptions()) + + categoryDrawer->categoryHeight(index, listView->viewOptions()) + listView->spacing() * 2); if (listView->gridSize().isEmpty()) @@ -267,7 +273,7 @@ QRect KCategorizedView::Private::visualCategoryRectInViewport(const QString &cat retRect.setTop(retRect.top() + (rowsInt * itemHeight) + - categoryDrawer->categoryHeight(listView->viewOptions()) + + categoryDrawer->categoryHeight(index, listView->viewOptions()) + listView->spacing() * 2); if (listView->gridSize().isEmpty()) @@ -277,7 +283,7 @@ QRect KCategorizedView::Private::visualCategoryRectInViewport(const QString &cat } } - retRect.setHeight(categoryDrawer->categoryHeight(listView->viewOptions())); + retRect.setHeight(categoryDrawer->categoryHeight(index, listView->viewOptions())); return retRect; } @@ -355,23 +361,25 @@ void KCategorizedView::Private::drawNewCategory(const QModelIndex &index, } QStyleOption optionCopy = option; - const QString category = proxyModel->data(index, KCategorizedSortFilterProxyModel::CategoryRole).toString(); + 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) + if ((listView->selectionMode() != SingleSelection) && (listView->selectionMode() != NoSelection)) { + if ((category == hoveredCategory) && !mouseButtonPressed) { - optionCopy.state |= QStyle::State_Selected; + 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; + } } } @@ -388,7 +396,9 @@ void KCategorizedView::Private::updateScrollbars() QModelIndex lastIndex = categoriesIndexes.isEmpty() ? QModelIndex() : categoriesIndexes[categories.last()].last(); int lastItemBottom = cachedRectIndex(lastIndex).top() + - listView->spacing() + (listView->gridSize().isEmpty() ? 0 : listView->gridSize().height()) - listView->viewport()->height(); + listView->spacing() + (listView->gridSize().isEmpty() ? biggestItemSize.height() : listView->gridSize().height()) - listView->viewport()->height(); + + listView->horizontalScrollBar()->setRange(0, 0); listView->verticalScrollBar()->setSingleStep(listView->viewport()->height() / 10); listView->verticalScrollBar()->setPageStep(listView->viewport()->height()); @@ -414,6 +424,36 @@ void KCategorizedView::Private::drawDraggedItems(QPainter *painter) } } +void KCategorizedView::Private::layoutChanged(bool forceItemReload) +{ + if ((listView->viewMode() == KCategorizedView::IconMode) && proxyModel && + categoryDrawer && proxyModel->isCategorizedModel() && + ((forceItemReload || + (modelSortRole != proxyModel->sortRole()) || + (modelSortColumn != proxyModel->sortColumn()) || + (modelSortOrder != proxyModel->sortOrder()) || + (modelLastRowCount != proxyModel->rowCount()) || + (modelCategorized != proxyModel->isCategorizedModel())))) + { + // Force the view to update all elements + listView->rowsInsertedArtifficial(QModelIndex(), 0, proxyModel->rowCount() - 1); + + if (!forceItemReload) + { + modelSortRole = proxyModel->sortRole(); + modelSortColumn = proxyModel->sortColumn(); + modelSortOrder = proxyModel->sortOrder(); + modelLastRowCount = proxyModel->rowCount(); + modelCategorized = proxyModel->isCategorizedModel(); + } + } + else if ((listView->viewMode() == KCategorizedView::IconMode) && proxyModel && + categoryDrawer && proxyModel->isCategorizedModel()) + { + updateScrollbars(); + } +} + void KCategorizedView::Private::drawDraggedItems() { QRect rectToUpdate; @@ -456,13 +496,12 @@ void KCategorizedView::setGridSize(const QSize &size) { QListView::setGridSize(size); - slotLayoutChanged(); + d->layoutChanged(true); } void KCategorizedView::setModel(QAbstractItemModel *model) { d->lastSelection = QItemSelection(); - d->currentViewIndex = QModelIndex(); d->forcedSelectionPosition = 0; d->elementsInfo.clear(); d->elementsPosition.clear(); @@ -473,6 +512,7 @@ void KCategorizedView::setModel(QAbstractItemModel *model) d->modelIndexList.clear(); d->hovered = QModelIndex(); d->mouseButtonPressed = false; + d->rightMouseButtonPressed = false; if (d->proxyModel) { @@ -483,6 +523,10 @@ void KCategorizedView::setModel(QAbstractItemModel *model) QObject::disconnect(d->proxyModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(slotLayoutChanged())); + + QObject::disconnect(d->proxyModel, + SIGNAL(rowsRemoved(QModelIndex,int,int)), + this, SLOT(rowsRemoved(QModelIndex,int,int))); } QListView::setModel(model); @@ -491,6 +535,12 @@ void KCategorizedView::setModel(QAbstractItemModel *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())); @@ -498,6 +548,19 @@ void KCategorizedView::setModel(QAbstractItemModel *model) 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))); + + if (d->proxyModel->rowCount()) + { + d->layoutChanged(true); + } + } + else + { + d->modelCategorized = false; } } @@ -525,7 +588,6 @@ KCategoryDrawer *KCategorizedView::categoryDrawer() const void KCategorizedView::setCategoryDrawer(KCategoryDrawer *categoryDrawer) { d->lastSelection = QItemSelection(); - d->currentViewIndex = QModelIndex(); d->forcedSelectionPosition = 0; d->elementsInfo.clear(); d->elementsPosition.clear(); @@ -536,6 +598,7 @@ void KCategorizedView::setCategoryDrawer(KCategoryDrawer *categoryDrawer) d->modelIndexList.clear(); d->hovered = QModelIndex(); d->mouseButtonPressed = false; + d->rightMouseButtonPressed = false; if (!categoryDrawer && d->proxyModel) { @@ -546,6 +609,10 @@ void KCategorizedView::setCategoryDrawer(KCategoryDrawer *categoryDrawer) QObject::disconnect(d->proxyModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(slotLayoutChanged())); + + QObject::disconnect(d->proxyModel, + SIGNAL(rowsRemoved(QModelIndex,int,int)), + this, SLOT(rowsRemoved(QModelIndex,int,int))); } else if (categoryDrawer && d->proxyModel) { @@ -556,6 +623,10 @@ void KCategorizedView::setCategoryDrawer(KCategoryDrawer *categoryDrawer) 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))); } d->categoryDrawer = categoryDrawer; @@ -564,7 +635,10 @@ void KCategorizedView::setCategoryDrawer(KCategoryDrawer *categoryDrawer) { if (d->proxyModel) { - rowsInserted(QModelIndex(), 0, d->proxyModel->rowCount() - 1); + if (d->proxyModel->rowCount()) + { + d->layoutChanged(true); + } } } else @@ -590,8 +664,6 @@ QModelIndex KCategorizedView::indexAt(const QPoint &point) const index = item[0]; } - d->hovered = index; - return index; } @@ -600,7 +672,6 @@ void KCategorizedView::reset() QListView::reset(); d->lastSelection = QItemSelection(); - d->currentViewIndex = QModelIndex(); d->forcedSelectionPosition = 0; d->elementsInfo.clear(); d->elementsPosition.clear(); @@ -612,6 +683,7 @@ void KCategorizedView::reset() d->hovered = QModelIndex(); d->biggestItemSize = QSize(0, 0); d->mouseButtonPressed = false; + d->rightMouseButtonPressed = false; } void KCategorizedView::paintEvent(QPaintEvent *event) @@ -672,7 +744,10 @@ void KCategorizedView::paintEvent(QPaintEvent *event) option.state |= QStyle::State_Editing; } - if ((index == d->hovered) && !d->mouseButtonPressed) + // we are only interested to give the mouse over feedback when no + // dragging is happening (ereslibre) + if ((index == d->hovered) && !d->mouseButtonPressed && + (this->state() == QAbstractItemView::NoState)) option.state |= QStyle::State_MouseOver; else option.state &= ~QStyle::State_MouseOver; @@ -682,6 +757,7 @@ void KCategorizedView::paintEvent(QPaintEvent *event) // Redraw categories QStyleOptionViewItem otherOption; + bool intersectedInThePast = false; foreach (const QString &category, d->categories) { otherOption = option; @@ -690,42 +766,52 @@ void KCategorizedView::paintEvent(QPaintEvent *event) if (otherOption.rect.intersects(area)) { + intersectedInThePast = true; + QModelIndex indexToDraw = d->proxyModel->index(d->categoriesIndexes[category][0].row(), d->proxyModel->sortColumn()); d->drawNewCategory(indexToDraw, d->proxyModel->sortRole(), otherOption, &painter); } + else if (intersectedInThePast) + { + break; // the visible area has been finished, we don't need to keep asking, the rest won't intersect + // this is doable because we know that categories are correctly ordered on the list + } } - if (d->mouseButtonPressed && !d->isDragging) + if ((selectionMode() != SingleSelection) && (selectionMode() != NoSelection)) { - QPoint start, end, initialPressPosition; + if (d->mouseButtonPressed && !d->isDragging) + { + QPoint start, end, initialPressPosition; - initialPressPosition = d->initialPressPosition; + initialPressPosition = d->initialPressPosition; - initialPressPosition.setY(initialPressPosition.y() - verticalOffset()); - initialPressPosition.setX(initialPressPosition.x() - horizontalOffset()); + initialPressPosition.setY(initialPressPosition.y() - verticalOffset()); + initialPressPosition.setX(initialPressPosition.x() - horizontalOffset()); - if (d->initialPressPosition.x() > d->mousePosition.x() || - d->initialPressPosition.y() > d->mousePosition.y()) - { - start = d->mousePosition; - end = initialPressPosition; - } - else - { - start = initialPressPosition; - end = d->mousePosition; - } + if (d->initialPressPosition.x() > d->mousePosition.x() || + d->initialPressPosition.y() > d->mousePosition.y()) + { + start = d->mousePosition; + end = initialPressPosition; + } + else + { + start = initialPressPosition; + end = d->mousePosition; + } - QStyleOptionRubberBand yetAnotherOption; - yetAnotherOption.initFrom(this); - yetAnotherOption.shape = QRubberBand::Rectangle; - yetAnotherOption.opaque = false; - yetAnotherOption.rect = QRect(start, end).intersected(viewport()->rect().adjusted(-16, -16, 16, 16)); - painter.save(); - style()->drawControl(QStyle::CE_RubberBand, &yetAnotherOption, &painter); - painter.restore(); + QStyleOptionRubberBand yetAnotherOption; + yetAnotherOption.initFrom(this); + yetAnotherOption.shape = QRubberBand::Rectangle; + yetAnotherOption.opaque = false; + yetAnotherOption.rect = QRect(start, end).intersected(viewport()->rect().adjusted(-16, -16, 16, 16)); + painter.save(); + style()->drawControl(QStyle::CE_RubberBand, &yetAnotherOption, &painter); + painter.restore(); + } } if (d->isDragging && !d->dragLeftViewport) @@ -770,65 +856,130 @@ void KCategorizedView::setSelection(const QRect &rect, if (flags & QItemSelectionModel::Clear) { - if (!rect.intersects(d->categoryVisualRect(d->hoveredCategory))) - { - d->lastSelection = QItemSelection(); - } + selectionModel()->clear(); + d->lastSelection.clear(); } - selectionModel()->clear(); - QModelIndexList dirtyIndexes = d->intersectionSet(rect); + // no items affected, just leave if (!dirtyIndexes.count()) { - if (!d->lastSelection.isEmpty() && - (rect.intersects(d->categoryVisualRect(d->hoveredCategory)) || d->mouseButtonPressed)) - { - selectionModel()->select(d->lastSelection, flags); - } + selectionModel()->select(d->lastSelection, QItemSelectionModel::SelectCurrent); return; } - QItemSelection selection; + QModelIndex topLeft; + QModelIndex bottomRight; - if (!d->mouseButtonPressed) + if (d->mouseButtonPressed || d->rightMouseButtonPressed) // selection with click + drag { - selection = QItemSelection(dirtyIndexes[0], dirtyIndexes[0]); - d->currentViewIndex = dirtyIndexes[0]; - } - else - { - 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 (flags & QItemSelectionModel::Current) + { + if (rect.topLeft() == rect.bottomRight()) + { + selectionModel()->setCurrentIndex(indexAt(rect.topLeft()), QItemSelectionModel::NoUpdate); + } - if (d->lastSelection.count()) - { - if ((selection.count() == 1) && (selection[0].indexes().count() == 1)) selection.merge(d->lastSelection, flags); + } else - selection.merge(d->lastSelection, QItemSelectionModel::Select); + { + selection.merge(selectionModel()->selection(), flags); + + selectionModel()->select(selection, QItemSelectionModel::SelectCurrent); + + return; + } + + selectionModel()->select(selection, flags); } + else // selection with click + keyboard keys + { + 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; + } + + 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); + selectionModel()->select(selection, flags); + } } void KCategorizedView::mouseMoveEvent(QMouseEvent *event) @@ -841,6 +992,17 @@ void KCategorizedView::mouseMoveEvent(QMouseEvent *event) return; } + QModelIndexList item = d->intersectionSet(QRect(event->pos(), event->pos())); + + if (item.count() == 1) + { + d->hovered = item[0]; + } + else + { + d->hovered = QModelIndex(); + } + const QString previousHoveredCategory = d->hoveredCategory; d->mousePosition = event->pos(); @@ -883,11 +1045,10 @@ void KCategorizedView::mouseMoveEvent(QMouseEvent *event) end = d->mousePosition; } - rect = QRect(start, end).intersected(viewport()->rect().adjusted(-16, -16, 16, 16)); + rect = QRect(start, end).adjusted(-16, -16, 16, 16); + rect = rect.united(QRect(start, end).adjusted(16, 16, -16, -16)).intersected(viewport()->rect()); - //viewport()->update(rect.united(d->lastSelectionRect)); - - d->lastSelectionRect = rect; + viewport()->update(rect); } } @@ -905,15 +1066,22 @@ void KCategorizedView::mousePressEvent(QMouseEvent *event) d->initialPressPosition.setX(d->initialPressPosition.x() + horizontalOffset()); } + else if (event->button() == Qt::RightButton) + { + d->rightMouseButtonPressed = true; + } QListView::mousePressEvent(event); + d->lastSelection = selectionModel()->selection(); + viewport()->update(d->categoryVisualRect(d->hoveredCategory)); } void KCategorizedView::mouseReleaseEvent(QMouseEvent *event) { d->mouseButtonPressed = false; + d->rightMouseButtonPressed = false; QListView::mouseReleaseEvent(event); @@ -927,38 +1095,57 @@ void KCategorizedView::mouseReleaseEvent(QMouseEvent *event) initialPressPosition.setY(initialPressPosition.y() + verticalOffset()); initialPressPosition.setX(initialPressPosition.x() + horizontalOffset()); - QItemSelection selection; - QItemSelection deselection; - - if (initialPressPosition == d->initialPressPosition) + if ((selectionMode() != SingleSelection) && (selectionMode() != NoSelection) && + (initialPressPosition == d->initialPressPosition)) { foreach(const QString &category, d->categories) { if (d->categoryVisualRect(category).contains(event->pos())) { - foreach (const QModelIndex &index, d->categoriesIndexes[category]) + QItemSelection selection; + QModelIndexList indexList = d->categoriesIndexes[category]; + + foreach (const QModelIndex &index, indexList) { QModelIndex selectIndex = index.model()->index(index.row(), 0); - if (!d->lastSelection.contains(selectIndex)) - { - selection << QItemSelectionRange(selectIndex); - } - else - { - deselection << QItemSelectionRange(selectIndex); - } + selection << QItemSelectionRange(selectIndex); } selectionModel()->select(selection, QItemSelectionModel::Select); - selectionModel()->select(deselection, QItemSelectionModel::Deselect); break; } } } - d->lastSelection = selectionModel()->selection(); + QRect rect; + if (!d->isDragging) + { + QPoint start, end, initialPressPosition; + + initialPressPosition = d->initialPressPosition; + + initialPressPosition.setY(initialPressPosition.y() - verticalOffset()); + initialPressPosition.setX(initialPressPosition.x() - horizontalOffset()); + + if (d->initialPressPosition.x() > d->mousePosition.x() || + d->initialPressPosition.y() > d->mousePosition.y()) + { + start = d->mousePosition; + end = initialPressPosition; + } + else + { + start = initialPressPosition; + end = d->mousePosition; + } + + rect = QRect(start, end).adjusted(-16, -16, 16, 16); + rect = rect.united(QRect(start, end).adjusted(16, 16, -16, -16)).intersected(viewport()->rect()); + + viewport()->update(rect); + } if (d->hovered.isValid()) viewport()->update(visualRect(d->hovered)); @@ -980,11 +1167,14 @@ void KCategorizedView::startDrag(Qt::DropActions supportedActions) // 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. - //QListView::startDrag(supportedActions); - QAbstractItemView::startDrag(supportedActions); + // QAbstractItemView::startDrag(supportedActions); +#if !defined(DOLPHIN_DRAGANDDROP) + QListView::startDrag(supportedActions); +#endif d->isDragging = false; d->mouseButtonPressed = false; + d->rightMouseButtonPressed = false; viewport()->update(d->lastDraggedItemsRect); } @@ -1004,10 +1194,15 @@ void KCategorizedView::dragMoveEvent(QDragMoveEvent *event) d->dragLeftViewport = false; +#if defined(DOLPHIN_DRAGANDDROP) + QAbstractItemView::dragMoveEvent(event); +#else + QListView::dragMoveEvent(event); +#endif + if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel()) { - QListView::dragMoveEvent(event); return; } @@ -1018,11 +1213,24 @@ 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 || @@ -1034,8 +1242,6 @@ QModelIndex KCategorizedView::moveCursor(CursorAction cursorAction, return QListView::moveCursor(cursorAction, modifiers); } - const QModelIndex current = selectionModel()->currentIndex(); - int viewportWidth = viewport()->width() - spacing(); int itemWidth; @@ -1050,6 +1256,30 @@ QModelIndex KCategorizedView::moveCursor(CursorAction cursorAction, int itemWidthPlusSeparation = spacing() + itemWidth; int elementsPerRow = viewportWidth / itemWidthPlusSeparation; + if (!elementsPerRow) + elementsPerRow++; + + QModelIndex current = selectionModel()->currentIndex(); + + if (!current.isValid()) + { + if (cursorAction == MoveEnd) + { + current = model()->index(model()->rowCount() - 1, 0, QModelIndex()); + d->forcedSelectionPosition = d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow; + } + else + { + current = model()->index(0, 0, QModelIndex()); + d->forcedSelectionPosition = 0; + } + + return current; + } + else if (!current.isValid()) + { + return QModelIndex(); + } QString lastCategory = d->categories.first(); QString theCategory = d->categories.first(); @@ -1133,18 +1363,58 @@ QModelIndex KCategorizedView::moveCursor(CursorAction cursorAction, } case QAbstractItemView::MoveLeft: + 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->proxyModel->index(current.row() - 1, 0); case QAbstractItemView::MoveRight: + 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->proxyModel->index(current.row() + 1, 0); @@ -1156,16 +1426,14 @@ 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->categoryDrawer || !d->proxyModel->isCategorizedModel()) { - d->lastSelection = QItemSelection(); - d->currentViewIndex = QModelIndex(); d->forcedSelectionPosition = 0; d->elementsInfo.clear(); d->elementsPosition.clear(); @@ -1177,6 +1445,7 @@ void KCategorizedView::rowsInserted(const QModelIndex &parent, d->hovered = QModelIndex(); d->biggestItemSize = QSize(0, 0); d->mouseButtonPressed = false; + d->rightMouseButtonPressed = false; return; } @@ -1185,13 +1454,11 @@ 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(); @@ -1203,32 +1470,32 @@ void KCategorizedView::rowsInsertedArtifficial(const QModelIndex &parent, d->hovered = QModelIndex(); d->biggestItemSize = QSize(0, 0); d->mouseButtonPressed = false; + d->rightMouseButtonPressed = false; if (start > end || end < 0 || start < 0 || !d->proxyModel->rowCount()) { return; } - // Add all elements mapped to the source model - for (int k = 0; k < d->proxyModel->rowCount(); k++) - { - d->biggestItemSize = QSize(qMax(sizeHintForIndex(d->proxyModel->index(k, 0)).width(), - d->biggestItemSize.width()), - qMax(sizeHintForIndex(d->proxyModel->index(k, 0)).height(), - d->biggestItemSize.height())); - - d->modelIndexList << d->proxyModel->index(k, d->proxyModel->sortColumn()); - } - - // Explore categories - QString prevCategory = d->proxyModel->data(d->modelIndexList[0], KCategorizedSortFilterProxyModel::CategoryRole).toString(); + // 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; - foreach (const QModelIndex &index, d->modelIndexList) + for (int k = 0; k < d->proxyModel->rowCount(); ++k) { - lastCategory = d->proxyModel->data(index, KCategorizedSortFilterProxyModel::CategoryRole).toString(); + 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(indexSize).height(), + d->biggestItemSize.height())); + + d->modelIndexList << index; + + lastCategory = d->proxyModel->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString(); elementInfo.category = lastCategory; @@ -1256,17 +1523,21 @@ void KCategorizedView::rowsInsertedArtifficial(const QModelIndex &parent, d->categories << prevCategory; d->updateScrollbars(); + + // FIXME: We need to safely save the last selection. This is on my TODO + // list (ereslibre). + selectionModel()->clear(); } void KCategorizedView::rowsRemoved(const QModelIndex &parent, - int start, - int end) + int start, + int end) { if ((viewMode() == KCategorizedView::IconMode) && d->proxyModel && d->categoryDrawer && d->proxyModel->isCategorizedModel()) { // Force the view to update all elements - rowsInsertedArtifficial(parent, start, end); + rowsInsertedArtifficial(QModelIndex(), 0, d->proxyModel->rowCount() - 1); } } @@ -1286,12 +1557,40 @@ void KCategorizedView::updateGeometries() void KCategorizedView::slotLayoutChanged() { - if ((viewMode() == KCategorizedView::IconMode) && d->proxyModel && - d->categoryDrawer && d->proxyModel->isCategorizedModel()) + 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++; + + if (d->mouseButtonPressed || d->rightMouseButtonPressed) + d->forcedSelectionPosition = d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow; + + QListView::currentChanged(current, previous); } #include "kcategorizedview.moc"