2 * This file is part of the KDE project
3 * Copyright (C) 2007 Rafael Fernández López <ereslibre@kde.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
21 #include "kcategorizedview.h"
22 #include "kcategorizedview_p.h"
24 #include <math.h> // trunc on C99 compliant systems
25 #include <kdefakes.h> // trunc for not C99 compliant systems
29 #include <QPaintEvent>
33 #include "kcategorydrawer.h"
34 #include "kcategorizedsortfilterproxymodel.h"
36 // By defining DOLPHIN_DRAGANDDROP the custom drag and drop implementation of
37 // KCategorizedView is bypassed to have a consistent drag and drop look for all
38 // views. Hopefully transparent pixmaps for drag objects will be supported in
39 // Qt 4.4, so that this workaround can be skipped.
40 #define DOLPHIN_DRAGANDDROP
42 KCategorizedView::Private::Private(KCategorizedView
*listView
)
45 , biggestItemSize(QSize(0, 0))
46 , mouseButtonPressed(false)
47 , rightMouseButtonPressed(false)
49 , dragLeftViewport(false)
54 KCategorizedView::Private::~Private()
58 const QModelIndexList
&KCategorizedView::Private::intersectionSet(const QRect
&rect
)
61 QRect indexVisualRect
;
63 intersectedIndexes
.clear();
67 if (listView
->gridSize().isEmpty())
69 itemHeight
= biggestItemSize
.height();
73 itemHeight
= listView
->gridSize().height();
76 // Lets find out where we should start
77 int top
= proxyModel
->rowCount() - 1;
79 int middle
= (top
+ bottom
) / 2;
82 middle
= (top
+ bottom
) / 2;
84 index
= proxyModel
->index(middle
, 0);
85 indexVisualRect
= visualRect(index
);
86 // We need the whole height (not only the visualRect). This will help us to update
87 // all needed indexes correctly (ereslibre)
88 indexVisualRect
.setHeight(indexVisualRect
.height() + (itemHeight
- indexVisualRect
.height()));
90 if (qMax(indexVisualRect
.topLeft().y(),
91 indexVisualRect
.bottomRight().y()) < qMin(rect
.topLeft().y(),
92 rect
.bottomRight().y()))
102 for (int i
= middle
; i
< proxyModel
->rowCount(); i
++)
104 index
= proxyModel
->index(i
, 0);
105 indexVisualRect
= visualRect(index
);
107 if (rect
.intersects(indexVisualRect
))
108 intersectedIndexes
.append(index
);
110 // If we passed next item, stop searching for hits
111 if (qMax(rect
.bottomRight().y(), rect
.topLeft().y()) <
112 qMin(indexVisualRect
.topLeft().y(),
113 indexVisualRect
.bottomRight().y()))
117 return intersectedIndexes
;
120 QRect
KCategorizedView::Private::visualRectInViewport(const QModelIndex
&index
) const
122 if (!index
.isValid())
125 QString curCategory
= elementsInfo
[index
.row()].category
;
129 if (listView
->flow() == QListView::LeftToRight
)
131 if (listView
->layoutDirection() == Qt::LeftToRight
)
133 retRect
= QRect(listView
->spacing(), listView
->spacing() * 2 +
134 categoryDrawer
->categoryHeight(index
, listView
->viewOptions()), 0, 0);
138 retRect
= QRect(listView
->viewport()->width() - listView
->spacing(), listView
->spacing() * 2 +
139 categoryDrawer
->categoryHeight(index
, listView
->viewOptions()), 0, 0);
144 retRect
= QRect(listView
->spacing(), listView
->spacing() * 2 +
145 categoryDrawer
->categoryHeight(index
, listView
->viewOptions()), 0, 0);
148 int viewportWidth
= listView
->viewport()->width() - listView
->spacing();
153 if (listView
->gridSize().isEmpty() && (listView
->flow() == QListView::LeftToRight
))
155 itemHeight
= biggestItemSize
.height();
156 itemWidth
= biggestItemSize
.width();
158 else if (listView
->flow() == QListView::LeftToRight
)
160 itemHeight
= listView
->gridSize().height();
161 itemWidth
= listView
->gridSize().width();
163 else if (listView
->gridSize().isEmpty() && (listView
->flow() == QListView::TopToBottom
))
165 itemHeight
= biggestItemSize
.height();
166 itemWidth
= listView
->viewport()->width() - listView
->spacing() * 2;
170 itemHeight
= listView
->gridSize().height();
171 itemWidth
= listView
->gridSize().width() - listView
->spacing() * 2;
174 int itemWidthPlusSeparation
= listView
->spacing() + itemWidth
;
175 if (!itemWidthPlusSeparation
)
176 itemWidthPlusSeparation
++;
177 int elementsPerRow
= viewportWidth
/ itemWidthPlusSeparation
;
184 if (listView
->flow() == QListView::LeftToRight
)
186 column
= elementsInfo
[index
.row()].relativeOffsetToCategory
% elementsPerRow
;
187 row
= elementsInfo
[index
.row()].relativeOffsetToCategory
/ elementsPerRow
;
189 if (listView
->layoutDirection() == Qt::LeftToRight
)
191 retRect
.setLeft(retRect
.left() + column
* listView
->spacing() +
196 retRect
.setLeft(retRect
.right() - column
* listView
->spacing() -
197 column
* itemWidth
- itemWidth
);
199 retRect
.setRight(retRect
.right() - column
* listView
->spacing() -
206 column
= elementsInfo
[index
.row()].relativeOffsetToCategory
% elementsPerRow
;
207 row
= elementsInfo
[index
.row()].relativeOffsetToCategory
/ elementsPerRow
;
210 foreach (const QString
&category
, categories
)
212 if (category
== curCategory
)
215 float rows
= (float) ((float) categoriesIndexes
[category
].count() /
216 (float) elementsPerRow
);
218 int rowsInt
= categoriesIndexes
[category
].count() / elementsPerRow
;
220 if (rows
- trunc(rows
)) rowsInt
++;
222 retRect
.setTop(retRect
.top() +
223 (rowsInt
* itemHeight
) +
224 categoryDrawer
->categoryHeight(index
, listView
->viewOptions()) +
225 listView
->spacing() * 2);
227 if (listView
->gridSize().isEmpty())
229 retRect
.setTop(retRect
.top() +
230 (rowsInt
* listView
->spacing()));
234 if (listView
->gridSize().isEmpty())
236 retRect
.setTop(retRect
.top() + row
* listView
->spacing() +
241 retRect
.setTop(retRect
.top() + (row
* itemHeight
));
244 retRect
.setWidth(itemWidth
);
246 QModelIndex heightIndex
= proxyModel
->index(index
.row(), 0);
247 if (listView
->gridSize().isEmpty())
249 retRect
.setHeight(listView
->sizeHintForIndex(heightIndex
).height());
253 retRect
.setHeight(qMin(listView
->sizeHintForIndex(heightIndex
).height(),
254 listView
->gridSize().height()));
260 QRect
KCategorizedView::Private::visualCategoryRectInViewport(const QString
&category
) const
262 QRect
retRect(listView
->spacing(),
264 listView
->viewport()->width() - listView
->spacing() * 2,
267 if (!proxyModel
->rowCount() || !categories
.contains(category
))
270 QModelIndex index
= proxyModel
->index(0, 0, QModelIndex());
272 int viewportWidth
= listView
->viewport()->width() - listView
->spacing();
277 if (listView
->gridSize().isEmpty())
279 itemHeight
= biggestItemSize
.height();
280 itemWidth
= biggestItemSize
.width();
284 itemHeight
= listView
->gridSize().height();
285 itemWidth
= listView
->gridSize().width();
288 int itemWidthPlusSeparation
= listView
->spacing() + itemWidth
;
289 int elementsPerRow
= viewportWidth
/ itemWidthPlusSeparation
;
294 if (listView
->flow() == QListView::TopToBottom
)
299 foreach (const QString
&itCategory
, categories
)
301 if (itCategory
== category
)
304 float rows
= (float) ((float) categoriesIndexes
[itCategory
].count() /
305 (float) elementsPerRow
);
306 int rowsInt
= categoriesIndexes
[itCategory
].count() / elementsPerRow
;
308 if (rows
- trunc(rows
)) rowsInt
++;
310 retRect
.setTop(retRect
.top() +
311 (rowsInt
* itemHeight
) +
312 categoryDrawer
->categoryHeight(index
, listView
->viewOptions()) +
313 listView
->spacing() * 2);
315 if (listView
->gridSize().isEmpty())
317 retRect
.setTop(retRect
.top() +
318 (rowsInt
* listView
->spacing()));
322 retRect
.setHeight(categoryDrawer
->categoryHeight(index
, listView
->viewOptions()));
327 // We're sure elementsPosition doesn't contain index
328 const QRect
&KCategorizedView::Private::cacheIndex(const QModelIndex
&index
)
330 QRect rect
= visualRectInViewport(index
);
331 elementsPosition
[index
.row()] = rect
;
333 return elementsPosition
[index
.row()];
336 // We're sure categoriesPosition doesn't contain category
337 const QRect
&KCategorizedView::Private::cacheCategory(const QString
&category
)
339 QRect rect
= visualCategoryRectInViewport(category
);
340 categoriesPosition
[category
] = rect
;
342 return categoriesPosition
[category
];
345 const QRect
&KCategorizedView::Private::cachedRectIndex(const QModelIndex
&index
)
347 if (elementsPosition
.contains(index
.row())) // If we have it cached
349 return elementsPosition
[index
.row()];
351 else // Otherwise, cache it
353 return cacheIndex(index
);
357 const QRect
&KCategorizedView::Private::cachedRectCategory(const QString
&category
)
359 if (categoriesPosition
.contains(category
)) // If we have it cached
361 return categoriesPosition
[category
];
363 else // Otherwise, cache it and
365 return cacheCategory(category
);
369 QRect
KCategorizedView::Private::visualRect(const QModelIndex
&index
)
371 QRect retRect
= cachedRectIndex(index
);
372 int dx
= -listView
->horizontalOffset();
373 int dy
= -listView
->verticalOffset();
374 retRect
.adjust(dx
, dy
, dx
, dy
);
379 QRect
KCategorizedView::Private::categoryVisualRect(const QString
&category
)
381 QRect retRect
= cachedRectCategory(category
);
382 int dx
= -listView
->horizontalOffset();
383 int dy
= -listView
->verticalOffset();
384 retRect
.adjust(dx
, dy
, dx
, dy
);
389 void KCategorizedView::Private::drawNewCategory(const QModelIndex
&index
,
391 const QStyleOption
&option
,
394 if (!index
.isValid())
399 QStyleOption optionCopy
= option
;
400 const QString category
= proxyModel
->data(index
, KCategorizedSortFilterProxyModel::CategoryDisplayRole
).toString();
402 optionCopy
.state
&= ~QStyle::State_Selected
;
404 if ((listView
->selectionMode() != SingleSelection
) && (listView
->selectionMode() != NoSelection
)) {
405 if ((category
== hoveredCategory
) && !mouseButtonPressed
)
407 optionCopy
.state
|= QStyle::State_MouseOver
;
409 else if ((category
== hoveredCategory
) && mouseButtonPressed
)
411 QPoint initialPressPosition
= listView
->viewport()->mapFromGlobal(QCursor::pos());
412 initialPressPosition
.setY(initialPressPosition
.y() + listView
->verticalOffset());
413 initialPressPosition
.setX(initialPressPosition
.x() + listView
->horizontalOffset());
415 if (initialPressPosition
== this->initialPressPosition
)
417 optionCopy
.state
|= QStyle::State_Selected
;
422 categoryDrawer
->drawCategory(index
,
429 void KCategorizedView::Private::updateScrollbars()
431 // find the last index in the last category
432 QModelIndex lastIndex
= categoriesIndexes
.isEmpty() ? QModelIndex() : categoriesIndexes
[categories
.last()].last();
434 int lastItemBottom
= cachedRectIndex(lastIndex
).top() +
435 listView
->spacing() + (listView
->gridSize().isEmpty() ? biggestItemSize
.height() : listView
->gridSize().height()) - listView
->viewport()->height();
437 listView
->horizontalScrollBar()->setRange(0, 0);
439 listView
->verticalScrollBar()->setSingleStep(listView
->viewport()->height() / 10);
440 listView
->verticalScrollBar()->setPageStep(listView
->viewport()->height());
441 listView
->verticalScrollBar()->setRange(0, lastItemBottom
);
444 void KCategorizedView::Private::drawDraggedItems(QPainter
*painter
)
446 QStyleOptionViewItemV3 option
= listView
->viewOptions();
447 option
.state
&= ~QStyle::State_MouseOver
;
448 foreach (const QModelIndex
&index
, listView
->selectionModel()->selectedIndexes())
450 const int dx
= mousePosition
.x() - initialPressPosition
.x() + listView
->horizontalOffset();
451 const int dy
= mousePosition
.y() - initialPressPosition
.y() + listView
->verticalOffset();
453 option
.rect
= visualRect(index
);
454 option
.rect
.adjust(dx
, dy
, dx
, dy
);
456 if (option
.rect
.intersects(listView
->viewport()->rect()))
458 listView
->itemDelegate(index
)->paint(painter
, option
, index
);
463 void KCategorizedView::Private::layoutChanged(bool forceItemReload
)
465 if (proxyModel
&& categoryDrawer
&& proxyModel
->isCategorizedModel() &&
467 (modelSortRole
!= proxyModel
->sortRole()) ||
468 (modelSortColumn
!= proxyModel
->sortColumn()) ||
469 (modelSortOrder
!= proxyModel
->sortOrder()) ||
470 (modelLastRowCount
!= proxyModel
->rowCount()) ||
471 (modelCategorized
!= proxyModel
->isCategorizedModel()))))
473 // Force the view to update all elements
474 listView
->rowsInsertedArtifficial(QModelIndex(), 0, proxyModel
->rowCount() - 1);
476 if (!forceItemReload
)
478 modelSortRole
= proxyModel
->sortRole();
479 modelSortColumn
= proxyModel
->sortColumn();
480 modelSortOrder
= proxyModel
->sortOrder();
481 modelLastRowCount
= proxyModel
->rowCount();
482 modelCategorized
= proxyModel
->isCategorizedModel();
485 else if (proxyModel
&& categoryDrawer
&& proxyModel
->isCategorizedModel())
491 void KCategorizedView::Private::drawDraggedItems()
495 foreach (const QModelIndex
&index
, listView
->selectionModel()->selectedIndexes())
497 int dx
= mousePosition
.x() - initialPressPosition
.x() + listView
->horizontalOffset();
498 int dy
= mousePosition
.y() - initialPressPosition
.y() + listView
->verticalOffset();
500 currentRect
= visualRect(index
);
501 currentRect
.adjust(dx
, dy
, dx
, dy
);
503 if (currentRect
.intersects(listView
->viewport()->rect()))
505 rectToUpdate
= rectToUpdate
.united(currentRect
);
509 listView
->viewport()->update(lastDraggedItemsRect
.united(rectToUpdate
));
511 lastDraggedItemsRect
= rectToUpdate
;
515 //==============================================================================
518 KCategorizedView::KCategorizedView(QWidget
*parent
)
520 , d(new Private(this))
522 setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel
);
523 setVerticalScrollMode(QAbstractItemView::ScrollPerPixel
);
526 KCategorizedView::~KCategorizedView()
531 void KCategorizedView::setGridSize(const QSize
&size
)
533 QListView::setGridSize(size
);
535 d
->layoutChanged(true);
538 void KCategorizedView::setModel(QAbstractItemModel
*model
)
540 d
->lastSelection
= QItemSelection();
541 d
->forcedSelectionPosition
= 0;
542 d
->elementsInfo
.clear();
543 d
->elementsPosition
.clear();
544 d
->categoriesIndexes
.clear();
545 d
->categoriesPosition
.clear();
546 d
->categories
.clear();
547 d
->intersectedIndexes
.clear();
548 d
->modelIndexList
.clear();
549 d
->hovered
= QModelIndex();
550 d
->mouseButtonPressed
= false;
551 d
->rightMouseButtonPressed
= false;
555 QObject::disconnect(d
->proxyModel
,
556 SIGNAL(layoutChanged()),
557 this, SLOT(slotLayoutChanged()));
559 QObject::disconnect(d
->proxyModel
,
560 SIGNAL(dataChanged(QModelIndex
,QModelIndex
)),
561 this, SLOT(slotLayoutChanged()));
563 QObject::disconnect(d
->proxyModel
,
564 SIGNAL(rowsRemoved(QModelIndex
,int,int)),
565 this, SLOT(rowsRemoved(QModelIndex
,int,int)));
568 QListView::setModel(model
);
570 d
->proxyModel
= dynamic_cast<KCategorizedSortFilterProxyModel
*>(model
);
574 d
->modelSortRole
= d
->proxyModel
->sortRole();
575 d
->modelSortColumn
= d
->proxyModel
->sortColumn();
576 d
->modelSortOrder
= d
->proxyModel
->sortOrder();
577 d
->modelLastRowCount
= d
->proxyModel
->rowCount();
578 d
->modelCategorized
= d
->proxyModel
->isCategorizedModel();
580 QObject::connect(d
->proxyModel
,
581 SIGNAL(layoutChanged()),
582 this, SLOT(slotLayoutChanged()));
584 QObject::connect(d
->proxyModel
,
585 SIGNAL(dataChanged(QModelIndex
,QModelIndex
)),
586 this, SLOT(slotLayoutChanged()));
588 QObject::connect(d
->proxyModel
,
589 SIGNAL(rowsRemoved(QModelIndex
,int,int)),
590 this, SLOT(rowsRemoved(QModelIndex
,int,int)));
592 if (d
->proxyModel
->rowCount())
594 d
->layoutChanged(true);
599 d
->modelCategorized
= false;
603 QRect
KCategorizedView::visualRect(const QModelIndex
&index
) const
605 if (!d
->proxyModel
|| !d
->categoryDrawer
|| !d
->proxyModel
->isCategorizedModel())
607 return QListView::visualRect(index
);
610 if (!qobject_cast
<const QSortFilterProxyModel
*>(index
.model()))
612 return d
->visualRect(d
->proxyModel
->mapFromSource(index
));
615 return d
->visualRect(index
);
618 KCategoryDrawer
*KCategorizedView::categoryDrawer() const
620 return d
->categoryDrawer
;
623 void KCategorizedView::setCategoryDrawer(KCategoryDrawer
*categoryDrawer
)
625 d
->lastSelection
= QItemSelection();
626 d
->forcedSelectionPosition
= 0;
627 d
->elementsInfo
.clear();
628 d
->elementsPosition
.clear();
629 d
->categoriesIndexes
.clear();
630 d
->categoriesPosition
.clear();
631 d
->categories
.clear();
632 d
->intersectedIndexes
.clear();
633 d
->modelIndexList
.clear();
634 d
->hovered
= QModelIndex();
635 d
->mouseButtonPressed
= false;
636 d
->rightMouseButtonPressed
= false;
638 if (!categoryDrawer
&& d
->proxyModel
)
640 QObject::disconnect(d
->proxyModel
,
641 SIGNAL(layoutChanged()),
642 this, SLOT(slotLayoutChanged()));
644 QObject::disconnect(d
->proxyModel
,
645 SIGNAL(dataChanged(QModelIndex
,QModelIndex
)),
646 this, SLOT(slotLayoutChanged()));
648 QObject::disconnect(d
->proxyModel
,
649 SIGNAL(rowsRemoved(QModelIndex
,int,int)),
650 this, SLOT(rowsRemoved(QModelIndex
,int,int)));
652 else if (categoryDrawer
&& d
->proxyModel
)
654 QObject::connect(d
->proxyModel
,
655 SIGNAL(layoutChanged()),
656 this, SLOT(slotLayoutChanged()));
658 QObject::connect(d
->proxyModel
,
659 SIGNAL(dataChanged(QModelIndex
,QModelIndex
)),
660 this, SLOT(slotLayoutChanged()));
662 QObject::connect(d
->proxyModel
,
663 SIGNAL(rowsRemoved(QModelIndex
,int,int)),
664 this, SLOT(rowsRemoved(QModelIndex
,int,int)));
667 d
->categoryDrawer
= categoryDrawer
;
673 if (d
->proxyModel
->rowCount())
675 d
->layoutChanged(true);
685 QModelIndex
KCategorizedView::indexAt(const QPoint
&point
) const
687 if (!d
->proxyModel
|| !d
->categoryDrawer
|| !d
->proxyModel
->isCategorizedModel())
689 return QListView::indexAt(point
);
694 QModelIndexList item
= d
->intersectionSet(QRect(point
, point
));
696 if (item
.count() == 1)
704 void KCategorizedView::reset()
708 d
->lastSelection
= QItemSelection();
709 d
->forcedSelectionPosition
= 0;
710 d
->elementsInfo
.clear();
711 d
->elementsPosition
.clear();
712 d
->categoriesIndexes
.clear();
713 d
->categoriesPosition
.clear();
714 d
->categories
.clear();
715 d
->intersectedIndexes
.clear();
716 d
->modelIndexList
.clear();
717 d
->hovered
= QModelIndex();
718 d
->biggestItemSize
= QSize(0, 0);
719 d
->mouseButtonPressed
= false;
720 d
->rightMouseButtonPressed
= false;
723 void KCategorizedView::paintEvent(QPaintEvent
*event
)
725 if (!d
->proxyModel
|| !d
->categoryDrawer
|| !d
->proxyModel
->isCategorizedModel())
727 QListView::paintEvent(event
);
731 QStyleOptionViewItemV3 option
= viewOptions();
732 option
.widget
= this;
735 option
.features
|= QStyleOptionViewItemV2::WrapText
;
738 QPainter
painter(viewport());
739 QRect area
= event
->rect();
740 const bool focus
= (hasFocus() || viewport()->hasFocus()) &&
741 currentIndex().isValid();
742 const QStyle::State state
= option
.state
;
743 const bool enabled
= (state
& QStyle::State_Enabled
) != 0;
747 QModelIndexList dirtyIndexes
= d
->intersectionSet(area
);
748 foreach (const QModelIndex
&index
, dirtyIndexes
)
750 option
.state
= state
;
751 option
.rect
= visualRect(index
);
753 if (selectionModel() && selectionModel()->isSelected(index
))
755 option
.state
|= QStyle::State_Selected
;
760 QPalette::ColorGroup cg
;
761 if ((d
->proxyModel
->flags(index
) & Qt::ItemIsEnabled
) == 0)
763 option
.state
&= ~QStyle::State_Enabled
;
764 cg
= QPalette::Disabled
;
768 cg
= QPalette::Normal
;
770 option
.palette
.setCurrentColorGroup(cg
);
773 if (focus
&& currentIndex() == index
)
775 option
.state
|= QStyle::State_HasFocus
;
776 if (this->state() == EditingState
)
777 option
.state
|= QStyle::State_Editing
;
780 // we are only interested to give the mouse over feedback when no
781 // dragging is happening (ereslibre)
782 if ((index
== d
->hovered
) && !d
->mouseButtonPressed
&&
783 (this->state() == QAbstractItemView::NoState
))
784 option
.state
|= QStyle::State_MouseOver
;
786 option
.state
&= ~QStyle::State_MouseOver
;
788 itemDelegate(index
)->paint(&painter
, option
, index
);
792 QStyleOptionViewItem otherOption
;
793 bool intersectedInThePast
= false;
794 foreach (const QString
&category
, d
->categories
)
796 otherOption
= option
;
797 otherOption
.rect
= d
->categoryVisualRect(category
);
798 otherOption
.state
&= ~QStyle::State_MouseOver
;
800 if (otherOption
.rect
.intersects(area
))
802 intersectedInThePast
= true;
804 QModelIndex indexToDraw
= d
->proxyModel
->index(d
->categoriesIndexes
[category
][0].row(), d
->proxyModel
->sortColumn());
806 d
->drawNewCategory(indexToDraw
,
807 d
->proxyModel
->sortRole(), otherOption
, &painter
);
809 else if (intersectedInThePast
)
811 break; // the visible area has been finished, we don't need to keep asking, the rest won't intersect
812 // this is doable because we know that categories are correctly ordered on the list
816 if ((selectionMode() != SingleSelection
) && (selectionMode() != NoSelection
))
818 if (d
->mouseButtonPressed
&& !d
->isDragging
)
820 QPoint start
, end
, initialPressPosition
;
822 initialPressPosition
= d
->initialPressPosition
;
824 initialPressPosition
.setY(initialPressPosition
.y() - verticalOffset());
825 initialPressPosition
.setX(initialPressPosition
.x() - horizontalOffset());
827 if (d
->initialPressPosition
.x() > d
->mousePosition
.x() ||
828 d
->initialPressPosition
.y() > d
->mousePosition
.y())
830 start
= d
->mousePosition
;
831 end
= initialPressPosition
;
835 start
= initialPressPosition
;
836 end
= d
->mousePosition
;
839 QStyleOptionRubberBand yetAnotherOption
;
840 yetAnotherOption
.initFrom(this);
841 yetAnotherOption
.shape
= QRubberBand::Rectangle
;
842 yetAnotherOption
.opaque
= false;
843 yetAnotherOption
.rect
= QRect(start
, end
).intersected(viewport()->rect().adjusted(-16, -16, 16, 16));
845 style()->drawControl(QStyle::CE_RubberBand
, &yetAnotherOption
, &painter
);
850 if (d
->isDragging
&& !d
->dragLeftViewport
)
852 painter
.setOpacity(0.5);
853 d
->drawDraggedItems(&painter
);
859 void KCategorizedView::resizeEvent(QResizeEvent
*event
)
861 QListView::resizeEvent(event
);
863 // Clear the items positions cache
864 d
->elementsPosition
.clear();
865 d
->categoriesPosition
.clear();
866 d
->forcedSelectionPosition
= 0;
868 if (!d
->proxyModel
|| !d
->categoryDrawer
|| !d
->proxyModel
->isCategorizedModel())
873 d
->updateScrollbars();
876 void KCategorizedView::setSelection(const QRect
&rect
,
877 QItemSelectionModel::SelectionFlags flags
)
879 if (!d
->proxyModel
|| !d
->categoryDrawer
|| !d
->proxyModel
->isCategorizedModel())
881 QListView::setSelection(rect
, flags
);
888 if (flags
& QItemSelectionModel::Clear
)
890 selectionModel()->clear();
891 d
->lastSelection
.clear();
894 QModelIndexList dirtyIndexes
= d
->intersectionSet(rect
);
896 // no items affected, just leave
897 if (!dirtyIndexes
.count())
899 selectionModel()->select(d
->lastSelection
, QItemSelectionModel::SelectCurrent
);
905 QModelIndex bottomRight
;
907 if (d
->mouseButtonPressed
|| d
->rightMouseButtonPressed
) // selection with click + drag
909 QItemSelection selection
;
911 QModelIndex prev
= dirtyIndexes
[0];
912 QModelIndex first
= prev
;
913 foreach (const QModelIndex
&index
, dirtyIndexes
)
915 // we have a different interval. non-contiguous items
916 if ((index
.row() - prev
.row()) > 1) {
917 selection
<< QItemSelectionRange(first
, prev
);
925 selection
<< QItemSelectionRange(first
, prev
);
927 if (flags
& QItemSelectionModel::Current
)
929 if (rect
.topLeft() == rect
.bottomRight())
931 selectionModel()->setCurrentIndex(indexAt(rect
.topLeft()), QItemSelectionModel::NoUpdate
);
934 selection
.merge(d
->lastSelection
, flags
);
938 selection
.merge(selectionModel()->selection(), flags
);
940 selectionModel()->select(selection
, QItemSelectionModel::SelectCurrent
);
945 selectionModel()->select(selection
, flags
);
947 else // selection with click + keyboard keys
949 QModelIndex topLeftIndex
= indexAt(QPoint(rect
.topLeft().x(),
950 rect
.topLeft().y()));
951 QModelIndex bottomRightIndex
= indexAt(QPoint(rect
.bottomRight().x(),
952 rect
.bottomRight().y()));
954 // keyboard selection comes "upside down". Let's normalize it
955 if (topLeftIndex
.row() > bottomRightIndex
.row())
957 QModelIndex auxIndex
= topLeftIndex
;
958 topLeftIndex
= bottomRightIndex
;
959 bottomRightIndex
= auxIndex
;
962 int viewportWidth
= viewport()->width() - spacing();
965 if (gridSize().isEmpty())
967 itemWidth
= d
->biggestItemSize
.width();
971 itemWidth
= gridSize().width();
974 int itemWidthPlusSeparation
= spacing() + itemWidth
;
975 if (!itemWidthPlusSeparation
)
976 itemWidthPlusSeparation
++;
977 int elementsPerRow
= viewportWidth
/ itemWidthPlusSeparation
;
981 QModelIndexList
theoricDirty(dirtyIndexes
);
982 dirtyIndexes
.clear();
983 int first
= model()->rowCount();
986 foreach (const QModelIndex
&index
, theoricDirty
)
988 if ((index
.row() < first
) &&
989 ((((topLeftIndex
.row() / elementsPerRow
) == (index
.row() / elementsPerRow
)) &&
990 ((topLeftIndex
.row() % elementsPerRow
) <= (index
.row() % elementsPerRow
))) ||
991 (topLeftIndex
.row() / elementsPerRow
) != (index
.row() / elementsPerRow
)))
997 if ((index
.row() > last
) &&
998 ((((bottomRightIndex
.row() / elementsPerRow
) == (index
.row() / elementsPerRow
)) &&
999 ((bottomRightIndex
.row() % elementsPerRow
) >= (index
.row() % elementsPerRow
))) ||
1000 (bottomRightIndex
.row() / elementsPerRow
) != (index
.row() / elementsPerRow
)))
1003 bottomRight
= index
;
1007 for (int i
= first
; i
<= last
; i
++)
1009 dirtyIndexes
<< model()->index(i
, theoricDirty
[0].column(), theoricDirty
[0].parent());
1012 QItemSelection
selection(topLeft
, bottomRight
);
1014 selectionModel()->select(selection
, flags
);
1018 void KCategorizedView::mouseMoveEvent(QMouseEvent
*event
)
1020 QListView::mouseMoveEvent(event
);
1022 if (!d
->proxyModel
|| !d
->categoryDrawer
|| !d
->proxyModel
->isCategorizedModel())
1027 QModelIndexList item
= d
->intersectionSet(QRect(event
->pos(), event
->pos()));
1029 if (item
.count() == 1)
1031 d
->hovered
= item
[0];
1035 d
->hovered
= QModelIndex();
1038 const QString previousHoveredCategory
= d
->hoveredCategory
;
1040 d
->mousePosition
= event
->pos();
1041 d
->hoveredCategory
= QString();
1043 // Redraw categories
1044 foreach (const QString
&category
, d
->categories
)
1046 if (d
->categoryVisualRect(category
).intersects(QRect(event
->pos(), event
->pos())))
1048 d
->hoveredCategory
= category
;
1049 viewport()->update(d
->categoryVisualRect(category
));
1051 else if ((category
== previousHoveredCategory
) &&
1052 (!d
->categoryVisualRect(previousHoveredCategory
).intersects(QRect(event
->pos(), event
->pos()))))
1054 viewport()->update(d
->categoryVisualRect(category
));
1059 if (d
->mouseButtonPressed
&& !d
->isDragging
)
1061 QPoint start
, end
, initialPressPosition
;
1063 initialPressPosition
= d
->initialPressPosition
;
1065 initialPressPosition
.setY(initialPressPosition
.y() - verticalOffset());
1066 initialPressPosition
.setX(initialPressPosition
.x() - horizontalOffset());
1068 if (d
->initialPressPosition
.x() > d
->mousePosition
.x() ||
1069 d
->initialPressPosition
.y() > d
->mousePosition
.y())
1071 start
= d
->mousePosition
;
1072 end
= initialPressPosition
;
1076 start
= initialPressPosition
;
1077 end
= d
->mousePosition
;
1080 rect
= QRect(start
, end
).adjusted(-16, -16, 16, 16);
1081 rect
= rect
.united(QRect(start
, end
).adjusted(16, 16, -16, -16)).intersected(viewport()->rect());
1083 viewport()->update(rect
);
1087 void KCategorizedView::mousePressEvent(QMouseEvent
*event
)
1089 d
->dragLeftViewport
= false;
1091 if (event
->button() == Qt::LeftButton
)
1093 d
->mouseButtonPressed
= true;
1095 d
->initialPressPosition
= event
->pos();
1096 d
->initialPressPosition
.setY(d
->initialPressPosition
.y() +
1098 d
->initialPressPosition
.setX(d
->initialPressPosition
.x() +
1099 horizontalOffset());
1101 else if (event
->button() == Qt::RightButton
)
1103 d
->rightMouseButtonPressed
= true;
1106 QListView::mousePressEvent(event
);
1108 d
->lastSelection
= selectionModel()->selection();
1110 viewport()->update(d
->categoryVisualRect(d
->hoveredCategory
));
1113 void KCategorizedView::mouseReleaseEvent(QMouseEvent
*event
)
1115 d
->mouseButtonPressed
= false;
1116 d
->rightMouseButtonPressed
= false;
1118 QListView::mouseReleaseEvent(event
);
1120 if (!d
->proxyModel
|| !d
->categoryDrawer
|| !d
->proxyModel
->isCategorizedModel())
1125 QPoint initialPressPosition
= viewport()->mapFromGlobal(QCursor::pos());
1126 initialPressPosition
.setY(initialPressPosition
.y() + verticalOffset());
1127 initialPressPosition
.setX(initialPressPosition
.x() + horizontalOffset());
1129 if ((selectionMode() != SingleSelection
) && (selectionMode() != NoSelection
) &&
1130 (initialPressPosition
== d
->initialPressPosition
))
1132 foreach(const QString
&category
, d
->categories
)
1134 if (d
->categoryVisualRect(category
).contains(event
->pos()))
1136 QItemSelection selection
= selectionModel()->selection();
1137 QModelIndexList indexList
= d
->categoriesIndexes
[category
];
1139 foreach (const QModelIndex
&index
, indexList
)
1141 QModelIndex selectIndex
= index
.model()->index(index
.row(), 0);
1143 selection
<< QItemSelectionRange(selectIndex
);
1146 selectionModel()->select(selection
, QItemSelectionModel::SelectCurrent
);
1156 QPoint start
, end
, initialPressPosition
;
1158 initialPressPosition
= d
->initialPressPosition
;
1160 initialPressPosition
.setY(initialPressPosition
.y() - verticalOffset());
1161 initialPressPosition
.setX(initialPressPosition
.x() - horizontalOffset());
1163 if (d
->initialPressPosition
.x() > d
->mousePosition
.x() ||
1164 d
->initialPressPosition
.y() > d
->mousePosition
.y())
1166 start
= d
->mousePosition
;
1167 end
= initialPressPosition
;
1171 start
= initialPressPosition
;
1172 end
= d
->mousePosition
;
1175 rect
= QRect(start
, end
).adjusted(-16, -16, 16, 16);
1176 rect
= rect
.united(QRect(start
, end
).adjusted(16, 16, -16, -16)).intersected(viewport()->rect());
1178 viewport()->update(rect
);
1181 if (d
->hovered
.isValid())
1182 viewport()->update(visualRect(d
->hovered
));
1183 else if (!d
->hoveredCategory
.isEmpty())
1184 viewport()->update(d
->categoryVisualRect(d
->hoveredCategory
));
1187 void KCategorizedView::leaveEvent(QEvent
*event
)
1189 d
->hovered
= QModelIndex();
1190 d
->hoveredCategory
= QString();
1192 QListView::leaveEvent(event
);
1195 void KCategorizedView::startDrag(Qt::DropActions supportedActions
)
1197 // FIXME: QAbstractItemView does far better here since it sets the
1198 // pixmap of selected icons to the dragging cursor, but it sets a non
1199 // ARGB window so it is no transparent. Use QAbstractItemView when
1200 // this is fixed on Qt.
1201 // QAbstractItemView::startDrag(supportedActions);
1202 #if !defined(DOLPHIN_DRAGANDDROP)
1203 QListView::startDrag(supportedActions
);
1206 d
->isDragging
= false;
1207 d
->mouseButtonPressed
= false;
1208 d
->rightMouseButtonPressed
= false;
1210 viewport()->update(d
->lastDraggedItemsRect
);
1213 void KCategorizedView::dragMoveEvent(QDragMoveEvent
*event
)
1215 d
->mousePosition
= event
->pos();
1217 if (d
->mouseButtonPressed
)
1219 d
->isDragging
= true;
1223 d
->isDragging
= false;
1226 d
->dragLeftViewport
= false;
1228 #if defined(DOLPHIN_DRAGANDDROP)
1229 QAbstractItemView::dragMoveEvent(event
);
1231 QListView::dragMoveEvent(event
);
1234 if (!d
->proxyModel
|| !d
->categoryDrawer
|| !d
->proxyModel
->isCategorizedModel())
1239 d
->drawDraggedItems();
1242 void KCategorizedView::dragLeaveEvent(QDragLeaveEvent
*event
)
1244 d
->dragLeftViewport
= true;
1246 #if defined(DOLPHIN_DRAGANDDROP)
1247 QAbstractItemView::dragLeaveEvent(event
);
1249 QListView::dragLeaveEvent(event
);
1253 void KCategorizedView::dropEvent(QDropEvent
*event
)
1255 #if defined(DOLPHIN_DRAGANDDROP)
1256 QAbstractItemView::dropEvent(event
);
1258 QListView::dropEvent(event
);
1262 QModelIndex
KCategorizedView::moveCursor(CursorAction cursorAction
,
1263 Qt::KeyboardModifiers modifiers
)
1265 if ((viewMode() != KCategorizedView::IconMode
) ||
1267 !d
->categoryDrawer
||
1268 d
->categories
.isEmpty() ||
1269 !d
->proxyModel
->isCategorizedModel())
1271 return QListView::moveCursor(cursorAction
, modifiers
);
1274 int viewportWidth
= viewport()->width() - spacing();
1277 if (gridSize().isEmpty())
1279 itemWidth
= d
->biggestItemSize
.width();
1283 itemWidth
= gridSize().width();
1286 int itemWidthPlusSeparation
= spacing() + itemWidth
;
1287 if (!itemWidthPlusSeparation
)
1288 itemWidthPlusSeparation
++;
1289 int elementsPerRow
= viewportWidth
/ itemWidthPlusSeparation
;
1290 if (!elementsPerRow
)
1293 QModelIndex current
= selectionModel()->currentIndex();
1295 if (!current
.isValid())
1297 if (cursorAction
== MoveEnd
)
1299 current
= model()->index(model()->rowCount() - 1, 0, QModelIndex());
1300 d
->forcedSelectionPosition
= d
->elementsInfo
[current
.row()].relativeOffsetToCategory
% elementsPerRow
;
1304 current
= model()->index(0, 0, QModelIndex());
1305 d
->forcedSelectionPosition
= 0;
1310 else if (!current
.isValid())
1312 return QModelIndex();
1315 QString lastCategory
= d
->categories
.first();
1316 QString theCategory
= d
->categories
.first();
1317 QString afterCategory
= d
->categories
.first();
1319 bool hasToBreak
= false;
1320 foreach (const QString
&category
, d
->categories
)
1324 afterCategory
= category
;
1329 if (category
== d
->elementsInfo
[current
.row()].category
)
1331 theCategory
= category
;
1338 lastCategory
= category
;
1342 switch (cursorAction
)
1344 case QAbstractItemView::MoveUp
: {
1345 if (d
->elementsInfo
[current
.row()].relativeOffsetToCategory
>= elementsPerRow
)
1347 int indexToMove
= current
.row();
1348 indexToMove
-= qMin(((d
->elementsInfo
[current
.row()].relativeOffsetToCategory
) + d
->forcedSelectionPosition
), elementsPerRow
- d
->forcedSelectionPosition
+ (d
->elementsInfo
[current
.row()].relativeOffsetToCategory
% elementsPerRow
));
1350 return d
->proxyModel
->index(indexToMove
, 0);
1354 int lastCategoryLastRow
= (d
->categoriesIndexes
[lastCategory
].count() - 1) % elementsPerRow
;
1355 int indexToMove
= current
.row() - d
->elementsInfo
[current
.row()].relativeOffsetToCategory
;
1357 if (d
->forcedSelectionPosition
>= lastCategoryLastRow
)
1363 indexToMove
-= qMin((lastCategoryLastRow
- d
->forcedSelectionPosition
+ 1), d
->forcedSelectionPosition
+ elementsPerRow
+ 1);
1366 return d
->proxyModel
->index(indexToMove
, 0);
1370 case QAbstractItemView::MoveDown
: {
1371 if (d
->elementsInfo
[current
.row()].relativeOffsetToCategory
< (d
->categoriesIndexes
[theCategory
].count() - 1 - ((d
->categoriesIndexes
[theCategory
].count() - 1) % elementsPerRow
)))
1373 int indexToMove
= current
.row();
1374 indexToMove
+= qMin(elementsPerRow
, d
->categoriesIndexes
[theCategory
].count() - 1 - d
->elementsInfo
[current
.row()].relativeOffsetToCategory
);
1376 return d
->proxyModel
->index(indexToMove
, 0);
1380 int afterCategoryLastRow
= qMin(elementsPerRow
, d
->categoriesIndexes
[afterCategory
].count());
1381 int indexToMove
= current
.row() + (d
->categoriesIndexes
[theCategory
].count() - d
->elementsInfo
[current
.row()].relativeOffsetToCategory
);
1383 if (d
->forcedSelectionPosition
>= afterCategoryLastRow
)
1385 indexToMove
+= afterCategoryLastRow
- 1;
1389 indexToMove
+= qMin(d
->forcedSelectionPosition
, elementsPerRow
);
1392 return d
->proxyModel
->index(indexToMove
, 0);
1396 case QAbstractItemView::MoveLeft
:
1397 if (layoutDirection() == Qt::RightToLeft
)
1399 if (!(d
->elementsInfo
[current
.row() + 1].relativeOffsetToCategory
% elementsPerRow
))
1402 d
->forcedSelectionPosition
= d
->elementsInfo
[current
.row() + 1].relativeOffsetToCategory
% elementsPerRow
;
1404 #if 0 //follow qt view behavior. lateral movements won't change visual row
1405 if (d
->forcedSelectionPosition
< 0)
1406 d
->forcedSelectionPosition
= (d
->categoriesIndexes
[theCategory
].count() - 1) % elementsPerRow
;
1409 return d
->proxyModel
->index(current
.row() + 1, 0);
1412 if (!(d
->elementsInfo
[current
.row()].relativeOffsetToCategory
% elementsPerRow
))
1415 d
->forcedSelectionPosition
= d
->elementsInfo
[current
.row() - 1].relativeOffsetToCategory
% elementsPerRow
;
1417 #if 0 //follow qt view behavior. lateral movements won't change visual row
1418 if (d
->forcedSelectionPosition
< 0)
1419 d
->forcedSelectionPosition
= (d
->categoriesIndexes
[theCategory
].count() - 1) % elementsPerRow
;
1422 return d
->proxyModel
->index(current
.row() - 1, 0);
1424 case QAbstractItemView::MoveRight
:
1425 if (layoutDirection() == Qt::RightToLeft
)
1427 if (!(d
->elementsInfo
[current
.row()].relativeOffsetToCategory
% elementsPerRow
))
1430 d
->forcedSelectionPosition
= d
->elementsInfo
[current
.row() - 1].relativeOffsetToCategory
% elementsPerRow
;
1432 #if 0 //follow qt view behavior. lateral movements won't change visual row
1433 if (d
->forcedSelectionPosition
< 0)
1434 d
->forcedSelectionPosition
= (d
->categoriesIndexes
[theCategory
].count() - 1) % elementsPerRow
;
1437 return d
->proxyModel
->index(current
.row() - 1, 0);
1440 if (!(d
->elementsInfo
[current
.row() + 1].relativeOffsetToCategory
% elementsPerRow
))
1443 d
->forcedSelectionPosition
= d
->elementsInfo
[current
.row() + 1].relativeOffsetToCategory
% elementsPerRow
;
1445 #if 0 //follow qt view behavior. lateral movements won't change visual row
1446 if (d
->forcedSelectionPosition
< 0)
1447 d
->forcedSelectionPosition
= (d
->categoriesIndexes
[theCategory
].count() - 1) % elementsPerRow
;
1450 return d
->proxyModel
->index(current
.row() + 1, 0);
1456 return QListView::moveCursor(cursorAction
, modifiers
);
1459 void KCategorizedView::rowsInserted(const QModelIndex
&parent
,
1463 QListView::rowsInserted(parent
, start
, end
);
1465 if (!d
->proxyModel
|| !d
->categoryDrawer
|| !d
->proxyModel
->isCategorizedModel())
1467 d
->forcedSelectionPosition
= 0;
1468 d
->elementsInfo
.clear();
1469 d
->elementsPosition
.clear();
1470 d
->categoriesIndexes
.clear();
1471 d
->categoriesPosition
.clear();
1472 d
->categories
.clear();
1473 d
->intersectedIndexes
.clear();
1474 d
->modelIndexList
.clear();
1475 d
->hovered
= QModelIndex();
1476 d
->biggestItemSize
= QSize(0, 0);
1477 d
->mouseButtonPressed
= false;
1478 d
->rightMouseButtonPressed
= false;
1483 rowsInsertedArtifficial(parent
, start
, end
);
1486 void KCategorizedView::rowsInsertedArtifficial(const QModelIndex
&parent
,
1492 d
->forcedSelectionPosition
= 0;
1493 d
->elementsInfo
.clear();
1494 d
->elementsPosition
.clear();
1495 d
->categoriesIndexes
.clear();
1496 d
->categoriesPosition
.clear();
1497 d
->categories
.clear();
1498 d
->intersectedIndexes
.clear();
1499 d
->modelIndexList
.clear();
1500 d
->hovered
= QModelIndex();
1501 d
->biggestItemSize
= QSize(0, 0);
1502 d
->mouseButtonPressed
= false;
1503 d
->rightMouseButtonPressed
= false;
1505 if (start
> end
|| end
< 0 || start
< 0 || !d
->proxyModel
->rowCount())
1510 // Add all elements mapped to the source model and explore categories
1511 QString prevCategory
= d
->proxyModel
->data(d
->proxyModel
->index(0, d
->proxyModel
->sortColumn()), KCategorizedSortFilterProxyModel::CategoryDisplayRole
).toString();
1512 QString lastCategory
= prevCategory
;
1513 QModelIndexList modelIndexList
;
1514 struct Private::ElementInfo elementInfo
;
1516 for (int k
= 0; k
< d
->proxyModel
->rowCount(); ++k
)
1518 QModelIndex index
= d
->proxyModel
->index(k
, d
->proxyModel
->sortColumn());
1519 QModelIndex indexSize
= d
->proxyModel
->index(k
, 0);
1521 d
->biggestItemSize
= QSize(qMax(sizeHintForIndex(indexSize
).width(),
1522 d
->biggestItemSize
.width()),
1523 qMax(sizeHintForIndex(indexSize
).height(),
1524 d
->biggestItemSize
.height()));
1526 d
->modelIndexList
<< index
;
1528 lastCategory
= d
->proxyModel
->data(index
, KCategorizedSortFilterProxyModel::CategoryDisplayRole
).toString();
1530 elementInfo
.category
= lastCategory
;
1532 if (prevCategory
!= lastCategory
)
1535 d
->categoriesIndexes
.insert(prevCategory
, modelIndexList
);
1536 d
->categories
<< prevCategory
;
1537 modelIndexList
.clear();
1544 elementInfo
.relativeOffsetToCategory
= offset
;
1546 modelIndexList
<< index
;
1547 prevCategory
= lastCategory
;
1549 d
->elementsInfo
.insert(index
.row(), elementInfo
);
1552 d
->categoriesIndexes
.insert(prevCategory
, modelIndexList
);
1553 d
->categories
<< prevCategory
;
1555 d
->updateScrollbars();
1557 // FIXME: We need to safely save the last selection. This is on my TODO
1558 // list (ereslibre).
1559 selectionModel()->clear();
1562 void KCategorizedView::rowsRemoved(const QModelIndex
&parent
,
1566 if (d
->proxyModel
&& d
->categoryDrawer
&& d
->proxyModel
->isCategorizedModel())
1568 // Force the view to update all elements
1569 rowsInsertedArtifficial(QModelIndex(), 0, d
->proxyModel
->rowCount() - 1);
1573 void KCategorizedView::updateGeometries()
1575 if (!d
->proxyModel
|| !d
->categoryDrawer
|| !d
->proxyModel
->isCategorizedModel())
1577 QListView::updateGeometries();
1581 // Avoid QListView::updateGeometries(), since it will try to set another
1582 // range to our scroll bars, what we don't want (ereslibre)
1583 QAbstractItemView::updateGeometries();
1586 void KCategorizedView::slotLayoutChanged()
1591 void KCategorizedView::currentChanged(const QModelIndex
¤t
,
1592 const QModelIndex
&previous
)
1594 // We need to update the forcedSelectionPosition property in order to correctly
1595 // navigate after with keyboard using up & down keys
1597 int viewportWidth
= viewport()->width() - spacing();
1602 if (gridSize().isEmpty())
1604 itemHeight
= d
->biggestItemSize
.height();
1605 itemWidth
= d
->biggestItemSize
.width();
1609 itemHeight
= gridSize().height();
1610 itemWidth
= gridSize().width();
1613 int itemWidthPlusSeparation
= spacing() + itemWidth
;
1614 if (!itemWidthPlusSeparation
)
1615 itemWidthPlusSeparation
++;
1616 int elementsPerRow
= viewportWidth
/ itemWidthPlusSeparation
;
1617 if (!elementsPerRow
)
1620 if (d
->mouseButtonPressed
|| d
->rightMouseButtonPressed
)
1621 d
->forcedSelectionPosition
= d
->elementsInfo
[current
.row()].relativeOffsetToCategory
% elementsPerRow
;
1623 QListView::currentChanged(current
, previous
);
1626 #include "kcategorizedview.moc"