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