X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/083248d16bf92003dfeb2106890ed4b068344dfc..169cca55b9621689712321da8c0425f8002d0008:/src/kitemviews/private/kitemlistviewlayouter.cpp diff --git a/src/kitemviews/private/kitemlistviewlayouter.cpp b/src/kitemviews/private/kitemlistviewlayouter.cpp index d6e78ae1a..d54457908 100644 --- a/src/kitemviews/private/kitemlistviewlayouter.cpp +++ b/src/kitemviews/private/kitemlistviewlayouter.cpp @@ -22,11 +22,11 @@ #include #include "kitemlistsizehintresolver.h" -#include +#include "dolphindebug.h" // #define KITEMLISTVIEWLAYOUTER_DEBUG -KItemListViewLayouter::KItemListViewLayouter(QObject* parent) : +KItemListViewLayouter::KItemListViewLayouter(KItemListSizeHintResolver* sizeHintResolver, QObject* parent) : QObject(parent), m_dirty(true), m_visibleIndexesDirty(true), @@ -36,7 +36,7 @@ KItemListViewLayouter::KItemListViewLayouter(QObject* parent) : m_itemMargin(), m_headerHeight(0), m_model(0), - m_sizeHintResolver(0), + m_sizeHintResolver(sizeHintResolver), m_scrollOffset(0), m_maximumScrollOffset(0), m_itemOffset(0), @@ -46,11 +46,14 @@ KItemListViewLayouter::KItemListViewLayouter(QObject* parent) : m_columnWidth(0), m_xPosInc(0), m_columnCount(0), + m_rowOffsets(), + m_columnOffsets(), m_groupItemIndexes(), m_groupHeaderHeight(0), m_groupHeaderMargin(0), m_itemInfos() { + Q_ASSERT(m_sizeHintResolver); } KItemListViewLayouter::~KItemListViewLayouter() @@ -207,19 +210,6 @@ const KItemModelBase* KItemListViewLayouter::model() const return m_model; } -void KItemListViewLayouter::setSizeHintResolver(const KItemListSizeHintResolver* sizeHintResolver) -{ - if (m_sizeHintResolver != sizeHintResolver) { - m_sizeHintResolver = sizeHintResolver; - m_dirty = true; - } -} - -const KItemListSizeHintResolver* KItemListViewLayouter::sizeHintResolver() const -{ - return m_sizeHintResolver; -} - int KItemListViewLayouter::firstVisibleIndex() const { const_cast(this)->doLayout(); @@ -239,20 +229,27 @@ QRectF KItemListViewLayouter::itemRect(int index) const return QRectF(); } + QSizeF sizeHint = m_sizeHintResolver->sizeHint(index); + + const qreal x = m_columnOffsets.at(m_itemInfos.at(index).column); + const qreal y = m_rowOffsets.at(m_itemInfos.at(index).row); + if (m_scrollOrientation == Qt::Horizontal) { // Rotate the logical direction which is always vertical by 90° // to get the physical horizontal direction - const QRectF& b = m_itemInfos[index].rect; - QRectF bounds(b.y(), b.x(), b.height(), b.width()); - QPointF pos = bounds.topLeft(); + QPointF pos(y, x); pos.rx() -= m_scrollOffset; - bounds.moveTo(pos); - return bounds; + sizeHint.transpose(); + return QRectF(pos, sizeHint); } - QRectF bounds = m_itemInfos[index].rect; - bounds.moveTo(bounds.topLeft() - QPointF(m_itemOffset, m_scrollOffset)); - return bounds; + if (sizeHint.width() <= 0) { + // In Details View, a size hint with negative width is used internally. + sizeHint.rwidth() = m_itemSize.width(); + } + + const QPointF pos(x - m_itemOffset, y - m_scrollOffset); + return QRectF(pos, sizeHint); } QRectF KItemListViewLayouter::groupHeaderRect(int index) const @@ -274,27 +271,30 @@ QRectF KItemListViewLayouter::groupHeaderRect(int index) const pos.rx() -= m_itemMargin.width(); pos.ry() = 0; - // Determine the maximum width used in the - // current column. As the scroll-direction is - // Qt::Horizontal and m_itemRects is accessed directly, - // the logical height represents the visual width. - qreal width = minimumGroupHeaderWidth(); - const qreal y = m_itemInfos[index].rect.y(); + // Determine the maximum width used in the current column. As the + // scroll-direction is Qt::Horizontal and m_itemRects is accessed + // directly, the logical height represents the visual width, and + // the logical row represents the column. + qreal headerWidth = minimumGroupHeaderWidth(); + const int row = m_itemInfos[index].row; const int maxIndex = m_itemInfos.count() - 1; while (index <= maxIndex) { - QRectF bounds = m_itemInfos[index].rect; - if (bounds.y() != y) { + if (m_itemInfos[index].row != row) { break; } - if (bounds.height() > width) { - width = bounds.height(); + const qreal itemWidth = (m_scrollOrientation == Qt::Vertical) + ? m_sizeHintResolver->sizeHint(index).width() + : m_sizeHintResolver->sizeHint(index).height(); + + if (itemWidth > headerWidth) { + headerWidth = itemWidth; } ++index; } - size = QSizeF(width, m_size.height()); + size = QSizeF(headerWidth, m_size.height()); } return QRectF(pos, size); } @@ -403,28 +403,42 @@ void KItemListViewLayouter::doLayout() } } - int rowCount = itemCount / m_columnCount; - if (itemCount % m_columnCount != 0) { - ++rowCount; + m_itemInfos.resize(itemCount); + + // Calculate the offset of each column, i.e., the x-coordinate where the column starts. + m_columnOffsets.resize(m_columnCount); + qreal currentOffset = m_xPosInc; + + if (grouped && horizontalScrolling) { + // All group headers will always be aligned on the top and not + // flipped like the other properties. + currentOffset += m_groupHeaderHeight; } - m_itemInfos.resize(itemCount); + for (int column = 0; column < m_columnCount; ++column) { + m_columnOffsets[column] = currentOffset; + currentOffset += m_columnWidth; + } + + // Prepare the QVector which stores the y-coordinate for each new row. + int numberOfRows = (itemCount + m_columnCount - 1) / m_columnCount; + if (grouped && m_columnCount > 1) { + // In the worst case, a new row will be started for every group. + // We could calculate the exact number of rows now to prevent that we reserve + // too much memory, but the code required to do that might need much more + // memory than it would save in the average case. + numberOfRows += m_groupItemIndexes.count(); + } + m_rowOffsets.resize(numberOfRows); qreal y = m_headerHeight + itemMargin.height(); int row = 0; int index = 0; while (index < itemCount) { - qreal x = m_xPosInc; qreal maxItemHeight = itemSize.height(); if (grouped) { - if (horizontalScrolling) { - // All group headers will always be aligned on the top and not - // flipped like the other properties - x += m_groupHeaderHeight; - } - if (m_groupItemIndexes.contains(index)) { // The item is the first item of a group. // Increase the y-position to provide space @@ -444,19 +458,18 @@ void KItemListViewLayouter::doLayout() } } + m_rowOffsets[row] = y; + int column = 0; while (index < itemCount && column < m_columnCount) { qreal requiredItemHeight = itemSize.height(); - if (m_sizeHintResolver) { - const QSizeF sizeHint = m_sizeHintResolver->sizeHint(index); - const qreal sizeHintHeight = horizontalScrolling ? sizeHint.width() : sizeHint.height(); - if (sizeHintHeight > requiredItemHeight) { - requiredItemHeight = sizeHintHeight; - } + const QSizeF sizeHint = m_sizeHintResolver->sizeHint(index); + const qreal sizeHintHeight = sizeHint.height(); + if (sizeHintHeight > requiredItemHeight) { + requiredItemHeight = sizeHintHeight; } ItemInfo& itemInfo = m_itemInfos[index]; - itemInfo.rect = QRectF(x, y, itemSize.width(), requiredItemHeight); itemInfo.column = column; itemInfo.row = row; @@ -480,7 +493,6 @@ void KItemListViewLayouter::doLayout() } maxItemHeight = qMax(maxItemHeight, requiredItemHeight); - x += m_columnWidth; ++index; ++column; @@ -496,18 +508,7 @@ void KItemListViewLayouter::doLayout() } if (itemCount > 0) { - // Calculate the maximum y-range of the last row for m_maximumScrollOffset - m_maximumScrollOffset = m_itemInfos.last().rect.bottom(); - const qreal rowY = m_itemInfos.last().rect.y(); - - int index = m_itemInfos.count() - 2; - while (index >= 0 && m_itemInfos[index].rect.bottom() >= rowY) { - m_maximumScrollOffset = qMax(m_maximumScrollOffset, m_itemInfos[index].rect.bottom()); - --index; - } - - m_maximumScrollOffset += itemMargin.height(); - + m_maximumScrollOffset = y; m_maximumItemOffset = m_columnCount * m_columnWidth; } else { m_maximumScrollOffset = 0; @@ -515,7 +516,7 @@ void KItemListViewLayouter::doLayout() } #ifdef KITEMLISTVIEWLAYOUTER_DEBUG - kDebug() << "[TIME] doLayout() for " << m_model->count() << "items:" << timer.elapsed(); + qCDebug(DolphinDebug) << "[TIME] doLayout() for " << m_model->count() << "items:" << timer.elapsed(); #endif m_dirty = false; } @@ -546,7 +547,7 @@ void KItemListViewLayouter::updateVisibleIndexes() int mid = 0; do { mid = (min + max) / 2; - if (m_itemInfos[mid].rect.top() < m_scrollOffset) { + if (m_rowOffsets.at(m_itemInfos[mid].row) < m_scrollOffset) { min = mid + 1; } else { max = mid - 1; @@ -556,13 +557,13 @@ void KItemListViewLayouter::updateVisibleIndexes() if (mid > 0) { // Include the row before the first fully visible index, as it might // be partly visible - if (m_itemInfos[mid].rect.top() >= m_scrollOffset) { + if (m_rowOffsets.at(m_itemInfos[mid].row) >= m_scrollOffset) { --mid; - Q_ASSERT(m_itemInfos[mid].rect.top() < m_scrollOffset); + Q_ASSERT(m_rowOffsets.at(m_itemInfos[mid].row) < m_scrollOffset); } - const qreal rowTop = m_itemInfos[mid].rect.top(); - while (mid > 0 && m_itemInfos[mid - 1].rect.top() == rowTop) { + const int firstVisibleRow = m_itemInfos[mid].row; + while (mid > 0 && m_itemInfos[mid - 1].row == firstVisibleRow) { --mid; } } @@ -579,14 +580,14 @@ void KItemListViewLayouter::updateVisibleIndexes() max = maxIndex; do { mid = (min + max) / 2; - if (m_itemInfos[mid].rect.y() <= bottom) { + if (m_rowOffsets.at(m_itemInfos[mid].row) <= bottom) { min = mid + 1; } else { max = mid - 1; } } while (min <= max); - while (mid > 0 && m_itemInfos[mid].rect.y() > bottom) { + while (mid > 0 && m_rowOffsets.at(m_itemInfos[mid].row) > bottom) { --mid; } m_lastVisibleIndex = mid; @@ -620,4 +621,3 @@ qreal KItemListViewLayouter::minimumGroupHeaderWidth() const return 100; } -#include "kitemlistviewlayouter.moc"