From: Emmanuel Pescosta Date: Sun, 12 Jan 2014 22:24:00 +0000 (+0100) Subject: Calculate all item size hints at once. X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/commitdiff_plain/3ff6e83491e2da9678af0bc149e450ff87db5e8d Calculate all item size hints at once. The speed up is really small, but theses changes are mostly straightforward and make the code a bit nicer - break the KStandardItemListWidgetInformant::itemSizeHint beast into three smaller functions. FIXED-IN: 4.13 REVIEW: 112979 --- diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index 7f497210c..38ce63af0 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -460,9 +460,9 @@ int KItemListView::lastVisibleIndex() const return m_layouter->lastVisibleIndex(); } -QSizeF KItemListView::itemSizeHint(int index) const +void KItemListView::calculateItemSizeHints(QVector& sizeHints) const { - return widgetCreator()->itemSizeHint(index, this); + widgetCreator()->calculateItemSizeHints(sizeHints, this); } void KItemListView::setSupportsItemExpanding(bool supportsExpanding) diff --git a/src/kitemviews/kitemlistview.h b/src/kitemviews/kitemlistview.h index dbe923086..f39e73a97 100644 --- a/src/kitemviews/kitemlistview.h +++ b/src/kitemviews/kitemlistview.h @@ -194,12 +194,12 @@ public: int lastVisibleIndex() const; /** - * @return Required size for the item with the index \p index. + * @return Required size for all items in the model. * The returned value might be larger than KItemListView::itemSize(). * In this case the layout grid will be stretched to assure an * unclipped item. */ - QSizeF itemSizeHint(int index) const; + void calculateItemSizeHints(QVector& sizeHints) const; /** * If set to true, items having child-items can be expanded to show the child-items as @@ -802,7 +802,7 @@ public: virtual void recycle(KItemListWidget* widget); - virtual QSizeF itemSizeHint(int index, const KItemListView* view) const = 0; + virtual void calculateItemSizeHints(QVector& sizeHints, const KItemListView* view) const = 0; virtual qreal preferredRoleColumnWidth(const QByteArray& role, int index, @@ -821,7 +821,7 @@ public: virtual KItemListWidget* create(KItemListView* view); - virtual QSizeF itemSizeHint(int index, const KItemListView* view) const; + virtual void calculateItemSizeHints(QVector& sizeHints, const KItemListView* view) const; virtual qreal preferredRoleColumnWidth(const QByteArray& role, int index, @@ -854,9 +854,9 @@ KItemListWidget* KItemListWidgetCreator::create(KItemListView* view) } template -QSizeF KItemListWidgetCreator::itemSizeHint(int index, const KItemListView* view) const +void KItemListWidgetCreator::calculateItemSizeHints(QVector& sizeHints, const KItemListView* view) const { - return m_informant->itemSizeHint(index, view); + return m_informant->calculateItemSizeHints(sizeHints, view); } template diff --git a/src/kitemviews/kitemlistwidget.h b/src/kitemviews/kitemlistwidget.h index 55181faa8..954629ddd 100644 --- a/src/kitemviews/kitemlistwidget.h +++ b/src/kitemviews/kitemlistwidget.h @@ -49,7 +49,7 @@ public: KItemListWidgetInformant(); virtual ~KItemListWidgetInformant(); - virtual QSizeF itemSizeHint(int index, const KItemListView* view) const = 0; + virtual void calculateItemSizeHints(QVector& sizeHints, const KItemListView* view) const = 0; virtual qreal preferredRoleColumnWidth(const QByteArray& role, int index, diff --git a/src/kitemviews/kstandarditemlistwidget.cpp b/src/kitemviews/kstandarditemlistwidget.cpp index acdf839ac..9a9a734ed 100644 --- a/src/kitemviews/kstandarditemlistwidget.cpp +++ b/src/kitemviews/kstandarditemlistwidget.cpp @@ -55,84 +55,25 @@ KStandardItemListWidgetInformant::~KStandardItemListWidgetInformant() { } -QSizeF KStandardItemListWidgetInformant::itemSizeHint(int index, const KItemListView* view) const +void KStandardItemListWidgetInformant::calculateItemSizeHints(QVector& sizeHints, const KItemListView* view) const { - const KItemListStyleOption& option = view->styleOption(); - const int additionalRolesCount = qMax(view->visibleRoles().count() - 1, 0); - switch (static_cast(view)->itemLayout()) { - case KStandardItemListWidget::IconsLayout: { - const QString text = KStringHandler::preProcessWrap(itemText(index, view)); - - const qreal itemWidth = view->itemSize().width(); - const qreal maxWidth = itemWidth - 2 * option.padding; - QTextLine line; - - // Calculate the number of lines required for wrapping the name - QTextOption textOption(Qt::AlignHCenter); - textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); - - qreal textHeight = 0; - QTextLayout layout(text, option.font); - layout.setTextOption(textOption); - layout.beginLayout(); - while ((line = layout.createLine()).isValid()) { - line.setLineWidth(maxWidth); - line.naturalTextWidth(); - textHeight += line.height(); - } - layout.endLayout(); - - // Add one line for each additional information - textHeight += additionalRolesCount * option.fontMetrics.lineSpacing(); - - const qreal maxTextHeight = option.maxTextSize.height(); - if (maxTextHeight > 0 && textHeight > maxTextHeight) { - textHeight = maxTextHeight; - } - - return QSizeF(itemWidth, textHeight + option.iconSize + option.padding * 3); - } - - case KStandardItemListWidget::CompactLayout: { - // For each row exactly one role is shown. Calculate the maximum required width that is necessary - // to show all roles without horizontal clipping. - qreal maximumRequiredWidth = 0.0; - - const QList& visibleRoles = view->visibleRoles(); - const bool showOnlyTextRole = (visibleRoles.count() == 1) && (visibleRoles.first() == "text"); - - if (showOnlyTextRole) { - maximumRequiredWidth = option.fontMetrics.width(itemText(index, view)); - } else { - const QHash values = view->model()->data(index); - foreach (const QByteArray& role, view->visibleRoles()) { - const QString text = roleText(role, values); - const qreal requiredWidth = option.fontMetrics.width(text); - maximumRequiredWidth = qMax(maximumRequiredWidth, requiredWidth); - } - } + case KStandardItemListWidget::IconsLayout: + calculateIconsLayoutItemSizeHints(sizeHints, view); + break; - qreal width = option.padding * 4 + option.iconSize + maximumRequiredWidth; - const qreal maxWidth = option.maxTextSize.width(); - if (maxWidth > 0 && width > maxWidth) { - width = maxWidth; - } - const qreal height = option.padding * 2 + qMax(option.iconSize, (1 + additionalRolesCount) * option.fontMetrics.lineSpacing()); - return QSizeF(width, height); - } + case KStandardItemListWidget::CompactLayout: + calculateCompactLayoutItemSizeHints(sizeHints, view); + break; - case KStandardItemListWidget::DetailsLayout: { - const qreal height = option.padding * 2 + qMax(option.iconSize, option.fontMetrics.height()); - return QSizeF(-1, height); - } + case KStandardItemListWidget::DetailsLayout: + calculateDetailsLayoutItemSizeHints(sizeHints, view); + break; default: Q_ASSERT(false); break; } - - return QSize(); } qreal KStandardItemListWidgetInformant::preferredRoleColumnWidth(const QByteArray& role, @@ -181,6 +122,107 @@ QString KStandardItemListWidgetInformant::roleText(const QByteArray& role, return values.value(role).toString(); } +void KStandardItemListWidgetInformant::calculateIconsLayoutItemSizeHints(QVector& sizeHints, const KItemListView* view) const +{ + const KItemListStyleOption& option = view->styleOption(); + const QFont& font = option.font; + const int additionalRolesCount = qMax(view->visibleRoles().count() - 1, 0); + + const qreal itemWidth = view->itemSize().width(); + const qreal maxWidth = itemWidth - 2 * option.padding; + const qreal maxTextHeight = option.maxTextSize.height(); + const qreal additionalRolesSpacing = additionalRolesCount * option.fontMetrics.lineSpacing(); + const qreal spacingAndIconHeight = option.iconSize + option.padding * 3; + + QTextOption textOption(Qt::AlignHCenter); + textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + + for (int index = 0; index < sizeHints.count(); ++index) { + if (!sizeHints.at(index).isEmpty()) { + continue; + } + + const QString& text = KStringHandler::preProcessWrap(itemText(index, view)); + + // Calculate the number of lines required for wrapping the name + qreal textHeight = 0; + QTextLayout layout(text, font); + layout.setTextOption(textOption); + layout.beginLayout(); + QTextLine line; + while ((line = layout.createLine()).isValid()) { + line.setLineWidth(maxWidth); + line.naturalTextWidth(); + textHeight += line.height(); + } + layout.endLayout(); + + // Add one line for each additional information + textHeight += additionalRolesSpacing; + + if (maxTextHeight > 0 && textHeight > maxTextHeight) { + textHeight = maxTextHeight; + } + + sizeHints[index] = QSizeF(itemWidth, textHeight + spacingAndIconHeight); + } +} + +void KStandardItemListWidgetInformant::calculateCompactLayoutItemSizeHints(QVector& sizeHints, const KItemListView* view) const +{ + const KItemListStyleOption& option = view->styleOption(); + const QFontMetrics& fontMetrics = option.fontMetrics; + const int additionalRolesCount = qMax(view->visibleRoles().count() - 1, 0); + + const QList& visibleRoles = view->visibleRoles(); + const bool showOnlyTextRole = (visibleRoles.count() == 1) && (visibleRoles.first() == "text"); + const qreal maxWidth = option.maxTextSize.width(); + const qreal paddingAndIconWidth = option.padding * 4 + option.iconSize; + const qreal height = option.padding * 2 + qMax(option.iconSize, (1 + additionalRolesCount) * option.fontMetrics.lineSpacing()); + + for (int index = 0; index < sizeHints.count(); ++index) { + if (!sizeHints.at(index).isEmpty()) { + continue; + } + + // For each row exactly one role is shown. Calculate the maximum required width that is necessary + // to show all roles without horizontal clipping. + qreal maximumRequiredWidth = 0.0; + + if (showOnlyTextRole) { + maximumRequiredWidth = fontMetrics.width(itemText(index, view)); + } else { + const QHash& values = view->model()->data(index); + foreach (const QByteArray& role, visibleRoles) { + const QString& text = roleText(role, values); + const qreal requiredWidth = fontMetrics.width(text); + maximumRequiredWidth = qMax(maximumRequiredWidth, requiredWidth); + } + } + + qreal width = paddingAndIconWidth + maximumRequiredWidth; + if (maxWidth > 0 && width > maxWidth) { + width = maxWidth; + } + + sizeHints[index] = QSizeF(width, height); + } +} + +void KStandardItemListWidgetInformant::calculateDetailsLayoutItemSizeHints(QVector& sizeHints, const KItemListView* view) const +{ + const KItemListStyleOption& option = view->styleOption(); + const qreal height = option.padding * 2 + qMax(option.iconSize, option.fontMetrics.height()); + + for (int index = 0; index < sizeHints.count(); ++index) { + if (!sizeHints.at(index).isEmpty()) { + continue; + } + + sizeHints[index] = QSizeF(-1, height); + } +} + KStandardItemListWidget::KStandardItemListWidget(KItemListWidgetInformant* informant, QGraphicsItem* parent) : KItemListWidget(informant, parent), m_isCut(false), diff --git a/src/kitemviews/kstandarditemlistwidget.h b/src/kitemviews/kstandarditemlistwidget.h index 7dd93b2b8..ca198c36b 100644 --- a/src/kitemviews/kstandarditemlistwidget.h +++ b/src/kitemviews/kstandarditemlistwidget.h @@ -38,7 +38,7 @@ public: KStandardItemListWidgetInformant(); virtual ~KStandardItemListWidgetInformant(); - virtual QSizeF itemSizeHint(int index, const KItemListView* view) const; + virtual void calculateItemSizeHints(QVector& sizeHints, const KItemListView* view) const; virtual qreal preferredRoleColumnWidth(const QByteArray& role, int index, @@ -61,6 +61,10 @@ protected: virtual QString roleText(const QByteArray& role, const QHash& values) const; + void calculateIconsLayoutItemSizeHints(QVector& sizeHints, const KItemListView* view) const; + void calculateCompactLayoutItemSizeHints(QVector& sizeHints, const KItemListView* view) const; + void calculateDetailsLayoutItemSizeHints(QVector& sizeHints, const KItemListView* view) const; + friend class KStandardItemListWidget; // Accesses roleText() }; diff --git a/src/kitemviews/private/kitemlistsizehintresolver.cpp b/src/kitemviews/private/kitemlistsizehintresolver.cpp index 0e2286b45..029beddf9 100644 --- a/src/kitemviews/private/kitemlistsizehintresolver.cpp +++ b/src/kitemviews/private/kitemlistsizehintresolver.cpp @@ -23,7 +23,8 @@ KItemListSizeHintResolver::KItemListSizeHintResolver(const KItemListView* itemListView) : m_itemListView(itemListView), - m_sizeHintCache() + m_sizeHintCache(), + m_needsResolving(false) { } @@ -31,14 +32,10 @@ KItemListSizeHintResolver::~KItemListSizeHintResolver() { } -QSizeF KItemListSizeHintResolver::sizeHint(int index) const +QSizeF KItemListSizeHintResolver::sizeHint(int index) { - QSizeF size = m_sizeHintCache.at(index); - if (size.isEmpty()) { - size = m_itemListView->itemSizeHint(index); - m_sizeHintCache[index] = size; - } - return size; + updateCache(); + return m_sizeHintCache.at(index); } void KItemListSizeHintResolver::itemsInserted(const KItemRangeList& itemRanges) @@ -77,6 +74,8 @@ void KItemListSizeHintResolver::itemsInserted(const KItemRangeList& itemRanges) } } + m_needsResolving = true; + Q_ASSERT(m_sizeHintCache.count() == m_itemListView->model()->count()); } @@ -135,9 +134,20 @@ void KItemListSizeHintResolver::itemsChanged(int index, int count, const QSetcalculateItemSizeHints(m_sizeHintCache); + m_needsResolving = false; + } } diff --git a/src/kitemviews/private/kitemlistsizehintresolver.h b/src/kitemviews/private/kitemlistsizehintresolver.h index 486f9b631..86580bf7b 100644 --- a/src/kitemviews/private/kitemlistsizehintresolver.h +++ b/src/kitemviews/private/kitemlistsizehintresolver.h @@ -36,7 +36,7 @@ class LIBDOLPHINPRIVATE_EXPORT KItemListSizeHintResolver public: KItemListSizeHintResolver(const KItemListView* itemListView); virtual ~KItemListSizeHintResolver(); - QSizeF sizeHint(int index) const; + QSizeF sizeHint(int index); void itemsInserted(const KItemRangeList& itemRanges); void itemsRemoved(const KItemRangeList& itemRanges); @@ -44,10 +44,12 @@ public: void itemsChanged(int index, int count, const QSet& roles); void clearCache(); + void updateCache(); private: const KItemListView* m_itemListView; mutable QVector m_sizeHintCache; + bool m_needsResolving; }; #endif diff --git a/src/kitemviews/private/kitemlistviewlayouter.cpp b/src/kitemviews/private/kitemlistviewlayouter.cpp index 90e8a6d0f..73f3d6182 100644 --- a/src/kitemviews/private/kitemlistviewlayouter.cpp +++ b/src/kitemviews/private/kitemlistviewlayouter.cpp @@ -209,7 +209,7 @@ const KItemModelBase* KItemListViewLayouter::model() const return m_model; } -void KItemListViewLayouter::setSizeHintResolver(const KItemListSizeHintResolver* sizeHintResolver) +void KItemListViewLayouter::setSizeHintResolver(KItemListSizeHintResolver* sizeHintResolver) { if (m_sizeHintResolver != sizeHintResolver) { m_sizeHintResolver = sizeHintResolver; diff --git a/src/kitemviews/private/kitemlistviewlayouter.h b/src/kitemviews/private/kitemlistviewlayouter.h index 19b14796d..5ae472411 100644 --- a/src/kitemviews/private/kitemlistviewlayouter.h +++ b/src/kitemviews/private/kitemlistviewlayouter.h @@ -103,7 +103,7 @@ public: void setModel(const KItemModelBase* model); const KItemModelBase* model() const; - void setSizeHintResolver(const KItemListSizeHintResolver* sizeHintResolver); + void setSizeHintResolver(KItemListSizeHintResolver* sizeHintResolver); const KItemListSizeHintResolver* sizeHintResolver() const; /** @@ -205,7 +205,7 @@ private: QSizeF m_itemMargin; qreal m_headerHeight; const KItemModelBase* m_model; - const KItemListSizeHintResolver* m_sizeHintResolver; + KItemListSizeHintResolver* m_sizeHintResolver; qreal m_scrollOffset; qreal m_maximumScrollOffset;