]> cloud.milkyroute.net Git - dolphin.git/blob - src/kcategorizedview.cpp
6590c4b2ac99095147add4275863abb12945d921
[dolphin.git] / src / kcategorizedview.cpp
1 /**
2 * This file is part of the KDE project
3 * Copyright (C) 2007 Rafael Fernández López <ereslibre@kde.org>
4 *
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.
9 *
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.
14 *
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.
19 */
20
21 #include "kcategorizedview.h"
22 #include "kcategorizedview_p.h"
23
24 #include <math.h> // trunc on C99 compliant systems
25 #include <kdefakes.h> // trunc for not C99 compliant systems
26
27 #include <QPainter>
28 #include <QScrollBar>
29 #include <QPaintEvent>
30
31 #include <kstyle.h>
32
33 #include "kcategorydrawer.h"
34 #include "kcategorizedsortfilterproxymodel.h"
35
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
41
42 KCategorizedView::Private::Private(KCategorizedView *listView)
43 : listView(listView)
44 , categoryDrawer(0)
45 , biggestItemSize(QSize(0, 0))
46 , mouseButtonPressed(false)
47 , isDragging(false)
48 , dragLeftViewport(false)
49 , proxyModel(0)
50 {
51 }
52
53 KCategorizedView::Private::~Private()
54 {
55 }
56
57 const QModelIndexList &KCategorizedView::Private::intersectionSet(const QRect &rect)
58 {
59 QModelIndex index;
60 QRect indexVisualRect;
61
62 intersectedIndexes.clear();
63
64 int itemHeight;
65
66 if (listView->gridSize().isEmpty())
67 {
68 itemHeight = biggestItemSize.height();
69 }
70 else
71 {
72 itemHeight = listView->gridSize().height();
73 }
74
75 // Lets find out where we should start
76 int top = proxyModel->rowCount() - 1;
77 int bottom = 0;
78 int middle = (top + bottom) / 2;
79 while (bottom <= top)
80 {
81 middle = (top + bottom) / 2;
82
83 index = proxyModel->index(middle, 0);
84 indexVisualRect = visualRect(index);
85 // We need the whole height (not only the visualRect). This will help us to update
86 // all needed indexes correctly (ereslibre)
87 indexVisualRect.setHeight(indexVisualRect.height() + (itemHeight - indexVisualRect.height()));
88
89 if (qMax(indexVisualRect.topLeft().y(),
90 indexVisualRect.bottomRight().y()) < qMin(rect.topLeft().y(),
91 rect.bottomRight().y()))
92 {
93 bottom = middle + 1;
94 }
95 else
96 {
97 top = middle - 1;
98 }
99 }
100
101 for (int i = middle; i < proxyModel->rowCount(); i++)
102 {
103 index = proxyModel->index(i, 0);
104 indexVisualRect = visualRect(index);
105
106 if (rect.intersects(indexVisualRect))
107 intersectedIndexes.append(index);
108
109 // If we passed next item, stop searching for hits
110 if (qMax(rect.bottomRight().y(), rect.topLeft().y()) <
111 qMin(indexVisualRect.topLeft().y(),
112 indexVisualRect.bottomRight().y()))
113 break;
114 }
115
116 return intersectedIndexes;
117 }
118
119 QRect KCategorizedView::Private::visualRectInViewport(const QModelIndex &index) const
120 {
121 if (!index.isValid())
122 return QRect();
123
124 QString curCategory = elementsInfo[index.row()].category;
125
126 QRect retRect;
127
128 if (listView->layoutDirection() == Qt::LeftToRight)
129 {
130 retRect = QRect(listView->spacing(), listView->spacing() * 2 +
131 categoryDrawer->categoryHeight(listView->viewOptions()), 0, 0);
132 }
133 else
134 {
135 retRect = QRect(listView->viewport()->width() - listView->spacing(), listView->spacing() * 2 +
136 categoryDrawer->categoryHeight(listView->viewOptions()), 0, 0);
137 }
138
139 int viewportWidth = listView->viewport()->width() - listView->spacing();
140
141 int itemHeight;
142 int itemWidth;
143
144 if (listView->gridSize().isEmpty())
145 {
146 itemHeight = biggestItemSize.height();
147 itemWidth = biggestItemSize.width();
148 }
149 else
150 {
151 itemHeight = listView->gridSize().height();
152 itemWidth = listView->gridSize().width();
153 }
154
155 int itemWidthPlusSeparation = listView->spacing() + itemWidth;
156 int elementsPerRow = viewportWidth / itemWidthPlusSeparation;
157 if (!elementsPerRow)
158 elementsPerRow++;
159
160 int column = elementsInfo[index.row()].relativeOffsetToCategory % elementsPerRow;
161 int row = elementsInfo[index.row()].relativeOffsetToCategory / elementsPerRow;
162
163 if (listView->layoutDirection() == Qt::LeftToRight)
164 {
165 retRect.setLeft(retRect.left() + column * listView->spacing() +
166 column * itemWidth);
167 }
168 else
169 {
170 retRect.setLeft(retRect.right() - column * listView->spacing() -
171 column * itemWidth - itemWidth);
172
173 retRect.setRight(retRect.right() - column * listView->spacing() -
174 column * itemWidth);
175 }
176
177 foreach (const QString &category, categories)
178 {
179 if (category == curCategory)
180 break;
181
182 float rows = (float) ((float) categoriesIndexes[category].count() /
183 (float) elementsPerRow);
184
185 int rowsInt = categoriesIndexes[category].count() / elementsPerRow;
186
187 if (rows - trunc(rows)) rowsInt++;
188
189 retRect.setTop(retRect.top() +
190 (rowsInt * itemHeight) +
191 categoryDrawer->categoryHeight(listView->viewOptions()) +
192 listView->spacing() * 2);
193
194 if (listView->gridSize().isEmpty())
195 {
196 retRect.setTop(retRect.top() +
197 (rowsInt * listView->spacing()));
198 }
199 }
200
201 if (listView->gridSize().isEmpty())
202 {
203 retRect.setTop(retRect.top() + row * listView->spacing() +
204 (row * itemHeight));
205 }
206 else
207 {
208 retRect.setTop(retRect.top() + (row * itemHeight));
209 }
210
211 retRect.setWidth(itemWidth);
212
213 QModelIndex heightIndex = proxyModel->index(index.row(), 0);
214 if (listView->gridSize().isEmpty())
215 {
216 retRect.setHeight(listView->sizeHintForIndex(heightIndex).height());
217 }
218 else
219 {
220 retRect.setHeight(qMin(listView->sizeHintForIndex(heightIndex).height(),
221 listView->gridSize().height()));
222 }
223
224 return retRect;
225 }
226
227 QRect KCategorizedView::Private::visualCategoryRectInViewport(const QString &category)
228 const
229 {
230 QRect retRect(listView->spacing(),
231 listView->spacing(),
232 listView->viewport()->width() - listView->spacing() * 2,
233 0);
234
235 if (!proxyModel->rowCount() || !categories.contains(category))
236 return QRect();
237
238 QModelIndex index = proxyModel->index(0, 0, QModelIndex());
239
240 int viewportWidth = listView->viewport()->width() - listView->spacing();
241
242 int itemHeight;
243 int itemWidth;
244
245 if (listView->gridSize().isEmpty())
246 {
247 itemHeight = biggestItemSize.height();
248 itemWidth = biggestItemSize.width();
249 }
250 else
251 {
252 itemHeight = listView->gridSize().height();
253 itemWidth = listView->gridSize().width();
254 }
255
256 int itemWidthPlusSeparation = listView->spacing() + itemWidth;
257 int elementsPerRow = viewportWidth / itemWidthPlusSeparation;
258
259 if (!elementsPerRow)
260 elementsPerRow++;
261
262 foreach (const QString &itCategory, categories)
263 {
264 if (itCategory == category)
265 break;
266
267 float rows = (float) ((float) categoriesIndexes[itCategory].count() /
268 (float) elementsPerRow);
269 int rowsInt = categoriesIndexes[itCategory].count() / elementsPerRow;
270
271 if (rows - trunc(rows)) rowsInt++;
272
273 retRect.setTop(retRect.top() +
274 (rowsInt * itemHeight) +
275 categoryDrawer->categoryHeight(listView->viewOptions()) +
276 listView->spacing() * 2);
277
278 if (listView->gridSize().isEmpty())
279 {
280 retRect.setTop(retRect.top() +
281 (rowsInt * listView->spacing()));
282 }
283 }
284
285 retRect.setHeight(categoryDrawer->categoryHeight(listView->viewOptions()));
286
287 return retRect;
288 }
289
290 // We're sure elementsPosition doesn't contain index
291 const QRect &KCategorizedView::Private::cacheIndex(const QModelIndex &index)
292 {
293 QRect rect = visualRectInViewport(index);
294 elementsPosition[index.row()] = rect;
295
296 return elementsPosition[index.row()];
297 }
298
299 // We're sure categoriesPosition doesn't contain category
300 const QRect &KCategorizedView::Private::cacheCategory(const QString &category)
301 {
302 QRect rect = visualCategoryRectInViewport(category);
303 categoriesPosition[category] = rect;
304
305 return categoriesPosition[category];
306 }
307
308 const QRect &KCategorizedView::Private::cachedRectIndex(const QModelIndex &index)
309 {
310 if (elementsPosition.contains(index.row())) // If we have it cached
311 { // return it
312 return elementsPosition[index.row()];
313 }
314 else // Otherwise, cache it
315 { // and return it
316 return cacheIndex(index);
317 }
318 }
319
320 const QRect &KCategorizedView::Private::cachedRectCategory(const QString &category)
321 {
322 if (categoriesPosition.contains(category)) // If we have it cached
323 { // return it
324 return categoriesPosition[category];
325 }
326 else // Otherwise, cache it and
327 { // return it
328 return cacheCategory(category);
329 }
330 }
331
332 QRect KCategorizedView::Private::visualRect(const QModelIndex &index)
333 {
334 QRect retRect = cachedRectIndex(index);
335 int dx = -listView->horizontalOffset();
336 int dy = -listView->verticalOffset();
337 retRect.adjust(dx, dy, dx, dy);
338
339 return retRect;
340 }
341
342 QRect KCategorizedView::Private::categoryVisualRect(const QString &category)
343 {
344 QRect retRect = cachedRectCategory(category);
345 int dx = -listView->horizontalOffset();
346 int dy = -listView->verticalOffset();
347 retRect.adjust(dx, dy, dx, dy);
348
349 return retRect;
350 }
351
352 void KCategorizedView::Private::drawNewCategory(const QModelIndex &index,
353 int sortRole,
354 const QStyleOption &option,
355 QPainter *painter)
356 {
357 if (!index.isValid())
358 {
359 return;
360 }
361
362 QStyleOption optionCopy = option;
363 const QString category = proxyModel->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
364
365 optionCopy.state &= ~QStyle::State_Selected;
366
367 if ((category == hoveredCategory) && !mouseButtonPressed)
368 {
369 optionCopy.state |= QStyle::State_MouseOver;
370 }
371 else if ((category == hoveredCategory) && mouseButtonPressed)
372 {
373 QPoint initialPressPosition = listView->viewport()->mapFromGlobal(QCursor::pos());
374 initialPressPosition.setY(initialPressPosition.y() + listView->verticalOffset());
375 initialPressPosition.setX(initialPressPosition.x() + listView->horizontalOffset());
376
377 if (initialPressPosition == this->initialPressPosition)
378 {
379 optionCopy.state |= QStyle::State_Selected;
380 }
381 }
382
383 categoryDrawer->drawCategory(index,
384 sortRole,
385 optionCopy,
386 painter);
387 }
388
389
390 void KCategorizedView::Private::updateScrollbars()
391 {
392 // find the last index in the last category
393 QModelIndex lastIndex = categoriesIndexes.isEmpty() ? QModelIndex() : categoriesIndexes[categories.last()].last();
394
395 int lastItemBottom = cachedRectIndex(lastIndex).top() +
396 listView->spacing() + (listView->gridSize().isEmpty() ? 0 : listView->gridSize().height()) - listView->viewport()->height();
397
398 listView->horizontalScrollBar()->setRange(0, 0);
399
400 listView->verticalScrollBar()->setSingleStep(listView->viewport()->height() / 10);
401 listView->verticalScrollBar()->setPageStep(listView->viewport()->height());
402 listView->verticalScrollBar()->setRange(0, lastItemBottom);
403 }
404
405 void KCategorizedView::Private::drawDraggedItems(QPainter *painter)
406 {
407 QStyleOptionViewItemV3 option = listView->viewOptions();
408 option.state &= ~QStyle::State_MouseOver;
409 foreach (const QModelIndex &index, listView->selectionModel()->selectedIndexes())
410 {
411 const int dx = mousePosition.x() - initialPressPosition.x() + listView->horizontalOffset();
412 const int dy = mousePosition.y() - initialPressPosition.y() + listView->verticalOffset();
413
414 option.rect = visualRect(index);
415 option.rect.adjust(dx, dy, dx, dy);
416
417 if (option.rect.intersects(listView->viewport()->rect()))
418 {
419 listView->itemDelegate(index)->paint(painter, option, index);
420 }
421 }
422 }
423
424 void KCategorizedView::Private::layoutChanged(bool forceItemReload)
425 {
426 if ((listView->viewMode() == KCategorizedView::IconMode) && proxyModel &&
427 categoryDrawer && proxyModel->isCategorizedModel() &&
428 ((forceItemReload ||
429 (modelSortRole != proxyModel->sortRole()) ||
430 (modelSortColumn != proxyModel->sortColumn()) ||
431 (modelSortOrder != proxyModel->sortOrder()) ||
432 (modelLastRowCount != proxyModel->rowCount()) ||
433 (modelCategorized != proxyModel->isCategorizedModel()))))
434 {
435 // Force the view to update all elements
436 listView->rowsInsertedArtifficial(QModelIndex(), 0, proxyModel->rowCount() - 1);
437
438 if (!forceItemReload)
439 {
440 modelSortRole = proxyModel->sortRole();
441 modelSortColumn = proxyModel->sortColumn();
442 modelSortOrder = proxyModel->sortOrder();
443 modelLastRowCount = proxyModel->rowCount();
444 modelCategorized = proxyModel->isCategorizedModel();
445 }
446 }
447 else if ((listView->viewMode() == KCategorizedView::IconMode) && proxyModel &&
448 categoryDrawer && proxyModel->isCategorizedModel())
449 {
450 updateScrollbars();
451 }
452 }
453
454 void KCategorizedView::Private::drawDraggedItems()
455 {
456 QRect rectToUpdate;
457 QRect currentRect;
458 foreach (const QModelIndex &index, listView->selectionModel()->selectedIndexes())
459 {
460 int dx = mousePosition.x() - initialPressPosition.x() + listView->horizontalOffset();
461 int dy = mousePosition.y() - initialPressPosition.y() + listView->verticalOffset();
462
463 currentRect = visualRect(index);
464 currentRect.adjust(dx, dy, dx, dy);
465
466 if (currentRect.intersects(listView->viewport()->rect()))
467 {
468 rectToUpdate = rectToUpdate.united(currentRect);
469 }
470 }
471
472 listView->viewport()->update(lastDraggedItemsRect.united(rectToUpdate));
473
474 lastDraggedItemsRect = rectToUpdate;
475 }
476
477
478 //==============================================================================
479
480
481 KCategorizedView::KCategorizedView(QWidget *parent)
482 : QListView(parent)
483 , d(new Private(this))
484 {
485 }
486
487 KCategorizedView::~KCategorizedView()
488 {
489 delete d;
490 }
491
492 void KCategorizedView::setGridSize(const QSize &size)
493 {
494 QListView::setGridSize(size);
495
496 d->layoutChanged(true);
497 }
498
499 void KCategorizedView::setModel(QAbstractItemModel *model)
500 {
501 d->lastSelection = QItemSelection();
502 d->currentViewIndex = QModelIndex();
503 d->forcedSelectionPosition = 0;
504 d->elementsInfo.clear();
505 d->elementsPosition.clear();
506 d->categoriesIndexes.clear();
507 d->categoriesPosition.clear();
508 d->categories.clear();
509 d->intersectedIndexes.clear();
510 d->modelIndexList.clear();
511 d->hovered = QModelIndex();
512 d->mouseButtonPressed = false;
513
514 if (d->proxyModel)
515 {
516 QObject::disconnect(d->proxyModel,
517 SIGNAL(layoutChanged()),
518 this, SLOT(slotLayoutChanged()));
519
520 QObject::disconnect(d->proxyModel,
521 SIGNAL(dataChanged(QModelIndex,QModelIndex)),
522 this, SLOT(slotLayoutChanged()));
523
524 QObject::disconnect(d->proxyModel,
525 SIGNAL(rowsRemoved(QModelIndex,int,int)),
526 this, SLOT(rowsRemoved(QModelIndex,int,int)));
527 }
528
529 QListView::setModel(model);
530
531 d->proxyModel = dynamic_cast<KCategorizedSortFilterProxyModel*>(model);
532
533 if (d->proxyModel)
534 {
535 d->modelSortRole = d->proxyModel->sortRole();
536 d->modelSortColumn = d->proxyModel->sortColumn();
537 d->modelSortOrder = d->proxyModel->sortOrder();
538 d->modelLastRowCount = d->proxyModel->rowCount();
539 d->modelCategorized = d->proxyModel->isCategorizedModel();
540
541 QObject::connect(d->proxyModel,
542 SIGNAL(layoutChanged()),
543 this, SLOT(slotLayoutChanged()));
544
545 QObject::connect(d->proxyModel,
546 SIGNAL(dataChanged(QModelIndex,QModelIndex)),
547 this, SLOT(slotLayoutChanged()));
548
549 QObject::connect(d->proxyModel,
550 SIGNAL(rowsRemoved(QModelIndex,int,int)),
551 this, SLOT(rowsRemoved(QModelIndex,int,int)));
552
553 if (d->proxyModel->rowCount())
554 {
555 d->layoutChanged(true);
556 }
557 }
558 else
559 {
560 d->modelCategorized = false;
561 }
562 }
563
564 QRect KCategorizedView::visualRect(const QModelIndex &index) const
565 {
566 if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
567 !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
568 {
569 return QListView::visualRect(index);
570 }
571
572 if (!qobject_cast<const QSortFilterProxyModel*>(index.model()))
573 {
574 return d->visualRect(d->proxyModel->mapFromSource(index));
575 }
576
577 return d->visualRect(index);
578 }
579
580 KCategoryDrawer *KCategorizedView::categoryDrawer() const
581 {
582 return d->categoryDrawer;
583 }
584
585 void KCategorizedView::setCategoryDrawer(KCategoryDrawer *categoryDrawer)
586 {
587 d->lastSelection = QItemSelection();
588 d->currentViewIndex = QModelIndex();
589 d->forcedSelectionPosition = 0;
590 d->elementsInfo.clear();
591 d->elementsPosition.clear();
592 d->categoriesIndexes.clear();
593 d->categoriesPosition.clear();
594 d->categories.clear();
595 d->intersectedIndexes.clear();
596 d->modelIndexList.clear();
597 d->hovered = QModelIndex();
598 d->mouseButtonPressed = false;
599
600 if (!categoryDrawer && d->proxyModel)
601 {
602 QObject::disconnect(d->proxyModel,
603 SIGNAL(layoutChanged()),
604 this, SLOT(slotLayoutChanged()));
605
606 QObject::disconnect(d->proxyModel,
607 SIGNAL(dataChanged(QModelIndex,QModelIndex)),
608 this, SLOT(slotLayoutChanged()));
609
610 QObject::disconnect(d->proxyModel,
611 SIGNAL(rowsRemoved(QModelIndex,int,int)),
612 this, SLOT(rowsRemoved(QModelIndex,int,int)));
613 }
614 else if (categoryDrawer && d->proxyModel)
615 {
616 QObject::connect(d->proxyModel,
617 SIGNAL(layoutChanged()),
618 this, SLOT(slotLayoutChanged()));
619
620 QObject::connect(d->proxyModel,
621 SIGNAL(dataChanged(QModelIndex,QModelIndex)),
622 this, SLOT(slotLayoutChanged()));
623
624 QObject::connect(d->proxyModel,
625 SIGNAL(rowsRemoved(QModelIndex,int,int)),
626 this, SLOT(rowsRemoved(QModelIndex,int,int)));
627 }
628
629 d->categoryDrawer = categoryDrawer;
630
631 if (categoryDrawer)
632 {
633 if (d->proxyModel)
634 {
635 if (d->proxyModel->rowCount())
636 {
637 d->layoutChanged(true);
638 }
639 }
640 }
641 else
642 {
643 updateGeometries();
644 }
645 }
646
647 QModelIndex KCategorizedView::indexAt(const QPoint &point) const
648 {
649 if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
650 !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
651 {
652 return QListView::indexAt(point);
653 }
654
655 QModelIndex index;
656
657 QModelIndexList item = d->intersectionSet(QRect(point, point));
658
659 if (item.count() == 1)
660 {
661 index = item[0];
662 }
663
664 d->hovered = index;
665
666 return index;
667 }
668
669 void KCategorizedView::reset()
670 {
671 QListView::reset();
672
673 d->lastSelection = QItemSelection();
674 d->currentViewIndex = QModelIndex();
675 d->forcedSelectionPosition = 0;
676 d->elementsInfo.clear();
677 d->elementsPosition.clear();
678 d->categoriesIndexes.clear();
679 d->categoriesPosition.clear();
680 d->categories.clear();
681 d->intersectedIndexes.clear();
682 d->modelIndexList.clear();
683 d->hovered = QModelIndex();
684 d->biggestItemSize = QSize(0, 0);
685 d->mouseButtonPressed = false;
686 }
687
688 void KCategorizedView::paintEvent(QPaintEvent *event)
689 {
690 if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
691 !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
692 {
693 QListView::paintEvent(event);
694 return;
695 }
696
697 QStyleOptionViewItemV3 option = viewOptions();
698 option.widget = this;
699 if (wordWrap())
700 {
701 option.features |= QStyleOptionViewItemV2::WrapText;
702 }
703
704 QPainter painter(viewport());
705 QRect area = event->rect();
706 const bool focus = (hasFocus() || viewport()->hasFocus()) &&
707 currentIndex().isValid();
708 const QStyle::State state = option.state;
709 const bool enabled = (state & QStyle::State_Enabled) != 0;
710
711 painter.save();
712
713 QModelIndexList dirtyIndexes = d->intersectionSet(area);
714 foreach (const QModelIndex &index, dirtyIndexes)
715 {
716 option.state = state;
717 option.rect = visualRect(index);
718
719 if (selectionModel() && selectionModel()->isSelected(index))
720 {
721 option.state |= QStyle::State_Selected;
722 }
723
724 if (enabled)
725 {
726 QPalette::ColorGroup cg;
727 if ((d->proxyModel->flags(index) & Qt::ItemIsEnabled) == 0)
728 {
729 option.state &= ~QStyle::State_Enabled;
730 cg = QPalette::Disabled;
731 }
732 else
733 {
734 cg = QPalette::Normal;
735 }
736 option.palette.setCurrentColorGroup(cg);
737 }
738
739 if (focus && currentIndex() == index)
740 {
741 option.state |= QStyle::State_HasFocus;
742 if (this->state() == EditingState)
743 option.state |= QStyle::State_Editing;
744 }
745
746 if ((index == d->hovered) && !d->mouseButtonPressed)
747 option.state |= QStyle::State_MouseOver;
748 else
749 option.state &= ~QStyle::State_MouseOver;
750
751 itemDelegate(index)->paint(&painter, option, index);
752 }
753
754 // Redraw categories
755 QStyleOptionViewItem otherOption;
756 bool intersectedInThePast = false;
757 foreach (const QString &category, d->categories)
758 {
759 otherOption = option;
760 otherOption.rect = d->categoryVisualRect(category);
761 otherOption.state &= ~QStyle::State_MouseOver;
762
763 if (otherOption.rect.intersects(area))
764 {
765 intersectedInThePast = true;
766
767 QModelIndex indexToDraw = d->proxyModel->index(d->categoriesIndexes[category][0].row(), d->proxyModel->sortColumn());
768
769 d->drawNewCategory(indexToDraw,
770 d->proxyModel->sortRole(), otherOption, &painter);
771 }
772 else if (intersectedInThePast)
773 {
774 break; // the visible area has been finished, we don't need to keep asking, the rest won't intersect
775 // this is doable because we know that categories are correctly ordered on the list
776 }
777 }
778
779 if (d->mouseButtonPressed && !d->isDragging)
780 {
781 QPoint start, end, initialPressPosition;
782
783 initialPressPosition = d->initialPressPosition;
784
785 initialPressPosition.setY(initialPressPosition.y() - verticalOffset());
786 initialPressPosition.setX(initialPressPosition.x() - horizontalOffset());
787
788 if (d->initialPressPosition.x() > d->mousePosition.x() ||
789 d->initialPressPosition.y() > d->mousePosition.y())
790 {
791 start = d->mousePosition;
792 end = initialPressPosition;
793 }
794 else
795 {
796 start = initialPressPosition;
797 end = d->mousePosition;
798 }
799
800 QStyleOptionRubberBand yetAnotherOption;
801 yetAnotherOption.initFrom(this);
802 yetAnotherOption.shape = QRubberBand::Rectangle;
803 yetAnotherOption.opaque = false;
804 yetAnotherOption.rect = QRect(start, end).intersected(viewport()->rect().adjusted(-16, -16, 16, 16));
805 painter.save();
806 style()->drawControl(QStyle::CE_RubberBand, &yetAnotherOption, &painter);
807 painter.restore();
808 }
809
810 if (d->isDragging && !d->dragLeftViewport)
811 {
812 painter.setOpacity(0.5);
813 d->drawDraggedItems(&painter);
814 }
815
816 painter.restore();
817 }
818
819 void KCategorizedView::resizeEvent(QResizeEvent *event)
820 {
821 QListView::resizeEvent(event);
822
823 // Clear the items positions cache
824 d->elementsPosition.clear();
825 d->categoriesPosition.clear();
826 d->forcedSelectionPosition = 0;
827
828 if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
829 !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
830 {
831 return;
832 }
833
834 d->updateScrollbars();
835 }
836
837 void KCategorizedView::setSelection(const QRect &rect,
838 QItemSelectionModel::SelectionFlags flags)
839 {
840 if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
841 !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
842 {
843 QListView::setSelection(rect, flags);
844 return;
845 }
846
847 if (!flags)
848 return;
849
850 if (flags & QItemSelectionModel::Clear)
851 {
852 selectionModel()->clear();
853 }
854
855 QModelIndexList dirtyIndexes = d->intersectionSet(rect);
856
857 // no items affected, just leave
858 if (!dirtyIndexes.count())
859 {
860 selectionModel()->select(d->lastSelection, flags);
861
862 d->lastSelection.clear();
863
864 return;
865 }
866
867 d->lastSelection.clear();
868
869 if (!(flags & QItemSelectionModel::Current))
870 {
871 Q_ASSERT(dirtyIndexes.count() == 1);
872
873 selectionModel()->select(dirtyIndexes[0], flags);
874
875 return;
876 }
877
878 QModelIndex topLeft;
879 QModelIndex bottomRight;
880
881 if (d->mouseButtonPressed) // selection with click + drag
882 {
883 QModelIndex prev = dirtyIndexes[0];
884 QModelIndex first = prev;
885 foreach (const QModelIndex &index, dirtyIndexes)
886 {
887 if ((index.row() - prev.row()) > 1) {
888 d->lastSelection << QItemSelectionRange(first, prev);
889
890 first = index;
891 }
892
893 prev = index;
894 }
895
896 d->lastSelection << QItemSelectionRange(first, prev);
897
898 selectionModel()->select(d->lastSelection, flags);
899 }
900 else // selection with click + keyboard keys
901 {
902 QModelIndex topLeftIndex = indexAt(QPoint(rect.topLeft().x(),
903 rect.topLeft().y()));
904 QModelIndex bottomRightIndex = indexAt(QPoint(rect.bottomRight().x(),
905 rect.bottomRight().y()));
906
907 // keyboard selection comes "upside down". Let's normalize it
908 if (topLeftIndex.row() > bottomRightIndex.row())
909 {
910 QModelIndex auxIndex = topLeftIndex;
911 topLeftIndex = bottomRightIndex;
912 bottomRightIndex = auxIndex;
913 }
914
915 int viewportWidth = viewport()->width() - spacing();
916 int itemWidth;
917
918 if (gridSize().isEmpty())
919 {
920 itemWidth = d->biggestItemSize.width();
921 }
922 else
923 {
924 itemWidth = gridSize().width();
925 }
926
927 int itemWidthPlusSeparation = spacing() + itemWidth;
928 int elementsPerRow = viewportWidth / itemWidthPlusSeparation;
929 if (!elementsPerRow)
930 elementsPerRow++;
931
932 QModelIndexList theoricDirty(dirtyIndexes);
933 dirtyIndexes.clear();
934 int first = model()->rowCount();
935 int last = 0;
936
937 foreach (const QModelIndex &index, theoricDirty)
938 {
939 if ((index.row() < first) &&
940 ((((topLeftIndex.row() / elementsPerRow) == (index.row() / elementsPerRow)) &&
941 ((topLeftIndex.row() % elementsPerRow) <= (index.row() % elementsPerRow))) ||
942 (topLeftIndex.row() / elementsPerRow) != (index.row() / elementsPerRow)))
943 {
944 first = index.row();
945 topLeft = index;
946 }
947
948 if ((index.row() > last) &&
949 ((((bottomRightIndex.row() / elementsPerRow) == (index.row() / elementsPerRow)) &&
950 ((bottomRightIndex.row() % elementsPerRow) >= (index.row() % elementsPerRow))) ||
951 (bottomRightIndex.row() / elementsPerRow) != (index.row() / elementsPerRow)))
952 {
953 last = index.row();
954 bottomRight = index;
955 }
956 }
957
958 for (int i = first; i <= last; i++)
959 {
960 dirtyIndexes << model()->index(i, theoricDirty[0].column(), theoricDirty[0].parent());
961 }
962
963 // our current selection will result modified
964 d->lastSelection = QItemSelection(topLeft, bottomRight);
965
966 selectionModel()->select(d->lastSelection, flags);
967 }
968 }
969
970 void KCategorizedView::mouseMoveEvent(QMouseEvent *event)
971 {
972 QListView::mouseMoveEvent(event);
973
974 if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
975 !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
976 {
977 return;
978 }
979
980 const QString previousHoveredCategory = d->hoveredCategory;
981
982 d->mousePosition = event->pos();
983 d->hoveredCategory = QString();
984
985 // Redraw categories
986 foreach (const QString &category, d->categories)
987 {
988 if (d->categoryVisualRect(category).intersects(QRect(event->pos(), event->pos())))
989 {
990 d->hoveredCategory = category;
991 viewport()->update(d->categoryVisualRect(category));
992 }
993 else if ((category == previousHoveredCategory) &&
994 (!d->categoryVisualRect(previousHoveredCategory).intersects(QRect(event->pos(), event->pos()))))
995 {
996 viewport()->update(d->categoryVisualRect(category));
997 }
998 }
999
1000 QRect rect;
1001 if (d->mouseButtonPressed && !d->isDragging)
1002 {
1003 QPoint start, end, initialPressPosition;
1004
1005 initialPressPosition = d->initialPressPosition;
1006
1007 initialPressPosition.setY(initialPressPosition.y() - verticalOffset());
1008 initialPressPosition.setX(initialPressPosition.x() - horizontalOffset());
1009
1010 if (d->initialPressPosition.x() > d->mousePosition.x() ||
1011 d->initialPressPosition.y() > d->mousePosition.y())
1012 {
1013 start = d->mousePosition;
1014 end = initialPressPosition;
1015 }
1016 else
1017 {
1018 start = initialPressPosition;
1019 end = d->mousePosition;
1020 }
1021
1022 rect = QRect(start, end).intersected(viewport()->rect().adjusted(-16, -16, 16, 16));
1023 }
1024 }
1025
1026 void KCategorizedView::mousePressEvent(QMouseEvent *event)
1027 {
1028 d->dragLeftViewport = false;
1029
1030 if (event->button() == Qt::LeftButton)
1031 {
1032 d->mouseButtonPressed = true;
1033
1034 d->initialPressPosition = event->pos();
1035 d->initialPressPosition.setY(d->initialPressPosition.y() +
1036 verticalOffset());
1037 d->initialPressPosition.setX(d->initialPressPosition.x() +
1038 horizontalOffset());
1039 }
1040
1041 QListView::mousePressEvent(event);
1042
1043 viewport()->update(d->categoryVisualRect(d->hoveredCategory));
1044 }
1045
1046 void KCategorizedView::mouseReleaseEvent(QMouseEvent *event)
1047 {
1048 d->mouseButtonPressed = false;
1049
1050 QListView::mouseReleaseEvent(event);
1051
1052 if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
1053 !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
1054 {
1055 return;
1056 }
1057
1058 QPoint initialPressPosition = viewport()->mapFromGlobal(QCursor::pos());
1059 initialPressPosition.setY(initialPressPosition.y() + verticalOffset());
1060 initialPressPosition.setX(initialPressPosition.x() + horizontalOffset());
1061
1062 if (initialPressPosition == d->initialPressPosition)
1063 {
1064 foreach(const QString &category, d->categories)
1065 {
1066 if (d->categoryVisualRect(category).contains(event->pos()))
1067 {
1068 QItemSelection selection;
1069 QModelIndexList indexList = d->categoriesIndexes[category];
1070
1071 foreach (const QModelIndex &index, indexList)
1072 {
1073 QModelIndex selectIndex = index.model()->index(index.row(), 0);
1074
1075 selection << QItemSelectionRange(selectIndex);
1076 }
1077
1078 selectionModel()->select(selection, QItemSelectionModel::SelectCurrent);
1079
1080 break;
1081 }
1082 }
1083 }
1084
1085 if (d->hovered.isValid())
1086 viewport()->update(visualRect(d->hovered));
1087 else if (!d->hoveredCategory.isEmpty())
1088 viewport()->update(d->categoryVisualRect(d->hoveredCategory));
1089 }
1090
1091 void KCategorizedView::leaveEvent(QEvent *event)
1092 {
1093 d->hovered = QModelIndex();
1094 d->hoveredCategory = QString();
1095
1096 QListView::leaveEvent(event);
1097 }
1098
1099 void KCategorizedView::startDrag(Qt::DropActions supportedActions)
1100 {
1101 // FIXME: QAbstractItemView does far better here since it sets the
1102 // pixmap of selected icons to the dragging cursor, but it sets a non
1103 // ARGB window so it is no transparent. Use QAbstractItemView when
1104 // this is fixed on Qt.
1105 // QAbstractItemView::startDrag(supportedActions);
1106 #if !defined(DOLPHIN_DRAGANDDROP)
1107 QListView::startDrag(supportedActions);
1108 #endif
1109
1110 d->isDragging = false;
1111 d->mouseButtonPressed = false;
1112
1113 viewport()->update(d->lastDraggedItemsRect);
1114 }
1115
1116 void KCategorizedView::dragMoveEvent(QDragMoveEvent *event)
1117 {
1118 d->mousePosition = event->pos();
1119
1120 if (d->mouseButtonPressed)
1121 {
1122 d->isDragging = true;
1123 }
1124 else
1125 {
1126 d->isDragging = false;
1127 }
1128
1129 d->dragLeftViewport = false;
1130
1131 if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
1132 !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
1133 {
1134 #if defined(DOLPHIN_DRAGANDDROP)
1135 QAbstractItemView::dragMoveEvent(event);
1136 #else
1137 QListView::dragMoveEvent(event);
1138 #endif
1139 return;
1140 }
1141
1142 d->drawDraggedItems();
1143 }
1144
1145 void KCategorizedView::dragLeaveEvent(QDragLeaveEvent *event)
1146 {
1147 d->dragLeftViewport = true;
1148
1149 #if defined(DOLPHIN_DRAGANDDROP)
1150 QAbstractItemView::dragLeaveEvent(event);
1151 #else
1152 QListView::dragLeaveEvent(event);
1153 #endif
1154 }
1155
1156 void KCategorizedView::dropEvent(QDropEvent *event)
1157 {
1158 #if defined(DOLPHIN_DRAGANDDROP)
1159 QAbstractItemView::dropEvent(event);
1160 #else
1161 QListView::dropEvent(event);
1162 #endif
1163 }
1164
1165 QModelIndex KCategorizedView::moveCursor(CursorAction cursorAction,
1166 Qt::KeyboardModifiers modifiers)
1167 {
1168 if ((viewMode() != KCategorizedView::IconMode) ||
1169 !d->proxyModel ||
1170 !d->categoryDrawer ||
1171 d->categories.isEmpty() ||
1172 !d->proxyModel->isCategorizedModel()
1173 )
1174 {
1175 return QListView::moveCursor(cursorAction, modifiers);
1176 }
1177
1178 QModelIndex current = selectionModel()->currentIndex();
1179
1180 if (!current.isValid())
1181 {
1182 current = model()->index(0, 0, QModelIndex());
1183 setCurrentIndex(current);
1184 d->forcedSelectionPosition = 0;
1185
1186 return current;
1187 }
1188
1189 int viewportWidth = viewport()->width() - spacing();
1190 int itemWidth;
1191
1192 if (gridSize().isEmpty())
1193 {
1194 itemWidth = d->biggestItemSize.width();
1195 }
1196 else
1197 {
1198 itemWidth = gridSize().width();
1199 }
1200
1201 int itemWidthPlusSeparation = spacing() + itemWidth;
1202 int elementsPerRow = viewportWidth / itemWidthPlusSeparation;
1203 if (!elementsPerRow)
1204 elementsPerRow++;
1205
1206 QString lastCategory = d->categories.first();
1207 QString theCategory = d->categories.first();
1208 QString afterCategory = d->categories.first();
1209
1210 bool hasToBreak = false;
1211 foreach (const QString &category, d->categories)
1212 {
1213 if (hasToBreak)
1214 {
1215 afterCategory = category;
1216
1217 break;
1218 }
1219
1220 if (category == d->elementsInfo[current.row()].category)
1221 {
1222 theCategory = category;
1223
1224 hasToBreak = true;
1225 }
1226
1227 if (!hasToBreak)
1228 {
1229 lastCategory = category;
1230 }
1231 }
1232
1233 switch (cursorAction)
1234 {
1235 case QAbstractItemView::MoveUp: {
1236 if (d->elementsInfo[current.row()].relativeOffsetToCategory >= elementsPerRow)
1237 {
1238 int indexToMove = current.row();
1239 indexToMove -= qMin(((d->elementsInfo[current.row()].relativeOffsetToCategory) + d->forcedSelectionPosition), elementsPerRow - d->forcedSelectionPosition + (d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow));
1240
1241 return d->proxyModel->index(indexToMove, 0);
1242 }
1243 else
1244 {
1245 int lastCategoryLastRow = (d->categoriesIndexes[lastCategory].count() - 1) % elementsPerRow;
1246 int indexToMove = current.row() - d->elementsInfo[current.row()].relativeOffsetToCategory;
1247
1248 if (d->forcedSelectionPosition >= lastCategoryLastRow)
1249 {
1250 indexToMove -= 1;
1251 }
1252 else
1253 {
1254 indexToMove -= qMin((lastCategoryLastRow - d->forcedSelectionPosition + 1), d->forcedSelectionPosition + elementsPerRow + 1);
1255 }
1256
1257 return d->proxyModel->index(indexToMove, 0);
1258 }
1259 }
1260
1261 case QAbstractItemView::MoveDown: {
1262 if (d->elementsInfo[current.row()].relativeOffsetToCategory < (d->categoriesIndexes[theCategory].count() - 1 - ((d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow)))
1263 {
1264 int indexToMove = current.row();
1265 indexToMove += qMin(elementsPerRow, d->categoriesIndexes[theCategory].count() - 1 - d->elementsInfo[current.row()].relativeOffsetToCategory);
1266
1267 return d->proxyModel->index(indexToMove, 0);
1268 }
1269 else
1270 {
1271 int afterCategoryLastRow = qMin(elementsPerRow, d->categoriesIndexes[afterCategory].count());
1272 int indexToMove = current.row() + (d->categoriesIndexes[theCategory].count() - d->elementsInfo[current.row()].relativeOffsetToCategory);
1273
1274 if (d->forcedSelectionPosition >= afterCategoryLastRow)
1275 {
1276 indexToMove += afterCategoryLastRow - 1;
1277 }
1278 else
1279 {
1280 indexToMove += qMin(d->forcedSelectionPosition, elementsPerRow);
1281 }
1282
1283 return d->proxyModel->index(indexToMove, 0);
1284 }
1285 }
1286
1287 case QAbstractItemView::MoveLeft:
1288 if (layoutDirection() == Qt::RightToLeft)
1289 {
1290 if (!(d->elementsInfo[current.row() + 1].relativeOffsetToCategory % elementsPerRow))
1291 return current;
1292
1293 d->forcedSelectionPosition = d->elementsInfo[current.row() + 1].relativeOffsetToCategory % elementsPerRow;
1294
1295 #if 0 //follow qt view behavior. lateral movements won't change visual row
1296 if (d->forcedSelectionPosition < 0)
1297 d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow;
1298 #endif
1299
1300 return d->proxyModel->index(current.row() + 1, 0);
1301 }
1302
1303 if (!(d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow))
1304 return current;
1305
1306 d->forcedSelectionPosition = d->elementsInfo[current.row() - 1].relativeOffsetToCategory % elementsPerRow;
1307
1308 #if 0 //follow qt view behavior. lateral movements won't change visual row
1309 if (d->forcedSelectionPosition < 0)
1310 d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow;
1311 #endif
1312
1313 return d->proxyModel->index(current.row() - 1, 0);
1314
1315 case QAbstractItemView::MoveRight:
1316 if (layoutDirection() == Qt::RightToLeft)
1317 {
1318 if (!(d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow))
1319 return current;
1320
1321 d->forcedSelectionPosition = d->elementsInfo[current.row() - 1].relativeOffsetToCategory % elementsPerRow;
1322
1323 #if 0 //follow qt view behavior. lateral movements won't change visual row
1324 if (d->forcedSelectionPosition < 0)
1325 d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow;
1326 #endif
1327
1328 return d->proxyModel->index(current.row() - 1, 0);
1329 }
1330
1331 if (!(d->elementsInfo[current.row() + 1].relativeOffsetToCategory % elementsPerRow))
1332 return current;
1333
1334 d->forcedSelectionPosition = d->elementsInfo[current.row() + 1].relativeOffsetToCategory % elementsPerRow;
1335
1336 #if 0 //follow qt view behavior. lateral movements won't change visual row
1337 if (d->forcedSelectionPosition < 0)
1338 d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow;
1339 #endif
1340
1341 return d->proxyModel->index(current.row() + 1, 0);
1342
1343 default:
1344 break;
1345 }
1346
1347 return QListView::moveCursor(cursorAction, modifiers);
1348 }
1349
1350 void KCategorizedView::rowsInserted(const QModelIndex &parent,
1351 int start,
1352 int end)
1353 {
1354 QListView::rowsInserted(parent, start, end);
1355
1356 if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
1357 !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
1358 {
1359 d->lastSelection = QItemSelection();
1360 d->currentViewIndex = QModelIndex();
1361 d->forcedSelectionPosition = 0;
1362 d->elementsInfo.clear();
1363 d->elementsPosition.clear();
1364 d->categoriesIndexes.clear();
1365 d->categoriesPosition.clear();
1366 d->categories.clear();
1367 d->intersectedIndexes.clear();
1368 d->modelIndexList.clear();
1369 d->hovered = QModelIndex();
1370 d->biggestItemSize = QSize(0, 0);
1371 d->mouseButtonPressed = false;
1372
1373 return;
1374 }
1375
1376 rowsInsertedArtifficial(parent, start, end);
1377 }
1378
1379 void KCategorizedView::rowsInsertedArtifficial(const QModelIndex &parent,
1380 int start,
1381 int end)
1382 {
1383 Q_UNUSED(parent);
1384
1385 d->lastSelection = QItemSelection();
1386 d->currentViewIndex = QModelIndex();
1387 d->forcedSelectionPosition = 0;
1388 d->elementsInfo.clear();
1389 d->elementsPosition.clear();
1390 d->categoriesIndexes.clear();
1391 d->categoriesPosition.clear();
1392 d->categories.clear();
1393 d->intersectedIndexes.clear();
1394 d->modelIndexList.clear();
1395 d->hovered = QModelIndex();
1396 d->biggestItemSize = QSize(0, 0);
1397 d->mouseButtonPressed = false;
1398
1399 if (start > end || end < 0 || start < 0 || !d->proxyModel->rowCount())
1400 {
1401 return;
1402 }
1403
1404 // Add all elements mapped to the source model and explore categories
1405 QString prevCategory = d->proxyModel->data(d->proxyModel->index(0, d->proxyModel->sortColumn()), KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
1406 QString lastCategory = prevCategory;
1407 QModelIndexList modelIndexList;
1408 struct Private::ElementInfo elementInfo;
1409 int offset = -1;
1410 for (int k = 0; k < d->proxyModel->rowCount(); ++k)
1411 {
1412 QModelIndex index = d->proxyModel->index(k, d->proxyModel->sortColumn());
1413 QModelIndex indexSize = d->proxyModel->index(k, 0);
1414
1415 d->biggestItemSize = QSize(qMax(sizeHintForIndex(indexSize).width(),
1416 d->biggestItemSize.width()),
1417 qMax(sizeHintForIndex(indexSize).height(),
1418 d->biggestItemSize.height()));
1419
1420 d->modelIndexList << index;
1421
1422 lastCategory = d->proxyModel->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
1423
1424 elementInfo.category = lastCategory;
1425
1426 if (prevCategory != lastCategory)
1427 {
1428 offset = 0;
1429 d->categoriesIndexes.insert(prevCategory, modelIndexList);
1430 d->categories << prevCategory;
1431 modelIndexList.clear();
1432 }
1433 else
1434 {
1435 offset++;
1436 }
1437
1438 elementInfo.relativeOffsetToCategory = offset;
1439
1440 modelIndexList << index;
1441 prevCategory = lastCategory;
1442
1443 d->elementsInfo.insert(index.row(), elementInfo);
1444 }
1445
1446 d->categoriesIndexes.insert(prevCategory, modelIndexList);
1447 d->categories << prevCategory;
1448
1449 d->updateScrollbars();
1450 }
1451
1452 void KCategorizedView::rowsRemoved(const QModelIndex &parent,
1453 int start,
1454 int end)
1455 {
1456 if ((viewMode() == KCategorizedView::IconMode) && d->proxyModel &&
1457 d->categoryDrawer && d->proxyModel->isCategorizedModel())
1458 {
1459 // Force the view to update all elements
1460 rowsInsertedArtifficial(QModelIndex(), 0, d->proxyModel->rowCount() - 1);
1461 }
1462 }
1463
1464 void KCategorizedView::updateGeometries()
1465 {
1466 if ((viewMode() != KCategorizedView::IconMode) || !d->proxyModel ||
1467 !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
1468 {
1469 QListView::updateGeometries();
1470 return;
1471 }
1472
1473 // Avoid QListView::updateGeometries(), since it will try to set another
1474 // range to our scroll bars, what we don't want (ereslibre)
1475 QAbstractItemView::updateGeometries();
1476 }
1477
1478 void KCategorizedView::slotLayoutChanged()
1479 {
1480 d->layoutChanged();
1481 }
1482
1483 #include "kcategorizedview.moc"