diff options
Diffstat (limited to 'src/gui/itemviews')
39 files changed, 2487 insertions, 2185 deletions
diff --git a/src/gui/itemviews/qabstractitemdelegate.cpp b/src/gui/itemviews/qabstractitemdelegate.cpp index 101047a..f7396f0 100644 --- a/src/gui/itemviews/qabstractitemdelegate.cpp +++ b/src/gui/itemviews/qabstractitemdelegate.cpp @@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE data items from a model. \ingroup model-view - \mainclass + A QAbstractItemDelegate provides the interface and common functionality for delegates in the model/view architecture. Delegates display diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp index 3d7ab5c..07c5454 100644 --- a/src/gui/itemviews/qabstractitemview.cpp +++ b/src/gui/itemviews/qabstractitemview.cpp @@ -61,6 +61,7 @@ #ifndef QT_NO_ACCESSIBILITY #include <qaccessible.h> #endif +#include <private/qactiontokeyeventmapper_p.h> QT_BEGIN_NAMESPACE @@ -73,6 +74,7 @@ QAbstractItemViewPrivate::QAbstractItemViewPrivate() currentlyCommittingEditor(0), pressedModifiers(Qt::NoModifier), pressedPosition(QPoint(-1, -1)), + pressedAlreadySelected(false), viewportEnteredNeeded(false), state(QAbstractItemView::NoState), editTriggers(QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed), @@ -108,16 +110,16 @@ void QAbstractItemViewPrivate::init() Q_Q(QAbstractItemView); q->setItemDelegate(new QStyledItemDelegate(q)); - q->verticalScrollBar()->setRange(0, 0); - q->horizontalScrollBar()->setRange(0, 0); + vbar->setRange(0, 0); + hbar->setRange(0, 0); - QObject::connect(q->verticalScrollBar(), SIGNAL(actionTriggered(int)), + QObject::connect(vbar, SIGNAL(actionTriggered(int)), q, SLOT(verticalScrollbarAction(int))); - QObject::connect(q->horizontalScrollBar(), SIGNAL(actionTriggered(int)), + QObject::connect(hbar, SIGNAL(actionTriggered(int)), q, SLOT(horizontalScrollbarAction(int))); - QObject::connect(q->verticalScrollBar(), SIGNAL(valueChanged(int)), + QObject::connect(vbar, SIGNAL(valueChanged(int)), q, SLOT(verticalScrollbarValueChanged(int))); - QObject::connect(q->horizontalScrollBar(), SIGNAL(valueChanged(int)), + QObject::connect(hbar, SIGNAL(valueChanged(int)), q, SLOT(horizontalScrollbarValueChanged(int))); viewport->setBackgroundRole(QPalette::Base); @@ -127,6 +129,37 @@ void QAbstractItemViewPrivate::init() q->setAttribute(Qt::WA_InputMethodEnabled); } +void QAbstractItemViewPrivate::checkMouseMove(const QPersistentModelIndex &index) +{ + //we take a persistent model index because the model might change by emitting signals + Q_Q(QAbstractItemView); + if (viewportEnteredNeeded || enteredIndex != index) { + viewportEnteredNeeded = false; + + if (index.isValid()) { + emit q->entered(index); +#ifndef QT_NO_STATUSTIP + QString statustip = model->data(index, Qt::StatusTipRole).toString(); + if (parent && !statustip.isEmpty()) { + QStatusTipEvent tip(statustip); + QApplication::sendEvent(parent, &tip); + } +#endif + } else { +#ifndef QT_NO_STATUSTIP + if (parent) { + QString emptyString; + QStatusTipEvent tip( emptyString ); + QApplication::sendEvent(parent, &tip); + } +#endif + emit q->viewportEntered(); + } + enteredIndex = index; + } +} + + /*! \class QAbstractItemView @@ -134,7 +167,7 @@ void QAbstractItemViewPrivate::init() item view classes. \ingroup model-view - \mainclass + QAbstractItemView class is the base class for every standard view that uses a QAbstractItemModel. QAbstractItemView is an abstract @@ -552,7 +585,7 @@ void QAbstractItemView::setModel(QAbstractItemModel *model) "QAbstractItemView::setModel", "The parent of a top level index should be invalid"); - if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) { + if (d->model != QAbstractItemModelPrivate::staticEmptyModel()) { connect(d->model, SIGNAL(destroyed()), this, SLOT(_q_modelDestroyed())); connect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), @@ -820,8 +853,8 @@ QAbstractItemDelegate *QAbstractItemView::itemDelegateForColumn(int column) cons } /*! - Returns the item delegate used by this view and model for - the given \a index. + Returns the item delegate used by this view and model for + the given \a index. */ QAbstractItemDelegate *QAbstractItemView::itemDelegate(const QModelIndex &index) const { @@ -830,14 +863,14 @@ QAbstractItemDelegate *QAbstractItemView::itemDelegate(const QModelIndex &index) } /*! - \property QAbstractItemView::selectionMode - \brief which selection mode the view operates in + \property QAbstractItemView::selectionMode + \brief which selection mode the view operates in - This property controls whether the user can select one or many items - and, in many-item selections, whether the selection must be a - continuous range of items. + This property controls whether the user can select one or many items + and, in many-item selections, whether the selection must be a + continuous range of items. - \sa SelectionMode SelectionBehavior + \sa SelectionMode SelectionBehavior */ void QAbstractItemView::setSelectionMode(SelectionMode mode) { @@ -852,13 +885,13 @@ QAbstractItemView::SelectionMode QAbstractItemView::selectionMode() const } /*! - \property QAbstractItemView::selectionBehavior - \brief which selection behavior the view uses + \property QAbstractItemView::selectionBehavior + \brief which selection behavior the view uses - This property holds whether selections are done - in terms of single items, rows or columns. + This property holds whether selections are done + in terms of single items, rows or columns. - \sa SelectionMode SelectionBehavior + \sa SelectionMode SelectionBehavior */ void QAbstractItemView::setSelectionBehavior(QAbstractItemView::SelectionBehavior behavior) @@ -875,7 +908,9 @@ QAbstractItemView::SelectionBehavior QAbstractItemView::selectionBehavior() cons /*! Sets the current item to be the item at \a index. - Depending on the current selection mode, the item may also be selected. + + Unless the current selection mode is + \l{QAbstractItemView::}{NoSelection}, the item is also be selected. Note that this function also updates the starting position for any new selections the user performs. @@ -929,6 +964,8 @@ void QAbstractItemView::reset() d->currentIndexSet = false; setState(NoState); setRootIndex(QModelIndex()); + if (d->selectionModel) + d->selectionModel->reset(); } /*! @@ -959,11 +996,11 @@ QModelIndex QAbstractItemView::rootIndex() const } /*! - Selects all item in the view. - This function wil use the selection selection behavior - set on the view when selecting. + Selects all items in the view. + This function will use the selection behavior + set on the view when selecting. - \sa setSelection(), selectedIndexes(), clearSelection() + \sa setSelection(), selectedIndexes(), clearSelection() */ void QAbstractItemView::selectAll() { @@ -1192,10 +1229,10 @@ bool QAbstractItemView::tabKeyNavigation() const #ifndef QT_NO_DRAGANDDROP /*! - \property QAbstractItemView::showDropIndicator - \brief whether the drop indicator is shown when dragging items and dropping. + \property QAbstractItemView::showDropIndicator + \brief whether the drop indicator is shown when dragging items and dropping. - \sa dragEnabled DragDropMode dragDropOverwriteMode acceptDrops + \sa dragEnabled DragDropMode dragDropOverwriteMode acceptDrops */ void QAbstractItemView::setDropIndicatorShown(bool enable) @@ -1211,10 +1248,10 @@ bool QAbstractItemView::showDropIndicator() const } /*! - \property QAbstractItemView::dragEnabled - \brief whether the view supports dragging of its own items + \property QAbstractItemView::dragEnabled + \brief whether the view supports dragging of its own items - \sa showDropIndicator DragDropMode dragDropOverwriteMode acceptDrops + \sa showDropIndicator DragDropMode dragDropOverwriteMode acceptDrops */ void QAbstractItemView::setDragEnabled(bool enable) @@ -1250,11 +1287,11 @@ bool QAbstractItemView::dragEnabled() const */ /*! - \property QAbstractItemView::dragDropMode - \brief the drag and drop event the view will act upon + \property QAbstractItemView::dragDropMode + \brief the drag and drop event the view will act upon - \since 4.2 - \sa showDropIndicator dragDropOverwriteMode + \since 4.2 + \sa showDropIndicator dragDropOverwriteMode */ void QAbstractItemView::setDragDropMode(DragDropMode behavior) { @@ -1290,14 +1327,14 @@ QAbstractItemView::DragDropMode QAbstractItemView::dragDropMode() const #endif // QT_NO_DRAGANDDROP /*! - \property QAbstractItemView::alternatingRowColors - \brief whether to draw the background using alternating colors + \property QAbstractItemView::alternatingRowColors + \brief whether to draw the background using alternating colors - If this property is true, the item background will be drawn using - QPalette::Base and QPalette::AlternateBase; otherwise the background - will be drawn using the QPalette::Base color. + If this property is true, the item background will be drawn using + QPalette::Base and QPalette::AlternateBase; otherwise the background + will be drawn using the QPalette::Base color. - By default, this property is false. + By default, this property is false. */ void QAbstractItemView::setAlternatingRowColors(bool enable) { @@ -1426,10 +1463,10 @@ bool QAbstractItemView::viewportEvent(QEvent *event) case QEvent::HoverEnter: { QHoverEvent *he = static_cast<QHoverEvent*>(event); d->hover = indexAt(he->pos()); - d->viewport->update(visualRect(d->hover)); + update(d->hover); break; } case QEvent::HoverLeave: { - d->viewport->update(visualRect(d->hover)); // update old + update(d->hover); // update old d->hover = QModelIndex(); break; } case QEvent::HoverMove: { @@ -1557,7 +1594,7 @@ void QAbstractItemView::mouseMoveEvent(QMouseEvent *event) } #endif // QT_NO_DRAGANDDROP - QModelIndex index = indexAt(bottomRight); + QPersistentModelIndex index = indexAt(bottomRight); QModelIndex buddy = d->model->buddy(d->pressedIndex); if ((state() == EditingState && d->hasEditor(buddy)) || edit(index, NoEditTriggers, event)) @@ -1568,36 +1605,10 @@ void QAbstractItemView::mouseMoveEvent(QMouseEvent *event) else topLeft = bottomRight; - if (d->viewportEnteredNeeded || d->enteredIndex != index) { - d->viewportEnteredNeeded = false; - - // signal handlers may change the model - QPersistentModelIndex persistent = index; - if (persistent.isValid()) { - emit entered(persistent); -#ifndef QT_NO_STATUSTIP - QString statustip = d->model->data(persistent, Qt::StatusTipRole).toString(); - if (parent() && !statustip.isEmpty()) { - QStatusTipEvent tip(statustip); - QApplication::sendEvent(parent(), &tip); - } -#endif - } else { -#ifndef QT_NO_STATUSTIP - if (parent()) { - QString emptyString; - QStatusTipEvent tip(emptyString); - QApplication::sendEvent(parent(), &tip); - } -#endif - emit viewportEntered(); - } - d->enteredIndex = persistent; - index = persistent; - } + d->checkMouseMove(index); #ifndef QT_NO_DRAGANDDROP - if (index.isValid() + if (d->pressedIndex.isValid() && d->dragEnabled && (state() != DragSelectingState) && (event->buttons() != Qt::NoButton) @@ -1613,14 +1624,13 @@ void QAbstractItemView::mouseMoveEvent(QMouseEvent *event) // Do the normalize ourselves, since QRect::normalized() is flawed QRect selectionRect = QRect(topLeft, bottomRight); - QPersistentModelIndex persistent = index; setSelection(selectionRect, command); // set at the end because it might scroll the view - if (persistent.isValid() - && (persistent != d->selectionModel->currentIndex()) - && d->isIndexEnabled(persistent)) - d->selectionModel->setCurrentIndex(persistent, QItemSelectionModel::NoUpdate); + if (index.isValid() + && (index != d->selectionModel->currentIndex()) + && d->isIndexEnabled(index)) + d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate); } } @@ -1642,7 +1652,7 @@ void QAbstractItemView::mouseReleaseEvent(QMouseEvent *event) if (d->isIndexValid(index) && d->isIndexEnabled(index) && d->sendDelegateEvent(index, event)) - d->viewport->update(visualRect(index)); + update(index); return; } @@ -1651,9 +1661,6 @@ void QAbstractItemView::mouseReleaseEvent(QMouseEvent *event) EditTrigger trigger = (selectedClicked ? SelectedClicked : NoEditTriggers); bool edited = edit(index, trigger, event); - if (d->selectionModel) - d->selectionModel->select(index, selectionCommand(index, event)); - setState(NoState); if (click) { @@ -2003,15 +2010,18 @@ void QAbstractItemView::keyPressEvent(QKeyEvent *event) if (QApplication::keypadNavigationEnabled()) { if (!hasEditFocus()) { setEditFocus(true); + QActionToKeyEventMapper::addSoftKey(QAction::BackSoftKey, Qt::Key_Back, this); return; } } break; case Qt::Key_Back: - if (QApplication::keypadNavigationEnabled() && hasEditFocus()) + if (QApplication::keypadNavigationEnabled() && hasEditFocus()) { + QActionToKeyEventMapper::removeSoftkey(this); setEditFocus(false); - else + } else { event->ignore(); + } return; default: if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) { @@ -2165,11 +2175,12 @@ void QAbstractItemView::keyPressEvent(QKeyEvent *event) } #endif bool modified = (event->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier)); - if (!event->text().isEmpty() && !modified) { - if (!edit(currentIndex(), AnyKeyPressed, event)) - keyboardSearch(event->text()); + if (!event->text().isEmpty() && !modified && !edit(currentIndex(), AnyKeyPressed, event)) { + keyboardSearch(event->text()); + event->accept(); + } else { + event->ignore(); } - event->ignore(); break; } } } @@ -2195,6 +2206,8 @@ void QAbstractItemView::resizeEvent(QResizeEvent *event) void QAbstractItemView::timerEvent(QTimerEvent *event) { Q_D(QAbstractItemView); + if (event->timerId() == d->fetchMoreTimer.timerId()) + d->fetchMore(); if (event->timerId() == d->autoScrollTimer.timerId()) doAutoScroll(); else if (event->timerId() == d->updateTimer.timerId()) @@ -2250,8 +2263,8 @@ void QAbstractItemView::inputMethodEvent(QInputMethodEvent *event) \value BelowItem The item will be dropped below the index. \value OnViewport The item will be dropped onto a region of the viewport with -no items. The way each view handles items dropped onto the viewport depends on -the behavior of the underlying model in use. + no items. The way each view handles items dropped onto the viewport depends on + the behavior of the underlying model in use. */ @@ -2268,11 +2281,11 @@ QAbstractItemView::DropIndicatorPosition QAbstractItemView::dropIndicatorPositio #endif /*! - This convenience function returns a list of all selected and - non-hidden item indexes in the view. The list contains no - duplicates, and is not sorted. + This convenience function returns a list of all selected and + non-hidden item indexes in the view. The list contains no + duplicates, and is not sorted. - \sa QItemSelectionModel::selectedIndexes() + \sa QItemSelectionModel::selectedIndexes() */ QModelIndexList QAbstractItemView::selectedIndexes() const { @@ -2325,7 +2338,7 @@ bool QAbstractItemView::edit(const QModelIndex &index, EditTrigger trigger, QEve } if (d->sendDelegateEvent(index, event)) { - d->viewport->update(visualRect(index)); + update(index); return true; } @@ -2354,8 +2367,8 @@ bool QAbstractItemView::edit(const QModelIndex &index, EditTrigger trigger, QEve } /*! - \internal - Updates the data shown in the open editor widgets in the view. + \internal + Updates the data shown in the open editor widgets in the view. */ void QAbstractItemView::updateEditorData() { @@ -2364,8 +2377,8 @@ void QAbstractItemView::updateEditorData() } /*! - \internal - Updates the geometry of the open editor widgets in the view. + \internal + Updates the geometry of the open editor widgets in the view. */ void QAbstractItemView::updateEditorGeometries() { @@ -2397,8 +2410,8 @@ void QAbstractItemView::updateEditorGeometries() //we release the editor outside of the loop because it might change the focus and try //to change the d->editors list. - foreach(QWidget *editor, editorsToRelease) { - d->releaseEditor(editor); + for (int i = 0; i < editorsToRelease.count(); ++i) { + d->releaseEditor(editorsToRelease.at(i)); } } @@ -2410,27 +2423,29 @@ void QAbstractItemView::updateEditorGeometries() void QAbstractItemView::updateGeometries() { updateEditorGeometries(); - QMetaObject::invokeMethod(this, "_q_fetchMore", Qt::QueuedConnection); + d_func()->fetchMoreTimer.start(0, this); //fetch more later } /*! - \internal + \internal */ void QAbstractItemView::verticalScrollbarValueChanged(int value) { Q_D(QAbstractItemView); if (verticalScrollBar()->maximum() == value && d->model->canFetchMore(d->root)) d->model->fetchMore(d->root); + d->checkMouseMove(viewport()->mapFromGlobal(QCursor::pos())); } /*! - \internal + \internal */ void QAbstractItemView::horizontalScrollbarValueChanged(int value) { Q_D(QAbstractItemView); if (horizontalScrollBar()->maximum() == value && d->model->canFetchMore(d->root)) d->model->fetchMore(d->root); + d->checkMouseMove(viewport()->mapFromGlobal(QCursor::pos())); } /*! @@ -2525,9 +2540,9 @@ void QAbstractItemView::closeEditor(QWidget *editor, QAbstractItemDelegate::EndE } /*! - Commit the data in the \a editor to the model. + Commit the data in the \a editor to the model. - \sa closeEditor() + \sa closeEditor() */ void QAbstractItemView::commitData(QWidget *editor) { @@ -2546,9 +2561,9 @@ void QAbstractItemView::commitData(QWidget *editor) } /*! - This function is called when the given \a editor has been destroyed. + This function is called when the given \a editor has been destroyed. - \sa closeEditor() + \sa closeEditor() */ void QAbstractItemView::editorDestroyed(QObject *editor) { @@ -2619,12 +2634,12 @@ int QAbstractItemView::verticalStepsPerItem() const } /*! - Moves to and selects the item best matching the string \a search. - If no item is found nothing happens. + Moves to and selects the item best matching the string \a search. + If no item is found nothing happens. - In the default implementation, the search is reset if \a search is empty, or - the time interval since the last search has exceeded - QApplication::keyboardInputInterval(). + In the default implementation, the search is reset if \a search is empty, or + the time interval since the last search has exceeded + QApplication::keyboardInputInterval(). */ void QAbstractItemView::keyboardSearch(const QString &search) { @@ -2639,7 +2654,7 @@ void QAbstractItemView::keyboardSearch(const QString &search) if (search.isEmpty() || (d->keyboardInputTime.msecsTo(now) > QApplication::keyboardInputInterval())) { d->keyboardInput = search; - skipRow = true; + skipRow = currentIndex().isValid(); //if it is not valid we should really start at QModelIndex(0,0) } else { d->keyboardInput += search; } @@ -2679,9 +2694,9 @@ void QAbstractItemView::keyboardSearch(const QString &search) setCurrentIndex(firstMatch); break; } - int row = firstMatch.row() + 1; - if (row >= d->model->rowCount(firstMatch.parent())) - row = 0; + int row = firstMatch.row() + 1; + if (row >= d->model->rowCount(firstMatch.parent())) + row = 0; current = firstMatch.sibling(row, firstMatch.column()); //avoid infinite loop if all the matching items are disabled. @@ -2794,9 +2809,9 @@ void QAbstractItemView::openPersistentEditor(const QModelIndex &index) } /*! - Closes the persistent editor for the item at the given \a index. + Closes the persistent editor for the item at the given \a index. - \sa openPersistentEditor() + \sa openPersistentEditor() */ void QAbstractItemView::closePersistentEditor(const QModelIndex &index) { @@ -2851,9 +2866,9 @@ void QAbstractItemView::setIndexWidget(const QModelIndex &index, QWidget *widget d->persistent.insert(widget); d->addEditor(index, widget, true); widget->show(); + dataChanged(index, index); // update the geometry if (!d->delayedPendingLayout) widget->setGeometry(visualRect(index)); - dataChanged(index, index); // update the geometry } } @@ -2960,7 +2975,7 @@ void QAbstractItemView::dataChanged(const QModelIndex &topLeft, const QModelInde void QAbstractItemView::rowsInserted(const QModelIndex &, int, int) { if (!isVisible()) - QMetaObject::invokeMethod(this, "_q_fetchMore", Qt::QueuedConnection); + d_func()->fetchMoreTimer.start(0, this); //fetch more later else updateEditorGeometries(); } @@ -3144,9 +3159,7 @@ void QAbstractItemView::selectionChanged(const QItemSelection &selected, { Q_D(QAbstractItemView); if (isVisible() && updatesEnabled()) { - d->setDirtyRegion(visualRegionForSelection(deselected)); - d->setDirtyRegion(visualRegionForSelection(selected)); - d->updateDirtyRegion(); + d->viewport->update(visualRegionForSelection(deselected) | visualRegionForSelection(selected)); } } @@ -3174,19 +3187,18 @@ void QAbstractItemView::currentChanged(const QModelIndex ¤t, const QModelI closeEditor(editor, QAbstractItemDelegate::NoHint); } if (isVisible()) { - d->setDirtyRegion(visualRect(previous)); - d->updateDirtyRegion(); + update(previous); } } + if (current.isValid() && !d->autoScrollTimer.isActive()) { if (isVisible()) { if (d->autoScroll) scrollTo(current); - d->setDirtyRegion(visualRect(current)); - d->updateDirtyRegion(); + update(current); edit(current, CurrentChanged, 0); if (current.row() == (d->model->rowCount(d->root) - 1)) - d->_q_fetchMore(); + d->fetchMore(); } else { d->shouldScrollToCurrentOnShow = d->autoScroll; } @@ -3334,14 +3346,14 @@ void QAbstractItemView::setDirtyRegion(const QRegion ®ion) } /*! - Prepares the view for scrolling by (\a{dx},\a{dy}) pixels by moving the dirty regions in the - opposite direction. You only need to call this function if you are implementing a scrolling - viewport in your view subclass. + Prepares the view for scrolling by (\a{dx},\a{dy}) pixels by moving the dirty regions in the + opposite direction. You only need to call this function if you are implementing a scrolling + viewport in your view subclass. - If you implement scrollContentsBy() in a subclass of QAbstractItemView, call this function - before you call QWidget::scroll() on the viewport. Alternatively, just call update(). + If you implement scrollContentsBy() in a subclass of QAbstractItemView, call this function + before you call QWidget::scroll() on the viewport. Alternatively, just call update(). - \sa scrollContentsBy(), dirtyRegionOffset(), setDirtyRegion() + \sa scrollContentsBy(), dirtyRegionOffset(), setDirtyRegion() */ void QAbstractItemView::scrollDirtyRegion(int dx, int dy) { @@ -3350,13 +3362,13 @@ void QAbstractItemView::scrollDirtyRegion(int dx, int dy) } /*! - Returns the offset of the dirty regions in the view. + Returns the offset of the dirty regions in the view. - If you use scrollDirtyRegion() and implement a paintEvent() in a subclass of - QAbstractItemView, you should translate the area given by the paint event with - the offset returned from this function. + If you use scrollDirtyRegion() and implement a paintEvent() in a subclass of + QAbstractItemView, you should translate the area given by the paint event with + the offset returned from this function. - \sa scrollDirtyRegion(), setDirtyRegion() + \sa scrollDirtyRegion(), setDirtyRegion() */ QPoint QAbstractItemView::dirtyRegionOffset() const { @@ -3369,11 +3381,7 @@ QPoint QAbstractItemView::dirtyRegionOffset() const */ void QAbstractItemView::startAutoScroll() { - Q_D(QAbstractItemView); - // ### it would be nice to make this into a style hint one day - int scrollInterval = (verticalScrollMode() == QAbstractItemView::ScrollPerItem) ? 150 : 50; - d->autoScrollTimer.start(scrollInterval, this); - d->autoScrollCount = 0; + d_func()->startAutoScroll(); } /*! @@ -3381,9 +3389,7 @@ void QAbstractItemView::startAutoScroll() */ void QAbstractItemView::stopAutoScroll() { - Q_D(QAbstractItemView); - d->autoScrollTimer.stop(); - d->autoScrollCount = 0; + d_func()->stopAutoScroll(); } /*! @@ -3528,7 +3534,7 @@ QItemSelectionModel::SelectionFlags QAbstractItemViewPrivate::extendedSelectionC const bool shiftKeyPressed = modifiers & Qt::ShiftModifier; const bool controlKeyPressed = modifiers & Qt::ControlModifier; if (((index == pressedIndex && selectionModel->isSelected(index)) - || !index.isValid()) && state != QAbstractItemView::DragSelectingState + || !index.isValid()) && state != QAbstractItemView::DragSelectingState && !shiftKeyPressed && !controlKeyPressed && !rightButtonPressed) return QItemSelectionModel::ClearAndSelect|selectionBehaviorFlags(); return QItemSelectionModel::NoUpdate; @@ -3607,8 +3613,9 @@ QAbstractItemViewPrivate::contiguousSelectionCommand(const QModelIndex &index, } } -void QAbstractItemViewPrivate::_q_fetchMore() +void QAbstractItemViewPrivate::fetchMore() { + fetchMoreTimer.stop(); if (!model->canFetchMore(root)) return; int last = model->rowCount(root) - 1; @@ -3759,7 +3766,7 @@ void QAbstractItemViewPrivate::updateEditorData(const QModelIndex &tl, const QMo but the behavior is view dependant (table just clears the selected indexes for example). Either remove the selected rows or clear them - */ +*/ void QAbstractItemViewPrivate::clearOrRemove() { #ifndef QT_NO_DRAGANDDROP @@ -3795,11 +3802,11 @@ void QAbstractItemViewPrivate::clearOrRemove() When persistent aeditor gets/loses focus, we need to check and setcorrectly the current index. - */ +*/ void QAbstractItemViewPrivate::checkPersistentEditorFocus() { Q_Q(QAbstractItemView); - if (QWidget *widget = qApp->focusWidget()) { + if (QWidget *widget = QApplication::focusWidget()) { if (persistent.contains(widget)) { //a persistent editor has gained the focus QModelIndex index = indexForEditor(widget); @@ -3881,30 +3888,48 @@ bool QAbstractItemViewPrivate::openEditor(const QModelIndex &index, QEvent *even return true; } -QPixmap QAbstractItemViewPrivate::renderToPixmap(const QModelIndexList &indexes, QRect *r) const +/* + \internal + + returns the pair QRect/QModelIndex that should be painted on the viewports's rect +*/ + +QItemViewPaintPairs QAbstractItemViewPrivate::draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const { + Q_ASSERT(r); Q_Q(const QAbstractItemView); - QRect rect = q->visualRect(indexes.at(0)); - QList<QRect> rects; + QRect &rect = *r; + const QRect viewportRect = viewport->rect(); + QItemViewPaintPairs ret; for (int i = 0; i < indexes.count(); ++i) { - rects.append(q->visualRect(indexes.at(i))); - rect |= rects.at(i); + const QModelIndex &index = indexes.at(i); + const QRect current = q->visualRect(index); + if (current.intersects(viewportRect)) { + ret += qMakePair(current, index); + rect |= current; + } } - rect = rect.intersected(viewport->rect()); - if (rect.width() <= 0 || rect.height() <= 0) + rect &= viewportRect; + return ret; +} + +QPixmap QAbstractItemViewPrivate::renderToPixmap(const QModelIndexList &indexes, QRect *r) const +{ + Q_ASSERT(r); + QItemViewPaintPairs paintPairs = draggablePaintPairs(indexes, r); + if (paintPairs.isEmpty()) return QPixmap(); - QImage image(rect.size(), QImage::Format_ARGB32_Premultiplied); - image.fill(0); - QPainter painter(&image); + QPixmap pixmap(r->size()); + pixmap.fill(Qt::transparent); + QPainter painter(&pixmap); QStyleOptionViewItemV4 option = viewOptionsV4(); option.state |= QStyle::State_Selected; - for (int j = 0; j < indexes.count(); ++j) { - option.rect = QRect(rects.at(j).topLeft() - rect.topLeft(), rects.at(j).size()); - delegateForIndex(indexes.at(j))->paint(&painter, option, indexes.at(j)); + for (int j = 0; j < paintPairs.count(); ++j) { + option.rect = paintPairs.at(j).first.translated(-r->topLeft()); + const QModelIndex ¤t = paintPairs.at(j).second; + delegateForIndex(current)->paint(&painter, option, current); } - painter.end(); - if (r) *r = rect; - return QPixmap::fromImage(image); + return pixmap; } void QAbstractItemViewPrivate::selectAll(QItemSelectionModel::SelectionFlags command) diff --git a/src/gui/itemviews/qabstractitemview.h b/src/gui/itemviews/qabstractitemview.h index 0495d54..36c19e5 100644 --- a/src/gui/itemviews/qabstractitemview.h +++ b/src/gui/itemviews/qabstractitemview.h @@ -353,7 +353,6 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_rowsRemoved(const QModelIndex&, int, int)) Q_PRIVATE_SLOT(d_func(), void _q_modelDestroyed()) Q_PRIVATE_SLOT(d_func(), void _q_layoutChanged()) - Q_PRIVATE_SLOT(d_func(), void _q_fetchMore()) friend class QTreeViewPrivate; // needed to compile with MSVC friend class QAccessibleItemRow; diff --git a/src/gui/itemviews/qabstractitemview_p.h b/src/gui/itemviews/qabstractitemview_p.h index 7b28556..4517941 100644 --- a/src/gui/itemviews/qabstractitemview_p.h +++ b/src/gui/itemviews/qabstractitemview_p.h @@ -61,11 +61,10 @@ #include "QtGui/qmime.h" #include "QtGui/qpainter.h" #include "QtCore/qpair.h" -#include "QtCore/qtimer.h" -#include "QtCore/qtimeline.h" #include "QtGui/qregion.h" #include "QtCore/qdebug.h" #include "QtGui/qpainter.h" +#include "QtCore/qbasictimer.h" #ifndef QT_NO_ITEMVIEWS @@ -87,6 +86,9 @@ struct QEditorInfo }; +typedef QPair<QRect, QModelIndex> QItemViewPaintPair; +typedef QList<QItemViewPaintPair> QItemViewPaintPairs; + class QEmptyModel : public QAbstractItemModel { public: @@ -99,7 +101,7 @@ public: QVariant data(const QModelIndex &, int) const { return QVariant(); } }; -class Q_GUI_EXPORT QAbstractItemViewPrivate : public QAbstractScrollAreaPrivate +class Q_AUTOTEST_EXPORT QAbstractItemViewPrivate : public QAbstractScrollAreaPrivate { Q_DECLARE_PUBLIC(QAbstractItemView) @@ -109,13 +111,14 @@ public: void init(); - void _q_rowsRemoved(const QModelIndex &parent, int start, int end); - void _q_columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end); - void _q_columnsRemoved(const QModelIndex &parent, int start, int end); - void _q_columnsInserted(const QModelIndex &parent, int start, int end); - void _q_modelDestroyed(); - void _q_layoutChanged(); - void _q_fetchMore(); + virtual void _q_rowsRemoved(const QModelIndex &parent, int start, int end); + virtual void _q_columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end); + virtual void _q_columnsRemoved(const QModelIndex &parent, int start, int end); + virtual void _q_columnsInserted(const QModelIndex &parent, int start, int end); + virtual void _q_modelDestroyed(); + virtual void _q_layoutChanged(); + + void fetchMore(); bool shouldEdit(QAbstractItemView::EditTrigger trigger, const QModelIndex &index) const; bool shouldForwardEvent(QAbstractItemView::EditTrigger trigger, const QEvent *event) const; @@ -123,6 +126,15 @@ public: void doDelayedItemsLayout(int delay = 0); void interruptDelayedItemsLayout() const; + void startAutoScroll() + { // ### it would be nice to make this into a style hint one day + int scrollInterval = (verticalScrollMode == QAbstractItemView::ScrollPerItem) ? 150 : 50; + autoScrollTimer.start(scrollInterval, q_func()); + autoScrollCount = 0; + } + void stopAutoScroll() { autoScrollTimer.stop(); autoScrollCount = 0;} + + bool dropOn(QDropEvent *event, int *row, int *col, QModelIndex *index); bool droppingOnItself(QDropEvent *event, const QModelIndex &index); @@ -139,6 +151,9 @@ public: const QEvent *event) const; virtual void selectAll(QItemSelectionModel::SelectionFlags command); + void checkMouseMove(const QPersistentModelIndex &index); + inline void checkMouseMove(const QPoint &pos) { checkMouseMove(q_func()->indexAt(pos)); } + inline QItemSelectionModel::SelectionFlags selectionBehaviorFlags() const { switch (selectionBehavior) { @@ -173,7 +188,9 @@ public: q_func()->style()->drawPrimitive(QStyle::PE_IndicatorItemViewItemDrop, &opt, painter, q_func()); } } + #endif + virtual QItemViewPaintPairs draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const; inline void releaseEditor(QWidget *editor) const { if (editor) { @@ -218,7 +235,7 @@ public: void clearOrRemove(); void checkPersistentEditorFocus(); - QPixmap renderToPixmap(const QModelIndexList &indexes, QRect *r = 0) const; + QPixmap renderToPixmap(const QModelIndexList &indexes, QRect *r) const; inline QPoint offset() const { const Q_Q(QAbstractItemView); @@ -304,7 +321,7 @@ public: */ inline bool isPersistent(const QModelIndex &index) const { - return static_cast<QAbstractItemModelPrivate *>(model->d_ptr)->persistent.indexes.contains(index); + return static_cast<QAbstractItemModelPrivate *>(model->d_ptr.data())->persistent.indexes.contains(index); } QModelIndexList selectedDraggableIndexes() const; @@ -372,7 +389,6 @@ public: QBasicTimer updateTimer; QBasicTimer delayedEditing; QBasicTimer delayedAutoScroll; //used when an item is clicked - QTimeLine timeline; QAbstractItemView::ScrollMode verticalScrollMode; QAbstractItemView::ScrollMode horizontalScrollMode; @@ -384,6 +400,7 @@ public: private: mutable QBasicTimer delayedLayout; + mutable QBasicTimer fetchMoreTimer; }; QT_BEGIN_INCLUDE_NAMESPACE diff --git a/src/gui/itemviews/qcolumnview.cpp b/src/gui/itemviews/qcolumnview.cpp index ac31ecc..efd4879 100644 --- a/src/gui/itemviews/qcolumnview.cpp +++ b/src/gui/itemviews/qcolumnview.cpp @@ -52,7 +52,6 @@ #include <qscrollbar.h> #include <qpainter.h> #include <qdebug.h> -#include <qpainterpath.h> QT_BEGIN_NAMESPACE @@ -64,7 +63,7 @@ QT_BEGIN_NAMESPACE \brief The QColumnView class provides a model/view implementation of a column view. \ingroup model-view \ingroup advanced - \mainclass + QColumnView displays a model in a number of QListViews, one for each hierarchy in the tree. This is sometimes referred to as a cascading list. @@ -108,9 +107,13 @@ void QColumnViewPrivate::initialize() { Q_Q(QColumnView); q->setTextElideMode(Qt::ElideMiddle); - q->connect(¤tAnimation, SIGNAL(frameChanged(int)), - q->horizontalScrollBar(), SLOT(setValue(int))); - q->connect(¤tAnimation, SIGNAL(finished()), q, SLOT(_q_changeCurrentColumn())); +#ifndef QT_NO_ANIMATION + QObject::connect(¤tAnimation, SIGNAL(finished()), q, SLOT(_q_changeCurrentColumn())); + currentAnimation.setDuration(ANIMATION_DURATION_MSEC); + currentAnimation.setTargetObject(hbar); + currentAnimation.setPropertyName("value"); + currentAnimation.setEasingCurve(QEasingCurve::InOutQuad); +#endif //QT_NO_ANIMATION delete itemDelegate; q->setItemDelegate(new QColumnViewDelegate(q)); } @@ -260,10 +263,12 @@ void QColumnView::scrollTo(const QModelIndex &index, ScrollHint hint) if (!index.isValid() || d->columns.isEmpty()) return; - if (d->currentAnimation.state() == QTimeLine::Running) +#ifndef QT_NO_ANIMATION + if (d->currentAnimation.state() == QPropertyAnimation::Running) return; d->currentAnimation.stop(); +#endif //QT_NO_ANIMATION // Fill up what is needed to get to index d->closeColumns(index, true); @@ -326,22 +331,12 @@ void QColumnView::scrollTo(const QModelIndex &index, ScrollHint hint) } } - //horizontalScrollBar()->setValue(newScrollbarValue); - //d->_q_changeCurrentColumn(); - //return; - // or do the following currentAnimation - - int oldValue = horizontalScrollBar()->value(); - - if (oldValue < newScrollbarValue) { - d->currentAnimation.setFrameRange(oldValue, newScrollbarValue); - d->currentAnimation.setDirection(QTimeLine::Forward); - d->currentAnimation.setCurrentTime(0); - } else { - d->currentAnimation.setFrameRange(newScrollbarValue, oldValue); - d->currentAnimation.setDirection(QTimeLine::Backward); - } +#ifndef QT_NO_ANIMATION + d->currentAnimation.setEndValue(newScrollbarValue); d->currentAnimation.start(); +#else + horizontalScrollBar()->setValue(newScrollbarValue); +#endif //QT_NO_ANIMATION } /*! @@ -410,8 +405,10 @@ void QColumnView::resizeEvent(QResizeEvent *event) void QColumnViewPrivate::updateScrollbars() { Q_Q(QColumnView); - if (currentAnimation.state() == QTimeLine::Running) +#ifndef QT_NO_ANIMATION + if (currentAnimation.state() == QPropertyAnimation::Running) return; +#endif //QT_NO_ANIMATION // find the total horizontal length of the laid out columns int horizontalLength = 0; @@ -421,23 +418,23 @@ void QColumnViewPrivate::updateScrollbars() horizontalLength = (columns.first()->x() + columns.first()->width()) - columns.last()->x(); } - QSize viewportSize = q->viewport()->size(); - if (horizontalLength < viewportSize.width() && q->horizontalScrollBar()->value() == 0) { - q->horizontalScrollBar()->setRange(0, 0); + QSize viewportSize = viewport->size(); + if (horizontalLength < viewportSize.width() && hbar->value() == 0) { + hbar->setRange(0, 0); } else { int visibleLength = qMin(horizontalLength + q->horizontalOffset(), viewportSize.width()); int hiddenLength = horizontalLength - visibleLength; - if (hiddenLength != q->horizontalScrollBar()->maximum()) - q->horizontalScrollBar()->setRange(0, hiddenLength); + if (hiddenLength != hbar->maximum()) + hbar->setRange(0, hiddenLength); } if (!columns.isEmpty()) { int pageStepSize = columns.at(0)->width(); - if (pageStepSize != q->horizontalScrollBar()->pageStep()) - q->horizontalScrollBar()->setPageStep(pageStepSize); + if (pageStepSize != hbar->pageStep()) + hbar->setPageStep(pageStepSize); } - bool visible = (q->horizontalScrollBar()->maximum() > 0); - if (visible != q->horizontalScrollBar()->isVisible()) - q->horizontalScrollBar()->setVisible(visible); + bool visible = (hbar->maximum() > 0); + if (visible != hbar->isVisible()) + hbar->setVisible(visible); } /*! @@ -696,7 +693,7 @@ QAbstractItemView *QColumnViewPrivate::createColumn(const QModelIndex &index, bo q, SIGNAL(pressed(const QModelIndex &))); view->setFocusPolicy(Qt::NoFocus); - view->setParent(q->viewport()); + view->setParent(viewport); Q_ASSERT(view); // Setup corner grip @@ -707,13 +704,13 @@ QAbstractItemView *QColumnViewPrivate::createColumn(const QModelIndex &index, bo } if (columnSizes.count() > columns.count()) { - view->setGeometry(0, 0, columnSizes.at(columns.count()), q->viewport()->height()); + view->setGeometry(0, 0, columnSizes.at(columns.count()), viewport->height()); } else { int initialWidth = view->sizeHint().width(); if (q->isRightToLeft()) - view->setGeometry(q->viewport()->width() - initialWidth, 0, initialWidth, q->viewport()->height()); + view->setGeometry(viewport->width() - initialWidth, 0, initialWidth, viewport->height()); else - view->setGeometry(0, 0, initialWidth, q->viewport()->height()); + view->setGeometry(0, 0, initialWidth, viewport->height()); columnSizes.resize(qMax(columnSizes.count(), columns.count() + 1)); columnSizes[columns.count()] = initialWidth; } @@ -896,6 +893,15 @@ QList<int> QColumnView::columnWidths() const /*! \reimp */ +void QColumnView::rowsInserted(const QModelIndex &parent, int start, int end) +{ + QAbstractItemView::rowsInserted(parent, start, end); + d_func()->checkColumnCreation(parent); +} + +/*! + \reimp +*/ void QColumnView::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) { Q_D(QColumnView); @@ -1036,7 +1042,6 @@ QColumnViewPrivate::QColumnViewPrivate() : QAbstractItemViewPrivate() ,showResizeGrips(true) ,offset(0) -,currentAnimation(ANIMATION_DURATION_MSEC) ,previewWidget(0) ,previewColumn(0) { @@ -1048,6 +1053,41 @@ QColumnViewPrivate::~QColumnViewPrivate() /*! \internal + + */ +void QColumnViewPrivate::_q_columnsInserted(const QModelIndex &parent, int start, int end) +{ + QAbstractItemViewPrivate::_q_columnsInserted(parent, start, end); + checkColumnCreation(parent); +} + +/*! + \internal + + Makes sure we create a corresponding column as a result of changing the model. + + */ +void QColumnViewPrivate::checkColumnCreation(const QModelIndex &parent) +{ + if (parent == q_func()->currentIndex() && model->hasChildren(parent)) { + //the parent has children and is the current + //let's try to find out if there is already a mapping that is good + for (int i = 0; i < columns.count(); ++i) { + QAbstractItemView *view = columns.at(i); + if (view->rootIndex() == parent) { + if (view == previewColumn) { + //let's recreate the parent + closeColumns(parent, false); + createColumn(parent, true /*show*/); + } + break; + } + } + } +} + +/*! + \internal Place all of the columns where they belong inside of the viewport, resize as necessary. */ void QColumnViewPrivate::doLayout() @@ -1056,11 +1096,11 @@ void QColumnViewPrivate::doLayout() if (!model || columns.isEmpty()) return; - int viewportHeight = q->viewport()->height(); + int viewportHeight = viewport->height(); int x = columns.at(0)->x(); if (q->isRightToLeft()) { - x = q->viewport()->width() + q->horizontalOffset(); + x = viewport->width() + q->horizontalOffset(); for (int i = 0; i < columns.size(); ++i) { QAbstractItemView *view = columns.at(i); x -= view->width(); @@ -1116,7 +1156,7 @@ void QColumnViewDelegate::paint(QPainter *painter, // Draw > if (index.model()->hasChildren(index)) { const QWidget *view = opt.widget; - QStyle *style = view ? view->style() : qApp->style(); + QStyle *style = view ? view->style() : QApplication::style(); style->drawPrimitive(QStyle::PE_IndicatorColumnViewArrow, &opt, painter, view); } } diff --git a/src/gui/itemviews/qcolumnview.h b/src/gui/itemviews/qcolumnview.h index c5cfb3f..0d7880f 100644 --- a/src/gui/itemviews/qcolumnview.h +++ b/src/gui/itemviews/qcolumnview.h @@ -97,16 +97,14 @@ protected: QRegion visualRegionForSelection(const QItemSelection &selection) const; int horizontalOffset() const; int verticalOffset() const; - void scrollContentsBy(int dx, int dy); + void rowsInserted(const QModelIndex &parent, int start, int end); + void currentChanged(const QModelIndex ¤t, const QModelIndex &previous); // QColumnView functions + void scrollContentsBy(int dx, int dy); virtual QAbstractItemView* createColumn(const QModelIndex &rootIndex); void initializeColumn(QAbstractItemView *column) const; -protected Q_SLOTS: - // QAbstractItemView overloads - void currentChanged(const QModelIndex ¤t, const QModelIndex &previous); - private: Q_DECLARE_PRIVATE(QColumnView) Q_DISABLE_COPY(QColumnView) diff --git a/src/gui/itemviews/qcolumnview_p.h b/src/gui/itemviews/qcolumnview_p.h index 2d7c4f9..97def07 100644 --- a/src/gui/itemviews/qcolumnview_p.h +++ b/src/gui/itemviews/qcolumnview_p.h @@ -55,12 +55,12 @@ #include "qcolumnview.h" -#ifndef QT_NO_QCOlUMNVIEW +#ifndef QT_NO_QCOLUMNVIEW #include <private/qabstractitemview_p.h> #include <QtCore/qabstractitemmodel.h> -#include <QtCore/qtimeline.h> +#include <QtCore/qpropertyanimation.h> #include <QtGui/qabstractitemdelegate.h> #include <QtGui/qabstractitemview.h> #include <QtGui/qitemdelegate.h> @@ -148,16 +148,21 @@ public: void closeColumns(const QModelIndex &parent = QModelIndex(), bool build = false); void doLayout(); void setPreviewWidget(QWidget *widget); + void checkColumnCreation(const QModelIndex &parent); + void _q_gripMoved(int offset); void _q_changeCurrentColumn(); void _q_clicked(const QModelIndex &index); + void _q_columnsInserted(const QModelIndex &parent, int start, int end); QList<QAbstractItemView*> columns; QVector<int> columnSizes; // used during init and corner moving bool showResizeGrips; int offset; - QTimeLine currentAnimation; +#ifndef QT_NO_ANIMATION + QPropertyAnimation currentAnimation; +#endif QWidget *previewWidget; QAbstractItemView *previewColumn; }; diff --git a/src/gui/itemviews/qdirmodel.cpp b/src/gui/itemviews/qdirmodel.cpp index 01526af..a4dbf52 100644 --- a/src/gui/itemviews/qdirmodel.cpp +++ b/src/gui/itemviews/qdirmodel.cpp @@ -44,6 +44,7 @@ #ifndef QT_NO_DIRMODEL #include <qstack.h> #include <qfile.h> +#include <qfilesystemmodel.h> #include <qurl.h> #include <qmime.h> #include <qpair.h> @@ -871,8 +872,10 @@ QModelIndex QDirModel::index(const QString &path, int column) const return QModelIndex(); QString absolutePath = QDir(path).absolutePath(); -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) absolutePath = absolutePath.toLower(); +#endif +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) // On Windows, "filename......." and "filename" are equivalent if (absolutePath.endsWith(QLatin1Char('.'))) { int i; @@ -912,7 +915,10 @@ QModelIndex QDirModel::index(const QString &path, int column) const pathElements.pop_front(); if (childAppended) emit const_cast<QDirModel*>(this)->layoutChanged(); - } else if (pathElements.at(0).endsWith(QLatin1Char(':'))) { + } else +#endif +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) + if (pathElements.at(0).endsWith(QLatin1Char(':'))) { pathElements[0] += QLatin1Char('/'); } #else @@ -934,11 +940,9 @@ QModelIndex QDirModel::index(const QString &path, int column) const for (int j = parent->children.count() - 1; j >= 0; --j) { const QFileInfo& fi = parent->children.at(j).info; QString childFileName; -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) childFileName = idx.isValid() ? fi.fileName() : fi.absoluteFilePath(); +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) childFileName = childFileName.toLower(); -#else - childFileName = idx.isValid() ? fi.fileName() : fi.absoluteFilePath(); #endif if (childFileName == element) { if (i == pathElements.count() - 1) @@ -955,7 +959,7 @@ QModelIndex QDirModel::index(const QString &path, int column) const if (parent->info.isRoot()) newPath = parent->info.absoluteFilePath() + element; else - newPath= parent->info.absoluteFilePath() + QLatin1Char('/') + element; + newPath = parent->info.absoluteFilePath() + QLatin1Char('/') + element; #else QString newPath = parent->info.absoluteFilePath() + QLatin1Char('/') + element; #endif @@ -1307,6 +1311,8 @@ QString QDirModelPrivate::name(const QModelIndex &index) const #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) if (name.startsWith(QLatin1Char('/'))) // UNC host return info.fileName(); +#endif +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) if (name.endsWith(QLatin1Char('/'))) name.chop(1); #endif @@ -1338,14 +1344,14 @@ QString QDirModelPrivate::size(const QModelIndex &index) const const quint64 tb = 1024 * gb; quint64 bytes = n->info.size(); if (bytes >= tb) - return QLocale().toString(bytes / tb) + QString::fromLatin1(" TB"); + return QFileSystemModel::tr("%1 TB").arg(QLocale().toString(qreal(bytes) / tb, 'f', 3)); if (bytes >= gb) - return QLocale().toString(bytes / gb) + QString::fromLatin1(" GB"); + return QFileSystemModel::tr("%1 GB").arg(QLocale().toString(qreal(bytes) / gb, 'f', 2)); if (bytes >= mb) - return QLocale().toString(bytes / mb) + QString::fromLatin1(" MB"); + return QFileSystemModel::tr("%1 MB").arg(QLocale().toString(qreal(bytes) / mb, 'f', 1)); if (bytes >= kb) - return QLocale().toString(bytes / kb) + QString::fromLatin1(" KB"); - return QLocale().toString(bytes) + QString::fromLatin1(" bytes"); + return QFileSystemModel::tr("%1 KB").arg(QLocale().toString(bytes / kb)); + return QFileSystemModel::tr("%1 bytes").arg(QLocale().toString(bytes)); } QString QDirModelPrivate::type(const QModelIndex &index) const diff --git a/src/gui/itemviews/qfileiconprovider.cpp b/src/gui/itemviews/qfileiconprovider.cpp index 035055c..b1177db 100644 --- a/src/gui/itemviews/qfileiconprovider.cpp +++ b/src/gui/itemviews/qfileiconprovider.cpp @@ -48,15 +48,14 @@ #include <qpixmapcache.h> #if defined(Q_WS_WIN) #define _WIN32_IE 0x0500 +#include <qt_windows.h> +#include <commctrl.h> #include <objbase.h> #include <private/qpixmapdata_p.h> #elif defined(Q_WS_MAC) -#include <private/qt_mac_p.h> +#include <private/qt_cocoa_helpers_mac_p.h> #endif #include <private/qfunctions_p.h> -#ifdef Q_OS_WINCE -#include <Commctrl.h> -#endif #ifndef SHGFI_ADDOVERLAYS #define SHGFI_ADDOVERLAYS 0x000000020 @@ -180,7 +179,6 @@ QFileIconProvider::QFileIconProvider() QFileIconProvider::~QFileIconProvider() { - delete d_ptr; } /*! @@ -215,8 +213,7 @@ QIcon QFileIconProvider::icon(IconType type) const QIcon QFileIconProviderPrivate::getWinIcon(const QFileInfo &fileInfo) const { QIcon retIcon; - QString fileExtension = fileInfo.suffix().toUpper(); - fileExtension.prepend( QLatin1String(".") ); + const QString fileExtension = QLatin1Char('.') + fileInfo.suffix().toUpper(); QString key; if (fileInfo.isFile() && !fileInfo.isExecutable() && !fileInfo.isSymLink()) @@ -244,10 +241,10 @@ QIcon QFileIconProviderPrivate::getWinIcon(const QFileInfo &fileInfo) const //Get the small icon #ifndef Q_OS_WINCE - val = SHGetFileInfo((const WCHAR *)QDir::toNativeSeparators(fileInfo.filePath()).utf16(), 0, &info, + val = SHGetFileInfo((const wchar_t *)QDir::toNativeSeparators(fileInfo.filePath()).utf16(), 0, &info, sizeof(SHFILEINFO), SHGFI_ICON|SHGFI_SMALLICON|SHGFI_SYSICONINDEX|SHGFI_ADDOVERLAYS); #else - val = SHGetFileInfo((const WCHAR *)QDir::toNativeSeparators(fileInfo.filePath()).utf16(), 0, &info, + val = SHGetFileInfo((const wchar_t *)QDir::toNativeSeparators(fileInfo.filePath()).utf16(), 0, &info, sizeof(SHFILEINFO), SHGFI_SMALLICON|SHGFI_SYSICONINDEX); #endif if (val) { @@ -283,10 +280,10 @@ QIcon QFileIconProviderPrivate::getWinIcon(const QFileInfo &fileInfo) const //Get the big icon #ifndef Q_OS_WINCE - val = SHGetFileInfo((const WCHAR *)QDir::toNativeSeparators(fileInfo.filePath()).utf16(), 0, &info, + val = SHGetFileInfo((const wchar_t *)QDir::toNativeSeparators(fileInfo.filePath()).utf16(), 0, &info, sizeof(SHFILEINFO), SHGFI_ICON|SHGFI_LARGEICON|SHGFI_SYSICONINDEX|SHGFI_ADDOVERLAYS); #else - val = SHGetFileInfo((const WCHAR *)QDir::toNativeSeparators(fileInfo.filePath()).utf16(), 0, &info, + val = SHGetFileInfo((const wchar_t *)QDir::toNativeSeparators(fileInfo.filePath()).utf16(), 0, &info, sizeof(SHFILEINFO), SHGFI_LARGEICON|SHGFI_SYSICONINDEX); #endif if (val) { @@ -353,10 +350,11 @@ QIcon QFileIconProviderPrivate::getMacIcon(const QFileInfo &fi) const return retIcon; IconRef iconRef; SInt16 iconLabel; - status = GetIconRefFromFileInfo(&macRef, macName.length, macName.unicode, kIconServicesCatalogInfoMask, &info, kIconServicesNormalUsageFlag, &iconRef, &iconLabel); + status = GetIconRefFromFileInfo(&macRef, macName.length, macName.unicode, + kIconServicesCatalogInfoMask, &info, kIconServicesNormalUsageFlag, + &iconRef, &iconLabel); if (status != noErr) return retIcon; - extern void qt_mac_constructQIconFromIconRef(const IconRef, const IconRef, QIcon*, QStyle::StandardPixmap = QStyle::SP_CustomBase); // qmacstyle_mac.cpp qt_mac_constructQIconFromIconRef(iconRef, 0, &retIcon); ReleaseIconRef(iconRef); @@ -391,11 +389,9 @@ QIcon QFileIconProvider::icon(const QFileInfo &info) const return icon; #endif if (info.isRoot()) -#if defined (Q_WS_WIN) && !defined(Q_OS_WINCE) +#if defined (Q_WS_WIN) && !defined(Q_WS_WINCE) { - uint type = DRIVE_UNKNOWN; - QT_WA({ type = GetDriveTypeW((wchar_t *)info.absoluteFilePath().utf16()); }, - { type = GetDriveTypeA(info.absoluteFilePath().toLocal8Bit()); }); + UINT type = GetDriveType((wchar_t *)info.absoluteFilePath().utf16()); switch (type) { case DRIVE_REMOVABLE: @@ -451,26 +447,22 @@ QString QFileIconProvider::type(const QFileInfo &info) const } if (info.isDir()) - return QApplication::translate("QFileDialog", #ifdef Q_WS_WIN - "File Folder", "Match Windows Explorer" + return QApplication::translate("QFileDialog", "File Folder", "Match Windows Explorer"); #else - "Folder", "All other platforms" + return QApplication::translate("QFileDialog", "Folder", "All other platforms"); #endif - ); // Windows - "File Folder" // OS X - "Folder" // Konqueror - "Folder" // Nautilus - "folder" if (info.isSymLink()) - return QApplication::translate("QFileDialog", #ifdef Q_OS_MAC - "Alias", "Mac OS X Finder" + return QApplication::translate("QFileDialog", "Alias", "Mac OS X Finder"); #else - "Shortcut", "All other platforms" + return QApplication::translate("QFileDialog", "Shortcut", "All other platforms"); #endif - ); // OS X - "Alias" // Windows - "Shortcut" // Konqueror - "Folder" or "TXT File" i.e. what it is pointing to diff --git a/src/gui/itemviews/qfileiconprovider.h b/src/gui/itemviews/qfileiconprovider.h index a5a3891..cf1b34f 100644 --- a/src/gui/itemviews/qfileiconprovider.h +++ b/src/gui/itemviews/qfileiconprovider.h @@ -42,8 +42,9 @@ #ifndef QFILEICONPROVIDER_H #define QFILEICONPROVIDER_H -#include <QtGui/qicon.h> #include <QtCore/qfileinfo.h> +#include <QtCore/qscopedpointer.h> +#include <QtGui/qicon.h> QT_BEGIN_HEADER @@ -67,7 +68,7 @@ public: private: Q_DECLARE_PRIVATE(QFileIconProvider) - QFileIconProviderPrivate *d_ptr; + QScopedPointer<QFileIconProviderPrivate> d_ptr; Q_DISABLE_COPY(QFileIconProvider) }; diff --git a/src/gui/itemviews/qheaderview.cpp b/src/gui/itemviews/qheaderview.cpp index 3575ccb..a1c3e4e 100644 --- a/src/gui/itemviews/qheaderview.cpp +++ b/src/gui/itemviews/qheaderview.cpp @@ -62,9 +62,11 @@ #ifndef QT_NO_DATASTREAM #include <qdatastream.h> +#endif QT_BEGIN_NAMESPACE +#ifndef QT_NO_DATASTREAM QDataStream &operator<<(QDataStream &out, const QHeaderViewPrivate::SectionSpan &span) { span.write(out); @@ -76,7 +78,7 @@ QDataStream &operator>>(QDataStream &in, QHeaderViewPrivate::SectionSpan &span) span.read(in); return in; } -#endif +#endif // QT_NO_DATASTREAM /*! @@ -86,7 +88,7 @@ QDataStream &operator>>(QDataStream &in, QHeaderViewPrivate::SectionSpan &span) item views. \ingroup model-view - \mainclass + A QHeaderView displays the headers used in item views such as the QTableView and QTreeView classes. It takes the place of Qt3's \c QHeader @@ -520,31 +522,29 @@ int QHeaderView::length() const QSize QHeaderView::sizeHint() const { Q_D(const QHeaderView); - if (count() < 1) - return QSize(0, 0); if (d->cachedSizeHint.isValid()) return d->cachedSizeHint; - int width = 0; - int height = 0; + d->cachedSizeHint = QSize(0, 0); //reinitialize the cached size hint + const int sectionCount = count(); + // get size hint for the first n sections - int c = qMin(count(), 100); - for (int i = 0; i < c; ++i) { + int i = 0; + for (int checked = 0; checked < 100 && i < sectionCount; ++i) { if (isSectionHidden(i)) continue; + checked++; QSize hint = sectionSizeFromContents(i); - width = qMax(hint.width(), width); - height = qMax(hint.height(), height); + d->cachedSizeHint = d->cachedSizeHint.expandedTo(hint); } // get size hint for the last n sections - c = qMax(count() - 100, c); - for (int j = count() - 1; j >= c; --j) { + i = qMax(i, sectionCount - 100 ); + for (int j = sectionCount - 1, checked = 0; j >= i && checked < 100; --j) { if (isSectionHidden(j)) continue; + checked++; QSize hint = sectionSizeFromContents(j); - width = qMax(hint.width(), width); - height = qMax(hint.height(), height); + d->cachedSizeHint = d->cachedSizeHint.expandedTo(hint); } - d->cachedSizeHint = QSize(width, height); return d->cachedSizeHint; } @@ -1151,7 +1151,8 @@ void QHeaderView::setResizeMode(ResizeMode mode) \overload Sets the constraints on how the section specified by \a logicalIndex in - the header can be resized to those described by the given \a mode. + the header can be resized to those described by the given \a mode. The logical + index should exist at the time this function is called. \note This setting will be ignored for the last section if the stretchLastSection property is set to true. This is the default for the horizontal headers provided @@ -1194,8 +1195,9 @@ QHeaderView::ResizeMode QHeaderView::resizeMode(int logicalIndex) const { Q_D(const QHeaderView); int visual = visualIndex(logicalIndex); - Q_ASSERT(visual != -1); - return d->visualIndexResizeMode(visual); + if (visual == -1) + return Fixed; //the default value + return d->headerSectionResizeMode(visual); } /*! @@ -1234,7 +1236,7 @@ void QHeaderView::setSortIndicatorShown(bool show) if (sortIndicatorSection() < 0 || sortIndicatorSection() > count()) return; - if (d->visualIndexResizeMode(sortIndicatorSection()) == ResizeToContents) + if (d->headerSectionResizeMode(sortIndicatorSection()) == ResizeToContents) resizeSections(); d->viewport->update(); @@ -1535,7 +1537,7 @@ bool QHeaderView::restoreState(const QByteArray &state) } return false; } -#endif +#endif // QT_NO_DATASTREAM /*! \reimp @@ -1969,20 +1971,19 @@ void QHeaderView::currentChanged(const QModelIndex ¤t, const QModelIndex & if (d->orientation == Qt::Horizontal && current.column() != old.column()) { if (old.isValid() && old.parent() == d->root) - d->setDirtyRegion(QRect(sectionViewportPosition(old.column()), 0, + d->viewport->update(QRect(sectionViewportPosition(old.column()), 0, sectionSize(old.column()), d->viewport->height())); if (current.isValid() && current.parent() == d->root) - d->setDirtyRegion(QRect(sectionViewportPosition(current.column()), 0, + d->viewport->update(QRect(sectionViewportPosition(current.column()), 0, sectionSize(current.column()), d->viewport->height())); } else if (d->orientation == Qt::Vertical && current.row() != old.row()) { if (old.isValid() && old.parent() == d->root) - d->setDirtyRegion(QRect(0, sectionViewportPosition(old.row()), + d->viewport->update(QRect(0, sectionViewportPosition(old.row()), d->viewport->width(), sectionSize(old.row()))); if (current.isValid() && current.parent() == d->root) - d->setDirtyRegion(QRect(0, sectionViewportPosition(current.row()), + d->viewport->update(QRect(0, sectionViewportPosition(current.row()), d->viewport->width(), sectionSize(current.row()))); } - d->updateDirtyRegion(); } @@ -2538,7 +2539,7 @@ QSize QHeaderView::sectionSizeFromContents(int logicalIndex) const if (opt.icon.isNull()) opt.icon = qvariant_cast<QPixmap>(variant); QSize size = style()->sizeFromContents(QStyle::CT_HeaderSection, &opt, QSize(), this); - if (isSortIndicatorShown() && sortIndicatorSection() == logicalIndex) { + if (isSortIndicatorShown()) { int margin = style()->pixelMetric(QStyle::PM_HeaderMargin, &opt, this); if (d->orientation == Qt::Horizontal) size.rwidth() += size.height() + margin; @@ -2615,7 +2616,7 @@ void QHeaderView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bot int first = orientation() == Qt::Horizontal ? topLeft.column() : topLeft.row(); int last = orientation() == Qt::Horizontal ? bottomRight.column() : bottomRight.row(); for (int i = first; i <= last && !resizeRequired; ++i) - resizeRequired = (resizeRequired && resizeMode(i)); + resizeRequired = (resizeMode(i) == ResizeToContents); if (resizeRequired) d->doDelayedResizeSections(); } @@ -2821,16 +2822,12 @@ void QHeaderViewPrivate::setupSectionIndicator(int section, int position) sectionIndicator = new QLabel(viewport); } - int x, y, w, h; + int w, h; int p = q->sectionViewportPosition(section); if (orientation == Qt::Horizontal) { - x = p; - y = 0; w = q->sectionSize(section); h = viewport->height(); } else { - x = 0; - y = p; w = viewport->width(); h = q->sectionSize(section); } @@ -2936,22 +2933,25 @@ int QHeaderViewPrivate::lastVisibleVisualIndex() const void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool useGlobalMode) { Q_Q(QHeaderView); + //stop the timer in case it is delayed + delayedResize.stop(); executePostedLayout(); if (sectionCount == 0) return; + + if (resizeRecursionBlock) + return; + resizeRecursionBlock = true; + invalidateCachedSizeHint(); + const int lastVisibleSection = lastVisibleVisualIndex(); + // find stretchLastSection if we have it int stretchSection = -1; - if (stretchLastSection && !useGlobalMode) { - for (int i = sectionCount - 1; i >= 0; --i) { - if (!isVisualIndexHidden(i)) { - stretchSection = i; - break; - } - } - } + if (stretchLastSection && !useGlobalMode) + stretchSection = lastVisibleVisualIndex(); // count up the number of strected sections and how much space left for them int lengthToStrech = (orientation == Qt::Horizontal ? viewport->width() : viewport->height()); @@ -2965,7 +2965,7 @@ void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool if (useGlobalMode && (i != stretchSection)) resizeMode = globalMode; else - resizeMode = (i == stretchSection ? QHeaderView::Stretch : visualIndexResizeMode(i)); + resizeMode = (i == stretchSection ? QHeaderView::Stretch : headerSectionResizeMode(i)); if (resizeMode == QHeaderView::Stretch) { ++numberOfStretchedSections; @@ -2997,7 +2997,6 @@ void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool int spanStartSection = 0; int previousSectionLength = 0; - const int lastVisibleSection = lastVisibleVisualIndex(); QHeaderView::ResizeMode previousSectionResizeMode = QHeaderView::Interactive; @@ -3016,7 +3015,7 @@ void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool else resizeMode = (i == stretchSection ? QHeaderView::Stretch - : visualIndexResizeMode(i)); + : newSectionResizeMode); if (resizeMode == QHeaderView::Stretch && stretchSectionLength != -1) { if (i == lastVisibleSection) newSectionLength = qMax(stretchSectionLength, lastSectionSize); @@ -3053,7 +3052,7 @@ void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool (sectionCount - spanStartSection) * previousSectionLength, previousSectionResizeMode); //Q_ASSERT(headerLength() == length); - + resizeRecursionBlock = false; viewport->update(); } @@ -3470,11 +3469,10 @@ void QHeaderViewPrivate::setGlobalHeaderResizeMode(QHeaderView::ResizeMode mode) int QHeaderViewPrivate::viewSectionSizeHint(int logical) const { - Q_Q(const QHeaderView); - if (QAbstractItemView *parent = qobject_cast<QAbstractItemView*>(q->parent())) { + if (QAbstractItemView *view = qobject_cast<QAbstractItemView*>(parent)) { return (orientation == Qt::Horizontal - ? parent->sizeHintForColumn(logical) - : parent->sizeHintForRow(logical)); + ? view->sizeHintForColumn(logical) + : view->sizeHintForRow(logical)); } return 0; } @@ -3560,7 +3558,7 @@ bool QHeaderViewPrivate::read(QDataStream &in) in >> minimumSectionSize; in >> align; - defaultAlignment = (Qt::Alignment)align; + defaultAlignment = Qt::Alignment(align); in >> global; globalResizeMode = (QHeaderView::ResizeMode)global; @@ -3570,9 +3568,9 @@ bool QHeaderViewPrivate::read(QDataStream &in) return true; } -QT_END_NAMESPACE +#endif // QT_NO_DATASTREAM -#endif // QT_NO_DATASTREAEM +QT_END_NAMESPACE #endif // QT_NO_ITEMVIEWS diff --git a/src/gui/itemviews/qheaderview.h b/src/gui/itemviews/qheaderview.h index e2510ae..ff1c7ef 100644 --- a/src/gui/itemviews/qheaderview.h +++ b/src/gui/itemviews/qheaderview.h @@ -221,14 +221,13 @@ protected: bool isIndexHidden(const QModelIndex &index) const; QModelIndex moveCursor(CursorAction, Qt::KeyboardModifiers); - void setSelection(const QRect&, QItemSelectionModel::SelectionFlags); + void setSelection(const QRect& rect, QItemSelectionModel::SelectionFlags flags); QRegion visualRegionForSelection(const QItemSelection &selection) const; void initStyleOption(QStyleOptionHeader *option) const; private: Q_PRIVATE_SLOT(d_func(), void _q_sectionsRemoved(const QModelIndex &parent, int logicalFirst, int logicalLast)) Q_PRIVATE_SLOT(d_func(), void _q_layoutAboutToBeChanged()) - Q_PRIVATE_SLOT(d_func(), void _q_layoutChanged()) Q_DECLARE_PRIVATE(QHeaderView) Q_DISABLE_COPY(QHeaderView) }; diff --git a/src/gui/itemviews/qheaderview_p.h b/src/gui/itemviews/qheaderview_p.h index 35d1ad3..dc4b3de 100644 --- a/src/gui/itemviews/qheaderview_p.h +++ b/src/gui/itemviews/qheaderview_p.h @@ -90,6 +90,7 @@ public: highlightSelected(false), stretchLastSection(false), cascadingResizing(false), + resizeRecursionBlock(false), stretchSections(0), contentsSections(0), minimumSectionSize(-1), @@ -169,10 +170,6 @@ public: if (!sectionHidden.isEmpty()) sectionHidden.setBit(visual, hidden); } - inline QHeaderView::ResizeMode visualIndexResizeMode(int visual) const { - return headerSectionResizeMode(visual); - } - inline bool hasAutoResizeSections() const { return stretchSections || stretchLastSection || contentsSections; } @@ -210,7 +207,7 @@ public: } inline bool sectionIsCascadable(int visual) const { - return visualIndexResizeMode(visual) == QHeaderView::Interactive; + return headerSectionResizeMode(visual) == QHeaderView::Interactive; } inline int modelSectionCount() const { @@ -230,7 +227,6 @@ public: inline void executePostedResize() const { if (delayedResize.isActive() && state == NoState) { - delayedResize.stop(); const_cast<QHeaderView*>(q_func())->resizeSections(); } } @@ -274,6 +270,7 @@ public: bool highlightSelected; bool stretchLastSection; bool cascadingResizing; + bool resizeRecursionBlock; int stretchSections; int contentsSections; int defaultSectionSize; diff --git a/src/gui/itemviews/qitemdelegate.cpp b/src/gui/itemviews/qitemdelegate.cpp index 94d3fce..84585dd 100644 --- a/src/gui/itemviews/qitemdelegate.cpp +++ b/src/gui/itemviews/qitemdelegate.cpp @@ -185,7 +185,7 @@ QSizeF QItemDelegatePrivate::doTextLayout(int lineWidth) const data items from a model. \ingroup model-view - \mainclass + QItemDelegate can be used to provide custom display features and editor widgets for item views based on QAbstractItemView subclasses. Using a @@ -352,7 +352,10 @@ void QItemDelegate::setClipping(bool clip) QString QItemDelegatePrivate::valueToText(const QVariant &value, const QStyleOptionViewItemV4 &option) { QString text; - switch (value.type()) { + switch (value.userType()) { + case QMetaType::Float: + text = option.locale.toString(value.toFloat(), 'g'); + break; case QVariant::Double: text = option.locale.toString(value.toDouble(), 'g', DBL_DIG); break; @@ -719,8 +722,6 @@ void QItemDelegate::drawDisplay(QPainter *painter, const QStyleOptionViewItem &o //let's add the last line (after the last QChar::LineSeparator) elided += option.fontMetrics.elidedText(text.mid(start), option.textElideMode, textRect.width()); - if (end != -1) - elided += QChar::LineSeparator; } d->textLayout.setText(elided); textLayoutSize = d->doTextLayout(textRect.width()); @@ -861,6 +862,8 @@ void QItemDelegate::drawBackground(QPainter *painter, /*! \internal + + Code duplicated in QCommonStylePrivate::viewItemLayout */ void QItemDelegate::doLayout(const QStyleOptionViewItem &option, @@ -882,8 +885,10 @@ void QItemDelegate::doLayout(const QStyleOptionViewItem &option, int w, h; textRect->adjust(-textMargin, 0, textMargin, 0); // add width padding - if (textRect->height() == 0 && !hasPixmap) + if (textRect->height() == 0 && (!hasPixmap || !hint)) { + //if there is no text, we still want to have a decent height for the item sizeHint and the editor size textRect->setHeight(option.fontMetrics.height()); + } QSize pm(0, 0); if (hasPixmap) { @@ -1219,7 +1224,7 @@ bool QItemDelegate::eventFilter(QObject *object, QEvent *event) if (editor->parentWidget()) editor->parentWidget()->setFocus(); return true; - } else if (event->type() == QEvent::FocusOut || event->type() == QEvent::Hide) { + } else if (event->type() == QEvent::FocusOut || (event->type() == QEvent::Hide && editor->isWindow())) { //the Hide event will take care of he editors that are in fact complete dialogs if (!editor->isActiveWindow() || (QApplication::focusWidget() != editor)) { QWidget *w = QApplication::focusWidget(); @@ -1234,12 +1239,7 @@ bool QItemDelegate::eventFilter(QObject *object, QEvent *event) if (QDragManager::self() && QDragManager::self()->object != 0) return false; #endif - // Opening a modal dialog will start a new eventloop - // that will process the deleteLater event. - if (QApplication::activeModalWidget() - && !QApplication::activeModalWidget()->isAncestorOf(editor) - && qobject_cast<QDialog*>(QApplication::activeModalWidget())) - return false; + emit commitData(editor); emit closeEditor(editor, NoHint); } @@ -1297,8 +1297,14 @@ bool QItemDelegate::editorEvent(QEvent *event, return false; } - Qt::CheckState state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked + Qt::CheckState state; + if ( flags & Qt::ItemIsTristate ) { + state = static_cast<Qt::CheckState>( (value.toInt() + 1) % 3 ); + } else { + state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked ? Qt::Unchecked : Qt::Checked); + } + return model->setData(index, state, Qt::CheckStateRole); } @@ -1321,7 +1327,7 @@ QStyleOptionViewItem QItemDelegate::setOptions(const QModelIndex &index, // set text alignment value = index.data(Qt::TextAlignmentRole); if (value.isValid()) - opt.displayAlignment = (Qt::Alignment)value.toInt(); + opt.displayAlignment = Qt::Alignment(value.toInt()); // set foreground brush value = index.data(Qt::ForegroundRole); diff --git a/src/gui/itemviews/qitemselectionmodel.cpp b/src/gui/itemviews/qitemselectionmodel.cpp index b57a0e9..8369db7 100644 --- a/src/gui/itemviews/qitemselectionmodel.cpp +++ b/src/gui/itemviews/qitemselectionmodel.cpp @@ -270,67 +270,77 @@ QItemSelectionRange QItemSelectionRange::intersect(const QItemSelectionRange &ot */ -/*! - Returns the list of model index items stored in the selection. -*/ +/* + \internal -QModelIndexList QItemSelectionRange::indexes() const + utility function for getting the indexes from a range + it avoid concatenating list and works on one + */ + +static void indexesFromRange(const QItemSelectionRange &range, QModelIndexList &result) { - QModelIndex index; - QModelIndexList result; - if (isValid() && model()) { - for (int column = left(); column <= right(); ++column) { - for (int row = top(); row <= bottom(); ++row) { - index = model()->index(row, column, parent()); - Qt::ItemFlags flags = model()->flags(index); + if (range.isValid() && range.model()) { + for (int column = range.left(); column <= range.right(); ++column) { + for (int row = range.top(); row <= range.bottom(); ++row) { + QModelIndex index = range.model()->index(row, column, range.parent()); + Qt::ItemFlags flags = range.model()->flags(index); if ((flags & Qt::ItemIsSelectable) && (flags & Qt::ItemIsEnabled)) result.append(index); } } } - return result; } /*! - \class QItemSelection + Returns the list of model index items stored in the selection. +*/ - \brief The QItemSelection class manages information about selected items in a model. +QModelIndexList QItemSelectionRange::indexes() const +{ + QModelIndexList result; + indexesFromRange(*this, result); + return result; +} - \ingroup model-view +/*! + \class QItemSelection - A QItemSelection describes the items in a model that have been - selected by the user. A QItemSelection is basically a list of - selection ranges, see QItemSelectionRange. It provides functions for - creating and manipulating selections, and selecting a range of items - from a model. + \brief The QItemSelection class manages information about selected items in a model. - The QItemSelection class is one of the \l{Model/View Classes} - and is part of Qt's \l{Model/View Programming}{model/view framework}. + \ingroup model-view - An item selection can be constructed and initialized to contain a - range of items from an existing model. The following example constructs - a selection that contains a range of items from the given \c model, - beginning at the \c topLeft, and ending at the \c bottomRight. + A QItemSelection describes the items in a model that have been + selected by the user. A QItemSelection is basically a list of + selection ranges, see QItemSelectionRange. It provides functions for + creating and manipulating selections, and selecting a range of items + from a model. - \snippet doc/src/snippets/code/src_gui_itemviews_qitemselectionmodel.cpp 0 + The QItemSelection class is one of the \l{Model/View Classes} + and is part of Qt's \l{Model/View Programming}{model/view framework}. - An empty item selection can be constructed, and later populated as - required. So, if the model is going to be unavailable when we construct - the item selection, we can rewrite the above code in the following way: + An item selection can be constructed and initialized to contain a + range of items from an existing model. The following example constructs + a selection that contains a range of items from the given \c model, + beginning at the \c topLeft, and ending at the \c bottomRight. - \snippet doc/src/snippets/code/src_gui_itemviews_qitemselectionmodel.cpp 1 + \snippet doc/src/snippets/code/src_gui_itemviews_qitemselectionmodel.cpp 0 - QItemSelection saves memory, and avoids unnecessary work, by working with - selection ranges rather than recording the model item index for each - item in the selection. Generally, an instance of this class will contain - a list of non-overlapping selection ranges. + An empty item selection can be constructed, and later populated as + required. So, if the model is going to be unavailable when we construct + the item selection, we can rewrite the above code in the following way: - Use merge() to merge one item selection into another without making - overlapping ranges. Use split() to split one selection range into - smaller ranges based on a another selection range. + \snippet doc/src/snippets/code/src_gui_itemviews_qitemselectionmodel.cpp 1 - \sa {Model/View Programming}, QItemSelectionModel + QItemSelection saves memory, and avoids unnecessary work, by working with + selection ranges rather than recording the model item index for each + item in the selection. Generally, an instance of this class will contain + a list of non-overlapping selection ranges. + Use merge() to merge one item selection into another without making + overlapping ranges. Use split() to split one selection range into + smaller ranges based on a another selection range. + + \sa {Model/View Programming}, QItemSelectionModel */ /*! @@ -404,19 +414,19 @@ QModelIndexList QItemSelection::indexes() const QModelIndexList result; QList<QItemSelectionRange>::const_iterator it = begin(); for (; it != end(); ++it) - result += (*it).indexes(); + indexesFromRange(*it, result); return result; } /*! - Merges the \a other selection with this QItemSelection using the - \a command given. This method guarantees that no ranges are overlapping. + Merges the \a other selection with this QItemSelection using the + \a command given. This method guarantees that no ranges are overlapping. - Note that only QItemSelectionModel::Select, - QItemSelectionModel::Deselect, and QItemSelectionModel::Toggle are - supported. + Note that only QItemSelectionModel::Select, + QItemSelectionModel::Deselect, and QItemSelectionModel::Toggle are + supported. - \sa split() + \sa split() */ void QItemSelection::merge(const QItemSelection &other, QItemSelectionModel::SelectionFlags command) { @@ -468,10 +478,10 @@ void QItemSelection::merge(const QItemSelection &other, QItemSelectionModel::Sel } /*! - Splits the selection \a range using the selection \a other range. - Removes all items in \a other from \a range and puts the result in \a result. - This can be compared with the semantics of the \e subtract operation of a set. - \sa merge() + Splits the selection \a range using the selection \a other range. + Removes all items in \a other from \a range and puts the result in \a result. + This can be compared with the semantics of the \e subtract operation of a set. + \sa merge() */ void QItemSelection::split(const QItemSelectionRange &range, @@ -518,11 +528,11 @@ void QItemSelection::split(const QItemSelectionRange &range, } /*! - \internal + \internal - returns a QItemSelection where all ranges have been expanded to: - Rows: left: 0 and right: columnCount()-1 - Columns: top: 0 and bottom: rowCount()-1 + returns a QItemSelection where all ranges have been expanded to: + Rows: left: 0 and right: columnCount()-1 + Columns: top: 0 and bottom: rowCount()-1 */ QItemSelection QItemSelectionModelPrivate::expandSelection(const QItemSelection &selection, @@ -557,12 +567,13 @@ QItemSelection QItemSelectionModelPrivate::expandSelection(const QItemSelection } /*! - \internal + \internal */ void QItemSelectionModelPrivate::_q_rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { Q_Q(QItemSelectionModel); + finalize(); // update current index if (currentIndex.isValid() && parent == currentIndex.parent() @@ -580,15 +591,46 @@ void QItemSelectionModelPrivate::_q_rowsAboutToBeRemoved(const QModelIndex &pare emit q->currentColumnChanged(currentIndex, old); } - // update selectionsx - QModelIndex tl = model->index(start, 0, parent); - QModelIndex br = model->index(end, model->columnCount(parent) - 1, parent); - q->select(QItemSelection(tl, br), QItemSelectionModel::Deselect); - finalize(); + QItemSelection deselected; + QItemSelection::iterator it = ranges.begin(); + while (it != ranges.end()) { + if (it->topLeft().parent() != parent) { // Check parents until reaching root or contained in range + QModelIndex itParent = it->topLeft().parent(); + while (itParent.isValid() && itParent.parent() != parent) + itParent = itParent.parent(); + + if (parent.isValid() && start <= itParent.row() && itParent.row() <= end) { + deselected.append(*it); + it = ranges.erase(it); + } else { + ++it; + } + } else if (start <= it->bottom() && it->bottom() <= end // Full inclusion + && start <= it->top() && it->top() <= end) { + deselected.append(*it); + it = ranges.erase(it); + } else if (start <= it->top() && it->top() <= end) { // Top intersection + deselected.append(QItemSelectionRange(it->topLeft(), model->index(end, it->left(), it->parent()))); + *it = QItemSelectionRange(model->index(end + 1, it->left(), it->parent()), it->bottomRight()); + ++it; + } else if (start <= it->bottom() && it->bottom() <= end) { // Bottom intersection + deselected.append(QItemSelectionRange(model->index(start, it->right(), it->parent()), it->bottomRight())); + *it = QItemSelectionRange(it->topLeft(), model->index(start - 1, it->right(), it->parent())); + ++it; + } else { + if (it->top() < start && end < it->bottom()) // Middle intersection (do nothing) + deselected.append(QItemSelectionRange(model->index(start, it->right(), it->parent()), + model->index(end, it->left(), it->parent()))); + ++it; + } + } + + if (!deselected.isEmpty()) + emit q->selectionChanged(QItemSelection(), deselected); } /*! - \internal + \internal */ void QItemSelectionModelPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end) @@ -619,9 +661,9 @@ void QItemSelectionModelPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &p } /*! - \internal + \internal - Split selection ranges if columns are about to be inserted in the middle. + Split selection ranges if columns are about to be inserted in the middle. */ void QItemSelectionModelPrivate::_q_columnsAboutToBeInserted(const QModelIndex &parent, int start, int end) @@ -648,9 +690,9 @@ void QItemSelectionModelPrivate::_q_columnsAboutToBeInserted(const QModelIndex & } /*! - \internal + \internal - Split selection ranges if rows are about to be inserted in the middle. + Split selection ranges if rows are about to be inserted in the middle. */ void QItemSelectionModelPrivate::_q_rowsAboutToBeInserted(const QModelIndex &parent, int start, int end) @@ -677,11 +719,11 @@ void QItemSelectionModelPrivate::_q_rowsAboutToBeInserted(const QModelIndex &par } /*! - \internal + \internal - Split selection into individual (persistent) indexes. This is done in - preparation for the layoutChanged() signal, where the indexes can be - merged again. + Split selection into individual (persistent) indexes. This is done in + preparation for the layoutChanged() signal, where the indexes can be + merged again. */ void QItemSelectionModelPrivate::_q_layoutAboutToBeChanged() { @@ -692,14 +734,15 @@ void QItemSelectionModelPrivate::_q_layoutAboutToBeChanged() if (ranges.isEmpty() && currentSelection.count() == 1) { QItemSelectionRange range = currentSelection.first(); QModelIndex parent = range.parent(); - if (range.top() == 0 + tableRowCount = model->rowCount(parent); + tableColCount = model->columnCount(parent); + if (tableRowCount * tableColCount > 100 + && range.top() == 0 && range.left() == 0 - && range.bottom() == model->rowCount(parent) - 1 - && range.right() == model->columnCount(parent) - 1) { + && range.bottom() == tableRowCount - 1 + && range.right() == tableColCount - 1) { tableSelected = true; tableParent = parent; - tableColCount = model->columnCount(parent); - tableRowCount = model->rowCount(parent); return; } } @@ -715,10 +758,10 @@ void QItemSelectionModelPrivate::_q_layoutAboutToBeChanged() } /*! - \internal + \internal - Merges \a indexes into an item selection made up of ranges. - Assumes that the indexes are sorted. + Merges \a indexes into an item selection made up of ranges. + Assumes that the indexes are sorted. */ static QItemSelection mergeIndexes(const QList<QPersistentModelIndex> &indexes) { @@ -763,9 +806,9 @@ static QItemSelection mergeIndexes(const QList<QPersistentModelIndex> &indexes) } /*! - \internal + \internal - Merge the selected indexes into selection ranges again. + Merge the selected indexes into selection ranges again. */ void QItemSelectionModelPrivate::_q_layoutChanged() { @@ -807,41 +850,41 @@ void QItemSelectionModelPrivate::_q_layoutChanged() } /*! - \class QItemSelectionModel + \class QItemSelectionModel - \brief The QItemSelectionModel class keeps track of a view's selected items. + \brief The QItemSelectionModel class keeps track of a view's selected items. - \ingroup model-view + \ingroup model-view - A QItemSelectionModel keeps track of the selected items in a view, or - in several views onto the same model. It also keeps track of the - currently selected item in a view. + A QItemSelectionModel keeps track of the selected items in a view, or + in several views onto the same model. It also keeps track of the + currently selected item in a view. - The QItemSelectionModel class is one of the \l{Model/View Classes} - and is part of Qt's \l{Model/View Programming}{model/view framework}. + The QItemSelectionModel class is one of the \l{Model/View Classes} + and is part of Qt's \l{Model/View Programming}{model/view framework}. - The selected items are stored using ranges. Whenever you want to - modify the selected items use select() and provide either a - QItemSelection, or a QModelIndex and a QItemSelectionModel::SelectionFlag. + The selected items are stored using ranges. Whenever you want to + modify the selected items use select() and provide either a + QItemSelection, or a QModelIndex and a QItemSelectionModel::SelectionFlag. - The QItemSelectionModel takes a two layer approach to selection - management, dealing with both selected items that have been committed - and items that are part of the current selection. The current - selected items are part of the current interactive selection (for - example with rubber-band selection or keyboard-shift selections). + The QItemSelectionModel takes a two layer approach to selection + management, dealing with both selected items that have been committed + and items that are part of the current selection. The current + selected items are part of the current interactive selection (for + example with rubber-band selection or keyboard-shift selections). - To update the currently selected items, use the bitwise OR of - QItemSelectionModel::Current and any of the other SelectionFlags. - If you omit the QItemSelectionModel::Current command, a new current - selection will be created, and the previous one added to the whole - selection. All functions operate on both layers; for example, - selectedItems() will return items from both layers. + To update the currently selected items, use the bitwise OR of + QItemSelectionModel::Current and any of the other SelectionFlags. + If you omit the QItemSelectionModel::Current command, a new current + selection will be created, and the previous one added to the whole + selection. All functions operate on both layers; for example, + selectedItems() will return items from both layers. - \sa {Model/View Programming}, QAbstractItemModel, {Chart Example} + \sa {Model/View Programming}, QAbstractItemModel, {Chart Example} */ /*! - Constructs a selection model that operates on the specified item \a model. + Constructs a selection model that operates on the specified item \a model. */ QItemSelectionModel::QItemSelectionModel(QAbstractItemModel *model) : QObject(*new QItemSelectionModelPrivate, model) @@ -864,7 +907,7 @@ QItemSelectionModel::QItemSelectionModel(QAbstractItemModel *model) } /*! - Constructs a selection model that operates on the specified item \a model with \a parent. + Constructs a selection model that operates on the specified item \a model with \a parent. */ QItemSelectionModel::QItemSelectionModel(QAbstractItemModel *model, QObject *parent) : QObject(*new QItemSelectionModelPrivate, parent) @@ -887,7 +930,7 @@ QItemSelectionModel::QItemSelectionModel(QAbstractItemModel *model, QObject *par } /*! - \internal + \internal */ QItemSelectionModel::QItemSelectionModel(QItemSelectionModelPrivate &dd, QAbstractItemModel *model) : QObject(dd, model) @@ -910,7 +953,7 @@ QItemSelectionModel::QItemSelectionModel(QItemSelectionModelPrivate &dd, QAbstra } /*! - Destroys the selection model. + Destroys the selection model. */ QItemSelectionModel::~QItemSelectionModel() { @@ -932,10 +975,10 @@ QItemSelectionModel::~QItemSelectionModel() } /*! - Selects the model item \a index using the specified \a command, and emits - selectionChanged(). + Selects the model item \a index using the specified \a command, and emits + selectionChanged(). - \sa QItemSelectionModel::SelectionFlags + \sa QItemSelectionModel::SelectionFlags */ void QItemSelectionModel::select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command) { @@ -944,37 +987,37 @@ void QItemSelectionModel::select(const QModelIndex &index, QItemSelectionModel:: } /*! - \fn void QItemSelectionModel::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) + \fn void QItemSelectionModel::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) - This signal is emitted whenever the current item changes. The \a previous - model item index is replaced by the \a current index as the selection's - current item. + This signal is emitted whenever the current item changes. The \a previous + model item index is replaced by the \a current index as the selection's + current item. - Note that this signal will not be emitted when the item model is reset. + Note that this signal will not be emitted when the item model is reset. - \sa currentIndex() setCurrentIndex() selectionChanged() + \sa currentIndex() setCurrentIndex() selectionChanged() */ /*! - \fn void QItemSelectionModel::currentColumnChanged(const QModelIndex ¤t, const QModelIndex &previous) + \fn void QItemSelectionModel::currentColumnChanged(const QModelIndex ¤t, const QModelIndex &previous) - This signal is emitted if the \a current item changes and its column is - different to the column of the \a previous current item. + This signal is emitted if the \a current item changes and its column is + different to the column of the \a previous current item. - Note that this signal will not be emitted when the item model is reset. + Note that this signal will not be emitted when the item model is reset. - \sa currentChanged() currentRowChanged() currentIndex() setCurrentIndex() + \sa currentChanged() currentRowChanged() currentIndex() setCurrentIndex() */ /*! - \fn void QItemSelectionModel::currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous) + \fn void QItemSelectionModel::currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous) - This signal is emitted if the \a current item changes and its row is - different to the row of the \a previous current item. + This signal is emitted if the \a current item changes and its row is + different to the row of the \a previous current item. - Note that this signal will not be emitted when the item model is reset. + Note that this signal will not be emitted when the item model is reset. - \sa currentChanged() currentColumnChanged() currentIndex() setCurrentIndex() + \sa currentChanged() currentColumnChanged() currentIndex() setCurrentIndex() */ /*! @@ -991,32 +1034,32 @@ void QItemSelectionModel::select(const QModelIndex &index, QItemSelectionModel:: */ /*! - \enum QItemSelectionModel::SelectionFlag + \enum QItemSelectionModel::SelectionFlag - This enum describes the way the selection model will be updated. + This enum describes the way the selection model will be updated. - \value NoUpdate No selection will be made. - \value Clear The complete selection will be cleared. - \value Select All specified indexes will be selected. - \value Deselect All specified indexes will be deselected. - \value Toggle All specified indexes will be selected or - deselected depending on their current state. - \value Current The current selection will be updated. - \value Rows All indexes will be expanded to span rows. - \value Columns All indexes will be expanded to span columns. - \value SelectCurrent A combination of Select and Current, provided for - convenience. - \value ToggleCurrent A combination of Toggle and Current, provided for - convenience. - \value ClearAndSelect A combination of Clear and Select, provided for - convenience. + \value NoUpdate No selection will be made. + \value Clear The complete selection will be cleared. + \value Select All specified indexes will be selected. + \value Deselect All specified indexes will be deselected. + \value Toggle All specified indexes will be selected or + deselected depending on their current state. + \value Current The current selection will be updated. + \value Rows All indexes will be expanded to span rows. + \value Columns All indexes will be expanded to span columns. + \value SelectCurrent A combination of Select and Current, provided for + convenience. + \value ToggleCurrent A combination of Toggle and Current, provided for + convenience. + \value ClearAndSelect A combination of Clear and Select, provided for + convenience. */ /*! - Selects the item \a selection using the specified \a command, and emits - selectionChanged(). + Selects the item \a selection using the specified \a command, and emits + selectionChanged(). - \sa QItemSelectionModel::SelectionFlag + \sa QItemSelectionModel::SelectionFlag */ void QItemSelectionModel::select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) { @@ -1056,7 +1099,7 @@ void QItemSelectionModel::select(const QItemSelection &selection, QItemSelection } /*! - Clears the selection model. Emits selectionChanged() and currentChanged(). + Clears the selection model. Emits selectionChanged() and currentChanged(). */ void QItemSelectionModel::clear() { @@ -1072,7 +1115,7 @@ void QItemSelectionModel::clear() } /*! - Clears the selection model. Does not emit any signals. + Clears the selection model. Does not emit any signals. */ void QItemSelectionModel::reset() { @@ -1082,8 +1125,8 @@ void QItemSelectionModel::reset() } /*! - \since 4.2 - Clears the selection in the selection model. Emits selectionChanged(). + \since 4.2 + Clears the selection in the selection model. Emits selectionChanged(). */ void QItemSelectionModel::clearSelection() { @@ -1099,14 +1142,14 @@ void QItemSelectionModel::clearSelection() /*! - Sets the model item \a index to be the current item, and emits - currentChanged(). The current item is used for keyboard navigation and - focus indication; it is independent of any selected items, although a - selected item can also be the current item. + Sets the model item \a index to be the current item, and emits + currentChanged(). The current item is used for keyboard navigation and + focus indication; it is independent of any selected items, although a + selected item can also be the current item. - Depending on the specified \a command, the \a index can also become part - of the current selection. - \sa select() + Depending on the specified \a command, the \a index can also become part + of the current selection. + \sa select() */ void QItemSelectionModel::setCurrentIndex(const QModelIndex &index, QItemSelectionModel::SelectionFlags command) { @@ -1130,8 +1173,8 @@ void QItemSelectionModel::setCurrentIndex(const QModelIndex &index, QItemSelecti } /*! - Returns the model item index for the current item, or an invalid index - if there is no current item. + Returns the model item index for the current item, or an invalid index + if there is no current item. */ QModelIndex QItemSelectionModel::currentIndex() const { @@ -1139,7 +1182,7 @@ QModelIndex QItemSelectionModel::currentIndex() const } /*! - Returns true if the given model item \a index is selected. + Returns true if the given model item \a index is selected. */ bool QItemSelectionModel::isSelected(const QModelIndex &index) const { @@ -1176,12 +1219,12 @@ bool QItemSelectionModel::isSelected(const QModelIndex &index) const } /*! - Returns true if all items are selected in the \a row with the given - \a parent. + Returns true if all items are selected in the \a row with the given + \a parent. - Note that this function is usually faster than calling isSelected() - on all items in the same row and that unselectable items are - ignored. + Note that this function is usually faster than calling isSelected() + on all items in the same row and that unselectable items are + ignored. */ bool QItemSelectionModel::isRowSelected(int row, const QModelIndex &parent) const { @@ -1236,12 +1279,12 @@ bool QItemSelectionModel::isRowSelected(int row, const QModelIndex &parent) cons } /*! - Returns true if all items are selected in the \a column with the given - \a parent. + Returns true if all items are selected in the \a column with the given + \a parent. - Note that this function is usually faster than calling isSelected() - on all items in the same column and that unselectable items are - ignored. + Note that this function is usually faster than calling isSelected() + on all items in the same column and that unselectable items are + ignored. */ bool QItemSelectionModel::isColumnSelected(int column, const QModelIndex &parent) const { @@ -1296,8 +1339,8 @@ bool QItemSelectionModel::isColumnSelected(int column, const QModelIndex &parent } /*! - Returns true if there are any items selected in the \a row with the given - \a parent. + Returns true if there are any items selected in the \a row with the given + \a parent. */ bool QItemSelectionModel::rowIntersectsSelection(int row, const QModelIndex &parent) const { @@ -1325,8 +1368,8 @@ bool QItemSelectionModel::rowIntersectsSelection(int row, const QModelIndex &par } /*! - Returns true if there are any items selected in the \a column with the given - \a parent. + Returns true if there are any items selected in the \a column with the given + \a parent. */ bool QItemSelectionModel::columnIntersectsSelection(int column, const QModelIndex &parent) const { @@ -1366,15 +1409,14 @@ bool QItemSelectionModel::hasSelection() const QItemSelection sel = d->ranges; sel.merge(d->currentSelection, d->currentCommand); return !sel.isEmpty(); - } - else { + } else { return !(d->ranges.isEmpty() && d->currentSelection.isEmpty()); } } /*! - Returns a list of all selected model item indexes. The list contains no - duplicates, and is not sorted. + Returns a list of all selected model item indexes. The list contains no + duplicates, and is not sorted. */ QModelIndexList QItemSelectionModel::selectedIndexes() const { @@ -1385,10 +1427,10 @@ QModelIndexList QItemSelectionModel::selectedIndexes() const } /*! - \since 4.2 - Returns the indexes in the given \a column for the rows where all columns are selected. + \since 4.2 + Returns the indexes in the given \a column for the rows where all columns are selected. - \sa selectedIndexes(), selectedColumns() + \sa selectedIndexes(), selectedColumns() */ QModelIndexList QItemSelectionModel::selectedRows(int column) const @@ -1449,7 +1491,7 @@ QModelIndexList QItemSelectionModel::selectedColumns(int row) const } /*! - Returns the selection ranges stored in the selection model. + Returns the selection ranges stored in the selection model. */ const QItemSelection QItemSelectionModel::selection() const { @@ -1469,7 +1511,7 @@ const QItemSelection QItemSelectionModel::selection() const } /*! - Returns the item model operated on by the selection model. + Returns the item model operated on by the selection model. */ const QAbstractItemModel *QItemSelectionModel::model() const { @@ -1477,8 +1519,8 @@ const QAbstractItemModel *QItemSelectionModel::model() const } /*! - Compares the two selections \a newSelection and \a oldSelection - and emits selectionChanged() with the deselected and selected items. + Compares the two selections \a newSelection and \a oldSelection + and emits selectionChanged() with the deselected and selected items. */ void QItemSelectionModel::emitSelectionChanged(const QItemSelection &newSelection, const QItemSelection &oldSelection) @@ -1553,7 +1595,7 @@ QDebug operator<<(QDebug dbg, const QItemSelectionRange &range) { #ifndef Q_BROKEN_DEBUG_STREAM dbg.nospace() << "QItemSelectionRange(" << range.topLeft() - << "," << range.bottomRight() << ")"; + << ',' << range.bottomRight() << ')'; return dbg.space(); #else qWarning("This compiler doesn't support streaming QItemSelectionRange to QDebug"); diff --git a/src/gui/itemviews/qitemselectionmodel_p.h b/src/gui/itemviews/qitemselectionmodel_p.h index fadc3f9..7e39d1f 100644 --- a/src/gui/itemviews/qitemselectionmodel_p.h +++ b/src/gui/itemviews/qitemselectionmodel_p.h @@ -65,7 +65,7 @@ public: QItemSelectionModelPrivate() : model(0), currentCommand(QItemSelectionModel::NoUpdate), - tableSelected(false) {} + tableSelected(false), tableColCount(0), tableRowCount(0) {} QItemSelection expandSelection(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) const; diff --git a/src/gui/itemviews/qlistview.cpp b/src/gui/itemviews/qlistview.cpp index 35b44b4..fc801ad 100644 --- a/src/gui/itemviews/qlistview.cpp +++ b/src/gui/itemviews/qlistview.cpp @@ -1,4 +1,4 @@ -/*************************************************************************** +/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Nokia Corporation (qt-info@nokia.com) @@ -66,7 +66,7 @@ QT_BEGIN_NAMESPACE \ingroup model-view \ingroup advanced - \mainclass + A QListView presents items stored in a model, either as a simple non-hierarchical list, or as a collection of icons. This class is used @@ -458,13 +458,13 @@ QSize QListView::gridSize() const void QListView::setViewMode(ViewMode mode) { Q_D(QListView); + if (d->commonListView && d->viewMode == mode) + return; d->viewMode = mode; + delete d->commonListView; if (mode == ListMode) { - delete d->dynamicListView; - d->dynamicListView = 0; - if (!d->staticListView) - d->staticListView = new QStaticListViewBase(this, d); + d->commonListView = new QListModeViewBase(this, d); if (!(d->modeProperties & QListViewPrivate::Wrap)) d->setWrapping(false); if (!(d->modeProperties & QListViewPrivate::Spacing)) @@ -480,10 +480,7 @@ void QListView::setViewMode(ViewMode mode) if (!(d->modeProperties & QListViewPrivate::SelectionRectVisible)) d->showElasticBand = false; } else { - delete d->staticListView; - d->staticListView = 0; - if (!d->dynamicListView) - d->dynamicListView = new QDynamicListViewBase(this, d); + d->commonListView = new QIconModeViewBase(this, d); if (!(d->modeProperties & QListViewPrivate::Wrap)) d->setWrapping(true); if (!(d->modeProperties & QListViewPrivate::Spacing)) @@ -547,24 +544,12 @@ void QListView::setRowHidden(int row, bool hide) { Q_D(QListView); const bool hidden = d->isHidden(row); - if (d->viewMode == ListMode) { - if (hide && !hidden) - d->hiddenRows.append(d->model->index(row, 0)); - else if (!hide && hidden) - d->hiddenRows.remove(d->hiddenRows.indexOf(d->model->index(row, 0))); - d->doDelayedItemsLayout(); - } else { - if (hide && !hidden) { - d->dynamicListView->removeItem(row); - d->hiddenRows.append(d->model->index(row, 0)); - } else if (!hide && hidden) { - d->hiddenRows.remove(d->hiddenRows.indexOf(d->model->index(row, 0))); - d->dynamicListView->insertItem(row); - } - if (d->resizeMode == Adjust) - d->doDelayedItemsLayout(); - d->viewport->update(); - } + if (hide && !hidden) + d->commonListView->appendHiddenRow(row); + else if (!hide && hidden) + d->commonListView->removeHiddenRow(row); + d->doDelayedItemsLayout(); + d->viewport->update(); } /*! @@ -573,7 +558,7 @@ void QListView::setRowHidden(int row, bool hide) QRect QListView::visualRect(const QModelIndex &index) const { Q_D(const QListView); - return d->mapToViewport(rectForIndex(index), d->viewMode == QListView::ListMode); + return d->mapToViewport(rectForIndex(index)); } /*! @@ -588,7 +573,7 @@ void QListView::scrollTo(const QModelIndex &index, ScrollHint hint) const QRect rect = visualRect(index); if (hint == EnsureVisible && d->viewport->rect().contains(rect)) { - d->setDirtyRegion(rect); + d->viewport->update(rect); return; } @@ -610,69 +595,17 @@ int QListViewPrivate::horizontalScrollToValue(const QModelIndex &index, const QR const bool rightOf = q->isRightToLeft() ? rect.right() > area.right() : (rect.right() > area.right()) && (rect.left() > area.left()); - int horizontalValue = q->horizontalScrollBar()->value(); - - // ScrollPerItem - if (q->horizontalScrollMode() == QAbstractItemView::ScrollPerItem && viewMode == QListView::ListMode) { - const QListViewItem item = indexToListViewItem(index); - const QRect rect = q->visualRect(index); - horizontalValue = staticListView->horizontalPerItemValue(itemIndex(item), - horizontalValue, area.width(), - leftOf, rightOf, isWrapping(), hint, rect.width()); - } else { // ScrollPerPixel - if (q->isRightToLeft()) { - if (hint == QListView::PositionAtCenter) { - horizontalValue += ((area.width() - rect.width()) / 2) - rect.left(); - } else { - if (leftOf) - horizontalValue -= rect.left(); - else if (rightOf) - horizontalValue += qMin(rect.left(), area.width() - rect.right()); - } - } else { - if (hint == QListView::PositionAtCenter) { - horizontalValue += rect.left() - ((area.width()- rect.width()) / 2); - } else { - if (leftOf) - horizontalValue += rect.left(); - else if (rightOf) - horizontalValue += qMin(rect.left(), rect.right() - area.width()); - } - } - } - return horizontalValue; + return commonListView->horizontalScrollToValue(q->visualIndex(index), hint, leftOf, rightOf, area, rect); } int QListViewPrivate::verticalScrollToValue(const QModelIndex &index, const QRect &rect, QListView::ScrollHint hint) const { Q_Q(const QListView); - const QRect area = viewport->rect(); const bool above = (hint == QListView::EnsureVisible && rect.top() < area.top()); const bool below = (hint == QListView::EnsureVisible && rect.bottom() > area.bottom()); - - int verticalValue = q->verticalScrollBar()->value(); - - // ScrollPerItem - if (q->verticalScrollMode() == QAbstractItemView::ScrollPerItem && viewMode == QListView::ListMode) { - const QListViewItem item = indexToListViewItem(index); - const QRect rect = q->visualRect(index); - verticalValue = staticListView->verticalPerItemValue(itemIndex(item), - verticalValue, area.height(), - above, below, isWrapping(), hint, rect.height()); - - } else { // ScrollPerPixel - QRect adjusted = rect.adjusted(-spacing(), -spacing(), spacing(), spacing()); - if (hint == QListView::PositionAtTop || above) - verticalValue += adjusted.top(); - else if (hint == QListView::PositionAtBottom || below) - verticalValue += qMin(adjusted.top(), adjusted.bottom() - area.height() + 1); - else if (hint == QListView::PositionAtCenter) - verticalValue += adjusted.top() - ((area.height() - adjusted.height()) / 2); - } - - return verticalValue; + return commonListView->verticalScrollToValue(q->visualIndex(index), hint, above, below, area, rect); } void QListViewPrivate::selectAll(QItemSelectionModel::SelectionFlags command) @@ -709,6 +642,31 @@ void QListViewPrivate::selectAll(QItemSelectionModel::SelectionFlags command) selectionModel->select(selection, command); } +/*! + \reimp + + We have a QListView way of knowing what elements are on the viewport + through the intersectingSet function +*/ +QItemViewPaintPairs QListViewPrivate::draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const +{ + Q_ASSERT(r); + Q_Q(const QListView); + QRect &rect = *r; + const QRect viewportRect = viewport->rect(); + QItemViewPaintPairs ret; + const QSet<QModelIndex> visibleIndexes = intersectingSet(viewportRect).toList().toSet(); + for (int i = 0; i < indexes.count(); ++i) { + const QModelIndex &index = indexes.at(i); + if (visibleIndexes.contains(index)) { + const QRect current = q->visualRect(index); + ret += qMakePair(current, index); + rect |= current; + } + } + rect &= viewportRect; + return ret; +} /*! \internal @@ -739,23 +697,12 @@ void QListView::setRootIndex(const QModelIndex &index) Scroll the view contents by \a dx and \a dy. */ + void QListView::scrollContentsBy(int dx, int dy) { Q_D(QListView); - d->delayedAutoScroll.stop(); // auto scroll was canceled by the user scrolling - - if (d->viewMode == ListMode) - d->staticListView->scrollContentsBy(dx, dy); - else if (state() == DragSelectingState) - d->scrollElasticBandBy(isRightToLeft() ? -dx : dx, dy); - - d->scrollContentsBy(isRightToLeft() ? -dx : dx, dy); - - // update the dragged items - if (d->viewMode == IconMode) // ### move to dynamic class - if (!d->dynamicListView->draggedItems.isEmpty()) - d->setDirtyRegion(d->dynamicListView->draggedItemsRect().translated(dx, dy)); + d->commonListView->scrollContentsBy(dx, dy, d->state == QListView::DragSelectingState); } /*! @@ -784,9 +731,7 @@ QSize QListView::contentsSize() const */ void QListView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { - Q_D(QListView); - if (d->viewMode == IconMode) - d->dynamicListView->dataChanged(topLeft, bottomRight); + d_func()->commonListView->dataChanged(topLeft, bottomRight); QAbstractItemView::dataChanged(topLeft, bottomRight); } @@ -837,7 +782,7 @@ void QListView::mouseMoveEvent(QMouseEvent *e) && d->selectionMode != NoSelection) { QRect rect(d->pressedPosition, e->pos() + QPoint(horizontalOffset(), verticalOffset())); rect = rect.normalized(); - d->setDirtyRegion(d->mapToViewport(rect.united(d->elasticBand), d->viewMode == QListView::ListMode)); + d->viewport->update(d->mapToViewport(rect.united(d->elasticBand))); d->elasticBand = rect; } } @@ -851,7 +796,7 @@ void QListView::mouseReleaseEvent(QMouseEvent *e) QAbstractItemView::mouseReleaseEvent(e); // #### move this implementation into a dynamic class if (d->showElasticBand && d->elasticBand.isValid()) { - d->setDirtyRegion(d->mapToViewport(d->elasticBand, d->viewMode == QListView::ListMode)); + d->viewport->update(d->mapToViewport(d->elasticBand)); d->elasticBand = QRect(); } } @@ -908,69 +853,27 @@ void QListView::resizeEvent(QResizeEvent *e) */ void QListView::dragMoveEvent(QDragMoveEvent *e) { - // ### move implementation to dynamic - Q_D(QListView); - if (e->source() == this && d->viewMode == IconMode) { - // the ignore by default - e->ignore(); - if (d->canDecode(e)) { - // get old dragged items rect - QRect itemsRect = d->dynamicListView->itemsRect(d->dynamicListView->draggedItems); - d->setDirtyRegion(itemsRect.translated(d->dynamicListView->draggedItemsDelta())); - // update position - d->dynamicListView->draggedItemsPos = e->pos(); - // get new items rect - d->setDirtyRegion(itemsRect.translated(d->dynamicListView->draggedItemsDelta())); - // set the item under the cursor to current - QModelIndex index; - if (d->movement == Snap) { - QRect rect(d->dynamicListView->snapToGrid(e->pos() + d->offset()), d->gridSize()); - d->intersectingSet(rect); - index = d->intersectVector.count() > 0 - ? d->intersectVector.last() : QModelIndex(); - } else { - index = indexAt(e->pos()); - } - // check if we allow drops here - if (e->source() == this && d->dynamicListView->draggedItems.contains(index)) - e->accept(); // allow changing item position - else if (d->model->flags(index) & Qt::ItemIsDropEnabled) - e->accept(); // allow dropping on dropenabled items - else if (!index.isValid()) - e->accept(); // allow dropping in empty areas - } - // do autoscrolling - if (d->shouldAutoScroll(e->pos())) - startAutoScroll(); - } else { // not internal + if (!d_func()->commonListView->filterDragMoveEvent(e)) QAbstractItemView::dragMoveEvent(e); - } } + /*! \reimp */ void QListView::dragLeaveEvent(QDragLeaveEvent *e) { - // ### move implementation to dynamic - Q_D(QListView); - if (d->viewMode == IconMode) { - d->viewport->update(d->dynamicListView->draggedItemsRect()); // erase the area - d->dynamicListView->draggedItemsPos = QPoint(-1, -1); // don't draw the dragged items - } - QAbstractItemView::dragLeaveEvent(e); + if (!d_func()->commonListView->filterDragLeaveEvent(e)) + QAbstractItemView::dragLeaveEvent(e); } /*! \reimp */ -void QListView::dropEvent(QDropEvent *event) +void QListView::dropEvent(QDropEvent *e) { - Q_D(QListView); - if (event->source() == this && d->viewMode == IconMode) - internalDrop(event); // ### move to dynamic - else - QAbstractItemView::dropEvent(event); + if (!d_func()->commonListView->filterDropEvent(e)) + QAbstractItemView::dropEvent(e); } /*! @@ -978,10 +881,7 @@ void QListView::dropEvent(QDropEvent *event) */ void QListView::startDrag(Qt::DropActions supportedActions) { - Q_D(QListView); - if (d->viewMode == IconMode) // ### move to dynamic - internalDrag(supportedActions); - else + if (!d_func()->commonListView->filterStartDrag(supportedActions)) QAbstractItemView::startDrag(supportedActions); } @@ -993,41 +893,8 @@ void QListView::startDrag(Qt::DropActions supportedActions) */ void QListView::internalDrop(QDropEvent *event) { - Q_D(QListView); - if (d->viewMode == QListView::ListMode) - return; - - // ### move to dynamic class - QPoint offset(horizontalOffset(), verticalOffset()); - QPoint end = event->pos() + offset; - QPoint start = d->pressedPosition; - QPoint delta = (d->movement == Snap ? - d->dynamicListView->snapToGrid(end) - - d->dynamicListView->snapToGrid(start) : end - start); - QSize contents = d->contentsSize(); - QList<QModelIndex> indexes = d->selectionModel->selectedIndexes(); - for (int i = 0; i < indexes.count(); ++i) { - QModelIndex index = indexes.at(i); - QRect rect = rectForIndex(index); - d->setDirtyRegion(d->mapToViewport(rect, d->viewMode == QListView::ListMode)); - QPoint dest = rect.topLeft() + delta; - if (isRightToLeft()) - dest.setX(d->flipX(dest.x()) - rect.width()); - d->dynamicListView->moveItem(index.row(), dest); - d->setDirtyRegion(visualRect(index)); - } - stopAutoScroll(); - d->dynamicListView->draggedItems.clear(); - emit indexesMoved(indexes); - event->accept(); // we have handled the event - // if the size has not grown, we need to check if it has shrinked - if (d->dynamicListView - && (d->contentsSize().width() <= contents.width() - || d->contentsSize().height() <= contents.height())) { - d->dynamicListView->updateContentsSize(); - } - if (d->contentsSize() != contents) - updateGeometries(); + // ### Qt5: remove that function + Q_UNUSED(event); } /*! @@ -1038,31 +905,8 @@ void QListView::internalDrop(QDropEvent *event) */ void QListView::internalDrag(Qt::DropActions supportedActions) { - Q_D(QListView); - if (d->viewMode == QListView::ListMode) - return; - - // #### move to dynamic class - - // This function does the same thing as in QAbstractItemView::startDrag(), - // plus adding viewitems to the draggedItems list. - // We need these items to draw the drag items - QModelIndexList indexes = d->selectionModel->selectedIndexes(); - if (indexes.count() > 0 ) { - if (d->viewport->acceptDrops()) { - QModelIndexList::ConstIterator it = indexes.constBegin(); - for (; it != indexes.constEnd(); ++it) - if (d->model->flags(*it) & Qt::ItemIsDragEnabled - && (*it).column() == d->column) - d->dynamicListView->draggedItems.push_back(*it); - } - QDrag *drag = new QDrag(this); - drag->setMimeData(d->model->mimeData(indexes)); - Qt::DropAction action = drag->exec(supportedActions, Qt::CopyAction); - d->dynamicListView->draggedItems.clear(); - if (action == Qt::MoveAction) - d->clearOrRemove(); - } + // ### Qt5: remove that function + Q_UNUSED(supportedActions); } #endif // QT_NO_DRAGANDDROP @@ -1090,6 +934,7 @@ QStyleOptionViewItem QListView::viewOptions() const return option; } + /*! \reimp */ @@ -1100,16 +945,8 @@ void QListView::paintEvent(QPaintEvent *e) return; QStyleOptionViewItemV4 option = d->viewOptionsV4(); QPainter painter(d->viewport); - QRect area = e->rect(); - QVector<QModelIndex> toBeRendered; -// QVector<QRect> rects = e->region().rects(); -// for (int i = 0; i < rects.size(); ++i) { -// d->intersectingSet(rects.at(i).translated(horizontalOffset(), verticalOffset())); -// toBeRendered += d->intersectVector; -// } - d->intersectingSet(e->rect().translated(horizontalOffset(), verticalOffset()), false); - toBeRendered = d->intersectVector; + const QVector<QModelIndex> toBeRendered = d->intersectingSet(e->rect().translated(horizontalOffset(), verticalOffset()), false); const QModelIndex current = currentIndex(); const QModelIndex hover = d->hover; @@ -1194,18 +1031,7 @@ void QListView::paintEvent(QPaintEvent *e) } #ifndef QT_NO_DRAGANDDROP - // #### move this implementation into a dynamic class - if (d->viewMode == IconMode) - if (!d->dynamicListView->draggedItems.isEmpty() - && d->viewport->rect().contains(d->dynamicListView->draggedItemsPos)) { - QPoint delta = d->dynamicListView->draggedItemsDelta(); - painter.translate(delta.x(), delta.y()); - d->dynamicListView->drawItems(&painter, d->dynamicListView->draggedItems); - } - // FIXME: Until the we can provide a proper drop indicator - // in IconMode, it makes no sense to show it - if (d->viewMode == ListMode) - d->paintDropIndicator(&painter); + d->commonListView->paintDragDrop(&painter); #endif #ifndef QT_NO_RUBBERBAND @@ -1231,9 +1057,9 @@ QModelIndex QListView::indexAt(const QPoint &p) const { Q_D(const QListView); QRect rect(p.x() + horizontalOffset(), p.y() + verticalOffset(), 1, 1); - d->intersectingSet(rect); - QModelIndex index = d->intersectVector.count() > 0 - ? d->intersectVector.last() : QModelIndex(); + const QVector<QModelIndex> intersectVector = d->intersectingSet(rect); + QModelIndex index = intersectVector.count() > 0 + ? intersectVector.last() : QModelIndex(); if (index.isValid() && visualRect(index).contains(p)) return index; return QModelIndex(); @@ -1244,31 +1070,7 @@ QModelIndex QListView::indexAt(const QPoint &p) const */ int QListView::horizontalOffset() const { - Q_D(const QListView); - // ### split into static and dynamic - if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem && d->viewMode == ListMode) { - if (d->isWrapping()) { - if (d->flow == TopToBottom && !d->staticListView->segmentPositions.isEmpty()) { - const int max = d->staticListView->segmentPositions.count() - 1; - int currentValue = qBound(0, horizontalScrollBar()->value(), max); - int position = d->staticListView->segmentPositions.at(currentValue); - int maximumValue = qBound(0, horizontalScrollBar()->maximum(), max); - int maximum = d->staticListView->segmentPositions.at(maximumValue); - return (isRightToLeft() ? maximum - position : position); - } - //return 0; - } else { - if (d->flow == LeftToRight && !d->staticListView->flowPositions.isEmpty()) { - int position = d->staticListView->flowPositions.at(horizontalScrollBar()->value()); - int maximum = d->staticListView->flowPositions.at(horizontalScrollBar()->maximum()); - return (isRightToLeft() ? maximum - position : position); - } - //return 0; - } - } - return (isRightToLeft() - ? horizontalScrollBar()->maximum() - horizontalScrollBar()->value() - : horizontalScrollBar()->value()); + return d_func()->commonListView->horizontalOffset(); } /*! @@ -1276,30 +1078,7 @@ int QListView::horizontalOffset() const */ int QListView::verticalOffset() const { - // ## split into static and dynamic - Q_D(const QListView); - if (verticalScrollMode() == QAbstractItemView::ScrollPerItem && d->viewMode == ListMode) { - if (d->isWrapping()) { - if (d->flow == LeftToRight && !d->staticListView->segmentPositions.isEmpty()) { - int value = verticalScrollBar()->value(); - if (value >= d->staticListView->segmentPositions.count()) { - //qWarning("QListView: Vertical scroll bar is out of bounds"); - return 0; - } - return d->staticListView->segmentPositions.at(value); - } - } else { - if (d->flow == TopToBottom && !d->staticListView->flowPositions.isEmpty()) { - int value = verticalScrollBar()->value(); - if (value > d->staticListView->flowPositions.count()) { - //qWarning("QListView: Vertical scroll bar is out of bounds"); - return 0; - } - return d->staticListView->flowPositions.at(value) - d->spacing(); - } - } - } - return verticalScrollBar()->value(); + return d_func()->commonListView->verticalOffset(); } /*! @@ -1331,38 +1110,38 @@ QModelIndex QListView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifie if (d->gridSize().isValid()) rect.setSize(d->gridSize()); QSize contents = d->contentsSize(); - d->intersectVector.clear(); + QVector<QModelIndex> intersectVector; switch (cursorAction) { case MoveLeft: - while (d->intersectVector.isEmpty()) { + while (intersectVector.isEmpty()) { rect.translate(-rect.width(), 0); if (rect.right() <= 0) return current; if (rect.left() < 0) rect.setLeft(0); - d->intersectingSet(rect); - d->removeCurrentAndDisabled(&d->intersectVector, current); + intersectVector = d->intersectingSet(rect); + d->removeCurrentAndDisabled(&intersectVector, current); } - return d->closestIndex(initialRect, d->intersectVector); + return d->closestIndex(initialRect, intersectVector); case MoveRight: - while (d->intersectVector.isEmpty()) { + while (intersectVector.isEmpty()) { rect.translate(rect.width(), 0); if (rect.left() >= contents.width()) return current; if (rect.right() > contents.width()) rect.setRight(contents.width()); - d->intersectingSet(rect); - d->removeCurrentAndDisabled(&d->intersectVector, current); + intersectVector = d->intersectingSet(rect); + d->removeCurrentAndDisabled(&intersectVector, current); } - return d->closestIndex(initialRect, d->intersectVector); + return d->closestIndex(initialRect, intersectVector); case MovePageUp: rect.moveTop(rect.top() - d->viewport->height()); if (rect.top() < rect.height()) rect.moveTop(rect.height()); case MovePrevious: case MoveUp: - while (d->intersectVector.isEmpty()) { + while (intersectVector.isEmpty()) { rect.translate(0, -rect.height()); if (rect.bottom() <= 0) { #ifdef QT_KEYPAD_NAVIGATION @@ -1378,17 +1157,17 @@ QModelIndex QListView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifie } if (rect.top() < 0) rect.setTop(0); - d->intersectingSet(rect); - d->removeCurrentAndDisabled(&d->intersectVector, current); + intersectVector = d->intersectingSet(rect); + d->removeCurrentAndDisabled(&intersectVector, current); } - return d->closestIndex(initialRect, d->intersectVector); + return d->closestIndex(initialRect, intersectVector); case MovePageDown: rect.moveTop(rect.top() + d->viewport->height()); if (rect.bottom() > contents.height() - rect.height()) rect.moveBottom(contents.height() - rect.height()); case MoveNext: case MoveDown: - while (d->intersectVector.isEmpty()) { + while (intersectVector.isEmpty()) { rect.translate(0, rect.height()); if (rect.top() >= contents.height()) { #ifdef QT_KEYPAD_NAVIGATION @@ -1405,10 +1184,10 @@ QModelIndex QListView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifie } if (rect.bottom() > contents.height()) rect.setBottom(contents.height()); - d->intersectingSet(rect); - d->removeCurrentAndDisabled(&d->intersectVector, current); + intersectVector = d->intersectingSet(rect); + d->removeCurrentAndDisabled(&intersectVector, current); } - return d->closestIndex(initialRect, d->intersectVector); + return d->closestIndex(initialRect, intersectVector); case MoveHome: return d->model->index(0, d->column, d->root); case MoveEnd: @@ -1425,15 +1204,7 @@ QModelIndex QListView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifie */ QRect QListView::rectForIndex(const QModelIndex &index) const { - Q_D(const QListView); - if (!d->isIndexValid(index) - || index.parent() != d->root - || index.column() != d->column - || isIndexHidden(index)) - return QRect(); - d->executePostedLayout(); - QListViewItem item = d->indexToListViewItem(index); - return d->viewItemRect(item); + return d_func()->rectForIndex(index); } /*! @@ -1441,8 +1212,8 @@ QRect QListView::rectForIndex(const QModelIndex &index) const Sets the contents position of the item at \a index in the model to the given \a position. - If the list view's movement mode is Static, this function will have no - effect. + If the list view's movement mode is Static or its view mode is ListView, + this function will have no effect. */ void QListView::setPositionForIndex(const QPoint &position, const QModelIndex &index) { @@ -1454,15 +1225,7 @@ void QListView::setPositionForIndex(const QPoint &position, const QModelIndex &i return; d->executePostedLayout(); - if (index.row() >= d->dynamicListView->items.count()) - return; - const QSize oldContents = d->contentsSize(); - d->setDirtyRegion(visualRect(index)); // update old position - d->dynamicListView->moveItem(index.row(), position); - d->setDirtyRegion(visualRect(index)); // update new position - - if (d->contentsSize() != oldContents) - updateGeometries(); // update the scroll bars + d->commonListView->setPositionForIndex(position, index); } /*! @@ -1483,10 +1246,10 @@ void QListView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFl QItemSelection selection; if (rect.width() == 1 && rect.height() == 1) { - d->intersectingSet(rect.translated(horizontalOffset(), verticalOffset())); + const QVector<QModelIndex> intersectVector = d->intersectingSet(rect.translated(horizontalOffset(), verticalOffset())); QModelIndex tl; - if (!d->intersectVector.isEmpty()) - tl = d->intersectVector.last(); // special case for mouse press; only select the top item + if (!intersectVector.isEmpty()) + tl = intersectVector.last(); // special case for mouse press; only select the top item if (tl.isValid() && d->isIndexEnabled(tl)) selection.select(tl, tl); } else { @@ -1496,14 +1259,14 @@ void QListView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFl QModelIndex tl, br; // get the first item const QRect topLeft(rect.left() + horizontalOffset(), rect.top() + verticalOffset(), 1, 1); - d->intersectingSet(topLeft); - if (!d->intersectVector.isEmpty()) - tl = d->intersectVector.last(); + QVector<QModelIndex> intersectVector = d->intersectingSet(topLeft); + if (!intersectVector.isEmpty()) + tl = intersectVector.last(); // get the last item const QRect bottomRight(rect.right() + horizontalOffset(), rect.bottom() + verticalOffset(), 1, 1); - d->intersectingSet(bottomRight); - if (!d->intersectVector.isEmpty()) - br = d->intersectVector.last(); + intersectVector = d->intersectingSet(bottomRight); + if (!intersectVector.isEmpty()) + br = intersectVector.last(); // get the ranges if (tl.isValid() && br.isValid() @@ -1546,7 +1309,10 @@ void QListView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFl } // middle rectangle if (top.bottom() < bottom.top()) { - middle.setTop(top.bottom() + 1); + if (gridSize().isValid() && !gridSize().isNull()) + middle.setTop(top.top() + gridSize().height()); + else + middle.setTop(top.bottom() + 1); middle.setLeft(qMin(top.left(), bottom.left())); middle.setBottom(bottom.top() - 1); middle.setRight(qMax(top.right(), bottom.right())); @@ -1573,7 +1339,10 @@ void QListView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFl // only set middle if the middle.setTop(0); middle.setBottom(ch); - middle.setLeft(left.right() + 1); + if (gridSize().isValid() && !gridSize().isNull()) + middle.setLeft(left.left() + gridSize().width()); + else + middle.setLeft(left.right() + 1); middle.setRight(right.left() - 1); } else if (left.bottom() < right.top()) { left.setBottom(right.top() - 1); @@ -1610,6 +1379,10 @@ QRegion QListView::visualRegionForSelection(const QItemSelection &selection) con if (!selection.at(i).isValid()) continue; QModelIndex parent = selection.at(i).topLeft().parent(); + //we only display the children of the root in a listview + //we're not interested in the other model indexes + if (parent != d->root) + continue; int t = selection.at(i).topLeft().row(); int b = selection.at(i).bottomRight().row(); if (d->viewMode == IconMode || d->isWrapping()) { // in non-static mode, we have to go through all selected items @@ -1618,8 +1391,8 @@ QRegion QListView::visualRegionForSelection(const QItemSelection &selection) con } else { // in static mode, we can optimize a bit while (t <= b && d->isHidden(t)) ++t; while (b >= t && d->isHidden(b)) --b; - const QModelIndex top = d->model->index(t, c, d->root); - const QModelIndex bottom = d->model->index(b, c, d->root); + const QModelIndex top = d->model->index(t, c, parent); + const QModelIndex bottom = d->model->index(b, c, parent); QRect rect(visualRect(top).topLeft(), visualRect(bottom).bottomRight()); selectionRegion += QRegion(rect); @@ -1635,14 +1408,16 @@ QRegion QListView::visualRegionForSelection(const QItemSelection &selection) con QModelIndexList QListView::selectedIndexes() const { Q_D(const QListView); - QModelIndexList viewSelected; - QModelIndexList modelSelected; - if (d->selectionModel) - modelSelected = d->selectionModel->selectedIndexes(); - for (int i = 0; i < modelSelected.count(); ++i) { - QModelIndex index = modelSelected.at(i); + if (!d->selectionModel) + return QModelIndexList(); + + QModelIndexList viewSelected = d->selectionModel->selectedIndexes(); + for (int i = 0; i < viewSelected.count(); ++i) { + const QModelIndex &index = viewSelected.at(i); if (!isIndexHidden(index) && index.parent() == d->root && index.column() == d->column) - viewSelected.append(index); + ++i; + else + viewSelected.removeAt(i); } return viewSelected; } @@ -1686,99 +1461,8 @@ void QListView::updateGeometries() QModelIndex index = d->model->index(0, d->column, d->root); QStyleOptionViewItemV4 option = d->viewOptionsV4(); QSize step = d->itemSize(option, index); - - QSize csize = d->contentsSize(); - QSize vsize = d->viewport->size(); - QSize max = maximumViewportSize(); - if (max.width() >= d->contentsSize().width() && max.height() >= d->contentsSize().height()) - vsize = max; - - // ### reorder the logic - - // ### split into static and dynamic - - const bool vertical = verticalScrollMode() == QAbstractItemView::ScrollPerItem; - const bool horizontal = horizontalScrollMode() == QAbstractItemView::ScrollPerItem; - - if (d->flow == TopToBottom) { - if (horizontal && d->isWrapping() && d->viewMode == ListMode) { - const QVector<int> segmentPositions = d->staticListView->segmentPositions; - const int steps = segmentPositions.count() - 1; - if (steps > 0) { - int pageSteps = d->staticListView->perItemScrollingPageSteps(vsize.width(), - csize.width(), - isWrapping()); - horizontalScrollBar()->setSingleStep(1); - horizontalScrollBar()->setPageStep(pageSteps); - horizontalScrollBar()->setRange(0, steps - pageSteps); - } else { - horizontalScrollBar()->setRange(0, 0); - } - } else { - horizontalScrollBar()->setSingleStep(step.width() + d->spacing()); - horizontalScrollBar()->setPageStep(vsize.width()); - horizontalScrollBar()->setRange(0, d->contentsSize().width() - vsize.width()); - } - if (vertical && !d->isWrapping() && d->viewMode == ListMode) { - const QVector<int> flowPositions = d->staticListView->flowPositions; - const int steps = flowPositions.count() - 1; - if (steps > 0) { - int pageSteps = d->staticListView->perItemScrollingPageSteps(vsize.height(), - csize.height(), - isWrapping()); - verticalScrollBar()->setSingleStep(1); - verticalScrollBar()->setPageStep(pageSteps); - verticalScrollBar()->setRange(0, steps - pageSteps); - } else { - verticalScrollBar()->setRange(0, 0); - } - // } else if (vertical && d->isWrapping() && d->movement == Static) { - // ### wrapped scrolling in flow direction - } else { - verticalScrollBar()->setSingleStep(step.height() + d->spacing()); - verticalScrollBar()->setPageStep(vsize.height()); - verticalScrollBar()->setRange(0, d->contentsSize().height() - vsize.height()); - } - } else { // LeftToRight - if (horizontal && !d->isWrapping() && d->viewMode == ListMode) { - const QVector<int> flowPositions = d->staticListView->flowPositions; - int steps = flowPositions.count() - 1; - if (steps > 0) { - int pageSteps = d->staticListView->perItemScrollingPageSteps(vsize.width(), - csize.width(), - isWrapping()); - horizontalScrollBar()->setSingleStep(1); - horizontalScrollBar()->setPageStep(pageSteps); - horizontalScrollBar()->setRange(0, steps - pageSteps); - } else { - horizontalScrollBar()->setRange(0, 0); - } - // } else if (horizontal && d->isWrapping() && d->movement == Static) { - // ### wrapped scrolling in flow direction - } else { - horizontalScrollBar()->setSingleStep(step.width() + d->spacing()); - horizontalScrollBar()->setPageStep(vsize.width()); - horizontalScrollBar()->setRange(0, d->contentsSize().width() - vsize.width()); - } - if (vertical && d->isWrapping() && d->viewMode == ListMode) { - const QVector<int> segmentPositions = d->staticListView->segmentPositions; - int steps = segmentPositions.count() - 1; - if (steps > 0) { - int pageSteps = d->staticListView->perItemScrollingPageSteps(vsize.height(), - csize.height(), - isWrapping()); - verticalScrollBar()->setSingleStep(1); - verticalScrollBar()->setPageStep(pageSteps); - verticalScrollBar()->setRange(0, steps - pageSteps); - } else { - verticalScrollBar()->setRange(0, 0); - } - } else { - verticalScrollBar()->setSingleStep(step.height() + d->spacing()); - verticalScrollBar()->setPageStep(vsize.height()); - verticalScrollBar()->setRange(0, d->contentsSize().height() - vsize.height()); - } - } + d->commonListView->updateHorizontalScrollBar(step); + d->commonListView->updateVerticalScrollBar(step); } QAbstractItemView::updateGeometries(); @@ -1927,8 +1611,7 @@ bool QListView::event(QEvent *e) QListViewPrivate::QListViewPrivate() : QAbstractItemViewPrivate(), - dynamicListView(0), - staticListView(0), + commonListView(0), wrap(false), space(0), flow(QListView::TopToBottom), @@ -1939,25 +1622,21 @@ QListViewPrivate::QListViewPrivate() modeProperties(0), column(0), uniformItemSizes(false), - batchSize(100) + batchSize(100), + showElasticBand(false) { } QListViewPrivate::~QListViewPrivate() { - delete staticListView; - delete dynamicListView; + delete commonListView; } void QListViewPrivate::clear() { - // ### split into dynamic and static // initialization of data structs cachedItemSize = QSize(); - if (viewMode == QListView::ListMode) - staticListView->clear(); - else - dynamicListView->clear(); + commonListView->clear(); } void QListViewPrivate::prepareItemsLayout() @@ -1966,27 +1645,26 @@ void QListViewPrivate::prepareItemsLayout() clear(); //take the size as if there were scrollbar in order to prevent scrollbar to blink - layoutBounds = QRect(QPoint(0,0), q->maximumViewportSize()); + layoutBounds = QRect(QPoint(), q->maximumViewportSize()); int frameAroundContents = 0; if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents)) frameAroundContents = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth) * 2; - int verticalMargin = vbarpolicy==Qt::ScrollBarAlwaysOff ? 0 : - q->style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, q->verticalScrollBar()) + frameAroundContents; - int horizontalMargin = hbarpolicy==Qt::ScrollBarAlwaysOff ? 0 : - q->style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, q->horizontalScrollBar()) + frameAroundContents; + + // maximumViewportSize() already takes scrollbar into account if policy is + // Qt::ScrollBarAlwaysOn but scrollbar extent must be deduced if policy + // is Qt::ScrollBarAsNeeded + int verticalMargin = vbarpolicy==Qt::ScrollBarAsNeeded + ? q->style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, vbar) + frameAroundContents + : 0; + int horizontalMargin = hbarpolicy==Qt::ScrollBarAsNeeded + ? q->style()->pixelMetric(QStyle::PM_ScrollBarExtent, 0, hbar) + frameAroundContents + : 0; layoutBounds.adjust(0, 0, -verticalMargin, -horizontalMargin); - int rowCount = model->rowCount(root); - int colCount = model->columnCount(root); - if (colCount <= 0) - rowCount = 0; // no contents - if (viewMode == QListView::ListMode) { - staticListView->flowPositions.resize(rowCount); - } else { - dynamicListView->tree.create(qMax(rowCount - hiddenRows.count(), 0)); - } + int rowCount = model->columnCount(root) <= 0 ? 0 : model->rowCount(root); + commonListView->setRowCount(rowCount); } /*! @@ -1994,7 +1672,6 @@ void QListViewPrivate::prepareItemsLayout() */ bool QListViewPrivate::doItemsLayout(int delta) { - // ### split into static and dynamic int max = model->rowCount(root) - 1; int first = batchStartRow(); int last = qMin(first + delta - 1, max); @@ -2018,9 +1695,7 @@ bool QListViewPrivate::doItemsLayout(int delta) info.flow = flow; info.max = max; - if (viewMode == QListView::ListMode) - return staticListView->doBatchedItemLayout(info, max); - return dynamicListView->doBatchedItemLayout(info, max); + return commonListView->doBatchedItemLayout(info, max); } QListViewItem QListViewPrivate::indexToListViewItem(const QModelIndex &index) const @@ -2028,33 +1703,19 @@ QListViewItem QListViewPrivate::indexToListViewItem(const QModelIndex &index) co if (!index.isValid() || isHidden(index.row())) return QListViewItem(); - if (viewMode == QListView::ListMode) - return staticListView->indexToListViewItem(index); - return dynamicListView->indexToListViewItem(index); -} - - -int QListViewPrivate::itemIndex(const QListViewItem &item) const -{ - if (viewMode == QListView::ListMode) - return staticListView->itemIndex(item); - return dynamicListView->itemIndex(item); + return commonListView->indexToListViewItem(index); } -QRect QListViewPrivate::mapToViewport(const QRect &rect, bool greedy) const +QRect QListViewPrivate::mapToViewport(const QRect &rect, bool extend) const { Q_Q(const QListView); if (!rect.isValid()) return rect; - QRect result = rect; - if (greedy) - result = staticListView->mapToViewport(rect); - + QRect result = extend ? commonListView->mapToViewport(rect) : rect; int dx = -q->horizontalOffset(); int dy = -q->verticalOffset(); - result.adjust(dx, dy, dx, dy); - return result; + return result.adjusted(dx, dy, dx, dy); } QModelIndex QListViewPrivate::closestIndex(const QRect &target, @@ -2112,8 +1773,8 @@ QItemSelection QListViewPrivate::selection(const QRect &rect) const { QItemSelection selection; QModelIndex tl, br; - intersectingSet(rect); - QVector<QModelIndex>::iterator it = intersectVector.begin(); + const QVector<QModelIndex> intersectVector = intersectingSet(rect); + QVector<QModelIndex>::const_iterator it = intersectVector.begin(); for (; it != intersectVector.end(); ++it) { if (!tl.isValid() && !br.isValid()) { tl = br = *it; @@ -2138,46 +1799,217 @@ QItemSelection QListViewPrivate::selection(const QRect &rect) const } /* - * Static ListView Implementation + * Common ListView Implementation +*/ + +void QCommonListViewBase::appendHiddenRow(int row) +{ + dd->hiddenRows.append(dd->model->index(row, 0)); +} + +void QCommonListViewBase::removeHiddenRow(int row) +{ + dd->hiddenRows.remove(dd->hiddenRows.indexOf(dd->model->index(row, 0))); +} + +void QCommonListViewBase::updateHorizontalScrollBar(const QSize &step) +{ + horizontalScrollBar()->setSingleStep(step.width() + spacing()); + horizontalScrollBar()->setPageStep(viewport()->width()); + horizontalScrollBar()->setRange(0, contentsSize.width() - viewport()->width()); +} + +void QCommonListViewBase::updateVerticalScrollBar(const QSize &step) +{ + verticalScrollBar()->setSingleStep(step.height() + spacing()); + verticalScrollBar()->setPageStep(viewport()->height()); + verticalScrollBar()->setRange(0, contentsSize.height() - viewport()->height()); +} + +void QCommonListViewBase::scrollContentsBy(int dx, int dy, bool /*scrollElasticBand*/) +{ + dd->scrollContentsBy(isRightToLeft() ? -dx : dx, dy); +} + +int QCommonListViewBase::verticalScrollToValue(int /*index*/, QListView::ScrollHint hint, + bool above, bool below, const QRect &area, const QRect &rect) const +{ + int verticalValue = verticalScrollBar()->value(); + QRect adjusted = rect.adjusted(-spacing(), -spacing(), spacing(), spacing()); + if (hint == QListView::PositionAtTop || above) + verticalValue += adjusted.top(); + else if (hint == QListView::PositionAtBottom || below) + verticalValue += qMin(adjusted.top(), adjusted.bottom() - area.height() + 1); + else if (hint == QListView::PositionAtCenter) + verticalValue += adjusted.top() - ((area.height() - adjusted.height()) / 2); + return verticalValue; +} + +int QCommonListViewBase::horizontalOffset() const +{ + return (isRightToLeft() ? horizontalScrollBar()->maximum() - horizontalScrollBar()->value() : horizontalScrollBar()->value()); +} + +int QCommonListViewBase::horizontalScrollToValue(const int /*index*/, QListView::ScrollHint hint, + bool leftOf, bool rightOf, const QRect &area, const QRect &rect) const +{ + int horizontalValue = horizontalScrollBar()->value(); + if (isRightToLeft()) { + if (hint == QListView::PositionAtCenter) { + horizontalValue += ((area.width() - rect.width()) / 2) - rect.left(); + } else { + if (leftOf) + horizontalValue -= rect.left(); + else if (rightOf) + horizontalValue += qMin(rect.left(), area.width() - rect.right()); + } + } else { + if (hint == QListView::PositionAtCenter) { + horizontalValue += rect.left() - ((area.width()- rect.width()) / 2); + } else { + if (leftOf) + horizontalValue += rect.left(); + else if (rightOf) + horizontalValue += qMin(rect.left(), rect.right() - area.width()); + } + } + return horizontalValue; +} + +/* + * ListMode ListView Implementation */ -int QStaticListViewBase::verticalPerItemValue(int itemIndex, int verticalValue, int areaHeight, - bool above, bool below, bool wrap, - QListView::ScrollHint hint, int itemHeight) const +#ifndef QT_NO_DRAGANDDROP +void QListModeViewBase::paintDragDrop(QPainter *painter) { - int value = qBound(0, verticalValue, flowPositions.count() - 1); - if (above) - return perItemScrollToValue(itemIndex, value, areaHeight, QListView::PositionAtTop, - Qt::Vertical,wrap, itemHeight); - else if (below) - return perItemScrollToValue(itemIndex, value, areaHeight, QListView::PositionAtBottom, - Qt::Vertical, wrap, itemHeight); - else if (hint != QListView::EnsureVisible) - return perItemScrollToValue(itemIndex, value, areaHeight, hint, Qt::Vertical, wrap, itemHeight); - return value; + // FIXME: Until the we can provide a proper drop indicator + // in IconMode, it makes no sense to show it + dd->paintDropIndicator(painter); } +#endif //QT_NO_DRAGANDDROP -int QStaticListViewBase::horizontalPerItemValue(int itemIndex, int horizontalValue, int areaWidth, - bool leftOf, bool rightOf, bool wrap, - QListView::ScrollHint hint, int itemWidth) const +void QListModeViewBase::updateVerticalScrollBar(const QSize &step) { - int value = qBound(0, horizontalValue, flowPositions.count() - 1); + if (verticalScrollMode() == QAbstractItemView::ScrollPerItem + && ((flow() == QListView::TopToBottom && !isWrapping()) + || (flow() == QListView::LeftToRight && isWrapping()))) { + const int steps = (flow() == QListView::TopToBottom ? flowPositions : segmentPositions).count() - 1; + if (steps > 0) { + const int pageSteps = perItemScrollingPageSteps(viewport()->height(), contentsSize.height(), isWrapping()); + verticalScrollBar()->setSingleStep(1); + verticalScrollBar()->setPageStep(pageSteps); + verticalScrollBar()->setRange(0, steps - pageSteps); + } else { + verticalScrollBar()->setRange(0, 0); + } + // } else if (vertical && d->isWrapping() && d->movement == Static) { + // ### wrapped scrolling in flow direction + } else { + QCommonListViewBase::updateVerticalScrollBar(step); + } +} + +void QListModeViewBase::updateHorizontalScrollBar(const QSize &step) +{ + if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem + && ((flow() == QListView::TopToBottom && isWrapping()) + || (flow() == QListView::LeftToRight && !isWrapping()))) { + int steps = (flow() == QListView::TopToBottom ? segmentPositions : flowPositions).count() - 1; + if (steps > 0) { + const int pageSteps = perItemScrollingPageSteps(viewport()->width(), contentsSize.width(), isWrapping()); + horizontalScrollBar()->setSingleStep(1); + horizontalScrollBar()->setPageStep(pageSteps); + horizontalScrollBar()->setRange(0, steps - pageSteps); + } else { + horizontalScrollBar()->setRange(0, 0); + } + } else { + QCommonListViewBase::updateHorizontalScrollBar(step); + } +} + +int QListModeViewBase::verticalScrollToValue(int index, QListView::ScrollHint hint, + bool above, bool below, const QRect &area, const QRect &rect) const +{ + if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) { + int value = qBound(0, verticalScrollBar()->value(), flowPositions.count() - 1); + if (above) + hint = QListView::PositionAtTop; + else if (below) + hint = QListView::PositionAtBottom; + if (hint == QListView::EnsureVisible) + return value; + + return perItemScrollToValue(index, value, area.height(), hint, Qt::Vertical, isWrapping(), rect.height()); + } + + return QCommonListViewBase::verticalScrollToValue(index, hint, above, below, area, rect); +} + +int QListModeViewBase::horizontalOffset() const +{ + if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) { + if (isWrapping()) { + if (flow() == QListView::TopToBottom && !segmentPositions.isEmpty()) { + const int max = segmentPositions.count() - 1; + int currentValue = qBound(0, horizontalScrollBar()->value(), max); + int position = segmentPositions.at(currentValue); + int maximumValue = qBound(0, horizontalScrollBar()->maximum(), max); + int maximum = segmentPositions.at(maximumValue); + return (isRightToLeft() ? maximum - position : position); + } + } else if (flow() == QListView::LeftToRight && !flowPositions.isEmpty()) { + int position = flowPositions.at(horizontalScrollBar()->value()); + int maximum = flowPositions.at(horizontalScrollBar()->maximum()); + return (isRightToLeft() ? maximum - position : position); + } + } + return QCommonListViewBase::horizontalOffset(); +} + +int QListModeViewBase::verticalOffset() const +{ + if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) { + if (isWrapping()) { + if (flow() == QListView::LeftToRight && !segmentPositions.isEmpty()) { + int value = verticalScrollBar()->value(); + if (value >= segmentPositions.count()) + return 0; + return segmentPositions.at(value); + } + } else if (flow() == QListView::TopToBottom && !flowPositions.isEmpty()) { + int value = verticalScrollBar()->value(); + if (value > flowPositions.count()) + return 0; + return flowPositions.at(value) - spacing(); + } + } + return QCommonListViewBase::verticalOffset(); +} + +int QListModeViewBase::horizontalScrollToValue(int index, QListView::ScrollHint hint, + bool leftOf, bool rightOf, const QRect &area, const QRect &rect) const +{ + if (horizontalScrollMode() != QAbstractItemView::ScrollPerItem) + return QCommonListViewBase::horizontalScrollToValue(index, hint, leftOf, rightOf, area, rect); + + int value = qBound(0, horizontalScrollBar()->value(), flowPositions.count() - 1); if (leftOf) - return perItemScrollToValue(itemIndex, value, areaWidth, QListView::PositionAtTop, - Qt::Horizontal, wrap, itemWidth); + hint = QListView::PositionAtTop; else if (rightOf) - return perItemScrollToValue(itemIndex, value, areaWidth, QListView::PositionAtBottom, - Qt::Horizontal, wrap, itemWidth); - else if (hint != QListView::EnsureVisible) - return perItemScrollToValue(itemIndex, value, areaWidth, hint, Qt::Horizontal, wrap, itemWidth); - return value; + hint = QListView::PositionAtBottom; + if (hint == QListView::EnsureVisible) + return value; + + return perItemScrollToValue(index, value, area.width(), hint, Qt::Horizontal, isWrapping(), rect.width()); } -void QStaticListViewBase::scrollContentsBy(int &dx, int &dy) +void QListModeViewBase::scrollContentsBy(int dx, int dy, bool scrollElasticBand) { // ### reorder this logic - const int verticalValue = verticalScrollBarValue(); - const int horizontalValue = horizontalScrollBarValue(); + const int verticalValue = verticalScrollBar()->value(); + const int horizontalValue = horizontalScrollBar()->value(); const bool vertical = (verticalScrollMode() == QAbstractItemView::ScrollPerItem); const bool horizontal = (horizontalScrollMode() == QAbstractItemView::ScrollPerItem); @@ -2216,9 +2048,10 @@ void QStaticListViewBase::scrollContentsBy(int &dx, int &dy) dx = previousCoordinate - currentCoordinate; } } + QCommonListViewBase::scrollContentsBy(dx, dy, scrollElasticBand); } -bool QStaticListViewBase::doBatchedItemLayout(const QListViewLayoutInfo &info, int max) +bool QListModeViewBase::doBatchedItemLayout(const QListViewLayoutInfo &info, int max) { doStaticLayout(info); if (batchStartRow > max) { // stop items layout @@ -2230,7 +2063,7 @@ bool QStaticListViewBase::doBatchedItemLayout(const QListViewLayoutInfo &info, i return false; // not done } -QListViewItem QStaticListViewBase::indexToListViewItem(const QModelIndex &index) const +QListViewItem QListModeViewBase::indexToListViewItem(const QModelIndex &index) const { if (flowPositions.isEmpty() || segmentPositions.isEmpty() @@ -2266,7 +2099,7 @@ QListViewItem QStaticListViewBase::indexToListViewItem(const QModelIndex &index) return QListViewItem(QRect(pos, size), index.row()); } -QPoint QStaticListViewBase::initStaticLayout(const QListViewLayoutInfo &info) +QPoint QListModeViewBase::initStaticLayout(const QListViewLayoutInfo &info) { int x, y; if (info.first == 0) { @@ -2301,7 +2134,7 @@ QPoint QStaticListViewBase::initStaticLayout(const QListViewLayoutInfo &info) /*! \internal */ -void QStaticListViewBase::doStaticLayout(const QListViewLayoutInfo &info) +void QListModeViewBase::doStaticLayout(const QListViewLayoutInfo &info) { const bool useItemSize = !info.grid.isValid(); const QPoint topLeft = initStaticLayout(info); @@ -2404,9 +2237,9 @@ void QStaticListViewBase::doStaticLayout(const QListViewLayoutInfo &info) Finds the set of items intersecting with \a area. In this function, itemsize is counted from topleft to the start of the next item. */ -void QStaticListViewBase::intersectingStaticSet(const QRect &area) const +QVector<QModelIndex> QListModeViewBase::intersectingSet(const QRect &area) const { - clearIntersections(); + QVector<QModelIndex> ret; int segStartPosition; int segEndPosition; int flowStartPosition; @@ -2423,7 +2256,7 @@ void QStaticListViewBase::intersectingStaticSet(const QRect &area) const flowEndPosition = area.bottom(); } if (segmentPositions.count() < 2 || flowPositions.isEmpty()) - return; + return ret; // the last segment position is actually the edge of the last segment const int segLast = segmentPositions.count() - 2; int seg = qBinarySearch<int>(segmentPositions, segStartPosition, 0, segLast + 1); @@ -2438,39 +2271,34 @@ void QStaticListViewBase::intersectingStaticSet(const QRect &area) const continue; QModelIndex index = modelIndex(row); if (index.isValid()) - appendToIntersections(index); + ret += index; #if 0 // for debugging else - qWarning("intersectingStaticSet: row %d was invalid", row); + qWarning("intersectingSet: row %d was invalid", row); #endif } } + return ret; } -int QStaticListViewBase::itemIndex(const QListViewItem &item) const -{ - return item.indexHint; -} - -QRect QStaticListViewBase::mapToViewport(const QRect &rect) const +QRect QListModeViewBase::mapToViewport(const QRect &rect) const { if (isWrapping()) return rect; // If the listview is in "listbox-mode", the items are as wide as the view. + // But we don't shrink the items. QRect result = rect; - QSize vsize = viewport()->size(); - QSize csize = contentsSize; if (flow() == QListView::TopToBottom) { result.setLeft(spacing()); - result.setWidth(qMax(csize.width(), vsize.width()) - 2 * spacing()); + result.setWidth(qMax(rect.width(), qMax(contentsSize.width(), viewport()->width()) - 2 * spacing())); } else { // LeftToRight result.setTop(spacing()); - result.setHeight(qMax(csize.height(), vsize.height()) - 2 * spacing()); + result.setHeight(qMax(rect.height(), qMax(contentsSize.height(), viewport()->height()) - 2 * spacing())); } return result; } -int QStaticListViewBase::perItemScrollingPageSteps(int length, int bounds, bool wrap) const +int QListModeViewBase::perItemScrollingPageSteps(int length, int bounds, bool wrap) const { const QVector<int> positions = (wrap ? segmentPositions : flowPositions); if (positions.isEmpty() || bounds <= length) @@ -2498,7 +2326,7 @@ int QStaticListViewBase::perItemScrollingPageSteps(int length, int bounds, bool return qMax(pageSteps, 1); } -int QStaticListViewBase::perItemScrollToValue(int index, int scrollValue, int viewportSize, +int QListModeViewBase::perItemScrollToValue(int index, int scrollValue, int viewportSize, QAbstractItemView::ScrollHint hint, Qt::Orientation orientation, bool wrap, int itemExtent) const { @@ -2558,7 +2386,7 @@ int QStaticListViewBase::perItemScrollToValue(int index, int scrollValue, int vi return scrollValue; } -void QStaticListViewBase::clear() +void QListModeViewBase::clear() { flowPositions.clear(); segmentPositions.clear(); @@ -2570,10 +2398,175 @@ void QStaticListViewBase::clear() } /* - * Dynamic ListView Implementation + * IconMode ListView Implementation */ -void QDynamicListViewBase::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) +void QIconModeViewBase::setPositionForIndex(const QPoint &position, const QModelIndex &index) +{ + if (index.row() >= items.count()) + return; + const QSize oldContents = contentsSize; + qq->update(index); // update old position + moveItem(index.row(), position); + qq->update(index); // update new position + + if (contentsSize != oldContents) + dd->viewUpdateGeometries(); // update the scroll bars +} + +void QIconModeViewBase::appendHiddenRow(int row) +{ + if (row >= 0 && row < items.count()) //remove item + tree.removeLeaf(items.at(row).rect(), row); + QCommonListViewBase::appendHiddenRow(row); +} + +void QIconModeViewBase::removeHiddenRow(int row) +{ + QCommonListViewBase::appendHiddenRow(row); + if (row >= 0 && row < items.count()) //insert item + tree.insertLeaf(items.at(row).rect(), row); +} + +#ifndef QT_NO_DRAGANDDROP +void QIconModeViewBase::paintDragDrop(QPainter *painter) +{ + if (!draggedItems.isEmpty() && viewport()->rect().contains(draggedItemsPos)) { + //we need to draw the items that arre dragged + painter->translate(draggedItemsDelta()); + QStyleOptionViewItemV4 option = viewOptions(); + option.state &= ~QStyle::State_MouseOver; + QVector<QModelIndex>::const_iterator it = draggedItems.begin(); + QListViewItem item = indexToListViewItem(*it); + for (; it != draggedItems.end(); ++it) { + item = indexToListViewItem(*it); + option.rect = viewItemRect(item); + delegate(*it)->paint(painter, option, *it); + } + } +} + +bool QIconModeViewBase::filterStartDrag(Qt::DropActions supportedActions) +{ + // This function does the same thing as in QAbstractItemView::startDrag(), + // plus adding viewitems to the draggedItems list. + // We need these items to draw the drag items + QModelIndexList indexes = dd->selectionModel->selectedIndexes(); + if (indexes.count() > 0 ) { + if (viewport()->acceptDrops()) { + QModelIndexList::ConstIterator it = indexes.constBegin(); + for (; it != indexes.constEnd(); ++it) + if (dd->model->flags(*it) & Qt::ItemIsDragEnabled + && (*it).column() == dd->column) + draggedItems.push_back(*it); + } + QDrag *drag = new QDrag(qq); + drag->setMimeData(dd->model->mimeData(indexes)); + Qt::DropAction action = drag->exec(supportedActions, Qt::CopyAction); + draggedItems.clear(); + if (action == Qt::MoveAction) + dd->clearOrRemove(); + } + return true; +} + +bool QIconModeViewBase::filterDropEvent(QDropEvent *e) +{ + if (e->source() != qq) + return false; + + const QSize contents = contentsSize; + QPoint offset(horizontalOffset(), verticalOffset()); + QPoint end = e->pos() + offset; + QPoint start = dd->pressedPosition; + QPoint delta = (dd->movement == QListView::Snap ? snapToGrid(end) - snapToGrid(start) : end - start); + QList<QModelIndex> indexes = dd->selectionModel->selectedIndexes(); + for (int i = 0; i < indexes.count(); ++i) { + QModelIndex index = indexes.at(i); + QRect rect = dd->rectForIndex(index); + viewport()->update(mapToViewport(rect)); + QPoint dest = rect.topLeft() + delta; + if (qq->isRightToLeft()) + dest.setX(dd->flipX(dest.x()) - rect.width()); + moveItem(index.row(), dest); + qq->update(index); + } + dd->stopAutoScroll(); + draggedItems.clear(); + dd->emitIndexesMoved(indexes); + e->accept(); // we have handled the event + // if the size has not grown, we need to check if it has shrinked + if (contentsSize != contents) { + if ((contentsSize.width() <= contents.width() + || contentsSize.height() <= contents.height())) { + updateContentsSize(); + } + dd->viewUpdateGeometries(); + } + return true; +} + +bool QIconModeViewBase::filterDragLeaveEvent(QDragLeaveEvent *e) +{ + viewport()->update(draggedItemsRect()); // erase the area + draggedItemsPos = QPoint(-1, -1); // don't draw the dragged items + return QCommonListViewBase::filterDragLeaveEvent(e); +} + +bool QIconModeViewBase::filterDragMoveEvent(QDragMoveEvent *e) +{ + if (e->source() != qq || !dd->canDecode(e)) + return false; + + // ignore by default + e->ignore(); + // get old dragged items rect + QRect itemsRect = this->itemsRect(draggedItems); + viewport()->update(itemsRect.translated(draggedItemsDelta())); + // update position + draggedItemsPos = e->pos(); + // get new items rect + viewport()->update(itemsRect.translated(draggedItemsDelta())); + // set the item under the cursor to current + QModelIndex index; + if (movement() == QListView::Snap) { + QRect rect(snapToGrid(e->pos() + offset()), gridSize()); + const QVector<QModelIndex> intersectVector = intersectingSet(rect); + index = intersectVector.count() > 0 ? intersectVector.last() : QModelIndex(); + } else { + index = qq->indexAt(e->pos()); + } + // check if we allow drops here + if (draggedItems.contains(index)) + e->accept(); // allow changing item position + else if (dd->model->flags(index) & Qt::ItemIsDropEnabled) + e->accept(); // allow dropping on dropenabled items + else if (!index.isValid()) + e->accept(); // allow dropping in empty areas + + // the event was treated. do autoscrolling + if (dd->shouldAutoScroll(e->pos())) + dd->startAutoScroll(); + return true; +} +#endif // QT_NO_DRAGANDDROP + +void QIconModeViewBase::setRowCount(int rowCount) +{ + tree.create(qMax(rowCount - hiddenCount(), 0)); +} + +void QIconModeViewBase::scrollContentsBy(int dx, int dy, bool scrollElasticBand) +{ + if (scrollElasticBand) + dd->scrollElasticBandBy(isRightToLeft() ? -dx : dx, dy); + + QCommonListViewBase::scrollContentsBy(dx, dy, scrollElasticBand); + if (!draggedItems.isEmpty()) + viewport()->update(draggedItemsRect().translated(dx, dy)); +} + +void QIconModeViewBase::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { if (column() >= topLeft.column() && column() <= bottomRight.column()) { QStyleOptionViewItemV4 option = viewOptions(); @@ -2583,23 +2576,29 @@ void QDynamicListViewBase::dataChanged(const QModelIndex &topLeft, const QModelI } } -bool QDynamicListViewBase::doBatchedItemLayout(const QListViewLayoutInfo &info, int max) +bool QIconModeViewBase::doBatchedItemLayout(const QListViewLayoutInfo &info, int max) { if (info.last >= items.count()) { - createItems(info.last + 1); + //first we create the items + QStyleOptionViewItemV4 option = viewOptions(); + for (int row = items.count(); row <= info.last; ++row) { + QSize size = itemSize(option, modelIndex(row)); + QListViewItem item(QRect(0, 0, size.width(), size.height()), row); // default pos + items.append(item); + } doDynamicLayout(info); } return (batchStartRow > max); // done } -QListViewItem QDynamicListViewBase::indexToListViewItem(const QModelIndex &index) const +QListViewItem QIconModeViewBase::indexToListViewItem(const QModelIndex &index) const { if (index.isValid() && index.row() < items.count()) return items.at(index.row()); return QListViewItem(); } -void QDynamicListViewBase::initBspTree(const QSize &contents) +void QIconModeViewBase::initBspTree(const QSize &contents) { // remove all items from the tree int leafCount = tree.leafCount(); @@ -2616,7 +2615,7 @@ void QDynamicListViewBase::initBspTree(const QSize &contents) tree.init(QRect(0, 0, contents.width(), contents.height()), type); } -QPoint QDynamicListViewBase::initDynamicLayout(const QListViewLayoutInfo &info) +QPoint QIconModeViewBase::initDynamicLayout(const QListViewLayoutInfo &info) { int x, y; if (info.first == 0) { @@ -2638,7 +2637,7 @@ QPoint QDynamicListViewBase::initDynamicLayout(const QListViewLayoutInfo &info) /*! \internal */ -void QDynamicListViewBase::doDynamicLayout(const QListViewLayoutInfo &info) +void QIconModeViewBase::doDynamicLayout(const QListViewLayoutInfo &info) { const bool useItemSize = !info.grid.isValid(); const QPoint topLeft = initDynamicLayout(info); @@ -2672,7 +2671,7 @@ void QDynamicListViewBase::doDynamicLayout(const QListViewLayoutInfo &info) if (moved.count() != items.count()) moved.resize(items.count()); - QRect rect(QPoint(0, 0), topLeft); + QRect rect(QPoint(), topLeft); QListViewItem *item = 0; for (int row = info.first; row <= info.last; ++row) { item = &items[row]; @@ -2765,40 +2764,18 @@ void QDynamicListViewBase::doDynamicLayout(const QListViewLayoutInfo &info) viewport()->update(); } -void QDynamicListViewBase::intersectingDynamicSet(const QRect &area) const +QVector<QModelIndex> QIconModeViewBase::intersectingSet(const QRect &area) const { - clearIntersections(); - QListViewPrivate *that = const_cast<QListViewPrivate*>(dd); + QIconModeViewBase *that = const_cast<QIconModeViewBase*>(this); QBspTree::Data data(static_cast<void*>(that)); - that->dynamicListView->tree.climbTree(area, &QDynamicListViewBase::addLeaf, data); -} - -void QDynamicListViewBase::createItems(int to) -{ - int count = items.count(); - QSize size; - QStyleOptionViewItemV4 option = viewOptions(); - for (int row = count; row < to; ++row) { - size = itemSize(option, modelIndex(row)); - QListViewItem item(QRect(0, 0, size.width(), size.height()), row); // default pos - items.append(item); - } + QVector<QModelIndex> res; + that->interSectingVector = &res; + that->tree.climbTree(area, &QIconModeViewBase::addLeaf, data); + that->interSectingVector = 0; + return res; } -void QDynamicListViewBase::drawItems(QPainter *painter, const QVector<QModelIndex> &indexes) const -{ - QStyleOptionViewItemV4 option = viewOptions(); - option.state &= ~QStyle::State_MouseOver; - QVector<QModelIndex>::const_iterator it = indexes.begin(); - QListViewItem item = indexToListViewItem(*it); - for (; it != indexes.end(); ++it) { - item = indexToListViewItem(*it); - option.rect = viewItemRect(item); - delegate(*it)->paint(painter, option, *it); - } -} - -QRect QDynamicListViewBase::itemsRect(const QVector<QModelIndex> &indexes) const +QRect QIconModeViewBase::itemsRect(const QVector<QModelIndex> &indexes) const { QVector<QModelIndex>::const_iterator it = indexes.begin(); QListViewItem item = indexToListViewItem(*it); @@ -2810,7 +2787,7 @@ QRect QDynamicListViewBase::itemsRect(const QVector<QModelIndex> &indexes) const return rect; } -int QDynamicListViewBase::itemIndex(const QListViewItem &item) const +int QIconModeViewBase::itemIndex(const QListViewItem &item) const { if (!item.isValid()) return -1; @@ -2846,39 +2823,27 @@ int QDynamicListViewBase::itemIndex(const QListViewItem &item) const return -1; } -void QDynamicListViewBase::addLeaf(QVector<int> &leaf, const QRect &area, - uint visited, QBspTree::Data data) +void QIconModeViewBase::addLeaf(QVector<int> &leaf, const QRect &area, + uint visited, QBspTree::Data data) { QListViewItem *vi; - QListViewPrivate *_this = static_cast<QListViewPrivate *>(data.ptr); + QIconModeViewBase *_this = static_cast<QIconModeViewBase *>(data.ptr); for (int i = 0; i < leaf.count(); ++i) { int idx = leaf.at(i); - if (idx < 0 || idx >= _this->dynamicListView->items.count()) + if (idx < 0 || idx >= _this->items.count()) continue; - vi = &_this->dynamicListView->items[idx]; + vi = &_this->items[idx]; Q_ASSERT(vi); if (vi->isValid() && vi->rect().intersects(area) && vi->visited != visited) { - QModelIndex index = _this->listViewItemToIndex(*vi); + QModelIndex index = _this->dd->listViewItemToIndex(*vi); Q_ASSERT(index.isValid()); - _this->intersectVector.append(index); + _this->interSectingVector->append(index); vi->visited = visited; } } } -void QDynamicListViewBase::insertItem(int index) -{ - if (index >= 0 && index < items.count()) - tree.insertLeaf(items.at(index).rect(), index); -} - -void QDynamicListViewBase::removeItem(int index) -{ - if (index >= 0 && index < items.count()) - tree.removeLeaf(items.at(index).rect(), index); -} - -void QDynamicListViewBase::moveItem(int index, const QPoint &dest) +void QIconModeViewBase::moveItem(int index, const QPoint &dest) { // does not impact on the bintree itself or the contents rect QListViewItem *item = &items[index]; @@ -2898,14 +2863,14 @@ void QDynamicListViewBase::moveItem(int index, const QPoint &dest) moved.setBit(index, true); } -QPoint QDynamicListViewBase::snapToGrid(const QPoint &pos) const +QPoint QIconModeViewBase::snapToGrid(const QPoint &pos) const { int x = pos.x() - (pos.x() % gridSize().width()); int y = pos.y() - (pos.y() % gridSize().height()); return QPoint(x, y); } -QPoint QDynamicListViewBase::draggedItemsDelta() const +QPoint QIconModeViewBase::draggedItemsDelta() const { if (movement() == QListView::Snap) { QPoint snapdelta = QPoint((offset().x() % gridSize().width()), @@ -2915,7 +2880,7 @@ QPoint QDynamicListViewBase::draggedItemsDelta() const return draggedItemsPos - pressedPosition(); } -QRect QDynamicListViewBase::draggedItemsRect() const +QRect QIconModeViewBase::draggedItemsRect() const { QRect rect = itemsRect(draggedItems); rect.translate(draggedItemsDelta()); @@ -2934,7 +2899,7 @@ void QListViewPrivate::scrollElasticBandBy(int dx, int dy) elasticBand.moveTop(elasticBand.top() - dy); } -void QDynamicListViewBase::clear() +void QIconModeViewBase::clear() { tree.destroy(); items.clear(); @@ -2943,7 +2908,7 @@ void QDynamicListViewBase::clear() batchSavedDeltaSeg = 0; } -void QDynamicListViewBase::updateContentsSize() +void QIconModeViewBase::updateContentsSize() { QRect bounding; for (int i = 0; i < items.count(); ++i) @@ -2996,7 +2961,7 @@ int QListView::visualIndex(const QModelIndex &index) const Q_D(const QListView); d->executePostedLayout(); QListViewItem itm = d->indexToListViewItem(index); - return d->itemIndex(itm); + return d->commonListView->itemIndex(itm); } QT_END_NAMESPACE diff --git a/src/gui/itemviews/qlistview_p.h b/src/gui/itemviews/qlistview_p.h index 6294c11..9c6a0c2 100644 --- a/src/gui/itemviews/qlistview_p.h +++ b/src/gui/itemviews/qlistview_p.h @@ -67,8 +67,8 @@ QT_BEGIN_NAMESPACE class QListViewItem { friend class QListViewPrivate; - friend class QStaticListViewBase; - friend class QDynamicListViewBase; + friend class QListModeViewBase; + friend class QIconModeViewBase; public: inline QListViewItem() : x(-1), y(-1), w(0), h(0), indexHint(-1), visited(0xffff) {} @@ -84,7 +84,7 @@ public: inline bool operator!=(const QListViewItem &other) const { return !(*this == other); } inline bool isValid() const - { return (x > -1) && (y > -1) && (w > 0) && (h > 0) && (indexHint > -1); } + { return rect().isValid() && (indexHint > -1); } inline void invalidate() { x = -1; y = -1; w = 0; h = 0; } inline void resize(const QSize &size) @@ -120,8 +120,42 @@ class QListViewPrivate; class QCommonListViewBase { public: - inline QCommonListViewBase(QListView *q, QListViewPrivate *d) : dd(d), qq(q) {} - + inline QCommonListViewBase(QListView *q, QListViewPrivate *d) : dd(d), qq(q), batchStartRow(0), batchSavedDeltaSeg(0) {} + virtual ~QCommonListViewBase() {} + + //common interface + virtual int itemIndex(const QListViewItem &item) const = 0; + virtual QListViewItem indexToListViewItem(const QModelIndex &index) const = 0; + virtual bool doBatchedItemLayout(const QListViewLayoutInfo &info, int max) = 0; + virtual void clear() = 0; + virtual void setRowCount(int) = 0; + virtual QVector<QModelIndex> intersectingSet(const QRect &area) const = 0; + + virtual int horizontalScrollToValue(int index, QListView::ScrollHint hint, + bool leftOf, bool rightOf, const QRect &area, const QRect &rect) const; + virtual int verticalScrollToValue(int index, QListView::ScrollHint hint, + bool above, bool below, const QRect &area, const QRect &rect) const; + virtual void scrollContentsBy(int dx, int dy, bool scrollElasticBand); + virtual QRect mapToViewport(const QRect &rect) const {return rect;} + virtual int horizontalOffset() const; + virtual int verticalOffset() const { return verticalScrollBar()->value(); } + virtual void updateHorizontalScrollBar(const QSize &step); + virtual void updateVerticalScrollBar(const QSize &step); + virtual void dataChanged(const QModelIndex &, const QModelIndex &) { } + virtual void appendHiddenRow(int row); + virtual void removeHiddenRow(int row); + virtual void setPositionForIndex(const QPoint &, const QModelIndex &) { } + +#ifndef QT_NO_DRAGANDDROP + virtual void paintDragDrop(QPainter *painter) = 0; + virtual bool filterDragMoveEvent(QDragMoveEvent *) { return false; } + virtual bool filterDragLeaveEvent(QDragLeaveEvent *) { return false; } + virtual bool filterDropEvent(QDropEvent *) { return false; } + virtual bool filterStartDrag(Qt::DropActions) { return false; } +#endif + + + //other inline members inline int spacing() const; inline bool isWrapping() const; inline QSize gridSize() const; @@ -133,8 +167,8 @@ public: inline bool uniformItemSizes() const; inline int column() const; - inline int verticalScrollBarValue() const; - inline int horizontalScrollBarValue() const; + inline QScrollBar *verticalScrollBar() const; + inline QScrollBar *horizontalScrollBar() const; inline QListView::ScrollMode verticalScrollMode() const; inline QListView::ScrollMode horizontalScrollMode() const; @@ -153,116 +187,111 @@ public: inline bool isHidden(int row) const; inline int hiddenCount() const; - inline void clearIntersections() const; - inline void appendToIntersections(const QModelIndex &idx) const; - inline bool isRightToLeft() const; QListViewPrivate *dd; QListView *qq; + QSize contentsSize; + int batchStartRow; + int batchSavedDeltaSeg; }; -// ### rename to QListModeViewBase -class QStaticListViewBase : public QCommonListViewBase +class QListModeViewBase : public QCommonListViewBase { - friend class QListViewPrivate; public: - QStaticListViewBase(QListView *q, QListViewPrivate *d) : QCommonListViewBase(q, d), - batchStartRow(0), batchSavedDeltaSeg(0), batchSavedPosition(0) {} + QListModeViewBase(QListView *q, QListViewPrivate *d) : QCommonListViewBase(q, d) {} QVector<int> flowPositions; QVector<int> segmentPositions; QVector<int> segmentStartRows; QVector<int> segmentExtents; - QSize contentsSize; - // used when laying out in batches - int batchStartRow; - int batchSavedDeltaSeg; int batchSavedPosition; + //reimplementations + int itemIndex(const QListViewItem &item) const { return item.indexHint; } + QListViewItem indexToListViewItem(const QModelIndex &index) const; bool doBatchedItemLayout(const QListViewLayoutInfo &info, int max); + void clear(); + void setRowCount(int rowCount) { flowPositions.resize(rowCount); } + QVector<QModelIndex> intersectingSet(const QRect &area) const; + + int horizontalScrollToValue(int index, QListView::ScrollHint hint, + bool leftOf, bool rightOf,const QRect &area, const QRect &rect) const; + int verticalScrollToValue(int index, QListView::ScrollHint hint, + bool above, bool below, const QRect &area, const QRect &rect) const; + void scrollContentsBy(int dx, int dy, bool scrollElasticBand); + QRect mapToViewport(const QRect &rect) const; + int horizontalOffset() const; + int verticalOffset() const; + void updateHorizontalScrollBar(const QSize &step); + void updateVerticalScrollBar(const QSize &step); + +#ifndef QT_NO_DRAGANDDROP + void paintDragDrop(QPainter *painter); +#endif +private: QPoint initStaticLayout(const QListViewLayoutInfo &info); void doStaticLayout(const QListViewLayoutInfo &info); - void intersectingStaticSet(const QRect &area) const; - - int itemIndex(const QListViewItem &item) const; - - int perItemScrollingPageSteps(int length, int bounds, bool wrap) const; - int perItemScrollToValue(int index, int value, int height, QAbstractItemView::ScrollHint hint, Qt::Orientation orientation, bool wrap, int extent) const; - - QRect mapToViewport(const QRect &rect) const; - - QListViewItem indexToListViewItem(const QModelIndex &index) const; - - void scrollContentsBy(int &dx, int &dy); - - int verticalPerItemValue(int itemIndex, int verticalValue, int areaHeight, - bool above, bool below, bool wrap, QListView::ScrollHint hint, int itemHeight) const; - int horizontalPerItemValue(int itemIndex, int horizontalValue, int areaWidth, - bool leftOf, bool rightOf, bool wrap, QListView::ScrollHint hint, int itemWidth) const; - - void clear(); + int perItemScrollingPageSteps(int length, int bounds, bool wrap) const; }; -// ### rename to QIconModeViewBase -class QDynamicListViewBase : public QCommonListViewBase +class QIconModeViewBase : public QCommonListViewBase { - friend class QListViewPrivate; public: - QDynamicListViewBase(QListView *q, QListViewPrivate *d) : QCommonListViewBase(q, d), - batchStartRow(0), batchSavedDeltaSeg(0) {} + QIconModeViewBase(QListView *q, QListViewPrivate *d) : QCommonListViewBase(q, d), interSectingVector(0) {} QBspTree tree; QVector<QListViewItem> items; QBitArray moved; - QSize contentsSize; - QVector<QModelIndex> draggedItems; // indices to the tree.itemVector mutable QPoint draggedItemsPos; // used when laying out in batches - int batchStartRow; - int batchSavedDeltaSeg; + QVector<QModelIndex> *interSectingVector; //used from within intersectingSet - void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + //reimplementations + int itemIndex(const QListViewItem &item) const; + QListViewItem indexToListViewItem(const QModelIndex &index) const; bool doBatchedItemLayout(const QListViewLayoutInfo &info, int max); + void clear(); + void setRowCount(int rowCount); + QVector<QModelIndex> intersectingSet(const QRect &area) const; + + void scrollContentsBy(int dx, int dy, bool scrollElasticBand); + void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + void appendHiddenRow(int row); + void removeHiddenRow(int row); + void setPositionForIndex(const QPoint &position, const QModelIndex &index); + +#ifndef QT_NO_DRAGANDDROP + void paintDragDrop(QPainter *painter); + bool filterDragMoveEvent(QDragMoveEvent *); + bool filterDragLeaveEvent(QDragLeaveEvent *); + bool filterDropEvent(QDropEvent *e); + bool filterStartDrag(Qt::DropActions); +#endif +private: void initBspTree(const QSize &contents); QPoint initDynamicLayout(const QListViewLayoutInfo &info); void doDynamicLayout(const QListViewLayoutInfo &info); - void intersectingDynamicSet(const QRect &area) const; - static void addLeaf(QVector<int> &leaf, const QRect &area, uint visited, QBspTree::Data data); - - void insertItem(int index); - void removeItem(int index); - void moveItem(int index, const QPoint &dest); - - int itemIndex(const QListViewItem &item) const; - - void createItems(int to); - void drawItems(QPainter *painter, const QVector<QModelIndex> &indexes) const; QRect itemsRect(const QVector<QModelIndex> &indexes) const; - - QPoint draggedItemsDelta() const; QRect draggedItemsRect() const; - QPoint snapToGrid(const QPoint &pos) const; - - void scrollElasticBandBy(int dx, int dy); - - QListViewItem indexToListViewItem(const QModelIndex &index) const; - - void clear(); void updateContentsSize(); + QPoint draggedItemsDelta() const; + void drawItems(QPainter *painter, const QVector<QModelIndex> &indexes) const; + void moveItem(int index, const QPoint &dest); + }; class QListViewPrivate: public QAbstractItemViewPrivate @@ -277,26 +306,16 @@ public: bool doItemsLayout(int num); - inline void intersectingSet(const QRect &area, bool doLayout = true) const { + inline QVector<QModelIndex> intersectingSet(const QRect &area, bool doLayout = true) const { if (doLayout) executePostedLayout(); QRect a = (q_func()->isRightToLeft() ? flipX(area.normalized()) : area.normalized()); - if (viewMode == QListView::ListMode) staticListView->intersectingStaticSet(a); - else dynamicListView->intersectingDynamicSet(a); + return commonListView->intersectingSet(a); } - // ### FIXME: - inline void resetBatchStartRow() - { if (viewMode == QListView::ListMode) staticListView->batchStartRow = 0; - else dynamicListView->batchStartRow = 0; } - inline int batchStartRow() const - { return (viewMode == QListView::ListMode - ? staticListView->batchStartRow : dynamicListView->batchStartRow); } - inline QSize contentsSize() const - { return (viewMode == QListView::ListMode - ? staticListView->contentsSize : dynamicListView->contentsSize); } - inline void setContentsSize(int w, int h) - { if (viewMode == QListView::ListMode) staticListView->contentsSize = QSize(w, h); - else dynamicListView->contentsSize = QSize(w, h); } + inline void resetBatchStartRow() { commonListView->batchStartRow = 0; } + inline int batchStartRow() const { return commonListView->batchStartRow; } + inline QSize contentsSize() const { return commonListView->contentsSize; } + inline void setContentsSize(int w, int h) { commonListView->contentsSize = QSize(w, h); } inline int flipX(int x) const { return qMax(viewport->width(), contentsSize().width()) - x; } @@ -307,12 +326,22 @@ public: inline QRect viewItemRect(const QListViewItem &item) const { if (q_func()->isRightToLeft()) return flipX(item.rect()); return item.rect(); } - int itemIndex(const QListViewItem &item) const; QListViewItem indexToListViewItem(const QModelIndex &index) const; inline QModelIndex listViewItemToIndex(const QListViewItem &item) const - { return model->index(itemIndex(item), column, root); } + { return model->index(commonListView->itemIndex(item), column, root); } + + QRect rectForIndex(const QModelIndex &index) const + { + if (!isIndexValid(index) || index.parent() != root || index.column() != column || isHidden(index.row())) + return QRect(); + executePostedLayout(); + return viewItemRect(indexToListViewItem(index)); + } + + void viewUpdateGeometries() { q_func()->updateGeometries(); } - QRect mapToViewport(const QRect &rect, bool greedy = false) const; + + QRect mapToViewport(const QRect &rect, bool extend = true) const; QModelIndex closestIndex(const QRect &target, const QVector<QModelIndex> &candidates) const; QSize itemSize(const QStyleOptionViewItem &option, const QModelIndex &index) const; @@ -351,9 +380,12 @@ public: void scrollElasticBandBy(int dx, int dy); - // ### FIXME: we only need one at a time - QDynamicListViewBase *dynamicListView; - QStaticListViewBase *staticListView; + QItemViewPaintPairs draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const; + + void emitIndexesMoved(const QModelIndexList &indexes) { emit q_func()->indexesMoved(indexes); } + + + QCommonListViewBase *commonListView; // ### FIXME: see if we can move the members into the dynamic/static classes @@ -383,9 +415,6 @@ public: QRect layoutBounds; - // used for intersecting set - mutable QVector<QModelIndex> intersectVector; - // timers QBasicTimer batchLayoutTimer; @@ -414,8 +443,8 @@ inline QPoint QCommonListViewBase::pressedPosition() const { return dd->pressedP inline bool QCommonListViewBase::uniformItemSizes() const { return dd->uniformItemSizes; } inline int QCommonListViewBase::column() const { return dd->column; } -inline int QCommonListViewBase::verticalScrollBarValue() const { return qq->verticalScrollBar()->value(); } -inline int QCommonListViewBase::horizontalScrollBarValue() const { return qq->horizontalScrollBar()->value(); } +inline QScrollBar *QCommonListViewBase::verticalScrollBar() const { return qq->verticalScrollBar(); } +inline QScrollBar *QCommonListViewBase::horizontalScrollBar() const { return qq->horizontalScrollBar(); } inline QListView::ScrollMode QCommonListViewBase::verticalScrollMode() const { return qq->verticalScrollMode(); } inline QListView::ScrollMode QCommonListViewBase::horizontalScrollMode() const { return qq->horizontalScrollMode(); } @@ -438,9 +467,6 @@ inline QAbstractItemDelegate *QCommonListViewBase::delegate(const QModelIndex &i inline bool QCommonListViewBase::isHidden(int row) const { return dd->isHidden(row); } inline int QCommonListViewBase::hiddenCount() const { return dd->hiddenRows.count(); } -inline void QCommonListViewBase::clearIntersections() const { dd->intersectVector.clear(); } -inline void QCommonListViewBase::appendToIntersections(const QModelIndex &idx) const { dd->intersectVector.append(idx); } - inline bool QCommonListViewBase::isRightToLeft() const { return qq->isRightToLeft(); } QT_END_NAMESPACE diff --git a/src/gui/itemviews/qlistwidget.cpp b/src/gui/itemviews/qlistwidget.cpp index 94186b8..b0d5384 100644 --- a/src/gui/itemviews/qlistwidget.cpp +++ b/src/gui/itemviews/qlistwidget.cpp @@ -447,21 +447,20 @@ Qt::DropActions QListModel::supportedDropActions() const \ingroup model-view - QListWidgetItem is used to represent items in a list provided by the - QListWidget class. Each item can hold several pieces of information, - and will display these appropriately. + A QListWidgetItem represents a single item in a QListWidget. Each item can + hold several pieces of information, and will display them appropriately. - The item view convenience classes use a classic item-based interface - rather than a pure model/view approach. For a more flexible list view - widget, consider using the QListView class with a standard model. + The item view convenience classes use a classic item-based interface rather + than a pure model/view approach. For a more flexible list view widget, + consider using the QListView class with a standard model. - List items can be automatically inserted into a list when they are - constructed by specifying the list widget: + List items can be inserted automatically into a list, when they are + constructed, by specifying the list widget: \snippet doc/src/snippets/qlistwidget-using/mainwindow.cpp 2 - They can also be created without a parent widget, and later inserted into - a list (see \l{QListWidget::insertItem()}). + Alternatively, list items can also be created without a parent widget, and + later inserted into a list using QListWidget::insertItem(). List items are typically used to display text() and an icon(). These are set with the setText() and setIcon() functions. The appearance of the text @@ -471,22 +470,24 @@ Qt::DropActions QListModel::supportedDropActions() const with setToolTip(), setStatusTip(), and setWhatsThis(). By default, items are enabled, selectable, checkable, and can be the source - of a drag and drop operation. + of drag and drop operations. + Each item's flags can be changed by calling setFlags() with the appropriate - value (see \l{Qt::ItemFlags}). Checkable items can be checked, unchecked and + value (see Qt::ItemFlags). Checkable items can be checked, unchecked and partially checked with the setCheckState() function. The corresponding - checkState() function indicates what check state the item currently has. + checkState() function indicates the item's current check state. + + The isHidden() function can be used to determine whether the item is + hidden. To hide an item, use setHidden(). - The isHidden() function can be used to determine whether the - item is hidden. Items can be hidden with setHidden(). \section1 Subclassing When subclassing QListWidgetItem to provide custom items, it is possible to - define new types for them so that they can be distinguished from standard - items. The constructors for subclasses that require this feature need to - call the base class constructor with a new type value equal to or greater - than \l UserType. + define new types for them enabling them to be distinguished from standard + items. For subclasses that require this feature, ensure that you call the + base class constructor with a new type value equal to or greater than + \l UserType, within \e your constructor. \sa QListWidget, {Model/View Programming}, QTreeWidgetItem, QTableWidgetItem */ @@ -515,52 +516,58 @@ Qt::DropActions QListModel::supportedDropActions() const /*! \fn QListWidget *QListWidgetItem::listWidget() const - Returns the list widget that contains the item. + Returns the list widget containing the item. */ /*! - \fn void QListWidgetItem::setSelected(bool select) - \since 4.2 + \fn void QListWidgetItem::setSelected(bool select) + \since 4.2 - Sets the selected state of the item to \a select. + Sets the selected state of the item to \a select. - \sa isSelected() + \sa isSelected() */ /*! - \fn bool QListWidgetItem::isSelected() const - \since 4.2 + \fn bool QListWidgetItem::isSelected() const + \since 4.2 - Returns true if the item is selected, otherwise returns false. + Returns true if the item is selected; otherwise returns false. - \sa setSelected() + \sa setSelected() */ /*! - \fn void QListWidgetItem::setHidden(bool hide) - \since 4.2 + \fn void QListWidgetItem::setHidden(bool hide) + \since 4.2 - Hides the item if \a hide is true, otherwise shows the item. + Hides the item if \a hide is true; otherwise shows the item. - \sa isHidden() + \sa isHidden() */ /*! - \fn bool QListWidgetItem::isHidden() const - \since 4.2 + \fn bool QListWidgetItem::isHidden() const + \since 4.2 - Returns true if the item is hidden, otherwise returns false. + Returns true if the item is hidden; otherwise returns false. - \sa setHidden() + \sa setHidden() */ /*! \fn QListWidgetItem::QListWidgetItem(QListWidget *parent, int type) Constructs an empty list widget item of the specified \a type with the - given \a parent. - If the parent is not specified, the item will need to be inserted into a - list widget with QListWidget::insertItem(). + given \a parent. If \a parent is not specified, the item will need to be + inserted into a list widget with QListWidget::insertItem(). + + This constructor inserts the item into the model of the parent that is + passed to the constructor. If the model is sorted then the behavior of the + insert is undetermined since the model will call the \c '<' operator method + on the item which, at this point, is not yet constructed. To avoid the + undetermined behavior, we recommend not to specify the parent and use + QListWidget::insertItem() instead. \sa type() */ @@ -579,9 +586,15 @@ QListWidgetItem::QListWidgetItem(QListWidget *view, int type) \fn QListWidgetItem::QListWidgetItem(const QString &text, QListWidget *parent, int type) Constructs an empty list widget item of the specified \a type with the - given \a text and \a parent. - If the parent is not specified, the item will need to be inserted into a - list widget with QListWidget::insertItem(). + given \a text and \a parent. If the parent is not specified, the item will + need to be inserted into a list widget with QListWidget::insertItem(). + + This constructor inserts the item into the model of the parent that is + passed to the constructor. If the model is sorted then the behavior of the + insert is undetermined since the model will call the \c '<' operator method + on the item which, at this point, is not yet constructed. To avoid the + undetermined behavior, we recommend not to specify the parent and use + QListWidget::insertItem() instead. \sa type() */ @@ -602,9 +615,16 @@ QListWidgetItem::QListWidgetItem(const QString &text, QListWidget *view, int typ \fn QListWidgetItem::QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent, int type) Constructs an empty list widget item of the specified \a type with the - given \a icon, \a text and \a parent. - If the parent is not specified, the item will need to be inserted into a - list widget with QListWidget::insertItem(). + given \a icon, \a text and \a parent. If the parent is not specified, the + item will need to be inserted into a list widget with + QListWidget::insertItem(). + + This constructor inserts the item into the model of the parent that is + passed to the constructor. If the model is sorted then the behavior of the + insert is undetermined since the model will call the \c '<' operator method + on the item which, at this point, is not yet constructed. To avoid the + undetermined behavior, we recommend not to specify the parent and use + QListWidget::insertItem() instead. \sa type() */ @@ -624,7 +644,7 @@ QListWidgetItem::QListWidgetItem(const QIcon &icon,const QString &text, } /*! - Destroys the list item. + Destroys the list item. */ QListWidgetItem::~QListWidgetItem() { @@ -634,7 +654,7 @@ QListWidgetItem::~QListWidgetItem() } /*! - Creates an exact copy of the item. + Creates an exact copy of the item. */ QListWidgetItem *QListWidgetItem::clone() const { @@ -642,11 +662,10 @@ QListWidgetItem *QListWidgetItem::clone() const } /*! - This function sets the data for a given \a role to the given \a value (see - \l{Qt::ItemDataRole}). Reimplement this function if you need - extra roles or special behavior for certain roles. + Sets the data for a given \a role to the given \a value. Reimplement this + function if you need extra roles or special behavior for certain roles. - \sa Qt::ItemDataRole, data() + \sa Qt::ItemDataRole, data() */ void QListWidgetItem::setData(int role, const QVariant &value) { @@ -668,9 +687,10 @@ void QListWidgetItem::setData(int role, const QVariant &value) } /*! - This function returns the item's data for a given \a role (see - Qt::ItemDataRole). Reimplement this function if you need - extra roles or special behavior for certain roles. + Returns the item's data for a given \a role. Reimplement this function if + you need extra roles or special behavior for certain roles. + + \sa Qt::ItemDataRole, setData() */ QVariant QListWidgetItem::data(int role) const { @@ -682,12 +702,13 @@ QVariant QListWidgetItem::data(int role) const } /*! - Returns true if this item's text is less then \a other item's text; - otherwise returns false. + Returns true if this item's text is less then \a other item's text; + otherwise returns false. */ bool QListWidgetItem::operator<(const QListWidgetItem &other) const { - return text() < other.text(); + const QVariant v1 = data(Qt::DisplayRole), v2 = other.data(Qt::DisplayRole); + return QAbstractItemModelPrivate::variantLessThan(v1, v2); } #ifndef QT_NO_DATASTREAM @@ -711,12 +732,13 @@ void QListWidgetItem::write(QDataStream &out) const { out << d->values; } +#endif // QT_NO_DATASTREAM /*! \since 4.1 - Constructs a copy of \a other. Note that type() and listWidget() - are not copied. + Constructs a copy of \a other. Note that type() and listWidget() are not + copied. This function is useful when reimplementing clone(). @@ -731,8 +753,8 @@ QListWidgetItem::QListWidgetItem(const QListWidgetItem &other) } /*! - Assigns \a other's data and flags to this item. Note that type() - and listWidget() are not copied. + Assigns \a other's data and flags to this item. Note that type() and + listWidget() are not copied. This function is useful when reimplementing clone(). @@ -745,6 +767,8 @@ QListWidgetItem &QListWidgetItem::operator=(const QListWidgetItem &other) return *this; } +#ifndef QT_NO_DATASTREAM + /*! \relates QListWidgetItem @@ -778,9 +802,9 @@ QDataStream &operator>>(QDataStream &in, QListWidgetItem &item) #endif // QT_NO_DATASTREAM /*! - \fn Qt::ItemFlags QListWidgetItem::flags() const + \fn Qt::ItemFlags QListWidgetItem::flags() const - Returns the item flags for this item (see \l{Qt::ItemFlags}). + Returns the item flags for this item (see \l{Qt::ItemFlags}). */ /*! @@ -824,15 +848,17 @@ QDataStream &operator>>(QDataStream &in, QListWidgetItem &item) */ /*! - \fn QFont QListWidgetItem::font() const + \fn QFont QListWidgetItem::font() const - Returns the font used to display this list item's text. + Returns the font used to display this list item's text. */ /*! - \fn int QListWidgetItem::textAlignment() const + \fn int QListWidgetItem::textAlignment() const + + Returns the text alignment for the list item. - Returns the text alignment for the list item (see \l{Qt::AlignmentFlag}). + \sa Qt::AlignmentFlag */ /*! @@ -878,26 +904,26 @@ QDataStream &operator>>(QDataStream &in, QListWidgetItem &item) */ /*! - \fn QSize QListWidgetItem::sizeHint() const - \since 4.1 + \fn QSize QListWidgetItem::sizeHint() const + \since 4.1 - Returns the size hint set for the list item. + Returns the size hint set for the list item. */ /*! - \fn void QListWidgetItem::setSizeHint(const QSize &size) - \since 4.1 + \fn void QListWidgetItem::setSizeHint(const QSize &size) + \since 4.1 - Sets the size hint for the list item to be \a size. - If no size hint is set, the item delegate will compute the - size hint based on the item data. + Sets the size hint for the list item to be \a size. If no size hint is set, + the item delegate will compute the size hint based on the item data. */ /*! - \fn void QListWidgetItem::setFlags(Qt::ItemFlags flags) + \fn void QListWidgetItem::setFlags(Qt::ItemFlags flags) - Sets the item flags for the list item to \a flags (see - \l{Qt::ItemFlags}). + Sets the item flags for the list item to \a flags. + + \sa Qt::ItemFlags */ void QListWidgetItem::setFlags(Qt::ItemFlags aflags) { itemFlags = aflags; @@ -926,10 +952,10 @@ void QListWidgetItem::setFlags(Qt::ItemFlags aflags) { \fn void QListWidgetItem::setStatusTip(const QString &statusTip) Sets the status tip for the list item to the text specified by - \a statusTip. QListWidget mouse tracking needs to be enabled for this + \a statusTip. QListWidget mouseTracking needs to be enabled for this feature to work. - \sa statusTip() setToolTip() setWhatsThis() + \sa statusTip(), setToolTip(), setWhatsThis(), QWidget::setMouseTracking() */ /*! @@ -937,29 +963,30 @@ void QListWidgetItem::setFlags(Qt::ItemFlags aflags) { Sets the tooltip for the list item to the text specified by \a toolTip. - \sa toolTip() setStatusTip() setWhatsThis() + \sa toolTip(), setStatusTip(), setWhatsThis() */ /*! \fn void QListWidgetItem::setWhatsThis(const QString &whatsThis) - Sets the "What's This?" help for the list item to the text specified - by \a whatsThis. + Sets the "What's This?" help for the list item to the text specified by + \a whatsThis. - \sa whatsThis() setStatusTip() setToolTip() + \sa whatsThis(), setStatusTip(), setToolTip() */ /*! - \fn void QListWidgetItem::setFont(const QFont &font) + \fn void QListWidgetItem::setFont(const QFont &font) - Sets the font used when painting the item to the given \a font. + Sets the font used when painting the item to the given \a font. */ /*! - \fn void QListWidgetItem::setTextAlignment(int alignment) + \fn void QListWidgetItem::setTextAlignment(int alignment) + + Sets the list item's text alignment to \a alignment. - Sets the list item's text alignment to \a alignment (see - \l{Qt::AlignmentFlag}). + \sa Qt::AlignmentFlag */ /*! @@ -1014,51 +1041,51 @@ void QListWidgetPrivate::setup() QObject::connect(q, SIGNAL(activated(QModelIndex)), q, SLOT(_q_emitItemActivated(QModelIndex))); QObject::connect(q, SIGNAL(entered(QModelIndex)), q, SLOT(_q_emitItemEntered(QModelIndex))); - QObject::connect(model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), + QObject::connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), q, SLOT(_q_emitItemChanged(QModelIndex))); QObject::connect(q->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), q, SLOT(_q_emitCurrentItemChanged(QModelIndex,QModelIndex))); QObject::connect(q->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), q, SIGNAL(itemSelectionChanged())); - QObject::connect(model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), + QObject::connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), q, SLOT(_q_dataChanged(QModelIndex,QModelIndex))); - QObject::connect(model(), SIGNAL(columnsRemoved(QModelIndex,int,int)), q, SLOT(_q_sort())); + QObject::connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)), q, SLOT(_q_sort())); } void QListWidgetPrivate::_q_emitItemPressed(const QModelIndex &index) { Q_Q(QListWidget); - emit q->itemPressed(model()->at(index.row())); + emit q->itemPressed(listModel()->at(index.row())); } void QListWidgetPrivate::_q_emitItemClicked(const QModelIndex &index) { Q_Q(QListWidget); - emit q->itemClicked(model()->at(index.row())); + emit q->itemClicked(listModel()->at(index.row())); } void QListWidgetPrivate::_q_emitItemDoubleClicked(const QModelIndex &index) { Q_Q(QListWidget); - emit q->itemDoubleClicked(model()->at(index.row())); + emit q->itemDoubleClicked(listModel()->at(index.row())); } void QListWidgetPrivate::_q_emitItemActivated(const QModelIndex &index) { Q_Q(QListWidget); - emit q->itemActivated(model()->at(index.row())); + emit q->itemActivated(listModel()->at(index.row())); } void QListWidgetPrivate::_q_emitItemEntered(const QModelIndex &index) { Q_Q(QListWidget); - emit q->itemEntered(model()->at(index.row())); + emit q->itemEntered(listModel()->at(index.row())); } void QListWidgetPrivate::_q_emitItemChanged(const QModelIndex &index) { Q_Q(QListWidget); - emit q->itemChanged(model()->at(index.row())); + emit q->itemChanged(listModel()->at(index.row())); } void QListWidgetPrivate::_q_emitCurrentItemChanged(const QModelIndex ¤t, @@ -1066,8 +1093,8 @@ void QListWidgetPrivate::_q_emitCurrentItemChanged(const QModelIndex ¤t, { Q_Q(QListWidget); QPersistentModelIndex persistentCurrent = current; - QListWidgetItem *currentItem = model()->at(persistentCurrent.row()); - emit q->currentItemChanged(currentItem, model()->at(previous.row())); + QListWidgetItem *currentItem = listModel()->at(persistentCurrent.row()); + emit q->currentItemChanged(currentItem, listModel()->at(previous.row())); //persistentCurrent is invalid if something changed the model in response //to the currentItemChanged signal emission and the item was removed @@ -1082,14 +1109,14 @@ void QListWidgetPrivate::_q_emitCurrentItemChanged(const QModelIndex ¤t, void QListWidgetPrivate::_q_sort() { if (sortingEnabled) - model()->sort(0, sortOrder); + model->sort(0, sortOrder); } void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { if (sortingEnabled && topLeft.isValid() && bottomRight.isValid()) - model()->ensureSorted(topLeft.column(), sortOrder, + listModel()->ensureSorted(topLeft.column(), sortOrder, topLeft.row(), bottomRight.row()); } @@ -1098,12 +1125,12 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, \brief The QListWidget class provides an item-based list widget. \ingroup model-view - \mainclass - QListWidget is a convenience class that provides a list view similar to - the one supplied by QListView, but with a classic item-based interface - for adding and removing items. QListWidget uses an internal model to - manage each QListWidgetItem in the list. + + QListWidget is a convenience class that provides a list view similar to the + one supplied by QListView, but with a classic item-based interface for + adding and removing items. QListWidget uses an internal model to manage + each QListWidgetItem in the list. For a more flexible list view widget, use the QListView class with a standard model. @@ -1118,23 +1145,23 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, function. There are two ways to add items to the list: they can be constructed with - the list widget as their parent widget, or they can be constructed with - no parent widget and added to the list later. If a list widget already - exists when the items are constructed, the first method is easier to use: + the list widget as their parent widget, or they can be constructed with no + parent widget and added to the list later. If a list widget already exists + when the items are constructed, the first method is easier to use: \snippet doc/src/snippets/qlistwidget-using/mainwindow.cpp 1 - If you need to insert a new item into the list at a particular position, - it is more required to construct the item without a parent widget and - use the insertItem() function to place it within the list. The list - widget will take ownership of the item. + If you need to insert a new item into the list at a particular position, it + is more required to construct the item without a parent widget and use the + insertItem() function to place it within the list. The list widget will + take ownership of the item. \snippet doc/src/snippets/qlistwidget-using/mainwindow.cpp 6 \snippet doc/src/snippets/qlistwidget-using/mainwindow.cpp 7 - For multiple items, insertItems() can be used instead. The number of - items in the list is found with the count() function. - To remove items from the list, use takeItem(). + For multiple items, insertItems() can be used instead. The number of items + in the list is found with the count() function. To remove items from the + list, use takeItem(). The current item in the list can be found with currentItem(), and changed with setCurrentItem(). The user can also change the current item by @@ -1160,9 +1187,9 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, Inserts the \a item at the end of the list widget. - \warning A QListWidgetItem can only be added to a - QListWidget once. Adding the same QListWidgetItem multiple - times to a QListWidget will result in undefined behavior. + \warning A QListWidgetItem can only be added to a QListWidget once. Adding + the same QListWidgetItem multiple times to a QListWidget will result in + undefined behavior. \sa insertItem() */ @@ -1170,8 +1197,7 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, /*! \fn void QListWidget::addItem(const QString &label) - Inserts an item with the text \a label at the end of the list - widget. + Inserts an item with the text \a label at the end of the list widget. */ /*! @@ -1185,8 +1211,8 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, /*! \fn void QListWidget::itemPressed(QListWidgetItem *item) - This signal is emitted with the specified \a item when a mouse button is pressed - on an item in the widget. + This signal is emitted with the specified \a item when a mouse button is + pressed on an item in the widget. \sa itemClicked(), itemDoubleClicked() */ @@ -1194,8 +1220,8 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, /*! \fn void QListWidget::itemClicked(QListWidgetItem *item) - This signal is emitted with the specified \a item when a mouse button is clicked - on an item in the widget. + This signal is emitted with the specified \a item when a mouse button is + clicked on an item in the widget. \sa itemPressed(), itemDoubleClicked() */ @@ -1203,8 +1229,8 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, /*! \fn void QListWidget::itemDoubleClicked(QListWidgetItem *item) - This signal is emitted with the specified \a item when a mouse button is double - clicked on an item in the widget. + This signal is emitted with the specified \a item when a mouse button is + double clicked on an item in the widget. \sa itemClicked(), itemPressed() */ @@ -1212,20 +1238,21 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, /*! \fn void QListWidget::itemActivated(QListWidgetItem *item) - This signal is emitted when the \a item is activated. The \a item - is activated when the user clicks or double clicks on it, - depending on the system configuration. It is also activated when - the user presses the activation key (on Windows and X11 this is - the \gui Return key, on Mac OS X it is \key{Ctrl+0}). + This signal is emitted when the \a item is activated. The \a item is + activated when the user clicks or double clicks on it, depending on the + system configuration. It is also activated when the user presses the + activation key (on Windows and X11 this is the \gui Return key, on Mac OS + X it is \key{Ctrl+0}). */ /*! \fn void QListWidget::itemEntered(QListWidgetItem *item) - This signal is emitted when the mouse cursor enters an item. The - \a item is the item entered. This signal is only emitted when - mouseTracking is turned on, or when a mouse button is pressed - while moving into an item. + This signal is emitted when the mouse cursor enters an item. The \a item is + the item entered. This signal is only emitted when mouseTracking is turned + on, or when a mouse button is pressed while moving into an item. + + \sa QWidget::setMouseTracking() */ /*! @@ -1237,24 +1264,28 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, /*! \fn void QListWidget::currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous) - This signal is emitted whenever the current item changes. The \a - previous item is the item that previously had the focus, \a - current is the new current item. + This signal is emitted whenever the current item changes. + + \a previous is the item that previously had the focus; \a current is the + new current item. */ /*! - \fn void QListWidget::currentTextChanged(const QString ¤tText) + \fn void QListWidget::currentTextChanged(const QString ¤tText) + + This signal is emitted whenever the current item changes. - This signal is emitted whenever the current item changes. The \a currentText - is the text data in the current item. If there is no current item, the \a currentText - is invalid. + \a currentText is the text data in the current item. If there is no current + item, the \a currentText is invalid. */ /*! - \fn void QListWidget::currentRowChanged(int currentRow) + \fn void QListWidget::currentRowChanged(int currentRow) - This signal is emitted whenever the current item changes. The \a currentRow - is the row of the current item. If there is no current item, the \a currentRow is -1. + This signal is emitted whenever the current item changes. + + \a currentRow is the row of the current item. If there is no current item, + the \a currentRow is -1. */ /*! @@ -1262,15 +1293,15 @@ void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, This signal is emitted whenever the selection changes. - \sa selectedItems() isItemSelected() currentItemChanged() + \sa selectedItems(), QListWidgetItem::isSelected(), currentItemChanged() */ /*! - \since 4.3 + \since 4.3 - \fn void QListWidget::removeItemWidget(QListWidgetItem *item) + \fn void QListWidget::removeItemWidget(QListWidgetItem *item) - Removes the widget set on the given \a item. + Removes the widget set on the given \a item. */ /*! @@ -1302,9 +1333,9 @@ QListWidget::~QListWidget() QListWidgetItem *QListWidget::item(int row) const { Q_D(const QListWidget); - if (row < 0 || row >= d->model()->rowCount()) + if (row < 0 || row >= d->model->rowCount()) return 0; - return d->model()->at(row); + return d->listModel()->at(row); } /*! @@ -1316,7 +1347,7 @@ QListWidgetItem *QListWidget::item(int row) const int QListWidget::row(const QListWidgetItem *item) const { Q_D(const QListWidget); - return d->model()->index(const_cast<QListWidgetItem*>(item)).row(); + return d->listModel()->index(const_cast<QListWidgetItem*>(item)).row(); } @@ -1330,12 +1361,12 @@ void QListWidget::insertItem(int row, QListWidgetItem *item) { Q_D(QListWidget); if (item && !item->view) - d->model()->insert(row, item); + d->listModel()->insert(row, item); } /*! - Inserts an item with the text \a label in the list widget at the - position given by \a row. + Inserts an item with the text \a label in the list widget at the position + given by \a row. \sa addItem() */ @@ -1343,7 +1374,7 @@ void QListWidget::insertItem(int row, QListWidgetItem *item) void QListWidget::insertItem(int row, const QString &label) { Q_D(QListWidget); - d->model()->insert(row, new QListWidgetItem(label)); + d->listModel()->insert(row, new QListWidgetItem(label)); } /*! @@ -1356,15 +1387,15 @@ void QListWidget::insertItem(int row, const QString &label) void QListWidget::insertItems(int row, const QStringList &labels) { Q_D(QListWidget); - d->model()->insert(row, labels); + d->listModel()->insert(row, labels); } /*! - Removes and returns the item from the given \a row in the list widget; otherwise - returns 0. + Removes and returns the item from the given \a row in the list widget; + otherwise returns 0. - Items removed from a list widget will not be managed by Qt, and will need to be - deleted manually. + Items removed from a list widget will not be managed by Qt, and will need + to be deleted manually. \sa insertItem(), addItem() */ @@ -1372,36 +1403,37 @@ void QListWidget::insertItems(int row, const QStringList &labels) QListWidgetItem *QListWidget::takeItem(int row) { Q_D(QListWidget); - if (row < 0 || row >= d->model()->rowCount()) + if (row < 0 || row >= d->model->rowCount()) return 0; - return d->model()->take(row); + return d->listModel()->take(row); } /*! - \property QListWidget::count - \brief the number of items in the list including any hidden items. + \property QListWidget::count + \brief the number of items in the list including any hidden items. */ int QListWidget::count() const { Q_D(const QListWidget); - return d->model()->rowCount(); + return d->model->rowCount(); } /*! - Returns the current item. + Returns the current item. */ QListWidgetItem *QListWidget::currentItem() const { Q_D(const QListWidget); - return d->model()->at(currentIndex().row()); + return d->listModel()->at(currentIndex().row()); } /*! - Sets the current item to \a item. + Sets the current item to \a item. - Depending on the current selection mode, the item may also be selected. + Unless the selection mode is \l{QAbstractItemView::}{NoSelection}, + the item is also be selected. */ void QListWidget::setCurrentItem(QListWidgetItem *item) { @@ -1409,8 +1441,8 @@ void QListWidget::setCurrentItem(QListWidgetItem *item) } /*! - \since 4.4 - Set the current item to \a item, using the given \a command. + \since 4.4 + Set the current item to \a item, using the given \a command. */ void QListWidget::setCurrentItem(QListWidgetItem *item, QItemSelectionModel::SelectionFlags command) { @@ -1418,10 +1450,10 @@ void QListWidget::setCurrentItem(QListWidgetItem *item, QItemSelectionModel::Sel } /*! - \property QListWidget::currentRow - \brief the row of the current item. + \property QListWidget::currentRow + \brief the row of the current item. - Depending on the current selection mode, the row may also be selected. + Depending on the current selection mode, the row may also be selected. */ int QListWidget::currentRow() const @@ -1432,7 +1464,7 @@ int QListWidget::currentRow() const void QListWidget::setCurrentRow(int row) { Q_D(QListWidget); - QModelIndex index = d->model()->index(row); + QModelIndex index = d->listModel()->index(row); if (d->selectionMode == SingleSelection) selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect); else if (d->selectionMode == NoSelection) @@ -1442,14 +1474,14 @@ void QListWidget::setCurrentRow(int row) } /*! - \since 4.4 + \since 4.4 - Sets the current row to be the given \a row, using the given \a command, + Sets the current row to be the given \a row, using the given \a command, */ void QListWidget::setCurrentRow(int row, QItemSelectionModel::SelectionFlags command) { Q_D(QListWidget); - d->selectionModel->setCurrentIndex(d->model()->index(row), command); + d->selectionModel->setCurrentIndex(d->listModel()->index(row), command); } /*! @@ -1458,7 +1490,7 @@ void QListWidget::setCurrentRow(int row, QItemSelectionModel::SelectionFlags com QListWidgetItem *QListWidget::itemAt(const QPoint &p) const { Q_D(const QListWidget); - return d->model()->at(indexAt(p).row()); + return d->listModel()->at(indexAt(p).row()); } @@ -1471,23 +1503,23 @@ QListWidgetItem *QListWidget::itemAt(const QPoint &p) const /*! - Returns the rectangle on the viewport occupied by the item at \a item. + Returns the rectangle on the viewport occupied by the item at \a item. */ QRect QListWidget::visualItemRect(const QListWidgetItem *item) const { Q_D(const QListWidget); - QModelIndex index = d->model()->index(const_cast<QListWidgetItem*>(item)); + QModelIndex index = d->listModel()->index(const_cast<QListWidgetItem*>(item)); return visualRect(index); } /*! - Sorts all the items in the list widget according to the specified \a order. + Sorts all the items in the list widget according to the specified \a order. */ void QListWidget::sortItems(Qt::SortOrder order) { Q_D(QListWidget); d->sortOrder = order; - d->model()->sort(0, order); + d->listModel()->sort(0, order); } /*! @@ -1495,8 +1527,10 @@ void QListWidget::sortItems(Qt::SortOrder order) \property QListWidget::sortingEnabled \brief whether sorting is enabled - If this property is true, sorting is enabled for the list; if the - property is false, sorting is not enabled. The default value is false. + If this property is true, sorting is enabled for the list; if the property + is false, sorting is not enabled. + + The default value is false. */ void QListWidget::setSortingEnabled(bool enable) { @@ -1511,7 +1545,7 @@ bool QListWidget::isSortingEnabled() const } /*! - \internal + \internal */ Qt::SortOrder QListWidget::sortOrder() const { @@ -1520,36 +1554,37 @@ Qt::SortOrder QListWidget::sortOrder() const } /*! - Starts editing the \a item if it is editable. + Starts editing the \a item if it is editable. */ void QListWidget::editItem(QListWidgetItem *item) { Q_D(QListWidget); - edit(d->model()->index(item)); + edit(d->listModel()->index(item)); } /*! - Opens an editor for the given \a item. The editor remains open after editing. + Opens an editor for the given \a item. The editor remains open after + editing. - \sa closePersistentEditor() + \sa closePersistentEditor() */ void QListWidget::openPersistentEditor(QListWidgetItem *item) { Q_D(QListWidget); - QModelIndex index = d->model()->index(item); + QModelIndex index = d->listModel()->index(item); QAbstractItemView::openPersistentEditor(index); } /*! - Closes the persistent editor for the given \a item. + Closes the persistent editor for the given \a item. - \sa openPersistentEditor() + \sa openPersistentEditor() */ void QListWidget::closePersistentEditor(QListWidgetItem *item) { Q_D(QListWidget); - QModelIndex index = d->model()->index(item); + QModelIndex index = d->listModel()->index(item); QAbstractItemView::closePersistentEditor(index); } @@ -1561,7 +1596,7 @@ void QListWidget::closePersistentEditor(QListWidgetItem *item) QWidget *QListWidget::itemWidget(QListWidgetItem *item) const { Q_D(const QListWidget); - QModelIndex index = d->model()->index(item); + QModelIndex index = d->listModel()->index(item); return QAbstractItemView::indexWidget(index); } @@ -1570,45 +1605,46 @@ QWidget *QListWidget::itemWidget(QListWidgetItem *item) const Sets the \a widget to be displayed in the give \a item. - This function should only be used to display static content in the place of a list - widget item. If you want to display custom dynamic content or implement a custom - editor widget, use QListView and subclass QItemDelegate instead. + This function should only be used to display static content in the place of + a list widget item. If you want to display custom dynamic content or + implement a custom editor widget, use QListView and subclass QItemDelegate + instead. \sa {Delegate Classes} */ void QListWidget::setItemWidget(QListWidgetItem *item, QWidget *widget) { Q_D(QListWidget); - QModelIndex index = d->model()->index(item); + QModelIndex index = d->listModel()->index(item); QAbstractItemView::setIndexWidget(index, widget); } /*! - Returns true if \a item is selected; otherwise returns false. + Returns true if \a item is selected; otherwise returns false. - \obsolete + \obsolete - This function is deprecated. Use \l{QListWidgetItem::isSelected()} instead. + This function is deprecated. Use QListWidgetItem::isSelected() instead. */ bool QListWidget::isItemSelected(const QListWidgetItem *item) const { Q_D(const QListWidget); - QModelIndex index = d->model()->index(const_cast<QListWidgetItem*>(item)); + QModelIndex index = d->listModel()->index(const_cast<QListWidgetItem*>(item)); return selectionModel()->isSelected(index); } /*! - Selects or deselects the given \a item depending on whether \a select is - true of false. + Selects or deselects the given \a item depending on whether \a select is + true of false. - \obsolete + \obsolete - This function is deprecated. Use \l{QListWidgetItem::setSelected()} instead. + This function is deprecated. Use QListWidgetItem::setSelected() instead. */ void QListWidget::setItemSelected(const QListWidgetItem *item, bool select) { Q_D(QListWidget); - QModelIndex index = d->model()->index(const_cast<QListWidgetItem*>(item)); + QModelIndex index = d->listModel()->index(const_cast<QListWidgetItem*>(item)); if (d->selectionMode == SingleSelection) { selectionModel()->select(index, select @@ -1623,7 +1659,7 @@ void QListWidget::setItemSelected(const QListWidgetItem *item, bool select) } /*! - Returns a list of all selected items in the list widget. + Returns a list of all selected items in the list widget. */ QList<QListWidgetItem*> QListWidget::selectedItems() const @@ -1632,31 +1668,32 @@ QList<QListWidgetItem*> QListWidget::selectedItems() const QModelIndexList indexes = selectionModel()->selectedIndexes(); QList<QListWidgetItem*> items; for (int i = 0; i < indexes.count(); ++i) - items.append(d->model()->at(indexes.at(i).row())); + items.append(d->listModel()->at(indexes.at(i).row())); return items; } /*! - Finds items with the text that matches the string \a text using the given \a flags. + Finds items with the text that matches the string \a text using the given + \a flags. */ QList<QListWidgetItem*> QListWidget::findItems(const QString &text, Qt::MatchFlags flags) const { Q_D(const QListWidget); - QModelIndexList indexes = d->model()->match(model()->index(0, 0, QModelIndex()), + QModelIndexList indexes = d->listModel()->match(model()->index(0, 0, QModelIndex()), Qt::DisplayRole, text, -1, flags); QList<QListWidgetItem*> items; for (int i = 0; i < indexes.size(); ++i) - items.append(d->model()->at(indexes.at(i).row())); + items.append(d->listModel()->at(indexes.at(i).row())); return items; } /*! - Returns true if the \a item is explicitly hidden; otherwise returns false. + Returns true if the \a item is explicitly hidden; otherwise returns false. - \obsolete + \obsolete - This function is deprecated. Use \l{QListWidgetItem::isHidden()} instead. + This function is deprecated. Use QListWidgetItem::isHidden() instead. */ bool QListWidget::isItemHidden(const QListWidgetItem *item) const { @@ -1664,11 +1701,11 @@ bool QListWidget::isItemHidden(const QListWidgetItem *item) const } /*! - If \a hide is true, the \a item will be hidden; otherwise it will be shown. + If \a hide is true, the \a item will be hidden; otherwise it will be shown. - \obsolete + \obsolete - This function is deprecated. Use \l{QListWidgetItem::setHidden()} instead. + This function is deprecated. Use QListWidgetItem::setHidden() instead. */ void QListWidget::setItemHidden(const QListWidgetItem *item, bool hide) { @@ -1676,28 +1713,28 @@ void QListWidget::setItemHidden(const QListWidgetItem *item, bool hide) } /*! - Scrolls the view if necessary to ensure that the \a item is - visible. The \a hint parameter specifies more precisely where the - \a item should be located after the operation. + Scrolls the view if necessary to ensure that the \a item is visible. + + \a hint specifies where the \a item should be located after the operation. */ void QListWidget::scrollToItem(const QListWidgetItem *item, QAbstractItemView::ScrollHint hint) { Q_D(QListWidget); - QModelIndex index = d->model()->index(const_cast<QListWidgetItem*>(item)); + QModelIndex index = d->listModel()->index(const_cast<QListWidgetItem*>(item)); QListView::scrollTo(index, hint); } /*! Removes all items and selections in the view. - \note All items will be permanently deleted. + \warning All items will be permanently deleted. */ void QListWidget::clear() { Q_D(QListWidget); selectionModel()->clear(); - d->model()->clear(); + d->listModel()->clear(); } /*! @@ -1708,7 +1745,7 @@ void QListWidget::clear() */ QStringList QListWidget::mimeTypes() const { - return d_func()->model()->QAbstractListModel::mimeTypes(); + return d_func()->listModel()->QAbstractListModel::mimeTypes(); } /*! @@ -1716,20 +1753,19 @@ QStringList QListWidget::mimeTypes() const \a items. The format used to describe the items is obtained from the mimeTypes() function. - If the list of items is empty, 0 is returned rather than a serialized - empty list. + If the list of items is empty, 0 is returned instead of a serialized empty + list. */ QMimeData *QListWidget::mimeData(const QList<QListWidgetItem*>) const { - return d_func()->model()->internalMimeData(); + return d_func()->listModel()->internalMimeData(); } #ifndef QT_NO_DRAGANDDROP /*! - Handles the \a data supplied by an external drag and drop operation - that ended with the given \a action in the given \a index. - Returns true if the data and action can be handled by the model; - otherwise returns false. + Handles \a data supplied by an external drag and drop operation that ended + with the given \a action in the given \a index. Returns true if \a data and + \a action can be handled by the model; otherwise returns false. \sa supportedDropActions() */ @@ -1744,7 +1780,7 @@ bool QListWidget::dropMimeData(int index, const QMimeData *data, Qt::DropAction row = -1; column = -1; } - return d_func()->model()->QAbstractListModel::dropMimeData(data, action , row, column, idx); + return d_func()->listModel()->QAbstractListModel::dropMimeData(data, action , row, column, idx); } /*! \reimp */ @@ -1796,21 +1832,21 @@ void QListWidget::dropEvent(QDropEvent *event) { } /*! - Returns the drop actions supported by this view. + Returns the drop actions supported by this view. - \sa Qt::DropActions + \sa Qt::DropActions */ Qt::DropActions QListWidget::supportedDropActions() const { Q_D(const QListWidget); - return d->model()->QAbstractListModel::supportedDropActions() | Qt::MoveAction; + return d->listModel()->QAbstractListModel::supportedDropActions() | Qt::MoveAction; } #endif // QT_NO_DRAGANDDROP /*! - Returns a list of pointers to the items contained in the \a data object. - If the object was not created by a QListWidget in the same process, the list - is empty. + Returns a list of pointers to the items contained in the \a data object. If + the object was not created by a QListWidget in the same process, the list + is empty. */ QList<QListWidgetItem*> QListWidget::items(const QMimeData *data) const { @@ -1821,29 +1857,29 @@ QList<QListWidgetItem*> QListWidget::items(const QMimeData *data) const } /*! - Returns the QModelIndex assocated with the given \a item. + Returns the QModelIndex assocated with the given \a item. */ QModelIndex QListWidget::indexFromItem(QListWidgetItem *item) const { Q_D(const QListWidget); - return d->model()->index(item); + return d->listModel()->index(item); } /*! - Returns a pointer to the QListWidgetItem assocated with the given \a index. + Returns a pointer to the QListWidgetItem assocated with the given \a index. */ QListWidgetItem *QListWidget::itemFromIndex(const QModelIndex &index) const { Q_D(const QListWidget); if (d->isIndexValid(index)) - return d->model()->at(index.row()); + return d->listModel()->at(index.row()); return 0; } /*! - \internal + \internal */ void QListWidget::setModel(QAbstractItemModel * /*model*/) { diff --git a/src/gui/itemviews/qlistwidget_p.h b/src/gui/itemviews/qlistwidget_p.h index 13ef414..9820ba4 100644 --- a/src/gui/itemviews/qlistwidget_p.h +++ b/src/gui/itemviews/qlistwidget_p.h @@ -143,7 +143,7 @@ class QListWidgetPrivate : public QListViewPrivate Q_DECLARE_PUBLIC(QListWidget) public: QListWidgetPrivate() : QListViewPrivate(), sortOrder(Qt::AscendingOrder), sortingEnabled(false) {} - inline QListModel *model() const { return qobject_cast<QListModel*>(q_func()->model()); } + inline QListModel *listModel() const { return qobject_cast<QListModel*>(model); } void setup(); void _q_emitItemPressed(const QModelIndex &index); void _q_emitItemClicked(const QModelIndex &index); @@ -163,7 +163,6 @@ class QListWidgetItemPrivate public: QListWidgetItemPrivate(QListWidgetItem *item) : q(item), theid(-1) {} QListWidgetItem *q; - int id; QVector<QWidgetItemData> values; int theid; }; diff --git a/src/gui/itemviews/qsortfilterproxymodel.cpp b/src/gui/itemviews/qsortfilterproxymodel.cpp index 36bbb74..df13df3 100644 --- a/src/gui/itemviews/qsortfilterproxymodel.cpp +++ b/src/gui/itemviews/qsortfilterproxymodel.cpp @@ -56,6 +56,15 @@ QT_BEGIN_NAMESPACE typedef QList<QPair<QModelIndex, QPersistentModelIndex> > QModelIndexPairList; +static inline QSet<int> qVectorToSet(const QVector<int> &vector) +{ + QSet<int> set; + set.reserve(vector.size()); + for(int i=0; i < vector.size(); ++i) + set << vector.at(i); + return set; +} + class QSortFilterProxyModelLessThan { public: @@ -137,6 +146,7 @@ public: const QModelIndex &source_parent) const; QModelIndex proxy_to_source(const QModelIndex &proxyIndex) const; QModelIndex source_to_proxy(const QModelIndex &sourceIndex) const; + bool can_create_mapping(const QModelIndex &source_parent) const; void remove_from_mapping(const QModelIndex &source_parent); @@ -164,6 +174,7 @@ public: const QModelIndex &source_bottom_right); void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int start, int end); + void _q_sourceAboutToBeReset(); void _q_sourceReset(); void _q_sourceLayoutAboutToBeChanged(); @@ -224,8 +235,8 @@ public: QModelIndexPairList store_persistent_indexes(); void update_persistent_indexes(const QModelIndexPairList &source_indexes); - void filter_changed(); - void handle_filter_changed( + void filter_changed(const QModelIndex &source_parent = QModelIndex()); + QSet<int> handle_filter_changed( QVector<int> &source_to_proxy, QVector<int> &proxy_to_source, const QModelIndex &source_parent, Qt::Orientation orient); @@ -345,6 +356,25 @@ QModelIndex QSortFilterProxyModelPrivate::source_to_proxy(const QModelIndex &sou return create_index(proxy_row, proxy_column, it); } +bool QSortFilterProxyModelPrivate::can_create_mapping(const QModelIndex &source_parent) const +{ + if (source_parent.isValid()) { + QModelIndex source_grand_parent = source_parent.parent(); + IndexMap::const_iterator it = source_index_mapping.constFind(source_grand_parent); + if (it == source_index_mapping.constEnd()) { + // Don't care, since we don't have mapping for the grand parent + return false; + } + Mapping *gm = it.value(); + if (gm->proxy_rows.at(source_parent.row()) == -1 || + gm->proxy_columns.at(source_parent.column()) == -1) { + // Don't care, since parent is filtered + return false; + } + } + return true; +} + /*! \internal @@ -650,20 +680,8 @@ void QSortFilterProxyModelPrivate::source_items_inserted( return; IndexMap::const_iterator it = source_index_mapping.constFind(source_parent); if (it == source_index_mapping.constEnd()) { - if (source_parent.isValid()) { - QModelIndex source_grand_parent = source_parent.parent(); - it = source_index_mapping.constFind(source_grand_parent); - if (it == source_index_mapping.constEnd()) { - // Don't care, since we don't have mapping for the grand parent - return; - } - Mapping *gm = it.value(); - if (gm->proxy_rows.at(source_parent.row()) == -1 || - gm->proxy_columns.at(source_parent.column()) == -1) { - // Don't care, since parent is filtered - return; - } - } + if (!can_create_mapping(source_parent)) + return; it = create_mapping(source_parent); Mapping *m = it.value(); QModelIndex proxy_parent = q->mapFromSource(source_parent); @@ -875,8 +893,8 @@ void QSortFilterProxyModelPrivate::proxy_item_range( { proxy_low = INT_MAX; proxy_high = INT_MIN; - foreach (int source_item, source_items) { - int proxy_item = source_to_proxy.at(source_item); + for (int i = 0; i < source_items.count(); ++i) { + int proxy_item = source_to_proxy.at(source_items.at(i)); Q_ASSERT(proxy_item != -1); if (proxy_item < proxy_low) proxy_low = proxy_item; @@ -937,34 +955,47 @@ void QSortFilterProxyModelPrivate::update_persistent_indexes( q->changePersistentIndexList(from, to); } + /*! \internal Updates the proxy model (adds/removes rows) based on the new filter. */ -void QSortFilterProxyModelPrivate::filter_changed() +void QSortFilterProxyModelPrivate::filter_changed(const QModelIndex &source_parent) { - QMap<QModelIndex, Mapping *>::const_iterator it; - for (it = source_index_mapping.constBegin(); it != source_index_mapping.constEnd(); ++it) { - QModelIndex source_parent = it.key(); - Mapping *m = it.value(); - handle_filter_changed(m->proxy_rows, m->source_rows, source_parent, Qt::Vertical); - handle_filter_changed(m->proxy_columns, m->source_columns, source_parent, Qt::Horizontal); + IndexMap::const_iterator it = source_index_mapping.constFind(source_parent); + if (it == source_index_mapping.constEnd()) + return; + Mapping *m = it.value(); + QSet<int> rows_removed = handle_filter_changed(m->proxy_rows, m->source_rows, source_parent, Qt::Vertical); + QSet<int> columns_removed = handle_filter_changed(m->proxy_columns, m->source_columns, source_parent, Qt::Horizontal); + QVector<QModelIndex>::iterator it2 = m->mapped_children.end(); + while (it2 != m->mapped_children.begin()) { + --it2; + const QModelIndex source_child_index = *it2; + if (rows_removed.contains(source_child_index.row()) || columns_removed.contains(source_child_index.column())) { + it2 = m->mapped_children.erase(it2); + remove_from_mapping(source_child_index); + } else { + filter_changed(source_child_index); + } } } /*! \internal + returns the removed items indexes */ -void QSortFilterProxyModelPrivate::handle_filter_changed( +QSet<int> QSortFilterProxyModelPrivate::handle_filter_changed( QVector<int> &source_to_proxy, QVector<int> &proxy_to_source, const QModelIndex &source_parent, Qt::Orientation orient) { Q_Q(QSortFilterProxyModel); // Figure out which mapped items to remove QVector<int> source_items_remove; - foreach (int source_item, proxy_to_source) { + for (int i = 0; i < proxy_to_source.count(); ++i) { + const int source_item = proxy_to_source.at(i); if ((orient == Qt::Vertical) ? !q->filterAcceptsRow(source_item, source_parent) : !q->filterAcceptsColumn(source_item, source_parent)) { @@ -994,6 +1025,7 @@ void QSortFilterProxyModelPrivate::handle_filter_changed( insert_source_items(source_to_proxy, proxy_to_source, source_items_insert, source_parent, orient); } + return qVectorToSet(source_items_remove); } void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &source_top_left, @@ -1044,15 +1076,14 @@ void QSortFilterProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &sourc if (!source_rows_remove.isEmpty()) { remove_source_items(m->proxy_rows, m->source_rows, source_rows_remove, source_parent, Qt::Vertical); - QSet<int> source_rows_remove_set = source_rows_remove.toList().toSet(); - QVector<QModelIndex>::iterator it = m->mapped_children.begin(); - while (it != m->mapped_children.end()) { + QSet<int> source_rows_remove_set = qVectorToSet(source_rows_remove); + QVector<QModelIndex>::iterator it = m->mapped_children.end(); + while (it != m->mapped_children.begin()) { + --it; const QModelIndex source_child_index = *it; if (source_rows_remove_set.contains(source_child_index.row())) { it = m->mapped_children.erase(it); remove_from_mapping(source_child_index); - } else { - ++it; } } } @@ -1118,11 +1149,17 @@ void QSortFilterProxyModelPrivate::_q_sourceHeaderDataChanged(Qt::Orientation or emit q->headerDataChanged(orientation, proxy_start, proxy_end); } +void QSortFilterProxyModelPrivate::_q_sourceAboutToBeReset() +{ + Q_Q(QSortFilterProxyModel); + q->beginResetModel(); +} + void QSortFilterProxyModelPrivate::_q_sourceReset() { Q_Q(QSortFilterProxyModel); // All internal structures are deleted in clear() - q->reset(); + q->endResetModel(); update_source_sort_column(); if (dynamic_sortfilter) sort(); @@ -1164,7 +1201,8 @@ void QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeInserted( Q_UNUSED(end); //Force the creation of a mapping now, even if its empty. //We need it because the proxy can be acessed at the moment it emits rowsAboutToBeInserted in insert_source_items - create_mapping(source_parent); + if (can_create_mapping(source_parent)) + create_mapping(source_parent); } void QSortFilterProxyModelPrivate::_q_sourceRowsInserted( @@ -1195,7 +1233,8 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeInserted( Q_UNUSED(end); //Force the creation of a mapping now, even if its empty. //We need it because the proxy can be acessed at the moment it emits columnsAboutToBeInserted in insert_source_items - create_mapping(source_parent); + if (can_create_mapping(source_parent)) + create_mapping(source_parent); } void QSortFilterProxyModelPrivate::_q_sourceColumnsInserted( @@ -1246,82 +1285,76 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsRemoved( /*! \since 4.1 \class QSortFilterProxyModel - \brief The QSortFilterProxyModel class provides support for sorting and filtering data passed - between another model and a view. + \brief The QSortFilterProxyModel class provides support for sorting and + filtering data passed between another model and a view. \ingroup model-view - QSortFilterProxyModel can be used for sorting items, filtering - out items, or both. The model transforms the structure of a - source model by mapping the model indexes it supplies to new - indexes, corresponding to different locations, for views to use. - This approach allows a given source model to be restructured as - far as views are concerned without requiring any transformations - on the underlying data, and without duplicating the data in + QSortFilterProxyModel can be used for sorting items, filtering out items, + or both. The model transforms the structure of a source model by mapping + the model indexes it supplies to new indexes, corresponding to different + locations, for views to use. This approach allows a given source model to + be restructured as far as views are concerned without requiring any + transformations on the underlying data, and without duplicating the data in memory. - Let's assume that we want to sort and filter the items provided - by a custom model. The code to set up the model and the view, \e - without sorting and filtering, would look like this: + Let's assume that we want to sort and filter the items provided by a custom + model. The code to set up the model and the view, \e without sorting and + filtering, would look like this: \snippet doc/src/snippets/qsortfilterproxymodel-details/main.cpp 1 - To add sorting and filtering support to \c MyItemModel, we need - to create a QSortFilterProxyModel, call setSourceModel() with the - \c MyItemModel as argument, and install the QSortFilterProxyModel - on the view: + To add sorting and filtering support to \c MyItemModel, we need to create + a QSortFilterProxyModel, call setSourceModel() with the \c MyItemModel as + argument, and install the QSortFilterProxyModel on the view: \snippet doc/src/snippets/qsortfilterproxymodel-details/main.cpp 0 \snippet doc/src/snippets/qsortfilterproxymodel-details/main.cpp 2 - At this point, neither sorting nor filtering is enabled; the - original data is displayed in the view. Any changes made through - the QSortFilterProxyModel are applied to the original model. + At this point, neither sorting nor filtering is enabled; the original data + is displayed in the view. Any changes made through the + QSortFilterProxyModel are applied to the original model. - The QSortFilterProxyModel acts as a wrapper for the original - model. If you need to convert source \l{QModelIndex}es to - sorted/filtered model indexes or vice versa, use mapToSource(), - mapFromSource(), mapSelectionToSource(), and - mapSelectionFromSource(). + The QSortFilterProxyModel acts as a wrapper for the original model. If you + need to convert source \l{QModelIndex}es to sorted/filtered model indexes + or vice versa, use mapToSource(), mapFromSource(), mapSelectionToSource(), + and mapSelectionFromSource(). - \note By default, the model does not dynamically re-sort and re-filter - data whenever the original model changes. This behavior can be - changed by setting the \l{QSortFilterProxyModel::dynamicSortFilter} - {dynamicSortFilter} property. + \note By default, the model does not dynamically re-sort and re-filter data + whenever the original model changes. This behavior can be changed by + setting the \l{QSortFilterProxyModel::dynamicSortFilter}{dynamicSortFilter} + property. - The \l{itemviews/basicsortfiltermodel}{Basic Sort/Filter Model} - and \l{itemviews/customsortfiltermodel}{Custom Sort/Filter Model} - examples illustrate how to use QSortFilterProxyModel to perform - basic sorting and filtering and how to subclass it to implement - custom behavior. + The \l{itemviews/basicsortfiltermodel}{Basic Sort/Filter Model} and + \l{itemviews/customsortfiltermodel}{Custom Sort/Filter Model} examples + illustrate how to use QSortFilterProxyModel to perform basic sorting and + filtering and how to subclass it to implement custom behavior. \section1 Sorting QTableView and QTreeView have a - \l{QTreeView::sortingEnabled}{sortingEnabled} property that - controls whether the user can sort the view by clicking the - view's horizontal header. For example: + \l{QTreeView::sortingEnabled}{sortingEnabled} property that controls + whether the user can sort the view by clicking the view's horizontal + header. For example: \snippet doc/src/snippets/qsortfilterproxymodel-details/main.cpp 3 - When this feature is on (the default is off), clicking on a - header section sorts the items according to that column. By - clicking repeatedly, the user can alternate between ascending and - descending order. + When this feature is on (the default is off), clicking on a header section + sorts the items according to that column. By clicking repeatedly, the user + can alternate between ascending and descending order. \image qsortfilterproxymodel-sorting.png A sorted QTreeView - Behind the scene, the view calls the sort() virtual function on - the model to reorder the data in the model. To make your data - sortable, you can either implement sort() in your model, or you - use a QSortFilterProxyModel to wrap your model -- - QSortFilterProxyModel provides a generic sort() reimplementation - that operates on the sortRole() (Qt::DisplayRole by default) of - the items and that understands several data types, including \c - int, QString, and QDateTime. For hierarchical models, sorting is - applied recursively to all child items. String comparisons are - case sensitive by default; this can be changed by setting the - \l{QSortFilterProxyModel::}{sortCaseSensitivity} property. + Behind the scene, the view calls the sort() virtual function on the model + to reorder the data in the model. To make your data sortable, you can + either implement sort() in your model, or use a QSortFilterProxyModel to + wrap your model -- QSortFilterProxyModel provides a generic sort() + reimplementation that operates on the sortRole() (Qt::DisplayRole by + default) of the items and that understands several data types, including + \c int, QString, and QDateTime. For hierarchical models, sorting is applied + recursively to all child items. String comparisons are case sensitive by + default; this can be changed by setting the \l{QSortFilterProxyModel::} + {sortCaseSensitivity} property. Custom sorting behavior is achieved by subclassing QSortFilterProxyModel and reimplementing lessThan(), which is @@ -1333,43 +1366,42 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsRemoved( \l{itemviews/customsortfiltermodel}{Custom Sort/Filter Model} example.) - An alternative approach to sorting is to disable sorting on the - view and to impose a certain order to the user. This is done by - explicitly calling sort() with the desired column and order as - arguments on the QSortFilterProxyModel (or on the original model - if it implements sort()). For example: + An alternative approach to sorting is to disable sorting on the view and to + impose a certain order to the user. This is done by explicitly calling + sort() with the desired column and order as arguments on the + QSortFilterProxyModel (or on the original model if it implements sort()). + For example: \snippet doc/src/snippets/qsortfilterproxymodel-details/main.cpp 4 - QSortFilterProxyModel can be sorted by column -1, in which case it - returns to the sort order of the underlying source model. + QSortFilterProxyModel can be sorted by column -1, in which case it returns + to the sort order of the underlying source model. \section1 Filtering - In addition to sorting, QSortFilterProxyModel can be used to hide - items that don't match a certain filter. The filter is specified - using a QRegExp object and is applied to the filterRole() - (Qt::DisplayRole by default) of each item, for a given column. - The QRegExp object can be used to match a regular expression, a - wildcard pattern, or a fixed string. For example: + In addition to sorting, QSortFilterProxyModel can be used to hide items + that do not match a certain filter. The filter is specified using a QRegExp + object and is applied to the filterRole() (Qt::DisplayRole by default) of + each item, for a given column. The QRegExp object can be used to match a + regular expression, a wildcard pattern, or a fixed string. For example: \snippet doc/src/snippets/qsortfilterproxymodel-details/main.cpp 5 - For hierarchical models, the filter is applied recursively to all - children. If a parent item doesn't match the filter, none of its - children will be shown. + For hierarchical models, the filter is applied recursively to all children. + If a parent item doesn't match the filter, none of its children will be + shown. - A common use case is to let the user specify the filter regexp, - wildcard pattern, or fixed string in a QLineEdit and to connect - the \l{QLineEdit::textChanged()}{textChanged()} signal to - setFilterRegExp(), setFilterWildcard(), or setFilterFixedString() - to reapply the filter. + A common use case is to let the user specify the filter regexp, wildcard + pattern, or fixed string in a QLineEdit and to connect the + \l{QLineEdit::textChanged()}{textChanged()} signal to setFilterRegExp(), + setFilterWildcard(), or setFilterFixedString() to reapply the filter. Custom filtering behavior can be achieved by reimplementing the filterAcceptsRow() and filterAcceptsColumn() functions. For - example, the following implementation ignores the - \l{QSortFilterProxyModel::filterKeyColumn}{filterKeyColumn} - property and performs filtering on columns 0, 1, and 2: + example (from the \l{itemviews/customsortfiltermodel} + {Custom Sort/Filter Model} example), the following implementation ignores + the \l{QSortFilterProxyModel::filterKeyColumn}{filterKeyColumn} property + and performs filtering on columns 0, 1, and 2: \snippet examples/itemviews/customsortfiltermodel/mysortfilterproxymodel.cpp 3 @@ -1379,24 +1411,24 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsRemoved( If you are working with large amounts of filtering and have to invoke invalidateFilter() repeatedly, using reset() may be more efficient, - depending on the implementation of your model. However, note that reset() - returns the proxy model to its original state, losing selection - information, and will cause the proxy model to be repopulated. + depending on the implementation of your model. However, reset() returns the + proxy model to its original state, losing selection information, and will + cause the proxy model to be repopulated. \section1 Subclassing - \bold{Note:} Some general guidelines for subclassing models are - available in the \l{Model Subclassing Reference}. - Since QAbstractProxyModel and its subclasses are derived from - QAbstractItemModel, much of the same advice about subclassing normal - models also applies to proxy models. In addition, it is worth noting - that many of the default implementations of functions in this class - are written so that they call the equivalent functions in the relevant - source model. This simple proxying mechanism may need to be overridden - for source models with more complex behavior; for example, if the - source model provides a custom hasChildren() implementation, you - should also provide one in the proxy model. + QAbstractItemModel, much of the same advice about subclassing normal models + also applies to proxy models. In addition, it is worth noting that many of + the default implementations of functions in this class are written so that + they call the equivalent functions in the relevant source model. This + simple proxying mechanism may need to be overridden for source models with + more complex behavior; for example, if the source model provides a custom + hasChildren() implementation, you should also provide one in the proxy + model. + + \note Some general guidelines for subclassing models are available in the + \l{Model Subclassing Reference}. \sa QAbstractProxyModel, QAbstractItemModel, {Model/View Programming}, {Basic Sort/Filter Model Example}, {Custom Sort/Filter Model Example} @@ -1474,6 +1506,7 @@ void QSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel) disconnect(d->model, SIGNAL(layoutChanged()), this, SLOT(_q_sourceLayoutChanged())); + disconnect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset())); disconnect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset())); QAbstractProxyModel::setSourceModel(sourceModel); @@ -1514,6 +1547,7 @@ void QSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel) connect(d->model, SIGNAL(layoutChanged()), this, SLOT(_q_sourceLayoutChanged())); + connect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_sourceAboutToBeReset())); connect(d->model, SIGNAL(modelReset()), this, SLOT(_q_sourceReset())); d->clear_mapping(); @@ -1959,9 +1993,11 @@ Qt::SortOrder QSortFilterProxyModel::sortOrder() const \brief the QRegExp used to filter the contents of the source model Setting this property overwrites the current - \l{QSortFilterProxyModel::filterCaseSensitivity} - {filterCaseSensitivity}. By default, the QRegExp is an empty - string matching all contents. + \l{QSortFilterProxyModel::filterCaseSensitivity}{filterCaseSensitivity}. + By default, the QRegExp is an empty string matching all contents. + + If no QRegExp or an empty string is set, everything in the source model + will be accepted. \sa filterCaseSensitivity, setFilterWildcard(), setFilterFixedString() */ @@ -2284,7 +2320,7 @@ bool QSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex Q_D(const QSortFilterProxyModel); QVariant l = (left.model() ? left.model()->data(left, d->sort_role) : QVariant()); QVariant r = (right.model() ? right.model()->data(right, d->sort_role) : QVariant()); - switch (l.type()) { + switch (l.userType()) { case QVariant::Invalid: return (r.type() == QVariant::Invalid); case QVariant::Int: @@ -2295,6 +2331,8 @@ bool QSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex return l.toLongLong() < r.toLongLong(); case QVariant::ULongLong: return l.toULongLong() < r.toULongLong(); + case QMetaType::Float: + return l.toFloat() < r.toFloat(); case QVariant::Double: return l.toDouble() < r.toDouble(); case QVariant::Char: diff --git a/src/gui/itemviews/qsortfilterproxymodel.h b/src/gui/itemviews/qsortfilterproxymodel.h index 896d79e..f448b1b 100644 --- a/src/gui/itemviews/qsortfilterproxymodel.h +++ b/src/gui/itemviews/qsortfilterproxymodel.h @@ -177,6 +177,7 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_sourceDataChanged(const QModelIndex &source_top_left, const QModelIndex &source_bottom_right)) Q_PRIVATE_SLOT(d_func(), void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int start, int end)) + Q_PRIVATE_SLOT(d_func(), void _q_sourceAboutToBeReset()) Q_PRIVATE_SLOT(d_func(), void _q_sourceReset()) Q_PRIVATE_SLOT(d_func(), void _q_sourceLayoutAboutToBeChanged()) Q_PRIVATE_SLOT(d_func(), void _q_sourceLayoutChanged()) diff --git a/src/gui/itemviews/qstandarditemmodel.cpp b/src/gui/itemviews/qstandarditemmodel.cpp index 4d68d52..f327c99 100644 --- a/src/gui/itemviews/qstandarditemmodel.cpp +++ b/src/gui/itemviews/qstandarditemmodel.cpp @@ -329,7 +329,6 @@ QStandardItemModelPrivate::QStandardItemModelPrivate() */ QStandardItemModelPrivate::~QStandardItemModelPrivate() { - delete root; delete itemPrototype; qDeleteAll(columnHeaderItems); qDeleteAll(rowHeaderItems); @@ -554,7 +553,7 @@ void QStandardItemModelPrivate::rowsInserted(QStandardItem *parent, int row, int count) { Q_Q(QStandardItemModel); - if (parent == root) + if (parent == root.data()) rowHeaderItems.insert(row, count, 0); q->endInsertRows(); } @@ -566,7 +565,7 @@ void QStandardItemModelPrivate::columnsInserted(QStandardItem *parent, int column, int count) { Q_Q(QStandardItemModel); - if (parent == root) + if (parent == root.data()) columnHeaderItems.insert(column, count, 0); q->endInsertColumns(); } @@ -578,7 +577,7 @@ void QStandardItemModelPrivate::rowsRemoved(QStandardItem *parent, int row, int count) { Q_Q(QStandardItemModel); - if (parent == root) { + if (parent == root.data()) { for (int i = row; i < row + count; ++i) { QStandardItem *oldItem = rowHeaderItems.at(i); if (oldItem) @@ -597,7 +596,7 @@ void QStandardItemModelPrivate::columnsRemoved(QStandardItem *parent, int column, int count) { Q_Q(QStandardItemModel); - if (parent == root) { + if (parent == root.data()) { for (int i = column; i < column + count; ++i) { QStandardItem *oldItem = columnHeaderItems.at(i); if (oldItem) @@ -778,8 +777,6 @@ QStandardItem &QStandardItem::operator=(const QStandardItem &other) */ QStandardItem::~QStandardItem() { - Q_D(QStandardItem); - delete d; } /*! @@ -790,7 +787,7 @@ QStandardItem::~QStandardItem() QStandardItem *QStandardItem::parent() const { Q_D(const QStandardItem); - if (!d->model || (d->model->d_func()->root != d->parent)) + if (!d->model || (d->model->d_func()->root.data() != d->parent)) return d->parent; return 0; } @@ -899,7 +896,7 @@ Qt::ItemFlags QStandardItem::flags() const if (!v.isValid()) return (Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable |Qt::ItemIsDragEnabled|Qt::ItemIsDropEnabled); - return ((Qt::ItemFlags)(v.toInt())); + return Qt::ItemFlags(v.toInt()); } /*! @@ -1742,18 +1739,23 @@ QList<QStandardItem*> QStandardItem::takeRow(int row) Q_D(QStandardItem); if ((row < 0) || (row >= rowCount())) return QList<QStandardItem*>(); + if (d->model) + d->model->d_func()->rowsAboutToBeRemoved(this, row, row); QList<QStandardItem*> items; - int index = d->childIndex(row, 0); - for (int column = 0; column < d->columnCount(); ++column) { - QStandardItem *ch = d->children.at(index); - if (ch) { - ch->d_func()->setParentAndModel(0, 0); - d->children.replace(index, 0); + int index = d->childIndex(row, 0); // Will return -1 if there are no columns + if (index != -1) { + int col_count = d->columnCount(); + for (int column = 0; column < col_count; ++column) { + QStandardItem *ch = d->children.at(index + column); + if (ch) + ch->d_func()->setParentAndModel(0, 0); + items.append(ch); } - items.append(ch); - ++index; + d->children.remove(index, col_count); } - removeRow(row); + d->rows--; + if (d->model) + d->model->d_func()->rowsRemoved(this, row, 1); return items; } @@ -1769,18 +1771,21 @@ QList<QStandardItem*> QStandardItem::takeColumn(int column) Q_D(QStandardItem); if ((column < 0) || (column >= columnCount())) return QList<QStandardItem*>(); + if (d->model) + d->model->d_func()->columnsAboutToBeRemoved(this, column, column); QList<QStandardItem*> items; - int index = d->childIndex(0, column); - for (int row = 0; row < d->rowCount(); ++row) { + + for (int row = d->rowCount() - 1; row >= 0; --row) { + int index = d->childIndex(row, column); QStandardItem *ch = d->children.at(index); - if (ch) { + if (ch) ch->d_func()->setParentAndModel(0, 0); - d->children.replace(index, 0); - } - items.append(ch); - index += d->columnCount(); + d->children.remove(index); + items.prepend(ch); } - removeColumn(column); + d->columns--; + if (d->model) + d->model->d_func()->columnsRemoved(this, column, 1); return items; } @@ -1801,7 +1806,7 @@ bool QStandardItem::operator<(const QStandardItem &other) const const int role = model() ? model()->sortRole() : Qt::DisplayRole; const QVariant l = data(role), r = other.data(role); // this code is copied from QSortFilterProxyModel::lessThan() - switch (l.type()) { + switch (l.userType()) { case QVariant::Invalid: return (r.type() == QVariant::Invalid); case QVariant::Int: @@ -1812,6 +1817,8 @@ bool QStandardItem::operator<(const QStandardItem &other) const return l.toLongLong() < r.toLongLong(); case QVariant::ULongLong: return l.toULongLong() < r.toULongLong(); + case QMetaType::Float: + return l.toFloat() < r.toFloat(); case QVariant::Double: return l.toDouble() < r.toDouble(); case QVariant::Char: @@ -1890,7 +1897,7 @@ void QStandardItem::read(QDataStream &in) in >> d->values; qint32 flags; in >> flags; - setFlags((Qt::ItemFlags)flags); + setFlags(Qt::ItemFlags(flags)); } /*! @@ -1938,7 +1945,7 @@ QDataStream &operator<<(QDataStream &out, const QStandardItem &item) return out; } -#endif // !QT_NO_DATASTREAM +#endif // QT_NO_DATASTREAM /*! \class QStandardItemModel @@ -2079,8 +2086,7 @@ QStandardItemModel::~QStandardItemModel() void QStandardItemModel::clear() { Q_D(QStandardItemModel); - delete d->root; - d->root = new QStandardItem; + d->root.reset(new QStandardItem); d->root->d_func()->setModel(this); qDeleteAll(d->columnHeaderItems); d->columnHeaderItems.clear(); @@ -2227,7 +2233,7 @@ QStandardItem *QStandardItemModel::item(int row, int column) const QStandardItem *QStandardItemModel::invisibleRootItem() const { Q_D(const QStandardItemModel); - return d->root; + return d->root.data(); } /*! @@ -2729,7 +2735,7 @@ QModelIndex QStandardItemModel::index(int row, int column, const QModelIndex &pa bool QStandardItemModel::insertColumns(int column, int count, const QModelIndex &parent) { Q_D(QStandardItemModel); - QStandardItem *item = parent.isValid() ? itemFromIndex(parent) : d->root; + QStandardItem *item = parent.isValid() ? itemFromIndex(parent) : d->root.data(); if (item == 0) return false; return item->d_func()->insertColumns(column, count, QList<QStandardItem*>()); @@ -2741,7 +2747,7 @@ bool QStandardItemModel::insertColumns(int column, int count, const QModelIndex bool QStandardItemModel::insertRows(int row, int count, const QModelIndex &parent) { Q_D(QStandardItemModel); - QStandardItem *item = parent.isValid() ? itemFromIndex(parent) : d->root; + QStandardItem *item = parent.isValid() ? itemFromIndex(parent) : d->root.data(); if (item == 0) return false; return item->d_func()->insertRows(row, count, QList<QStandardItem*>()); @@ -2907,8 +2913,8 @@ QMimeData *QStandardItemModel::mimeData(const QModelIndexList &indexes) const QStack<QStandardItem*> stack; itemsSet.reserve(indexes.count()); stack.reserve(indexes.count()); - foreach (const QModelIndex &index, indexes) { - QStandardItem *item = itemFromIndex(index); + for (int i = 0; i < indexes.count(); ++i) { + QStandardItem *item = itemFromIndex(indexes.at(i)); itemsSet << item; stack.push(item); } diff --git a/src/gui/itemviews/qstandarditemmodel.h b/src/gui/itemviews/qstandarditemmodel.h index 79b5702..2e7e112 100644 --- a/src/gui/itemviews/qstandarditemmodel.h +++ b/src/gui/itemviews/qstandarditemmodel.h @@ -240,7 +240,7 @@ protected: QStandardItem(const QStandardItem &other); QStandardItem(QStandardItemPrivate &dd); QStandardItem &operator=(const QStandardItem &other); - QStandardItemPrivate *d_ptr; + QScopedPointer<QStandardItemPrivate> d_ptr; void emitDataChanged(); diff --git a/src/gui/itemviews/qstandarditemmodel_p.h b/src/gui/itemviews/qstandarditemmodel_p.h index a429f49..de096b3 100644 --- a/src/gui/itemviews/qstandarditemmodel_p.h +++ b/src/gui/itemviews/qstandarditemmodel_p.h @@ -75,6 +75,7 @@ public: parent(0), rows(0), columns(0), + q_ptr(0), lastIndexOf(2) { } virtual ~QStandardItemPrivate(); @@ -152,7 +153,7 @@ public: inline QStandardItem *itemFromIndex(const QModelIndex &index) const { Q_Q(const QStandardItemModel); if (!index.isValid()) - return root; + return root.data(); if (index.model() != q) return 0; QStandardItem *parent = static_cast<QStandardItem*>(index.internalPointer()); @@ -177,7 +178,7 @@ public: QVector<QStandardItem*> columnHeaderItems; QVector<QStandardItem*> rowHeaderItems; - QStandardItem *root; + QScopedPointer<QStandardItem> root; const QStandardItem *itemPrototype; int sortRole; }; diff --git a/src/gui/itemviews/qstringlistmodel.cpp b/src/gui/itemviews/qstringlistmodel.cpp index ad8d413..f8ae658 100644 --- a/src/gui/itemviews/qstringlistmodel.cpp +++ b/src/gui/itemviews/qstringlistmodel.cpp @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE \brief The QStringListModel class provides a model that supplies strings to views. \ingroup model-view - \mainclass + QStringListModel is an editable model that can be used for simple cases where you need to display a number of strings in a view diff --git a/src/gui/itemviews/qstyleditemdelegate.cpp b/src/gui/itemviews/qstyleditemdelegate.cpp index b7ae1a1..ab77bda 100644 --- a/src/gui/itemviews/qstyleditemdelegate.cpp +++ b/src/gui/itemviews/qstyleditemdelegate.cpp @@ -112,7 +112,7 @@ public: data items from a model. \ingroup model-view - \mainclass + \since 4.4 When displaying data from models in Qt item views, e.g., a @@ -267,9 +267,10 @@ QStyledItemDelegate::~QStyledItemDelegate() QString QStyledItemDelegate::displayText(const QVariant &value, const QLocale& locale) const { QString text; - switch (value.type()) { + switch (value.userType()) { + case QMetaType::Float: case QVariant::Double: - text = locale.toString(value.toDouble()); + text = locale.toString(value.toReal()); break; case QVariant::Int: case QVariant::LongLong: @@ -322,7 +323,7 @@ void QStyledItemDelegate::initStyleOption(QStyleOptionViewItem *option, value = index.data(Qt::TextAlignmentRole); if (value.isValid() && !value.isNull()) - option->displayAlignment = (Qt::Alignment)value.toInt(); + option->displayAlignment = Qt::Alignment(value.toInt()); value = index.data(Qt::ForegroundRole); if (qVariantCanConvert<QBrush>(value)) @@ -671,7 +672,7 @@ bool QStyledItemDelegate::eventFilter(QObject *object, QEvent *event) if (editor->parentWidget()) editor->parentWidget()->setFocus(); return true; - } else if (event->type() == QEvent::FocusOut || event->type() == QEvent::Hide) { + } else if (event->type() == QEvent::FocusOut || (event->type() == QEvent::Hide && editor->isWindow())) { //the Hide event will take care of he editors that are in fact complete dialogs if (!editor->isActiveWindow() || (QApplication::focusWidget() != editor)) { QWidget *w = QApplication::focusWidget(); @@ -686,13 +687,7 @@ bool QStyledItemDelegate::eventFilter(QObject *object, QEvent *event) if (QDragManager::self() && QDragManager::self()->object != 0) return false; #endif - // Opening a modal dialog will start a new eventloop - // that will process the deleteLater event. - QWidget *activeModalWidget = QApplication::activeModalWidget(); - if (activeModalWidget - && !activeModalWidget->isAncestorOf(editor) - && qobject_cast<QDialog*>(activeModalWidget)) - return false; + emit commitData(editor); emit closeEditor(editor, NoHint); } @@ -752,8 +747,13 @@ bool QStyledItemDelegate::editorEvent(QEvent *event, return false; } - Qt::CheckState state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked + Qt::CheckState state; + if ( flags & Qt::ItemIsTristate ) { + state = static_cast<Qt::CheckState>( (value.toInt() + 1) % 3 ); + } else { + state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked ? Qt::Unchecked : Qt::Checked); + } return model->setData(index, state, Qt::CheckStateRole); } diff --git a/src/gui/itemviews/qtableview.cpp b/src/gui/itemviews/qtableview.cpp index 876059c..c12af3b 100644 --- a/src/gui/itemviews/qtableview.cpp +++ b/src/gui/itemviews/qtableview.cpp @@ -59,6 +59,138 @@ QT_BEGIN_NAMESPACE +/** \internal + Add a span to the collection. the collection takes the ownership. + */ +void QSpanCollection::addSpan(QSpanCollection::Span *span) +{ + spans.append(span); + Index::iterator it_y = index.lowerBound(-span->top()); + if (it_y == index.end() || it_y.key() != -span->top()) { + //there is no spans that starts with the row in the index, so create a sublist for it. + SubIndex sub_index; + if (it_y != index.end()) { + //the previouslist is the list of spans that sarts _before_ the row of the span. + // and which may intersect this row. + const SubIndex previousList = it_y.value(); + foreach(Span *s, previousList) { + //If a subspans intersect the row, we need to split it into subspans + if(s->bottom() >= span->top()) + sub_index.insert(-s->left(), s); + } + } + it_y = index.insert(-span->top(), sub_index); + //we will insert span to *it_y in the later loop + } + + //insert the span as supspan in all the lists that intesects the span + while(-it_y.key() <= span->bottom()) { + (*it_y).insert(-span->left(), span); + if(it_y == index.begin()) + break; + --it_y; + } +} + + +/** \internal +* Has to be called after the height and width of a span is changed. +* +* old_height is the height before the change +* +* if the size of the span is now 0x0 the span will be deleted. +*/ +void QSpanCollection::updateSpan(QSpanCollection::Span *span, int old_height) +{ + if (old_height < span->height()) { + //add the span as subspan in all the lists that intersect the new covered columns + Index::iterator it_y = index.lowerBound(-(span->top() + old_height - 1)); + Q_ASSERT(it_y != index.end()); //it_y must exist since the span is in the list + while (-it_y.key() <= span->bottom()) { + (*it_y).insert(-span->left(), span); + if(it_y == index.begin()) + break; + --it_y; + } + } else if (old_height > span->height()) { + //remove the span from all the subspans lists that intersect the columns not covered anymore + Index::iterator it_y = index.lowerBound(-span->bottom()); + Q_ASSERT(it_y != index.end()); //it_y must exist since the span is in the list + while (-it_y.key() <= span->top() + old_height -1) { + if(-it_y.key() != span->bottom()) { + (*it_y).remove(-span->left()); + if (it_y->isEmpty()) { + it_y = index.erase(it_y) - 1; + } + } + if(it_y == index.begin()) + break; + --it_y; + } + } + + if (span->width() == 0 && span->height() == 0) { + spans.removeOne(span); + delete span; + } +} + +/** \internal + * \return a spans that spans over cell x,y (column,row) or 0 if there is none. + */ +QSpanCollection::Span *QSpanCollection::spanAt(int x, int y) const +{ + Index::const_iterator it_y = index.lowerBound(-y); + if (it_y == index.end()) + return 0; + SubIndex::const_iterator it_x = (*it_y).lowerBound(-x); + if (it_x == (*it_y).end()) + return 0; + Span *span = *it_x; + if (span->right() >= x && span->bottom() >= y) + return span; + return 0; +} + + +/** \internal +* remove and deletes all spans inside the collection +*/ +void QSpanCollection::clear() +{ + qDeleteAll(spans); + index.clear(); + spans.clear(); +} + +/** \internal + * return a list to all the spans that spans over cells in the given rectangle + */ +QList<QSpanCollection::Span *> QSpanCollection::spansInRect(int x, int y, int w, int h) const +{ + QSet<Span *> list; + Index::const_iterator it_y = index.lowerBound(-y); + if(it_y == index.end()) + --it_y; + while(-it_y.key() <= y + h) { + SubIndex::const_iterator it_x = (*it_y).lowerBound(-x); + if (it_x == (*it_y).end()) + --it_x; + while(-it_x.key() <= x + w) { + Span *s = *it_x; + if (s->bottom() >= y && s->right() >= x) + list << s; + if (it_x == (*it_y).begin()) + break; + --it_x; + } + if(it_y == index.begin()) + break; + --it_y; + } + return list.toList(); +} + class QTableCornerButton : public QAbstractButton { Q_OBJECT @@ -149,35 +281,40 @@ void QTableViewPrivate::trimHiddenSelections(QItemSelectionRange *range) const */ void QTableViewPrivate::setSpan(int row, int column, int rowSpan, int columnSpan) { - if (row < 0 || column < 0 || rowSpan < 0 || columnSpan < 0) + if (row < 0 || column < 0 || rowSpan <= 0 || columnSpan <= 0) { + qWarning() << "QTableView::setSpan: invalid span given: (" << row << ',' << column << ',' << rowSpan << ',' << columnSpan << ')'; return; - Span sp(row, column, rowSpan, columnSpan); - QList<Span>::iterator it; - for (it = spans.begin(); it != spans.end(); ++it) { - if (((*it).top() == sp.top()) && ((*it).left() == sp.left())) { - if ((sp.height() == 1) && (sp.width() == 1)) - spans.erase(it); // "Implicit" span (1, 1), no need to store it - else - *it = sp; // Replace + } + QSpanCollection::Span *sp = spans.spanAt(column, row); + if (sp) { + if (sp->top() != row || sp->left() != column) { + qWarning() << "QTableView::setSpan: span cannot overlap"; return; } + if (rowSpan == 1 && columnSpan == 1) { + rowSpan = columnSpan = 0; + } + const int old_height = sp->height(); + sp->m_bottom = row + rowSpan - 1; + sp->m_right = column + columnSpan - 1; + spans.updateSpan(sp, old_height); + return; } - spans.append(sp); + sp = new QSpanCollection::Span(row, column, rowSpan, columnSpan); + spans.addSpan(sp); } /*! \internal Gets the span information for the cell at (\a row, \a column). */ -QTableViewPrivate::Span QTableViewPrivate::span(int row, int column) const +QSpanCollection::Span QTableViewPrivate::span(int row, int column) const { - QList<Span>::const_iterator it; - for (it = spans.constBegin(); it != spans.constEnd(); ++it) { - Span span = *it; - if (isInSpan(row, column, span)) - return span; - } - return Span(row, column, 1, 1); + QSpanCollection::Span *sp = spans.spanAt(column, row); + if (sp) + return *sp; + + return QSpanCollection::Span(row, column, 1, 1); } /*! @@ -233,67 +370,9 @@ bool QTableViewPrivate::spanContainsSection(const QHeaderView *header, int logic /*! \internal - Returns true if one or more spans intersect column \a column. -*/ -bool QTableViewPrivate::spansIntersectColumn(int column) const -{ - QList<Span>::const_iterator it; - for (it = spans.constBegin(); it != spans.constEnd(); ++it) { - Span span = *it; - if (spanContainsColumn(column, span.left(), span.width())) - return true; - } - return false; -} - -/*! - \internal - Returns true if one or more spans intersect row \a row. -*/ -bool QTableViewPrivate::spansIntersectRow(int row) const -{ - QList<Span>::const_iterator it; - for (it = spans.constBegin(); it != spans.constEnd(); ++it) { - Span span = *it; - if (spanContainsRow(row, span.top(), span.height())) - return true; - } - return false; -} - -/*! - \internal - Returns true if one or more spans intersect one or more columns. -*/ -bool QTableViewPrivate::spansIntersectColumns(const QList<int> &columns) const -{ - QList<int>::const_iterator it; - for (it = columns.constBegin(); it != columns.constEnd(); ++it) { - if (spansIntersectColumn(*it)) - return true; - } - return false; -} - -/*! - \internal - Returns true if one or more spans intersect one or more rows. -*/ -bool QTableViewPrivate::spansIntersectRows(const QList<int> &rows) const -{ - QList<int>::const_iterator it; - for (it = rows.constBegin(); it != rows.constEnd(); ++it) { - if (spansIntersectRow(*it)) - return true; - } - return false; -} - -/*! - \internal Returns the visual rect for the given \a span. */ -QRect QTableViewPrivate::visualSpanRect(const Span &span) const +QRect QTableViewPrivate::visualSpanRect(const QSpanCollection::Span &span) const { Q_Q(const QTableView); // vertical @@ -319,42 +398,54 @@ QRect QTableViewPrivate::visualSpanRect(const Span &span) const preparation for the main drawing loop. \a drawn is a QBitArray of visualRowCountxvisualCoulumnCount which say if particular cell has been drawn */ -void QTableViewPrivate::drawAndClipSpans(const QRect &area, QPainter *painter, +void QTableViewPrivate::drawAndClipSpans(const QRegion &area, QPainter *painter, const QStyleOptionViewItemV4 &option, QBitArray *drawn, int firstVisualRow, int lastVisualRow, int firstVisualColumn, int lastVisualColumn) { bool alternateBase = false; QRegion region = viewport->rect(); - QList<Span>::const_iterator it; - for (it = spans.constBegin(); it != spans.constEnd(); ++it) { - Span span = *it; + QList<QSpanCollection::Span *> visibleSpans; + bool sectionMoved = verticalHeader->sectionsMoved() || horizontalHeader->sectionsMoved(); - int row = span.top(); - int col = span.left(); + if (!sectionMoved) { + visibleSpans = spans.spansInRect(logicalColumn(firstVisualColumn), logicalRow(firstVisualRow), + lastVisualColumn - firstVisualColumn + 1, lastVisualRow - firstVisualRow + 1); + } else { + QSet<QSpanCollection::Span *> set; + for(int x = firstVisualColumn; x <= lastVisualColumn; x++) + for(int y = firstVisualRow; y <= lastVisualRow; y++) + set.insert(spans.spanAt(x,y)); + set.remove(0); + visibleSpans = set.toList(); + } + + foreach (QSpanCollection::Span *span, visibleSpans) { + int row = span->top(); + int col = span->left(); if (isHidden(row, col)) continue; QModelIndex index = model->index(row, col, root); if (!index.isValid()) continue; - QRect rect = visualSpanRect(span); + QRect rect = visualSpanRect(*span); rect.translate(scrollDelayOffset); - if (!rect.intersects(area)) + if (!area.intersects(rect)) continue; QStyleOptionViewItemV4 opt = option; opt.rect = rect; - alternateBase = alternatingColors && (span.top() & 1); + alternateBase = alternatingColors && (span->top() & 1); if (alternateBase) opt.features |= QStyleOptionViewItemV2::Alternate; else opt.features &= ~QStyleOptionViewItemV2::Alternate; drawCell(painter, opt, index); region -= rect; - for (int r = span.top(); r <= span.bottom(); ++r) { + for (int r = span->top(); r <= span->bottom(); ++r) { const int vr = visualRow(r); if (vr < firstVisualRow || vr > lastVisualRow) continue; - for (int c = span.left(); c <= span.right(); ++c) { + for (int c = span->left(); c <= span->right(); ++c) { const int vc = visualColumn(c); if (vc < firstVisualColumn || vc > lastVisualColumn) continue; @@ -397,8 +488,7 @@ void QTableViewPrivate::drawCell(QPainter *painter, const QStyleOptionViewItemV4 opt.state |= QStyle::State_HasFocus; } - if (opt.features & QStyleOptionViewItemV2::Alternate) - painter->fillRect(opt.rect, opt.palette.brush(QPalette::AlternateBase)); + q->style()->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, painter, q); if (const QWidget *widget = editorForIndex(index).editor) { painter->save(); @@ -418,7 +508,7 @@ void QTableViewPrivate::drawCell(QPainter *painter, const QStyleOptionViewItemV4 \ingroup model-view \ingroup advanced - \mainclass + A QTableView implements a table view that displays items from a model. This class is used to provide standard tables that were @@ -753,7 +843,8 @@ void QTableView::paintEvent(QPaintEvent *event) uint x = horizontalHeader->length() - horizontalHeader->offset() - (rightToLeft ? 0 : 1); uint y = verticalHeader->length() - verticalHeader->offset() - 1; - QVector<QRect> rects = event->region().rects(); + const QRegion region = event->region().translated(offset); + const QVector<QRect> rects = region.rects(); //firstVisualRow is the visual index of the first visible row. lastVisualRow is the visual index of the last visible Row. //same goes for ...VisualColumn @@ -773,9 +864,13 @@ void QTableView::paintEvent(QPaintEvent *event) QBitArray drawn((lastVisualRow - firstVisualRow + 1) * (lastVisualColumn - firstVisualColumn + 1)); + if (d->hasSpans()) { + d->drawAndClipSpans(region, &painter, option, &drawn, + firstVisualRow, lastVisualRow, firstVisualColumn, lastVisualColumn); + } + for (int i = 0; i < rects.size(); ++i) { QRect dirtyArea = rects.at(i); - dirtyArea.translate(offset); dirtyArea.setBottom(qMin(dirtyArea.bottom(), int(y))); if (rightToLeft) { dirtyArea.setLeft(qMax(dirtyArea.left(), d->viewport->width() - int(x))); @@ -783,10 +878,6 @@ void QTableView::paintEvent(QPaintEvent *event) dirtyArea.setRight(qMin(dirtyArea.right(), int(x))); } - if (d->hasSpans()) - d->drawAndClipSpans(dirtyArea, &painter, option, &drawn, - firstVisualRow, lastVisualRow, firstVisualColumn, lastVisualColumn); - // get the horizontal start and end visual sections int left = horizontalHeader->visualIndexAt(dirtyArea.left()); int right = horizontalHeader->visualIndexAt(dirtyArea.right()); @@ -913,7 +1004,7 @@ QModelIndex QTableView::indexAt(const QPoint &pos) const int c = columnAt(pos.x()); if (r >= 0 && c >= 0) { if (d->hasSpans()) { - QTableViewPrivate::Span span = d->span(r, c); + QSpanCollection::Span span = d->span(r, c); r = span.top(); c = span.left(); } @@ -1011,14 +1102,14 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi --visualRow; if (d->hasSpans()) { int row = d->logicalRow(visualRow); - QTableViewPrivate::Span span = d->span(row, current.column()); + QSpanCollection::Span span = d->span(row, current.column()); visualRow = d->visualRow(span.top()); visualColumn = d->visualColumn(span.left()); } break; case MoveDown: if (d->hasSpans()) { - QTableViewPrivate::Span span = d->span(current.row(), current.column()); + QSpanCollection::Span span = d->span(current.row(), current.column()); visualRow = d->visualRow(d->rowSpanEndLogical(span.top(), span.height())); } #ifdef QT_KEYPAD_NAVIGATION @@ -1030,7 +1121,7 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi ++visualRow; if (d->hasSpans()) { int row = d->logicalRow(visualRow); - QTableViewPrivate::Span span = d->span(row, current.column()); + QSpanCollection::Span span = d->span(row, current.column()); visualColumn = d->visualColumn(span.left()); } break; @@ -1058,7 +1149,7 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi --visualColumn; if (d->hasSpans()) { int column = d->logicalColumn(visualColumn); - QTableViewPrivate::Span span = d->span(current.row(), column); + QSpanCollection::Span span = d->span(current.row(), column); visualRow = d->visualRow(span.top()); visualColumn = d->visualColumn(span.left()); } @@ -1078,7 +1169,7 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi } // else MoveRight case MoveRight: if (d->hasSpans()) { - QTableViewPrivate::Span span = d->span(current.row(), current.column()); + QSpanCollection::Span span = d->span(current.row(), current.column()); visualColumn = d->visualColumn(d->columnSpanEndLogical(span.left(), span.width())); } ++visualColumn; @@ -1086,7 +1177,7 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi ++visualColumn; if (d->hasSpans()) { int column = d->logicalColumn(visualColumn); - QTableViewPrivate::Span span = d->span(current.row(), column); + QSpanCollection::Span span = d->span(current.row(), column); visualRow = d->visualRow(span.top()); } break; @@ -1106,17 +1197,16 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi visualRow = bottom; break; case MovePageUp: { - int top = 0; - while (top < bottom && d->isVisualRowHiddenOrDisabled(top, visualColumn)) - ++top; - int newRow = qMax(rowAt(visualRect(current).top() - d->viewport->height()), top); - return d->model->index(qBound(0, newRow, bottom), current.column(), d->root); + int newRow = rowAt(visualRect(current).top() - d->viewport->height()); + if (newRow == -1) + newRow = d->logicalRow(0); + return d->model->index(newRow, current.column(), d->root); } case MovePageDown: { - int newRow = qMin(rowAt(visualRect(current).bottom() + d->viewport->height()), bottom); - if (newRow < 0) - newRow = bottom; - return d->model->index(qBound(0, newRow, bottom), current.column(), d->root); + int newRow = rowAt(visualRect(current).bottom() + d->viewport->height()); + if (newRow == -1) + newRow = d->logicalRow(bottom); + return d->model->index(newRow, current.column(), d->root); }} int logicalRow = d->logicalRow(visualRow); @@ -1161,9 +1251,8 @@ void QTableView::setSelection(const QRect &rect, QItemSelectionModel::SelectionF int right = qMax(d->visualColumn(tl.column()), d->visualColumn(br.column())); do { expanded = false; - QList<QTableViewPrivate::Span>::const_iterator it; - for (it = d->spans.constBegin(); it != d->spans.constEnd(); ++it) { - QTableViewPrivate::Span span = *it; + foreach (QSpanCollection::Span *it, d->spans.spans) { + const QSpanCollection::Span &span = *it; int t = d->visualRow(span.top()); int l = d->visualColumn(span.left()); int b = d->visualRow(d->rowSpanEndLogical(span.top(), span.height())); @@ -1253,7 +1342,7 @@ QRegion QTableView::visualRegionForSelection(const QItemSelection &selection) co bool verticalMoved = verticalHeader()->sectionsMoved(); bool horizontalMoved = horizontalHeader()->sectionsMoved(); - if ((verticalMoved && horizontalMoved) || d->hasSpans()) { + if ((verticalMoved && horizontalMoved) || (d->hasSpans() && (verticalMoved || horizontalMoved))) { for (int i = 0; i < selection.count(); ++i) { QItemSelectionRange range = selection.at(i); if (range.parent() != d->root || !range.isValid()) @@ -1296,9 +1385,19 @@ QRegion QTableView::visualRegionForSelection(const QItemSelection &selection) co if (range.parent() != d->root || !range.isValid()) continue; d->trimHiddenSelections(&range); - QRect tl = visualRect(range.topLeft()); - QRect br = visualRect(range.bottomRight()); - selectionRegion += QRegion(tl|br); + + const int rtop = rowViewportPosition(range.top()); + const int rbottom = rowViewportPosition(range.bottom()) + rowHeight(range.bottom()); + const int rleft = columnViewportPosition(range.left()); + const int rright = columnViewportPosition(range.right()) + columnWidth(range.right()); + selectionRegion += QRect(QPoint(rleft, rtop), QPoint(rright, rbottom)); + if (d->hasSpans()) { + foreach (QSpanCollection::Span *s, + d->spans.spansInRect(range.left(), range.top(), range.width(), range.height())) { + if (range.contains(s->top(), s->left(), range.parent())) + selectionRegion += d->visualSpanRect(*s); + } + } } } @@ -1428,6 +1527,8 @@ void QTableView::updateGeometries() ++columnsInViewport; } } + columnsInViewport = qMax(columnsInViewport, 1); //there must be always at least 1 column + if (horizontalScrollMode() == QAbstractItemView::ScrollPerItem) { const int visibleColumns = columnCount - d->horizontalHeader->hiddenSectionCount(); horizontalScrollBar()->setRange(0, visibleColumns - columnsInViewport); @@ -1454,6 +1555,8 @@ void QTableView::updateGeometries() ++rowsInViewport; } } + rowsInViewport = qMax(rowsInViewport, 1); //there must be always at least 1 row + if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) { const int visibleRows = rowCount - d->verticalHeader->hiddenSectionCount(); verticalScrollBar()->setRange(0, visibleRows - rowsInViewport); @@ -1743,14 +1846,14 @@ void QTableView::setSortingEnabled(bool enable) disconnect(horizontalHeader(), SIGNAL(sectionPressed(int)), this, SLOT(selectColumn(int))); connect(horizontalHeader(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), - this, SLOT(sortByColumn(int))); + this, SLOT(sortByColumn(int)), Qt::UniqueConnection); sortByColumn(horizontalHeader()->sortIndicatorSection(), horizontalHeader()->sortIndicatorOrder()); } else { connect(d->horizontalHeader, SIGNAL(sectionEntered(int)), - this, SLOT(_q_selectColumn(int))); + this, SLOT(_q_selectColumn(int)), Qt::UniqueConnection); connect(horizontalHeader(), SIGNAL(sectionPressed(int)), - this, SLOT(selectColumn(int))); + this, SLOT(selectColumn(int)), Qt::UniqueConnection); disconnect(horizontalHeader(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(sortByColumn(int))); } @@ -1874,7 +1977,7 @@ QRect QTableView::visualRect(const QModelIndex &index) const d->executePostedLayout(); if (d->hasSpans()) { - QTableViewPrivate::Span span = d->span(index.row(), index.column()); + QSpanCollection::Span span = d->span(index.row(), index.column()); return d->visualSpanRect(span); } @@ -1903,7 +2006,7 @@ void QTableView::scrollTo(const QModelIndex &index, ScrollHint hint) || isIndexHidden(index)) return; - QTableViewPrivate::Span span; + QSpanCollection::Span span; if (d->hasSpans()) span = d->span(index.row(), index.column()); @@ -1936,7 +2039,7 @@ void QTableView::scrollTo(const QModelIndex &index, ScrollHint hint) if (positionAtRight || hint == PositionAtCenter || positionAtLeft) { int hiddenSections = 0; if (d->horizontalHeader->sectionsHidden()) { - for (int s = horizontalIndex; s >= 0; --s) { + for (int s = horizontalIndex - 1; s >= 0; --s) { int column = d->horizontalHeader->logicalIndex(s); if (d->horizontalHeader->isSectionHidden(column)) ++hiddenSections; @@ -1991,7 +2094,7 @@ void QTableView::scrollTo(const QModelIndex &index, ScrollHint hint) if (hint == PositionAtBottom || hint == PositionAtCenter || hint == PositionAtTop) { int hiddenSections = 0; if (d->verticalHeader->sectionsHidden()) { - for (int s = verticalIndex; s >= 0; --s) { + for (int s = verticalIndex - 1; s >= 0; --s) { int row = d->verticalHeader->logicalIndex(s); if (d->verticalHeader->isSectionHidden(row)) ++hiddenSections; @@ -2010,7 +2113,7 @@ void QTableView::scrollTo(const QModelIndex &index, ScrollHint hint) } } - d->setDirtyRegion(visualRect(index)); + update(index); } /*! @@ -2058,7 +2161,7 @@ void QTableView::timerEvent(QTimerEvent *event) QRect rect; int viewportHeight = d->viewport->height(); int viewportWidth = d->viewport->width(); - if (d->hasSpans() && d->spansIntersectColumns(d->columnsToUpdate)) { + if (d->hasSpans()) { rect = QRect(0, 0, viewportWidth, viewportHeight); } else { for (int i = d->columnsToUpdate.size()-1; i >= 0; --i) { @@ -2083,7 +2186,7 @@ void QTableView::timerEvent(QTimerEvent *event) int viewportHeight = d->viewport->height(); int viewportWidth = d->viewport->width(); int top; - if (d->hasSpans() && d->spansIntersectRows(d->rowsToUpdate)) { + if (d->hasSpans()) { top = 0; } else { top = viewportHeight; @@ -2114,7 +2217,7 @@ void QTableView::rowMoved(int, int oldIndex, int newIndex) updateGeometries(); int logicalOldIndex = d->verticalHeader->logicalIndex(oldIndex); int logicalNewIndex = d->verticalHeader->logicalIndex(newIndex); - if (d->hasSpans() && (d->spansIntersectRow(logicalOldIndex) || d->spansIntersectRow(logicalNewIndex))) { + if (d->hasSpans()) { d->viewport->update(); } else { int oldTop = rowViewportPosition(logicalOldIndex); @@ -2142,7 +2245,7 @@ void QTableView::columnMoved(int, int oldIndex, int newIndex) updateGeometries(); int logicalOldIndex = d->horizontalHeader->logicalIndex(oldIndex); int logicalNewIndex = d->horizontalHeader->logicalIndex(newIndex); - if (d->hasSpans() && (d->spansIntersectColumn(logicalOldIndex) || d->spansIntersectColumn(logicalNewIndex))) { + if (d->hasSpans()) { d->viewport->update(); } else { int oldLeft = columnViewportPosition(logicalOldIndex); @@ -2325,7 +2428,7 @@ bool QTableView::isIndexHidden(const QModelIndex &index) const if (isRowHidden(index.row()) || isColumnHidden(index.column())) return true; if (d->hasSpans()) { - QTableViewPrivate::Span span = d->span(index.row(), index.column()); + QSpanCollection::Span span = d->span(index.row(), index.column()); return !((span.top() == index.row()) && (span.left() == index.column())); } return false; diff --git a/src/gui/itemviews/qtableview_p.h b/src/gui/itemviews/qtableview_p.h index 7c0aa58..cd49dce 100644 --- a/src/gui/itemviews/qtableview_p.h +++ b/src/gui/itemviews/qtableview_p.h @@ -53,12 +53,69 @@ // We mean it. // +#include <QtCore/QList> +#include <QtCore/QMap> +#include <QtCore/QSet> +#include <QtCore/QDebug> #include "private/qabstractitemview_p.h" #ifndef QT_NO_TABLEVIEW QT_BEGIN_NAMESPACE +/** \internal +* +* This is a list of span with a binary index to look up quickly a span at a certain index. +* +* The index is a map of map. +* spans are mentaly divided into sub spans so that the start of any subspans doesn't overlap +* with any other subspans. There is no real representation of the subspans. +* The key of the first map is the row where the subspan starts, the value of the first map is +* a list (map) of all subspans that starts at the same row. It is indexed with its row +*/ +class QSpanCollection +{ +public: + struct Span + { + int m_top; + int m_left; + int m_bottom; + int m_right; + Span() + : m_top(-1), m_left(-1), m_bottom(-1), m_right(-1) { } + Span(int row, int column, int rowCount, int columnCount) + : m_top(row), m_left(column), m_bottom(row+rowCount-1), m_right(column+columnCount-1) { } + inline int top() const { return m_top; } + inline int left() const { return m_left; } + inline int bottom() const { return m_bottom; } + inline int right() const { return m_right; } + inline int height() const { return m_bottom - m_top + 1; } + inline int width() const { return m_right - m_left + 1; } + }; + + ~QSpanCollection() + { + qDeleteAll(spans); + } + + void addSpan(Span *span); + void updateSpan(Span *span, int old_height); + Span *spanAt(int x, int y) const; + void clear(); + QList<Span *> spansInRect(int x, int y, int w, int h) const; + + QList<Span *> spans; //lists of all spans +private: + //the indexes are negative so the QMap::lowerBound do what i need. + typedef QMap<int, Span *> SubIndex; + typedef QMap<int, SubIndex> Index; + Index index; +}; + +Q_DECLARE_TYPEINFO ( QSpanCollection::Span, Q_MOVABLE_TYPE); + + class QTableViewPrivate : public QAbstractItemViewPrivate { Q_DECLARE_PUBLIC(QTableView) @@ -98,11 +155,7 @@ public: int sectionSpanEndLogical(const QHeaderView *header, int logical, int span) const; int sectionSpanSize(const QHeaderView *header, int logical, int span) const; bool spanContainsSection(const QHeaderView *header, int logical, int spanLogical, int span) const; - bool spansIntersectColumn(int column) const; - bool spansIntersectRow(int row) const; - bool spansIntersectColumns(const QList<int> &columns) const; - bool spansIntersectRows(const QList<int> &rows) const; - void drawAndClipSpans(const QRect &area, QPainter *painter, + void drawAndClipSpans(const QRegion &area, QPainter *painter, const QStyleOptionViewItemV4 &option, QBitArray *drawn, int firstVisualRow, int lastVisualRow, int firstVisualColumn, int lastVisualColumn); void drawCell(QPainter *painter, const QStyleOptionViewItemV4 &option, const QModelIndex &index); @@ -121,27 +174,10 @@ public: bool sortingEnabled; bool geometryRecursionBlock; - struct Span - { - int m_top; - int m_left; - int m_bottom; - int m_right; - Span() - : m_top(-1), m_left(-1), m_bottom(-1), m_right(-1) { } - Span(int row, int column, int rowCount, int columnCount) - : m_top(row), m_left(column), m_bottom(row+rowCount-1), m_right(column+columnCount-1) { } - inline int top() const { return m_top; } - inline int left() const { return m_left; } - inline int bottom() const { return m_bottom; } - inline int right() const { return m_right; } - inline int height() const { return m_bottom - m_top + 1; } - inline int width() const { return m_right - m_left + 1; } - }; - QList<Span> spans; + QSpanCollection spans; void setSpan(int row, int column, int rowSpan, int columnSpan); - Span span(int row, int column) const; + QSpanCollection::Span span(int row, int column) const; inline int rowSpan(int row, int column) const { return span(row, column).height(); } @@ -149,17 +185,7 @@ public: return span(row, column).width(); } inline bool hasSpans() const { - return !spans.isEmpty(); - } - inline bool spanContainsRow(int row, int spanRow, int span) const { - return spanContainsSection(verticalHeader, row, spanRow, span); - } - inline bool spanContainsColumn(int column, int spanColumn, int span) const { - return spanContainsSection(horizontalHeader, column, spanColumn, span); - } - inline bool isInSpan(int row, int column, const Span &span) const { - return spanContainsRow(row, span.top(), span.height()) - && spanContainsColumn(column, span.left(), span.width()); + return !spans.spans.isEmpty(); } inline int rowSpanHeight(int row, int span) const { return sectionSpanSize(verticalHeader, row, span); @@ -194,7 +220,7 @@ public: return isColumnHidden(c) || !isCellEnabled(r, c); } - QRect visualSpanRect(const Span &span) const; + QRect visualSpanRect(const QSpanCollection::Span &span) const; void _q_selectRow(int row); void _q_selectColumn(int column); diff --git a/src/gui/itemviews/qtablewidget.cpp b/src/gui/itemviews/qtablewidget.cpp index 891cbcc..af0885d 100644 --- a/src/gui/itemviews/qtablewidget.cpp +++ b/src/gui/itemviews/qtablewidget.cpp @@ -226,6 +226,8 @@ QTableWidgetItem *QTableModel::takeItem(int row, int column) itm->view = 0; itm->d->id = -1; tableItems[i] = 0; + QModelIndex ind = index(itm); + emit dataChanged(ind, ind); } return itm; } @@ -530,24 +532,6 @@ void QTableModel::sort(int column, Qt::SortOrder order) emit layoutChanged(); } -bool QTableModel::canConvertToDouble(const QVariant &value) -{ - switch (value.type()) { - case QVariant::Bool: - case QVariant::Int: - case QVariant::UInt: - case QVariant::LongLong: - case QVariant::ULongLong: - case QVariant::Double: - case QVariant::Char: - return true; - default: - return false; - } - return false; -} - - /* \internal @@ -1410,9 +1394,7 @@ QVariant QTableWidgetItem::data(int role) const bool QTableWidgetItem::operator<(const QTableWidgetItem &other) const { const QVariant v1 = data(Qt::DisplayRole), v2 = other.data(Qt::DisplayRole); - if (QTableModel::canConvertToDouble(v1) && QTableModel::canConvertToDouble(v2)) - return v1.toDouble() < v2.toDouble(); - return v1.toString() < v2.toString(); + return QAbstractItemModelPrivate::variantLessThan(v1, v2); } #ifndef QT_NO_DATASTREAM @@ -1506,7 +1488,7 @@ QTableWidgetItem &QTableWidgetItem::operator=(const QTableWidgetItem &other) \brief The QTableWidget class provides an item-based table view with a default model. \ingroup model-view - \mainclass + Table widgets provide standard table display facilities for applications. The items in a QTableWidget are provided by QTableWidgetItem. @@ -1588,7 +1570,7 @@ void QTableWidgetPrivate::setup() QObject::connect(q, SIGNAL(activated(QModelIndex)), q, SLOT(_q_emitItemActivated(QModelIndex))); QObject::connect(q, SIGNAL(entered(QModelIndex)), q, SLOT(_q_emitItemEntered(QModelIndex))); // model signals - QObject::connect(model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), + QObject::connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), q, SLOT(_q_emitItemChanged(QModelIndex))); // selection signals QObject::connect(q->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), @@ -1596,15 +1578,15 @@ void QTableWidgetPrivate::setup() QObject::connect(q->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), q, SIGNAL(itemSelectionChanged())); // sorting - QObject::connect(model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), + QObject::connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), q, SLOT(_q_dataChanged(QModelIndex,QModelIndex))); - QObject::connect(model(), SIGNAL(columnsRemoved(QModelIndex,int,int)), q, SLOT(_q_sort())); + QObject::connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)), q, SLOT(_q_sort())); } void QTableWidgetPrivate::_q_emitItemPressed(const QModelIndex &index) { Q_Q(QTableWidget); - if (QTableWidgetItem *item = model()->item(index)) + if (QTableWidgetItem *item = tableModel()->item(index)) emit q->itemPressed(item); emit q->cellPressed(index.row(), index.column()); } @@ -1612,7 +1594,7 @@ void QTableWidgetPrivate::_q_emitItemPressed(const QModelIndex &index) void QTableWidgetPrivate::_q_emitItemClicked(const QModelIndex &index) { Q_Q(QTableWidget); - if (QTableWidgetItem *item = model()->item(index)) + if (QTableWidgetItem *item = tableModel()->item(index)) emit q->itemClicked(item); emit q->cellClicked(index.row(), index.column()); } @@ -1620,7 +1602,7 @@ void QTableWidgetPrivate::_q_emitItemClicked(const QModelIndex &index) void QTableWidgetPrivate::_q_emitItemDoubleClicked(const QModelIndex &index) { Q_Q(QTableWidget); - if (QTableWidgetItem *item = model()->item(index)) + if (QTableWidgetItem *item = tableModel()->item(index)) emit q->itemDoubleClicked(item); emit q->cellDoubleClicked(index.row(), index.column()); } @@ -1628,7 +1610,7 @@ void QTableWidgetPrivate::_q_emitItemDoubleClicked(const QModelIndex &index) void QTableWidgetPrivate::_q_emitItemActivated(const QModelIndex &index) { Q_Q(QTableWidget); - if (QTableWidgetItem *item = model()->item(index)) + if (QTableWidgetItem *item = tableModel()->item(index)) emit q->itemActivated(item); emit q->cellActivated(index.row(), index.column()); } @@ -1636,7 +1618,7 @@ void QTableWidgetPrivate::_q_emitItemActivated(const QModelIndex &index) void QTableWidgetPrivate::_q_emitItemEntered(const QModelIndex &index) { Q_Q(QTableWidget); - if (QTableWidgetItem *item = model()->item(index)) + if (QTableWidgetItem *item = tableModel()->item(index)) emit q->itemEntered(item); emit q->cellEntered(index.row(), index.column()); } @@ -1644,7 +1626,7 @@ void QTableWidgetPrivate::_q_emitItemEntered(const QModelIndex &index) void QTableWidgetPrivate::_q_emitItemChanged(const QModelIndex &index) { Q_Q(QTableWidget); - if (QTableWidgetItem *item = model()->item(index)) + if (QTableWidgetItem *item = tableModel()->item(index)) emit q->itemChanged(item); emit q->cellChanged(index.row(), index.column()); } @@ -1653,8 +1635,8 @@ void QTableWidgetPrivate::_q_emitCurrentItemChanged(const QModelIndex ¤t, const QModelIndex &previous) { Q_Q(QTableWidget); - QTableWidgetItem *currentItem = model()->item(current); - QTableWidgetItem *previousItem = model()->item(previous); + QTableWidgetItem *currentItem = tableModel()->item(current); + QTableWidgetItem *previousItem = tableModel()->item(previous); if (currentItem || previousItem) emit q->currentItemChanged(currentItem, previousItem); emit q->currentCellChanged(current.row(), current.column(), previous.row(), previous.column()); @@ -1662,23 +1644,21 @@ void QTableWidgetPrivate::_q_emitCurrentItemChanged(const QModelIndex ¤t, void QTableWidgetPrivate::_q_sort() { - Q_Q(QTableWidget); if (sortingEnabled) { - int column = q->horizontalHeader()->sortIndicatorSection(); - Qt::SortOrder order = q->horizontalHeader()->sortIndicatorOrder(); - model()->sort(column, order); + int column = horizontalHeader->sortIndicatorSection(); + Qt::SortOrder order = horizontalHeader->sortIndicatorOrder(); + model->sort(column, order); } } void QTableWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { - Q_Q(QTableWidget); if (sortingEnabled && topLeft.isValid() && bottomRight.isValid()) { - int column = q->horizontalHeader()->sortIndicatorSection(); + int column = horizontalHeader->sortIndicatorSection(); if (column >= topLeft.column() && column <= bottomRight.column()) { - Qt::SortOrder order = q->horizontalHeader()->sortIndicatorOrder(); - model()->ensureSorted(column, order, topLeft.row(), bottomRight.row()); + Qt::SortOrder order = horizontalHeader->sortIndicatorOrder(); + tableModel()->ensureSorted(column, order, topLeft.row(), bottomRight.row()); } } } @@ -1739,7 +1719,7 @@ void QTableWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, This signal is emitted whenever the selection changes. - \sa selectedItems() isItemSelected() + \sa selectedItems() QTableWidgetItem::isSelected() */ @@ -1882,7 +1862,7 @@ QTableWidget::~QTableWidget() void QTableWidget::setRowCount(int rows) { Q_D(QTableWidget); - d->model()->setRowCount(rows); + d->tableModel()->setRowCount(rows); } /*! @@ -1892,7 +1872,7 @@ void QTableWidget::setRowCount(int rows) int QTableWidget::rowCount() const { Q_D(const QTableWidget); - return d->model()->rowCount(); + return d->model->rowCount(); } /*! @@ -1905,7 +1885,7 @@ int QTableWidget::rowCount() const void QTableWidget::setColumnCount(int columns) { Q_D(QTableWidget); - d->model()->setColumnCount(columns); + d->tableModel()->setColumnCount(columns); } /*! @@ -1915,7 +1895,7 @@ void QTableWidget::setColumnCount(int columns) int QTableWidget::columnCount() const { Q_D(const QTableWidget); - return d->model()->columnCount(); + return d->model->columnCount(); } /*! @@ -1924,7 +1904,7 @@ int QTableWidget::columnCount() const int QTableWidget::row(const QTableWidgetItem *item) const { Q_D(const QTableWidget); - return d->model()->index(item).row(); + return d->tableModel()->index(item).row(); } /*! @@ -1933,7 +1913,7 @@ int QTableWidget::row(const QTableWidgetItem *item) const int QTableWidget::column(const QTableWidgetItem *item) const { Q_D(const QTableWidget); - return d->model()->index(item).column(); + return d->tableModel()->index(item).column(); } @@ -1946,7 +1926,7 @@ int QTableWidget::column(const QTableWidgetItem *item) const QTableWidgetItem *QTableWidget::item(int row, int column) const { Q_D(const QTableWidget); - return d->model()->item(row, column); + return d->tableModel()->item(row, column); } /*! @@ -1975,7 +1955,7 @@ void QTableWidget::setItem(int row, int column, QTableWidgetItem *item) qWarning("QTableWidget: cannot insert an item that is already owned by another QTableWidget"); } else { item->view = this; - d->model()->setItem(row, column, item); + d->tableModel()->setItem(row, column, item); } } else { delete takeItem(row, column); @@ -1988,7 +1968,7 @@ void QTableWidget::setItem(int row, int column, QTableWidgetItem *item) QTableWidgetItem *QTableWidget::takeItem(int row, int column) { Q_D(QTableWidget); - QTableWidgetItem *item = d->model()->takeItem(row, column); + QTableWidgetItem *item = d->tableModel()->takeItem(row, column); if (item) item->view = 0; return item; @@ -2000,7 +1980,7 @@ QTableWidgetItem *QTableWidget::takeItem(int row, int column) QTableWidgetItem *QTableWidget::verticalHeaderItem(int row) const { Q_D(const QTableWidget); - return d->model()->verticalHeaderItem(row); + return d->tableModel()->verticalHeaderItem(row); } /*! @@ -2011,7 +1991,7 @@ void QTableWidget::setVerticalHeaderItem(int row, QTableWidgetItem *item) Q_D(QTableWidget); if (item) { item->view = this; - d->model()->setVerticalHeaderItem(row, item); + d->tableModel()->setVerticalHeaderItem(row, item); } else { delete takeVerticalHeaderItem(row); } @@ -2024,7 +2004,7 @@ void QTableWidget::setVerticalHeaderItem(int row, QTableWidgetItem *item) QTableWidgetItem *QTableWidget::takeVerticalHeaderItem(int row) { Q_D(QTableWidget); - QTableWidgetItem *itm = d->model()->takeVerticalHeaderItem(row); + QTableWidgetItem *itm = d->tableModel()->takeVerticalHeaderItem(row); if (itm) itm->view = 0; return itm; @@ -2037,7 +2017,7 @@ QTableWidgetItem *QTableWidget::takeVerticalHeaderItem(int row) QTableWidgetItem *QTableWidget::horizontalHeaderItem(int column) const { Q_D(const QTableWidget); - return d->model()->horizontalHeaderItem(column); + return d->tableModel()->horizontalHeaderItem(column); } /*! @@ -2048,7 +2028,7 @@ void QTableWidget::setHorizontalHeaderItem(int column, QTableWidgetItem *item) Q_D(QTableWidget); if (item) { item->view = this; - d->model()->setHorizontalHeaderItem(column, item); + d->tableModel()->setHorizontalHeaderItem(column, item); } else { delete takeHorizontalHeaderItem(column); } @@ -2061,7 +2041,7 @@ void QTableWidget::setHorizontalHeaderItem(int column, QTableWidgetItem *item) QTableWidgetItem *QTableWidget::takeHorizontalHeaderItem(int column) { Q_D(QTableWidget); - QTableWidgetItem *itm = d->model()->takeHorizontalHeaderItem(column); + QTableWidgetItem *itm = d->tableModel()->takeHorizontalHeaderItem(column); if (itm) itm->view = 0; return itm; @@ -2073,7 +2053,7 @@ QTableWidgetItem *QTableWidget::takeHorizontalHeaderItem(int column) void QTableWidget::setVerticalHeaderLabels(const QStringList &labels) { Q_D(QTableWidget); - QTableModel *model = d->model(); + QTableModel *model = d->tableModel(); QTableWidgetItem *item = 0; for (int i = 0; i < model->rowCount() && i < labels.count(); ++i) { item = model->verticalHeaderItem(i); @@ -2091,7 +2071,7 @@ void QTableWidget::setVerticalHeaderLabels(const QStringList &labels) void QTableWidget::setHorizontalHeaderLabels(const QStringList &labels) { Q_D(QTableWidget); - QTableModel *model = d->model(); + QTableModel *model = d->tableModel(); QTableWidgetItem *item = 0; for (int i = 0; i < model->columnCount() && i < labels.count(); ++i) { item = model->horizontalHeaderItem(i); @@ -2131,21 +2111,21 @@ int QTableWidget::currentColumn() const QTableWidgetItem *QTableWidget::currentItem() const { Q_D(const QTableWidget); - return d->model()->item(currentIndex()); + return d->tableModel()->item(currentIndex()); } /*! Sets the current item to \a item. - Depending on the current \l{QAbstractItemView::SelectionMode}{selection mode}, - the item may also be selected. + Unless the selection mode is \l{QAbstractItemView::}{NoSelection}, + the item is also be selected. \sa currentItem(), setCurrentCell() */ void QTableWidget::setCurrentItem(QTableWidgetItem *item) { Q_D(QTableWidget); - setCurrentIndex(d->model()->index(item)); + setCurrentIndex(d->tableModel()->index(item)); } /*! @@ -2158,7 +2138,7 @@ void QTableWidget::setCurrentItem(QTableWidgetItem *item) void QTableWidget::setCurrentItem(QTableWidgetItem *item, QItemSelectionModel::SelectionFlags command) { Q_D(QTableWidget); - d->selectionModel->setCurrentIndex(d->model()->index(item), command); + d->selectionModel->setCurrentIndex(d->tableModel()->index(item), command); } /*! @@ -2197,7 +2177,7 @@ void QTableWidget::setCurrentCell(int row, int column, QItemSelectionModel::Sele void QTableWidget::sortItems(int column, Qt::SortOrder order) { Q_D(QTableWidget); - d->model()->sort(column, order); + d->model->sort(column, order); horizontalHeader()->setSortIndicator(column, order); } @@ -2226,7 +2206,7 @@ void QTableWidget::editItem(QTableWidgetItem *item) Q_D(QTableWidget); if (!item) return; - edit(d->model()->index(item)); + edit(d->tableModel()->index(item)); } /*! @@ -2239,7 +2219,7 @@ void QTableWidget::openPersistentEditor(QTableWidgetItem *item) Q_D(QTableWidget); if (!item) return; - QModelIndex index = d->model()->index(item); + QModelIndex index = d->tableModel()->index(item); QAbstractItemView::openPersistentEditor(index); } @@ -2253,7 +2233,7 @@ void QTableWidget::closePersistentEditor(QTableWidgetItem *item) Q_D(QTableWidget); if (!item) return; - QModelIndex index = d->model()->index(item); + QModelIndex index = d->tableModel()->index(item); QAbstractItemView::closePersistentEditor(index); } @@ -2303,7 +2283,7 @@ void QTableWidget::setCellWidget(int row, int column, QWidget *widget) bool QTableWidget::isItemSelected(const QTableWidgetItem *item) const { Q_D(const QTableWidget); - QModelIndex index = d->model()->index(item); + QModelIndex index = d->tableModel()->index(item); return selectionModel()->isSelected(index); } @@ -2317,7 +2297,7 @@ bool QTableWidget::isItemSelected(const QTableWidgetItem *item) const void QTableWidget::setItemSelected(const QTableWidgetItem *item, bool select) { Q_D(QTableWidget); - QModelIndex index = d->model()->index(item); + QModelIndex index = d->tableModel()->index(item); selectionModel()->select(index, select ? QItemSelectionModel::Select : QItemSelectionModel::Deselect); } @@ -2374,7 +2354,7 @@ QList<QTableWidgetItem*> QTableWidget::selectedItems() QModelIndex index = indexes.at(i); if (isIndexHidden(index)) continue; - QTableWidgetItem *item = d->model()->item(index); + QTableWidgetItem *item = d->tableModel()->item(index); if (item) items.append(item); } @@ -2390,11 +2370,11 @@ QList<QTableWidgetItem*> QTableWidget::findItems(const QString &text, Qt::MatchF Q_D(const QTableWidget); QModelIndexList indexes; for (int column = 0; column < columnCount(); ++column) - indexes += d->model()->match(model()->index(0, column, QModelIndex()), + indexes += d->model->match(model()->index(0, column, QModelIndex()), Qt::DisplayRole, text, -1, flags); QList<QTableWidgetItem*> items; for (int i = 0; i < indexes.size(); ++i) - items.append(d->model()->item(indexes.at(i))); + items.append(d->tableModel()->item(indexes.at(i))); return items; } @@ -2428,7 +2408,7 @@ int QTableWidget::visualColumn(int logicalColumn) const QTableWidgetItem *QTableWidget::itemAt(const QPoint &p) const { Q_D(const QTableWidget); - return d->model()->item(indexAt(p)); + return d->tableModel()->item(indexAt(p)); } /*! @@ -2439,7 +2419,7 @@ QRect QTableWidget::visualItemRect(const QTableWidgetItem *item) const Q_D(const QTableWidget); if (!item) return QRect(); - QModelIndex index = d->model()->index(const_cast<QTableWidgetItem*>(item)); + QModelIndex index = d->tableModel()->index(const_cast<QTableWidgetItem*>(item)); Q_ASSERT(index.isValid()); return visualRect(index); } @@ -2455,7 +2435,7 @@ void QTableWidget::scrollToItem(const QTableWidgetItem *item, QAbstractItemView: Q_D(QTableWidget); if (!item) return; - QModelIndex index = d->model()->index(const_cast<QTableWidgetItem*>(item)); + QModelIndex index = d->tableModel()->index(const_cast<QTableWidgetItem*>(item)); Q_ASSERT(index.isValid()); QTableView::scrollTo(index, hint); } @@ -2468,7 +2448,7 @@ void QTableWidget::scrollToItem(const QTableWidgetItem *item, QAbstractItemView: const QTableWidgetItem *QTableWidget::itemPrototype() const { Q_D(const QTableWidget); - return d->model()->itemPrototype(); + return d->tableModel()->itemPrototype(); } /*! @@ -2487,7 +2467,7 @@ const QTableWidgetItem *QTableWidget::itemPrototype() const void QTableWidget::setItemPrototype(const QTableWidgetItem *item) { Q_D(QTableWidget); - d->model()->setItemPrototype(item); + d->tableModel()->setItemPrototype(item); } /*! @@ -2496,7 +2476,7 @@ void QTableWidget::setItemPrototype(const QTableWidgetItem *item) void QTableWidget::insertRow(int row) { Q_D(QTableWidget); - d->model()->insertRows(row); + d->tableModel()->insertRows(row); } /*! @@ -2505,7 +2485,7 @@ void QTableWidget::insertRow(int row) void QTableWidget::insertColumn(int column) { Q_D(QTableWidget); - d->model()->insertColumns(column); + d->tableModel()->insertColumns(column); } /*! @@ -2514,7 +2494,7 @@ void QTableWidget::insertColumn(int column) void QTableWidget::removeRow(int row) { Q_D(QTableWidget); - d->model()->removeRows(row); + d->tableModel()->removeRows(row); } /*! @@ -2523,7 +2503,7 @@ void QTableWidget::removeRow(int row) void QTableWidget::removeColumn(int column) { Q_D(QTableWidget); - d->model()->removeColumns(column); + d->tableModel()->removeColumns(column); } /*! @@ -2536,7 +2516,7 @@ void QTableWidget::clear() { Q_D(QTableWidget); selectionModel()->clear(); - d->model()->clear(); + d->tableModel()->clear(); } /*! @@ -2550,7 +2530,7 @@ void QTableWidget::clearContents() { Q_D(QTableWidget); selectionModel()->clear(); - d->model()->clearContents(); + d->tableModel()->clearContents(); } /*! @@ -2561,7 +2541,7 @@ void QTableWidget::clearContents() */ QStringList QTableWidget::mimeTypes() const { - return d_func()->model()->QAbstractTableModel::mimeTypes(); + return d_func()->tableModel()->QAbstractTableModel::mimeTypes(); } /*! @@ -2574,7 +2554,7 @@ QStringList QTableWidget::mimeTypes() const */ QMimeData *QTableWidget::mimeData(const QList<QTableWidgetItem*>) const { - return d_func()->model()->internalMimeData(); + return d_func()->tableModel()->internalMimeData(); } /*! @@ -2596,7 +2576,7 @@ bool QTableWidget::dropMimeData(int row, int column, const QMimeData *data, Qt:: column = -1; } #endif - return d_func()->model()->QAbstractTableModel::dropMimeData(data, action , row, column, idx); + return d_func()->tableModel()->QAbstractTableModel::dropMimeData(data, action , row, column, idx); } /*! @@ -2606,7 +2586,7 @@ bool QTableWidget::dropMimeData(int row, int column, const QMimeData *data, Qt:: */ Qt::DropActions QTableWidget::supportedDropActions() const { - return d_func()->model()->QAbstractTableModel::supportedDropActions() | Qt::MoveAction; + return d_func()->tableModel()->QAbstractTableModel::supportedDropActions() | Qt::MoveAction; } /*! @@ -2630,7 +2610,7 @@ QList<QTableWidgetItem*> QTableWidget::items(const QMimeData *data) const QModelIndex QTableWidget::indexFromItem(QTableWidgetItem *item) const { Q_D(const QTableWidget); - return d->model()->index(item); + return d->tableModel()->index(item); } /*! @@ -2640,7 +2620,7 @@ QModelIndex QTableWidget::indexFromItem(QTableWidgetItem *item) const QTableWidgetItem *QTableWidget::itemFromIndex(const QModelIndex &index) const { Q_D(const QTableWidget); - return d->model()->item(index); + return d->tableModel()->item(index); } /*! diff --git a/src/gui/itemviews/qtablewidget_p.h b/src/gui/itemviews/qtablewidget_p.h index fdfbc20..a80c1ee 100644 --- a/src/gui/itemviews/qtablewidget_p.h +++ b/src/gui/itemviews/qtablewidget_p.h @@ -144,7 +144,6 @@ public: const QPair<QTableWidgetItem*,int> &right); static bool itemGreaterThan(const QPair<QTableWidgetItem*,int> &left, const QPair<QTableWidgetItem*,int> &right); - static bool canConvertToDouble(const QVariant &value); void ensureSorted(int column, Qt::SortOrder order, int start, int end); QVector<QTableWidgetItem*> columnItems(int column) const; @@ -190,7 +189,7 @@ class QTableWidgetPrivate : public QTableViewPrivate Q_DECLARE_PUBLIC(QTableWidget) public: QTableWidgetPrivate() : QTableViewPrivate() {} - inline QTableModel *model() const { return qobject_cast<QTableModel*>(q_func()->model()); } + inline QTableModel *tableModel() const { return qobject_cast<QTableModel*>(model); } void setup(); // view signals diff --git a/src/gui/itemviews/qtreeview.cpp b/src/gui/itemviews/qtreeview.cpp index 99cbacc..a5b4044 100644 --- a/src/gui/itemviews/qtreeview.cpp +++ b/src/gui/itemviews/qtreeview.cpp @@ -66,7 +66,7 @@ QT_BEGIN_NAMESPACE \ingroup model-view \ingroup advanced - \mainclass + A QTreeView implements a tree representation of items from a model. This class is used to provide standard hierarchical lists that @@ -238,11 +238,6 @@ void QTreeView::setModel(QAbstractItemModel *model) connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(rowsRemoved(QModelIndex,int,int))); - connect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)), - this, SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int))); - connect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)), - this, SLOT(_q_columnsRemoved(QModelIndex,int,int))); - connect(d->model, SIGNAL(modelAboutToBeReset()), SLOT(_q_modelAboutToBeReset())); if (d->sortingEnabled) @@ -267,10 +262,6 @@ void QTreeView::setSelectionModel(QItemSelectionModel *selectionModel) Q_D(QTreeView); Q_ASSERT(selectionModel); if (d->selectionModel) { - if (d->allColumnsShowFocus) { - QObject::disconnect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), - this, SLOT(_q_currentChanged(QModelIndex,QModelIndex))); - } // support row editing disconnect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), d->model, SLOT(submit())); @@ -280,10 +271,6 @@ void QTreeView::setSelectionModel(QItemSelectionModel *selectionModel) QAbstractItemView::setSelectionModel(selectionModel); if (d->selectionModel) { - if (d->allColumnsShowFocus) { - QObject::connect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), - this, SLOT(_q_currentChanged(QModelIndex,QModelIndex))); - } // support row editing connect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), d->model, SLOT(submit())); @@ -680,10 +667,9 @@ void QTreeView::dataChanged(const QModelIndex &topLeft, const QModelIndex &botto // refresh the height cache here; we don't really lose anything by getting the size hint, // since QAbstractItemView::dataChanged() will get the visualRect for the items anyway - QModelIndex top = topLeft.sibling(topLeft.row(), 0); - int topViewIndex = d->viewIndex(top); + int topViewIndex = d->viewIndex(topLeft); if (topViewIndex == 0) - d->defaultItemHeight = indexRowSizeHint(top); + d->defaultItemHeight = indexRowSizeHint(topLeft); bool sizeChanged = false; if (topViewIndex != -1) { if (topLeft == bottomRight) { @@ -691,8 +677,7 @@ void QTreeView::dataChanged(const QModelIndex &topLeft, const QModelIndex &botto d->invalidateHeightCache(topViewIndex); sizeChanged = (oldHeight != d->itemHeight(topViewIndex)); } else { - QModelIndex bottom = bottomRight.sibling(bottomRight.row(), 0); - int bottomViewIndex = d->viewIndex(bottom); + int bottomViewIndex = d->viewIndex(bottomRight); for (int i = topViewIndex; i <= bottomViewIndex; ++i) { int oldHeight = d->itemHeight(i); d->invalidateHeightCache(i); @@ -853,7 +838,7 @@ void QTreeView::setSortingEnabled(bool enable) // because otherwise it will not call sort on the model. sortByColumn(header()->sortIndicatorSection(), header()->sortIndicatorOrder()); connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), - this, SLOT(_q_sortIndicatorChanged(int, Qt::SortOrder))); + this, SLOT(_q_sortIndicatorChanged(int, Qt::SortOrder)), Qt::UniqueConnection); } else { disconnect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(_q_sortIndicatorChanged(int, Qt::SortOrder))); @@ -908,15 +893,6 @@ void QTreeView::setAllColumnsShowFocus(bool enable) Q_D(QTreeView); if (d->allColumnsShowFocus == enable) return; - if (d->selectionModel) { - if (enable) { - QObject::connect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), - this, SLOT(_q_currentChanged(QModelIndex,QModelIndex))); - } else { - QObject::disconnect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), - this, SLOT(_q_currentChanged(QModelIndex,QModelIndex))); - } - } d->allColumnsShowFocus = enable; d->viewport->update(); } @@ -1119,18 +1095,22 @@ void QTreeView::scrollTo(const QModelIndex &index, ScrollHint hint) } else if (hint == PositionAtTop || (hint == EnsureVisible && item < top)) { verticalScrollBar()->setValue(item); } else { // PositionAtBottom or PositionAtCenter - int itemLocation = item; + const int currentItemHeight = d->itemHeight(item); int y = (hint == PositionAtCenter - ? area.height() / 2 + //we center on the current item with a preference to the top item (ie. -1) + ? area.height() / 2 + currentItemHeight - 1 + //otherwise we simply take the whole space : area.height()); - while (y > 0 && item > 0) - y -= d->itemHeight(item--); - // end up half over the top of the area - if (y < 0 && item < itemLocation) - ++item; - // end up half over the bottom of the area - if (item >= 0 && item < itemLocation) - ++item; + if (y > currentItemHeight) { + while (item >= 0) { + y -= d->itemHeight(item); + if (y < 0) { //there is no more space left + item++; + break; + } + item--; + } + } verticalScrollBar()->setValue(item); } } else { // ScrollPerPixel @@ -1142,7 +1122,7 @@ void QTreeView::scrollTo(const QModelIndex &index, ScrollHint hint) if (rect.isEmpty()) { // nothing to do } else if (hint == EnsureVisible && area.contains(rect)) { - d->setDirtyRegion(rect); + d->viewport->update(rect); // nothing to do } else { bool above = (hint == EnsureVisible @@ -1274,10 +1254,13 @@ void QTreeView::paintEvent(QPaintEvent *event) Q_D(QTreeView); d->executePostedLayout(); QPainter painter(viewport()); +#ifndef QT_NO_ANIMATION if (d->isAnimating()) { - drawTree(&painter, event->region() - d->animationRect()); + drawTree(&painter, event->region() - d->animatedOperation.rect()); d->drawAnimatedOperation(&painter); - } else { + } else +#endif //QT_NO_ANIMATION + { drawTree(&painter, event->region()); #ifndef QT_NO_DRAGANDDROP d->paintDropIndicator(&painter); @@ -1313,20 +1296,20 @@ bool QTreeViewPrivate::expandOrCollapseItemAtPos(const QPoint &pos) { Q_Q(QTreeView); // we want to handle mousePress in EditingState (persistent editors) - if ((q->state() != QAbstractItemView::NoState - && q->state() != QAbstractItemView::EditingState) + if ((state != QAbstractItemView::NoState + && state != QAbstractItemView::EditingState) || !viewport->rect().contains(pos)) return true; int i = itemDecorationAt(pos); - if ((i != -1) && q->itemsExpandable() && hasVisibleChildren(viewItems.at(i).index)) { + if ((i != -1) && itemsExpandable && hasVisibleChildren(viewItems.at(i).index)) { if (viewItems.at(i).expanded) collapse(i, true); else expand(i, true); if (!isAnimating()) { q->updateGeometries(); - q->viewport()->update(); + viewport->update(); } return true; } @@ -1342,6 +1325,50 @@ void QTreeViewPrivate::_q_modelDestroyed() } /*! + \reimp + + We have a QTreeView way of knowing what elements are on the viewport +*/ +QItemViewPaintPairs QTreeViewPrivate::draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const +{ + Q_ASSERT(r); + return QAbstractItemViewPrivate::draggablePaintPairs(indexes, r); + Q_Q(const QTreeView); + QRect &rect = *r; + const QRect viewportRect = viewport->rect(); + int itemOffset = 0; + int row = firstVisibleItem(&itemOffset); + QPair<int, int> startEnd = startAndEndColumns(viewportRect); + QVector<int> columns; + for (int i = startEnd.first; i <= startEnd.second; ++i) { + int logical = header->logicalIndex(i); + if (!header->isSectionHidden(logical)) + columns += logical; + } + QSet<QModelIndex> visibleIndexes; + for (; itemOffset < viewportRect.bottom() && row < viewItems.count(); ++row) { + const QModelIndex &index = viewItems.at(row).index; + for (int colIndex = 0; colIndex < columns.count(); ++colIndex) + visibleIndexes += index.sibling(index.row(), columns.at(colIndex)); + itemOffset += itemHeight(row); + } + + //now that we have the visible indexes, we can try to find those which are selected + QItemViewPaintPairs ret; + for (int i = 0; i < indexes.count(); ++i) { + const QModelIndex &index = indexes.at(i); + if (visibleIndexes.contains(index)) { + const QRect current = q->visualRect(index); + ret += qMakePair(current, index); + rect |= current; + } + } + rect &= viewportRect; + return ret; +} + + +/*! \since 4.2 Draws the part of the tree intersecting the given \a region using the specified \a painter. @@ -1548,7 +1575,7 @@ void QTreeView::drawRow(QPainter *painter, const QStyleOptionViewItem &option, ? logicalIndexBeforeLeft : logicalIndices.at(currentLogicalSection - 1); if (columnCount == 1 || (nextLogicalSection == 0 && prevLogicalSection == -1) - || (headerSection == 0 && nextLogicalSection == -1)) + || (headerSection == 0 && nextLogicalSection == -1) || spanning) opt.viewItemPosition = QStyleOptionViewItemV4::OnlyOne; else if (headerSection == 0 || (nextLogicalSection != 0 && prevLogicalSection == -1)) opt.viewItemPosition = QStyleOptionViewItemV4::Beginning; @@ -1817,10 +1844,10 @@ void QTreeView::mouseDoubleClickEvent(QMouseEvent *event) if (i == -1) return; // user clicked outside the items - const QModelIndex &index = d->viewItems.at(i).index; + const QPersistentModelIndex firstColumnIndex = d->viewItems.at(i).index; int column = d->header->logicalIndexAt(event->x()); - QPersistentModelIndex persistent = index.sibling(index.row(), column); + QPersistentModelIndex persistent = firstColumnIndex.sibling(firstColumnIndex.row(), column); if (d->pressedIndex != persistent) { mousePressEvent(event); @@ -1843,10 +1870,10 @@ void QTreeView::mouseDoubleClickEvent(QMouseEvent *event) if (d->itemsExpandable && d->expandsOnDoubleClick && d->hasVisibleChildren(persistent)) { - if (!((i < d->viewItems.count()) && (d->viewItems.at(i).index == persistent))) { + if (!((i < d->viewItems.count()) && (d->viewItems.at(i).index == firstColumnIndex))) { // find the new index of the item for (i = 0; i < d->viewItems.count(); ++i) { - if (d->viewItems.at(i).index == persistent) + if (d->viewItems.at(i).index == firstColumnIndex) break; } if (i == d->viewItems.count()) @@ -2074,7 +2101,8 @@ QModelIndex QTreeView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifie const bool useTopIndex = (cursorAction == MoveUp || cursorAction == MovePrevious); int index = useTopIndex ? INT_MAX : INT_MIN; const QItemSelection selection = d->selectionModel->selection(); - foreach (const QItemSelectionRange &range, selection) { + for (int i = 0; i < selection.count(); ++i) { + const QItemSelectionRange &range = selection.at(i); int candidate = d->viewIndex(useTopIndex ? range.topLeft() : range.bottomRight()); if (candidate >= 0) index = useTopIndex ? qMin(index, candidate) : qMax(index, candidate); @@ -2424,14 +2452,10 @@ void QTreeView::rowsInserted(const QModelIndex &parent, int start, int end) ? d->viewItems.count() : d->viewItems.at(parentItem).total) - 1; - int firstColumn = 0; - while (isColumnHidden(firstColumn) && firstColumn < header()->count() - 1) - ++firstColumn; - const int delta = end - start + 1; QVector<QTreeViewItem> insertedItems(delta); for (int i = 0; i < delta; ++i) { - insertedItems[i].index = d->model->index(i + start, firstColumn, parent); + insertedItems[i].index = d->model->index(i + start, 0, parent); insertedItems[i].level = childLevel; } if (d->viewItems.isEmpty()) @@ -2614,7 +2638,7 @@ void QTreeView::expandAll() d->viewItems[i].expanded = true; d->layout(i); QModelIndex idx = d->viewItems.at(i).index; - d->expandedIndexes.insert(idx.sibling(idx.row(), 0)); + d->expandedIndexes.insert(idx); } updateGeometries(); d->viewport->update(); @@ -2773,15 +2797,14 @@ int QTreeView::indexRowSizeHint(const QModelIndex &index) const if (isRightToLeft()) { start = (start == -1 ? count - 1 : start); - end = (end == -1 ? 0 : end); + end = 0; } else { start = (start == -1 ? 0 : start); - end = (end == -1 ? count - 1 : end); + end = count - 1; } - int tmp = start; - start = qMin(start, end); - end = qMax(tmp, end); + if (end < start) + qSwap(end, start); int height = -1; QStyleOptionViewItemV4 option = d->viewOptionsV4(); @@ -2829,7 +2852,7 @@ int QTreeView::rowHeight(const QModelIndex &index) const } /*! - \reimp + \internal */ void QTreeView::horizontalScrollbarAction(int action) { @@ -2861,10 +2884,9 @@ void QTreeViewPrivate::initialize() header->setStretchLastSection(true); header->setDefaultAlignment(Qt::AlignLeft|Qt::AlignVCenter); q->setHeader(header); - - // animation - QObject::connect(&timeline, SIGNAL(frameChanged(int)), q, SLOT(_q_animate())); - QObject::connect(&timeline, SIGNAL(finished()), q, SLOT(_q_endAnimatedOperation()), Qt::QueuedConnection); +#ifndef QT_NO_ANIMATION + QObject::connect(&animatedOperation, SIGNAL(finished()), q, SLOT(_q_endAnimatedOperation())); +#endif //QT_NO_ANIMATION } void QTreeViewPrivate::expand(int item, bool emitSignal) @@ -2874,10 +2896,11 @@ void QTreeViewPrivate::expand(int item, bool emitSignal) if (item == -1 || viewItems.at(item).expanded) return; +#ifndef QT_NO_ANIMATION if (emitSignal && animationsEnabled) - prepareAnimatedOperation(item, AnimatedOperation::Expand); - - QAbstractItemView::State oldState = q->state(); + prepareAnimatedOperation(item, QVariantAnimation::Forward); +#endif //QT_NO_ANIMATION + QAbstractItemView::State oldState = state; q->setState(QAbstractItemView::ExpandingState); const QModelIndex index = viewItems.at(item).index; storeExpanded(index); @@ -2887,8 +2910,10 @@ void QTreeViewPrivate::expand(int item, bool emitSignal) if (emitSignal) { emit q->expanded(index); +#ifndef QT_NO_ANIMATION if (animationsEnabled) beginAnimatedOperation(); +#endif //QT_NO_ANIMATION } if (model->canFetchMore(index)) model->fetchMore(index); @@ -2912,10 +2937,12 @@ void QTreeViewPrivate::collapse(int item, bool emitSignal) if (it == expandedIndexes.end() || viewItems.at(item).expanded == false) return; // nothing to do +#ifndef QT_NO_ANIMATION if (emitSignal && animationsEnabled) - prepareAnimatedOperation(item, AnimatedOperation::Collapse); + prepareAnimatedOperation(item, QVariantAnimation::Backward); +#endif //QT_NO_ANIMATION - QAbstractItemView::State oldState = q->state(); + QAbstractItemView::State oldState = state; q->setState(QAbstractItemView::CollapsingState); expandedIndexes.erase(it); viewItems[item].expanded = false; @@ -2932,29 +2959,33 @@ void QTreeViewPrivate::collapse(int item, bool emitSignal) if (emitSignal) { emit q->collapsed(modelIndex); +#ifndef QT_NO_ANIMATION if (animationsEnabled) beginAnimatedOperation(); +#endif //QT_NO_ANIMATION } } -void QTreeViewPrivate::prepareAnimatedOperation(int item, AnimatedOperation::Type type) +#ifndef QT_NO_ANIMATION +void QTreeViewPrivate::prepareAnimatedOperation(int item, QVariantAnimation::Direction direction) { animatedOperation.item = item; - animatedOperation.type = type; + animatedOperation.viewport = viewport; + animatedOperation.setDirection(direction); int top = coordinateForItem(item) + itemHeight(item); QRect rect = viewport->rect(); rect.setTop(top); - if (type == AnimatedOperation::Collapse) { + if (direction == QVariantAnimation::Backward) { const int limit = rect.height() * 2; int h = 0; int c = item + viewItems.at(item).total + 1; for (int i = item + 1; i < c && h < limit; ++i) h += itemHeight(i); rect.setHeight(h); - animatedOperation.duration = h; + animatedOperation.setEndValue(top + h); } - animatedOperation.top = top; + animatedOperation.setStartValue(top); animatedOperation.before = renderTreeToPixmapForAnimation(rect); } @@ -2963,50 +2994,29 @@ void QTreeViewPrivate::beginAnimatedOperation() Q_Q(QTreeView); QRect rect = viewport->rect(); - rect.setTop(animatedOperation.top); - if (animatedOperation.type == AnimatedOperation::Expand) { + rect.setTop(animatedOperation.top()); + if (animatedOperation.direction() == QVariantAnimation::Forward) { const int limit = rect.height() * 2; int h = 0; int c = animatedOperation.item + viewItems.at(animatedOperation.item).total + 1; for (int i = animatedOperation.item + 1; i < c && h < limit; ++i) h += itemHeight(i); rect.setHeight(h); - animatedOperation.duration = h; + animatedOperation.setEndValue(animatedOperation.top() + h); } animatedOperation.after = renderTreeToPixmapForAnimation(rect); q->setState(QAbstractItemView::AnimatingState); - - timeline.stop(); - timeline.setDuration(250); - timeline.setFrameRange(animatedOperation.top, animatedOperation.top + animatedOperation.duration); - timeline.start(); -} - -void QTreeViewPrivate::_q_endAnimatedOperation() -{ - Q_Q(QTreeView); - animatedOperation.before = QPixmap(); - animatedOperation.after = QPixmap(); - q->setState(QAbstractItemView::NoState); - q->updateGeometries(); - viewport->update(); -} - -void QTreeViewPrivate::_q_animate() -{ - QRect rect = viewport->rect(); - rect.moveTop(animatedOperation.top); - viewport->repaint(rect); + animatedOperation.start(); //let's start the animation } void QTreeViewPrivate::drawAnimatedOperation(QPainter *painter) const { - int start = timeline.startFrame(); - int end = timeline.endFrame(); - bool collapsing = animatedOperation.type == AnimatedOperation::Collapse; - int current = collapsing ? end - timeline.currentFrame() + start : timeline.currentFrame(); + const int start = animatedOperation.startValue().toInt(), + end = animatedOperation.endValue().toInt(), + current = animatedOperation.currentValue().toInt(); + bool collapsing = animatedOperation.direction() == QVariantAnimation::Backward; const QPixmap top = collapsing ? animatedOperation.before : animatedOperation.after; painter->drawPixmap(0, start, top, 0, end - current - 1, top.width(), top.height()); const QPixmap bottom = collapsing ? animatedOperation.after : animatedOperation.before; @@ -3049,26 +3059,14 @@ QPixmap QTreeViewPrivate::renderTreeToPixmapForAnimation(const QRect &rect) cons return pixmap; } -void QTreeViewPrivate::_q_currentChanged(const QModelIndex ¤t, const QModelIndex &previous) +void QTreeViewPrivate::_q_endAnimatedOperation() { Q_Q(QTreeView); - if (previous.isValid()) { - QRect previousRect = q->visualRect(previous); - if (allColumnsShowFocus) { - previousRect.setX(0); - previousRect.setWidth(viewport->width()); - } - viewport->update(previousRect); - } - if (current.isValid()) { - QRect currentRect = q->visualRect(current); - if (allColumnsShowFocus) { - currentRect.setX(0); - currentRect.setWidth(viewport->width()); - } - viewport->update(currentRect); - } + q->setState(QAbstractItemView::NoState); + q->updateGeometries(); + viewport->update(); } +#endif //QT_NO_ANIMATION void QTreeViewPrivate::_q_modelAboutToBeReset() { @@ -3077,16 +3075,16 @@ void QTreeViewPrivate::_q_modelAboutToBeReset() void QTreeViewPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { - Q_UNUSED(parent); if (start <= 0 && 0 <= end) viewItems.clear(); + QAbstractItemViewPrivate::_q_columnsAboutToBeRemoved(parent, start, end); } void QTreeViewPrivate::_q_columnsRemoved(const QModelIndex &parent, int start, int end) { - Q_UNUSED(parent); if (start <= 0 && 0 <= end) doDelayedItemsLayout(); + QAbstractItemViewPrivate::_q_columnsRemoved(parent, start, end); } void QTreeViewPrivate::layout(int i) @@ -3094,10 +3092,6 @@ void QTreeViewPrivate::layout(int i) Q_Q(QTreeView); QModelIndex current; QModelIndex parent = (i < 0) ? (QModelIndex)root : modelIndex(i); - // modelIndex() will return an index that don't have a parent if column 0 is hidden, - // so we must make sure that parent points to the actual parent that has children. - if (parent != root) - parent = model->index(parent.row(), 0, parent.parent()); if (i>=0 && !parent.isValid()) { //modelIndex() should never return something invalid for the real items. @@ -3132,13 +3126,9 @@ void QTreeViewPrivate::layout(int i) int last = 0; int children = 0; - int firstColumn = 0; - while (header->isSectionHidden(firstColumn) && firstColumn < header->count()) - ++firstColumn; - for (int j = first; j < first + count; ++j) { - current = model->index(j - first, firstColumn, parent); - if (isRowHidden(current.sibling(current.row(), 0))) { + current = model->index(j - first, 0, parent); + if (isRowHidden(current)) { ++hidden; last = j - hidden + children; } else { @@ -3219,19 +3209,18 @@ int QTreeViewPrivate::itemHeight(int item) const */ int QTreeViewPrivate::coordinateForItem(int item) const { - Q_Q(const QTreeView); if (verticalScrollMode == QAbstractItemView::ScrollPerPixel) { if (uniformRowHeights) - return (item * defaultItemHeight) - q->verticalScrollBar()->value(); + return (item * defaultItemHeight) - vbar->value(); // ### optimize (spans or caching) int y = 0; for (int i = 0; i < viewItems.count(); ++i) { if (i == item) - return y - q->verticalScrollBar()->value(); + return y - vbar->value(); y += itemHeight(i); } } else { // ScrollPerItem - int topViewItemIndex = q->verticalScrollBar()->value(); + int topViewItemIndex = vbar->value(); if (uniformRowHeights) return defaultItemHeight * (item - topViewItemIndex); if (item >= topViewItemIndex) { @@ -3271,7 +3260,6 @@ int QTreeViewPrivate::coordinateForItem(int item) const */ int QTreeViewPrivate::itemAtCoordinate(int coordinate) const { - Q_Q(const QTreeView); const int itemCount = viewItems.count(); if (itemCount == 0) return -1; @@ -3279,19 +3267,19 @@ int QTreeViewPrivate::itemAtCoordinate(int coordinate) const return -1; if (verticalScrollMode == QAbstractItemView::ScrollPerPixel) { if (uniformRowHeights) { - const int viewItemIndex = (coordinate + q->verticalScrollBar()->value()) / defaultItemHeight; + const int viewItemIndex = (coordinate + vbar->value()) / defaultItemHeight; return ((viewItemIndex >= itemCount || viewItemIndex < 0) ? -1 : viewItemIndex); } // ### optimize int viewItemCoordinate = 0; - const int contentsCoordinate = coordinate + q->verticalScrollBar()->value(); + const int contentsCoordinate = coordinate + vbar->value(); for (int viewItemIndex = 0; viewItemIndex < viewItems.count(); ++viewItemIndex) { viewItemCoordinate += itemHeight(viewItemIndex); if (viewItemCoordinate >= contentsCoordinate) return (viewItemIndex >= itemCount ? -1 : viewItemIndex); } } else { // ScrollPerItem - int topViewItemIndex = q->verticalScrollBar()->value(); + int topViewItemIndex = vbar->value(); if (uniformRowHeights) { if (coordinate < 0) coordinate -= defaultItemHeight - 1; @@ -3321,15 +3309,11 @@ int QTreeViewPrivate::itemAtCoordinate(int coordinate) const int QTreeViewPrivate::viewIndex(const QModelIndex &_index) const { - Q_Q(const QTreeView); if (!_index.isValid() || viewItems.isEmpty()) return -1; const int totalCount = viewItems.count(); - int firstColumn = 0; - while (q->isColumnHidden(firstColumn) && firstColumn < header->count()) - ++firstColumn; - const QModelIndex index = _index.sibling(_index.row(), firstColumn); + const QModelIndex index = _index.sibling(_index.row(), 0); // A quick check near the last item to see if we are just incrementing @@ -3387,8 +3371,7 @@ QModelIndex QTreeViewPrivate::modelIndex(int i, int column) const int QTreeViewPrivate::firstVisibleItem(int *offset) const { - Q_Q(const QTreeView); - const int value = q->verticalScrollBar()->value(); + const int value = vbar->value(); if (verticalScrollMode == QAbstractItemView::ScrollPerItem) { if (offset) *offset = 0; @@ -3465,9 +3448,9 @@ void QTreeViewPrivate::updateScrollBars() if (verticalScrollMode == QAbstractItemView::ScrollPerItem) { if (!viewItems.isEmpty()) itemsInViewport = qMax(1, itemsInViewport); - q->verticalScrollBar()->setRange(0, viewItems.count() - itemsInViewport); - q->verticalScrollBar()->setPageStep(itemsInViewport); - q->verticalScrollBar()->setSingleStep(1); + vbar->setRange(0, viewItems.count() - itemsInViewport); + vbar->setPageStep(itemsInViewport); + vbar->setSingleStep(1); } else { // scroll per pixel int contentsHeight = 0; if (uniformRowHeights) { @@ -3476,9 +3459,9 @@ void QTreeViewPrivate::updateScrollBars() for (int i = 0; i < viewItems.count(); ++i) contentsHeight += itemHeight(i); } - q->verticalScrollBar()->setRange(0, contentsHeight - viewportSize.height()); - q->verticalScrollBar()->setPageStep(viewportSize.height()); - q->verticalScrollBar()->setSingleStep(qMax(viewportSize.height() / (itemsInViewport + 1), 2)); + vbar->setRange(0, contentsHeight - viewportSize.height()); + vbar->setPageStep(viewportSize.height()); + vbar->setSingleStep(qMax(viewportSize.height() / (itemsInViewport + 1), 2)); } const int columnCount = header->count(); @@ -3494,23 +3477,23 @@ void QTreeViewPrivate::updateScrollBars() if (columnCount > 0) columnsInViewport = qMax(1, columnsInViewport); if (horizontalScrollMode == QAbstractItemView::ScrollPerItem) { - q->horizontalScrollBar()->setRange(0, columnCount - columnsInViewport); - q->horizontalScrollBar()->setPageStep(columnsInViewport); - q->horizontalScrollBar()->setSingleStep(1); + hbar->setRange(0, columnCount - columnsInViewport); + hbar->setPageStep(columnsInViewport); + hbar->setSingleStep(1); } else { // scroll per pixel const int horizontalLength = header->length(); const QSize maxSize = q->maximumViewportSize(); - if (maxSize.width() >= horizontalLength && q->verticalScrollBar()->maximum() <= 0) + if (maxSize.width() >= horizontalLength && vbar->maximum() <= 0) viewportSize = maxSize; - q->horizontalScrollBar()->setPageStep(viewportSize.width()); - q->horizontalScrollBar()->setRange(0, qMax(horizontalLength - viewportSize.width(), 0)); - q->horizontalScrollBar()->setSingleStep(qMax(viewportSize.width() / (columnsInViewport + 1), 2)); + hbar->setPageStep(viewportSize.width()); + hbar->setRange(0, qMax(horizontalLength - viewportSize.width(), 0)); + hbar->setSingleStep(qMax(viewportSize.width() / (columnsInViewport + 1), 2)); } } int QTreeViewPrivate::itemDecorationAt(const QPoint &pos) const { - const_cast<QTreeView *>(q_func())->executeDelayedItemsLayout(); + executePostedLayout(); int x = pos.x(); int column = header->logicalIndexAt(x); if (column != 0) @@ -3576,7 +3559,8 @@ QList<QPair<int, int> > QTreeViewPrivate::columnRanges(const QModelIndex &topInd QPair<int, int> current; current.first = -2; // -1 is not enough because -1+1 = 0 current.second = -2; - foreach (int logicalColumn, logicalIndexes) { + for(int i = 0; i < logicalIndexes.count(); ++i) { + const int logicalColumn = logicalIndexes.at(i); if (current.second + 1 != logicalColumn) { if (current.first != -2) { //let's save the current one @@ -3811,6 +3795,21 @@ void QTreeView::currentChanged(const QModelIndex ¤t, const QModelIndex &pr } #endif QAbstractItemView::currentChanged(current, previous); + + if (allColumnsShowFocus()) { + if (previous.isValid()) { + QRect previousRect = visualRect(previous); + previousRect.setX(0); + previousRect.setWidth(viewport()->width()); + viewport()->update(previousRect); + } + if (current.isValid()) { + QRect currentRect = visualRect(current); + currentRect.setX(0); + currentRect.setWidth(viewport()->width()); + viewport()->update(currentRect); + } + } } /*! diff --git a/src/gui/itemviews/qtreeview.h b/src/gui/itemviews/qtreeview.h index b8f42d0..c87b453 100644 --- a/src/gui/itemviews/qtreeview.h +++ b/src/gui/itemviews/qtreeview.h @@ -144,19 +144,20 @@ public: void sortByColumn(int column, Qt::SortOrder order); + void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); + void selectAll(); + Q_SIGNALS: void expanded(const QModelIndex &index); void collapsed(const QModelIndex &index); public Q_SLOTS: - void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); void hideColumn(int column); void showColumn(int column); void expand(const QModelIndex &index); void collapse(const QModelIndex &index); void resizeColumnToContents(int column); void sortByColumn(int column); - void selectAll(); void expandAll(); void collapseAll(); void expandToDepth(int depth); @@ -222,14 +223,11 @@ private: Q_DECLARE_PRIVATE(QTreeView) Q_DISABLE_COPY(QTreeView) +#ifndef QT_NO_ANIMATION Q_PRIVATE_SLOT(d_func(), void _q_endAnimatedOperation()) - Q_PRIVATE_SLOT(d_func(), void _q_animate()) - Q_PRIVATE_SLOT(d_func(), void _q_currentChanged(const QModelIndex&, const QModelIndex &)) - Q_PRIVATE_SLOT(d_func(), void _q_columnsAboutToBeRemoved(const QModelIndex &, int, int)) - Q_PRIVATE_SLOT(d_func(), void _q_columnsRemoved(const QModelIndex &, int, int)) +#endif //QT_NO_ANIMATION Q_PRIVATE_SLOT(d_func(), void _q_modelAboutToBeReset()) Q_PRIVATE_SLOT(d_func(), void _q_sortIndicatorChanged(int column, Qt::SortOrder order)) - Q_PRIVATE_SLOT(d_func(), void _q_modelDestroyed()) }; #endif // QT_NO_TREEVIEW diff --git a/src/gui/itemviews/qtreeview_p.h b/src/gui/itemviews/qtreeview_p.h index 3f9b8c8..a38dd25 100644 --- a/src/gui/itemviews/qtreeview_p.h +++ b/src/gui/itemviews/qtreeview_p.h @@ -54,6 +54,7 @@ // #include "private/qabstractitemview_p.h" +#include <QtCore/qvariantanimation.h> #ifndef QT_NO_TREEVIEW @@ -81,42 +82,41 @@ public: uniformRowHeights(false), rootDecoration(true), itemsExpandable(true), sortingEnabled(false), expandsOnDoubleClick(true), - allColumnsShowFocus(false), + allColumnsShowFocus(false), current(0), spanning(false), animationsEnabled(false), columnResizeTimerID(0), autoExpandDelay(-1), hoverBranch(-1), geometryRecursionBlock(false) {} ~QTreeViewPrivate() {} void initialize(); - struct AnimatedOperation + QItemViewPaintPairs draggablePaintPairs(const QModelIndexList &indexes, QRect *r) const; + +#ifndef QT_NO_ANIMATION + struct AnimatedOperation : public QVariantAnimation { - enum Type { Expand, Collapse }; int item; - int top; - int duration; - Type type; QPixmap before; QPixmap after; - }; - - void expand(int item, bool emitSignal); - void collapse(int item, bool emitSignal); - - void prepareAnimatedOperation(int item, AnimatedOperation::Type type); + QWidget *viewport; + AnimatedOperation() : item(0) { setEasingCurve(QEasingCurve::InOutQuad); } + int top() const { return startValue().toInt(); } + QRect rect() const { QRect rect = viewport->rect(); rect.moveTop(top()); return rect; } + void updateCurrentValue(const QVariant &) { viewport->update(rect()); } + void updateState(State, State state) { if (state == Stopped) before = after = QPixmap(); } + } animatedOperation; + void prepareAnimatedOperation(int item, QVariantAnimation::Direction d); void beginAnimatedOperation(); - void _q_endAnimatedOperation(); void drawAnimatedOperation(QPainter *painter) const; QPixmap renderTreeToPixmapForAnimation(const QRect &rect) const; + void _q_endAnimatedOperation(); +#endif //QT_NO_ANIMATION - inline QRect animationRect() const - { return QRect(0, animatedOperation.top, viewport->width(), - viewport->height() - animatedOperation.top); } + void expand(int item, bool emitSignal); + void collapse(int item, bool emitSignal); - void _q_currentChanged(const QModelIndex&, const QModelIndex&); void _q_columnsAboutToBeRemoved(const QModelIndex &, int, int); void _q_columnsRemoved(const QModelIndex &, int, int); void _q_modelAboutToBeReset(); - void _q_animate(); void _q_sortIndicatorChanged(int column, Qt::SortOrder order); void _q_modelDestroyed(); @@ -177,8 +177,6 @@ public: // used when expanding and collapsing items QSet<QPersistentModelIndex> expandedIndexes; - QStack<bool> expandParent; - AnimatedOperation animatedOperation; bool animationsEnabled; inline bool storeExpanded(const QPersistentModelIndex &idx) { diff --git a/src/gui/itemviews/qtreewidget.cpp b/src/gui/itemviews/qtreewidget.cpp index 52f3d5d..7d6439f 100644 --- a/src/gui/itemviews/qtreewidget.cpp +++ b/src/gui/itemviews/qtreewidget.cpp @@ -75,7 +75,7 @@ public: \brief The QTreeModel class manages the items stored in a tree view. \ingroup model-view - \mainclass + */ /*! @@ -577,7 +577,7 @@ void QTreeModel::sort(int column, Qt::SortOrder order) if (column < 0 || column >= columnCount()) return; - //layoutAboutToBeChanged and layoutChanged will be called by sortChildren + //layoutAboutToBeChanged and layoutChanged will be called by sortChildren rootItem->sortChildren(column, order, true); } @@ -853,7 +853,7 @@ void QTreeModel::sortItems(QList<QTreeWidgetItem*> *items, int column, Qt::SortO items->replace(r, item); for (int c = 0; c < colCount; ++c) { QModelIndex from = createIndex(oldRow, c, item); - if (static_cast<QAbstractItemModelPrivate *>(d_ptr)->persistent.indexes.contains(from)) { + if (static_cast<QAbstractItemModelPrivate *>(d_ptr.data())->persistent.indexes.contains(from)) { QModelIndex to = createIndex(r, c, item); fromList << from; toList << to; @@ -1768,6 +1768,7 @@ QVariant QTreeWidgetItem::data(int column, int role) const // special case for check state in tristate if (children.count() && (itemFlags & Qt::ItemIsTristate)) return childrenCheckState(column); + // fallthrough intended default: if (column >= 0 && column < values.size()) { const QVector<QWidgetItemData> &column_values = values.at(column); @@ -1787,7 +1788,9 @@ QVariant QTreeWidgetItem::data(int column, int role) const bool QTreeWidgetItem::operator<(const QTreeWidgetItem &other) const { int column = view ? view->sortColumn() : 0; - return text(column) < other.text(column); + const QVariant v1 = data(column, Qt::DisplayRole); + const QVariant v2 = other.data(column, Qt::DisplayRole); + return QAbstractItemModelPrivate::variantLessThan(v1, v2); } #ifndef QT_NO_DATASTREAM @@ -1827,6 +1830,7 @@ void QTreeWidgetItem::write(QDataStream &out) const { out << values << d->display; } +#endif // QT_NO_DATASTREAM /*! \since 4.1 @@ -1863,8 +1867,6 @@ QTreeWidgetItem &QTreeWidgetItem::operator=(const QTreeWidgetItem &other) return *this; } -#endif // QT_NO_DATASTREAM - /*! Appends the \a child item to the list of children. @@ -2071,11 +2073,13 @@ QList<QTreeWidgetItem*> QTreeWidgetItem::takeChildren() void QTreeWidgetItemPrivate::sortChildren(int column, Qt::SortOrder order, bool climb) { QTreeModel *model = (q->view ? qobject_cast<QTreeModel*>(q->view->model()) : 0); + if (!model) + return; model->sortItems(&q->children, column, order); if (climb) { QList<QTreeWidgetItem*>::iterator it = q->children.begin(); for (; it != q->children.end(); ++it) { - //here we call the private object's method to avoid emitting + //here we call the private object's method to avoid emitting //the layoutAboutToBeChanged and layoutChanged signals (*it)->d->sortChildren(column, order, climb); } @@ -2277,11 +2281,10 @@ void QTreeWidgetPrivate::_q_emitCurrentItemChanged(const QModelIndex ¤t, void QTreeWidgetPrivate::_q_sort() { - Q_Q(QTreeWidget); if (sortingEnabled) { - int column = q->header()->sortIndicatorSection(); - Qt::SortOrder order = q->header()->sortIndicatorOrder(); - model()->sort(column, order); + int column = header->sortIndicatorSection(); + Qt::SortOrder order = header->sortIndicatorOrder(); + treeModel()->sort(column, order); } } @@ -2290,7 +2293,7 @@ void QTreeWidgetPrivate::_q_selectionChanged(const QItemSelection &selected, con Q_Q(QTreeWidget); QModelIndexList indices = selected.indexes(); int i; - QTreeModel *m = model(); + QTreeModel *m = treeModel(); for (i = 0; i < indices.count(); ++i) { QTreeWidgetItem *item = m->item(indices.at(i)); item->d->selected = true; @@ -2308,13 +2311,12 @@ void QTreeWidgetPrivate::_q_selectionChanged(const QItemSelection &selected, con void QTreeWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { - Q_Q(QTreeWidget); if (sortingEnabled && topLeft.isValid() && bottomRight.isValid() - && !model()->sortPendingTimer.isActive()) { - int column = q->header()->sortIndicatorSection(); + && !treeModel()->sortPendingTimer.isActive()) { + int column = header->sortIndicatorSection(); if (column >= topLeft.column() && column <= bottomRight.column()) { - Qt::SortOrder order = q->header()->sortIndicatorOrder(); - model()->ensureSorted(column, order, topLeft.row(), + Qt::SortOrder order = header->sortIndicatorOrder(); + treeModel()->ensureSorted(column, order, topLeft.row(), bottomRight.row(), topLeft.parent()); } } @@ -2327,7 +2329,7 @@ void QTreeWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, tree model. \ingroup model-view - \mainclass + The QTreeWidget class is a convenience class that provides a standard tree widget with a classic item-based interface similar to that used by @@ -2436,7 +2438,7 @@ void QTreeWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, \note This signal will not be emitted if an item changes its state when expandAll() is invoked. - \sa isItemExpanded(), itemCollapsed(), expandItem() + \sa QTreeWidgetItem::isExpanded(), itemCollapsed(), expandItem() */ /*! @@ -2448,7 +2450,7 @@ void QTreeWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, \note This signal will not be emitted if an item changes its state when collapseAll() is invoked. - \sa isItemExpanded(), itemExpanded(), collapseItem() + \sa QTreeWidgetItem::isExpanded(), itemExpanded(), collapseItem() */ /*! @@ -2542,7 +2544,7 @@ QTreeWidget::~QTreeWidget() int QTreeWidget::columnCount() const { Q_D(const QTreeWidget); - return d->model()->columnCount(); + return d->model->columnCount(); } /* @@ -2554,7 +2556,7 @@ void QTreeWidget::setColumnCount(int columns) Q_D(QTreeWidget); if (columns < 0) return; - d->model()->setColumnCount(columns); + d->treeModel()->setColumnCount(columns); } /*! @@ -2571,7 +2573,7 @@ void QTreeWidget::setColumnCount(int columns) QTreeWidgetItem *QTreeWidget::invisibleRootItem() const { Q_D(const QTreeWidget); - return d->model()->rootItem; + return d->treeModel()->rootItem; } /*! @@ -2584,7 +2586,7 @@ QTreeWidgetItem *QTreeWidget::invisibleRootItem() const QTreeWidgetItem *QTreeWidget::topLevelItem(int index) const { Q_D(const QTreeWidget); - return d->model()->rootItem->child(index); + return d->treeModel()->rootItem->child(index); } /*! @@ -2599,7 +2601,7 @@ QTreeWidgetItem *QTreeWidget::topLevelItem(int index) const int QTreeWidget::topLevelItemCount() const { Q_D(const QTreeWidget); - return d->model()->rootItem->childCount(); + return d->treeModel()->rootItem->childCount(); } /*! @@ -2613,7 +2615,7 @@ int QTreeWidget::topLevelItemCount() const void QTreeWidget::insertTopLevelItem(int index, QTreeWidgetItem *item) { Q_D(QTreeWidget); - d->model()->rootItem->insertChild(index, item); + d->treeModel()->rootItem->insertChild(index, item); } /*! @@ -2638,7 +2640,7 @@ void QTreeWidget::addTopLevelItem(QTreeWidgetItem *item) QTreeWidgetItem *QTreeWidget::takeTopLevelItem(int index) { Q_D(QTreeWidget); - return d->model()->rootItem->takeChild(index); + return d->treeModel()->rootItem->takeChild(index); } /*! @@ -2647,8 +2649,8 @@ QTreeWidgetItem *QTreeWidget::takeTopLevelItem(int index) int QTreeWidget::indexOfTopLevelItem(QTreeWidgetItem *item) { Q_D(QTreeWidget); - d->model()->executePendingSort(); - return d->model()->rootItem->children.indexOf(item); + d->treeModel()->executePendingSort(); + return d->treeModel()->rootItem->children.indexOf(item); } /*! @@ -2660,8 +2662,8 @@ int QTreeWidget::indexOfTopLevelItem(QTreeWidgetItem *item) int QTreeWidget::indexOfTopLevelItem(QTreeWidgetItem *item) const { Q_D(const QTreeWidget); - d->model()->executePendingSort(); - return d->model()->rootItem->children.indexOf(item); + d->treeModel()->executePendingSort(); + return d->treeModel()->rootItem->children.indexOf(item); } /*! @@ -2676,7 +2678,7 @@ int QTreeWidget::indexOfTopLevelItem(QTreeWidgetItem *item) const void QTreeWidget::insertTopLevelItems(int index, const QList<QTreeWidgetItem*> &items) { Q_D(QTreeWidget); - d->model()->rootItem->insertChildren(index, items); + d->treeModel()->rootItem->insertChildren(index, items); } /*! @@ -2698,7 +2700,7 @@ void QTreeWidget::addTopLevelItems(const QList<QTreeWidgetItem*> &items) QTreeWidgetItem *QTreeWidget::headerItem() const { Q_D(const QTreeWidget); - return d->model()->headerItem; + return d->treeModel()->headerItem; } /*! @@ -2719,16 +2721,16 @@ void QTreeWidget::setHeaderItem(QTreeWidgetItem *item) int oldCount = columnCount(); if (oldCount < item->columnCount()) - d->model()->beginInsertColumns(QModelIndex(), oldCount, item->columnCount()); + d->treeModel()->beginInsertColumns(QModelIndex(), oldCount, item->columnCount()); else - d->model()->beginRemoveColumns(QModelIndex(), item->columnCount(), oldCount); - delete d->model()->headerItem; - d->model()->headerItem = item; + d->treeModel()->beginRemoveColumns(QModelIndex(), item->columnCount(), oldCount); + delete d->treeModel()->headerItem; + d->treeModel()->headerItem = item; if (oldCount < item->columnCount()) - d->model()->endInsertColumns(); + d->treeModel()->endInsertColumns(); else - d->model()->endRemoveColumns(); - d->model()->headerDataChanged(Qt::Horizontal, 0, oldCount); + d->treeModel()->endRemoveColumns(); + d->treeModel()->headerDataChanged(Qt::Horizontal, 0, oldCount); } @@ -2745,8 +2747,7 @@ void QTreeWidget::setHeaderLabels(const QStringList &labels) Q_D(QTreeWidget); if (columnCount() < labels.count()) setColumnCount(labels.count()); - QTreeModel *model = d->model(); - QTreeWidgetItem *item = model->headerItem; + QTreeWidgetItem *item = d->treeModel()->headerItem; for (int i = 0; i < labels.count(); ++i) item->setText(i, labels.at(i)); } @@ -2783,7 +2784,8 @@ int QTreeWidget::currentColumn() const /*! Sets the current \a item in the tree widget. - Depending on the current selection mode, the item may also be selected. + Unless the selection mode is \l{QAbstractItemView::}{NoSelection}, + the item is also be selected. \sa currentItem(), currentItemChanged() */ @@ -2874,7 +2876,7 @@ void QTreeWidget::sortItems(int column, Qt::SortOrder order) { Q_D(QTreeWidget); header()->setSortIndicator(column, order); - d->model()->sort(column, order); + d->model->sort(column, order); } /*! @@ -3041,7 +3043,7 @@ QList<QTreeWidgetItem*> QTreeWidget::selectedItems() const QList<QTreeWidgetItem*> QTreeWidget::findItems(const QString &text, Qt::MatchFlags flags, int column) const { Q_D(const QTreeWidget); - QModelIndexList indexes = d->model()->match(model()->index(0, column, QModelIndex()), + QModelIndexList indexes = d->model->match(model()->index(0, column, QModelIndex()), Qt::DisplayRole, text, -1, flags); QList<QTreeWidgetItem*> items; for (int i = 0; i < indexes.size(); ++i) @@ -3059,11 +3061,11 @@ QList<QTreeWidgetItem*> QTreeWidget::findItems(const QString &text, Qt::MatchFla bool QTreeWidget::isItemHidden(const QTreeWidgetItem *item) const { Q_D(const QTreeWidget); - if (item == d->model()->headerItem) + if (item == d->treeModel()->headerItem) return header()->isHidden(); if (d->hiddenIndexes.isEmpty()) return false; - QTreeModel::SkipSorting skipSorting(d->model()); + QTreeModel::SkipSorting skipSorting(d->treeModel()); return d->isRowHidden(d->index(item)); } @@ -3079,7 +3081,7 @@ bool QTreeWidget::isItemHidden(const QTreeWidgetItem *item) const void QTreeWidget::setItemHidden(const QTreeWidgetItem *item, bool hide) { Q_D(QTreeWidget); - if (item == d->model()->headerItem) { + if (item == d->treeModel()->headerItem) { header()->setHidden(hide); } else { const QModelIndex index = d->index(item); @@ -3099,7 +3101,7 @@ void QTreeWidget::setItemHidden(const QTreeWidgetItem *item, bool hide) bool QTreeWidget::isItemExpanded(const QTreeWidgetItem *item) const { Q_D(const QTreeWidget); - QTreeModel::SkipSorting skipSorting(d->model()); + QTreeModel::SkipSorting skipSorting(d->treeModel()); return isExpanded(d->index(item)); } @@ -3109,14 +3111,14 @@ bool QTreeWidget::isItemExpanded(const QTreeWidgetItem *item) const \sa expandItem(), collapseItem(), itemExpanded() - \obsolete + \obsolete - This function is deprecated. Use \l{QTreeWidgetItem::setExpanded()} instead. + This function is deprecated. Use \l{QTreeWidgetItem::setExpanded()} instead. */ void QTreeWidget::setItemExpanded(const QTreeWidgetItem *item, bool expand) { Q_D(QTreeWidget); - QTreeModel::SkipSorting skipSorting(d->model()); + QTreeModel::SkipSorting skipSorting(d->treeModel()); setExpanded(d->index(item), expand); } @@ -3131,7 +3133,7 @@ void QTreeWidget::setItemExpanded(const QTreeWidgetItem *item, bool expand) bool QTreeWidget::isFirstItemColumnSpanned(const QTreeWidgetItem *item) const { Q_D(const QTreeWidget); - if (item == d->model()->headerItem) + if (item == d->treeModel()->headerItem) return false; // We can't set the header items to spanning const QModelIndex index = d->index(item); return isFirstColumnSpanned(index.row(), index.parent()); @@ -3148,7 +3150,7 @@ bool QTreeWidget::isFirstItemColumnSpanned(const QTreeWidgetItem *item) const void QTreeWidget::setFirstItemColumnSpanned(const QTreeWidgetItem *item, bool span) { Q_D(QTreeWidget); - if (item == d->model()->headerItem) + if (item == d->treeModel()->headerItem) return; // We can't set header items to spanning const QModelIndex index = d->index(item); setFirstColumnSpanned(index.row(), index.parent(), span); @@ -3162,7 +3164,7 @@ void QTreeWidget::setFirstItemColumnSpanned(const QTreeWidgetItem *item, bool sp QTreeWidgetItem *QTreeWidget::itemAbove(const QTreeWidgetItem *item) const { Q_D(const QTreeWidget); - if (item == d->model()->headerItem) + if (item == d->treeModel()->headerItem) return 0; const QModelIndex index = d->index(item); const QModelIndex above = indexAbove(index); @@ -3177,7 +3179,7 @@ QTreeWidgetItem *QTreeWidget::itemAbove(const QTreeWidgetItem *item) const QTreeWidgetItem *QTreeWidget::itemBelow(const QTreeWidgetItem *item) const { Q_D(const QTreeWidget); - if (item == d->model()->headerItem) + if (item == d->treeModel()->headerItem) return 0; const QModelIndex index = d->index(item); const QModelIndex below = indexBelow(index); @@ -3217,7 +3219,7 @@ void QTreeWidget::scrollToItem(const QTreeWidgetItem *item, QAbstractItemView::S void QTreeWidget::expandItem(const QTreeWidgetItem *item) { Q_D(QTreeWidget); - QTreeModel::SkipSorting skipSorting(d->model()); + QTreeModel::SkipSorting skipSorting(d->treeModel()); expand(d->index(item)); } @@ -3230,7 +3232,7 @@ void QTreeWidget::expandItem(const QTreeWidgetItem *item) void QTreeWidget::collapseItem(const QTreeWidgetItem *item) { Q_D(QTreeWidget); - QTreeModel::SkipSorting skipSorting(d->model()); + QTreeModel::SkipSorting skipSorting(d->treeModel()); collapse(d->index(item)); } @@ -3247,7 +3249,7 @@ void QTreeWidget::clear() { Q_D(QTreeWidget); selectionModel()->clear(); - d->model()->clear(); + d->treeModel()->clear(); } /*! @@ -3272,7 +3274,7 @@ QStringList QTreeWidget::mimeTypes() const QMimeData *QTreeWidget::mimeData(const QList<QTreeWidgetItem*> items) const { Q_D(const QTreeWidget); - if (d->model()->cachedIndexes.isEmpty()) { + if (d->treeModel()->cachedIndexes.isEmpty()) { QList<QModelIndex> indexes; for (int i = 0; i < items.count(); ++i) { QTreeWidgetItem *item = items.at(i); @@ -3280,9 +3282,9 @@ QMimeData *QTreeWidget::mimeData(const QList<QTreeWidgetItem*> items) const indexes << indexFromItem(item, c); } } - return model()->QAbstractItemModel::mimeData(indexes); + return d->model->QAbstractItemModel::mimeData(indexes); } - return d->model()->internalMimeData(); + return d->treeModel()->internalMimeData(); } /*! @@ -3426,7 +3428,7 @@ bool QTreeWidget::event(QEvent *e) { Q_D(QTreeWidget); if (e->type() == QEvent::Polish) - d->model()->executePendingSort(); + d->treeModel()->executePendingSort(); return QTreeView::event(e); } diff --git a/src/gui/itemviews/qtreewidget_p.h b/src/gui/itemviews/qtreewidget_p.h index 5543ead..872645b 100644 --- a/src/gui/itemviews/qtreewidget_p.h +++ b/src/gui/itemviews/qtreewidget_p.h @@ -219,12 +219,11 @@ class QTreeWidgetPrivate : public QTreeViewPrivate Q_DECLARE_PUBLIC(QTreeWidget) public: QTreeWidgetPrivate() : QTreeViewPrivate(), explicitSortColumn(-1) {} - inline QTreeModel *model() const - { return qobject_cast<QTreeModel*>(q_func()->model()); } + inline QTreeModel *treeModel() const { return qobject_cast<QTreeModel*>(model); } inline QModelIndex index(const QTreeWidgetItem *item, int column = 0) const - { return model()->index(item, column); } + { return treeModel()->index(item, column); } inline QTreeWidgetItem *item(const QModelIndex &index) const - { return model()->item(index); } + { return treeModel()->item(index); } void _q_emitItemPressed(const QModelIndex &index); void _q_emitItemClicked(const QModelIndex &index); void _q_emitItemDoubleClicked(const QModelIndex &index); diff --git a/src/gui/itemviews/qtreewidgetitemiterator.cpp b/src/gui/itemviews/qtreewidgetitemiterator.cpp index 3f99b5e..1a4df1f 100644 --- a/src/gui/itemviews/qtreewidgetitemiterator.cpp +++ b/src/gui/itemviews/qtreewidgetitemiterator.cpp @@ -97,7 +97,7 @@ QTreeWidgetItemIterator::QTreeWidgetItemIterator(QTreeWidget *widget, IteratorFl Q_ASSERT(widget); QTreeModel *model = qobject_cast<QTreeModel*>(widget->model()); Q_ASSERT(model); - d_ptr = new QTreeWidgetItemIteratorPrivate(this, model); + d_ptr.reset(new QTreeWidgetItemIteratorPrivate(this, model)); model->iterators.append(this); if (!model->rootItem->children.isEmpty()) current = model->rootItem->children.first(); if (current && !matchesFlags(current)) @@ -150,7 +150,6 @@ QTreeWidgetItemIterator::QTreeWidgetItemIterator(QTreeWidgetItem *item, Iterator QTreeWidgetItemIterator::~QTreeWidgetItemIterator() { d_func()->m_model->iterators.removeAll(this); - delete d_ptr; } /*! diff --git a/src/gui/itemviews/qtreewidgetitemiterator.h b/src/gui/itemviews/qtreewidgetitemiterator.h index aaf01fb..45a5505 100644 --- a/src/gui/itemviews/qtreewidgetitemiterator.h +++ b/src/gui/itemviews/qtreewidgetitemiterator.h @@ -43,6 +43,7 @@ #define QTREEWIDGETITEMITERATOR_H #include <QtCore/qglobal.h> +#include <QtCore/qscopedpointer.h> QT_BEGIN_HEADER @@ -105,7 +106,7 @@ public: private: bool matchesFlags(const QTreeWidgetItem *item) const; - QTreeWidgetItemIteratorPrivate *d_ptr; + QScopedPointer<QTreeWidgetItemIteratorPrivate> d_ptr; QTreeWidgetItem *current; IteratorFlags flags; Q_DECLARE_PRIVATE(QTreeWidgetItemIterator) diff --git a/src/gui/itemviews/qtreewidgetitemiterator_p.h b/src/gui/itemviews/qtreewidgetitemiterator_p.h index 23b6121..532b963 100644 --- a/src/gui/itemviews/qtreewidgetitemiterator_p.h +++ b/src/gui/itemviews/qtreewidgetitemiterator_p.h @@ -73,7 +73,8 @@ public: } QTreeWidgetItemIteratorPrivate(const QTreeWidgetItemIteratorPrivate& other) - : m_currentIndex(other.m_currentIndex), m_model(other.m_model), m_parentIndex(other.m_parentIndex) + : m_currentIndex(other.m_currentIndex), m_model(other.m_model), + m_parentIndex(other.m_parentIndex), q_ptr(other.q_ptr) { } |