diff options
Diffstat (limited to 'src/widgets/itemviews')
-rw-r--r-- | src/widgets/itemviews/qabstractitemdelegate.cpp | 6 | ||||
-rw-r--r-- | src/widgets/itemviews/qabstractitemview.cpp | 90 | ||||
-rw-r--r-- | src/widgets/itemviews/qabstractitemview_p.h | 1 | ||||
-rw-r--r-- | src/widgets/itemviews/qheaderview.cpp | 30 | ||||
-rw-r--r-- | src/widgets/itemviews/qheaderview_p.h | 2 | ||||
-rw-r--r-- | src/widgets/itemviews/qlistview.cpp | 13 | ||||
-rw-r--r-- | src/widgets/itemviews/qtableview.cpp | 6 | ||||
-rw-r--r-- | src/widgets/itemviews/qtreeview.cpp | 19 | ||||
-rw-r--r-- | src/widgets/itemviews/qtreewidget.cpp | 25 |
9 files changed, 142 insertions, 50 deletions
diff --git a/src/widgets/itemviews/qabstractitemdelegate.cpp b/src/widgets/itemviews/qabstractitemdelegate.cpp index c5b22b5667..e120817edc 100644 --- a/src/widgets/itemviews/qabstractitemdelegate.cpp +++ b/src/widgets/itemviews/qabstractitemdelegate.cpp @@ -389,10 +389,12 @@ bool QAbstractItemDelegate::helpEvent(QHelpEvent *event, { if (!event || !view) return false; - Q_D(QAbstractItemDelegate); + Q_UNUSED(index); + Q_UNUSED(option); switch (event->type()) { #ifndef QT_NO_TOOLTIP case QEvent::ToolTip: { + Q_D(QAbstractItemDelegate); QHelpEvent *he = static_cast<QHelpEvent*>(event); const int precision = inherits("QItemDelegate") ? 10 : 6; // keep in sync with DBL_DIG in qitemdelegate.cpp const QString tooltip = index.isValid() ? @@ -413,6 +415,7 @@ bool QAbstractItemDelegate::helpEvent(QHelpEvent *event, event->setAccepted(index.data(Qt::WhatsThisRole).isValid()); break; case QEvent::WhatsThis: { + Q_D(QAbstractItemDelegate); QHelpEvent *he = static_cast<QHelpEvent*>(event); const int precision = inherits("QItemDelegate") ? 10 : 6; // keep in sync with DBL_DIG in qitemdelegate.cpp const QString whatsthis = index.isValid() ? @@ -423,6 +426,7 @@ bool QAbstractItemDelegate::helpEvent(QHelpEvent *event, break; } #endif + case QEvent::None: default: break; } diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp index b8cc5621fb..93dc5ee80c 100644 --- a/src/widgets/itemviews/qabstractitemview.cpp +++ b/src/widgets/itemviews/qabstractitemview.cpp @@ -87,6 +87,7 @@ QAbstractItemViewPrivate::QAbstractItemViewPrivate() pressedModifiers(Qt::NoModifier), pressedPosition(QPoint(-1, -1)), pressedAlreadySelected(false), + releaseFromDoubleClick(false), viewportEnteredNeeded(false), state(QAbstractItemView::NoState), stateBeforeAnimation(QAbstractItemView::NoState), @@ -1168,12 +1169,21 @@ QModelIndex QAbstractItemView::rootIndex() const void QAbstractItemView::selectAll() { Q_D(QAbstractItemView); - SelectionMode mode = d->selectionMode; - if (mode == MultiSelection || mode == ExtendedSelection) + const SelectionMode mode = d->selectionMode; + switch (mode) { + case MultiSelection: + case ExtendedSelection: d->selectAll(QItemSelectionModel::ClearAndSelect - |d->selectionBehaviorFlags()); - else if (mode != SingleSelection) - d->selectAll(selectionCommand(d->model->index(0, 0, d->root))); + | d->selectionBehaviorFlags()); + break; + case NoSelection: + case ContiguousSelection: + if (d->model->hasChildren(d->root)) + d->selectAll(selectionCommand(d->model->index(0, 0, d->root))); + break; + case SingleSelection: + break; + } } /*! @@ -1754,6 +1764,7 @@ bool QAbstractItemView::viewportEvent(QEvent *event) void QAbstractItemView::mousePressEvent(QMouseEvent *event) { Q_D(QAbstractItemView); + d->releaseFromDoubleClick = false; d->delayedAutoScroll.stop(); //any interaction with the view cancel the auto scrolling QPoint pos = event->pos(); QPersistentModelIndex index = indexAt(pos); @@ -1899,6 +1910,8 @@ void QAbstractItemView::mouseMoveEvent(QMouseEvent *event) void QAbstractItemView::mouseReleaseEvent(QMouseEvent *event) { Q_D(QAbstractItemView); + const bool releaseFromDoubleClick = d->releaseFromDoubleClick; + d->releaseFromDoubleClick = false; QPoint pos = event->pos(); QPersistentModelIndex index = indexAt(pos); @@ -1911,7 +1924,7 @@ void QAbstractItemView::mouseReleaseEvent(QMouseEvent *event) return; } - bool click = (index == d->pressedIndex && index.isValid()); + bool click = (index == d->pressedIndex && index.isValid() && !releaseFromDoubleClick); bool selectedClicked = click && (event->button() == Qt::LeftButton) && d->pressedAlreadySelected; EditTrigger trigger = (selectedClicked ? SelectedClicked : NoEditTriggers); const bool edited = click ? edit(index, trigger, event) : false; @@ -1964,7 +1977,7 @@ void QAbstractItemView::mouseDoubleClickEvent(QMouseEvent *event) if ((event->button() == Qt::LeftButton) && !edit(persistent, DoubleClicked, event) && !style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, this)) emit activated(persistent); - d->pressedIndex = QModelIndex(); + d->releaseFromDoubleClick = true; } #if QT_CONFIG(draganddrop) @@ -2334,11 +2347,12 @@ void QAbstractItemView::keyPressEvent(QKeyEvent *event) #if !defined(QT_NO_CLIPBOARD) && !defined(QT_NO_SHORTCUT) if (event == QKeySequence::Copy) { - QVariant variant; - if (d->model) - variant = d->model->data(currentIndex(), Qt::DisplayRole); - if (variant.canConvert<QString>()) - QGuiApplication::clipboard()->setText(variant.toString()); + const QModelIndex index = currentIndex(); + if (index.isValid() && d->model) { + const QVariant variant = d->model->data(index, Qt::DisplayRole); + if (variant.canConvert<QString>()) + QGuiApplication::clipboard()->setText(variant.toString()); + } event->accept(); } #endif @@ -3404,15 +3418,39 @@ void QAbstractItemView::rowsAboutToBeRemoved(const QModelIndex &parent, int star } else { int row = end + 1; QModelIndex next; - do { // find the next visible and enabled item + const int rowCount = d->model->rowCount(parent); + bool found = false; + // find the next visible and enabled item + while (row < rowCount && !found) { next = d->model->index(row++, current.column(), current.parent()); - } while (next.isValid() && (isIndexHidden(next) || !d->isIndexEnabled(next))); - if (row > d->model->rowCount(parent)) { +#ifdef QT_DEBUG + if (!next.isValid()) { + qWarning("Model unexpectedly returned an invalid index"); + break; + } +#endif + if (!isIndexHidden(next) && d->isIndexEnabled(next)) { + found = true; + break; + } + } + + if (!found) { row = start - 1; - do { // find the previous visible and enabled item + // find the previous visible and enabled item + while (row >= 0) { next = d->model->index(row--, current.column(), current.parent()); - } while (next.isValid() && (isIndexHidden(next) || !d->isIndexEnabled(next))); +#ifdef QT_DEBUG + if (!next.isValid()) { + qWarning("Model unexpectedly returned an invalid index"); + break; + } +#endif + if (!isIndexHidden(next) && d->isIndexEnabled(next)) + break; + } } + setCurrentIndex(next); } } @@ -3490,9 +3528,19 @@ void QAbstractItemViewPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &par } else { int column = end; QModelIndex next; - do { // find the next visible and enabled item + const int columnCount = model->columnCount(current.parent()); + // find the next visible and enabled item + while (column < columnCount) { next = model->index(current.row(), column++, current.parent()); - } while (next.isValid() && (q->isIndexHidden(next) || !isIndexEnabled(next))); +#ifdef QT_DEBUG + if (!next.isValid()) { + qWarning("Model unexpectedly returned an invalid index"); + break; + } +#endif + if (!q->isIndexHidden(next) && isIndexEnabled(next)) + break; + } q->setCurrentIndex(next); } } @@ -4301,7 +4349,7 @@ void QAbstractItemViewPrivate::updateEditorData(const QModelIndex &tl, const QMo In DND if something has been moved then this is called. Typically this means you should "remove" the selected item or row, - but the behavior is view dependant (table just clears the selected indexes for example). + but the behavior is view-dependent (table just clears the selected indexes for example). Either remove the selected rows or clear them */ @@ -4494,6 +4542,8 @@ void QAbstractItemViewPrivate::selectAll(QItemSelectionModel::SelectionFlags com { if (!selectionModel) return; + if (!model->hasChildren(root)) + return; QItemSelection selection; QModelIndex tl = model->index(0, 0, root); diff --git a/src/widgets/itemviews/qabstractitemview_p.h b/src/widgets/itemviews/qabstractitemview_p.h index 33924799fe..7532cf5789 100644 --- a/src/widgets/itemviews/qabstractitemview_p.h +++ b/src/widgets/itemviews/qabstractitemview_p.h @@ -385,6 +385,7 @@ public: Qt::KeyboardModifiers pressedModifiers; QPoint pressedPosition; bool pressedAlreadySelected; + bool releaseFromDoubleClick; //forces the next mouseMoveEvent to send the viewportEntered signal //if the mouse is over the viewport and not over an item diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index 84e2fd72a9..3b396c689b 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -2528,7 +2528,7 @@ void QHeaderView::mousePressEvent(QMouseEvent *e) int handle = d->sectionHandleAt(pos); d->originalSize = -1; // clear the stored original size if (handle == -1) { - d->pressed = logicalIndexAt(pos); + d->firstPressed = d->pressed = logicalIndexAt(pos); if (d->clickableSections) emit sectionPressed(d->pressed); @@ -2576,7 +2576,7 @@ void QHeaderView::mouseMoveEvent(QMouseEvent *e) // just before the mouseReleaseEvent and resets the state. This prevents // column dragging from working. So this code is disabled under Cocoa. d->state = QHeaderViewPrivate::NoState; - d->pressed = -1; + d->firstPressed = d->pressed = -1; } switch (d->state) { case QHeaderViewPrivate::ResizeSection: { @@ -2705,9 +2705,27 @@ void QHeaderView::mouseReleaseEvent(QMouseEvent *e) case QHeaderViewPrivate::NoState: if (d->clickableSections) { int section = logicalIndexAt(pos); - if (section != -1 && section == d->pressed) { - d->flipSortIndicator(section); - emit sectionClicked(section); + if (section != -1 && section == d->firstPressed) { + QRect firstPressedSectionRect; + switch (d->orientation) { + case Qt::Horizontal: + firstPressedSectionRect.setRect(sectionViewportPosition(d->firstPressed), + 0, + sectionSize(d->firstPressed), + d->viewport->height()); + break; + case Qt::Vertical: + firstPressedSectionRect.setRect(0, + sectionViewportPosition(d->firstPressed), + d->viewport->width(), + sectionSize(d->firstPressed)); + break; + }; + + if (firstPressedSectionRect.contains(e->pos())) { + d->flipSortIndicator(section); + emit sectionClicked(section); + } } if (d->pressed != -1) updateSection(d->pressed); @@ -2721,7 +2739,7 @@ void QHeaderView::mouseReleaseEvent(QMouseEvent *e) break; } d->state = QHeaderViewPrivate::NoState; - d->pressed = -1; + d->firstPressed = d->pressed = -1; } /*! diff --git a/src/widgets/itemviews/qheaderview_p.h b/src/widgets/itemviews/qheaderview_p.h index 766adef36d..0f6641c3df 100644 --- a/src/widgets/itemviews/qheaderview_p.h +++ b/src/widgets/itemviews/qheaderview_p.h @@ -82,6 +82,7 @@ public: originalSize(-1), section(-1), target(-1), + firstPressed(-1), pressed(-1), hover(-1), length(0), @@ -274,6 +275,7 @@ public: int originalSize; int section; // used for resizing and moving sections int target; + int firstPressed; int pressed; int hover; diff --git a/src/widgets/itemviews/qlistview.cpp b/src/widgets/itemviews/qlistview.cpp index 2d33759d8c..fab44923de 100644 --- a/src/widgets/itemviews/qlistview.cpp +++ b/src/widgets/itemviews/qlistview.cpp @@ -572,6 +572,8 @@ void QListView::scrollTo(const QModelIndex &index, ScrollHint hint) return; const QRect rect = visualRect(index); + if (!rect.isValid()) + return; if (hint == EnsureVisible && d->viewport->rect().contains(rect)) { d->viewport->update(rect); return; @@ -940,7 +942,8 @@ void QListView::dropEvent(QDropEvent *event) int r = row == -1 ? model()->rowCount() : (dropRow.row() >= 0 ? dropRow.row() : row); for (int i = 0; i < persIndexes.count(); ++i) { const QPersistentModelIndex &pIndex = persIndexes.at(i); - if (r != pIndex.row()) { + // only generate a move when not same row or behind itself + if (r != pIndex.row() && r != pIndex.row() + 1) { // try to move (preserves selection) d->dropEventMoved |= model()->moveRow(QModelIndex(), pIndex.row(), QModelIndex(), r); if (!d->dropEventMoved) // can't move - abort and let QAbstractItemView handle this @@ -1539,12 +1542,14 @@ void QListView::doItemsLayout() setState(ExpandingState); if (d->model->columnCount(d->root) > 0) { // no columns means no contents d->resetBatchStartRow(); - if (layoutMode() == SinglePass) + if (layoutMode() == SinglePass) { d->doItemsLayout(d->model->rowCount(d->root)); // layout everything - else if (!d->batchLayoutTimer.isActive()) { + } else if (!d->batchLayoutTimer.isActive()) { if (!d->doItemsLayout(d->batchSize)) // layout is done d->batchLayoutTimer.start(0, this); // do a new batch as fast as possible } + } else { // clear the QBspTree generated by the last layout + d->clear(); } QAbstractItemView::doItemsLayout(); setState(oldState); // restoring the oldState @@ -2930,6 +2935,8 @@ bool QIconModeViewBase::filterDropEvent(QDropEvent *e) dd->stopAutoScroll(); draggedItems.clear(); dd->emitIndexesMoved(indexes); + // do not delete item on internal move, see filterStartDrag() + dd->dropEventMoved = true; e->accept(); // we have handled the event // if the size has not grown, we need to check if it has shrinked if (contentsSize != contents) { diff --git a/src/widgets/itemviews/qtableview.cpp b/src/widgets/itemviews/qtableview.cpp index 1b72536dcf..d120c41dc9 100644 --- a/src/widgets/itemviews/qtableview.cpp +++ b/src/widgets/itemviews/qtableview.cpp @@ -1101,6 +1101,8 @@ int QTableViewPrivate::heightHintForIndex(const QModelIndex &index, int hint, QS table can be found by using rowHeight(); similarly, the width of columns can be found using columnWidth(). Since both of these are plain widgets, you can hide either of them using their hide() functions. + Each header is configured with its \l{QHeaderView::}{highlightSections} + and \l{QHeaderView::}{sectionsClickable} properties set to \c true. Rows and columns can be hidden and shown with hideRow(), hideColumn(), showRow(), and showColumn(). They can be selected with selectRow() @@ -2944,6 +2946,8 @@ void QTableView::timerEvent(QTimerEvent *event) updateGeometries(); killTimer(d->columnResizeTimerID); d->columnResizeTimerID = 0; + } else { + updateEditorGeometries(); } QRect rect; @@ -2972,6 +2976,8 @@ void QTableView::timerEvent(QTimerEvent *event) updateGeometries(); killTimer(d->rowResizeTimerID); d->rowResizeTimerID = 0; + } else { + updateEditorGeometries(); } int viewportHeight = d->viewport->height(); diff --git a/src/widgets/itemviews/qtreeview.cpp b/src/widgets/itemviews/qtreeview.cpp index b778ef9a47..6ab6576cbe 100644 --- a/src/widgets/itemviews/qtreeview.cpp +++ b/src/widgets/itemviews/qtreeview.cpp @@ -1448,7 +1448,8 @@ void QTreeViewPrivate::adjustViewOptionsForIndex(QStyleOptionViewItem *option, c void QTreeView::drawTree(QPainter *painter, const QRegion ®ion) const { Q_D(const QTreeView); - const QVector<QTreeViewItem> viewItems = d->viewItems; + // d->viewItems changes when posted layouts are executed in itemDecorationAt, so don't copy + const QVector<QTreeViewItem> &viewItems = d->viewItems; QStyleOptionViewItem option = d->viewOptionsV1(); const QStyle::State state = option.state; @@ -1947,7 +1948,7 @@ void QTreeView::mouseDoubleClickEvent(QMouseEvent *event) if (!style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, this)) emit activated(persistent); - d->pressedIndex = QModelIndex(); + d->releaseFromDoubleClick = true; d->executePostedLayout(); // we need to make sure viewItems is updated if (d->itemsExpandable && d->expandsOnDoubleClick @@ -2664,7 +2665,10 @@ QSize QTreeView::viewportSizeHint() const \since 4.2 Expands all expandable items. - \warning: if the model contains a large number of items, + \note This function will not try to \l{QAbstractItemModel::fetchMore}{fetch more} + data. + + \warning If the model contains a large number of items, this function will take some time to execute. \sa collapseAll(), expand(), collapse(), setExpanded() @@ -2686,7 +2690,10 @@ void QTreeView::expandAll() A \a depth of -1 will expand all children, a \a depth of 0 will only expand the given \a index. - \warning: if the model contains a large number of items, + \note This function will not try to \l{QAbstractItemModel::fetchMore}{fetch more} + data. + + \warning If the model contains a large number of items, this function will take some time to execute. \sa expandAll() @@ -2751,6 +2758,9 @@ void QTreeView::collapseAll() \since 4.3 Expands all expandable items to the given \a depth. + \note This function will not try to \l{QAbstractItemModel::fetchMore}{fetch more} + data. + \sa expandAll(), collapseAll(), expand(), collapse(), setExpanded() */ void QTreeView::expandToDepth(int depth) @@ -3459,6 +3469,7 @@ int QTreeViewPrivate::indentationForItem(int item) const int QTreeViewPrivate::itemHeight(int item) const { + Q_ASSERT(item < viewItems.count()); if (uniformRowHeights) return defaultItemHeight; if (viewItems.isEmpty()) diff --git a/src/widgets/itemviews/qtreewidget.cpp b/src/widgets/itemviews/qtreewidget.cpp index 47b06a4138..713cb8e0d2 100644 --- a/src/widgets/itemviews/qtreewidget.cpp +++ b/src/widgets/itemviews/qtreewidget.cpp @@ -508,22 +508,18 @@ bool QTreeModel::insertColumns(int column, int count, const QModelIndex &parent) bool QTreeModel::removeRows(int row, int count, const QModelIndex &parent) { if (count < 1 || row < 0 || (row + count) > rowCount(parent)) return false; - - beginRemoveRows(parent, row, row + count - 1); - - QSignalBlocker blocker(this); - - QTreeWidgetItem *itm = item(parent); + QTreeWidgetItem *parentItem = item(parent); + // if parentItem is valid, begin/end RemoveRows is handled by takeChild below + if (!parentItem) + beginRemoveRows(parent, row, row + count - 1); for (int i = row + count - 1; i >= row; --i) { - QTreeWidgetItem *child = itm ? itm->takeChild(i) : rootItem->children.takeAt(i); + QTreeWidgetItem *child = parentItem ? parentItem->takeChild(i) : rootItem->children.takeAt(i); Q_ASSERT(child); child->view = nullptr; delete child; - child = nullptr; } - blocker.unblock(); - - endRemoveRows(); + if (!parentItem) + endRemoveRows(); return true; } @@ -1690,7 +1686,7 @@ QTreeWidgetItem *QTreeWidgetItem::clone() const /*! Sets the item indicator \a policy. This policy decides when the tree branch expand/collapse indicator is shown. - The default value is ShowForChildren. + The default value is DontShowIndicatorWhenChildless. \sa childIndicatorPolicy() */ @@ -2601,9 +2597,6 @@ void QTreeWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft, This signal is emitted when the specified \a item is expanded so that all of its children are displayed. - \note This signal will not be emitted if an item changes its state when - expandAll() is invoked. - \sa QTreeWidgetItem::isExpanded(), itemCollapsed(), expandItem() */ @@ -2702,7 +2695,7 @@ QTreeWidget::~QTreeWidget() } /* - Retuns the number of header columns in the view. + Returns the number of header columns in the view. \sa sortColumn(), currentColumn(), topLevelItemCount() */ |