diff options
Diffstat (limited to 'src/widgets/itemviews')
-rw-r--r-- | src/widgets/itemviews/qabstractitemdelegate.cpp | 25 | ||||
-rw-r--r-- | src/widgets/itemviews/qheaderview.cpp | 16 | ||||
-rw-r--r-- | src/widgets/itemviews/qitemdelegate.cpp | 68 | ||||
-rw-r--r-- | src/widgets/itemviews/qlistview.cpp | 66 | ||||
-rw-r--r-- | src/widgets/itemviews/qlistview.h | 4 | ||||
-rw-r--r-- | src/widgets/itemviews/qlistview_p.h | 2 | ||||
-rw-r--r-- | src/widgets/itemviews/qlistwidget.cpp | 9 | ||||
-rw-r--r-- | src/widgets/itemviews/qtableview.cpp | 55 | ||||
-rw-r--r-- | src/widgets/itemviews/qtablewidget.cpp | 36 | ||||
-rw-r--r-- | src/widgets/itemviews/qtablewidget.h | 1 | ||||
-rw-r--r-- | src/widgets/itemviews/qtablewidget_p.h | 5 | ||||
-rw-r--r-- | src/widgets/itemviews/qtreeview.cpp | 57 | ||||
-rw-r--r-- | src/widgets/itemviews/qtreeview_p.h | 2 | ||||
-rw-r--r-- | src/widgets/itemviews/qtreewidget.cpp | 56 | ||||
-rw-r--r-- | src/widgets/itemviews/qtreewidget.h | 11 | ||||
-rw-r--r-- | src/widgets/itemviews/qtreewidget_p.h | 7 |
16 files changed, 298 insertions, 122 deletions
diff --git a/src/widgets/itemviews/qabstractitemdelegate.cpp b/src/widgets/itemviews/qabstractitemdelegate.cpp index c9f321c3f6..7bc0ece4b3 100644 --- a/src/widgets/itemviews/qabstractitemdelegate.cpp +++ b/src/widgets/itemviews/qabstractitemdelegate.cpp @@ -599,18 +599,21 @@ QString QAbstractItemDelegatePrivate::textForRole(Qt::ItemDataRole role, const Q case QVariant::DateTime: text = locale.toString(value.toDateTime(), formatType); break; - default: { - if (value.canConvert<QJsonValue>()) { - const QJsonValue val = value.toJsonValue(); - if (val.isBool()) - text = QVariant(val.toBool()).toString(); - else if (val.isDouble()) - text = locale.toString(val.toDouble(), 'g', precision); - else if (val.isString()) - text = val.toString(); - } else { - text = value.toString(); + case QVariant::Type(QMetaType::QJsonValue): { + const QJsonValue val = value.toJsonValue(); + if (val.isBool()) { + text = QVariant(val.toBool()).toString(); + break; + } + if (val.isDouble()) { + text = locale.toString(val.toDouble(), 'g', precision); + break; } + // val is a string (or null) here + Q_FALLTHROUGH(); + } + default: { + text = value.toString(); if (role == Qt::DisplayRole) text.replace(QLatin1Char('\n'), QChar::LineSeparator); break; diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index 9a8206de45..3396a91dc5 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -1853,11 +1853,13 @@ bool QHeaderView::restoreState(const QByteArray &state) */ void QHeaderView::reset() { + Q_D(QHeaderView); QAbstractItemView::reset(); // it would be correct to call clear, but some apps rely // on the header keeping the sections, even after calling reset //d->clear(); initializeSections(); + d->invalidateCachedSizeHint(); } /*! @@ -2871,6 +2873,7 @@ bool QHeaderView::viewportEvent(QEvent *e) } return true; } #endif // QT_CONFIG(statustip) + case QEvent::Resize: case QEvent::FontChange: case QEvent::StyleChange: d->invalidateCachedSizeHint(); @@ -2965,8 +2968,10 @@ void QHeaderView::paintSection(QPainter *painter, const QRect &rect, int logical margin += style()->pixelMetric(QStyle::PM_SmallIconSize, 0, this) + style()->pixelMetric(QStyle::PM_HeaderMargin, 0, this); - if (d->textElideMode != Qt::ElideNone) - opt.text = opt.fontMetrics.elidedText(opt.text, d->textElideMode , rect.width() - margin); + if (d->textElideMode != Qt::ElideNone) { + const QRect textRect = style()->subElementRect(QStyle::SE_HeaderLabel, &opt, this); + opt.text = opt.fontMetrics.elidedText(opt.text, d->textElideMode, textRect.width() - margin); + } QVariant foregroundBrush = d->model->headerData(logicalIndex, d->orientation, Qt::ForegroundRole); @@ -3366,7 +3371,9 @@ void QHeaderViewPrivate::setupSectionIndicator(int section, int position) sectionIndicator->resize(w, h); #endif - QPixmap pm(w, h); + const qreal pixmapDevicePixelRatio = q->devicePixelRatioF(); + QPixmap pm(QSize(w, h) * pixmapDevicePixelRatio); + pm.setDevicePixelRatio(pixmapDevicePixelRatio); pm.fill(QColor(0, 0, 0, 45)); QRect rect(0, 0, w, h); @@ -3831,6 +3838,7 @@ void QHeaderViewPrivate::cascadingResize(int visual, int newSize) void QHeaderViewPrivate::setDefaultSectionSize(int size) { Q_Q(QHeaderView); + size = qBound(q->minimumSectionSize(), size, q->maximumSectionSize()); executePostedLayout(); invalidateCachedSizeHint(); defaultSectionSize = size; @@ -4086,7 +4094,7 @@ bool QHeaderViewPrivate::read(QDataStream &in) } int sectionItemsLengthTotal = 0; - foreach (const SectionItem §ion, newSectionItems) + for (const SectionItem §ion : qAsConst(newSectionItems)) sectionItemsLengthTotal += section.size; if (sectionItemsLengthTotal != lengthIn) return false; diff --git a/src/widgets/itemviews/qitemdelegate.cpp b/src/widgets/itemviews/qitemdelegate.cpp index 91122283a4..dff4cc4593 100644 --- a/src/widgets/itemviews/qitemdelegate.cpp +++ b/src/widgets/itemviews/qitemdelegate.cpp @@ -103,7 +103,10 @@ public: QItemEditorFactory *f; bool clipPainting; - QRect textLayoutBounds(const QStyleOptionViewItem &options) const; + QRect displayRect(const QModelIndex &index, const QStyleOptionViewItem &option, + const QRect &decorationRect, const QRect &checkRect) const; + QRect textLayoutBounds(const QStyleOptionViewItem &option, + const QRect &decorationRect, const QRect &checkRect) const; QSizeF doTextLayout(int lineWidth) const; mutable QTextLayout textLayout; mutable QTextOption textOption; @@ -121,21 +124,53 @@ public: } tmp; }; -QRect QItemDelegatePrivate::textLayoutBounds(const QStyleOptionViewItem &option) const +QRect QItemDelegatePrivate::displayRect(const QModelIndex &index, const QStyleOptionViewItem &option, + const QRect &decorationRect, const QRect &checkRect) const +{ + Q_Q(const QItemDelegate); + const QVariant value = index.data(Qt::DisplayRole); + if (!value.isValid() || value.isNull()) + return QRect(); + + const QString text = valueToText(value, option); + const QVariant fontVal = index.data(Qt::FontRole); + const QFont fnt = qvariant_cast<QFont>(fontVal).resolve(option.font); + return q->textRectangle(nullptr, + textLayoutBounds(option, decorationRect, checkRect), + fnt, text); +} + +// similar to QCommonStylePrivate::viewItemSize(Qt::DisplayRole) +QRect QItemDelegatePrivate::textLayoutBounds(const QStyleOptionViewItem &option, + const QRect &decorationRect, const QRect &checkRect) const { QRect rect = option.rect; + const QWidget *w = widget(option); + QStyle *style = w ? w->style() : QApplication::style(); const bool wrapText = option.features & QStyleOptionViewItem::WrapText; + // see QItemDelegate::drawDisplay + const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, w) + 1; switch (option.decorationPosition) { case QStyleOptionViewItem::Left: case QStyleOptionViewItem::Right: - rect.setWidth(wrapText && rect.isValid() ? rect.width() : (QFIXED_MAX)); + rect.setWidth(wrapText && rect.isValid() ? rect.width() - 2 * textMargin : (QFIXED_MAX)); break; case QStyleOptionViewItem::Top: case QStyleOptionViewItem::Bottom: - rect.setWidth(wrapText ? option.decorationSize.width() : (QFIXED_MAX)); + rect.setWidth(wrapText ? option.decorationSize.width() - 2 * textMargin : (QFIXED_MAX)); break; } + if (wrapText) { + if (!decorationRect.isNull()) + rect.setWidth(rect.width() - decorationRect.width() - 2 * textMargin); + if (!checkRect.isNull()) + rect.setWidth(rect.width() - checkRect.width() - 2 * textMargin); + // adjust height to be sure that the text fits + const QSizeF size = doTextLayout(rect.width()); + rect.setHeight(qCeil(size.height())); + } + return rect; } @@ -395,14 +430,6 @@ void QItemDelegate::paint(QPainter *painter, decorationRect = QRect(); } - QString text; - QRect displayRect; - value = index.data(Qt::DisplayRole); - if (value.isValid() && !value.isNull()) { - text = d->valueToText(value, opt); - displayRect = textRectangle(painter, d->textLayoutBounds(opt), opt.font, text); - } - QRect checkRect; Qt::CheckState checkState = Qt::Unchecked; value = index.data(Qt::CheckStateRole); @@ -411,6 +438,14 @@ void QItemDelegate::paint(QPainter *painter, checkRect = doCheck(opt, opt.rect, value); } + QString text; + QRect displayRect; + value = index.data(Qt::DisplayRole); + if (value.isValid() && !value.isNull()) { + text = d->valueToText(value, opt); + displayRect = d->displayRect(index, opt, decorationRect, checkRect); + } + // do the layout doLayout(opt, &checkRect, &decorationRect, &displayRect, false); @@ -440,12 +475,13 @@ void QItemDelegate::paint(QPainter *painter, QSize QItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { + Q_D(const QItemDelegate); QVariant value = index.data(Qt::SizeHintRole); if (value.isValid()) return qvariant_cast<QSize>(value); QRect decorationRect = rect(option, index, Qt::DecorationRole); - QRect displayRect = rect(option, index, Qt::DisplayRole); QRect checkRect = rect(option, index, Qt::CheckStateRole); + QRect displayRect = d->displayRect(index, option, decorationRect, checkRect); doLayout(option, &checkRect, &decorationRect, &displayRect, true); @@ -1000,8 +1036,8 @@ QPixmap *QItemDelegate::selected(const QPixmap &pixmap, const QPalette &palette, /*! \internal + Only used (and usable) for Qt::DecorationRole and Qt::CheckStateRole */ - QRect QItemDelegate::rect(const QStyleOptionViewItem &option, const QModelIndex &index, int role) const { @@ -1032,7 +1068,9 @@ QRect QItemDelegate::rect(const QStyleOptionViewItem &option, const QString text = d->valueToText(value, option); value = index.data(Qt::FontRole); QFont fnt = qvariant_cast<QFont>(value).resolve(option.font); - return textRectangle(0, d->textLayoutBounds(option), fnt, text); } + return textRectangle(nullptr, + d->textLayoutBounds(option, QRect(), QRect()), + fnt, text); } } } return QRect(); diff --git a/src/widgets/itemviews/qlistview.cpp b/src/widgets/itemviews/qlistview.cpp index a7174a92e8..e5769940d4 100644 --- a/src/widgets/itemviews/qlistview.cpp +++ b/src/widgets/itemviews/qlistview.cpp @@ -1631,6 +1631,32 @@ bool QListView::isSelectionRectVisible() const } /*! + \property QListView::itemAlignment + \brief the alignment of each item in its cell + \since 5.12 + + This is only supported in ListMode with TopToBottom flow + and with wrapping enabled. + The default alignment is 0, which means that an item fills + its cell entirely. +*/ +void QListView::setItemAlignment(Qt::Alignment alignment) +{ + Q_D(QListView); + if (d->itemAlignment == alignment) + return; + d->itemAlignment = alignment; + if (viewMode() == ListMode && flow() == QListView::TopToBottom && isWrapping()) + d->doDelayedItemsLayout(); +} + +Qt::Alignment QListView::itemAlignment() const +{ + Q_D(const QListView); + return d->itemAlignment; +} + +/*! \reimp */ bool QListView::event(QEvent *e) @@ -1656,7 +1682,8 @@ QListViewPrivate::QListViewPrivate() column(0), uniformItemSizes(false), batchSize(100), - showElasticBand(false) + showElasticBand(false), + itemAlignment(Qt::Alignment()) { } @@ -2366,6 +2393,7 @@ QListViewItem QListModeViewBase::indexToListViewItem(const QModelIndex &index) c options.rect.setSize(contentsSize); QSize size = (uniformItemSizes() && cachedItemSize().isValid()) ? cachedItemSize() : itemSize(options, index); + QSize cellSize = size; QPoint pos; if (flow() == QListView::LeftToRight) { @@ -2378,12 +2406,22 @@ QListViewItem QListModeViewBase::indexToListViewItem(const QModelIndex &index) c int right = (segment + 1 >= segmentPositions.count() ? contentsSize.width() : segmentPositions.at(segment + 1)); - size.setWidth(right - pos.x()); + cellSize.setWidth(right - pos.x()); } else { // make the items as wide as the viewport - size.setWidth(qMax(size.width(), viewport()->width() - 2 * spacing())); + cellSize.setWidth(qMax(size.width(), viewport()->width() - 2 * spacing())); } } + if (dd->itemAlignment & Qt::AlignHorizontal_Mask) { + size.setWidth(qMin(size.width(), cellSize.width())); + if (dd->itemAlignment & Qt::AlignRight) + pos.setX(pos.x() + cellSize.width() - size.width()); + if (dd->itemAlignment & Qt::AlignHCenter) + pos.setX(pos.x() + (cellSize.width() - size.width()) / 2); + } else { + size.setWidth(cellSize.width()); + } + return QListViewItem(QRect(pos, size), index.row()); } @@ -2562,8 +2600,18 @@ QVector<QModelIndex> QListModeViewBase::intersectingSet(const QRect &area) const if (isHidden(row)) continue; QModelIndex index = modelIndex(row); - if (index.isValid()) - ret += index; + if (index.isValid()) { + if (flow() == QListView::LeftToRight || dd->itemAlignment == Qt::Alignment()) { + ret += index; + } else { + const auto viewItem = indexToListViewItem(index); + const int iw = viewItem.width(); + const int startPos = qMax(segStartPosition, segmentPositions.at(seg)); + const int endPos = qMin(segmentPositions.at(seg + 1), segEndPosition); + if (endPos >= viewItem.x && startPos < viewItem.x + iw) + ret += index; + } + } #if 0 // for debugging else qWarning("intersectingSet: row %d was invalid", row); @@ -2603,7 +2651,7 @@ int QListModeViewBase::perItemScrollingPageSteps(int length, int bounds, bool wr positions = segmentPositions; else if (!flowPositions.isEmpty()) { positions.reserve(scrollValueMap.size()); - foreach (int itemShown, scrollValueMap) + for (int itemShown : scrollValueMap) positions.append(flowPositions.at(itemShown)); } if (positions.isEmpty() || bounds <= length) @@ -2767,6 +2815,8 @@ bool QIconModeViewBase::filterStartDrag(Qt::DropActions supportedActions) drag->setHotSpot(dd->pressedPosition - rect.topLeft()); Qt::DropAction action = drag->exec(supportedActions, dd->defaultDropAction); draggedItems.clear(); + // for internal moves the action was set to Qt::CopyAction in + // filterDropEvent() to avoid the deletion here if (action == Qt::MoveAction) dd->clearOrRemove(); } @@ -2784,7 +2834,7 @@ bool QIconModeViewBase::filterDropEvent(QDropEvent *e) if (qq->acceptDrops()) { const Qt::ItemFlags dropableFlags = Qt::ItemIsDropEnabled|Qt::ItemIsEnabled; const QVector<QModelIndex> &dropIndices = intersectingSet(QRect(end, QSize(1, 1))); - foreach (const QModelIndex &index, dropIndices) + for (const QModelIndex &index : dropIndices) if ((index.flags() & dropableFlags) == dropableFlags) return false; } @@ -2803,6 +2853,8 @@ bool QIconModeViewBase::filterDropEvent(QDropEvent *e) dd->stopAutoScroll(); draggedItems.clear(); dd->emitIndexesMoved(indexes); + // do not delete item on internal move, see filterStartDrag() + e->setDropAction(Qt::CopyAction); 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/qlistview.h b/src/widgets/itemviews/qlistview.h index 9fc4035999..8a5d5e02ae 100644 --- a/src/widgets/itemviews/qlistview.h +++ b/src/widgets/itemviews/qlistview.h @@ -65,6 +65,7 @@ class Q_WIDGETS_EXPORT QListView : public QAbstractItemView Q_PROPERTY(int batchSize READ batchSize WRITE setBatchSize) Q_PROPERTY(bool wordWrap READ wordWrap WRITE setWordWrap) Q_PROPERTY(bool selectionRectVisible READ isSelectionRectVisible WRITE setSelectionRectVisible) + Q_PROPERTY(Qt::Alignment itemAlignment READ itemAlignment WRITE setItemAlignment) public: enum Movement { Static, Free, Snap }; @@ -125,6 +126,9 @@ public: void setSelectionRectVisible(bool show); bool isSelectionRectVisible() const; + void setItemAlignment(Qt::Alignment alignment); + Qt::Alignment itemAlignment() const; + QRect visualRect(const QModelIndex &index) const override; void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) override; QModelIndex indexAt(const QPoint &p) const override; diff --git a/src/widgets/itemviews/qlistview_p.h b/src/widgets/itemviews/qlistview_p.h index ca947292e3..181386d4d0 100644 --- a/src/widgets/itemviews/qlistview_p.h +++ b/src/widgets/itemviews/qlistview_p.h @@ -431,6 +431,8 @@ public: QRect elasticBand; bool showElasticBand; + + Qt::Alignment itemAlignment; }; // inline implementations diff --git a/src/widgets/itemviews/qlistwidget.cpp b/src/widgets/itemviews/qlistwidget.cpp index 4f1c7fe80a..72e0a67a64 100644 --- a/src/widgets/itemviews/qlistwidget.cpp +++ b/src/widgets/itemviews/qlistwidget.cpp @@ -48,9 +48,6 @@ QT_BEGIN_NAMESPACE -// workaround for VC++ 6.0 linker bug (?) -typedef bool(*LessThan)(const QPair<QListWidgetItem*,int>&,const QPair<QListWidgetItem*,int>&); - class QListWidgetMimeData : public QMimeData { Q_OBJECT @@ -301,7 +298,7 @@ void QListModel::sort(int column, Qt::SortOrder order) sorting[i].second = i; } - LessThan compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); + const auto compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); std::sort(sorting.begin(), sorting.end(), compare); QModelIndexList fromIndexes; QModelIndexList toIndexes; @@ -338,7 +335,7 @@ void QListModel::ensureSorted(int column, Qt::SortOrder order, int start, int en sorting[i].second = start + i; } - LessThan compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); + const auto compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); std::sort(sorting.begin(), sorting.end(), compare); QModelIndexList oldPersistentIndexes = persistentIndexList(); @@ -1847,7 +1844,7 @@ QMimeData *QListWidget::mimeData(const QList<QListWidgetItem*> items) const // if non empty, it's called from the model's own mimeData if (cachedIndexes.isEmpty()) { cachedIndexes.reserve(items.count()); - foreach (QListWidgetItem *item, items) + for (QListWidgetItem *item : items) cachedIndexes << indexFromItem(item); QMimeData *result = d->listModel()->internalMimeData(); diff --git a/src/widgets/itemviews/qtableview.cpp b/src/widgets/itemviews/qtableview.cpp index 1938fd8e92..9725a768de 100644 --- a/src/widgets/itemviews/qtableview.cpp +++ b/src/widgets/itemviews/qtableview.cpp @@ -74,7 +74,7 @@ void QSpanCollection::addSpan(QSpanCollection::Span *span) //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) { + for (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); @@ -798,6 +798,7 @@ void QTableViewPrivate::drawAndClipSpans(const QRegion &area, QPainter *painter, const QStyleOptionViewItem &option, QBitArray *drawn, int firstVisualRow, int lastVisualRow, int firstVisualColumn, int lastVisualColumn) { + Q_Q(const QTableView); bool alternateBase = false; QRegion region = viewport->rect(); @@ -816,7 +817,7 @@ void QTableViewPrivate::drawAndClipSpans(const QRegion &area, QPainter *painter, visibleSpans = set.toList(); } - foreach (QSpanCollection::Span *span, visibleSpans) { + for (QSpanCollection::Span *span : qAsConst(visibleSpans)) { int row = span->top(); int col = span->left(); QModelIndex index = model->index(row, col, root); @@ -831,6 +832,18 @@ void QTableViewPrivate::drawAndClipSpans(const QRegion &area, QPainter *painter, alternateBase = alternatingColors && (span->top() & 1); opt.features.setFlag(QStyleOptionViewItem::Alternate, alternateBase); drawCell(painter, opt, index); + if (showGrid) { + // adjust the clip rect to be able to paint the top & left grid lines + // if the headers are not visible, see paintEvent() + if (horizontalHeader->visualIndex(row) == 0) + rect.setTop(rect.top() + 1); + if (verticalHeader->visualIndex(row) == 0) { + if (q->isLeftToRight()) + rect.setLeft(rect.left() + 1); + else + rect.setRight(rect.right() - 1); + } + } region -= rect; for (int r = span->top(); r <= span->bottom(); ++r) { const int vr = visualRow(r); @@ -1163,7 +1176,6 @@ void QTableView::doItemsLayout() { Q_D(QTableView); QAbstractItemView::doItemsLayout(); - d->verticalHeader->d_func()->setScrollOffset(verticalScrollBar(), verticalScrollMode()); if (!d->verticalHeader->updatesEnabled()) d->verticalHeader->setUpdatesEnabled(true); } @@ -1321,10 +1333,10 @@ void QTableView::scrollContentsBy(int dx, int dy) //we need to update the first line of the previous top item in the view //because it has the grid drawn if the header is invisible. //It is strictly related to what's done at then end of the paintEvent - if (dy > 0 && d->horizontalHeader->isHidden() && d->verticalScrollMode == ScrollPerItem) { + if (dy > 0 && d->horizontalHeader->isHidden()) { d->viewport->update(0, dy, d->viewport->width(), dy); } - if (dx > 0 && d->verticalHeader->isHidden() && d->horizontalScrollMode == ScrollPerItem) { + if (dx > 0 && d->verticalHeader->isHidden()) { d->viewport->update(dx, 0, dx, d->viewport->height()); } } @@ -1504,10 +1516,26 @@ void QTableView::paintEvent(QPaintEvent *event) //draw the top & left grid lines if the headers are not visible. //We do update this line when subsequent scroll happen (see scrollContentsBy) - if (horizontalHeader->isHidden() && verticalScrollMode() == ScrollPerItem) - painter.drawLine(dirtyArea.left(), 0, dirtyArea.right(), 0); - if (verticalHeader->isHidden() && horizontalScrollMode() == ScrollPerItem) - painter.drawLine(0, dirtyArea.top(), 0, dirtyArea.bottom()); + if (horizontalHeader->isHidden() && top == 0) { + const int row = verticalHeader->logicalIndex(top); + if (!verticalHeader->isSectionHidden(row)) { + const int rowY = rowViewportPosition(row) + offset.y(); + if (rowY == dirtyArea.top()) + painter.drawLine(dirtyArea.left(), rowY, dirtyArea.right(), rowY); + } + } + if (verticalHeader->isHidden() && left == 0) { + const int col = horizontalHeader->logicalIndex(left); + if (!horizontalHeader->isSectionHidden(col)) { + int colX = columnViewportPosition(col) + offset.x(); + if (!isLeftToRight()) + colX += columnWidth(left) - 1; + if (isLeftToRight() && colX == dirtyArea.left()) + painter.drawLine(colX, dirtyArea.top(), colX, dirtyArea.bottom()); + if (!isLeftToRight() && colX == dirtyArea.right()) + painter.drawLine(colX, dirtyArea.top(), colX, dirtyArea.bottom()); + } + } painter.setPen(old); } } @@ -1788,8 +1816,12 @@ QModelIndex QTableView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifi break; case MovePageUp: { int newRow = rowAt(visualRect(current).bottom() - d->viewport->height()); - if (newRow == -1) - newRow = d->logicalRow(0); + if (newRow == -1) { + int visualRow = 0; + while (visualRow < bottom && isRowHidden(d->logicalRow(visualRow))) + ++visualRow; + newRow = d->logicalRow(visualRow); + } return d->model->index(newRow, current.column(), d->root); } case MovePageDown: { @@ -2194,6 +2226,7 @@ void QTableView::updateGeometries() verticalScrollBar()->setRange(0, verticalLength - vsize.height()); verticalScrollBar()->d_func()->itemviewChangeSingleStep(qMax(vsize.height() / (rowsInViewport + 1), 2)); } + d->verticalHeader->d_func()->setScrollOffset(verticalScrollBar(), verticalScrollMode()); d->geometryRecursionBlock = false; QAbstractItemView::updateGeometries(); diff --git a/src/widgets/itemviews/qtablewidget.cpp b/src/widgets/itemviews/qtablewidget.cpp index 9d5a2aa1bd..11925af7a0 100644 --- a/src/widgets/itemviews/qtablewidget.cpp +++ b/src/widgets/itemviews/qtablewidget.cpp @@ -453,17 +453,20 @@ bool QTableModel::setItemData(const QModelIndex &index, const QMap<int, QVariant QTableWidget *view = qobject_cast<QTableWidget*>(QObject::parent()); QTableWidgetItem *itm = item(index); if (itm) { - itm->view = 0; // prohibits item from calling itemChanged() - bool changed = false; + itm->view = nullptr; // prohibits item from calling itemChanged() + QVector<int> rolesVec; for (QMap<int, QVariant>::ConstIterator it = roles.constBegin(); it != roles.constEnd(); ++it) { - if (itm->data(it.key()) != it.value()) { - itm->setData(it.key(), it.value()); - changed = true; + const int role = (it.key() == Qt::EditRole ? Qt::DisplayRole : it.key()); + if (itm->data(role) != it.value()) { + itm->setData(role, it.value()); + rolesVec += role; + if (role == Qt::DisplayRole) + rolesVec += Qt::EditRole; } } itm->view = view; - if (changed) - itemChanged(itm); + if (!rolesVec.isEmpty()) + itemChanged(itm, rolesVec); return true; } @@ -506,7 +509,7 @@ void QTableModel::sort(int column, Qt::SortOrder order) unsortable.append(row); } - LessThan compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); + const auto compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); std::stable_sort(sortable.begin(), sortable.end(), compare); QVector<QTableWidgetItem*> sorted_table(tableItems.count()); @@ -558,7 +561,7 @@ void QTableModel::ensureSorted(int column, Qt::SortOrder order, sorting.append(QPair<QTableWidgetItem*,int>(itm, row)); } - LessThan compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); + const auto compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); std::stable_sort(sorting.begin(), sorting.end(), compare); QModelIndexList oldPersistentIndexes, newPersistentIndexes; QVector<QTableWidgetItem*> newTable = tableItems; @@ -771,7 +774,7 @@ void QTableModel::clearContents() endResetModel(); } -void QTableModel::itemChanged(QTableWidgetItem *item) +void QTableModel::itemChanged(QTableWidgetItem *item, const QVector<int> &roles) { if (!item) return; @@ -787,7 +790,7 @@ void QTableModel::itemChanged(QTableWidgetItem *item) } else { QModelIndex idx = index(item); if (idx.isValid()) - emit dataChanged(idx, idx); + emit dataChanged(idx, idx, roles); } } @@ -1386,8 +1389,13 @@ void QTableWidgetItem::setData(int role, const QVariant &value) } if (!found) values.append(QWidgetItemData(role, value)); - if (QTableModel *model = (view ? qobject_cast<QTableModel*>(view->model()) : 0)) - model->itemChanged(this); + if (QTableModel *model = (view ? qobject_cast<QTableModel*>(view->model()) : nullptr)) + { + const QVector<int> roles((role == Qt::DisplayRole) ? + QVector<int>({Qt::DisplayRole, Qt::EditRole}) : + QVector<int>({role})); + model->itemChanged(this, roles); + } } /*! @@ -2595,7 +2603,7 @@ QMimeData *QTableWidget::mimeData(const QList<QTableWidgetItem*> items) const // if non empty, it's called from the model's own mimeData if (cachedIndexes.isEmpty()) { cachedIndexes.reserve(items.count()); - foreach (QTableWidgetItem *item, items) + for (QTableWidgetItem *item : items) cachedIndexes << indexFromItem(item); QMimeData *result = d->tableModel()->internalMimeData(); diff --git a/src/widgets/itemviews/qtablewidget.h b/src/widgets/itemviews/qtablewidget.h index 7322e3aed7..9de27d164f 100644 --- a/src/widgets/itemviews/qtablewidget.h +++ b/src/widgets/itemviews/qtablewidget.h @@ -302,6 +302,7 @@ Q_SIGNALS: void itemActivated(QTableWidgetItem *item); void itemEntered(QTableWidgetItem *item); + // ### Qt 6: add changed roles void itemChanged(QTableWidgetItem *item); void currentItemChanged(QTableWidgetItem *current, QTableWidgetItem *previous); diff --git a/src/widgets/itemviews/qtablewidget_p.h b/src/widgets/itemviews/qtablewidget_p.h index 6412477be0..9899272fce 100644 --- a/src/widgets/itemviews/qtablewidget_p.h +++ b/src/widgets/itemviews/qtablewidget_p.h @@ -62,9 +62,6 @@ QT_REQUIRE_CONFIG(tablewidget); QT_BEGIN_NAMESPACE -// workaround for VC++ 6.0 linker bug -typedef bool(*LessThan)(const QPair<QTableWidgetItem*,int>&,const QPair<QTableWidgetItem*,int>&); - class QTableWidgetMimeData : public QMimeData { Q_OBJECT @@ -160,7 +157,7 @@ public: void clear(); void clearContents(); - void itemChanged(QTableWidgetItem *item); + void itemChanged(QTableWidgetItem *item, const QVector<int> &roles = QVector<int>()); QTableWidgetItem *createItem() const; const QTableWidgetItem *itemPrototype() const; diff --git a/src/widgets/itemviews/qtreeview.cpp b/src/widgets/itemviews/qtreeview.cpp index fbfbe56246..b534de5c6a 100644 --- a/src/widgets/itemviews/qtreeview.cpp +++ b/src/widgets/itemviews/qtreeview.cpp @@ -632,11 +632,8 @@ bool QTreeView::isFirstColumnSpanned(int row, const QModelIndex &parent) const Q_D(const QTreeView); if (d->spanningIndexes.isEmpty() || !d->model) return false; - QModelIndex index = d->model->index(row, 0, parent); - for (int i = 0; i < d->spanningIndexes.count(); ++i) - if (d->spanningIndexes.at(i) == index) - return true; - return false; + const QModelIndex index = d->model->index(row, 0, parent); + return d->spanningIndexes.contains(index); } /*! @@ -653,20 +650,14 @@ void QTreeView::setFirstColumnSpanned(int row, const QModelIndex &parent, bool s Q_D(QTreeView); if (!d->model) return; - QModelIndex index = d->model->index(row, 0, parent); + const QModelIndex index = d->model->index(row, 0, parent); if (!index.isValid()) return; - if (span) { - QPersistentModelIndex persistent(index); - if (!d->spanningIndexes.contains(persistent)) - d->spanningIndexes.append(persistent); - } else { - QPersistentModelIndex persistent(index); - int i = d->spanningIndexes.indexOf(persistent); - if (i >= 0) - d->spanningIndexes.remove(i); - } + if (span) + d->spanningIndexes.insert(index); + else + d->spanningIndexes.remove(index); d->executePostedLayout(); int i = d->viewIndex(index); @@ -1420,7 +1411,7 @@ QItemViewPaintPairs QTreeViewPrivate::draggablePaintPairs(const QModelIndexList if (spanningIndexes.isEmpty()) return QAbstractItemViewPrivate::draggablePaintPairs(indexes, r); QModelIndexList list; - foreach (const QModelIndex &idx, indexes) { + for (const QModelIndex &idx : indexes) { if (idx.column() > 0 && q->isFirstColumnSpanned(idx.row(), idx.parent())) continue; list << idx; @@ -2000,19 +1991,21 @@ void QTreeView::keyPressEvent(QKeyEvent *event) if (d->isIndexValid(current) && d->model && d->itemsExpandable) { switch (event->key()) { case Qt::Key_Asterisk: { + // do layouting only once after expanding is done + d->doDelayedItemsLayout(); QStack<QModelIndex> parents; parents.push(current); - while (!parents.isEmpty()) { - QModelIndex parent = parents.pop(); - for (int row = 0; row < d->model->rowCount(parent); ++row) { - QModelIndex child = d->model->index(row, 0, parent); - if (!d->isIndexValid(child)) - break; - parents.push(child); - expand(child); - } + while (!parents.isEmpty()) { + QModelIndex parent = parents.pop(); + for (int row = 0; row < d->model->rowCount(parent); ++row) { + QModelIndex child = d->model->index(row, 0, parent); + if (!d->isIndexValid(child)) + break; + parents.push(child); + expand(child); } - expand(current); + } + expand(current); break; } case Qt::Key_Plus: expand(current); @@ -2495,7 +2488,6 @@ void QTreeView::scrollContentsBy(int dx, int dy) int previousScrollbarValue = currentScrollbarValue + dy; // -(-dy) int currentViewIndex = currentScrollbarValue; // the first visible item int previousViewIndex = previousScrollbarValue; - const QVector<QTreeViewItem> viewItems = d->viewItems; dy = 0; if (previousViewIndex < currentViewIndex) { // scrolling down for (int i = previousViewIndex; i < currentViewIndex; ++i) { @@ -3732,9 +3724,14 @@ void QTreeViewPrivate::updateScrollBars() int QTreeViewPrivate::itemDecorationAt(const QPoint &pos) const { + Q_Q(const QTreeView); executePostedLayout(); - int x = pos.x(); - int column = header->logicalIndexAt(x); + bool spanned = false; + if (!spanningIndexes.isEmpty()) { + const QModelIndex index = q->indexAt(pos); + spanned = q->isFirstColumnSpanned(index.row(), index.parent()); + } + const int column = spanned ? 0 : header->logicalIndexAt(pos.x()); if (!isTreePosition(column)) return -1; // no logical index at x diff --git a/src/widgets/itemviews/qtreeview_p.h b/src/widgets/itemviews/qtreeview_p.h index 9a391ee88a..8b217036a2 100644 --- a/src/widgets/itemviews/qtreeview_p.h +++ b/src/widgets/itemviews/qtreeview_p.h @@ -247,7 +247,7 @@ public: void updateIndentationFromStyle(); // used for spanning rows - QVector<QPersistentModelIndex> spanningIndexes; + QSet<QPersistentModelIndex> spanningIndexes; // used for updating resized columns int columnResizeTimerID; diff --git a/src/widgets/itemviews/qtreewidget.cpp b/src/widgets/itemviews/qtreewidget.cpp index 654c241079..a0af27115d 100644 --- a/src/widgets/itemviews/qtreewidget.cpp +++ b/src/widgets/itemviews/qtreewidget.cpp @@ -52,9 +52,6 @@ QT_BEGIN_NAMESPACE -// workaround for VC++ 6.0 linker bug (?) -typedef bool(*LessThan)(const QPair<QTreeWidgetItem*,int>&,const QPair<QTreeWidgetItem*,int>&); - class QTreeModelLessThan { public: @@ -610,7 +607,7 @@ void QTreeModel::ensureSorted(int column, Qt::SortOrder order, sorting[i].second = start + i; } - LessThan compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); + const auto compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); std::stable_sort(sorting.begin(), sorting.end(), compare); QModelIndexList oldPersistentIndexes; @@ -777,7 +774,7 @@ bool QTreeModel::isChanging() const if column is -1 then all columns have changed */ -void QTreeModel::emitDataChanged(QTreeWidgetItem *item, int column) +void QTreeModel::emitDataChanged(QTreeWidgetItem *item, int column, const QVector<int> &roles) { if (signalsBlocked()) return; @@ -800,7 +797,7 @@ void QTreeModel::emitDataChanged(QTreeWidgetItem *item, int column) topLeft = index(item, column); bottomRight = topLeft; } - emit dataChanged(topLeft, bottomRight); + emit dataChanged(topLeft, bottomRight, roles); } void QTreeModel::beginInsertItems(QTreeWidgetItem *parent, int row, int count) @@ -850,7 +847,7 @@ void QTreeModel::sortItems(QList<QTreeWidgetItem*> *items, int column, Qt::SortO } // do the sorting - LessThan compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); + const auto compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan); std::stable_sort(sorting.begin(), sorting.end(), compare); QModelIndexList fromList; @@ -1015,6 +1012,14 @@ void QTreeModel::timerEvent(QTimerEvent *ev) \sa isHidden() */ +void QTreeWidgetItem::setHidden(bool ahide) +{ + if (view) { + view->setItemHidden(this, ahide); + d->hidden = ahide; + } +} + /*! \fn bool QTreeWidgetItem::isHidden() const \since 4.2 @@ -1024,6 +1029,11 @@ void QTreeModel::timerEvent(QTimerEvent *ev) \sa setHidden() */ +bool QTreeWidgetItem::isHidden() const +{ + return (view ? d->hidden : false); +} + /*! \fn void QTreeWidgetItem::setExpanded(bool expand) \since 4.2 @@ -1651,6 +1661,25 @@ void QTreeWidgetItem::setFlags(Qt::ItemFlags flags) itemChanged(); } +void QTreeWidgetItemPrivate::updateHiddenStatus(QTreeWidgetItem *item, bool inserting) +{ + QTreeModel *model = (item->view ? qobject_cast<QTreeModel*>(item->view->model()) : 0); + if (!model) + return; + QStack<QTreeWidgetItem *> parents; + parents.push(item); + while (!parents.isEmpty()) { + QTreeWidgetItem *parent = parents.pop(); + QModelIndex index = model->index(parent, 0); + if (parent->d->hidden) + item->view->setRowHidden(index.row(), index.parent(), inserting); + for (int i = 0; i < parent->children.count(); ++i) { + QTreeWidgetItem *child = parent->children.at(i); + parents.push(child); + } + } +} + void QTreeWidgetItemPrivate::propagateDisabled(QTreeWidgetItem *item) { Q_ASSERT(item); @@ -1766,11 +1795,14 @@ void QTreeWidgetItem::setData(int column, int role, const QVariant &value) } if (model) { - model->emitDataChanged(this, column); + const QVector<int> roles((role == Qt::DisplayRole || role == Qt::EditRole) ? + QVector<int>({Qt::DisplayRole, Qt::EditRole}) : + QVector<int>({role})); + model->emitDataChanged(this, column, roles); if (role == Qt::CheckStateRole) { QTreeWidgetItem *p; for (p = par; p && (p->itemFlags & Qt::ItemIsAutoTristate); p = p->par) - model->emitDataChanged(p, column); + model->emitDataChanged(p, column, roles); } } } @@ -1937,6 +1969,7 @@ void QTreeWidgetItem::insertChild(int index, QTreeWidgetItem *child) stack.push(i->children.at(c)); } children.insert(index, child); + d->updateHiddenStatus(child, true); model->endInsertItems(); model->skipPendingSort = wasSkipSort; } else { @@ -1974,6 +2007,7 @@ QTreeWidgetItem *QTreeWidgetItem::takeChild(int index) } if (index >= 0 && index < children.count()) { if (model) model->beginRemoveItems(this, index, 1); + d->updateHiddenStatus(children.at(index), false); QTreeWidgetItem *item = children.takeAt(index); item->par = 0; QStack<QTreeWidgetItem*> stack; @@ -2052,6 +2086,7 @@ void QTreeWidgetItem::insertChildren(int index, const QList<QTreeWidgetItem*> &c this->children.insert(index + n, child); if (child->par) d->propagateDisabled(child); + d->updateHiddenStatus(child, true); } if (model) model->endInsertItems(); } @@ -3099,6 +3134,8 @@ bool QTreeWidget::isItemHidden(const QTreeWidgetItem *item) const */ void QTreeWidget::setItemHidden(const QTreeWidgetItem *item, bool hide) { + if (!item) + return; Q_D(QTreeWidget); if (item == d->treeModel()->headerItem) { header()->setHidden(hide); @@ -3106,6 +3143,7 @@ void QTreeWidget::setItemHidden(const QTreeWidgetItem *item, bool hide) const QModelIndex index = d->index(item); setRowHidden(index.row(), index.parent(), hide); } + item->d->hidden = hide; } /*! diff --git a/src/widgets/itemviews/qtreewidget.h b/src/widgets/itemviews/qtreewidget.h index a31af0428a..975f208702 100644 --- a/src/widgets/itemviews/qtreewidget.h +++ b/src/widgets/itemviews/qtreewidget.h @@ -82,8 +82,8 @@ public: inline void setSelected(bool select); inline bool isSelected() const; - inline void setHidden(bool hide); - inline bool isHidden() const; + void setHidden(bool hide); + bool isHidden() const; inline void setExpanded(bool expand); inline bool isExpanded() const; @@ -339,6 +339,7 @@ Q_SIGNALS: void itemDoubleClicked(QTreeWidgetItem *item, int column); void itemActivated(QTreeWidgetItem *item, int column); void itemEntered(QTreeWidgetItem *item, int column); + // ### Qt 6: add changed roles void itemChanged(QTreeWidgetItem *item, int column); void itemExpanded(QTreeWidgetItem *item); void itemCollapsed(QTreeWidgetItem *item); @@ -409,12 +410,6 @@ inline void QTreeWidgetItem::setSelected(bool aselect) inline bool QTreeWidgetItem::isSelected() const { return (view ? view->isItemSelected(this) : false); } -inline void QTreeWidgetItem::setHidden(bool ahide) -{ if (view) view->setItemHidden(this, ahide); } - -inline bool QTreeWidgetItem::isHidden() const -{ return (view ? view->isItemHidden(this) : false); } - inline void QTreeWidgetItem::setExpanded(bool aexpand) { if (view) view->setItemExpanded(this, aexpand); } diff --git a/src/widgets/itemviews/qtreewidget_p.h b/src/widgets/itemviews/qtreewidget_p.h index f4625842ef..adc2c2c421 100644 --- a/src/widgets/itemviews/qtreewidget_p.h +++ b/src/widgets/itemviews/qtreewidget_p.h @@ -139,7 +139,7 @@ public: protected: QTreeModel(QTreeModelPrivate &, QTreeWidget *parent = 0); - void emitDataChanged(QTreeWidgetItem *item, int column); + void emitDataChanged(QTreeWidgetItem *item, int column, const QVector<int> &roles); void beginInsertItems(QTreeWidgetItem *parent, int row, int count); void endInsertItems(); void beginRemoveItems(QTreeWidgetItem *parent, int row, int count); @@ -187,13 +187,16 @@ class QTreeWidgetItemPrivate { public: QTreeWidgetItemPrivate(QTreeWidgetItem *item) - : q(item), disabled(false), selected(false), rowGuess(-1), policy(QTreeWidgetItem::DontShowIndicatorWhenChildless) {} + : q(item), disabled(false), selected(false), hidden(false), rowGuess(-1), + policy(QTreeWidgetItem::DontShowIndicatorWhenChildless) {} void propagateDisabled(QTreeWidgetItem *item); + void updateHiddenStatus(QTreeWidgetItem *item, bool inserting); void sortChildren(int column, Qt::SortOrder order, bool climb); QTreeWidgetItem *q; QVariantList display; uint disabled : 1; uint selected : 1; + uint hidden : 1; int rowGuess; QTreeWidgetItem::ChildIndicatorPolicy policy; }; |