X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/a24327cd50ef17b953ecb908d260b73460158107..d3839617193e92463806580699caa595c892b8a6:/src/kitemviews/kstandarditemlistwidget.cpp diff --git a/src/kitemviews/kstandarditemlistwidget.cpp b/src/kitemviews/kstandarditemlistwidget.cpp index 032a949c1..b17fac6d5 100644 --- a/src/kitemviews/kstandarditemlistwidget.cpp +++ b/src/kitemviews/kstandarditemlistwidget.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -35,7 +36,7 @@ KStandardItemListWidgetInformant::~KStandardItemListWidgetInformant() { } -void KStandardItemListWidgetInformant::calculateItemSizeHints(QVector& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const +void KStandardItemListWidgetInformant::calculateItemSizeHints(QVector>& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const { switch (static_cast(view)->itemLayout()) { case KStandardItemListView::IconsLayout: @@ -120,7 +121,7 @@ QFont KStandardItemListWidgetInformant::customizedFontForLinks(const QFont& base return baseFont; } -void KStandardItemListWidgetInformant::calculateIconsLayoutItemSizeHints(QVector& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const +void KStandardItemListWidgetInformant::calculateIconsLayoutItemSizeHints(QVector>& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const { const KItemListStyleOption& option = view->styleOption(); const QFont& normalFont = option.font; @@ -137,7 +138,7 @@ void KStandardItemListWidgetInformant::calculateIconsLayoutItemSizeHints(QVector textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); for (int index = 0; index < logicalHeightHints.count(); ++index) { - if (logicalHeightHints.at(index) > 0.0) { + if (logicalHeightHints.at(index).first > 0.0) { continue; } @@ -145,7 +146,7 @@ void KStandardItemListWidgetInformant::calculateIconsLayoutItemSizeHints(QVector const QFont& font = itemIsLink(index, view) ? linkFont : normalFont; 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); @@ -153,6 +154,7 @@ void KStandardItemListWidgetInformant::calculateIconsLayoutItemSizeHints(QVector layout.beginLayout(); QTextLine line; int lineCount = 0; + bool isElided = false; while ((line = layout.createLine()).isValid()) { line.setLineWidth(maxWidth); line.naturalTextWidth(); @@ -160,6 +162,7 @@ void KStandardItemListWidgetInformant::calculateIconsLayoutItemSizeHints(QVector ++lineCount; if (lineCount == option.maxTextLines) { + isElided = layout.createLine().isValid(); break; } } @@ -168,13 +171,14 @@ void KStandardItemListWidgetInformant::calculateIconsLayoutItemSizeHints(QVector // Add one line for each additional information textHeight += additionalRolesSpacing; - logicalHeightHints[index] = textHeight + spacingAndIconHeight; + logicalHeightHints[index].first = textHeight + spacingAndIconHeight; + logicalHeightHints[index].second = isElided; } logicalWidthHint = itemWidth; } -void KStandardItemListWidgetInformant::calculateCompactLayoutItemSizeHints(QVector& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const +void KStandardItemListWidgetInformant::calculateCompactLayoutItemSizeHints(QVector>& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const { const KItemListStyleOption& option = view->styleOption(); const QFontMetrics& normalFontMetrics = option.fontMetrics; @@ -189,7 +193,7 @@ void KStandardItemListWidgetInformant::calculateCompactLayoutItemSizeHints(QVect const QFontMetrics linkFontMetrics(customizedFontForLinks(option.font)); for (int index = 0; index < logicalHeightHints.count(); ++index) { - if (logicalHeightHints.at(index) > 0.0) { + if (logicalHeightHints.at(index).first > 0.0) { continue; } @@ -216,22 +220,37 @@ void KStandardItemListWidgetInformant::calculateCompactLayoutItemSizeHints(QVect width = maxWidth; } - logicalHeightHints[index] = width; + logicalHeightHints[index].first = width; } logicalWidthHint = height; } -void KStandardItemListWidgetInformant::calculateDetailsLayoutItemSizeHints(QVector& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const +void KStandardItemListWidgetInformant::calculateDetailsLayoutItemSizeHints(QVector>& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const { const KItemListStyleOption& option = view->styleOption(); - const qreal height = option.padding * 2 + qMax(option.iconSize, option.fontMetrics.height()); - logicalHeightHints.fill(height); + + float zoomLevel = 1; + if (option.iconSize >= KIconLoader::SizeEnormous) { + zoomLevel = 2; + } else if (option.iconSize >= KIconLoader::SizeHuge) { + zoomLevel = 1.8; + } else if (option.iconSize >= KIconLoader::SizeLarge) { + zoomLevel = 1.6; + } else if (option.iconSize >= KIconLoader::SizeMedium) { + zoomLevel = 1.4; + } else if (option.iconSize >= KIconLoader::SizeSmallMedium) { + zoomLevel = 1.2; + } + + const qreal contentHeight = qMax(option.iconSize, zoomLevel * option.fontMetrics.height()); + logicalHeightHints.fill(std::make_pair(contentHeight + 2 * option.padding, false)); logicalWidthHint = -1.0; } KStandardItemListWidget::KStandardItemListWidget(KItemListWidgetInformant* informant, QGraphicsItem* parent) : KItemListWidget(informant, parent), + m_textInfo(), m_isCut(false), m_isHidden(false), m_customizedFont(), @@ -245,9 +264,9 @@ KStandardItemListWidget::KStandardItemListWidget(KItemListWidgetInformant* infor m_pixmapPos(), m_pixmap(), m_scaledPixmapSize(), + m_columnWidthSum(), m_iconRect(), m_hoverPixmap(), - m_textInfo(), m_textRect(), m_sortedVisibleRoles(), m_expansionArea(), @@ -289,6 +308,18 @@ KStandardItemListWidget::Layout KStandardItemListWidget::layout() const return m_layout; } +void KStandardItemListWidget::setHighlightEntireRow(bool highlightEntireRow) { + if (m_highlightEntireRow != highlightEntireRow) { + m_highlightEntireRow = highlightEntireRow; + m_dirtyLayout = true; + update(); + } +} + +bool KStandardItemListWidget::highlightEntireRow() const { + return m_highlightEntireRow; +} + void KStandardItemListWidget::setSupportsItemExpanding(bool supportsItemExpanding) { if (m_supportsItemExpanding != supportsItemExpanding) { @@ -314,7 +345,7 @@ void KStandardItemListWidget::paint(QPainter* painter, const QStyleOptionGraphic } const KItemListStyleOption& itemListStyleOption = styleOption(); - if (isHovered()) { + if (isHovered() && !m_pixmap.isNull()) { if (hoverOpacity() < 1.0) { /* * Linear interpolation between m_pixmap and m_hoverPixmap. @@ -357,7 +388,7 @@ void KStandardItemListWidget::paint(QPainter* painter, const QStyleOptionGraphic } else { drawPixmap(painter, m_hoverPixmap); } - } else { + } else if (!m_pixmap.isNull()) { drawPixmap(painter, m_pixmap); } @@ -490,7 +521,11 @@ QRectF KStandardItemListWidget::selectionRect() const case DetailsLayout: { const int padding = styleOption().padding; QRectF adjustedIconRect = iconRect().adjusted(-padding, -padding, padding, padding); - return adjustedIconRect | m_textRect; + QRectF result = adjustedIconRect | m_textRect; + if (m_highlightEntireRow) { + result.setRight(m_columnWidthSum + leadingPadding()); + } + return result; } default: @@ -581,6 +616,13 @@ void KStandardItemListWidget::invalidateCache() m_dirtyContent = true; } +void KStandardItemListWidget::invalidateIconCache() +{ + m_dirtyContent = true; + m_dirtyContentRoles.insert("iconPixmap"); + m_dirtyContentRoles.insert("iconOverlays"); +} + void KStandardItemListWidget::refreshCache() { } @@ -700,6 +742,11 @@ void KStandardItemListWidget::columnWidthChanged(const QByteArray& role, m_dirtyLayout = true; } +void KStandardItemListWidget::leadingPaddingChanged(qreal padding) { + Q_UNUSED(padding) + m_dirtyLayout = true; +} + void KStandardItemListWidget::styleOptionChanged(const KItemListStyleOption& current, const KItemListStyleOption& previous) { @@ -741,7 +788,7 @@ void KStandardItemListWidget::editedRoleChanged(const QByteArray& current, const QGraphicsView* parent = scene()->views()[0]; if (current.isEmpty() || !parent || current != "text") { if (m_roleEditor) { - emit roleEditingCanceled(index(), current, data().value(current)); + Q_EMIT roleEditingCanceled(index(), current, data().value(current)); disconnect(m_roleEditor, &KItemListRoleEditor::roleEditingCanceled, this, &KStandardItemListWidget::slotRoleEditingCanceled); @@ -764,6 +811,7 @@ void KStandardItemListWidget::editedRoleChanged(const QByteArray& current, const m_roleEditor = new KItemListRoleEditor(parent); m_roleEditor->setRole(current); + m_roleEditor->setAllowUpDownKeyChainEdit(m_layout != IconsLayout); m_roleEditor->setFont(styleOption().font); const QString text = data().value(current).toString(); @@ -866,7 +914,7 @@ void KStandardItemListWidget::slotRoleEditingCanceled(const QByteArray& role, const QVariant& value) { closeRoleEditor(); - emit roleEditingCanceled(index(), role, value); + Q_EMIT roleEditingCanceled(index(), role, value); setEditedRole(QByteArray()); } @@ -874,7 +922,7 @@ void KStandardItemListWidget::slotRoleEditingFinished(const QByteArray& role, const QVariant& value) { closeRoleEditor(); - emit roleEditingFinished(index(), role, value); + Q_EMIT roleEditingFinished(index(), role, value); setEditedRole(QByteArray()); } @@ -891,10 +939,13 @@ void KStandardItemListWidget::triggerCacheRefreshing() m_isHidden = isHidden(); m_customizedFont = customizedFont(styleOption().font); m_customizedFontMetrics = QFontMetrics(m_customizedFont); + m_columnWidthSum = std::accumulate(m_sortedVisibleRoles.begin(), m_sortedVisibleRoles.end(), + qreal(), [this](qreal sum, const auto &role){ return sum + columnWidth(role); }); updateExpansionArea(); updateTextsCache(); updatePixmapCache(); + clearHoverCache(); m_dirtyLayout = false; m_dirtyContent = false; @@ -912,7 +963,8 @@ void KStandardItemListWidget::updateExpansionArea() const qreal inc = (widgetHeight - option.iconSize) / 2; const qreal x = expandedParentsCount * widgetHeight + inc; const qreal y = inc; - m_expansionArea = QRectF(x, y, option.iconSize, option.iconSize); + const qreal xPadding = m_highlightEntireRow ? leadingPadding() : 0; + m_expansionArea = QRectF(xPadding + x, y, option.iconSize, option.iconSize); return; } } @@ -944,7 +996,34 @@ void KStandardItemListWidget::updatePixmapCache() } if (updatePixmap) { - m_pixmap = values["iconPixmap"].value(); + m_pixmap = QPixmap(); + + int sequenceIndex = hoverSequenceIndex(); + + if (values.contains("hoverSequencePixmaps")) { + // Use one of the hover sequence pixmaps instead of the default + // icon pixmap. + + const QVector pixmaps = values["hoverSequencePixmaps"].value>(); + + if (values.contains("hoverSequenceWraparoundPoint")) { + const float wap = values["hoverSequenceWraparoundPoint"].toFloat(); + if (wap >= 1.0f) { + sequenceIndex %= static_cast(wap); + } + } + + const int loadedIndex = qMax(qMin(sequenceIndex, pixmaps.size()-1), 0); + + if (loadedIndex != 0) { + m_pixmap = pixmaps[loadedIndex]; + } + } + + if (m_pixmap.isNull()) { + m_pixmap = values["iconPixmap"].value(); + } + if (m_pixmap.isNull()) { // Use the icon that fits to the MIME-type QString iconName = values["iconName"].toString(); @@ -962,6 +1041,11 @@ void KStandardItemListWidget::updatePixmapCache() KPixmapModifier::scale(m_pixmap, QSize(maxIconWidth, maxIconHeight) * qApp->devicePixelRatio()); } + if (m_pixmap.isNull()) { + m_hoverPixmap = QPixmap(); + return; + } + if (m_isCut) { KIconEffect* effect = KIconLoader::global()->iconEffect(); m_pixmap = effect->apply(m_pixmap, KIconLoader::Desktop, KIconLoader::DisabledState); @@ -974,6 +1058,10 @@ void KStandardItemListWidget::updatePixmapCache() if (m_layout == IconsLayout && isSelected()) { const QColor color = palette().brush(QPalette::Normal, QPalette::Highlight).color(); QImage image = m_pixmap.toImage(); + if (image.isNull()) { + m_hoverPixmap = QPixmap(); + return; + } KIconEffect::colorize(image, color, 0.8f); m_pixmap = QPixmap::fromImage(image); } @@ -1113,7 +1201,7 @@ QString KStandardItemListWidget::elideRightKeepExtension(const QString &text, in QString ret = m_customizedFontMetrics.elidedText(text.chopped(extensionLength), Qt::ElideRight, elidingWidth - extensionWidth); - ret.append(text.right(extensionLength)); + ret.append(text.rightRef(extensionLength)); return ret; } } @@ -1313,7 +1401,7 @@ void KStandardItemListWidget::updateDetailsLayoutTextCache() if (m_supportsItemExpanding) { firstColumnInc += (m_expansionArea.left() + m_expansionArea.right() + widgetHeight) / 2; } else { - firstColumnInc += option.padding; + firstColumnInc += option.padding + leadingPadding(); } qreal x = firstColumnInc; @@ -1329,7 +1417,7 @@ void KStandardItemListWidget::updateDetailsLayoutTextCache() const bool isTextRole = (role == "text"); if (isTextRole) { - availableTextWidth -= firstColumnInc; + availableTextWidth -= firstColumnInc - leadingPadding(); } if (requiredWidth > availableTextWidth) { @@ -1351,7 +1439,7 @@ void KStandardItemListWidget::updateDetailsLayoutTextCache() // The column after the name should always be aligned on the same x-position independent // from the expansion-level shown in the name column - x -= firstColumnInc; + x -= firstColumnInc - leadingPadding(); } else if (isRoleRightAligned(role)) { textInfo->pos.rx() += roleWidth - requiredWidth - columnWidthInc; } @@ -1363,8 +1451,11 @@ void KStandardItemListWidget::updateAdditionalInfoTextColor() QColor c1; if (m_customTextColor.isValid()) { c1 = m_customTextColor; - } else if (isSelected() && m_layout != DetailsLayout) { - c1 = styleOption().palette.highlightedText().color(); + } else if (isSelected()) { + // The detail text colour needs to match the main text (HighlightedText) for the same level + // of readability. We short circuit early here to avoid interpolating with another colour. + m_additionalInfoTextColor = styleOption().palette.color(QPalette::HighlightedText); + return; } else { c1 = styleOption().palette.text().color(); } @@ -1403,15 +1494,15 @@ void KStandardItemListWidget::drawSiblingsInformation(QPainter* painter) const int x = (m_expansionArea.left() + m_expansionArea.right() - siblingSize) / 2; QRect siblingRect(x, 0, siblingSize, siblingSize); - QStyleOption option; - option.palette.setColor(QPalette::Text, option.palette.color(normalTextColorRole())); bool isItemSibling = true; const QBitArray siblings = siblingsInformation(); + QStyleOption option; + const auto normalColor = option.palette.color(normalTextColorRole()); + const auto highlightColor = option.palette.color(expansionAreaHovered() ? QPalette::Highlight : normalTextColorRole()); for (int i = siblings.count() - 1; i >= 0; --i) { option.rect = siblingRect; option.state = siblings.at(i) ? QStyle::State_Sibling : QStyle::State_None; - if (isItemSibling) { option.state |= QStyle::State_Item; if (m_isExpandable) { @@ -1420,7 +1511,10 @@ void KStandardItemListWidget::drawSiblingsInformation(QPainter* painter) if (data().value("isExpanded").toBool()) { option.state |= QStyle::State_Open; } + option.palette.setColor(QPalette::Text, highlightColor); isItemSibling = false; + } else { + option.palette.setColor(QPalette::Text, normalColor); } style()->drawPrimitive(QStyle::PE_IndicatorBranch, &option, painter); @@ -1479,7 +1573,8 @@ QPixmap KStandardItemListWidget::pixmapForIcon(const QString& name, const QStrin if (icon.isNull()) { icon = QIcon(name); } - if (icon.isNull()) { + if (icon.isNull() + || icon.pixmap(size / qApp->devicePixelRatio(), size / qApp->devicePixelRatio(), mode).isNull()) { icon = fallbackIcon; }