]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/kitemviews/kstandarditemlistwidget.cpp
Simplify handling of preview jobs
[dolphin.git] / src / kitemviews / kstandarditemlistwidget.cpp
index 5b0a0b7412314f164207c98713153df86009c03d..9a3f8f7bd1ce082e2ea07fad1f2aa32a3d649725 100644 (file)
@@ -42,6 +42,7 @@
 #include <QStyleOption>
 #include <QTextLayout>
 #include <QTextLine>
+#include <QPixmapCache>
 
 // #define KSTANDARDITEMLISTWIDGET_DEBUG
 
@@ -193,7 +194,8 @@ KStandardItemListWidget::KStandardItemListWidget(KItemListWidgetInformant* infor
     m_additionalInfoTextColor(),
     m_overlay(),
     m_rating(),
-    m_roleEditor(0)
+    m_roleEditor(0),
+    m_oldRoleEditor(0)
 {
 }
 
@@ -203,6 +205,7 @@ KStandardItemListWidget::~KStandardItemListWidget()
     m_textInfo.clear();
 
     delete m_roleEditor;
+    delete m_oldRoleEditor;
 }
 
 void KStandardItemListWidget::setLayout(Layout layout)
@@ -246,23 +249,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);
+            }
 
-        const qreal opacity = painter->opacity();
-        painter->setOpacity(hoverOpacity() * opacity);
-        drawPixmap(painter, m_hoverPixmap);
-        painter->setOpacity(opacity);
+            // 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);
+            }
+
+            // Finally paint pixmap1 on the widget
+            drawPixmap(painter, pixmap1);
+        } else {
+            drawPixmap(painter, m_hoverPixmap);
+        }
     } else {
         drawPixmap(painter, m_pixmap);
     }
 
     painter->setFont(m_customizedFont);
-    painter->setPen(m_isHidden ? m_additionalInfoTextColor : textColor());
+    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;
@@ -464,6 +507,11 @@ 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) {
@@ -475,13 +523,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)
@@ -576,18 +628,34 @@ 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)));
+            m_oldRoleEditor = m_roleEditor;
+            m_roleEditor->hide();
             m_roleEditor = 0;
         }
         return;
+    } else if (m_oldRoleEditor) {
+        // Delete the old editor before constructing the new one to
+        // prevent a memory leak.
+        m_oldRoleEditor->deleteLater();
+        m_oldRoleEditor = 0;
     }
 
     Q_ASSERT(!m_roleEditor);
@@ -595,7 +663,6 @@ 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);
 
@@ -605,32 +672,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
-    // TODO: This is file-item-specific and should be moved
-    // into KFileItemListWidget.
-    int selectionLength = text.length();
-
-    const QString extension = KMimeType::extractKnownExtension(text);
-    if (extension.isEmpty()) {
-        // For an unknown extension just exclude the extension after
-        // the last point. This does not work for multiple extensions like
-        // *.tar.gz but usually this is anyhow a known extension.
-        selectionLength = text.lastIndexOf(QLatin1Char('.'));
-    } else {
-        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);
@@ -691,21 +745,19 @@ void KStandardItemListWidget::slotCutItemsChanged()
     }
 }
 
-void KStandardItemListWidget::slotRoleEditingCanceled(int index,
-                                                      const QByteArray& role,
+void KStandardItemListWidget::slotRoleEditingCanceled(const QByteArray& role,
                                                       const QVariant& value)
 {
     closeRoleEditor();
-    emit roleEditingCanceled(index, role, value);
+    emit roleEditingCanceled(index(), role, value);
     setEditedRole(QByteArray());
 }
 
-void KStandardItemListWidget::slotRoleEditingFinished(int index,
-                                                      const QByteArray& role,
+void KStandardItemListWidget::slotRoleEditingFinished(const QByteArray& role,
                                                       const QVariant& value)
 {
     closeRoleEditor();
-    emit roleEditingFinished(index, role, value);
+    emit roleEditingFinished(index(), role, value);
     setEditedRole(QByteArray());
 }
 
@@ -819,7 +871,7 @@ void KStandardItemListWidget::updatePixmapCache()
         if (isSelected()) {
             const QColor color = palette().brush(QPalette::Normal, QPalette::Highlight).color();
             QImage image = m_pixmap.toImage();
-            KIconEffect::colorize(image, color, 1.0f);
+            KIconEffect::colorize(image, color, 0.8f);
             m_pixmap = QPixmap::fromImage(image);
         }
     }
@@ -1037,7 +1089,7 @@ void KStandardItemListWidget::updateIconsLayoutTextCache()
                 const QString elidedText = m_customizedFontMetrics.elidedText(text, Qt::ElideRight, maxWidth);
                 textInfo->staticText.setText(elidedText);
                 requiredWidth = m_customizedFontMetrics.width(elidedText);
-            } else if (role == "rating") { 
+            } else if (role == "rating") {
                // Use the width of the rating pixmap, because the rating text is empty.
                 requiredWidth = m_rating.width();
             }
@@ -1210,6 +1262,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();
@@ -1251,41 +1304,55 @@ QRectF KStandardItemListWidget::roleEditingRect(const QByteArray& role) const
 
 void KStandardItemListWidget::closeRoleEditor()
 {
+    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();
     }
-    m_roleEditor->deleteLater();
+
+    m_oldRoleEditor = m_roleEditor;
+    m_roleEditor->hide();
     m_roleEditor = 0;
 }
 
 QPixmap KStandardItemListWidget::pixmapForIcon(const QString& name, int size)
 {
-    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;
-    }
+    const QString key = "KStandardItemListWidget:" % name  % ":" % 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;
+        }
+
+        pixmap = icon.pixmap(requestedSize, requestedSize);
+        if (requestedSize != size) {
+            KPixmapModifier::scale(pixmap, QSize(size, size));
+        }
 
-    QPixmap pixmap = icon.pixmap(requestedSize, requestedSize);
-    if (requestedSize != size) {
-        KPixmapModifier::scale(pixmap, QSize(size, size));
+        QPixmapCache::insert(key, pixmap);
     }
 
     return pixmap;