X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/f63daef339dde16c7ef598f6fdaa5d2191da4685..c8d8556950005dfd96ebdb41d2f43ad90356367c:/src/kitemviews/kfileitemlistwidget.cpp diff --git a/src/kitemviews/kfileitemlistwidget.cpp b/src/kitemviews/kfileitemlistwidget.cpp index 5f659a1f6..62a2383d4 100644 --- a/src/kitemviews/kfileitemlistwidget.cpp +++ b/src/kitemviews/kfileitemlistwidget.cpp @@ -19,6 +19,7 @@ #include "kfileitemlistwidget.h" +#include "kfileitemclipboard_p.h" #include "kfileitemmodel.h" #include "kitemlistview.h" #include "kpixmapmodifier_p.h" @@ -37,11 +38,13 @@ #include #include -//#define KFILEITEMLISTWIDGET_DEBUG +// #define KFILEITEMLISTWIDGET_DEBUG KFileItemListWidget::KFileItemListWidget(QGraphicsItem* parent) : KItemListWidget(parent), - m_isDir(false), + m_isCut(false), + m_isHidden(false), + m_isExpandable(false), m_dirtyLayout(true), m_dirtyContent(true), m_dirtyContentRoles(), @@ -49,7 +52,8 @@ KFileItemListWidget::KFileItemListWidget(QGraphicsItem* parent) : m_pixmapPos(), m_pixmap(), m_scaledPixmapSize(), - m_hoverPixmapRect(), + m_originalPixmapSize(), + m_iconRect(), m_hoverPixmap(), m_textPos(), m_text(), @@ -86,12 +90,12 @@ KFileItemListWidget::Layout KFileItemListWidget::layout() const void KFileItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { - KItemListWidget::paint(painter, option, widget); - const_cast(this)->triggerCacheRefreshing(); + KItemListWidget::paint(painter, option, widget); + // Draw expansion toggle '>' or 'V' - if (m_isDir && !m_expansionArea.isEmpty()) { + if (m_isExpandable && !m_expansionArea.isEmpty()) { QStyleOption arrowOption; arrowOption.rect = m_expansionArea.toRect(); const QStyle::PrimitiveElement arrow = data()["isExpanded"].toBool() @@ -143,8 +147,11 @@ void KFileItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsIte } #ifdef KFILEITEMLISTWIDGET_DEBUG - painter->setPen(Qt::red); painter->setBrush(Qt::NoBrush); + painter->setPen(Qt::green); + painter->drawRect(m_iconRect); + + painter->setPen(Qt::red); painter->drawText(QPointF(0, itemListStyleOption.fontMetrics.height()), QString::number(index())); painter->drawRect(rect()); #endif @@ -153,11 +160,7 @@ void KFileItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsIte QRectF KFileItemListWidget::iconRect() const { const_cast(this)->triggerCacheRefreshing(); - - QRectF bounds = m_hoverPixmapRect; - const qreal margin = styleOption().margin; - bounds.adjust(-margin, -margin, margin, margin); - return bounds; + return m_iconRect; } QRectF KFileItemListWidget::textRect() const @@ -169,7 +172,42 @@ QRectF KFileItemListWidget::textRect() const QRectF KFileItemListWidget::expansionToggleRect() const { const_cast(this)->triggerCacheRefreshing(); - return m_isDir ? m_expansionArea : QRectF(); + return m_isExpandable ? m_expansionArea : QRectF(); +} + +QRectF KFileItemListWidget::selectionToggleRect() const +{ + const_cast(this)->triggerCacheRefreshing(); + + const int iconHeight = m_pixmap.height(); + + int toggleSize = KIconLoader::SizeSmall; + if (iconHeight >= KIconLoader::SizeEnormous) { + toggleSize = KIconLoader::SizeMedium; + } else if (iconHeight >= KIconLoader::SizeLarge) { + toggleSize = KIconLoader::SizeSmallMedium; + } + + QPointF pos = iconRect().topLeft(); + + // If the selection toggle has a very small distance to the + // widget borders, the size of the selection toggle will get + // increased to prevent an accidental clicking of the item + // when trying to hit the toggle. + const int widgetHeight = size().height(); + const int widgetWidth = size().width(); + const int minMargin = 2; + + if (toggleSize + minMargin * 2 >= widgetHeight) { + toggleSize = widgetHeight; + pos.setY(0); + } + if (toggleSize + minMargin * 2 >= widgetWidth) { + toggleSize = widgetWidth; + pos.setX(0); + } + + return QRectF(pos, QSizeF(toggleSize, toggleSize)); } QString KFileItemListWidget::roleText(const QByteArray& role, const QHash& values) @@ -192,13 +230,18 @@ QString KFileItemListWidget::roleText(const QByteArray& role, const QHash(); text = i18ncp("@item:intable", "%1 item", "%1 items", size); } } else { - const KIO::filesize_t size = roleValue.value(); - text = KIO::convertSize(size); + // Show the size in kilobytes (always round up) + const KLocale* locale = KGlobal::locale(); + const int roundInc = (locale->binaryUnitDialect() == KLocale::MetricBinaryDialect) ? 499 : 511; + const KIO::filesize_t size = roleValue.value() + roundInc; + text = locale->formatByteSize(size, 0, KLocale::DefaultBinaryDialect, KLocale::UnitKiloByte); } break; } @@ -238,7 +281,13 @@ void KFileItemListWidget::setTextColor(const QColor& color) QColor KFileItemListWidget::textColor() const { - return m_customTextColor.isValid() ? m_customTextColor : styleOption().palette.text().color(); + if (m_customTextColor.isValid() && !isSelected()) { + 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(); } void KFileItemListWidget::setOverlay(const QPixmap& overlay) @@ -304,12 +353,52 @@ void KFileItemListWidget::hoveredChanged(bool hovered) m_dirtyLayout = true; } +void KFileItemListWidget::selectedChanged(bool selected) +{ + Q_UNUSED(selected); + updateAdditionalInfoTextColor(); +} + void KFileItemListWidget::resizeEvent(QGraphicsSceneResizeEvent* event) { KItemListWidget::resizeEvent(event); m_dirtyLayout = true; } +void KFileItemListWidget::showEvent(QShowEvent* event) +{ + KItemListWidget::showEvent(event); + + // Listen to changes of the clipboard to mark the item as cut/uncut + KFileItemClipboard* clipboard = KFileItemClipboard::instance(); + + const KUrl itemUrl = data().value("url").value(); + m_isCut = clipboard->isCut(itemUrl); + + connect(clipboard, SIGNAL(cutItemsChanged()), + this, SLOT(slotCutItemsChanged())); +} + +void KFileItemListWidget::hideEvent(QHideEvent* event) +{ + disconnect(KFileItemClipboard::instance(), SIGNAL(cutItemsChanged()), + this, SLOT(slotCutItemsChanged())); + + KItemListWidget::hideEvent(event); +} + +void KFileItemListWidget::slotCutItemsChanged() +{ + const KUrl itemUrl = data().value("url").value(); + const bool isCut = KFileItemClipboard::instance()->isCut(itemUrl); + if (m_isCut != isCut) { + m_isCut = isCut; + m_pixmap = QPixmap(); + m_dirtyContent = true; + update(); + } +} + void KFileItemListWidget::triggerCacheRefreshing() { if ((!m_dirtyContent && !m_dirtyLayout) || index() < 0) { @@ -318,7 +407,9 @@ void KFileItemListWidget::triggerCacheRefreshing() refreshCache(); - m_isDir = data()["isDir"].toBool(); + const QHash values = data(); + m_isExpandable = values["isExpandable"].toBool(); + m_isHidden = values["name"].toString().startsWith(QLatin1Char('.')); updateExpansionArea(); updateTextsCache(); @@ -336,15 +427,17 @@ void KFileItemListWidget::updateExpansionArea() Q_ASSERT(values.contains("expansionLevel")); const KItemListStyleOption& option = styleOption(); const int expansionLevel = values.value("expansionLevel", 0).toInt(); - - const qreal widgetHeight = size().height(); - const qreal expansionLevelSize = KIconLoader::SizeSmall; - const qreal x = option.margin + expansionLevel * widgetHeight; - const qreal y = (widgetHeight - expansionLevelSize) / 2; - m_expansionArea = QRectF(x, y, expansionLevelSize, expansionLevelSize); - } else { - m_expansionArea = QRectF(); + if (expansionLevel >= 0) { + const qreal widgetHeight = size().height(); + const qreal expansionLevelSize = KIconLoader::SizeSmall; + const qreal x = option.margin + expansionLevel * widgetHeight; + const qreal y = (widgetHeight - expansionLevelSize) / 2; + m_expansionArea = QRectF(x, y, expansionLevelSize, expansionLevelSize); + return; + } } + + m_expansionArea = QRectF(); } void KFileItemListWidget::updatePixmapCache() @@ -372,7 +465,8 @@ void KFileItemListWidget::updatePixmapCache() if (!updatePixmap && m_dirtyContent) { updatePixmap = m_dirtyContentRoles.isEmpty() || m_dirtyContentRoles.contains("iconPixmap") - || m_dirtyContentRoles.contains("iconName"); + || m_dirtyContentRoles.contains("iconName") + || m_dirtyContentRoles.contains("iconOverlays"); } if (updatePixmap) { @@ -386,7 +480,7 @@ void KFileItemListWidget::updatePixmapCache() iconName = QLatin1String("unknown"); } m_pixmap = pixmapForIcon(iconName, iconHeight); - m_hoverPixmapRect.setSize(m_pixmap.size()); + m_originalPixmapSize = m_pixmap.size(); } else if (m_pixmap.size() != QSize(iconHeight, iconHeight)) { // A custom pixmap has been applied. Assure that the pixmap // is scaled to the available size. @@ -395,7 +489,7 @@ void KFileItemListWidget::updatePixmapCache() if (scale) { KPixmapModifier::scale(m_pixmap, QSize(iconHeight, iconHeight)); } - m_hoverPixmapRect.setSize(m_pixmap.size()); + m_originalPixmapSize = m_pixmap.size(); // To simplify the handling of scaling the original pixmap // will be embedded into a square pixmap. @@ -403,19 +497,40 @@ void KFileItemListWidget::updatePixmapCache() squarePixmap.fill(Qt::transparent); QPainter painter(&squarePixmap); - if (iconOnTop) { - const int x = (iconHeight - m_pixmap.width()) / 2; // Center horizontally - const int y = iconHeight - m_pixmap.height(); // Align on bottom - painter.drawPixmap(x, y, m_pixmap); - } else { - const int x = iconHeight - m_pixmap.width(); // Align right - const int y = (iconHeight - m_pixmap.height()) / 2; // Center vertically - painter.drawPixmap(x, y, m_pixmap); + const int x = (iconHeight - m_pixmap.width()) / 2; // Center horizontally + int y = iconHeight - m_pixmap.height(); // Move to bottom + if (!iconOnTop) { + y /= 2.0; // Center vertically } + painter.drawPixmap(x, y, m_pixmap); m_pixmap = squarePixmap; } else { - m_hoverPixmapRect.setSize(m_pixmap.size()); + m_originalPixmapSize = m_pixmap.size(); + } + + 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); + } + + if (m_isHidden) { + applyHiddenEffect(m_pixmap); } Q_ASSERT(m_pixmap.height() == iconHeight); @@ -435,17 +550,31 @@ void KFileItemListWidget::updatePixmapCache() m_pixmapPos.setY(option.margin); // Center the hover rectangle horizontally and align it on bottom - const qreal x = m_pixmapPos.x() + (m_scaledPixmapSize.width() - m_hoverPixmapRect.width()) / 2.0; - const qreal y = m_pixmapPos.y() + m_scaledPixmapSize.height() - m_hoverPixmapRect.height(); - m_hoverPixmapRect.moveTopLeft(QPointF(x, y)); + qreal hoverWidth = m_originalPixmapSize.width(); + qreal hoverHeight = m_originalPixmapSize.height(); + if (scaledIconHeight != m_pixmap.height()) { + const qreal scaleFactor = qreal(scaledIconHeight) / qreal(m_pixmap.height()); + hoverWidth *= scaleFactor; + hoverHeight *= scaleFactor; + } + const qreal hoverX = m_pixmapPos.x() + (m_scaledPixmapSize.width() - hoverWidth) / 2.0; + qreal hoverY = m_scaledPixmapSize.height() - hoverHeight; + if (!iconOnTop) { + hoverY /= 2.0; + } + hoverY += m_pixmapPos.y(); + m_iconRect = QRectF(hoverX, hoverY, hoverWidth, hoverHeight); + const qreal margin = option.margin; + m_iconRect.adjust(-margin, -margin, margin, margin); + // Prepare the pixmap that is used when the item gets hovered if (isHovered()) { m_hoverPixmap = m_pixmap; KIconEffect* effect = KIconLoader::global()->iconEffect(); // In the KIconLoader terminology, active = hover. if (effect->hasEffect(KIconLoader::Desktop, KIconLoader::ActiveState)) { - m_hoverPixmap = effect->apply(m_pixmap, KIconLoader::Desktop, KIconLoader::ActiveState); + m_hoverPixmap = effect->apply(m_pixmap, KIconLoader::Desktop, KIconLoader::ActiveState); } else { m_hoverPixmap = m_pixmap; } @@ -532,9 +661,9 @@ void KFileItemListWidget::updateIconsLayoutTextCache() m_text[Name].setTextWidth(maxWidth); m_textPos[Name] = QPointF(option.margin, widgetHeight - textLinesCount * fontHeight - option.margin); m_textRect = QRectF(option.margin + (maxWidth - requiredWidthForName) / 2, - m_textPos[Name].y(), - requiredWidthForName, - m_text[Name].size().height()); + m_textPos[Name].y(), + requiredWidthForName, + textLinesCountForName * fontHeight); // Calculate the position for each additional information qreal y = m_textPos[Name].y() + textLinesCountForName * fontHeight; @@ -690,10 +819,18 @@ void KFileItemListWidget::updateDetailsLayoutTextCache() void KFileItemListWidget::updateAdditionalInfoTextColor() { + QColor c1; + if (m_customTextColor.isValid()) { + c1 = m_customTextColor; + } else if (isSelected() && m_layout != DetailsLayout) { + c1 = styleOption().palette.highlightedText().color(); + } else { + c1 = styleOption().palette.text().color(); + } + // For the color of the additional info the inactive text color // is not used as this might lead to unreadable text for some color schemes. Instead - // the text color is slightly mixed with the background color. - const QColor c1 = textColor(); + // the text color c1 is slightly mixed with the background color. const QColor c2 = styleOption().palette.base().color(); const int p1 = 70; const int p2 = 100 - p1; @@ -704,29 +841,18 @@ void KFileItemListWidget::updateAdditionalInfoTextColor() void KFileItemListWidget::drawPixmap(QPainter* painter, const QPixmap& pixmap) { - const bool isHiddenItem = m_text[Name].text().startsWith(QLatin1Char('.')); - qreal opacity; - if (isHiddenItem) { - opacity = painter->opacity(); - painter->setOpacity(opacity * 0.3); - } - if (m_scaledPixmapSize != pixmap.size()) { QPixmap scaledPixmap = pixmap; KPixmapModifier::scale(scaledPixmap, m_scaledPixmapSize); painter->drawPixmap(m_pixmapPos, scaledPixmap); #ifdef KFILEITEMLISTWIDGET_DEBUG - painter->setPen(Qt::green); + painter->setPen(Qt::blue); painter->drawRect(QRectF(m_pixmapPos, QSizeF(scaledPixmap.size()))); #endif } else { painter->drawPixmap(m_pixmapPos, pixmap); } - - if (isHiddenItem) { - painter->setOpacity(opacity); - } } QPixmap KFileItemListWidget::pixmapForIcon(const QString& name, int size) @@ -778,4 +904,15 @@ KFileItemListWidget::TextId KFileItemListWidget::roleTextId(const QByteArray& ro return rolesHash.value(role); } +void KFileItemListWidget::applyCutEffect(QPixmap& pixmap) +{ + KIconEffect* effect = KIconLoader::global()->iconEffect(); + pixmap = effect->apply(pixmap, KIconLoader::Desktop, KIconLoader::DisabledState); +} + +void KFileItemListWidget::applyHiddenEffect(QPixmap& pixmap) +{ + KIconEffect::semiTransparent(pixmap); +} + #include "kfileitemlistwidget.moc"