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 , lastIndex(QModelIndex())
87 KListView::Private::~Private()
91 const QModelIndexList
&KListView::Private::intersectionSet(const QRect
&rect
)
94 QRect indexVisualRect
;
96 intersectedIndexes
.clear();
98 // Lets find out where we should start
99 int top
= proxyModel
->rowCount() - 1;
101 int middle
= (top
+ bottom
) / 2;
102 while (bottom
<= top
)
104 middle
= (top
+ bottom
) / 2;
106 index
= elementDictionary
[proxyModel
->index(middle
, 0)];
107 indexVisualRect
= visualRect(index
);
109 if (qMax(indexVisualRect
.topLeft().y(),
110 indexVisualRect
.bottomRight().y()) < qMin(rect
.topLeft().y(),
111 rect
.bottomRight().y()))
122 for (int i
= middle
; i
< proxyModel
->rowCount(); i
++)
124 index
= elementDictionary
[proxyModel
->index(i
, 0)];
125 indexVisualRect
= visualRect(index
);
127 if (rect
.intersects(indexVisualRect
))
128 intersectedIndexes
.append(index
);
130 // If we passed next item, stop searching for hits
131 if (qMax(rect
.bottomRight().y(), rect
.topLeft().y()) <
132 indexVisualRect
.topLeft().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() +
174 foreach (const QString
&category
, categories
)
176 if (category
== curCategory
)
179 rows
= (float) ((float) categoriesIndexes
[category
].count() /
180 (float) elementsPerRow
);
181 rowsInt
= categoriesIndexes
[category
].count() / elementsPerRow
;
183 if (rows
- trunc(rows
)) rowsInt
++;
185 retRect
.setTop(retRect
.top() +
186 (rowsInt
* listView
->spacing()) +
187 (rowsInt
* itemHeight
) +
188 30 /* categoryHeight */ +
189 listView
->spacing() * 2);
192 retRect
.setTop(retRect
.top() + row
* listView
->spacing() +
195 retRect
.setWidth(itemWidth
);
196 retRect
.setHeight(itemHeight
);
201 QRect
KListView::Private::visualCategoryRectInViewport(const QString
&category
)
204 QRect
retRect(listView
->spacing(),
206 listView
->viewport()->width() - listView
->spacing() * 2,
209 if (!proxyModel
->rowCount() || !categories
.contains(category
))
212 QModelIndex index
= proxyModel
->index(0, 0, QModelIndex());
214 int viewportWidth
= listView
->viewport()->width() - listView
->spacing();
216 // We really need all items to be of same size. Otherwise we cannot do this
218 // QSize itemSize = listView->sizeHintForIndex(index);
219 // int itemHeight = itemSize.height();
220 // int itemWidth = itemSize.width();
221 int itemHeight
= 107;
223 int itemWidthPlusSeparation
= listView
->spacing() + itemWidth
;
224 int elementsPerRow
= viewportWidth
/ itemWidthPlusSeparation
;
231 foreach (const QString
&itCategory
, categories
)
233 if (itCategory
== category
)
236 rows
= (float) ((float) categoriesIndexes
[itCategory
].count() /
237 (float) elementsPerRow
);
238 rowsInt
= categoriesIndexes
[itCategory
].count() / elementsPerRow
;
240 if (rows
- trunc(rows
)) rowsInt
++;
242 retRect
.setTop(retRect
.top() +
243 (rowsInt
* listView
->spacing()) +
244 (rowsInt
* itemHeight
) +
245 30 /* categoryHeight */ +
246 listView
->spacing() * 2);
249 retRect
.setHeight(30 /* categoryHeight */);
254 // We're sure elementsPosition doesn't contain index
255 const QRect
&KListView::Private::cacheIndex(const QModelIndex
&index
)
257 QRect rect
= visualRectInViewport(index
);
258 elementsPosition
[index
] = rect
;
260 return elementsPosition
[index
];
263 // We're sure categoriesPosition doesn't contain category
264 const QRect
&KListView::Private::cacheCategory(const QString
&category
)
266 QRect rect
= visualCategoryRectInViewport(category
);
267 categoriesPosition
[category
] = rect
;
269 return categoriesPosition
[category
];
272 const QRect
&KListView::Private::cachedRectIndex(const QModelIndex
&index
)
274 if (elementsPosition
.contains(index
)) // If we have it cached
276 return elementsPosition
[index
];
278 else // Otherwise, cache it
280 return cacheIndex(index
);
284 const QRect
&KListView::Private::cachedRectCategory(const QString
&category
)
286 if (categoriesPosition
.contains(category
)) // If we have it cached
288 return categoriesPosition
[category
];
290 else // Otherwise, cache it and
292 return cacheCategory(category
);
296 QRect
KListView::Private::visualRect(const QModelIndex
&index
)
298 QModelIndex mappedIndex
= proxyModel
->mapToSource(index
);
300 QRect retRect
= cachedRectIndex(mappedIndex
);
301 int dx
= -listView
->horizontalOffset();
302 int dy
= -listView
->verticalOffset();
303 retRect
.adjust(dx
, dy
, dx
, dy
);
308 QRect
KListView::Private::categoryVisualRect(const QString
&category
)
310 QRect retRect
= cachedRectCategory(category
);
311 int dx
= -listView
->horizontalOffset();
312 int dy
= -listView
->verticalOffset();
313 retRect
.adjust(dx
, dy
, dx
, dy
);
318 void KListView::Private::drawNewCategory(const QString
&category
,
319 const QStyleOption
&option
,
322 QColor color
= option
.palette
.color(QPalette::Text
);
325 painter
->setRenderHint(QPainter::Antialiasing
);
327 QStyleOptionButton opt
;
329 opt
.rect
= option
.rect
;
330 opt
.palette
= option
.palette
;
331 opt
.direction
= option
.direction
;
334 if (option
.rect
.contains(listView
->viewport()->mapFromGlobal(QCursor::pos())) &&
337 const QPalette::ColorGroup group
=
338 option
.state
& QStyle::State_Enabled
?
339 QPalette::Normal
: QPalette::Disabled
;
341 QLinearGradient
gradient(option
.rect
.topLeft(),
342 option
.rect
.bottomRight());
343 gradient
.setColorAt(0,
344 option
.palette
.color(group
,
345 QPalette::Highlight
).light());
346 gradient
.setColorAt(1, Qt::transparent
);
348 painter
->fillRect(option
.rect
, gradient
);
351 /*if (const KStyle *style = dynamic_cast<const KStyle*>(QApplication::style()))
353 style->drawControl(KStyle::CE_Category, &opt, painter, this);
357 QFont painterFont
= painter
->font();
358 painterFont
.setWeight(QFont::Bold
);
359 QFontMetrics
metrics(painterFont
);
360 painter
->setFont(painterFont
);
363 path
.addRect(option
.rect
.left(),
364 option
.rect
.bottom() - 2,
368 QLinearGradient
gradient(option
.rect
.topLeft(),
369 option
.rect
.bottomRight());
370 gradient
.setColorAt(0, color
);
371 gradient
.setColorAt(1, Qt::transparent
);
373 painter
->setBrush(gradient
);
374 painter
->fillPath(path
, gradient
);
376 painter
->setPen(color
);
378 painter
->drawText(option
.rect
, Qt::AlignVCenter
| Qt::AlignLeft
,
379 metrics
.elidedText(category
, Qt::ElideRight
, option
.rect
.width()));
385 void KListView::Private::updateScrollbars()
387 int lastItemBottom
= cachedRectIndex(lastIndex
).bottom() +
388 listView
->spacing() - listView
->viewport()->height();
390 listView
->verticalScrollBar()->setSingleStep(listView
->viewport()->height() / 10);
391 listView
->verticalScrollBar()->setPageStep(listView
->viewport()->height());
392 listView
->verticalScrollBar()->setRange(0, lastItemBottom
);
396 //==============================================================================
399 KListView::KListView(QWidget
*parent
)
401 , d(new Private(this))
405 KListView::~KListView()
410 void KListView::setModel(QAbstractItemModel
*model
)
414 QObject::disconnect(d
->proxyModel
,
415 SIGNAL(rowsRemoved(QModelIndex
,int,int)),
416 this, SLOT(rowsRemoved(QModelIndex
,int,int)));
418 QObject::disconnect(d
->proxyModel
,
419 SIGNAL(sortingRoleChanged()),
420 this, SLOT(slotSortingRoleChanged()));
423 QListView::setModel(model
);
425 d
->proxyModel
= dynamic_cast<KSortFilterProxyModel
*>(model
);
429 QObject::connect(d
->proxyModel
,
430 SIGNAL(rowsRemoved(QModelIndex
,int,int)),
431 this, SLOT(rowsRemoved(QModelIndex
,int,int)));
433 QObject::connect(d
->proxyModel
,
434 SIGNAL(sortingRoleChanged()),
435 this, SLOT(slotSortingRoleChanged()));
439 QRect
KListView::visualRect(const QModelIndex
&index
) const
441 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
444 return QListView::visualRect(index
);
447 if (!qobject_cast
<const QSortFilterProxyModel
*>(index
.model()))
449 return d
->visualRect(d
->proxyModel
->mapFromSource(index
));
452 return d
->visualRect(index
);
455 KItemCategorizer
*KListView::itemCategorizer() const
457 return d
->itemCategorizer
;
460 void KListView::setItemCategorizer(KItemCategorizer
*itemCategorizer
)
462 if (!itemCategorizer
&& d
->proxyModel
)
464 QObject::disconnect(d
->proxyModel
,
465 SIGNAL(rowsRemoved(QModelIndex
,int,int)),
466 this, SLOT(rowsRemoved(QModelIndex
,int,int)));
468 QObject::disconnect(d
->proxyModel
,
469 SIGNAL(sortingRoleChanged()),
470 this, SLOT(slotSortingRoleChanged()));
472 else if (itemCategorizer
&& d
->proxyModel
)
474 QObject::connect(d
->proxyModel
,
475 SIGNAL(rowsRemoved(QModelIndex
,int,int)),
476 this, SLOT(rowsRemoved(QModelIndex
,int,int)));
478 QObject::connect(d
->proxyModel
,
479 SIGNAL(sortingRoleChanged()),
480 this, SLOT(slotSortingRoleChanged()));
483 d
->itemCategorizer
= itemCategorizer
;
487 rowsInserted(QModelIndex(), 0, d
->proxyModel
->rowCount() - 1);
495 QModelIndex
KListView::indexAt(const QPoint
&point
) const
497 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
500 return QListView::indexAt(point
);
505 QModelIndexList item
= d
->intersectionSet(QRect(point
, point
));
507 if (item
.count() == 1)
517 void KListView::reset()
521 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
527 d
->elementsInfo
.clear();
528 d
->elementsPosition
.clear();
529 d
->elementDictionary
.clear();
530 d
->categoriesIndexes
.clear();
531 d
->categoriesPosition
.clear();
532 d
->isIndexSelected
.clear(); // selection cache
533 d
->categories
.clear();
534 d
->intersectedIndexes
.clear();
535 d
->sourceModelIndexList
.clear();
536 d
->hovered
= QModelIndex();
537 d
->mouseButtonPressed
= false;
540 void KListView::paintEvent(QPaintEvent
*event
)
542 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
545 QListView::paintEvent(event
);
549 QStyleOptionViewItemV3 option
= viewOptions();
550 QPainter
painter(viewport());
551 QRect area
= event
->rect();
552 const bool focus
= (hasFocus() || viewport()->hasFocus()) &&
553 currentIndex().isValid();
554 const QStyle::State state
= option
.state
;
555 const bool enabled
= (state
& QStyle::State_Enabled
) != 0;
559 QModelIndexList dirtyIndexes
= d
->intersectionSet(area
);
560 foreach (const QModelIndex
&index
, dirtyIndexes
)
562 option
.state
= state
;
563 option
.rect
= d
->visualRect(index
);
565 if (selectionModel() && selectionModel()->isSelected(index
))
567 option
.state
|= QStyle::State_Selected
;
572 QPalette::ColorGroup cg
;
573 if ((d
->proxyModel
->flags(index
) & Qt::ItemIsEnabled
) == 0)
575 option
.state
&= ~QStyle::State_Enabled
;
576 cg
= QPalette::Disabled
;
580 cg
= QPalette::Normal
;
582 option
.palette
.setCurrentColorGroup(cg
);
585 if (focus
&& currentIndex() == index
)
587 option
.state
|= QStyle::State_HasFocus
;
588 if (this->state() == EditingState
)
589 option
.state
|= QStyle::State_Editing
;
592 if ((index
== d
->hovered
) && !d
->mouseButtonPressed
)
593 option
.state
|= QStyle::State_MouseOver
;
595 option
.state
&= ~QStyle::State_MouseOver
;
597 itemDelegate(index
)->paint(&painter
, option
, index
);
601 QStyleOptionViewItem otherOption
;
602 foreach (const QString
&category
, d
->categories
)
604 otherOption
= option
;
605 otherOption
.rect
= d
->categoryVisualRect(category
);
607 if (otherOption
.rect
.intersects(area
))
609 d
->drawNewCategory(category
, otherOption
, &painter
);
613 if (d
->mouseButtonPressed
)
615 QPoint start
, end
, initialPressPosition
;
617 initialPressPosition
= d
->initialPressPosition
;
619 initialPressPosition
.setY(initialPressPosition
.y() - verticalOffset());
620 initialPressPosition
.setX(initialPressPosition
.x() - horizontalOffset());
622 if (d
->initialPressPosition
.x() > d
->mousePosition
.x() ||
623 d
->initialPressPosition
.y() > d
->mousePosition
.y())
625 start
= d
->mousePosition
;
626 end
= initialPressPosition
;
630 start
= initialPressPosition
;
631 end
= d
->mousePosition
;
634 QStyleOptionRubberBand yetAnotherOption
;
635 yetAnotherOption
.initFrom(this);
636 yetAnotherOption
.shape
= QRubberBand::Rectangle
;
637 yetAnotherOption
.opaque
= false;
638 yetAnotherOption
.rect
= QRect(start
, end
).intersected(viewport()->rect().adjusted(-16, -16, 16, 16));
640 style()->drawControl(QStyle::CE_RubberBand
, &yetAnotherOption
, &painter
);
647 void KListView::resizeEvent(QResizeEvent
*event
)
649 QListView::resizeEvent(event
);
651 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
657 // Clear the items positions cache
658 d
->elementsPosition
.clear();
659 d
->categoriesPosition
.clear();
661 d
->updateScrollbars();
664 void KListView::setSelection(const QRect
&rect
,
665 QItemSelectionModel::SelectionFlags flags
)
667 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
670 QListView::setSelection(rect
, flags
);
674 if (flags
& QItemSelectionModel::Clear
)
676 selectionModel()->clear();
677 d
->isIndexSelected
.clear();
678 d
->isTemporarySelected
.clear();
681 QItemSelection selection
;
682 QModelIndexList dirtyIndexes
= d
->intersectionSet(rect
);
683 foreach (const QModelIndex
&index
, dirtyIndexes
)
685 if (!d
->mouseButtonPressed
&& rect
.intersects(visualRect(index
)))
687 if (d
->isIndexSelected
.contains(index
))
689 if (!d
->isIndexSelected
[index
])
690 selection
.select(index
, index
);
692 d
->isIndexSelected
[index
] = true;
696 d
->isIndexSelected
.insert(index
, true);
697 selection
.select(index
, index
);
700 else if (d
->mouseButtonPressed
) // selection cache
702 if (!d
->isIndexSelected
.contains(index
) ||
703 (d
->isIndexSelected
.contains(index
) && !d
->isIndexSelected
[index
]))
705 if (d
->isTemporarySelected
.contains(index
))
707 d
->isTemporarySelected
[index
] = true;
711 d
->isTemporarySelected
.insert(index
, true);
715 if (d
->isIndexSelected
.contains(index
))
717 if (!d
->isIndexSelected
[index
])
718 selection
.select(index
, index
);
720 d
->isIndexSelected
[index
] = true;
724 d
->isIndexSelected
.insert(index
, true);
725 selection
.select(index
, index
);
730 QItemSelection deselect
;
732 foreach (const QModelIndex
&index
, d
->isIndexSelected
.keys())
734 if (!rect
.intersects(visualRect(index
)))
736 if (d
->isTemporarySelected
.contains(index
) &&
737 d
->isTemporarySelected
[index
])
739 deselect
.select(index
, index
);
740 d
->isTemporarySelected
[index
] = false;
741 d
->isIndexSelected
[index
] = false;
746 if (selection
.count())
747 selectionModel()->select(selection
, QItemSelectionModel::Select
);
749 if (deselect
.count())
750 selectionModel()->select(deselect
, QItemSelectionModel::Deselect
);
753 void KListView::mouseMoveEvent(QMouseEvent
*event
)
755 QListView::mouseMoveEvent(event
);
757 d
->mousePosition
= event
->pos();
759 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
767 viewport()->update();
770 void KListView::mousePressEvent(QMouseEvent
*event
)
772 QListView::mousePressEvent(event
);
774 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
782 if (event
->button() == Qt::LeftButton
)
784 d
->mouseButtonPressed
= true;
786 d
->initialPressPosition
= event
->pos();
787 d
->initialPressPosition
.setY(d
->initialPressPosition
.y() +
789 d
->initialPressPosition
.setX(d
->initialPressPosition
.x() +
793 viewport()->update();
796 void KListView::mouseReleaseEvent(QMouseEvent
*event
)
798 QListView::mouseReleaseEvent(event
);
800 d
->mouseButtonPressed
= false;
802 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
810 d
->isTemporarySelected
.clear(); // selection cache
812 QPoint initialPressPosition
= viewport()->mapFromGlobal(QCursor::pos());
813 initialPressPosition
.setY(initialPressPosition
.y() + verticalOffset());
814 initialPressPosition
.setX(initialPressPosition
.x() + horizontalOffset());
816 if (initialPressPosition
== d
->initialPressPosition
)
818 QItemSelection selection
;
819 foreach(const QString
&category
, d
->categories
)
821 if (d
->categoryVisualRect(category
).contains(event
->pos()))
824 foreach (const QModelIndex
&mappedIndex
,
825 d
->categoriesIndexes
[category
])
827 index
= d
->proxyModel
->mapFromSource(mappedIndex
);
829 if (d
->isIndexSelected
.contains(index
))
831 if (!d
->isIndexSelected
[index
])
832 selection
.select(index
, index
);
834 d
->isIndexSelected
[index
] = true;
838 d
->isIndexSelected
.insert(index
, true);
839 selection
.select(index
, index
);
843 selectionModel()->select(selection
, QItemSelectionModel::Toggle
);
850 viewport()->update();
853 void KListView::leaveEvent(QEvent
*event
)
855 QListView::leaveEvent(event
);
857 d
->hovered
= QModelIndex();
859 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
867 viewport()->update();
870 void KListView::startDrag(Qt::DropActions supportedActions
)
872 d
->mouseButtonPressed
= false;
874 QListView::startDrag(supportedActions
);
877 void KListView::rowsInserted(const QModelIndex
&parent
,
881 QListView::rowsInserted(parent
, start
, end
);
883 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
889 rowsInsertedArtifficial(parent
, start
, end
);
892 void KListView::rowsInsertedArtifficial(const QModelIndex
&parent
,
896 d
->elementsInfo
.clear();
897 d
->elementsPosition
.clear();
898 d
->elementDictionary
.clear();
899 d
->categoriesIndexes
.clear();
900 d
->categoriesPosition
.clear();
901 d
->isIndexSelected
.clear(); // selection cache
902 d
->categories
.clear();
903 d
->intersectedIndexes
.clear();
904 d
->sourceModelIndexList
.clear();
905 d
->hovered
= QModelIndex();
906 d
->mouseButtonPressed
= false;
908 if (start
> end
|| end
< 0 || start
< 0 || !d
->proxyModel
->rowCount())
913 // Add all elements mapped to the source model
914 for (int k
= 0; k
< d
->proxyModel
->rowCount(); k
++)
916 d
->sourceModelIndexList
<<
917 d
->proxyModel
->mapToSource(d
->proxyModel
->index(k
, 0));
920 // Sort them with the general purpose lessThan method
921 LessThan
generalLessThan(d
->proxyModel
,
922 LessThan::GeneralPurpose
);
924 qStableSort(d
->sourceModelIndexList
.begin(), d
->sourceModelIndexList
.end(),
927 // Explore categories
928 QString prevCategory
=
929 d
->itemCategorizer
->categoryForItem(d
->sourceModelIndexList
[0],
930 d
->proxyModel
->sortRole());
931 QString lastCategory
= prevCategory
;
932 QModelIndexList modelIndexList
;
933 struct Private::ElementInfo elementInfo
;
934 foreach (const QModelIndex
&index
, d
->sourceModelIndexList
)
936 lastCategory
= d
->itemCategorizer
->categoryForItem(index
,
937 d
->proxyModel
->sortRole());
939 elementInfo
.category
= lastCategory
;
941 if (prevCategory
!= lastCategory
)
943 d
->categoriesIndexes
.insert(prevCategory
, modelIndexList
);
944 d
->categories
<< prevCategory
;
945 modelIndexList
.clear();
948 modelIndexList
<< index
;
949 prevCategory
= lastCategory
;
951 d
->elementsInfo
.insert(index
, elementInfo
);
954 d
->categoriesIndexes
.insert(prevCategory
, modelIndexList
);
955 d
->categories
<< prevCategory
;
957 // Sort items locally in their respective categories with the category
959 LessThan
categoryLessThan(d
->proxyModel
,
960 LessThan::CategoryPurpose
);
962 foreach (const QString
&key
, d
->categories
)
964 QModelIndexList
&indexList
= d
->categoriesIndexes
[key
];
966 qStableSort(indexList
.begin(), indexList
.end(), categoryLessThan
);
969 d
->lastIndex
= d
->categoriesIndexes
[d
->categories
[d
->categories
.count() - 1]][d
->categoriesIndexes
[d
->categories
[d
->categories
.count() - 1]].count() - 1];
971 // Finally, fill data information of items situation. This will help when
972 // trying to compute an item place in the viewport
973 int i
= 0; // position relative to the category beginning
974 int j
= 0; // number of elements before current
975 foreach (const QString
&key
, d
->categories
)
977 foreach (const QModelIndex
&index
, d
->categoriesIndexes
[key
])
979 struct Private::ElementInfo
&elementInfo
= d
->elementsInfo
[index
];
981 elementInfo
.relativeOffsetToCategory
= i
;
983 d
->elementDictionary
.insert(d
->proxyModel
->index(j
, 0),
984 d
->proxyModel
->mapFromSource(index
));
993 d
->updateScrollbars();
996 void KListView::rowsRemoved(const QModelIndex
&parent
,
1002 // Force the view to update all elements
1003 rowsInsertedArtifficial(parent
, start
, end
);
1007 void KListView::updateGeometries()
1009 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
1010 !d
->itemCategorizer
)
1012 QListView::updateGeometries();
1016 // Avoid QListView::updateGeometries(), since it will try to set another
1017 // range to our scroll bars, what we don't want (ereslibre)
1018 QAbstractItemView::updateGeometries();
1021 void KListView::slotSortingRoleChanged()
1023 if ((viewMode() == KListView::IconMode
) && d
->proxyModel
&&
1026 // Force the view to update all elements
1027 rowsInsertedArtifficial(QModelIndex(), 0, d
->proxyModel
->rowCount() - 1);
1031 #include "klistview.moc"