]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/kitemviews/kstandarditemlistwidget.cpp
Try to avoid calling the model's data method if only "text" is needed
[dolphin.git] / src / kitemviews / kstandarditemlistwidget.cpp
index 0cd11d3637199993b711ac562ce26f9d7b8db8d9..4b9f33b6f07161f84d811040626f08ff8be935f4 100644 (file)
@@ -42,6 +42,7 @@
 #include <QStyleOption>
 #include <QTextLayout>
 #include <QTextLine>
+#include <QPixmapCache>
 
 // #define KSTANDARDITEMLISTWIDGET_DEBUG
 
@@ -56,13 +57,12 @@ KStandardItemListWidgetInformant::~KStandardItemListWidgetInformant()
 
 QSizeF KStandardItemListWidgetInformant::itemSizeHint(int index, const KItemListView* view) const
 {
-    const QHash<QByteArray, QVariant> values = view->model()->data(index);
     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(values["text"].toString());
+        const QString text = KStringHandler::preProcessWrap(itemText(index, view));
 
         const qreal itemWidth = view->itemSize().width();
         const qreal maxWidth = itemWidth - 2 * option.padding;
@@ -99,6 +99,7 @@ QSizeF KStandardItemListWidgetInformant::itemSizeHint(int index, const KItemList
         // to show all roles without horizontal clipping.
         qreal maximumRequiredWidth = 0.0;
 
+        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);
@@ -158,6 +159,11 @@ qreal KStandardItemListWidgetInformant::preferredRoleColumnWidth(const QByteArra
     return width;
 }
 
+QString KStandardItemListWidgetInformant::itemText(int index, const KItemListView* view) const
+{
+    return view->model()->data(index).value("text").toString();
+}
+
 QString KStandardItemListWidgetInformant::roleText(const QByteArray& role,
                                                    const QHash<QByteArray, QVariant>& values) const
 {
@@ -172,6 +178,8 @@ KStandardItemListWidget::KStandardItemListWidget(KItemListWidgetInformant* infor
     KItemListWidget(informant, parent),
     m_isCut(false),
     m_isHidden(false),
+    m_customizedFont(),
+    m_customizedFontMetrics(m_customizedFont),
     m_isExpandable(false),
     m_supportsItemExpanding(false),
     m_dirtyLayout(true),
@@ -191,7 +199,8 @@ KStandardItemListWidget::KStandardItemListWidget(KItemListWidgetInformant* infor
     m_additionalInfoTextColor(),
     m_overlay(),
     m_rating(),
-    m_roleEditor(0)
+    m_roleEditor(0),
+    m_oldRoleEditor(0)
 {
 }
 
@@ -200,7 +209,13 @@ KStandardItemListWidget::~KStandardItemListWidget()
     qDeleteAll(m_textInfo);
     m_textInfo.clear();
 
-    delete m_roleEditor;
+    if (m_roleEditor) {
+        m_roleEditor->deleteLater();
+    }
+
+    if (m_oldRoleEditor) {
+        m_oldRoleEditor->deleteLater();
+    }
 }
 
 void KStandardItemListWidget::setLayout(Layout layout)
@@ -244,23 +259,63 @@ void KStandardItemListWidget::paint(QPainter* painter, const QStyleOptionGraphic
 
     const KItemListStyleOption& itemListStyleOption = styleOption();
     if (isHovered()) {
-        // Blend the unhovered and hovered pixmap if the hovering
-        // animation is ongoing
         if (hoverOpacity() < 1.0) {
-            drawPixmap(painter, m_pixmap);
-        }
+            /*
+             * Linear interpolation between m_pixmap and m_hoverPixmap.
+             *
+             * Note that this cannot be achieved by painting m_hoverPixmap over
+             * m_pixmap, even if the opacities are adjusted. For details see
+             * https://git.reviewboard.kde.org/r/109614/
+             */
+            // Paint pixmap1 so that pixmap1 = m_pixmap * (1.0 - hoverOpacity())
+            QPixmap pixmap1(m_pixmap.size());
+            pixmap1.fill(Qt::transparent);
+            {
+                QPainter p(&pixmap1);
+                p.setOpacity(1.0 - hoverOpacity());
+                p.drawPixmap(0, 0, m_pixmap);
+            }
+
+            // Paint pixmap2 so that pixmap2 = m_hoverPixmap * hoverOpacity()
+            QPixmap pixmap2(pixmap1.size());
+            pixmap2.fill(Qt::transparent);
+            {
+                QPainter p(&pixmap2);
+                p.setOpacity(hoverOpacity());
+                p.drawPixmap(0, 0, m_hoverPixmap);
+            }
+
+            // Paint pixmap2 on pixmap1 using CompositionMode_Plus
+            // Now pixmap1 = pixmap2 + m_pixmap * (1.0 - hoverOpacity())
+            //             = m_hoverPixmap * hoverOpacity() + m_pixmap * (1.0 - hoverOpacity())
+            {
+                QPainter p(&pixmap1);
+                p.setCompositionMode(QPainter::CompositionMode_Plus);
+                p.drawPixmap(0, 0, pixmap2);
+            }
 
-        const qreal opacity = painter->opacity();
-        painter->setOpacity(hoverOpacity() * opacity);
-        drawPixmap(painter, m_hoverPixmap);
-        painter->setOpacity(opacity);
+            // Finally paint pixmap1 on the widget
+            drawPixmap(painter, pixmap1);
+        } else {
+            drawPixmap(painter, m_hoverPixmap);
+        }
     } else {
         drawPixmap(painter, m_pixmap);
     }
 
-    painter->setFont(itemListStyleOption.font);
-    painter->setPen(m_isHidden ? m_additionalInfoTextColor : textColor());
+    painter->setFont(m_customizedFont);
+    painter->setPen(textColor());
     const TextInfo* textInfo = m_textInfo.value("text");
+
+    if (!textInfo) {
+        // It seems that we can end up here even if m_textInfo does not contain
+        // the key "text", see bug 306167. According to triggerCacheRefreshing(),
+        // this can only happen if the index is negative. This can happen when
+        // the item is about to be removed, see KItemListView::slotItemsRemoved().
+        // TODO: try to reproduce the crash and find a better fix.
+        return;
+    }
+
     painter->drawStaticText(textInfo->pos, textInfo->staticText);
 
     bool clipAdditionalInfoBounds = false;
@@ -277,7 +332,7 @@ void KStandardItemListWidget::paint(QPainter* painter, const QStyleOptionGraphic
     }
 
     painter->setPen(m_additionalInfoTextColor);
-    painter->setFont(itemListStyleOption.font);
+    painter->setFont(m_customizedFont);
 
     for (int i = 1; i < m_sortedVisibleRoles.count(); ++i) {
         const TextInfo* textInfo = m_textInfo.value(m_sortedVisibleRoles[i]);
@@ -289,7 +344,7 @@ void KStandardItemListWidget::paint(QPainter* painter, const QStyleOptionGraphic
         QPointF pos = ratingTextInfo->pos;
         const Qt::Alignment align = ratingTextInfo->staticText.textOption().alignment();
         if (align & Qt::AlignHCenter) {
-            pos.rx() += (size().width() - m_rating.width()) / 2;
+            pos.rx() += (size().width() - m_rating.width()) / 2 - 2;
         }
         painter->drawPixmap(pos, m_rating);
     }
@@ -303,8 +358,11 @@ void KStandardItemListWidget::paint(QPainter* painter, const QStyleOptionGraphic
     painter->setPen(Qt::green);
     painter->drawRect(m_iconRect);
 
+    painter->setPen(Qt::blue);
+    painter->drawRect(m_textRect);
+
     painter->setPen(Qt::red);
-    painter->drawText(QPointF(0, itemListStyleOption.fontMetrics.height()), QString::number(index()));
+    painter->drawText(QPointF(0, m_customizedFontMetrics.height()), QString::number(index()));
     painter->drawRect(rect());
 #endif
 }
@@ -349,7 +407,7 @@ QRectF KStandardItemListWidget::textFocusRect() const
         const KItemListStyleOption& option = styleOption();
         if (option.extendedSelectionRegion) {
             const QString text = textInfo->staticText.text();
-            rect.setWidth(option.fontMetrics.width(text) + 2 * option.padding);
+            rect.setWidth(m_customizedFontMetrics.width(text) + 2 * option.padding);
         }
 
         return rect;
@@ -409,7 +467,7 @@ QPixmap KStandardItemListWidget::createDragPixmap(const QStyleOptionGraphicsItem
                                                   QWidget* widget)
 {
     QPixmap pixmap = KItemListWidget::createDragPixmap(option, widget);
-    if (m_layout != DetailsLayout || styleOption().extendedSelectionRegion) {
+    if (m_layout != DetailsLayout) {
         return pixmap;
     }
 
@@ -457,6 +515,16 @@ bool KStandardItemListWidget::isHidden() const
     return false;
 }
 
+QFont KStandardItemListWidget::customizedFont(const QFont& baseFont) const
+{
+    return baseFont;
+}
+
+QPalette::ColorRole KStandardItemListWidget::normalTextColorRole() const
+{
+    return QPalette::Text;
+}
+
 void KStandardItemListWidget::setTextColor(const QColor& color)
 {
     if (color != m_customTextColor) {
@@ -468,13 +536,17 @@ void KStandardItemListWidget::setTextColor(const QColor& color)
 
 QColor KStandardItemListWidget::textColor() const
 {
-    if (m_customTextColor.isValid() && !isSelected()) {
-        return m_customTextColor;
+    if (!isSelected()) {
+        if (m_isHidden) {
+            return m_additionalInfoTextColor;
+        } else if (m_customTextColor.isValid()) {
+            return m_customTextColor;
+        }
     }
 
     const QPalette::ColorGroup group = isActiveWindow() ? QPalette::Active : QPalette::Inactive;
-    const QPalette::ColorRole role = isSelected() ? QPalette::HighlightedText : QPalette::Text;
-    return styleOption().palette.brush(group, role).color();
+    const QPalette::ColorRole role = isSelected() ? QPalette::HighlightedText : normalTextColorRole();
+    return styleOption().palette.color(group, role);
 }
 
 void KStandardItemListWidget::setOverlay(const QPixmap& overlay)
@@ -559,6 +631,7 @@ void KStandardItemListWidget::selectedChanged(bool selected)
 {
     Q_UNUSED(selected);
     updateAdditionalInfoTextColor();
+    m_dirtyContent = true;
 }
 
 void KStandardItemListWidget::siblingsInformationChanged(const QBitArray& current, const QBitArray& previous)
@@ -568,15 +641,30 @@ void KStandardItemListWidget::siblingsInformationChanged(const QBitArray& curren
     m_dirtyLayout = true;
 }
 
+int KStandardItemListWidget::selectionLength(const QString& text) const
+{
+    return text.length();
+}
+
 void KStandardItemListWidget::editedRoleChanged(const QByteArray& current, const QByteArray& previous)
 {
     Q_UNUSED(previous);
 
-   QGraphicsView* parent = scene()->views()[0];
-   if (current.isEmpty() || !parent || current != "text") {
+    QGraphicsView* parent = scene()->views()[0];
+    if (current.isEmpty() || !parent || current != "text") {
         if (m_roleEditor) {
             emit roleEditingCanceled(index(), current, data().value(current));
-            m_roleEditor->deleteLater();
+
+            disconnect(m_roleEditor, SIGNAL(roleEditingCanceled(QByteArray,QVariant)),
+                       this, SLOT(slotRoleEditingCanceled(QByteArray,QVariant)));
+            disconnect(m_roleEditor, SIGNAL(roleEditingFinished(QByteArray,QVariant)),
+                       this, SLOT(slotRoleEditingFinished(QByteArray,QVariant)));
+
+            if (m_oldRoleEditor) {
+                m_oldRoleEditor->deleteLater();
+            }
+            m_oldRoleEditor = m_roleEditor;
+            m_roleEditor->hide();
             m_roleEditor = 0;
         }
         return;
@@ -587,8 +675,8 @@ void KStandardItemListWidget::editedRoleChanged(const QByteArray& current, const
     const TextInfo* textInfo = m_textInfo.value("text");
 
     m_roleEditor = new KItemListRoleEditor(parent);
-    m_roleEditor->setIndex(index());
     m_roleEditor->setRole(current);
+    m_roleEditor->setFont(styleOption().font);
 
     const QString text = data().value(current).toString();
     m_roleEditor->setPlainText(text);
@@ -596,25 +684,19 @@ void KStandardItemListWidget::editedRoleChanged(const QByteArray& current, const
     QTextOption textOption = textInfo->staticText.textOption();
     m_roleEditor->document()->setDefaultTextOption(textOption);
 
-    // Select the text without MIME-type extension
-    int selectionLength = text.length();
-
-    const QString extension = KMimeType::extractKnownExtension(text);
-    if (!extension.isEmpty()) {
-        selectionLength -= extension.length() + 1;
-    }
+    const int textSelectionLength = selectionLength(text);
 
-    if (selectionLength > 0) {
+    if (textSelectionLength > 0) {
         QTextCursor cursor = m_roleEditor->textCursor();
         cursor.movePosition(QTextCursor::StartOfBlock);
-        cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, selectionLength);
+        cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, textSelectionLength);
         m_roleEditor->setTextCursor(cursor);
     }
 
-    connect(m_roleEditor, SIGNAL(roleEditingCanceled(int,QByteArray,QVariant)),
-            this, SLOT(slotRoleEditingCanceled(int,QByteArray,QVariant)));
-    connect(m_roleEditor, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)),
-            this, SLOT(slotRoleEditingFinished(int,QByteArray,QVariant)));
+    connect(m_roleEditor, SIGNAL(roleEditingCanceled(QByteArray,QVariant)),
+            this, SLOT(slotRoleEditingCanceled(QByteArray,QVariant)));
+    connect(m_roleEditor, SIGNAL(roleEditingFinished(QByteArray,QVariant)),
+            this, SLOT(slotRoleEditingFinished(QByteArray,QVariant)));
 
     // Adjust the geometry of the editor
     QRectF rect = roleEditingRect(current);
@@ -675,23 +757,19 @@ void KStandardItemListWidget::slotCutItemsChanged()
     }
 }
 
-void KStandardItemListWidget::slotRoleEditingCanceled(int index,
-                                                  const QByteArray& role,
-                                                  const QVariant& value)
+void KStandardItemListWidget::slotRoleEditingCanceled(const QByteArray& role,
+                                                      const QVariant& value)
 {
-    m_roleEditor->deleteLater();
-    m_roleEditor = 0;
-    emit roleEditingCanceled(index, role, value);
+    closeRoleEditor();
+    emit roleEditingCanceled(index(), role, value);
     setEditedRole(QByteArray());
 }
 
-void KStandardItemListWidget::slotRoleEditingFinished(int index,
-                                                  const QByteArray& role,
-                                                  const QVariant& value)
+void KStandardItemListWidget::slotRoleEditingFinished(const QByteArray& role,
+                                                      const QVariant& value)
 {
-    m_roleEditor->deleteLater();
-    m_roleEditor = 0;
-    emit roleEditingFinished(index, role, value);
+    closeRoleEditor();
+    emit roleEditingFinished(index(), role, value);
     setEditedRole(QByteArray());
 }
 
@@ -706,6 +784,8 @@ void KStandardItemListWidget::triggerCacheRefreshing()
     const QHash<QByteArray, QVariant> values = data();
     m_isExpandable = m_supportsItemExpanding && values["isExpandable"].toBool();
     m_isHidden = isHidden();
+    m_customizedFont = customizedFont(styleOption().font);
+    m_customizedFontMetrics = QFontMetrics(m_customizedFont);
 
     updateExpansionArea();
     updateTextsCache();
@@ -720,7 +800,6 @@ void KStandardItemListWidget::updateExpansionArea()
 {
     if (m_supportsItemExpanding) {
         const QHash<QByteArray, QVariant> values = data();
-        Q_ASSERT(values.contains("expandedParentsCount"));
         const int expandedParentsCount = values.value("expandedParentsCount", 0).toInt();
         if (expandedParentsCount >= 0) {
             const qreal widgetHeight = size().height();
@@ -768,35 +847,28 @@ void KStandardItemListWidget::updatePixmapCache()
                 // use a generic icon as fallback
                 iconName = QLatin1String("unknown");
             }
-            m_pixmap = pixmapForIcon(iconName, maxIconHeight);
+            const QStringList overlays = values["iconOverlays"].toStringList();
+            m_pixmap = pixmapForIcon(iconName, overlays, maxIconHeight);
         } else if (m_pixmap.width() != maxIconWidth || m_pixmap.height() != maxIconHeight) {
             // A custom pixmap has been applied. Assure that the pixmap
             // is scaled to the maximum available size.
             KPixmapModifier::scale(m_pixmap, QSize(maxIconWidth, maxIconHeight));
         }
 
-        const QStringList overlays = values["iconOverlays"].toStringList();
-
-        // Strangely KFileItem::overlays() returns empty string-values, so
-        // we need to check first whether an overlay must be drawn at all.
-        // It is more efficient to do it here, as KIconLoader::drawOverlays()
-        // assumes that an overlay will be drawn and has some additional
-        // setup time.
-        foreach (const QString& overlay, overlays) {
-            if (!overlay.isEmpty()) {
-                // There is at least one overlay, draw all overlays above m_pixmap
-                // and cancel the check
-                KIconLoader::global()->drawOverlays(overlays, m_pixmap, KIconLoader::Desktop);
-                break;
-            }
-        }
-
         if (m_isCut) {
-            applyCutEffect(m_pixmap);
+            KIconEffect* effect = KIconLoader::global()->iconEffect();
+            m_pixmap = effect->apply(m_pixmap, KIconLoader::Desktop, KIconLoader::DisabledState);
         }
 
         if (m_isHidden) {
-            applyHiddenEffect(m_pixmap);
+            KIconEffect::semiTransparent(m_pixmap);
+        }
+
+        if (isSelected()) {
+            const QColor color = palette().brush(QPalette::Normal, QPalette::Highlight).color();
+            QImage image = m_pixmap.toImage();
+            KIconEffect::colorize(image, color, 0.8f);
+            m_pixmap = QPixmap::fromImage(image);
         }
     }
 
@@ -811,7 +883,7 @@ void KStandardItemListWidget::updatePixmapCache()
         scaledIconSize = static_cast<int>(textInfo->pos.y() - 2 * padding);
     } else {
         const int textRowsCount = (m_layout == CompactLayout) ? visibleRoles().count() : 1;
-        const qreal requiredTextHeight = textRowsCount * option.fontMetrics.height();
+        const qreal requiredTextHeight = textRowsCount * m_customizedFontMetrics.height();
         scaledIconSize = (requiredTextHeight < maxIconHeight) ?
                            widgetSize.height() - 2 * padding : maxIconHeight;
     }
@@ -897,7 +969,7 @@ void KStandardItemListWidget::updateTextsCache()
 
         const qreal availableWidth = (m_layout == DetailsLayout)
                                      ? columnWidth("rating") - columnPadding(option)
-                                     : m_textRect.width();
+                                     : size().width();
         if (ratingSize.width() > availableWidth) {
             ratingSize.rwidth() = availableWidth;
         }
@@ -931,7 +1003,7 @@ void KStandardItemListWidget::updateIconsLayoutTextCache()
     const qreal padding = option.padding;
     const qreal maxWidth = size().width() - 2 * padding;
     const qreal widgetHeight = size().height();
-    const qreal lineSpacing = option.fontMetrics.lineSpacing();
+    const qreal lineSpacing = m_customizedFontMetrics.lineSpacing();
 
     // Initialize properties for the "text" role. It will be used as anchor
     // for initializing the position of the other roles.
@@ -947,7 +1019,7 @@ void KStandardItemListWidget::updateIconsLayoutTextCache()
     const int additionalRolesCount = qMax(visibleRoles().count() - 1, 0);
     const int maxNameLines = (option.maxTextSize.height() / int(lineSpacing)) - additionalRolesCount;
 
-    QTextLayout layout(nameTextInfo->staticText.text(), option.font);
+    QTextLayout layout(nameTextInfo->staticText.text(), m_customizedFont);
     layout.setTextOption(nameTextInfo->staticText.textOption());
     layout.beginLayout();
     int nameLineIndex = 0;
@@ -963,12 +1035,15 @@ void KStandardItemListWidget::updateIconsLayoutTextCache()
             const int textLength = line.textStart() + line.textLength();
             if (textLength < nameText.length()) {
                 // Elide the last line of the text
-                QString lastTextLine = nameText.mid(line.textStart(), line.textLength());
-                lastTextLine = option.fontMetrics.elidedText(lastTextLine,
-                                                             Qt::ElideRight,
-                                                             line.naturalTextWidth() - 1);
+                QString lastTextLine = nameText.mid(line.textStart());
+                lastTextLine = m_customizedFontMetrics.elidedText(lastTextLine,
+                                                                  Qt::ElideRight,
+                                                                  maxWidth);
                 const QString elidedText = nameText.left(line.textStart()) + lastTextLine;
                 nameTextInfo->staticText.setText(elidedText);
+
+                const qreal lastLineWidth = m_customizedFontMetrics.boundingRect(lastTextLine).width();
+                nameWidth = qMax(nameWidth, lastLineWidth);
             }
             break;
         }
@@ -999,7 +1074,7 @@ void KStandardItemListWidget::updateIconsLayoutTextCache()
 
         qreal requiredWidth = 0;
 
-        QTextLayout layout(text, option.font);
+        QTextLayout layout(text, m_customizedFont);
         QTextOption textOption;
         textOption.setWrapMode(QTextOption::NoWrap);
         layout.setTextOption(textOption);
@@ -1010,9 +1085,12 @@ void KStandardItemListWidget::updateIconsLayoutTextCache()
             textLine.setLineWidth(maxWidth);
             requiredWidth = textLine.naturalTextWidth();
             if (requiredWidth > maxWidth) {
-                const QString elidedText = option.fontMetrics.elidedText(text, Qt::ElideRight, maxWidth);
+                const QString elidedText = m_customizedFontMetrics.elidedText(text, Qt::ElideRight, maxWidth);
                 textInfo->staticText.setText(elidedText);
-                requiredWidth = option.fontMetrics.width(elidedText);
+                requiredWidth = m_customizedFontMetrics.width(elidedText);
+            } else if (role == "rating") {
+               // Use the width of the rating pixmap, because the rating text is empty.
+                requiredWidth = m_rating.width();
             }
         }
         layout.endLayout();
@@ -1040,7 +1118,7 @@ void KStandardItemListWidget::updateCompactLayoutTextCache()
 
     const KItemListStyleOption& option = styleOption();
     const qreal widgetHeight = size().height();
-    const qreal lineSpacing = option.fontMetrics.lineSpacing();
+    const qreal lineSpacing = m_customizedFontMetrics.lineSpacing();
     const qreal textLinesHeight = qMax(visibleRoles().count(), 1) * lineSpacing;
     const int scaledIconSize = (textLinesHeight < option.iconSize) ? widgetHeight - 2 * option.padding : option.iconSize;
 
@@ -1053,10 +1131,10 @@ void KStandardItemListWidget::updateCompactLayoutTextCache()
         TextInfo* textInfo = m_textInfo.value(role);
         textInfo->staticText.setText(text);
 
-        qreal requiredWidth = option.fontMetrics.width(text);
+        qreal requiredWidth = m_customizedFontMetrics.width(text);
         if (requiredWidth > maxWidth) {
             requiredWidth = maxWidth;
-            const QString elidedText = option.fontMetrics.elidedText(text, Qt::ElideRight, maxWidth);
+            const QString elidedText = m_customizedFontMetrics.elidedText(text, Qt::ElideRight, maxWidth);
             textInfo->staticText.setText(elidedText);
         }
 
@@ -1068,7 +1146,7 @@ void KStandardItemListWidget::updateCompactLayoutTextCache()
         y += lineSpacing;
     }
 
-    m_textRect = QRectF(x - option.padding, 0, maximumRequiredTextWidth + 2 * option.padding, widgetHeight);
+    m_textRect = QRectF(x - 2 * option.padding, 0, maximumRequiredTextWidth + 3 * option.padding, widgetHeight);
 }
 
 void KStandardItemListWidget::updateDetailsLayoutTextCache()
@@ -1086,7 +1164,7 @@ void KStandardItemListWidget::updateDetailsLayoutTextCache()
 
     const qreal widgetHeight = size().height();
     const int scaledIconSize = widgetHeight - 2 * option.padding;
-    const int fontHeight = option.fontMetrics.height();
+    const int fontHeight = m_customizedFontMetrics.height();
 
     const qreal columnWidthInc = columnPadding(option);
     qreal firstColumnInc = scaledIconSize;
@@ -1103,7 +1181,7 @@ void KStandardItemListWidget::updateDetailsLayoutTextCache()
         QString text = roleText(role, values);
 
         // Elide the text in case it does not fit into the available column-width
-        qreal requiredWidth = option.fontMetrics.width(text);
+        qreal requiredWidth = m_customizedFontMetrics.width(text);
         const qreal roleWidth = columnWidth(role);
         qreal availableTextWidth = roleWidth - columnWidthInc;
 
@@ -1113,8 +1191,8 @@ void KStandardItemListWidget::updateDetailsLayoutTextCache()
         }
 
         if (requiredWidth > availableTextWidth) {
-            text = option.fontMetrics.elidedText(text, Qt::ElideRight, availableTextWidth);
-            requiredWidth = option.fontMetrics.width(text);
+            text = m_customizedFontMetrics.elidedText(text, Qt::ElideRight, availableTextWidth);
+            requiredWidth = m_customizedFontMetrics.width(text);
         }
 
         TextInfo* textInfo = m_textInfo.value(role);
@@ -1126,8 +1204,8 @@ void KStandardItemListWidget::updateDetailsLayoutTextCache()
             const qreal textWidth = option.extendedSelectionRegion
                                     ? size().width() - textInfo->pos.x()
                                     : requiredWidth + 2 * option.padding;
-            m_textRect = QRectF(textInfo->pos.x() - option.padding, 0,
-                                textWidth, size().height());
+            m_textRect = QRectF(textInfo->pos.x() - 2 * option.padding, 0,
+                                textWidth + option.padding, size().height());
 
             // The column after the name should always be aligned on the same x-position independent
             // from the expansion-level shown in the name column
@@ -1183,6 +1261,7 @@ void KStandardItemListWidget::drawSiblingsInformation(QPainter* painter)
     QRect siblingRect(x, 0, siblingSize, siblingSize);
 
     QStyleOption option;
+    option.palette.setColor(QPalette::Text, option.palette.color(normalTextColorRole()));
     bool isItemSibling = true;
 
     const QBitArray siblings = siblingsInformation();
@@ -1222,46 +1301,77 @@ QRectF KStandardItemListWidget::roleEditingRect(const QByteArray& role) const
     return rect;
 }
 
-QPixmap KStandardItemListWidget::pixmapForIcon(const QString& name, int size)
+void KStandardItemListWidget::closeRoleEditor()
 {
-    const KIcon icon(name);
-
-    int requestedSize;
-    if (size <= KIconLoader::SizeSmall) {
-        requestedSize = KIconLoader::SizeSmall;
-    } else if (size <= KIconLoader::SizeSmallMedium) {
-        requestedSize = KIconLoader::SizeSmallMedium;
-    } else if (size <= KIconLoader::SizeMedium) {
-        requestedSize = KIconLoader::SizeMedium;
-    } else if (size <= KIconLoader::SizeLarge) {
-        requestedSize = KIconLoader::SizeLarge;
-    } else if (size <= KIconLoader::SizeHuge) {
-        requestedSize = KIconLoader::SizeHuge;
-    } else if (size <= KIconLoader::SizeEnormous) {
-        requestedSize = KIconLoader::SizeEnormous;
-    } else if (size <= KIconLoader::SizeEnormous * 2) {
-        requestedSize = KIconLoader::SizeEnormous * 2;
-    } else {
-        requestedSize = size;
+    disconnect(m_roleEditor, SIGNAL(roleEditingCanceled(QByteArray,QVariant)),
+               this, SLOT(slotRoleEditingCanceled(QByteArray,QVariant)));
+    disconnect(m_roleEditor, SIGNAL(roleEditingFinished(QByteArray,QVariant)),
+               this, SLOT(slotRoleEditingFinished(QByteArray,QVariant)));
+
+    if (m_roleEditor->hasFocus()) {
+        // If the editing was not ended by a FocusOut event, we have
+        // to transfer the keyboard focus back to the KItemListContainer.
+        scene()->views()[0]->parentWidget()->setFocus();
     }
 
-    QPixmap pixmap = icon.pixmap(requestedSize, requestedSize);
-    if (requestedSize != size) {
-        KPixmapModifier::scale(pixmap, QSize(size, size));
+    if (m_oldRoleEditor) {
+        m_oldRoleEditor->deleteLater();
     }
-
-    return pixmap;
+    m_oldRoleEditor = m_roleEditor;
+    m_roleEditor->hide();
+    m_roleEditor = 0;
 }
 
-void KStandardItemListWidget::applyCutEffect(QPixmap& pixmap)
+QPixmap KStandardItemListWidget::pixmapForIcon(const QString& name, const QStringList& overlays, int size)
 {
-    KIconEffect* effect = KIconLoader::global()->iconEffect();
-    pixmap = effect->apply(pixmap, KIconLoader::Desktop, KIconLoader::DisabledState);
-}
+    const QString key = "KStandardItemListWidget:" % name % ":" % overlays.join(":") % ":" % QString::number(size);
+    QPixmap pixmap;
+
+    if (!QPixmapCache::find(key, pixmap)) {
+        const KIcon icon(name);
+
+        int requestedSize;
+        if (size <= KIconLoader::SizeSmall) {
+            requestedSize = KIconLoader::SizeSmall;
+        } else if (size <= KIconLoader::SizeSmallMedium) {
+            requestedSize = KIconLoader::SizeSmallMedium;
+        } else if (size <= KIconLoader::SizeMedium) {
+            requestedSize = KIconLoader::SizeMedium;
+        } else if (size <= KIconLoader::SizeLarge) {
+            requestedSize = KIconLoader::SizeLarge;
+        } else if (size <= KIconLoader::SizeHuge) {
+            requestedSize = KIconLoader::SizeHuge;
+        } else if (size <= KIconLoader::SizeEnormous) {
+            requestedSize = KIconLoader::SizeEnormous;
+        } else if (size <= KIconLoader::SizeEnormous * 2) {
+            requestedSize = KIconLoader::SizeEnormous * 2;
+        } else {
+            requestedSize = size;
+        }
 
-void KStandardItemListWidget::applyHiddenEffect(QPixmap& pixmap)
-{
-    KIconEffect::semiTransparent(pixmap);
+        pixmap = icon.pixmap(requestedSize, requestedSize);
+        if (requestedSize != size) {
+            KPixmapModifier::scale(pixmap, QSize(size, size));
+        }
+
+        // Strangely KFileItem::overlays() returns empty string-values, so
+        // we need to check first whether an overlay must be drawn at all.
+        // It is more efficient to do it here, as KIconLoader::drawOverlays()
+        // assumes that an overlay will be drawn and has some additional
+        // setup time.
+        foreach (const QString& overlay, overlays) {
+            if (!overlay.isEmpty()) {
+                // There is at least one overlay, draw all overlays above m_pixmap
+                // and cancel the check
+                KIconLoader::global()->drawOverlays(overlays, pixmap, KIconLoader::Desktop);
+                break;
+            }
+        }
+
+        QPixmapCache::insert(key, pixmap);
+    }
+
+    return pixmap;
 }
 
 QSizeF KStandardItemListWidget::preferredRatingSize(const KItemListStyleOption& option)