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
26 #include <QApplication>
29 #include <QPaintEvent>
34 #include "kitemcategorizer.h"
35 #include "ksortfilterproxymodel.h"
46 inline LessThan(const KSortFilterProxyModel
*proxyModel
,
48 : proxyModel(proxyModel
)
53 inline bool operator()(const QModelIndex
&left
,
54 const QModelIndex
&right
) const
56 if (purpose
== GeneralPurpose
)
58 return proxyModel
->lessThanGeneralPurpose(left
, right
);
61 return proxyModel
->lessThanCategoryPurpose(left
, right
);
65 const KSortFilterProxyModel
*proxyModel
;
66 const Purpose purpose
;
70 //==============================================================================
73 KListView::Private::Private(KListView
*listView
)
76 , mouseButtonPressed(false)
78 , lastIndex(QModelIndex())
82 KListView::Private::~Private()
86 const QModelIndexList
&KListView::Private::intersectionSet(const QRect
&rect
)
89 QRect indexVisualRect
;
91 intersectedIndexes
.clear();
93 // Lets find out where we should start
94 int top
= proxyModel
->rowCount() - 1;
96 int middle
= (top
+ bottom
) / 2;
99 middle
= (top
+ bottom
) / 2;
101 index
= elementDictionary
[proxyModel
->index(middle
, 0)];
102 indexVisualRect
= visualRect(index
);
104 if (qMax(indexVisualRect
.topLeft().y(),
105 indexVisualRect
.bottomRight().y()) < qMin(rect
.topLeft().y(),
106 rect
.bottomRight().y()))
117 for (int i
= middle
; i
< proxyModel
->rowCount(); i
++)
119 index
= elementDictionary
[proxyModel
->index(i
, 0)];
120 indexVisualRect
= visualRect(index
);
122 if (rect
.intersects(indexVisualRect
))
123 intersectedIndexes
.append(index
);
125 // If we passed next item, stop searching for hits
126 if (qMax(rect
.bottomRight().y(), rect
.topLeft().y()) <
127 indexVisualRect
.topLeft().y())
133 return intersectedIndexes
;
136 QRect
KListView::Private::visualRectInViewport(const QModelIndex
&index
) const
138 if (!index
.isValid())
141 QString curCategory
= elementsInfo
[index
].category
;
143 QRect
retRect(listView
->spacing(), listView
->spacing() * 2 +
144 30 /* categoryHeight */, 0, 0);
146 int viewportWidth
= listView
->viewport()->width() - listView
->spacing();
148 // We really need all items to be of same size. Otherwise we cannot do this
151 // listView->sizeHintForIndex(proxyModel->mapFromSource(index));
152 // int itemHeight = itemSize.height();
153 // int itemWidth = itemSize.width();*/
154 int itemHeight
= 107;
156 int itemWidthPlusSeparation
= listView
->spacing() + itemWidth
;
157 int elementsPerRow
= viewportWidth
/ itemWidthPlusSeparation
;
161 int column
= elementsInfo
[index
].relativeOffsetToCategory
% elementsPerRow
;
162 int row
= elementsInfo
[index
].relativeOffsetToCategory
/ elementsPerRow
;
164 retRect
.setLeft(retRect
.left() + column
* listView
->spacing() +
169 foreach (const QString
&category
, categories
)
171 if (category
== curCategory
)
174 rows
= (float) ((float) categoriesIndexes
[category
].count() /
175 (float) elementsPerRow
);
176 rowsInt
= categoriesIndexes
[category
].count() / elementsPerRow
;
178 if (rows
- trunc(rows
)) rowsInt
++;
180 retRect
.setTop(retRect
.top() +
181 (rowsInt
* listView
->spacing()) +
182 (rowsInt
* itemHeight
) +
183 30 /* categoryHeight */ +
184 listView
->spacing() * 2);
187 retRect
.setTop(retRect
.top() + row
* listView
->spacing() +
190 retRect
.setWidth(itemWidth
);
191 retRect
.setHeight(itemHeight
);
196 QRect
KListView::Private::visualCategoryRectInViewport(const QString
&category
)
199 QRect
retRect(listView
->spacing(),
201 listView
->viewport()->width() - listView
->spacing() * 2,
204 if (!proxyModel
->rowCount() || !categories
.contains(category
))
207 QModelIndex index
= proxyModel
->index(0, 0, QModelIndex());
209 int viewportWidth
= listView
->viewport()->width() - listView
->spacing();
211 // We really need all items to be of same size. Otherwise we cannot do this
213 // QSize itemSize = listView->sizeHintForIndex(index);
214 // int itemHeight = itemSize.height();
215 // int itemWidth = itemSize.width();
216 int itemHeight
= 107;
218 int itemWidthPlusSeparation
= listView
->spacing() + itemWidth
;
219 int elementsPerRow
= viewportWidth
/ itemWidthPlusSeparation
;
226 foreach (const QString
&itCategory
, categories
)
228 if (itCategory
== category
)
231 rows
= (float) ((float) categoriesIndexes
[itCategory
].count() /
232 (float) elementsPerRow
);
233 rowsInt
= categoriesIndexes
[itCategory
].count() / elementsPerRow
;
235 if (rows
- trunc(rows
)) rowsInt
++;
237 retRect
.setTop(retRect
.top() +
238 (rowsInt
* listView
->spacing()) +
239 (rowsInt
* itemHeight
) +
240 30 /* categoryHeight */ +
241 listView
->spacing() * 2);
244 retRect
.setHeight(30 /* categoryHeight */);
249 // We're sure elementsPosition doesn't contain index
250 const QRect
&KListView::Private::cacheIndex(const QModelIndex
&index
)
252 QRect rect
= visualRectInViewport(index
);
253 elementsPosition
[index
] = rect
;
255 return elementsPosition
[index
];
258 // We're sure categoriesPosition doesn't contain category
259 const QRect
&KListView::Private::cacheCategory(const QString
&category
)
261 QRect rect
= visualCategoryRectInViewport(category
);
262 categoriesPosition
[category
] = rect
;
264 return categoriesPosition
[category
];
267 const QRect
&KListView::Private::cachedRectIndex(const QModelIndex
&index
)
269 if (elementsPosition
.contains(index
)) // If we have it cached
271 return elementsPosition
[index
];
273 else // Otherwise, cache it
275 return cacheIndex(index
);
279 const QRect
&KListView::Private::cachedRectCategory(const QString
&category
)
281 if (categoriesPosition
.contains(category
)) // If we have it cached
283 return categoriesPosition
[category
];
285 else // Otherwise, cache it and
287 return cacheCategory(category
);
291 QRect
KListView::Private::visualRect(const QModelIndex
&index
)
293 QModelIndex mappedIndex
= proxyModel
->mapToSource(index
);
295 QRect retRect
= cachedRectIndex(mappedIndex
);
296 int dx
= -listView
->horizontalOffset();
297 int dy
= -listView
->verticalOffset();
298 retRect
.adjust(dx
, dy
, dx
, dy
);
303 QRect
KListView::Private::categoryVisualRect(const QString
&category
)
305 QRect retRect
= cachedRectCategory(category
);
306 int dx
= -listView
->horizontalOffset();
307 int dy
= -listView
->verticalOffset();
308 retRect
.adjust(dx
, dy
, dx
, dy
);
313 void KListView::Private::drawNewCategory(const QString
&category
,
314 const QStyleOption
&option
,
317 QColor color
= option
.palette
.color(QPalette::Text
);
320 painter
->setRenderHint(QPainter::Antialiasing
);
322 QStyleOptionButton opt
;
324 opt
.rect
= option
.rect
;
325 opt
.palette
= option
.palette
;
326 opt
.direction
= option
.direction
;
329 if (option
.rect
.contains(listView
->viewport()->mapFromGlobal(QCursor::pos())) &&
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();
384 listView
->verticalScrollBar()->setRange(0, lastItemBottom
);
388 //==============================================================================
391 KListView::KListView(QWidget
*parent
)
393 , d(new Private(this))
397 KListView::~KListView()
402 void KListView::setModel(QAbstractItemModel
*model
)
406 QObject::disconnect(d
->proxyModel
,
407 SIGNAL(rowsRemoved(QModelIndex
,int,int)),
408 this, SLOT(rowsRemoved(QModelIndex
,int,int)));
410 QObject::disconnect(d
->proxyModel
,
411 SIGNAL(sortingRoleChanged()),
412 this, SLOT(slotSortingRoleChanged()));
415 QListView::setModel(model
);
417 d
->proxyModel
= dynamic_cast<KSortFilterProxyModel
*>(model
);
421 QObject::connect(d
->proxyModel
,
422 SIGNAL(rowsRemoved(QModelIndex
,int,int)),
423 this, SLOT(rowsRemoved(QModelIndex
,int,int)));
425 QObject::connect(d
->proxyModel
,
426 SIGNAL(sortingRoleChanged()),
427 this, SLOT(slotSortingRoleChanged()));
431 QRect
KListView::visualRect(const QModelIndex
&index
) const
433 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
436 return QListView::visualRect(index
);
439 if (!qobject_cast
<const QSortFilterProxyModel
*>(index
.model()))
441 return d
->visualRect(d
->proxyModel
->mapFromSource(index
));
444 return d
->visualRect(index
);
447 KItemCategorizer
*KListView::itemCategorizer() const
449 return d
->itemCategorizer
;
452 void KListView::setItemCategorizer(KItemCategorizer
*itemCategorizer
)
454 if (!itemCategorizer
&& d
->proxyModel
)
456 QObject::disconnect(d
->proxyModel
,
457 SIGNAL(rowsRemoved(QModelIndex
,int,int)),
458 this, SLOT(rowsRemoved(QModelIndex
,int,int)));
460 QObject::disconnect(d
->proxyModel
,
461 SIGNAL(sortingRoleChanged()),
462 this, SLOT(slotSortingRoleChanged()));
464 else if (itemCategorizer
&& d
->proxyModel
)
466 QObject::connect(d
->proxyModel
,
467 SIGNAL(rowsRemoved(QModelIndex
,int,int)),
468 this, SLOT(rowsRemoved(QModelIndex
,int,int)));
470 QObject::connect(d
->proxyModel
,
471 SIGNAL(sortingRoleChanged()),
472 this, SLOT(slotSortingRoleChanged()));
475 d
->itemCategorizer
= itemCategorizer
;
479 rowsInserted(QModelIndex(), 0, d
->proxyModel
->rowCount() - 1);
483 QModelIndex
KListView::indexAt(const QPoint
&point
) const
485 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
488 return QListView::indexAt(point
);
493 QModelIndexList item
= d
->intersectionSet(QRect(point
, point
));
495 if (item
.count() == 1)
505 void KListView::reset()
509 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
515 d
->elementsInfo
.clear();
516 d
->elementsPosition
.clear();
517 d
->elementDictionary
.clear();
518 d
->categoriesIndexes
.clear();
519 d
->categoriesPosition
.clear();
520 d
->categories
.clear();
521 d
->intersectedIndexes
.clear();
522 d
->sourceModelIndexList
.clear();
523 d
->hovered
= QModelIndex();
524 d
->mouseButtonPressed
= false;
527 void KListView::paintEvent(QPaintEvent
*event
)
529 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
532 QListView::paintEvent(event
);
536 QStyleOptionViewItemV3 option
= viewOptions();
537 QPainter
painter(viewport());
538 QRect area
= event
->rect();
539 const bool focus
= (hasFocus() || viewport()->hasFocus()) &&
540 currentIndex().isValid();
541 const QStyle::State state
= option
.state
;
542 const bool enabled
= (state
& QStyle::State_Enabled
) != 0;
546 QModelIndexList dirtyIndexes
= d
->intersectionSet(area
);
547 foreach (const QModelIndex
&index
, dirtyIndexes
)
549 option
.state
= state
;
550 option
.rect
= d
->visualRect(index
);
552 if (selectionModel() && selectionModel()->isSelected(index
))
554 option
.state
|= QStyle::State_Selected
;
559 QPalette::ColorGroup cg
;
560 if ((d
->proxyModel
->flags(index
) & Qt::ItemIsEnabled
) == 0)
562 option
.state
&= ~QStyle::State_Enabled
;
563 cg
= QPalette::Disabled
;
567 cg
= QPalette::Normal
;
569 option
.palette
.setCurrentColorGroup(cg
);
572 if (focus
&& currentIndex() == index
)
574 option
.state
|= QStyle::State_HasFocus
;
575 if (this->state() == EditingState
)
576 option
.state
|= QStyle::State_Editing
;
579 if ((index
== d
->hovered
) && !d
->mouseButtonPressed
)
580 option
.state
|= QStyle::State_MouseOver
;
582 option
.state
&= ~QStyle::State_MouseOver
;
584 itemDelegate(index
)->paint(&painter
, option
, index
);
588 QStyleOptionViewItem otherOption
;
589 foreach (const QString
&category
, d
->categories
)
591 otherOption
= option
;
592 otherOption
.rect
= d
->categoryVisualRect(category
);
594 if (otherOption
.rect
.intersects(area
))
596 d
->drawNewCategory(category
, otherOption
, &painter
);
600 if (d
->mouseButtonPressed
)
602 QPoint start
, end
, initialPressPosition
;
604 initialPressPosition
= d
->initialPressPosition
;
606 initialPressPosition
.setY(initialPressPosition
.y() - verticalOffset());
607 initialPressPosition
.setX(initialPressPosition
.x() - horizontalOffset());
609 if (d
->initialPressPosition
.x() > d
->mousePosition
.x() ||
610 d
->initialPressPosition
.y() > d
->mousePosition
.y())
612 start
= d
->mousePosition
;
613 end
= initialPressPosition
;
617 start
= initialPressPosition
;
618 end
= d
->mousePosition
;
621 QStyleOptionRubberBand yetAnotherOption
;
622 yetAnotherOption
.initFrom(this);
623 yetAnotherOption
.shape
= QRubberBand::Rectangle
;
624 yetAnotherOption
.opaque
= false;
625 yetAnotherOption
.rect
= QRect(start
, end
).intersected(viewport()->rect().adjusted(-16, -16, 16, 16));
627 style()->drawControl(QStyle::CE_RubberBand
, &yetAnotherOption
, &painter
);
634 void KListView::resizeEvent(QResizeEvent
*event
)
636 QListView::resizeEvent(event
);
638 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
644 // Clear the items positions cache
645 d
->elementsPosition
.clear();
646 d
->categoriesPosition
.clear();
648 d
->updateScrollbars();
651 void KListView::setSelection(const QRect
&rect
,
652 QItemSelectionModel::SelectionFlags flags
)
654 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
657 QListView::setSelection(rect
, flags
);
661 // FIXME: I have to rethink and rewrite this method (ereslibre)
663 QModelIndexList dirtyIndexes
= d
->intersectionSet(rect
);
664 foreach (const QModelIndex
&index
, dirtyIndexes
)
666 if (!d
->mouseButtonPressed
&& rect
.intersects(visualRect(index
)))
668 selectionModel()->select(index
, flags
);
672 selectionModel()->select(index
, QItemSelectionModel::Select
);
674 if (d
->mouseButtonPressed
)
675 d
->tempSelected
.append(index
);
679 if (d
->mouseButtonPressed
)
681 foreach (const QModelIndex
&index
, selectionModel()->selectedIndexes())
683 if (!rect
.intersects(visualRect(index
)))
685 selectionModel()->select(index
, QItemSelectionModel::Deselect
);
687 if (d
->mouseButtonPressed
)
689 d
->tempSelected
.removeAll(index
);
696 void KListView::mouseMoveEvent(QMouseEvent
*event
)
698 QListView::mouseMoveEvent(event
);
700 d
->mousePosition
= event
->pos();
702 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
710 viewport()->update();
713 void KListView::mousePressEvent(QMouseEvent
*event
)
715 QListView::mousePressEvent(event
);
717 d
->tempSelected
.clear();
719 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
727 if (event
->button() == Qt::LeftButton
)
729 d
->mouseButtonPressed
= true;
731 d
->initialPressPosition
= event
->pos();
732 d
->initialPressPosition
.setY(d
->initialPressPosition
.y() +
734 d
->initialPressPosition
.setX(d
->initialPressPosition
.x() +
738 viewport()->update();
741 void KListView::mouseReleaseEvent(QMouseEvent
*event
)
743 QListView::mouseReleaseEvent(event
);
745 d
->mouseButtonPressed
= false;
747 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
755 // FIXME: I have to rethink and rewrite this method (ereslibre)
757 QPoint initialPressPosition
= viewport()->mapFromGlobal(QCursor::pos());
758 initialPressPosition
.setY(initialPressPosition
.y() + verticalOffset());
759 initialPressPosition
.setX(initialPressPosition
.x() + horizontalOffset());
761 if (initialPressPosition
== d
->initialPressPosition
)
763 foreach(const QString
&category
, d
->categories
)
765 if (d
->categoryVisualRect(category
).contains(event
->pos()))
768 QItemSelectionModel::SelectionFlag flag
;
769 foreach (const QModelIndex
&mappedIndex
,
770 d
->categoriesIndexes
[category
])
772 index
= d
->proxyModel
->mapFromSource(mappedIndex
);
774 if (selectionModel()->selectedIndexes().contains(index
))
776 flag
= QItemSelectionModel::Deselect
;
780 flag
= QItemSelectionModel::Select
;
783 selectionModel()->select(index
, flag
);
789 viewport()->update();
792 void KListView::leaveEvent(QEvent
*event
)
794 QListView::leaveEvent(event
);
796 d
->hovered
= QModelIndex();
798 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
806 viewport()->update();
809 void KListView::rowsInserted(const QModelIndex
&parent
,
813 QListView::rowsInserted(parent
, start
, end
);
815 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
821 rowsInsertedArtifficial(parent
, start
, end
);
824 void KListView::rowsInsertedArtifficial(const QModelIndex
&parent
,
828 d
->elementsInfo
.clear();
829 d
->elementsPosition
.clear();
830 d
->elementDictionary
.clear();
831 d
->categoriesIndexes
.clear();
832 d
->categoriesPosition
.clear();
833 d
->categories
.clear();
834 d
->intersectedIndexes
.clear();
835 d
->sourceModelIndexList
.clear();
836 d
->hovered
= QModelIndex();
837 d
->mouseButtonPressed
= false;
839 if (start
> end
|| end
< 0 || start
< 0 || !d
->proxyModel
->rowCount())
844 // Add all elements mapped to the source model
845 for (int i
= 0; i
< d
->proxyModel
->rowCount(); i
++)
847 d
->sourceModelIndexList
<<
848 d
->proxyModel
->mapToSource(d
->proxyModel
->index(i
, 0));
851 // Sort them with the general purpose lessThan method
852 LessThan
generalLessThan(d
->proxyModel
,
853 LessThan::GeneralPurpose
);
855 qStableSort(d
->sourceModelIndexList
.begin(), d
->sourceModelIndexList
.end(),
858 // Explore categories
859 QString prevCategory
=
860 d
->itemCategorizer
->categoryForItem(d
->sourceModelIndexList
[0],
861 d
->proxyModel
->sortRole());
862 QString lastCategory
= prevCategory
;
863 QModelIndexList modelIndexList
;
864 struct Private::ElementInfo elementInfo
;
865 foreach (const QModelIndex
&index
, d
->sourceModelIndexList
)
867 lastCategory
= d
->itemCategorizer
->categoryForItem(index
,
868 d
->proxyModel
->sortRole());
870 elementInfo
.category
= lastCategory
;
872 if (prevCategory
!= lastCategory
)
874 d
->categoriesIndexes
.insert(prevCategory
, modelIndexList
);
875 d
->categories
<< prevCategory
;
876 modelIndexList
.clear();
879 modelIndexList
<< index
;
880 prevCategory
= lastCategory
;
882 d
->elementsInfo
.insert(index
, elementInfo
);
885 d
->categoriesIndexes
.insert(prevCategory
, modelIndexList
);
886 d
->categories
<< prevCategory
;
888 // Sort items locally in their respective categories with the category
890 LessThan
categoryLessThan(d
->proxyModel
,
891 LessThan::CategoryPurpose
);
893 foreach (const QString
&key
, d
->categories
)
895 QModelIndexList
&indexList
= d
->categoriesIndexes
[key
];
897 qStableSort(indexList
.begin(), indexList
.end(), categoryLessThan
);
900 d
->lastIndex
= d
->categoriesIndexes
[d
->categories
[d
->categories
.count() - 1]][d
->categoriesIndexes
[d
->categories
[d
->categories
.count() - 1]].count() - 1];
902 // Finally, fill data information of items situation. This will help when
903 // trying to compute an item place in the viewport
904 int i
= 0; // position relative to the category beginning
905 int j
= 0; // number of elements before current
906 foreach (const QString
&key
, d
->categories
)
908 foreach (const QModelIndex
&index
, d
->categoriesIndexes
[key
])
910 struct Private::ElementInfo
&elementInfo
= d
->elementsInfo
[index
];
912 elementInfo
.relativeOffsetToCategory
= i
;
914 d
->elementDictionary
.insert(d
->proxyModel
->index(j
, 0),
915 d
->proxyModel
->mapFromSource(index
));
924 d
->updateScrollbars();
927 void KListView::rowsRemoved(const QModelIndex
&parent
,
933 // Force the view to update all elements
934 rowsInsertedArtifficial(parent
, start
, end
);
938 void KListView::updateGeometries()
940 if ((viewMode() == KListView::ListMode
) || !d
->proxyModel
||
943 QListView::updateGeometries();
947 // Avoid QListView::updateGeometries(), since it will try to set another
948 // range to our scroll bars, what we don't want (ereslibre)
949 QAbstractItemView::updateGeometries();
952 void KListView::slotSortingRoleChanged()
956 // Force the view to update all elements
957 rowsInsertedArtifficial(QModelIndex(), 0, d
->proxyModel
->rowCount() -
962 #include "klistview.moc"