2 * This file is part of the KDE project
3 * Copyright (C) 2007 Rafael Fernández López <ereslibre@gmail.com>
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 "klistview.h"
22 #include "klistview_p.h"
24 #include <math.h> // trunc on C99 compliant systems
25 #include <kdefakes.h> // trunc for not C99 compliant systems
27 #include <QApplication>
30 #include <QPaintEvent>
35 #include "kitemcategorizer.h"
36 #include "ksortfilterproxymodel.h"
47 inline LessThan(const KSortFilterProxyModel
*proxyModel
,
49 : proxyModel(proxyModel
)
54 inline bool operator()(const QModelIndex
&left
,
55 const QModelIndex
&right
) const
57 if (purpose
== GeneralPurpose
)
59 return proxyModel
->sortOrder() == Qt::AscendingOrder
?
60 proxyModel
->lessThanGeneralPurpose(left
, right
) :
61 !proxyModel
->lessThanGeneralPurpose(left
, right
);
64 return proxyModel
->sortOrder() == Qt::AscendingOrder
?
65 proxyModel
->lessThanCategoryPurpose(left
, right
) :
66 !proxyModel
->lessThanCategoryPurpose(left
, right
);
70 const KSortFilterProxyModel
*proxyModel
;
71 const Purpose purpose
;
75 //==============================================================================
78 KListView::Private::Private(KListView
*listView
)
81 , mouseButtonPressed(false)
83 , dragLeftViewport(false)
85 , lastIndex(QModelIndex())
89 KListView::Private::~Private()
93 const QModelIndexList
&KListView::Private::intersectionSet(const QRect
&rect
)
96 QRect indexVisualRect
;
98 intersectedIndexes
.clear();
100 // Lets find out where we should start
101 int top
= proxyModel
->rowCount() - 1;
103 int middle
= (top
+ bottom
) / 2;
104 while (bottom
<= top
)
106 middle
= (top
+ bottom
) / 2;
108 index
= elementDictionary
[proxyModel
->index(middle
, 0)];
109 indexVisualRect
= visualRect(index
);
111 if (qMax(indexVisualRect
.topLeft().y(),
112 indexVisualRect
.bottomRight().y()) < qMin(rect
.topLeft().y(),
113 rect
.bottomRight().y()))
123 for (int i
= middle
; i
< proxyModel
->rowCount(); i
++)
125 index
= elementDictionary
[proxyModel
->index(i
, 0)];
126 indexVisualRect
= visualRect(index
);
128 if (rect
.intersects(indexVisualRect
))
129 intersectedIndexes
.append(index
);
131 // If we passed next item, stop searching for hits
132 if (qMax(rect
.bottomRight().y(), rect
.topLeft().y()) <
133 qMin(indexVisualRect
.topLeft().y(),
134 indexVisualRect
.bottomRight().y()))
138 return intersectedIndexes
;
141 QRect
KListView::Private::visualRectInViewport(const QModelIndex
&index
) const
143 if (!index
.isValid())
146 QString curCategory
= elementsInfo
[index
].category
;
148 QRect
retRect(listView
->spacing(), listView
->spacing() * 2 +
149 30 /* categoryHeight */, 0, 0);
151 int viewportWidth
= listView
->viewport()->width() - listView
->spacing();
153 // We really need all items to be of same size. Otherwise we cannot do this
156 // listView->sizeHintForIndex(proxyModel->mapFromSource(index));
157 // int itemHeight = itemSize.height();
158 // int itemWidth = itemSize.width();*/
159 int itemHeight
= 107;
161 int itemWidthPlusSeparation
= listView
->spacing() + itemWidth
;
162 int elementsPerRow
= viewportWidth
/ itemWidthPlusSeparation
;
166 int column
= elementsInfo
[index
].relativeOffsetToCategory
% elementsPerRow
;
167 int row
= elementsInfo
[index
].relativeOffsetToCategory
/ elementsPerRow
;
169 retRect
.setLeft(retRect
.left() + column
* listView
->spacing() +
172 foreach (const QString
&category
, categories
)
174 if (category
== curCategory
)
177 float rows
= (float) ((float) categoriesIndexes
[category
].count() /
178 (float) elementsPerRow
);
179 int rowsInt
= categoriesIndexes
[category
].count() / elementsPerRow
;
181 if (rows
- trunc(rows
)) rowsInt
++;
183 retRect
.setTop(retRect
.top() +
184 (rowsInt
* listView
->spacing()) +
185 (rowsInt
* itemHeight
) +
186 30 /* categoryHeight */ +
187 listView
->spacing() * 2);
190 retRect
.setTop(retRect
.top() + row
* listView
->spacing() +
193 retRect
.setWidth(itemWidth
);
194 retRect
.setHeight(itemHeight
);
199 QRect
KListView::Private::visualCategoryRectInViewport(const QString
&category
)
202 QRect
retRect(listView
->spacing(),
204 listView
->viewport()->width() - listView
->spacing() * 2,
207 if (!proxyModel
->rowCount() || !categories
.contains(category
))
210 QModelIndex index
= proxyModel
->index(0, 0, QModelIndex());
212 int viewportWidth
= listView
->viewport()->width() - listView
->spacing();
214 // We really need all items to be of same size. Otherwise we cannot do this
216 // QSize itemSize = listView->sizeHintForIndex(index);
217 // int itemHeight = itemSize.height();
218 // int itemWidth = itemSize.width();
219 int itemHeight
= 107;
221 int itemWidthPlusSeparation
= listView
->spacing() + itemWidth
;
222 int elementsPerRow
= viewportWidth
/ itemWidthPlusSeparation
;
227 foreach (const QString
&itCategory
, categories
)
229 if (itCategory
== category
)
232 float rows
= (float) ((float) categoriesIndexes
[itCategory
].count() /
233 (float) elementsPerRow
);
234 int rowsInt
= categoriesIndexes
[itCategory
].count() / elementsPerRow
;
236 if (rows
- trunc(rows
)) rowsInt
++;
238 retRect
.setTop(retRect
.top() +
239 (rowsInt
* listView
->spacing()) +
240 (rowsInt
* itemHeight
) +
241 30 /* categoryHeight */ +
242 listView
->spacing() * 2);
245 retRect
.setHeight(30 /* categoryHeight */);
250 // We're sure elementsPosition doesn't contain index
251 const QRect
&KListView::Private::cacheIndex(const QModelIndex
&index
)
253 QRect rect
= visualRectInViewport(index
);
254 elementsPosition
[index
] = rect
;
256 return elementsPosition
[index
];
259 // We're sure categoriesPosition doesn't contain category
260 const QRect
&KListView::Private::cacheCategory(const QString
&category
)
262 QRect rect
= visualCategoryRectInViewport(category
);
263 categoriesPosition
[category
] = rect
;
265 return categoriesPosition
[category
];
268 const QRect
&KListView::Private::cachedRectIndex(const QModelIndex
&index
)
270 if (elementsPosition
.contains(index
)) // If we have it cached
272 return elementsPosition
[index
];
274 else // Otherwise, cache it
276 return cacheIndex(index
);
280 const QRect
&KListView::Private::cachedRectCategory(const QString
&category
)
282 if (categoriesPosition
.contains(category
)) // If we have it cached
284 return categoriesPosition
[category
];
286 else // Otherwise, cache it and
288 return cacheCategory(category
);
292 QRect
KListView::Private::visualRect(const QModelIndex
&index
)
294 QModelIndex mappedIndex
= proxyModel
->mapToSource(index
);
296 QRect retRect
= cachedRectIndex(mappedIndex
);
297 int dx
= -listView
->horizontalOffset();
298 int dy
= -listView
->verticalOffset();
299 retRect
.adjust(dx
, dy
, dx
, dy
);
304 QRect
KListView::Private::categoryVisualRect(const QString
&category
)
306 QRect retRect
= cachedRectCategory(category
);
307 int dx
= -listView
->horizontalOffset();
308 int dy
= -listView
->verticalOffset();
309 retRect
.adjust(dx
, dy
, dx
, dy
);
314 void KListView::Private::drawNewCategory(const QString
&category
,
315 const QStyleOption
&option
,
318 QColor color
= option
.palette
.color(QPalette::Text
);
321 painter
->setRenderHint(QPainter::Antialiasing
);
323 QStyleOptionButton opt
;
325 opt
.rect
= option
.rect
;
326 opt
.palette
= option
.palette
;
327 opt
.direction
= option
.direction
;
330 if ((category
== hoveredCategory
) && !mouseButtonPressed
)
332 const QPalette::ColorGroup group
=
333 option
.state
& QStyle::State_Enabled
?
334 QPalette::Normal
: QPalette::Disabled
;
336 QLinearGradient
gradient(option
.rect
.topLeft(),
337 option
.rect
.bottomRight());
338 gradient
.setColorAt(0,
339 option
.palette
.color(group
,
340 QPalette::Highlight
).light());
341 gradient
.setColorAt(1, Qt::transparent
);
343 painter
->fillRect(option
.rect
, gradient
);
346 /*if (const KStyle *style = dynamic_cast<const KStyle*>(QApplication::style()))
348 style->drawControl(KStyle::CE_Category, &opt, painter, this);
352 QFont painterFont
= painter
->font();
353 painterFont
.setWeight(QFont::Bold
);
354 QFontMetrics
metrics(painterFont
);
355 painter
->setFont(painterFont
);
358 path
.addRect(option
.rect
.left(),
359 option
.rect
.bottom() - 2,
363 QLinearGradient
gradient(option
.rect
.topLeft(),
364 option
.rect
.bottomRight());
365 gradient
.setColorAt(0, color
);
366 gradient
.setColorAt(1, Qt::transparent
);
368 painter
->setBrush(gradient
);
369 painter
->fillPath(path
, gradient
);
371 painter
->setPen(color
);
373 painter
->drawText(option
.rect
, Qt::AlignVCenter
| Qt::AlignLeft
,
374 metrics
.elidedText(category
, Qt::ElideRight
, option
.rect
.width()));
380 void KListView::Private::updateScrollbars()
382 int lastItemBottom
= cachedRectIndex(lastIndex
).bottom() +
383 listView
->spacing() - listView
->viewport()->height();
385 listView
->verticalScrollBar()->setSingleStep(listView
->viewport()->height() / 10);
386 listView
->verticalScrollBar()->setPageStep(listView
->viewport()->height());
387 listView
->verticalScrollBar()->setRange(0, lastItemBottom
);
390 void KListView::Private::drawDraggedItems(QPainter
*painter
)
392 QStyleOptionViewItemV3 option
= listView
->viewOptions();
393 option
.state
&= ~QStyle::State_MouseOver
;
394 foreach (const QModelIndex
&index
, listView
->selectionModel()->selectedIndexes())
396 const int dx
= mousePosition
.x() - initialPressPosition
.x() + listView
->horizontalOffset();
397 const int dy
= mousePosition
.y() - initialPressPosition
.y() + listView
->verticalOffset();
399 option
.rect
= visualRect(index
);
400 option
.rect
.adjust(dx
, dy
, dx
, dy
);
402 if (option
.rect
.intersects(listView
->viewport()->rect()))
404 listView
->itemDelegate(index
)->paint(painter
, option
, index
);
409 void KListView::Private::drawDraggedItems()
413 foreach (const QModelIndex
&index
, listView
->selectionModel()->selectedIndexes())
415 int dx
= mousePosition
.x() - initialPressPosition
.x() + listView
->horizontalOffset();
416 int dy
= mousePosition
.y() - initialPressPosition
.y() + listView
->verticalOffset();
418 currentRect
= visualRect(index
);
419 currentRect
.adjust(dx
, dy
, dx
, dy
);
421 if (currentRect
.intersects(listView
->viewport()->rect()))
423 rectToUpdate
= rectToUpdate
.united(currentRect
);
427 listView
->viewport()->update(lastDraggedItemsRect
);
429 lastDraggedItemsRect
= rectToUpdate
;
431 listView
->viewport()->update(rectToUpdate
);
435 //==============================================================================
438 KListView::KListView(QWidget
*parent
)
440 , d(new Private(this))
444 KListView::~KListView()
449 void KListView::setModel(QAbstractItemModel
*model
)
453 QObject::disconnect(d
->proxyModel
,
454 SIGNAL(rowsRemoved(QModelIndex
,int,int)),
455 this, SLOT(rowsRemoved(QModelIndex
,int,int)));
457 QObject::disconnect(d
->proxyModel
,
458 SIGNAL(sortingRoleChanged()),
459 this, SLOT(slotSortingRoleChanged()));
462 QListView::setModel(model
);
464 d
->proxyModel
= dynamic_cast<KSortFilterProxyModel
*>(model
);
468 QObject::connect(d
->proxyModel
,
469 SIGNAL(rowsRemoved(QModelIndex
,int,int)),
470 this, SLOT(rowsRemoved(QModelIndex
,int,int)));
472 QObject::connect(d
->proxyModel
,
473 SIGNAL(sortingRoleChanged()),
474 this, SLOT(slotSortingRoleChanged()));
478 QRect
KListView::visualRect(const QModelIndex
&index
) const
480 if ((viewMode() != KListView::IconMode
) || !d
->proxyModel
||
483 return QListView::visualRect(index
);
486 if (!qobject_cast
<const QSortFilterProxyModel
*>(index
.model()))
488 return d
->visualRect(d
->proxyModel
->mapFromSource(index
));
491 return d
->visualRect(index
);
494 KItemCategorizer
*KListView::itemCategorizer() const
496 return d
->itemCategorizer
;
499 void KListView::setItemCategorizer(KItemCategorizer
*itemCategorizer
)
501 if (!itemCategorizer
&& d
->proxyModel
)
503 QObject::disconnect(d
->proxyModel
,
504 SIGNAL(rowsRemoved(QModelIndex
,int,int)),
505 this, SLOT(rowsRemoved(QModelIndex
,int,int)));
507 QObject::disconnect(d
->proxyModel
,
508 SIGNAL(sortingRoleChanged()),
509 this, SLOT(slotSortingRoleChanged()));
511 else if (itemCategorizer
&& d
->proxyModel
)
513 QObject::connect(d
->proxyModel
,
514 SIGNAL(rowsRemoved(QModelIndex
,int,int)),
515 this, SLOT(rowsRemoved(QModelIndex
,int,int)));
517 QObject::connect(d
->proxyModel
,
518 SIGNAL(sortingRoleChanged()),
519 this, SLOT(slotSortingRoleChanged()));
522 d
->itemCategorizer
= itemCategorizer
;
526 rowsInserted(QModelIndex(), 0, d
->proxyModel
->rowCount() - 1);
534 QModelIndex
KListView::indexAt(const QPoint
&point
) const
536 if ((viewMode() != KListView::IconMode
) || !d
->proxyModel
||
539 return QListView::indexAt(point
);
544 QModelIndexList item
= d
->intersectionSet(QRect(point
, point
));
546 if (item
.count() == 1)
556 void KListView::reset()
560 if ((viewMode() != KListView::IconMode
) || !d
->proxyModel
||
566 d
->elementsInfo
.clear();
567 d
->elementsPosition
.clear();
568 d
->elementDictionary
.clear();
569 d
->categoriesIndexes
.clear();
570 d
->categoriesPosition
.clear();
571 d
->categories
.clear();
572 d
->intersectedIndexes
.clear();
573 d
->sourceModelIndexList
.clear();
574 d
->hovered
= QModelIndex();
575 d
->mouseButtonPressed
= false;
578 void KListView::paintEvent(QPaintEvent
*event
)
580 if ((viewMode() != KListView::IconMode
) || !d
->proxyModel
||
583 QListView::paintEvent(event
);
587 QStyleOptionViewItemV3 option
= viewOptions();
588 QPainter
painter(viewport());
589 QRect area
= event
->rect();
590 const bool focus
= (hasFocus() || viewport()->hasFocus()) &&
591 currentIndex().isValid();
592 const QStyle::State state
= option
.state
;
593 const bool enabled
= (state
& QStyle::State_Enabled
) != 0;
597 QModelIndexList dirtyIndexes
= d
->intersectionSet(area
);
598 foreach (const QModelIndex
&index
, dirtyIndexes
)
600 option
.state
= state
;
601 option
.rect
= d
->visualRect(index
);
603 if (selectionModel() && selectionModel()->isSelected(index
))
605 option
.state
|= QStyle::State_Selected
;
610 QPalette::ColorGroup cg
;
611 if ((d
->proxyModel
->flags(index
) & Qt::ItemIsEnabled
) == 0)
613 option
.state
&= ~QStyle::State_Enabled
;
614 cg
= QPalette::Disabled
;
618 cg
= QPalette::Normal
;
620 option
.palette
.setCurrentColorGroup(cg
);
623 if (focus
&& currentIndex() == index
)
625 option
.state
|= QStyle::State_HasFocus
;
626 if (this->state() == EditingState
)
627 option
.state
|= QStyle::State_Editing
;
630 if ((index
== d
->hovered
) && !d
->mouseButtonPressed
)
631 option
.state
|= QStyle::State_MouseOver
;
633 option
.state
&= ~QStyle::State_MouseOver
;
635 itemDelegate(index
)->paint(&painter
, option
, index
);
638 if (d
->mouseButtonPressed
&& !d
->isDragging
)
640 QPoint start
, end
, initialPressPosition
;
642 initialPressPosition
= d
->initialPressPosition
;
644 initialPressPosition
.setY(initialPressPosition
.y() - verticalOffset());
645 initialPressPosition
.setX(initialPressPosition
.x() - horizontalOffset());
647 if (d
->initialPressPosition
.x() > d
->mousePosition
.x() ||
648 d
->initialPressPosition
.y() > d
->mousePosition
.y())
650 start
= d
->mousePosition
;
651 end
= initialPressPosition
;
655 start
= initialPressPosition
;
656 end
= d
->mousePosition
;
659 QStyleOptionRubberBand yetAnotherOption
;
660 yetAnotherOption
.initFrom(this);
661 yetAnotherOption
.shape
= QRubberBand::Rectangle
;
662 yetAnotherOption
.opaque
= false;
663 yetAnotherOption
.rect
= QRect(start
, end
).intersected(viewport()->rect().adjusted(-16, -16, 16, 16));
665 style()->drawControl(QStyle::CE_RubberBand
, &yetAnotherOption
, &painter
);
670 QStyleOptionViewItem otherOption
;
671 foreach (const QString
&category
, d
->categories
)
673 otherOption
= option
;
674 otherOption
.rect
= d
->categoryVisualRect(category
);
676 if (otherOption
.rect
.intersects(area
))
678 d
->drawNewCategory(category
, otherOption
, &painter
);
682 if (d
->isDragging
&& !d
->dragLeftViewport
)
684 painter
.setOpacity(0.5);
685 d
->drawDraggedItems(&painter
);
691 void KListView::resizeEvent(QResizeEvent
*event
)
693 QListView::resizeEvent(event
);
695 if ((viewMode() != KListView::IconMode
) || !d
->proxyModel
||
701 // Clear the items positions cache
702 d
->elementsPosition
.clear();
703 d
->categoriesPosition
.clear();
705 d
->updateScrollbars();
708 void KListView::setSelection(const QRect
&rect
,
709 QItemSelectionModel::SelectionFlags flags
)
711 if ((viewMode() != KListView::IconMode
) || !d
->proxyModel
||
714 QListView::setSelection(rect
, flags
);
721 selectionModel()->clear();
723 if (flags
& QItemSelectionModel::Clear
)
725 d
->lastSelection
= QItemSelection();
728 QModelIndexList dirtyIndexes
= d
->intersectionSet(rect
);
729 QItemSelection selection
;
731 if (!dirtyIndexes
.count())
733 if (d
->lastSelection
.count())
735 selectionModel()->select(d
->lastSelection
, flags
);
741 if (!d
->mouseButtonPressed
)
743 selection
= QItemSelection(dirtyIndexes
[0], dirtyIndexes
[0]);
747 QModelIndex first
= dirtyIndexes
[0];
749 foreach (const QModelIndex
&index
, dirtyIndexes
)
751 if (last
.isValid() && last
.row() + 1 != index
.row())
753 QItemSelectionRange
range(first
, last
);
764 selection
<< QItemSelectionRange(first
, last
);
767 if (d
->lastSelection
.count() && !d
->mouseButtonPressed
)
769 selection
.merge(d
->lastSelection
, flags
);
771 else if (d
->lastSelection
.count())
773 selection
.merge(d
->lastSelection
, QItemSelectionModel::Select
);
776 selectionModel()->select(selection
, flags
);
779 void KListView::mouseMoveEvent(QMouseEvent
*event
)
781 QListView::mouseMoveEvent(event
);
783 if ((viewMode() != KListView::IconMode
) || !d
->proxyModel
||
789 d
->mousePosition
= event
->pos();
790 d
->hoveredCategory
= QString();
793 foreach (const QString
&category
, d
->categories
)
795 if (d
->categoryVisualRect(category
).intersects(QRect(event
->pos(), event
->pos())))
797 d
->hoveredCategory
= category
;
800 viewport()->update(d
->categoryVisualRect(category
));
804 if (d
->mouseButtonPressed
&& !d
->isDragging
)
806 QPoint start
, end
, initialPressPosition
;
808 initialPressPosition
= d
->initialPressPosition
;
810 initialPressPosition
.setY(initialPressPosition
.y() - verticalOffset());
811 initialPressPosition
.setX(initialPressPosition
.x() - horizontalOffset());
813 if (d
->initialPressPosition
.x() > d
->mousePosition
.x() ||
814 d
->initialPressPosition
.y() > d
->mousePosition
.y())
816 start
= d
->mousePosition
;
817 end
= initialPressPosition
;
821 start
= initialPressPosition
;
822 end
= d
->mousePosition
;
825 viewport()->update(d
->lastSelectionRect
);
827 rect
= QRect(start
, end
).intersected(viewport()->rect().adjusted(-16, -16, 16, 16));
829 viewport()->update(rect
);
831 d
->lastSelectionRect
= rect
;
835 void KListView::mousePressEvent(QMouseEvent
*event
)
837 QListView::mousePressEvent(event
);
839 if ((viewMode() != KListView::IconMode
) || !d
->proxyModel
||
845 d
->dragLeftViewport
= false;
847 if (event
->button() == Qt::LeftButton
)
849 d
->mouseButtonPressed
= true;
851 d
->initialPressPosition
= event
->pos();
852 d
->initialPressPosition
.setY(d
->initialPressPosition
.y() +
854 d
->initialPressPosition
.setX(d
->initialPressPosition
.x() +
859 void KListView::mouseReleaseEvent(QMouseEvent
*event
)
861 QListView::mouseReleaseEvent(event
);
863 if ((viewMode() != KListView::IconMode
) || !d
->proxyModel
||
869 d
->mouseButtonPressed
= false;
871 QPoint initialPressPosition
= viewport()->mapFromGlobal(QCursor::pos());
872 initialPressPosition
.setY(initialPressPosition
.y() + verticalOffset());
873 initialPressPosition
.setX(initialPressPosition
.x() + horizontalOffset());
875 QItemSelection selection
;
877 if (initialPressPosition
== d
->initialPressPosition
)
879 foreach(const QString
&category
, d
->categories
)
881 if (d
->categoryVisualRect(category
).contains(event
->pos()))
883 QItemSelectionRange
selectionRange(d
->proxyModel
->mapFromSource(d
->categoriesIndexes
[category
][0]),
884 d
->proxyModel
->mapFromSource(d
->categoriesIndexes
[category
][d
->categoriesIndexes
[category
].count() - 1]));
886 selection
<< selectionRange
;
888 selectionModel()->select(selection
, QItemSelectionModel::Select
);
895 d
->lastSelection
= selectionModel()->selection();
897 if (d
->hovered
.isValid())
898 viewport()->update(d
->visualRect(d
->hovered
));
899 else if (!d
->hoveredCategory
.isEmpty())
900 viewport()->update(d
->categoryVisualRect(d
->hoveredCategory
));
903 void KListView::leaveEvent(QEvent
*event
)
905 QListView::leaveEvent(event
);
907 if ((viewMode() != KListView::IconMode
) || !d
->proxyModel
||
913 d
->hovered
= QModelIndex();
914 d
->hoveredCategory
= QString();
917 void KListView::startDrag(Qt::DropActions supportedActions
)
919 QListView::startDrag(supportedActions
);
921 d
->isDragging
= false;
922 d
->mouseButtonPressed
= false;
925 void KListView::dragMoveEvent(QDragMoveEvent
*event
)
927 if ((viewMode() != KListView::IconMode
) || !d
->proxyModel
||
930 QListView::dragMoveEvent(event
);
934 d
->mousePosition
= event
->pos();
936 if (d
->mouseButtonPressed
)
938 d
->isDragging
= true;
942 d
->isDragging
= false;
945 d
->dragLeftViewport
= false;
947 d
->drawDraggedItems();
950 void KListView::dragLeaveEvent(QDragLeaveEvent
*event
)
952 QListView::dragLeaveEvent(event
);
954 if ((viewMode() != KListView::IconMode
) || !d
->proxyModel
||
960 d
->dragLeftViewport
= true;
963 QModelIndex
KListView::moveCursor(CursorAction cursorAction
,
964 Qt::KeyboardModifiers modifiers
)
966 if ((viewMode() != KListView::IconMode
) || !d
->proxyModel
||
969 return QListView::moveCursor(cursorAction
, modifiers
);
972 return QListView::moveCursor(cursorAction
, modifiers
);
975 void KListView::rowsInserted(const QModelIndex
&parent
,
979 QListView::rowsInserted(parent
, start
, end
);
981 if ((viewMode() != KListView::IconMode
) || !d
->proxyModel
||
987 rowsInsertedArtifficial(parent
, start
, end
);
990 void KListView::rowsInsertedArtifficial(const QModelIndex
&parent
,
996 d
->lastSelection
= QItemSelection();
997 d
->elementsInfo
.clear();
998 d
->elementsPosition
.clear();
999 d
->elementDictionary
.clear();
1000 d
->categoriesIndexes
.clear();
1001 d
->categoriesPosition
.clear();
1002 d
->categories
.clear();
1003 d
->intersectedIndexes
.clear();
1004 d
->sourceModelIndexList
.clear();
1005 d
->hovered
= QModelIndex();
1006 d
->mouseButtonPressed
= false;
1008 if (start
> end
|| end
< 0 || start
< 0 || !d
->proxyModel
->rowCount())
1013 // Add all elements mapped to the source model
1014 for (int k
= 0; k
< d
->proxyModel
->rowCount(); k
++)
1016 d
->sourceModelIndexList
<<
1017 d
->proxyModel
->mapToSource(d
->proxyModel
->index(k
, 0));
1020 // Sort them with the general purpose lessThan method
1021 LessThan
generalLessThan(d
->proxyModel
,
1022 LessThan::GeneralPurpose
);
1024 qStableSort(d
->sourceModelIndexList
.begin(), d
->sourceModelIndexList
.end(),
1027 // Explore categories
1028 QString prevCategory
=
1029 d
->itemCategorizer
->categoryForItem(d
->sourceModelIndexList
[0],
1030 d
->proxyModel
->sortRole());
1031 QString lastCategory
= prevCategory
;
1032 QModelIndexList modelIndexList
;
1033 struct Private::ElementInfo elementInfo
;
1034 foreach (const QModelIndex
&index
, d
->sourceModelIndexList
)
1036 lastCategory
= d
->itemCategorizer
->categoryForItem(index
,
1037 d
->proxyModel
->sortRole());
1039 elementInfo
.category
= lastCategory
;
1041 if (prevCategory
!= lastCategory
)
1043 d
->categoriesIndexes
.insert(prevCategory
, modelIndexList
);
1044 d
->categories
<< prevCategory
;
1045 modelIndexList
.clear();
1048 modelIndexList
<< index
;
1049 prevCategory
= lastCategory
;
1051 d
->elementsInfo
.insert(index
, elementInfo
);
1054 d
->categoriesIndexes
.insert(prevCategory
, modelIndexList
);
1055 d
->categories
<< prevCategory
;
1057 // Sort items locally in their respective categories with the category
1059 LessThan
categoryLessThan(d
->proxyModel
,
1060 LessThan::CategoryPurpose
);
1062 foreach (const QString
&key
, d
->categories
)
1064 QModelIndexList
&indexList
= d
->categoriesIndexes
[key
];
1066 qStableSort(indexList
.begin(), indexList
.end(), categoryLessThan
);
1069 d
->lastIndex
= d
->categoriesIndexes
[d
->categories
[d
->categories
.count() - 1]][d
->categoriesIndexes
[d
->categories
[d
->categories
.count() - 1]].count() - 1];
1071 // Finally, fill data information of items situation. This will help when
1072 // trying to compute an item place in the viewport
1073 int i
= 0; // position relative to the category beginning
1074 int j
= 0; // number of elements before current
1075 foreach (const QString
&key
, d
->categories
)
1077 foreach (const QModelIndex
&index
, d
->categoriesIndexes
[key
])
1079 struct Private::ElementInfo
&elementInfo
= d
->elementsInfo
[index
];
1081 elementInfo
.relativeOffsetToCategory
= i
;
1083 d
->elementDictionary
.insert(d
->proxyModel
->index(j
, 0),
1084 d
->proxyModel
->mapFromSource(index
));
1093 d
->updateScrollbars();
1096 void KListView::rowsRemoved(const QModelIndex
&parent
,
1100 if ((viewMode() == KListView::IconMode
) && d
->proxyModel
&&
1103 // Force the view to update all elements
1104 rowsInsertedArtifficial(parent
, start
, end
);
1108 void KListView::updateGeometries()
1110 if ((viewMode() != KListView::IconMode
) || !d
->proxyModel
||
1111 !d
->itemCategorizer
)
1113 QListView::updateGeometries();
1117 // Avoid QListView::updateGeometries(), since it will try to set another
1118 // range to our scroll bars, what we don't want (ereslibre)
1119 QAbstractItemView::updateGeometries();
1122 void KListView::slotSortingRoleChanged()
1124 if ((viewMode() == KListView::IconMode
) && d
->proxyModel
&&
1127 // Force the view to update all elements
1128 rowsInsertedArtifficial(QModelIndex(), 0, d
->proxyModel
->rowCount() - 1);
1132 #include "klistview.moc"