00001
00021 #include "kcategorizedview.h"
00022 #include "kcategorizedview_p.h"
00023
00024 #include <math.h>
00025 #include <kdefakes.h>
00026
00027 #include <QPainter>
00028 #include <QScrollBar>
00029 #include <QPaintEvent>
00030
00031 #include <kdebug.h>
00032
00033 #include "kcategorydrawer.h"
00034 #include "kcategorizedsortfilterproxymodel.h"
00035
00036
00037
00038
00039
00040 #define DOLPHIN_DRAGANDDROP
00041
00042 KCategorizedView::Private::Private(KCategorizedView *listView)
00043 : listView(listView)
00044 , categoryDrawer(0)
00045 , biggestItemSize(QSize(0, 0))
00046 , mouseButtonPressed(false)
00047 , rightMouseButtonPressed(false)
00048 , isDragging(false)
00049 , dragLeftViewport(false)
00050 , proxyModel(0)
00051 {
00052 }
00053
00054 KCategorizedView::Private::~Private()
00055 {
00056 }
00057
00058 const QModelIndexList &KCategorizedView::Private::intersectionSet(const QRect &rect)
00059 {
00060 QModelIndex index;
00061 QRect indexVisualRect;
00062
00063 intersectedIndexes.clear();
00064
00065 int itemHeight;
00066
00067 if (listView->gridSize().isEmpty())
00068 {
00069 itemHeight = biggestItemSize.height();
00070 }
00071 else
00072 {
00073 itemHeight = listView->gridSize().height();
00074 }
00075
00076
00077 int top = proxyModel->rowCount() - 1;
00078 int bottom = 0;
00079 int middle = (top + bottom) / 2;
00080 while (bottom <= top)
00081 {
00082 middle = (top + bottom) / 2;
00083
00084 index = proxyModel->index(middle, 0);
00085 indexVisualRect = visualRect(index);
00086
00087
00088 indexVisualRect.setHeight(indexVisualRect.height() + (itemHeight - indexVisualRect.height()));
00089
00090 if (qMax(indexVisualRect.topLeft().y(),
00091 indexVisualRect.bottomRight().y()) < qMin(rect.topLeft().y(),
00092 rect.bottomRight().y()))
00093 {
00094 bottom = middle + 1;
00095 }
00096 else
00097 {
00098 top = middle - 1;
00099 }
00100 }
00101
00102 for (int i = middle; i < proxyModel->rowCount(); i++)
00103 {
00104 index = proxyModel->index(i, 0);
00105 indexVisualRect = visualRect(index);
00106
00107 if (rect.intersects(indexVisualRect))
00108 intersectedIndexes.append(index);
00109
00110
00111 if (qMax(rect.bottomRight().y(), rect.topLeft().y()) <
00112 qMin(indexVisualRect.topLeft().y(),
00113 indexVisualRect.bottomRight().y()))
00114 break;
00115 }
00116
00117 return intersectedIndexes;
00118 }
00119
00120 QRect KCategorizedView::Private::visualRectInViewport(const QModelIndex &index) const
00121 {
00122 if (!index.isValid())
00123 return QRect();
00124
00125 QString curCategory = elementsInfo[index.row()].category;
00126
00127 QRect retRect;
00128 const bool leftToRightFlow = (listView->flow() == QListView::LeftToRight);
00129
00130 if (leftToRightFlow)
00131 {
00132 if (listView->layoutDirection() == Qt::LeftToRight)
00133 {
00134 retRect = QRect(listView->spacing(), listView->spacing() * 2 +
00135 categoryDrawer->categoryHeight(index, listView->viewOptions()), 0, 0);
00136 }
00137 else
00138 {
00139 retRect = QRect(listView->viewport()->width() - listView->spacing(), listView->spacing() * 2 +
00140 categoryDrawer->categoryHeight(index, listView->viewOptions()), 0, 0);
00141 }
00142 }
00143 else
00144 {
00145 retRect = QRect(listView->spacing(), listView->spacing() * 2 +
00146 categoryDrawer->categoryHeight(index, listView->viewOptions()), 0, 0);
00147 }
00148
00149 int viewportWidth = listView->viewport()->width() - listView->spacing();
00150
00151 int itemHeight;
00152 int itemWidth;
00153
00154 if (listView->gridSize().isEmpty() && leftToRightFlow)
00155 {
00156 itemHeight = biggestItemSize.height();
00157 itemWidth = biggestItemSize.width();
00158 }
00159 else if (leftToRightFlow)
00160 {
00161 itemHeight = listView->gridSize().height();
00162 itemWidth = listView->gridSize().width();
00163 }
00164 else if (listView->gridSize().isEmpty() && !leftToRightFlow)
00165 {
00166 itemHeight = biggestItemSize.height();
00167 itemWidth = listView->viewport()->width() - listView->spacing() * 2;
00168 }
00169 else
00170 {
00171 itemHeight = listView->gridSize().height();
00172 itemWidth = listView->gridSize().width() - listView->spacing() * 2;
00173 }
00174
00175 int itemWidthPlusSeparation = listView->spacing() + itemWidth;
00176 if (!itemWidthPlusSeparation)
00177 itemWidthPlusSeparation++;
00178 int elementsPerRow = viewportWidth / itemWidthPlusSeparation;
00179 if (!elementsPerRow)
00180 elementsPerRow++;
00181
00182 int column;
00183 int row;
00184
00185 if (leftToRightFlow)
00186 {
00187 column = elementsInfo[index.row()].relativeOffsetToCategory % elementsPerRow;
00188 row = elementsInfo[index.row()].relativeOffsetToCategory / elementsPerRow;
00189
00190 if (listView->layoutDirection() == Qt::LeftToRight)
00191 {
00192 retRect.setLeft(retRect.left() + column * listView->spacing() +
00193 column * itemWidth);
00194 }
00195 else
00196 {
00197 retRect.setLeft(retRect.right() - column * listView->spacing() -
00198 column * itemWidth - itemWidth);
00199
00200 retRect.setRight(retRect.right() - column * listView->spacing() -
00201 column * itemWidth);
00202 }
00203 }
00204 else
00205 {
00206 elementsPerRow = 1;
00207 column = elementsInfo[index.row()].relativeOffsetToCategory % elementsPerRow;
00208 row = elementsInfo[index.row()].relativeOffsetToCategory / elementsPerRow;
00209 }
00210
00211 foreach (const QString &category, categories)
00212 {
00213 if (category == curCategory)
00214 break;
00215
00216 float rows = (float) ((float) categoriesIndexes[category].count() /
00217 (float) elementsPerRow);
00218
00219 int rowsInt = categoriesIndexes[category].count() / elementsPerRow;
00220
00221 if (rows - trunc(rows)) rowsInt++;
00222
00223 retRect.setTop(retRect.top() +
00224 (rowsInt * itemHeight) +
00225 categoryDrawer->categoryHeight(index, listView->viewOptions()) +
00226 listView->spacing() * 2);
00227
00228 if (listView->gridSize().isEmpty())
00229 {
00230 retRect.setTop(retRect.top() +
00231 (rowsInt * listView->spacing()));
00232 }
00233 }
00234
00235 if (listView->gridSize().isEmpty())
00236 {
00237 retRect.setTop(retRect.top() + row * listView->spacing() +
00238 (row * itemHeight));
00239 }
00240 else
00241 {
00242 retRect.setTop(retRect.top() + (row * itemHeight));
00243 }
00244
00245 retRect.setWidth(itemWidth);
00246
00247 QModelIndex heightIndex = proxyModel->index(index.row(), 0);
00248 if (listView->gridSize().isEmpty())
00249 {
00250 retRect.setHeight(listView->sizeHintForIndex(heightIndex).height());
00251 }
00252 else
00253 {
00254 const QSize sizeHint = listView->sizeHintForIndex(heightIndex);
00255 if (sizeHint.width() < itemWidth && leftToRightFlow) {
00256 retRect.setWidth(sizeHint.width());
00257 retRect.moveLeft(retRect.left() + (itemWidth - sizeHint.width()) / 2);
00258 }
00259 retRect.setHeight(qMin(sizeHint.height(), listView->gridSize().height()));
00260 }
00261
00262 return retRect;
00263 }
00264
00265 QRect KCategorizedView::Private::visualCategoryRectInViewport(const QString &category) const
00266 {
00267 QRect retRect(listView->spacing(),
00268 listView->spacing(),
00269 listView->viewport()->width() - listView->spacing() * 2,
00270 0);
00271
00272 if (!proxyModel || !categoryDrawer || !proxyModel->isCategorizedModel() || !proxyModel->rowCount() || !categories.contains(category))
00273 return QRect();
00274
00275 QModelIndex index = proxyModel->index(0, 0, QModelIndex());
00276
00277 int viewportWidth = listView->viewport()->width() - listView->spacing();
00278
00279 int itemHeight;
00280 int itemWidth;
00281
00282 if (listView->gridSize().isEmpty())
00283 {
00284 itemHeight = biggestItemSize.height();
00285 itemWidth = biggestItemSize.width();
00286 }
00287 else
00288 {
00289 itemHeight = listView->gridSize().height();
00290 itemWidth = listView->gridSize().width();
00291 }
00292
00293 int itemWidthPlusSeparation = listView->spacing() + itemWidth;
00294 int elementsPerRow = viewportWidth / itemWidthPlusSeparation;
00295
00296 if (!elementsPerRow)
00297 elementsPerRow++;
00298
00299 if (listView->flow() == QListView::TopToBottom)
00300 {
00301 elementsPerRow = 1;
00302 }
00303
00304 foreach (const QString &itCategory, categories)
00305 {
00306 if (itCategory == category)
00307 break;
00308
00309 float rows = (float) ((float) categoriesIndexes[itCategory].count() /
00310 (float) elementsPerRow);
00311 int rowsInt = categoriesIndexes[itCategory].count() / elementsPerRow;
00312
00313 if (rows - trunc(rows)) rowsInt++;
00314
00315 retRect.setTop(retRect.top() +
00316 (rowsInt * itemHeight) +
00317 categoryDrawer->categoryHeight(index, listView->viewOptions()) +
00318 listView->spacing() * 2);
00319
00320 if (listView->gridSize().isEmpty())
00321 {
00322 retRect.setTop(retRect.top() +
00323 (rowsInt * listView->spacing()));
00324 }
00325 }
00326
00327 retRect.setHeight(categoryDrawer->categoryHeight(index, listView->viewOptions()));
00328
00329 return retRect;
00330 }
00331
00332
00333 const QRect &KCategorizedView::Private::cacheIndex(const QModelIndex &index)
00334 {
00335 QRect rect = visualRectInViewport(index);
00336 QHash<int, QRect>::iterator it = elementsPosition.insert(index.row(), rect);
00337
00338 return *it;
00339 }
00340
00341
00342 const QRect &KCategorizedView::Private::cacheCategory(const QString &category)
00343 {
00344 QRect rect = visualCategoryRectInViewport(category);
00345 QHash<QString, QRect>::iterator it = categoriesPosition.insert(category, rect);
00346
00347 return *it;
00348 }
00349
00350 const QRect &KCategorizedView::Private::cachedRectIndex(const QModelIndex &index)
00351 {
00352 QHash<int, QRect>::const_iterator it = elementsPosition.constFind(index.row());
00353 if (it != elementsPosition.constEnd())
00354 {
00355 return *it;
00356 }
00357 else
00358 {
00359 return cacheIndex(index);
00360 }
00361 }
00362
00363 const QRect &KCategorizedView::Private::cachedRectCategory(const QString &category)
00364 {
00365 QHash<QString, QRect>::const_iterator it = categoriesPosition.constFind(category);
00366 if (it != categoriesPosition.constEnd())
00367 {
00368 return *it;
00369 }
00370 else
00371 {
00372 return cacheCategory(category);
00373 }
00374 }
00375
00376 QRect KCategorizedView::Private::visualRect(const QModelIndex &index)
00377 {
00378 QRect retRect = cachedRectIndex(index);
00379 int dx = -listView->horizontalOffset();
00380 int dy = -listView->verticalOffset();
00381 retRect.adjust(dx, dy, dx, dy);
00382
00383 return retRect;
00384 }
00385
00386 QRect KCategorizedView::Private::categoryVisualRect(const QString &category)
00387 {
00388 QRect retRect = cachedRectCategory(category);
00389 int dx = -listView->horizontalOffset();
00390 int dy = -listView->verticalOffset();
00391 retRect.adjust(dx, dy, dx, dy);
00392
00393 return retRect;
00394 }
00395
00396 void KCategorizedView::Private::drawNewCategory(const QModelIndex &index,
00397 int sortRole,
00398 const QStyleOption &option,
00399 QPainter *painter)
00400 {
00401 if (!index.isValid())
00402 {
00403 return;
00404 }
00405
00406 QStyleOption optionCopy = option;
00407 const QString category = proxyModel->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
00408
00409 optionCopy.state &= ~QStyle::State_Selected;
00410
00411 if ((listView->selectionMode() != SingleSelection) && (listView->selectionMode() != NoSelection)) {
00412 if ((category == hoveredCategory) && !mouseButtonPressed)
00413 {
00414 optionCopy.state |= QStyle::State_MouseOver;
00415 }
00416 else if ((category == hoveredCategory) && mouseButtonPressed)
00417 {
00418 QPoint initialPressPosition = listView->viewport()->mapFromGlobal(QCursor::pos());
00419 initialPressPosition.setY(initialPressPosition.y() + listView->verticalOffset());
00420 initialPressPosition.setX(initialPressPosition.x() + listView->horizontalOffset());
00421
00422 if (initialPressPosition == this->initialPressPosition)
00423 {
00424 optionCopy.state |= QStyle::State_Selected;
00425 }
00426 }
00427 }
00428
00429 categoryDrawer->drawCategory(index,
00430 sortRole,
00431 optionCopy,
00432 painter);
00433 }
00434
00435
00436 void KCategorizedView::Private::updateScrollbars()
00437 {
00438
00439 QModelIndex lastIndex = categoriesIndexes.isEmpty() ? QModelIndex() : categoriesIndexes[categories.last()].last();
00440
00441 int lastItemBottom = cachedRectIndex(lastIndex).top() +
00442 listView->spacing() + (listView->gridSize().isEmpty() ? biggestItemSize.height() : listView->gridSize().height()) - listView->viewport()->height();
00443
00444 listView->horizontalScrollBar()->setRange(0, 0);
00445
00446 if (listView->verticalScrollMode() == QAbstractItemView::ScrollPerItem)
00447 {
00448 listView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
00449 }
00450
00451 if (listView->horizontalScrollMode() == QAbstractItemView::ScrollPerItem)
00452 {
00453 listView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
00454 }
00455
00456 listView->verticalScrollBar()->setSingleStep(listView->viewport()->height() / 10);
00457 listView->verticalScrollBar()->setPageStep(listView->viewport()->height());
00458 listView->verticalScrollBar()->setRange(0, lastItemBottom);
00459 }
00460
00461 void KCategorizedView::Private::drawDraggedItems(QPainter *painter)
00462 {
00463 QStyleOptionViewItemV4 option = listView->viewOptions();
00464 option.state &= ~QStyle::State_MouseOver;
00465 foreach (const QModelIndex &index, listView->selectionModel()->selectedIndexes())
00466 {
00467 const int dx = mousePosition.x() - initialPressPosition.x() + listView->horizontalOffset();
00468 const int dy = mousePosition.y() - initialPressPosition.y() + listView->verticalOffset();
00469
00470 option.rect = visualRect(index);
00471 option.rect.adjust(dx, dy, dx, dy);
00472
00473 if (option.rect.intersects(listView->viewport()->rect()))
00474 {
00475 listView->itemDelegate(index)->paint(painter, option, index);
00476 }
00477 }
00478 }
00479
00480 void KCategorizedView::Private::layoutChanged(bool forceItemReload)
00481 {
00482 if (proxyModel && categoryDrawer && proxyModel->isCategorizedModel() &&
00483 ((forceItemReload ||
00484 (modelSortRole != proxyModel->sortRole()) ||
00485 (modelSortColumn != proxyModel->sortColumn()) ||
00486 (modelSortOrder != proxyModel->sortOrder()) ||
00487 (modelLastRowCount != proxyModel->rowCount()) ||
00488 (modelCategorized != proxyModel->isCategorizedModel()))))
00489 {
00490
00491 listView->rowsInsertedArtifficial(QModelIndex(), 0, proxyModel->rowCount() - 1);
00492
00493 if (!forceItemReload)
00494 {
00495 modelSortRole = proxyModel->sortRole();
00496 modelSortColumn = proxyModel->sortColumn();
00497 modelSortOrder = proxyModel->sortOrder();
00498 modelLastRowCount = proxyModel->rowCount();
00499 modelCategorized = proxyModel->isCategorizedModel();
00500 }
00501 }
00502
00503 if (proxyModel && categoryDrawer && proxyModel->isCategorizedModel())
00504 {
00505 updateScrollbars();
00506 }
00507 }
00508
00509 void KCategorizedView::Private::drawDraggedItems()
00510 {
00511 QRect rectToUpdate;
00512 QRect currentRect;
00513 foreach (const QModelIndex &index, listView->selectionModel()->selectedIndexes())
00514 {
00515 int dx = mousePosition.x() - initialPressPosition.x() + listView->horizontalOffset();
00516 int dy = mousePosition.y() - initialPressPosition.y() + listView->verticalOffset();
00517
00518 currentRect = visualRect(index);
00519 currentRect.adjust(dx, dy, dx, dy);
00520
00521 if (currentRect.intersects(listView->viewport()->rect()))
00522 {
00523 rectToUpdate = rectToUpdate.united(currentRect);
00524 }
00525 }
00526
00527 listView->viewport()->update(lastDraggedItemsRect.united(rectToUpdate));
00528
00529 lastDraggedItemsRect = rectToUpdate;
00530 }
00531
00532
00533
00534
00535
00536 KCategorizedView::KCategorizedView(QWidget *parent)
00537 : QListView(parent)
00538 , d(new Private(this))
00539 {
00540 }
00541
00542 KCategorizedView::~KCategorizedView()
00543 {
00544 delete d;
00545 }
00546
00547 void KCategorizedView::setGridSize(const QSize &size)
00548 {
00549 QListView::setGridSize(size);
00550
00551 d->layoutChanged(true);
00552 }
00553
00554 void KCategorizedView::setModel(QAbstractItemModel *model)
00555 {
00556 d->lastSelection = QItemSelection();
00557 d->forcedSelectionPosition = 0;
00558 d->elementsInfo.clear();
00559 d->elementsPosition.clear();
00560 d->categoriesIndexes.clear();
00561 d->categoriesPosition.clear();
00562 d->categories.clear();
00563 d->intersectedIndexes.clear();
00564 d->modelIndexList.clear();
00565 d->hovered = QModelIndex();
00566 d->mouseButtonPressed = false;
00567 d->rightMouseButtonPressed = false;
00568
00569 if (d->proxyModel)
00570 {
00571 QObject::disconnect(d->proxyModel,
00572 SIGNAL(layoutChanged()),
00573 this, SLOT(slotLayoutChanged()));
00574
00575 QObject::disconnect(d->proxyModel,
00576 SIGNAL(rowsRemoved(QModelIndex,int,int)),
00577 this, SLOT(rowsRemoved(QModelIndex,int,int)));
00578 }
00579
00580 QListView::setModel(model);
00581
00582 d->proxyModel = dynamic_cast<KCategorizedSortFilterProxyModel*>(model);
00583
00584 if (d->proxyModel)
00585 {
00586 d->modelSortRole = d->proxyModel->sortRole();
00587 d->modelSortColumn = d->proxyModel->sortColumn();
00588 d->modelSortOrder = d->proxyModel->sortOrder();
00589 d->modelLastRowCount = d->proxyModel->rowCount();
00590 d->modelCategorized = d->proxyModel->isCategorizedModel();
00591
00592 QObject::connect(d->proxyModel,
00593 SIGNAL(layoutChanged()),
00594 this, SLOT(slotLayoutChanged()));
00595
00596 QObject::connect(d->proxyModel,
00597 SIGNAL(rowsRemoved(QModelIndex,int,int)),
00598 this, SLOT(rowsRemoved(QModelIndex,int,int)));
00599
00600 if (d->proxyModel->rowCount())
00601 {
00602 d->layoutChanged(true);
00603 }
00604 }
00605 else
00606 {
00607 d->modelCategorized = false;
00608 }
00609 }
00610
00611 QRect KCategorizedView::visualRect(const QModelIndex &index) const
00612 {
00613 if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
00614 {
00615 return QListView::visualRect(index);
00616 }
00617
00618 if (!qobject_cast<const QSortFilterProxyModel*>(index.model()))
00619 {
00620 return d->visualRect(d->proxyModel->mapFromSource(index));
00621 }
00622
00623 return d->visualRect(index);
00624 }
00625
00626 KCategoryDrawer *KCategorizedView::categoryDrawer() const
00627 {
00628 return d->categoryDrawer;
00629 }
00630
00631 void KCategorizedView::setCategoryDrawer(KCategoryDrawer *categoryDrawer)
00632 {
00633 d->lastSelection = QItemSelection();
00634 d->forcedSelectionPosition = 0;
00635 d->elementsInfo.clear();
00636 d->elementsPosition.clear();
00637 d->categoriesIndexes.clear();
00638 d->categoriesPosition.clear();
00639 d->categories.clear();
00640 d->intersectedIndexes.clear();
00641 d->modelIndexList.clear();
00642 d->hovered = QModelIndex();
00643 d->mouseButtonPressed = false;
00644 d->rightMouseButtonPressed = false;
00645
00646 if (!categoryDrawer && d->proxyModel)
00647 {
00648 QObject::disconnect(d->proxyModel,
00649 SIGNAL(layoutChanged()),
00650 this, SLOT(slotLayoutChanged()));
00651
00652 QObject::disconnect(d->proxyModel,
00653 SIGNAL(rowsRemoved(QModelIndex,int,int)),
00654 this, SLOT(rowsRemoved(QModelIndex,int,int)));
00655 }
00656 else if (categoryDrawer && d->proxyModel)
00657 {
00658 QObject::connect(d->proxyModel,
00659 SIGNAL(layoutChanged()),
00660 this, SLOT(slotLayoutChanged()));
00661
00662 QObject::connect(d->proxyModel,
00663 SIGNAL(rowsRemoved(QModelIndex,int,int)),
00664 this, SLOT(rowsRemoved(QModelIndex,int,int)));
00665 }
00666
00667 d->categoryDrawer = categoryDrawer;
00668
00669 if (categoryDrawer)
00670 {
00671 if (d->proxyModel)
00672 {
00673 if (d->proxyModel->rowCount())
00674 {
00675 d->layoutChanged(true);
00676 }
00677 }
00678 }
00679 else
00680 {
00681 updateGeometries();
00682 }
00683 }
00684
00685 QModelIndex KCategorizedView::indexAt(const QPoint &point) const
00686 {
00687 if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
00688 {
00689 return QListView::indexAt(point);
00690 }
00691
00692 QModelIndex index;
00693
00694 const QModelIndexList item = d->intersectionSet(QRect(point, point));
00695
00696 if (item.count() == 1)
00697 {
00698 index = item[0];
00699 }
00700
00701 return index;
00702 }
00703
00704 void KCategorizedView::reset()
00705 {
00706 QListView::reset();
00707
00708 d->lastSelection = QItemSelection();
00709 d->forcedSelectionPosition = 0;
00710 d->elementsInfo.clear();
00711 d->elementsPosition.clear();
00712 d->categoriesIndexes.clear();
00713 d->categoriesPosition.clear();
00714 d->categories.clear();
00715 d->intersectedIndexes.clear();
00716 d->modelIndexList.clear();
00717 d->hovered = QModelIndex();
00718 d->biggestItemSize = QSize(0, 0);
00719 d->mouseButtonPressed = false;
00720 d->rightMouseButtonPressed = false;
00721 }
00722
00723 void KCategorizedView::paintEvent(QPaintEvent *event)
00724 {
00725 if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
00726 {
00727 QListView::paintEvent(event);
00728 return;
00729 }
00730
00731 bool alternatingRows = alternatingRowColors();
00732
00733 QStyleOptionViewItemV4 option = viewOptions();
00734 option.widget = this;
00735 if (wordWrap())
00736 {
00737 option.features |= QStyleOptionViewItemV4::WrapText;
00738 }
00739
00740 QPainter painter(viewport());
00741 QRect area = event->rect();
00742 const bool focus = (hasFocus() || viewport()->hasFocus()) &&
00743 currentIndex().isValid();
00744 const QStyle::State state = option.state;
00745 const bool enabled = (state & QStyle::State_Enabled) != 0;
00746
00747 painter.save();
00748
00749 QModelIndexList dirtyIndexes = d->intersectionSet(area);
00750 bool alternate = false;
00751 if (dirtyIndexes.count())
00752 {
00753 alternate = dirtyIndexes[0].row() % 2;
00754 }
00755 foreach (const QModelIndex &index, dirtyIndexes)
00756 {
00757 if (alternatingRows && alternate)
00758 {
00759 option.features |= QStyleOptionViewItemV4::Alternate;
00760 alternate = false;
00761 }
00762 else if (alternatingRows)
00763 {
00764 option.features &= ~QStyleOptionViewItemV4::Alternate;
00765 alternate = true;
00766 }
00767 option.state = state;
00768 option.rect = visualRect(index);
00769
00770 if (selectionModel() && selectionModel()->isSelected(index))
00771 {
00772 option.state |= QStyle::State_Selected;
00773 }
00774
00775 if (enabled)
00776 {
00777 QPalette::ColorGroup cg;
00778 if ((d->proxyModel->flags(index) & Qt::ItemIsEnabled) == 0)
00779 {
00780 option.state &= ~QStyle::State_Enabled;
00781 cg = QPalette::Disabled;
00782 }
00783 else
00784 {
00785 cg = QPalette::Normal;
00786 }
00787 option.palette.setCurrentColorGroup(cg);
00788 }
00789
00790 if (focus && currentIndex() == index)
00791 {
00792 option.state |= QStyle::State_HasFocus;
00793 if (this->state() == EditingState)
00794 option.state |= QStyle::State_Editing;
00795 }
00796
00797 if (index == d->hovered)
00798 option.state |= QStyle::State_MouseOver;
00799 else
00800 option.state &= ~QStyle::State_MouseOver;
00801
00802 itemDelegate(index)->paint(&painter, option, index);
00803 }
00804
00805
00806 QStyleOptionViewItemV4 otherOption;
00807 bool intersectedInThePast = false;
00808 foreach (const QString &category, d->categories)
00809 {
00810 otherOption = option;
00811 otherOption.rect = d->categoryVisualRect(category);
00812 otherOption.state &= ~QStyle::State_MouseOver;
00813
00814 if (otherOption.rect.intersects(area))
00815 {
00816 intersectedInThePast = true;
00817
00818 QModelIndex indexToDraw = d->proxyModel->index(d->categoriesIndexes[category][0].row(), d->proxyModel->sortColumn());
00819
00820 d->drawNewCategory(indexToDraw,
00821 d->proxyModel->sortRole(), otherOption, &painter);
00822 }
00823 else if (intersectedInThePast)
00824 {
00825 break;
00826
00827 }
00828 }
00829
00830 if ((selectionMode() != SingleSelection) && (selectionMode() != NoSelection))
00831 {
00832 if (d->mouseButtonPressed && !d->isDragging)
00833 {
00834 QPoint start, end, initialPressPosition;
00835
00836 initialPressPosition = d->initialPressPosition;
00837
00838 initialPressPosition.setY(initialPressPosition.y() - verticalOffset());
00839 initialPressPosition.setX(initialPressPosition.x() - horizontalOffset());
00840
00841 if (d->initialPressPosition.x() > d->mousePosition.x() ||
00842 d->initialPressPosition.y() > d->mousePosition.y())
00843 {
00844 start = d->mousePosition;
00845 end = initialPressPosition;
00846 }
00847 else
00848 {
00849 start = initialPressPosition;
00850 end = d->mousePosition;
00851 }
00852
00853 QStyleOptionRubberBand yetAnotherOption;
00854 yetAnotherOption.initFrom(this);
00855 yetAnotherOption.shape = QRubberBand::Rectangle;
00856 yetAnotherOption.opaque = false;
00857 yetAnotherOption.rect = QRect(start, end).intersected(viewport()->rect().adjusted(-16, -16, 16, 16));
00858 painter.save();
00859 style()->drawControl(QStyle::CE_RubberBand, &yetAnotherOption, &painter);
00860 painter.restore();
00861 }
00862 }
00863
00864 if (d->isDragging && !d->dragLeftViewport)
00865 {
00866 painter.setOpacity(0.5);
00867 d->drawDraggedItems(&painter);
00868 }
00869
00870 painter.restore();
00871 }
00872
00873 void KCategorizedView::resizeEvent(QResizeEvent *event)
00874 {
00875 QListView::resizeEvent(event);
00876
00877
00878 d->elementsPosition.clear();
00879 d->categoriesPosition.clear();
00880 d->forcedSelectionPosition = 0;
00881
00882 if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
00883 {
00884 return;
00885 }
00886
00887 d->updateScrollbars();
00888 }
00889
00890 void KCategorizedView::setSelection(const QRect &rect,
00891 QItemSelectionModel::SelectionFlags flags)
00892 {
00893 if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
00894 {
00895 QListView::setSelection(rect, flags);
00896 return;
00897 }
00898
00899 if (!flags)
00900 return;
00901
00902 if (flags & QItemSelectionModel::Clear)
00903 {
00904 selectionModel()->clear();
00905 d->lastSelection.clear();
00906 }
00907
00908 QModelIndexList dirtyIndexes = d->intersectionSet(rect);
00909
00910
00911 if (!dirtyIndexes.count())
00912 {
00913 selectionModel()->select(d->lastSelection, QItemSelectionModel::SelectCurrent);
00914
00915 return;
00916 }
00917
00918 QModelIndex topLeft;
00919 QModelIndex bottomRight;
00920
00921 if (d->mouseButtonPressed || d->rightMouseButtonPressed)
00922 {
00923 QItemSelection selection;
00924
00925 QModelIndex prev = dirtyIndexes[0];
00926 QModelIndex first = prev;
00927 foreach (const QModelIndex &index, dirtyIndexes)
00928 {
00929
00930 if ((index.row() - prev.row()) > 1) {
00931 selection << QItemSelectionRange(first, prev);
00932
00933 first = index;
00934 }
00935
00936 prev = index;
00937 }
00938
00939 selection << QItemSelectionRange(first, prev);
00940
00941 if (flags & QItemSelectionModel::Current)
00942 {
00943 if (rect.topLeft() == rect.bottomRight())
00944 {
00945 selectionModel()->setCurrentIndex(indexAt(rect.topLeft()), QItemSelectionModel::NoUpdate);
00946 }
00947
00948 selection.merge(d->lastSelection, flags);
00949 }
00950 else
00951 {
00952 selection.merge(selectionModel()->selection(), flags);
00953
00954 selectionModel()->select(selection, QItemSelectionModel::SelectCurrent);
00955
00956 return;
00957 }
00958
00959 selectionModel()->select(selection, flags);
00960 }
00961 else
00962 {
00963 QModelIndex topLeftIndex = indexAt(QPoint(rect.topLeft().x(),
00964 rect.topLeft().y()));
00965 QModelIndex bottomRightIndex = indexAt(QPoint(rect.bottomRight().x(),
00966 rect.bottomRight().y()));
00967
00968
00969 if (topLeftIndex.row() > bottomRightIndex.row())
00970 {
00971 QModelIndex auxIndex = topLeftIndex;
00972 topLeftIndex = bottomRightIndex;
00973 bottomRightIndex = auxIndex;
00974 }
00975
00976 int viewportWidth = viewport()->width() - spacing();
00977 int itemWidth;
00978
00979 if (gridSize().isEmpty())
00980 {
00981 itemWidth = d->biggestItemSize.width();
00982 }
00983 else
00984 {
00985 itemWidth = gridSize().width();
00986 }
00987
00988 int itemWidthPlusSeparation = spacing() + itemWidth;
00989 if (!itemWidthPlusSeparation)
00990 itemWidthPlusSeparation++;
00991 int elementsPerRow = viewportWidth / itemWidthPlusSeparation;
00992 if (!elementsPerRow)
00993 elementsPerRow++;
00994
00995 QModelIndexList theoricDirty(dirtyIndexes);
00996 dirtyIndexes.clear();
00997 int first = model()->rowCount();
00998 int last = 0;
00999
01000 foreach (const QModelIndex &index, theoricDirty)
01001 {
01002 if ((index.row() < first) &&
01003 ((((topLeftIndex.row() / elementsPerRow) == (index.row() / elementsPerRow)) &&
01004 ((topLeftIndex.row() % elementsPerRow) <= (index.row() % elementsPerRow))) ||
01005 (topLeftIndex.row() / elementsPerRow) != (index.row() / elementsPerRow)))
01006 {
01007 first = index.row();
01008 topLeft = index;
01009 }
01010
01011 if ((index.row() > last) &&
01012 ((((bottomRightIndex.row() / elementsPerRow) == (index.row() / elementsPerRow)) &&
01013 ((bottomRightIndex.row() % elementsPerRow) >= (index.row() % elementsPerRow))) ||
01014 (bottomRightIndex.row() / elementsPerRow) != (index.row() / elementsPerRow)))
01015 {
01016 last = index.row();
01017 bottomRight = index;
01018 }
01019 }
01020
01021 for (int i = first; i <= last; i++)
01022 {
01023 dirtyIndexes << model()->index(i, theoricDirty[0].column(), theoricDirty[0].parent());
01024 }
01025
01026 QItemSelection selection(topLeft, bottomRight);
01027
01028 selectionModel()->select(selection, flags);
01029 }
01030 }
01031
01032 void KCategorizedView::mouseMoveEvent(QMouseEvent *event)
01033 {
01034 QListView::mouseMoveEvent(event);
01035
01036 if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
01037 {
01038 return;
01039 }
01040
01041 const QModelIndexList item = d->intersectionSet(QRect(event->pos(), event->pos()));
01042
01043 if (item.count() == 1)
01044 {
01045 d->hovered = item[0];
01046 }
01047 else
01048 {
01049 d->hovered = QModelIndex();
01050 }
01051
01052 const QString previousHoveredCategory = d->hoveredCategory;
01053
01054 d->mousePosition = event->pos();
01055 d->hoveredCategory.clear();
01056
01057
01058 foreach (const QString &category, d->categories)
01059 {
01060 if (d->categoryVisualRect(category).intersects(QRect(event->pos(), event->pos())))
01061 {
01062 d->hoveredCategory = category;
01063 viewport()->update(d->categoryVisualRect(category));
01064 }
01065 else if ((category == previousHoveredCategory) &&
01066 (!d->categoryVisualRect(previousHoveredCategory).intersects(QRect(event->pos(), event->pos()))))
01067 {
01068 viewport()->update(d->categoryVisualRect(category));
01069 }
01070 }
01071
01072 QRect rect;
01073 if (d->mouseButtonPressed && !d->isDragging)
01074 {
01075 QPoint start, end, initialPressPosition;
01076
01077 initialPressPosition = d->initialPressPosition;
01078
01079 initialPressPosition.setY(initialPressPosition.y() - verticalOffset());
01080 initialPressPosition.setX(initialPressPosition.x() - horizontalOffset());
01081
01082 if (d->initialPressPosition.x() > d->mousePosition.x() ||
01083 d->initialPressPosition.y() > d->mousePosition.y())
01084 {
01085 start = d->mousePosition;
01086 end = initialPressPosition;
01087 }
01088 else
01089 {
01090 start = initialPressPosition;
01091 end = d->mousePosition;
01092 }
01093
01094 rect = QRect(start, end).adjusted(-16, -16, 16, 16);
01095 rect = rect.united(QRect(start, end).adjusted(16, 16, -16, -16)).intersected(viewport()->rect());
01096
01097 viewport()->update(rect);
01098 }
01099 }
01100
01101 void KCategorizedView::mousePressEvent(QMouseEvent *event)
01102 {
01103 d->dragLeftViewport = false;
01104
01105 if (event->button() == Qt::LeftButton)
01106 {
01107 d->mouseButtonPressed = true;
01108
01109 d->initialPressPosition = event->pos();
01110 d->initialPressPosition.setY(d->initialPressPosition.y() +
01111 verticalOffset());
01112 d->initialPressPosition.setX(d->initialPressPosition.x() +
01113 horizontalOffset());
01114 }
01115 else if (event->button() == Qt::RightButton)
01116 {
01117 d->rightMouseButtonPressed = true;
01118 }
01119
01120 QListView::mousePressEvent(event);
01121
01122 if (selectionModel())
01123 {
01124 d->lastSelection = selectionModel()->selection();
01125 }
01126
01127 viewport()->update(d->categoryVisualRect(d->hoveredCategory));
01128 }
01129
01130 void KCategorizedView::mouseReleaseEvent(QMouseEvent *event)
01131 {
01132 d->mouseButtonPressed = false;
01133 d->rightMouseButtonPressed = false;
01134
01135 QListView::mouseReleaseEvent(event);
01136
01137 if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
01138 {
01139 return;
01140 }
01141
01142 QPoint initialPressPosition = viewport()->mapFromGlobal(QCursor::pos());
01143 initialPressPosition.setY(initialPressPosition.y() + verticalOffset());
01144 initialPressPosition.setX(initialPressPosition.x() + horizontalOffset());
01145
01146 if ((selectionMode() != SingleSelection) && (selectionMode() != NoSelection) &&
01147 (initialPressPosition == d->initialPressPosition))
01148 {
01149 foreach(const QString &category, d->categories)
01150 {
01151 if (d->categoryVisualRect(category).contains(event->pos()) &&
01152 selectionModel())
01153 {
01154 QItemSelection selection = selectionModel()->selection();
01155 QModelIndexList indexList = d->categoriesIndexes[category];
01156
01157 foreach (const QModelIndex &index, indexList)
01158 {
01159 QModelIndex selectIndex = index.model()->index(index.row(), 0);
01160
01161 selection << QItemSelectionRange(selectIndex);
01162 }
01163
01164 selectionModel()->select(selection, QItemSelectionModel::SelectCurrent);
01165
01166 break;
01167 }
01168 }
01169 }
01170
01171 QRect rect;
01172 if (!d->isDragging)
01173 {
01174 QPoint start, end, initialPressPosition;
01175
01176 initialPressPosition = d->initialPressPosition;
01177
01178 initialPressPosition.setY(initialPressPosition.y() - verticalOffset());
01179 initialPressPosition.setX(initialPressPosition.x() - horizontalOffset());
01180
01181 if (d->initialPressPosition.x() > d->mousePosition.x() ||
01182 d->initialPressPosition.y() > d->mousePosition.y())
01183 {
01184 start = d->mousePosition;
01185 end = initialPressPosition;
01186 }
01187 else
01188 {
01189 start = initialPressPosition;
01190 end = d->mousePosition;
01191 }
01192
01193 rect = QRect(start, end).adjusted(-16, -16, 16, 16);
01194 rect = rect.united(QRect(start, end).adjusted(16, 16, -16, -16)).intersected(viewport()->rect());
01195
01196 viewport()->update(rect);
01197 }
01198
01199 if (d->hovered.isValid())
01200 viewport()->update(visualRect(d->hovered));
01201 else if (!d->hoveredCategory.isEmpty())
01202 viewport()->update(d->categoryVisualRect(d->hoveredCategory));
01203 }
01204
01205 void KCategorizedView::leaveEvent(QEvent *event)
01206 {
01207 d->hovered = QModelIndex();
01208 d->hoveredCategory.clear();
01209
01210 QListView::leaveEvent(event);
01211 }
01212
01213 void KCategorizedView::startDrag(Qt::DropActions supportedActions)
01214 {
01215
01216
01217
01218
01219
01220 #if defined(DOLPHIN_DRAGANDDROP)
01221 Q_UNUSED(supportedActions);
01222 #else
01223 QListView::startDrag(supportedActions);
01224 #endif
01225
01226 d->isDragging = false;
01227 d->mouseButtonPressed = false;
01228 d->rightMouseButtonPressed = false;
01229
01230 viewport()->update(d->lastDraggedItemsRect);
01231 }
01232
01233 void KCategorizedView::dragMoveEvent(QDragMoveEvent *event)
01234 {
01235 d->mousePosition = event->pos();
01236
01237 if (d->mouseButtonPressed)
01238 {
01239 d->isDragging = true;
01240 }
01241 else
01242 {
01243 d->isDragging = false;
01244 }
01245
01246 d->dragLeftViewport = false;
01247
01248 #if defined(DOLPHIN_DRAGANDDROP)
01249 QAbstractItemView::dragMoveEvent(event);
01250 #else
01251 QListView::dragMoveEvent(event);
01252 #endif
01253
01254 if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
01255 {
01256 return;
01257 }
01258
01259 d->hovered = indexAt(event->pos());
01260
01261 #if !defined(DOLPHIN_DRAGANDDROP)
01262 d->drawDraggedItems();
01263 #endif
01264 }
01265
01266 void KCategorizedView::dragLeaveEvent(QDragLeaveEvent *event)
01267 {
01268 d->dragLeftViewport = true;
01269
01270 #if defined(DOLPHIN_DRAGANDDROP)
01271 QAbstractItemView::dragLeaveEvent(event);
01272 #else
01273 QListView::dragLeaveEvent(event);
01274 #endif
01275 }
01276
01277 void KCategorizedView::dropEvent(QDropEvent *event)
01278 {
01279 #if defined(DOLPHIN_DRAGANDDROP)
01280 QAbstractItemView::dropEvent(event);
01281 #else
01282 QListView::dropEvent(event);
01283 #endif
01284 }
01285
01286 QModelIndex KCategorizedView::moveCursor(CursorAction cursorAction,
01287 Qt::KeyboardModifiers modifiers)
01288 {
01289 if ((viewMode() != KCategorizedView::IconMode) ||
01290 !d->proxyModel ||
01291 !d->categoryDrawer ||
01292 d->categories.isEmpty() ||
01293 !d->proxyModel->isCategorizedModel())
01294 {
01295 return QListView::moveCursor(cursorAction, modifiers);
01296 }
01297
01298 int viewportWidth = viewport()->width() - spacing();
01299 int itemWidth;
01300
01301 if (gridSize().isEmpty())
01302 {
01303 itemWidth = d->biggestItemSize.width();
01304 }
01305 else
01306 {
01307 itemWidth = gridSize().width();
01308 }
01309
01310 int itemWidthPlusSeparation = spacing() + itemWidth;
01311 if (!itemWidthPlusSeparation)
01312 itemWidthPlusSeparation++;
01313 int elementsPerRow = viewportWidth / itemWidthPlusSeparation;
01314 if (!elementsPerRow)
01315 elementsPerRow++;
01316
01317 QModelIndex current = selectionModel() ? selectionModel()->currentIndex()
01318 : QModelIndex();
01319
01320 if (!current.isValid())
01321 {
01322 if (cursorAction == MoveEnd)
01323 {
01324 current = model()->index(model()->rowCount() - 1, 0, QModelIndex());
01325 d->forcedSelectionPosition = d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow;
01326 }
01327 else
01328 {
01329 current = model()->index(0, 0, QModelIndex());
01330 d->forcedSelectionPosition = 0;
01331 }
01332
01333 return current;
01334 }
01335
01336 QString lastCategory = d->categories.first();
01337 QString theCategory = d->categories.first();
01338 QString afterCategory = d->categories.first();
01339
01340 bool hasToBreak = false;
01341 foreach (const QString &category, d->categories)
01342 {
01343 if (hasToBreak)
01344 {
01345 afterCategory = category;
01346
01347 break;
01348 }
01349
01350 if (category == d->elementsInfo[current.row()].category)
01351 {
01352 theCategory = category;
01353
01354 hasToBreak = true;
01355 }
01356
01357 if (!hasToBreak)
01358 {
01359 lastCategory = category;
01360 }
01361 }
01362
01363 switch (cursorAction)
01364 {
01365 case QAbstractItemView::MoveUp: {
01366 if (d->elementsInfo[current.row()].relativeOffsetToCategory >= elementsPerRow)
01367 {
01368 int indexToMove = current.row();
01369 indexToMove -= qMin(((d->elementsInfo[current.row()].relativeOffsetToCategory) + d->forcedSelectionPosition), elementsPerRow - d->forcedSelectionPosition + (d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow));
01370
01371 return d->proxyModel->index(indexToMove, 0);
01372 }
01373 else
01374 {
01375 int lastCategoryLastRow = (d->categoriesIndexes[lastCategory].count() - 1) % elementsPerRow;
01376 int indexToMove = current.row() - d->elementsInfo[current.row()].relativeOffsetToCategory;
01377
01378 if (d->forcedSelectionPosition >= lastCategoryLastRow)
01379 {
01380 indexToMove -= 1;
01381 }
01382 else
01383 {
01384 indexToMove -= qMin((lastCategoryLastRow - d->forcedSelectionPosition + 1), d->forcedSelectionPosition + elementsPerRow + 1);
01385 }
01386
01387 return d->proxyModel->index(indexToMove, 0);
01388 }
01389 }
01390
01391 case QAbstractItemView::MoveDown: {
01392 if (d->elementsInfo[current.row()].relativeOffsetToCategory < (d->categoriesIndexes[theCategory].count() - 1 - ((d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow)))
01393 {
01394 int indexToMove = current.row();
01395 indexToMove += qMin(elementsPerRow, d->categoriesIndexes[theCategory].count() - 1 - d->elementsInfo[current.row()].relativeOffsetToCategory);
01396
01397 return d->proxyModel->index(indexToMove, 0);
01398 }
01399 else
01400 {
01401 int afterCategoryLastRow = qMin(elementsPerRow, d->categoriesIndexes[afterCategory].count());
01402 int indexToMove = current.row() + (d->categoriesIndexes[theCategory].count() - d->elementsInfo[current.row()].relativeOffsetToCategory);
01403
01404 if (d->forcedSelectionPosition >= afterCategoryLastRow)
01405 {
01406 indexToMove += afterCategoryLastRow - 1;
01407 }
01408 else
01409 {
01410 indexToMove += qMin(d->forcedSelectionPosition, elementsPerRow);
01411 }
01412
01413 return d->proxyModel->index(indexToMove, 0);
01414 }
01415 }
01416
01417 case QAbstractItemView::MoveLeft:
01418 if (layoutDirection() == Qt::RightToLeft)
01419 {
01420 if (!(d->elementsInfo[current.row() + 1].relativeOffsetToCategory % elementsPerRow))
01421 return current;
01422
01423 d->forcedSelectionPosition = d->elementsInfo[current.row() + 1].relativeOffsetToCategory % elementsPerRow;
01424
01425 #if 0 //follow qt view behavior. lateral movements won't change visual row
01426 if (d->forcedSelectionPosition < 0)
01427 d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow;
01428 #endif
01429
01430 return d->proxyModel->index(current.row() + 1, 0);
01431 }
01432
01433 if (!(d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow))
01434 return current;
01435
01436 d->forcedSelectionPosition = d->elementsInfo[current.row() - 1].relativeOffsetToCategory % elementsPerRow;
01437
01438 #if 0 //follow qt view behavior. lateral movements won't change visual row
01439 if (d->forcedSelectionPosition < 0)
01440 d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow;
01441 #endif
01442
01443 return d->proxyModel->index(current.row() - 1, 0);
01444
01445 case QAbstractItemView::MoveRight:
01446 if (layoutDirection() == Qt::RightToLeft)
01447 {
01448 if (!(d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow))
01449 return current;
01450
01451 d->forcedSelectionPosition = d->elementsInfo[current.row() - 1].relativeOffsetToCategory % elementsPerRow;
01452
01453 #if 0 //follow qt view behavior. lateral movements won't change visual row
01454 if (d->forcedSelectionPosition < 0)
01455 d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow;
01456 #endif
01457
01458 return d->proxyModel->index(current.row() - 1, 0);
01459 }
01460
01461 if (!(d->elementsInfo[current.row() + 1].relativeOffsetToCategory % elementsPerRow))
01462 return current;
01463
01464 d->forcedSelectionPosition = d->elementsInfo[current.row() + 1].relativeOffsetToCategory % elementsPerRow;
01465
01466 #if 0 //follow qt view behavior. lateral movements won't change visual row
01467 if (d->forcedSelectionPosition < 0)
01468 d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow;
01469 #endif
01470
01471 return d->proxyModel->index(current.row() + 1, 0);
01472
01473 default:
01474 break;
01475 }
01476
01477 return QListView::moveCursor(cursorAction, modifiers);
01478 }
01479
01480 void KCategorizedView::rowsInserted(const QModelIndex &parent,
01481 int start,
01482 int end)
01483 {
01484 QListView::rowsInserted(parent, start, end);
01485
01486 if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
01487 {
01488 d->forcedSelectionPosition = 0;
01489 d->elementsInfo.clear();
01490 d->elementsPosition.clear();
01491 d->categoriesIndexes.clear();
01492 d->categoriesPosition.clear();
01493 d->categories.clear();
01494 d->intersectedIndexes.clear();
01495 d->modelIndexList.clear();
01496 d->hovered = QModelIndex();
01497 d->biggestItemSize = QSize(0, 0);
01498 d->mouseButtonPressed = false;
01499 d->rightMouseButtonPressed = false;
01500
01501 return;
01502 }
01503
01504 rowsInsertedArtifficial(parent, start, end);
01505 }
01506
01507 void KCategorizedView::rowsInsertedArtifficial(const QModelIndex &parent,
01508 int start,
01509 int end)
01510 {
01511 Q_UNUSED(parent);
01512
01513 d->forcedSelectionPosition = 0;
01514 d->elementsInfo.clear();
01515 d->elementsPosition.clear();
01516 d->categoriesIndexes.clear();
01517 d->categoriesPosition.clear();
01518 d->categories.clear();
01519 d->intersectedIndexes.clear();
01520 d->modelIndexList.clear();
01521 d->hovered = QModelIndex();
01522 d->biggestItemSize = QSize(0, 0);
01523 d->mouseButtonPressed = false;
01524 d->rightMouseButtonPressed = false;
01525
01526 if (start > end || end < 0 || start < 0 || !d->proxyModel->rowCount())
01527 {
01528 return;
01529 }
01530
01531
01532 QString prevCategory = d->proxyModel->data(d->proxyModel->index(0, d->proxyModel->sortColumn()), KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
01533 QString lastCategory = prevCategory;
01534 QModelIndexList modelIndexList;
01535 struct Private::ElementInfo elementInfo;
01536 int offset = -1;
01537 for (int k = 0; k < d->proxyModel->rowCount(); ++k)
01538 {
01539 QModelIndex index = d->proxyModel->index(k, d->proxyModel->sortColumn());
01540 QModelIndex indexSize = d->proxyModel->index(k, 0);
01541
01542 d->biggestItemSize = QSize(qMax(sizeHintForIndex(indexSize).width(),
01543 d->biggestItemSize.width()),
01544 qMax(sizeHintForIndex(indexSize).height(),
01545 d->biggestItemSize.height()));
01546
01547 d->modelIndexList << index;
01548
01549 lastCategory = d->proxyModel->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
01550
01551 elementInfo.category = lastCategory;
01552
01553 if (prevCategory != lastCategory)
01554 {
01555 offset = 0;
01556 d->categoriesIndexes.insert(prevCategory, modelIndexList);
01557 d->categories << prevCategory;
01558 modelIndexList.clear();
01559 }
01560 else
01561 {
01562 offset++;
01563 }
01564
01565 elementInfo.relativeOffsetToCategory = offset;
01566
01567 modelIndexList << index;
01568 prevCategory = lastCategory;
01569
01570 d->elementsInfo.insert(index.row(), elementInfo);
01571 }
01572
01573 d->categoriesIndexes.insert(prevCategory, modelIndexList);
01574 d->categories << prevCategory;
01575
01576 d->updateScrollbars();
01577
01578
01579
01580 selectionModel()->clear();
01581 }
01582
01583 void KCategorizedView::rowsRemoved(const QModelIndex &parent,
01584 int start,
01585 int end)
01586 {
01587 Q_UNUSED(parent);
01588 Q_UNUSED(start);
01589 Q_UNUSED(end);
01590 if (d->proxyModel && d->categoryDrawer && d->proxyModel->isCategorizedModel())
01591 {
01592
01593 rowsInsertedArtifficial(QModelIndex(), 0, d->proxyModel->rowCount() - 1);
01594 }
01595 }
01596
01597 void KCategorizedView::updateGeometries()
01598 {
01599 if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
01600 {
01601 QListView::updateGeometries();
01602 return;
01603 }
01604
01605
01606
01607 QAbstractItemView::updateGeometries();
01608 }
01609
01610 void KCategorizedView::slotLayoutChanged()
01611 {
01612 d->layoutChanged();
01613 }
01614
01615 void KCategorizedView::currentChanged(const QModelIndex ¤t,
01616 const QModelIndex &previous)
01617 {
01618
01619
01620
01621 int viewportWidth = viewport()->width() - spacing();
01622
01623 int itemHeight;
01624 int itemWidth;
01625
01626 if (gridSize().isEmpty())
01627 {
01628 itemHeight = d->biggestItemSize.height();
01629 itemWidth = d->biggestItemSize.width();
01630 }
01631 else
01632 {
01633 itemHeight = gridSize().height();
01634 itemWidth = gridSize().width();
01635 }
01636
01637 int itemWidthPlusSeparation = spacing() + itemWidth;
01638 if (!itemWidthPlusSeparation)
01639 itemWidthPlusSeparation++;
01640 int elementsPerRow = viewportWidth / itemWidthPlusSeparation;
01641 if (!elementsPerRow)
01642 elementsPerRow++;
01643
01644 if (d->mouseButtonPressed || d->rightMouseButtonPressed)
01645 d->forcedSelectionPosition = d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow;
01646
01647 QListView::currentChanged(current, previous);
01648 }
01649
01650 void KCategorizedView::dataChanged(const QModelIndex &topLeft,
01651 const QModelIndex &bottomRight)
01652 {
01653 if (topLeft == bottomRight)
01654 {
01655 d->cacheIndex(topLeft);
01656 }
01657 else
01658 {
01659 const int columnStart = topLeft.column();
01660 const int columnEnd = bottomRight.column();
01661 const int rowStart = topLeft.row();
01662 const int rowEnd = bottomRight.row();
01663
01664 for (int row = rowStart; row <= rowEnd; ++row)
01665 {
01666 for (int column = columnStart; column <= columnEnd; ++column)
01667 {
01668 d->cacheIndex(d->proxyModel->index(row, column));
01669 }
01670 }
01671 }
01672
01673 QListView::dataChanged(topLeft, bottomRight);
01674 slotLayoutChanged();
01675 }
01676
01677 #include "kcategorizedview.moc"