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 "kcategorydrawer.h"
00032 #include "kcategorizedsortfilterproxymodel.h"
00033
00034
00035
00036
00037
00038 #define DOLPHIN_DRAGANDDROP
00039
00040 KCategorizedView::Private::Private(KCategorizedView *listView)
00041 : listView(listView)
00042 , categoryDrawer(0)
00043 , biggestItemSize(QSize(0, 0))
00044 , mouseButtonPressed(false)
00045 , rightMouseButtonPressed(false)
00046 , isDragging(false)
00047 , dragLeftViewport(false)
00048 , proxyModel(0)
00049 {
00050 }
00051
00052 KCategorizedView::Private::~Private()
00053 {
00054 }
00055
00056 const QModelIndexList &KCategorizedView::Private::intersectionSet(const QRect &rect)
00057 {
00058 QModelIndex index;
00059 QRect indexVisualRect;
00060
00061 intersectedIndexes.clear();
00062
00063 int itemHeight;
00064
00065 if (listView->gridSize().isEmpty())
00066 {
00067 itemHeight = biggestItemSize.height();
00068 }
00069 else
00070 {
00071 itemHeight = listView->gridSize().height();
00072 }
00073
00074
00075 int top = proxyModel->rowCount() - 1;
00076 int bottom = 0;
00077 int middle = (top + bottom) / 2;
00078 while (bottom <= top)
00079 {
00080 middle = (top + bottom) / 2;
00081
00082 index = proxyModel->index(middle, 0);
00083 indexVisualRect = visualRect(index);
00084
00085
00086 indexVisualRect.setHeight(indexVisualRect.height() + (itemHeight - indexVisualRect.height()));
00087
00088 if (qMax(indexVisualRect.topLeft().y(),
00089 indexVisualRect.bottomRight().y()) < qMin(rect.topLeft().y(),
00090 rect.bottomRight().y()))
00091 {
00092 bottom = middle + 1;
00093 }
00094 else
00095 {
00096 top = middle - 1;
00097 }
00098 }
00099
00100 for (int i = middle; i < proxyModel->rowCount(); i++)
00101 {
00102 index = proxyModel->index(i, 0);
00103 indexVisualRect = visualRect(index);
00104
00105 if (rect.intersects(indexVisualRect))
00106 intersectedIndexes.append(index);
00107
00108
00109 if (qMax(rect.bottomRight().y(), rect.topLeft().y()) <
00110 qMin(indexVisualRect.topLeft().y(),
00111 indexVisualRect.bottomRight().y()))
00112 break;
00113 }
00114
00115 return intersectedIndexes;
00116 }
00117
00118 QRect KCategorizedView::Private::visualRectInViewport(const QModelIndex &index) const
00119 {
00120 if (!index.isValid())
00121 return QRect();
00122
00123 QString curCategory = elementsInfo[index.row()].category;
00124
00125 QRect retRect;
00126
00127 if (listView->flow() == QListView::LeftToRight)
00128 {
00129 if (listView->layoutDirection() == Qt::LeftToRight)
00130 {
00131 retRect = QRect(listView->spacing(), listView->spacing() * 2 +
00132 categoryDrawer->categoryHeight(index, listView->viewOptions()), 0, 0);
00133 }
00134 else
00135 {
00136 retRect = QRect(listView->viewport()->width() - listView->spacing(), listView->spacing() * 2 +
00137 categoryDrawer->categoryHeight(index, listView->viewOptions()), 0, 0);
00138 }
00139 }
00140 else
00141 {
00142 retRect = QRect(listView->spacing(), listView->spacing() * 2 +
00143 categoryDrawer->categoryHeight(index, listView->viewOptions()), 0, 0);
00144 }
00145
00146 int viewportWidth = listView->viewport()->width() - listView->spacing();
00147
00148 int itemHeight;
00149 int itemWidth;
00150
00151 if (listView->gridSize().isEmpty() && (listView->flow() == QListView::LeftToRight))
00152 {
00153 itemHeight = biggestItemSize.height();
00154 itemWidth = biggestItemSize.width();
00155 }
00156 else if (listView->flow() == QListView::LeftToRight)
00157 {
00158 itemHeight = listView->gridSize().height();
00159 itemWidth = listView->gridSize().width();
00160 }
00161 else if (listView->gridSize().isEmpty() && (listView->flow() == QListView::TopToBottom))
00162 {
00163 itemHeight = biggestItemSize.height();
00164 itemWidth = listView->viewport()->width() - listView->spacing() * 2;
00165 }
00166 else
00167 {
00168 itemHeight = listView->gridSize().height();
00169 itemWidth = listView->gridSize().width() - listView->spacing() * 2;
00170 }
00171
00172 int itemWidthPlusSeparation = listView->spacing() + itemWidth;
00173 if (!itemWidthPlusSeparation)
00174 itemWidthPlusSeparation++;
00175 int elementsPerRow = viewportWidth / itemWidthPlusSeparation;
00176 if (!elementsPerRow)
00177 elementsPerRow++;
00178
00179 int column;
00180 int row;
00181
00182 if (listView->flow() == QListView::LeftToRight)
00183 {
00184 column = elementsInfo[index.row()].relativeOffsetToCategory % elementsPerRow;
00185 row = elementsInfo[index.row()].relativeOffsetToCategory / elementsPerRow;
00186
00187 if (listView->layoutDirection() == Qt::LeftToRight)
00188 {
00189 retRect.setLeft(retRect.left() + column * listView->spacing() +
00190 column * itemWidth);
00191 }
00192 else
00193 {
00194 retRect.setLeft(retRect.right() - column * listView->spacing() -
00195 column * itemWidth - itemWidth);
00196
00197 retRect.setRight(retRect.right() - column * listView->spacing() -
00198 column * itemWidth);
00199 }
00200 }
00201 else
00202 {
00203 elementsPerRow = 1;
00204 column = elementsInfo[index.row()].relativeOffsetToCategory % elementsPerRow;
00205 row = elementsInfo[index.row()].relativeOffsetToCategory / elementsPerRow;
00206 }
00207
00208 foreach (const QString &category, categories)
00209 {
00210 if (category == curCategory)
00211 break;
00212
00213 float rows = (float) ((float) categoriesIndexes[category].count() /
00214 (float) elementsPerRow);
00215
00216 int rowsInt = categoriesIndexes[category].count() / elementsPerRow;
00217
00218 if (rows - trunc(rows)) rowsInt++;
00219
00220 retRect.setTop(retRect.top() +
00221 (rowsInt * itemHeight) +
00222 categoryDrawer->categoryHeight(index, listView->viewOptions()) +
00223 listView->spacing() * 2);
00224
00225 if (listView->gridSize().isEmpty())
00226 {
00227 retRect.setTop(retRect.top() +
00228 (rowsInt * listView->spacing()));
00229 }
00230 }
00231
00232 if (listView->gridSize().isEmpty())
00233 {
00234 retRect.setTop(retRect.top() + row * listView->spacing() +
00235 (row * itemHeight));
00236 }
00237 else
00238 {
00239 retRect.setTop(retRect.top() + (row * itemHeight));
00240 }
00241
00242 retRect.setWidth(itemWidth);
00243
00244 QModelIndex heightIndex = proxyModel->index(index.row(), 0);
00245 if (listView->gridSize().isEmpty())
00246 {
00247 retRect.setHeight(listView->sizeHintForIndex(heightIndex).height());
00248 }
00249 else
00250 {
00251 const QSize sizeHint = listView->sizeHintForIndex(heightIndex);
00252 if (sizeHint.width() < itemWidth) {
00253 retRect.setWidth(sizeHint.width());
00254 retRect.moveLeft(retRect.left() + (itemWidth - sizeHint.width()) / 2);
00255 }
00256 retRect.setHeight(qMin(sizeHint.height(), listView->gridSize().height()));
00257 }
00258
00259 return retRect;
00260 }
00261
00262 QRect KCategorizedView::Private::visualCategoryRectInViewport(const QString &category) const
00263 {
00264 QRect retRect(listView->spacing(),
00265 listView->spacing(),
00266 listView->viewport()->width() - listView->spacing() * 2,
00267 0);
00268
00269 if (!proxyModel || !categoryDrawer || !proxyModel->isCategorizedModel() || !proxyModel->rowCount() || !categories.contains(category))
00270 return QRect();
00271
00272 QModelIndex index = proxyModel->index(0, 0, QModelIndex());
00273
00274 int viewportWidth = listView->viewport()->width() - listView->spacing();
00275
00276 int itemHeight;
00277 int itemWidth;
00278
00279 if (listView->gridSize().isEmpty())
00280 {
00281 itemHeight = biggestItemSize.height();
00282 itemWidth = biggestItemSize.width();
00283 }
00284 else
00285 {
00286 itemHeight = listView->gridSize().height();
00287 itemWidth = listView->gridSize().width();
00288 }
00289
00290 int itemWidthPlusSeparation = listView->spacing() + itemWidth;
00291 int elementsPerRow = viewportWidth / itemWidthPlusSeparation;
00292
00293 if (!elementsPerRow)
00294 elementsPerRow++;
00295
00296 if (listView->flow() == QListView::TopToBottom)
00297 {
00298 elementsPerRow = 1;
00299 }
00300
00301 foreach (const QString &itCategory, categories)
00302 {
00303 if (itCategory == category)
00304 break;
00305
00306 float rows = (float) ((float) categoriesIndexes[itCategory].count() /
00307 (float) elementsPerRow);
00308 int rowsInt = categoriesIndexes[itCategory].count() / elementsPerRow;
00309
00310 if (rows - trunc(rows)) rowsInt++;
00311
00312 retRect.setTop(retRect.top() +
00313 (rowsInt * itemHeight) +
00314 categoryDrawer->categoryHeight(index, listView->viewOptions()) +
00315 listView->spacing() * 2);
00316
00317 if (listView->gridSize().isEmpty())
00318 {
00319 retRect.setTop(retRect.top() +
00320 (rowsInt * listView->spacing()));
00321 }
00322 }
00323
00324 retRect.setHeight(categoryDrawer->categoryHeight(index, listView->viewOptions()));
00325
00326 return retRect;
00327 }
00328
00329
00330 const QRect &KCategorizedView::Private::cacheIndex(const QModelIndex &index)
00331 {
00332 QRect rect = visualRectInViewport(index);
00333 QHash<int, QRect>::iterator it = elementsPosition.insert(index.row(), rect);
00334
00335 return *it;
00336 }
00337
00338
00339 const QRect &KCategorizedView::Private::cacheCategory(const QString &category)
00340 {
00341 QRect rect = visualCategoryRectInViewport(category);
00342 QHash<QString, QRect>::iterator it = categoriesPosition.insert(category, rect);
00343
00344 return *it;
00345 }
00346
00347 const QRect &KCategorizedView::Private::cachedRectIndex(const QModelIndex &index)
00348 {
00349 QHash<int, QRect>::const_iterator it = elementsPosition.constFind(index.row());
00350 if (it != elementsPosition.constEnd())
00351 {
00352 return *it;
00353 }
00354 else
00355 {
00356 return cacheIndex(index);
00357 }
00358 }
00359
00360 const QRect &KCategorizedView::Private::cachedRectCategory(const QString &category)
00361 {
00362 QHash<QString, QRect>::const_iterator it = categoriesPosition.constFind(category);
00363 if (it != categoriesPosition.constEnd())
00364 {
00365 return *it;
00366 }
00367 else
00368 {
00369 return cacheCategory(category);
00370 }
00371 }
00372
00373 QRect KCategorizedView::Private::visualRect(const QModelIndex &index)
00374 {
00375 QRect retRect = cachedRectIndex(index);
00376 int dx = -listView->horizontalOffset();
00377 int dy = -listView->verticalOffset();
00378 retRect.adjust(dx, dy, dx, dy);
00379
00380 return retRect;
00381 }
00382
00383 QRect KCategorizedView::Private::categoryVisualRect(const QString &category)
00384 {
00385 QRect retRect = cachedRectCategory(category);
00386 int dx = -listView->horizontalOffset();
00387 int dy = -listView->verticalOffset();
00388 retRect.adjust(dx, dy, dx, dy);
00389
00390 return retRect;
00391 }
00392
00393 void KCategorizedView::Private::drawNewCategory(const QModelIndex &index,
00394 int sortRole,
00395 const QStyleOption &option,
00396 QPainter *painter)
00397 {
00398 if (!index.isValid())
00399 {
00400 return;
00401 }
00402
00403 QStyleOption optionCopy = option;
00404 const QString category = proxyModel->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
00405
00406 optionCopy.state &= ~QStyle::State_Selected;
00407
00408 if ((listView->selectionMode() != SingleSelection) && (listView->selectionMode() != NoSelection)) {
00409 if ((category == hoveredCategory) && !mouseButtonPressed)
00410 {
00411 optionCopy.state |= QStyle::State_MouseOver;
00412 }
00413 else if ((category == hoveredCategory) && mouseButtonPressed)
00414 {
00415 QPoint initialPressPosition = listView->viewport()->mapFromGlobal(QCursor::pos());
00416 initialPressPosition.setY(initialPressPosition.y() + listView->verticalOffset());
00417 initialPressPosition.setX(initialPressPosition.x() + listView->horizontalOffset());
00418
00419 if (initialPressPosition == this->initialPressPosition)
00420 {
00421 optionCopy.state |= QStyle::State_Selected;
00422 }
00423 }
00424 }
00425
00426 categoryDrawer->drawCategory(index,
00427 sortRole,
00428 optionCopy,
00429 painter);
00430 }
00431
00432
00433 void KCategorizedView::Private::updateScrollbars()
00434 {
00435
00436 QModelIndex lastIndex = categoriesIndexes.isEmpty() ? QModelIndex() : categoriesIndexes[categories.last()].last();
00437
00438 int lastItemBottom = cachedRectIndex(lastIndex).top() +
00439 listView->spacing() + (listView->gridSize().isEmpty() ? biggestItemSize.height() : listView->gridSize().height()) - listView->viewport()->height();
00440
00441 listView->horizontalScrollBar()->setRange(0, 0);
00442
00443 if (listView->verticalScrollMode() == QAbstractItemView::ScrollPerItem)
00444 {
00445 listView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
00446 }
00447
00448 if (listView->horizontalScrollMode() == QAbstractItemView::ScrollPerItem)
00449 {
00450 listView->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
00451 }
00452
00453 listView->verticalScrollBar()->setSingleStep(listView->viewport()->height() / 10);
00454 listView->verticalScrollBar()->setPageStep(listView->viewport()->height());
00455 listView->verticalScrollBar()->setRange(0, lastItemBottom);
00456 }
00457
00458 void KCategorizedView::Private::drawDraggedItems(QPainter *painter)
00459 {
00460 QStyleOptionViewItemV4 option = listView->viewOptions();
00461 option.state &= ~QStyle::State_MouseOver;
00462 foreach (const QModelIndex &index, listView->selectionModel()->selectedIndexes())
00463 {
00464 const int dx = mousePosition.x() - initialPressPosition.x() + listView->horizontalOffset();
00465 const int dy = mousePosition.y() - initialPressPosition.y() + listView->verticalOffset();
00466
00467 option.rect = visualRect(index);
00468 option.rect.adjust(dx, dy, dx, dy);
00469
00470 if (option.rect.intersects(listView->viewport()->rect()))
00471 {
00472 listView->itemDelegate(index)->paint(painter, option, index);
00473 }
00474 }
00475 }
00476
00477 void KCategorizedView::Private::layoutChanged(bool forceItemReload)
00478 {
00479 if (proxyModel && categoryDrawer && proxyModel->isCategorizedModel() &&
00480 ((forceItemReload ||
00481 (modelSortRole != proxyModel->sortRole()) ||
00482 (modelSortColumn != proxyModel->sortColumn()) ||
00483 (modelSortOrder != proxyModel->sortOrder()) ||
00484 (modelLastRowCount != proxyModel->rowCount()) ||
00485 (modelCategorized != proxyModel->isCategorizedModel()))))
00486 {
00487
00488 listView->rowsInsertedArtifficial(QModelIndex(), 0, proxyModel->rowCount() - 1);
00489
00490 if (!forceItemReload)
00491 {
00492 modelSortRole = proxyModel->sortRole();
00493 modelSortColumn = proxyModel->sortColumn();
00494 modelSortOrder = proxyModel->sortOrder();
00495 modelLastRowCount = proxyModel->rowCount();
00496 modelCategorized = proxyModel->isCategorizedModel();
00497 }
00498 }
00499
00500 if (proxyModel && categoryDrawer && proxyModel->isCategorizedModel())
00501 {
00502 updateScrollbars();
00503 }
00504 }
00505
00506 void KCategorizedView::Private::drawDraggedItems()
00507 {
00508 QRect rectToUpdate;
00509 QRect currentRect;
00510 foreach (const QModelIndex &index, listView->selectionModel()->selectedIndexes())
00511 {
00512 int dx = mousePosition.x() - initialPressPosition.x() + listView->horizontalOffset();
00513 int dy = mousePosition.y() - initialPressPosition.y() + listView->verticalOffset();
00514
00515 currentRect = visualRect(index);
00516 currentRect.adjust(dx, dy, dx, dy);
00517
00518 if (currentRect.intersects(listView->viewport()->rect()))
00519 {
00520 rectToUpdate = rectToUpdate.united(currentRect);
00521 }
00522 }
00523
00524 listView->viewport()->update(lastDraggedItemsRect.united(rectToUpdate));
00525
00526 lastDraggedItemsRect = rectToUpdate;
00527 }
00528
00529
00530
00531
00532
00533 KCategorizedView::KCategorizedView(QWidget *parent)
00534 : QListView(parent)
00535 , d(new Private(this))
00536 {
00537 }
00538
00539 KCategorizedView::~KCategorizedView()
00540 {
00541 delete d;
00542 }
00543
00544 void KCategorizedView::setGridSize(const QSize &size)
00545 {
00546 QListView::setGridSize(size);
00547
00548 d->layoutChanged(true);
00549 }
00550
00551 void KCategorizedView::setModel(QAbstractItemModel *model)
00552 {
00553 d->lastSelection = QItemSelection();
00554 d->forcedSelectionPosition = 0;
00555 d->elementsInfo.clear();
00556 d->elementsPosition.clear();
00557 d->categoriesIndexes.clear();
00558 d->categoriesPosition.clear();
00559 d->categories.clear();
00560 d->intersectedIndexes.clear();
00561 d->modelIndexList.clear();
00562 d->hovered = QModelIndex();
00563 d->mouseButtonPressed = false;
00564 d->rightMouseButtonPressed = false;
00565
00566 if (d->proxyModel)
00567 {
00568 QObject::disconnect(d->proxyModel,
00569 SIGNAL(layoutChanged()),
00570 this, SLOT(slotLayoutChanged()));
00571
00572 QObject::disconnect(d->proxyModel,
00573 SIGNAL(rowsRemoved(QModelIndex,int,int)),
00574 this, SLOT(rowsRemoved(QModelIndex,int,int)));
00575 }
00576
00577 QListView::setModel(model);
00578
00579 d->proxyModel = dynamic_cast<KCategorizedSortFilterProxyModel*>(model);
00580
00581 if (d->proxyModel)
00582 {
00583 d->modelSortRole = d->proxyModel->sortRole();
00584 d->modelSortColumn = d->proxyModel->sortColumn();
00585 d->modelSortOrder = d->proxyModel->sortOrder();
00586 d->modelLastRowCount = d->proxyModel->rowCount();
00587 d->modelCategorized = d->proxyModel->isCategorizedModel();
00588
00589 QObject::connect(d->proxyModel,
00590 SIGNAL(layoutChanged()),
00591 this, SLOT(slotLayoutChanged()));
00592
00593 QObject::connect(d->proxyModel,
00594 SIGNAL(rowsRemoved(QModelIndex,int,int)),
00595 this, SLOT(rowsRemoved(QModelIndex,int,int)));
00596
00597 if (d->proxyModel->rowCount())
00598 {
00599 d->layoutChanged(true);
00600 }
00601 }
00602 else
00603 {
00604 d->modelCategorized = false;
00605 }
00606 }
00607
00608 QRect KCategorizedView::visualRect(const QModelIndex &index) const
00609 {
00610 if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
00611 {
00612 return QListView::visualRect(index);
00613 }
00614
00615 if (!qobject_cast<const QSortFilterProxyModel*>(index.model()))
00616 {
00617 return d->visualRect(d->proxyModel->mapFromSource(index));
00618 }
00619
00620 return d->visualRect(index);
00621 }
00622
00623 KCategoryDrawer *KCategorizedView::categoryDrawer() const
00624 {
00625 return d->categoryDrawer;
00626 }
00627
00628 void KCategorizedView::setCategoryDrawer(KCategoryDrawer *categoryDrawer)
00629 {
00630 d->lastSelection = QItemSelection();
00631 d->forcedSelectionPosition = 0;
00632 d->elementsInfo.clear();
00633 d->elementsPosition.clear();
00634 d->categoriesIndexes.clear();
00635 d->categoriesPosition.clear();
00636 d->categories.clear();
00637 d->intersectedIndexes.clear();
00638 d->modelIndexList.clear();
00639 d->hovered = QModelIndex();
00640 d->mouseButtonPressed = false;
00641 d->rightMouseButtonPressed = false;
00642
00643 if (!categoryDrawer && d->proxyModel)
00644 {
00645 QObject::disconnect(d->proxyModel,
00646 SIGNAL(layoutChanged()),
00647 this, SLOT(slotLayoutChanged()));
00648
00649 QObject::disconnect(d->proxyModel,
00650 SIGNAL(rowsRemoved(QModelIndex,int,int)),
00651 this, SLOT(rowsRemoved(QModelIndex,int,int)));
00652 }
00653 else if (categoryDrawer && d->proxyModel)
00654 {
00655 QObject::connect(d->proxyModel,
00656 SIGNAL(layoutChanged()),
00657 this, SLOT(slotLayoutChanged()));
00658
00659 QObject::connect(d->proxyModel,
00660 SIGNAL(rowsRemoved(QModelIndex,int,int)),
00661 this, SLOT(rowsRemoved(QModelIndex,int,int)));
00662 }
00663
00664 d->categoryDrawer = categoryDrawer;
00665
00666 if (categoryDrawer)
00667 {
00668 if (d->proxyModel)
00669 {
00670 if (d->proxyModel->rowCount())
00671 {
00672 d->layoutChanged(true);
00673 }
00674 }
00675 }
00676 else
00677 {
00678 updateGeometries();
00679 }
00680 }
00681
00682 QModelIndex KCategorizedView::indexAt(const QPoint &point) const
00683 {
00684 if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
00685 {
00686 return QListView::indexAt(point);
00687 }
00688
00689 QModelIndex index;
00690
00691 const QModelIndexList item = d->intersectionSet(QRect(point, point));
00692
00693 if (item.count() == 1)
00694 {
00695 index = item[0];
00696 }
00697
00698 return index;
00699 }
00700
00701 void KCategorizedView::reset()
00702 {
00703 QListView::reset();
00704
00705 d->lastSelection = QItemSelection();
00706 d->forcedSelectionPosition = 0;
00707 d->elementsInfo.clear();
00708 d->elementsPosition.clear();
00709 d->categoriesIndexes.clear();
00710 d->categoriesPosition.clear();
00711 d->categories.clear();
00712 d->intersectedIndexes.clear();
00713 d->modelIndexList.clear();
00714 d->hovered = QModelIndex();
00715 d->biggestItemSize = QSize(0, 0);
00716 d->mouseButtonPressed = false;
00717 d->rightMouseButtonPressed = false;
00718 }
00719
00720 void KCategorizedView::paintEvent(QPaintEvent *event)
00721 {
00722 if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
00723 {
00724 QListView::paintEvent(event);
00725 return;
00726 }
00727
00728 bool alternatingRows = alternatingRowColors();
00729
00730 QStyleOptionViewItemV4 option = viewOptions();
00731 option.widget = this;
00732 if (wordWrap())
00733 {
00734 option.features |= QStyleOptionViewItemV4::WrapText;
00735 }
00736
00737 QPainter painter(viewport());
00738 QRect area = event->rect();
00739 const bool focus = (hasFocus() || viewport()->hasFocus()) &&
00740 currentIndex().isValid();
00741 const QStyle::State state = option.state;
00742 const bool enabled = (state & QStyle::State_Enabled) != 0;
00743
00744 painter.save();
00745
00746 QModelIndexList dirtyIndexes = d->intersectionSet(area);
00747 bool alternate = false;
00748 if (dirtyIndexes.count())
00749 {
00750 alternate = dirtyIndexes[0].row() % 2;
00751 }
00752 foreach (const QModelIndex &index, dirtyIndexes)
00753 {
00754 if (alternatingRows && alternate)
00755 {
00756 option.features |= QStyleOptionViewItemV4::Alternate;
00757 alternate = false;
00758 }
00759 else if (alternatingRows)
00760 {
00761 option.features &= ~QStyleOptionViewItemV4::Alternate;
00762 alternate = true;
00763 }
00764 option.state = state;
00765 option.rect = visualRect(index);
00766
00767 if (selectionModel() && selectionModel()->isSelected(index))
00768 {
00769 option.state |= QStyle::State_Selected;
00770 }
00771
00772 if (enabled)
00773 {
00774 QPalette::ColorGroup cg;
00775 if ((d->proxyModel->flags(index) & Qt::ItemIsEnabled) == 0)
00776 {
00777 option.state &= ~QStyle::State_Enabled;
00778 cg = QPalette::Disabled;
00779 }
00780 else
00781 {
00782 cg = QPalette::Normal;
00783 }
00784 option.palette.setCurrentColorGroup(cg);
00785 }
00786
00787 if (focus && currentIndex() == index)
00788 {
00789 option.state |= QStyle::State_HasFocus;
00790 if (this->state() == EditingState)
00791 option.state |= QStyle::State_Editing;
00792 }
00793
00794
00795
00796 if ((index == d->hovered) && !d->mouseButtonPressed &&
00797 (this->state() == QAbstractItemView::NoState))
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 = QString();
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 = QString();
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 QListView::startDrag(supportedActions);
01222 #endif
01223
01224 d->isDragging = false;
01225 d->mouseButtonPressed = false;
01226 d->rightMouseButtonPressed = false;
01227
01228 viewport()->update(d->lastDraggedItemsRect);
01229 }
01230
01231 void KCategorizedView::dragMoveEvent(QDragMoveEvent *event)
01232 {
01233 d->mousePosition = event->pos();
01234
01235 if (d->mouseButtonPressed)
01236 {
01237 d->isDragging = true;
01238 }
01239 else
01240 {
01241 d->isDragging = false;
01242 }
01243
01244 d->dragLeftViewport = false;
01245
01246 #if defined(DOLPHIN_DRAGANDDROP)
01247 QAbstractItemView::dragMoveEvent(event);
01248 #else
01249 QListView::dragMoveEvent(event);
01250 #endif
01251
01252 if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
01253 {
01254 return;
01255 }
01256
01257 d->drawDraggedItems();
01258 }
01259
01260 void KCategorizedView::dragLeaveEvent(QDragLeaveEvent *event)
01261 {
01262 d->dragLeftViewport = true;
01263
01264 #if defined(DOLPHIN_DRAGANDDROP)
01265 QAbstractItemView::dragLeaveEvent(event);
01266 #else
01267 QListView::dragLeaveEvent(event);
01268 #endif
01269 }
01270
01271 void KCategorizedView::dropEvent(QDropEvent *event)
01272 {
01273 #if defined(DOLPHIN_DRAGANDDROP)
01274 QAbstractItemView::dropEvent(event);
01275 #else
01276 QListView::dropEvent(event);
01277 #endif
01278 }
01279
01280 QModelIndex KCategorizedView::moveCursor(CursorAction cursorAction,
01281 Qt::KeyboardModifiers modifiers)
01282 {
01283 if ((viewMode() != KCategorizedView::IconMode) ||
01284 !d->proxyModel ||
01285 !d->categoryDrawer ||
01286 d->categories.isEmpty() ||
01287 !d->proxyModel->isCategorizedModel())
01288 {
01289 return QListView::moveCursor(cursorAction, modifiers);
01290 }
01291
01292 int viewportWidth = viewport()->width() - spacing();
01293 int itemWidth;
01294
01295 if (gridSize().isEmpty())
01296 {
01297 itemWidth = d->biggestItemSize.width();
01298 }
01299 else
01300 {
01301 itemWidth = gridSize().width();
01302 }
01303
01304 int itemWidthPlusSeparation = spacing() + itemWidth;
01305 if (!itemWidthPlusSeparation)
01306 itemWidthPlusSeparation++;
01307 int elementsPerRow = viewportWidth / itemWidthPlusSeparation;
01308 if (!elementsPerRow)
01309 elementsPerRow++;
01310
01311 QModelIndex current = selectionModel() ? selectionModel()->currentIndex()
01312 : QModelIndex();
01313
01314 if (!current.isValid())
01315 {
01316 if (cursorAction == MoveEnd)
01317 {
01318 current = model()->index(model()->rowCount() - 1, 0, QModelIndex());
01319 d->forcedSelectionPosition = d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow;
01320 }
01321 else
01322 {
01323 current = model()->index(0, 0, QModelIndex());
01324 d->forcedSelectionPosition = 0;
01325 }
01326
01327 return current;
01328 }
01329
01330 QString lastCategory = d->categories.first();
01331 QString theCategory = d->categories.first();
01332 QString afterCategory = d->categories.first();
01333
01334 bool hasToBreak = false;
01335 foreach (const QString &category, d->categories)
01336 {
01337 if (hasToBreak)
01338 {
01339 afterCategory = category;
01340
01341 break;
01342 }
01343
01344 if (category == d->elementsInfo[current.row()].category)
01345 {
01346 theCategory = category;
01347
01348 hasToBreak = true;
01349 }
01350
01351 if (!hasToBreak)
01352 {
01353 lastCategory = category;
01354 }
01355 }
01356
01357 switch (cursorAction)
01358 {
01359 case QAbstractItemView::MoveUp: {
01360 if (d->elementsInfo[current.row()].relativeOffsetToCategory >= elementsPerRow)
01361 {
01362 int indexToMove = current.row();
01363 indexToMove -= qMin(((d->elementsInfo[current.row()].relativeOffsetToCategory) + d->forcedSelectionPosition), elementsPerRow - d->forcedSelectionPosition + (d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow));
01364
01365 return d->proxyModel->index(indexToMove, 0);
01366 }
01367 else
01368 {
01369 int lastCategoryLastRow = (d->categoriesIndexes[lastCategory].count() - 1) % elementsPerRow;
01370 int indexToMove = current.row() - d->elementsInfo[current.row()].relativeOffsetToCategory;
01371
01372 if (d->forcedSelectionPosition >= lastCategoryLastRow)
01373 {
01374 indexToMove -= 1;
01375 }
01376 else
01377 {
01378 indexToMove -= qMin((lastCategoryLastRow - d->forcedSelectionPosition + 1), d->forcedSelectionPosition + elementsPerRow + 1);
01379 }
01380
01381 return d->proxyModel->index(indexToMove, 0);
01382 }
01383 }
01384
01385 case QAbstractItemView::MoveDown: {
01386 if (d->elementsInfo[current.row()].relativeOffsetToCategory < (d->categoriesIndexes[theCategory].count() - 1 - ((d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow)))
01387 {
01388 int indexToMove = current.row();
01389 indexToMove += qMin(elementsPerRow, d->categoriesIndexes[theCategory].count() - 1 - d->elementsInfo[current.row()].relativeOffsetToCategory);
01390
01391 return d->proxyModel->index(indexToMove, 0);
01392 }
01393 else
01394 {
01395 int afterCategoryLastRow = qMin(elementsPerRow, d->categoriesIndexes[afterCategory].count());
01396 int indexToMove = current.row() + (d->categoriesIndexes[theCategory].count() - d->elementsInfo[current.row()].relativeOffsetToCategory);
01397
01398 if (d->forcedSelectionPosition >= afterCategoryLastRow)
01399 {
01400 indexToMove += afterCategoryLastRow - 1;
01401 }
01402 else
01403 {
01404 indexToMove += qMin(d->forcedSelectionPosition, elementsPerRow);
01405 }
01406
01407 return d->proxyModel->index(indexToMove, 0);
01408 }
01409 }
01410
01411 case QAbstractItemView::MoveLeft:
01412 if (layoutDirection() == Qt::RightToLeft)
01413 {
01414 if (!(d->elementsInfo[current.row() + 1].relativeOffsetToCategory % elementsPerRow))
01415 return current;
01416
01417 d->forcedSelectionPosition = d->elementsInfo[current.row() + 1].relativeOffsetToCategory % elementsPerRow;
01418
01419 #if 0 //follow qt view behavior. lateral movements won't change visual row
01420 if (d->forcedSelectionPosition < 0)
01421 d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow;
01422 #endif
01423
01424 return d->proxyModel->index(current.row() + 1, 0);
01425 }
01426
01427 if (!(d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow))
01428 return current;
01429
01430 d->forcedSelectionPosition = d->elementsInfo[current.row() - 1].relativeOffsetToCategory % elementsPerRow;
01431
01432 #if 0 //follow qt view behavior. lateral movements won't change visual row
01433 if (d->forcedSelectionPosition < 0)
01434 d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow;
01435 #endif
01436
01437 return d->proxyModel->index(current.row() - 1, 0);
01438
01439 case QAbstractItemView::MoveRight:
01440 if (layoutDirection() == Qt::RightToLeft)
01441 {
01442 if (!(d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow))
01443 return current;
01444
01445 d->forcedSelectionPosition = d->elementsInfo[current.row() - 1].relativeOffsetToCategory % elementsPerRow;
01446
01447 #if 0 //follow qt view behavior. lateral movements won't change visual row
01448 if (d->forcedSelectionPosition < 0)
01449 d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow;
01450 #endif
01451
01452 return d->proxyModel->index(current.row() - 1, 0);
01453 }
01454
01455 if (!(d->elementsInfo[current.row() + 1].relativeOffsetToCategory % elementsPerRow))
01456 return current;
01457
01458 d->forcedSelectionPosition = d->elementsInfo[current.row() + 1].relativeOffsetToCategory % elementsPerRow;
01459
01460 #if 0 //follow qt view behavior. lateral movements won't change visual row
01461 if (d->forcedSelectionPosition < 0)
01462 d->forcedSelectionPosition = (d->categoriesIndexes[theCategory].count() - 1) % elementsPerRow;
01463 #endif
01464
01465 return d->proxyModel->index(current.row() + 1, 0);
01466
01467 default:
01468 break;
01469 }
01470
01471 return QListView::moveCursor(cursorAction, modifiers);
01472 }
01473
01474 void KCategorizedView::rowsInserted(const QModelIndex &parent,
01475 int start,
01476 int end)
01477 {
01478 QListView::rowsInserted(parent, start, end);
01479
01480 if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
01481 {
01482 d->forcedSelectionPosition = 0;
01483 d->elementsInfo.clear();
01484 d->elementsPosition.clear();
01485 d->categoriesIndexes.clear();
01486 d->categoriesPosition.clear();
01487 d->categories.clear();
01488 d->intersectedIndexes.clear();
01489 d->modelIndexList.clear();
01490 d->hovered = QModelIndex();
01491 d->biggestItemSize = QSize(0, 0);
01492 d->mouseButtonPressed = false;
01493 d->rightMouseButtonPressed = false;
01494
01495 return;
01496 }
01497
01498 rowsInsertedArtifficial(parent, start, end);
01499 }
01500
01501 void KCategorizedView::rowsInsertedArtifficial(const QModelIndex &parent,
01502 int start,
01503 int end)
01504 {
01505 Q_UNUSED(parent);
01506
01507 d->forcedSelectionPosition = 0;
01508 d->elementsInfo.clear();
01509 d->elementsPosition.clear();
01510 d->categoriesIndexes.clear();
01511 d->categoriesPosition.clear();
01512 d->categories.clear();
01513 d->intersectedIndexes.clear();
01514 d->modelIndexList.clear();
01515 d->hovered = QModelIndex();
01516 d->biggestItemSize = QSize(0, 0);
01517 d->mouseButtonPressed = false;
01518 d->rightMouseButtonPressed = false;
01519
01520 if (start > end || end < 0 || start < 0 || !d->proxyModel->rowCount())
01521 {
01522 return;
01523 }
01524
01525
01526 QString prevCategory = d->proxyModel->data(d->proxyModel->index(0, d->proxyModel->sortColumn()), KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
01527 QString lastCategory = prevCategory;
01528 QModelIndexList modelIndexList;
01529 struct Private::ElementInfo elementInfo;
01530 int offset = -1;
01531 for (int k = 0; k < d->proxyModel->rowCount(); ++k)
01532 {
01533 QModelIndex index = d->proxyModel->index(k, d->proxyModel->sortColumn());
01534 QModelIndex indexSize = d->proxyModel->index(k, 0);
01535
01536 d->biggestItemSize = QSize(qMax(sizeHintForIndex(indexSize).width(),
01537 d->biggestItemSize.width()),
01538 qMax(sizeHintForIndex(indexSize).height(),
01539 d->biggestItemSize.height()));
01540
01541 d->modelIndexList << index;
01542
01543 lastCategory = d->proxyModel->data(index, KCategorizedSortFilterProxyModel::CategoryDisplayRole).toString();
01544
01545 elementInfo.category = lastCategory;
01546
01547 if (prevCategory != lastCategory)
01548 {
01549 offset = 0;
01550 d->categoriesIndexes.insert(prevCategory, modelIndexList);
01551 d->categories << prevCategory;
01552 modelIndexList.clear();
01553 }
01554 else
01555 {
01556 offset++;
01557 }
01558
01559 elementInfo.relativeOffsetToCategory = offset;
01560
01561 modelIndexList << index;
01562 prevCategory = lastCategory;
01563
01564 d->elementsInfo.insert(index.row(), elementInfo);
01565 }
01566
01567 d->categoriesIndexes.insert(prevCategory, modelIndexList);
01568 d->categories << prevCategory;
01569
01570 d->updateScrollbars();
01571
01572
01573
01574 selectionModel()->clear();
01575 }
01576
01577 void KCategorizedView::rowsRemoved(const QModelIndex &parent,
01578 int start,
01579 int end)
01580 {
01581 if (d->proxyModel && d->categoryDrawer && d->proxyModel->isCategorizedModel())
01582 {
01583
01584 rowsInsertedArtifficial(QModelIndex(), 0, d->proxyModel->rowCount() - 1);
01585 }
01586 }
01587
01588 void KCategorizedView::updateGeometries()
01589 {
01590 if (!d->proxyModel || !d->categoryDrawer || !d->proxyModel->isCategorizedModel())
01591 {
01592 QListView::updateGeometries();
01593 return;
01594 }
01595
01596
01597
01598 QAbstractItemView::updateGeometries();
01599 }
01600
01601 void KCategorizedView::slotLayoutChanged()
01602 {
01603 d->layoutChanged();
01604 }
01605
01606 void KCategorizedView::currentChanged(const QModelIndex ¤t,
01607 const QModelIndex &previous)
01608 {
01609
01610
01611
01612 int viewportWidth = viewport()->width() - spacing();
01613
01614 int itemHeight;
01615 int itemWidth;
01616
01617 if (gridSize().isEmpty())
01618 {
01619 itemHeight = d->biggestItemSize.height();
01620 itemWidth = d->biggestItemSize.width();
01621 }
01622 else
01623 {
01624 itemHeight = gridSize().height();
01625 itemWidth = gridSize().width();
01626 }
01627
01628 int itemWidthPlusSeparation = spacing() + itemWidth;
01629 if (!itemWidthPlusSeparation)
01630 itemWidthPlusSeparation++;
01631 int elementsPerRow = viewportWidth / itemWidthPlusSeparation;
01632 if (!elementsPerRow)
01633 elementsPerRow++;
01634
01635 if (d->mouseButtonPressed || d->rightMouseButtonPressed)
01636 d->forcedSelectionPosition = d->elementsInfo[current.row()].relativeOffsetToCategory % elementsPerRow;
01637
01638 QListView::currentChanged(current, previous);
01639 }
01640
01641 void KCategorizedView::dataChanged(const QModelIndex &topLeft,
01642 const QModelIndex &bottomRight)
01643 {
01644 if (topLeft == bottomRight)
01645 {
01646 d->cacheIndex(topLeft);
01647 }
01648 else
01649 {
01650 const int columnStart = topLeft.column();
01651 const int columnEnd = bottomRight.column();
01652 const int rowStart = topLeft.row();
01653 const int rowEnd = bottomRight.row();
01654
01655 for (int row = rowStart; row <= rowEnd; ++row)
01656 {
01657 for (int column = columnStart; column <= columnEnd; ++column)
01658 {
01659 d->cacheIndex(d->proxyModel->index(row, column));
01660 }
01661 }
01662 }
01663
01664 QListView::dataChanged(topLeft, bottomRight);
01665 slotLayoutChanged();
01666 }
01667
01668 #include "kcategorizedview.moc"