mirror of
https://invent.kde.org/system/dolphin
synced 2024-09-12 12:54:29 +00:00
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
This commit is contained in:
parent
ace34ac134
commit
3ff6e83491
|
@ -460,9 +460,9 @@ int KItemListView::lastVisibleIndex() const
|
|||
return m_layouter->lastVisibleIndex();
|
||||
}
|
||||
|
||||
QSizeF KItemListView::itemSizeHint(int index) const
|
||||
void KItemListView::calculateItemSizeHints(QVector<QSizeF>& sizeHints) const
|
||||
{
|
||||
return widgetCreator()->itemSizeHint(index, this);
|
||||
widgetCreator()->calculateItemSizeHints(sizeHints, this);
|
||||
}
|
||||
|
||||
void KItemListView::setSupportsItemExpanding(bool supportsExpanding)
|
||||
|
|
|
@ -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<QSizeF>& 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<QSizeF>& 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<QSizeF>& sizeHints, const KItemListView* view) const;
|
||||
|
||||
virtual qreal preferredRoleColumnWidth(const QByteArray& role,
|
||||
int index,
|
||||
|
@ -854,9 +854,9 @@ KItemListWidget* KItemListWidgetCreator<T>::create(KItemListView* view)
|
|||
}
|
||||
|
||||
template<class T>
|
||||
QSizeF KItemListWidgetCreator<T>::itemSizeHint(int index, const KItemListView* view) const
|
||||
void KItemListWidgetCreator<T>::calculateItemSizeHints(QVector<QSizeF>& sizeHints, const KItemListView* view) const
|
||||
{
|
||||
return m_informant->itemSizeHint(index, view);
|
||||
return m_informant->calculateItemSizeHints(sizeHints, view);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
|
|
|
@ -49,7 +49,7 @@ public:
|
|||
KItemListWidgetInformant();
|
||||
virtual ~KItemListWidgetInformant();
|
||||
|
||||
virtual QSizeF itemSizeHint(int index, const KItemListView* view) const = 0;
|
||||
virtual void calculateItemSizeHints(QVector<QSizeF>& sizeHints, const KItemListView* view) const = 0;
|
||||
|
||||
virtual qreal preferredRoleColumnWidth(const QByteArray& role,
|
||||
int index,
|
||||
|
|
|
@ -55,84 +55,25 @@ KStandardItemListWidgetInformant::~KStandardItemListWidgetInformant()
|
|||
{
|
||||
}
|
||||
|
||||
QSizeF KStandardItemListWidgetInformant::itemSizeHint(int index, const KItemListView* view) const
|
||||
void KStandardItemListWidgetInformant::calculateItemSizeHints(QVector<QSizeF>& sizeHints, const KItemListView* view) const
|
||||
{
|
||||
const KItemListStyleOption& option = view->styleOption();
|
||||
const int additionalRolesCount = qMax(view->visibleRoles().count() - 1, 0);
|
||||
|
||||
switch (static_cast<const KStandardItemListView*>(view)->itemLayout()) {
|
||||
case KStandardItemListWidget::IconsLayout: {
|
||||
const QString text = KStringHandler::preProcessWrap(itemText(index, view));
|
||||
case KStandardItemListWidget::IconsLayout:
|
||||
calculateIconsLayoutItemSizeHints(sizeHints, view);
|
||||
break;
|
||||
|
||||
const qreal itemWidth = view->itemSize().width();
|
||||
const qreal maxWidth = itemWidth - 2 * option.padding;
|
||||
QTextLine line;
|
||||
case KStandardItemListWidget::CompactLayout:
|
||||
calculateCompactLayoutItemSizeHints(sizeHints, view);
|
||||
break;
|
||||
|
||||
// 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<QByteArray>& visibleRoles = view->visibleRoles();
|
||||
const bool showOnlyTextRole = (visibleRoles.count() == 1) && (visibleRoles.first() == "text");
|
||||
|
||||
if (showOnlyTextRole) {
|
||||
maximumRequiredWidth = option.fontMetrics.width(itemText(index, view));
|
||||
} else {
|
||||
const QHash<QByteArray, QVariant> 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);
|
||||
}
|
||||
}
|
||||
|
||||
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::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<QSizeF>& 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<QSizeF>& 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<QByteArray>& 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<QByteArray, QVariant>& 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<QSizeF>& 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),
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
KStandardItemListWidgetInformant();
|
||||
virtual ~KStandardItemListWidgetInformant();
|
||||
|
||||
virtual QSizeF itemSizeHint(int index, const KItemListView* view) const;
|
||||
virtual void calculateItemSizeHints(QVector<QSizeF>& 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<QByteArray, QVariant>& values) const;
|
||||
|
||||
void calculateIconsLayoutItemSizeHints(QVector<QSizeF>& sizeHints, const KItemListView* view) const;
|
||||
void calculateCompactLayoutItemSizeHints(QVector<QSizeF>& sizeHints, const KItemListView* view) const;
|
||||
void calculateDetailsLayoutItemSizeHints(QVector<QSizeF>& sizeHints, const KItemListView* view) const;
|
||||
|
||||
friend class KStandardItemListWidget; // Accesses roleText()
|
||||
};
|
||||
|
||||
|
|
|
@ -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 QSet<QB
|
|||
++index;
|
||||
--count;
|
||||
}
|
||||
|
||||
m_needsResolving = true;
|
||||
}
|
||||
|
||||
void KItemListSizeHintResolver::clearCache()
|
||||
{
|
||||
m_sizeHintCache.fill(QSizeF());
|
||||
m_needsResolving = true;
|
||||
}
|
||||
|
||||
void KItemListSizeHintResolver::updateCache()
|
||||
{
|
||||
if (m_needsResolving) {
|
||||
m_itemListView->calculateItemSizeHints(m_sizeHintCache);
|
||||
m_needsResolving = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<QByteArray>& roles);
|
||||
|
||||
void clearCache();
|
||||
void updateCache();
|
||||
|
||||
private:
|
||||
const KItemListView* m_itemListView;
|
||||
mutable QVector<QSizeF> m_sizeHintCache;
|
||||
bool m_needsResolving;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue