X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/006f667ab14aff2d067373e7e88bde4800b2d9c2..86d2aa321d54bf3ae6c95476d649634fd0ff68d5:/src/kitemviews/kstandarditemlistwidget.cpp diff --git a/src/kitemviews/kstandarditemlistwidget.cpp b/src/kitemviews/kstandarditemlistwidget.cpp index 9f7b26959..1c89edb6e 100644 --- a/src/kitemviews/kstandarditemlistwidget.cpp +++ b/src/kitemviews/kstandarditemlistwidget.cpp @@ -22,19 +22,16 @@ #include "kfileitemlistview.h" #include "kfileitemmodel.h" -#include +#include #include #include -#include -#include +#include #include -#include #include "private/kfileitemclipboard.h" #include "private/kitemlistroleeditor.h" #include "private/kpixmapmodifier.h" -#include #include #include #include @@ -43,6 +40,7 @@ #include #include #include +#include // #define KSTANDARDITEMLISTWIDGET_DEBUG @@ -55,19 +53,19 @@ KStandardItemListWidgetInformant::~KStandardItemListWidgetInformant() { } -void KStandardItemListWidgetInformant::calculateItemSizeHints(QVector& sizeHints, const KItemListView* view) const +void KStandardItemListWidgetInformant::calculateItemSizeHints(QVector& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const { switch (static_cast(view)->itemLayout()) { case KStandardItemListWidget::IconsLayout: - calculateIconsLayoutItemSizeHints(sizeHints, view); + calculateIconsLayoutItemSizeHints(logicalHeightHints, logicalWidthHint, view); break; case KStandardItemListWidget::CompactLayout: - calculateCompactLayoutItemSizeHints(sizeHints, view); + calculateCompactLayoutItemSizeHints(logicalHeightHints, logicalWidthHint, view); break; case KStandardItemListWidget::DetailsLayout: - calculateDetailsLayoutItemSizeHints(sizeHints, view); + calculateDetailsLayoutItemSizeHints(logicalHeightHints, logicalWidthHint, view); break; default: @@ -86,16 +84,22 @@ qreal KStandardItemListWidgetInformant::preferredRoleColumnWidth(const QByteArra const QString text = roleText(role, values); qreal width = KStandardItemListWidget::columnPadding(option); + const QFontMetrics& normalFontMetrics = option.fontMetrics; + const QFontMetrics linkFontMetrics(customizedFontForLinks(option.font)); + if (role == "rating") { width += KStandardItemListWidget::preferredRatingSize(option).width(); } else { - width += option.fontMetrics.width(text); + // If current item is a link, we use the customized link font metrics instead of the normal font metrics. + const QFontMetrics& fontMetrics = itemIsLink(index, view) ? linkFontMetrics : normalFontMetrics; + + width += fontMetrics.width(text); if (role == "text") { if (view->supportsItemExpanding()) { // Increase the width by the expansion-toggle and the current expansion level const int expandedParentsCount = values.value("expandedParentsCount", 0).toInt(); - const qreal height = option.padding * 2 + qMax(option.iconSize, option.fontMetrics.height()); + const qreal height = option.padding * 2 + qMax(option.iconSize, fontMetrics.height()); width += (expandedParentsCount + 1) * height; } @@ -112,6 +116,13 @@ QString KStandardItemListWidgetInformant::itemText(int index, const KItemListVie return view->model()->data(index).value("text").toString(); } +bool KStandardItemListWidgetInformant::itemIsLink(int index, const KItemListView* view) const +{ + Q_UNUSED(index); + Q_UNUSED(view); + return false; +} + QString KStandardItemListWidgetInformant::roleText(const QByteArray& role, const QHash& values) const { @@ -122,10 +133,15 @@ QString KStandardItemListWidgetInformant::roleText(const QByteArray& role, return values.value(role).toString(); } -void KStandardItemListWidgetInformant::calculateIconsLayoutItemSizeHints(QVector& sizeHints, const KItemListView* view) const +QFont KStandardItemListWidgetInformant::customizedFontForLinks(const QFont& baseFont) const +{ + return baseFont; +} + +void KStandardItemListWidgetInformant::calculateIconsLayoutItemSizeHints(QVector& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const { const KItemListStyleOption& option = view->styleOption(); - const QFont& font = option.font; + const QFont& normalFont = option.font; const int additionalRolesCount = qMax(view->visibleRoles().count() - 1, 0); const qreal itemWidth = view->itemSize().width(); @@ -133,14 +149,19 @@ void KStandardItemListWidgetInformant::calculateIconsLayoutItemSizeHints(QVector const qreal additionalRolesSpacing = additionalRolesCount * option.fontMetrics.lineSpacing(); const qreal spacingAndIconHeight = option.iconSize + option.padding * 3; + const QFont linkFont = customizedFontForLinks(normalFont); + QTextOption textOption(Qt::AlignHCenter); textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); - for (int index = 0; index < sizeHints.count(); ++index) { - if (!sizeHints.at(index).isEmpty()) { + for (int index = 0; index < logicalHeightHints.count(); ++index) { + if (logicalHeightHints.at(index) > 0.0) { continue; } + // If the current item is a link, we use the customized link font instead of the normal font. + 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 @@ -165,27 +186,34 @@ void KStandardItemListWidgetInformant::calculateIconsLayoutItemSizeHints(QVector // Add one line for each additional information textHeight += additionalRolesSpacing; - sizeHints[index] = QSizeF(itemWidth, textHeight + spacingAndIconHeight); + logicalHeightHints[index] = textHeight + spacingAndIconHeight; } + + logicalWidthHint = itemWidth; } -void KStandardItemListWidgetInformant::calculateCompactLayoutItemSizeHints(QVector& sizeHints, const KItemListView* view) const +void KStandardItemListWidgetInformant::calculateCompactLayoutItemSizeHints(QVector& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const { const KItemListStyleOption& option = view->styleOption(); - const QFontMetrics& fontMetrics = option.fontMetrics; + const QFontMetrics& normalFontMetrics = option.fontMetrics; const int additionalRolesCount = qMax(view->visibleRoles().count() - 1, 0); const QList& visibleRoles = view->visibleRoles(); const bool showOnlyTextRole = (visibleRoles.count() == 1) && (visibleRoles.first() == "text"); const qreal maxWidth = option.maxTextWidth; const qreal paddingAndIconWidth = option.padding * 4 + option.iconSize; - const qreal height = option.padding * 2 + qMax(option.iconSize, (1 + additionalRolesCount) * option.fontMetrics.lineSpacing()); + const qreal height = option.padding * 2 + qMax(option.iconSize, (1 + additionalRolesCount) * normalFontMetrics.lineSpacing()); - for (int index = 0; index < sizeHints.count(); ++index) { - if (!sizeHints.at(index).isEmpty()) { + const QFontMetrics linkFontMetrics(customizedFontForLinks(option.font)); + + for (int index = 0; index < logicalHeightHints.count(); ++index) { + if (logicalHeightHints.at(index) > 0.0) { continue; } + // If the current item is a link, we use the customized link font metrics instead of the normal font metrics. + const QFontMetrics& fontMetrics = itemIsLink(index, view) ? linkFontMetrics : normalFontMetrics; + // 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; @@ -206,22 +234,18 @@ void KStandardItemListWidgetInformant::calculateCompactLayoutItemSizeHints(QVect width = maxWidth; } - sizeHints[index] = QSizeF(width, height); + logicalHeightHints[index] = width; } + + logicalWidthHint = height; } -void KStandardItemListWidgetInformant::calculateDetailsLayoutItemSizeHints(QVector& sizeHints, 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()); - - for (int index = 0; index < sizeHints.count(); ++index) { - if (!sizeHints.at(index).isEmpty()) { - continue; - } - - sizeHints[index] = QSizeF(-1, height); - } + logicalHeightHints.fill(height); + logicalWidthHint = -1.0; } KStandardItemListWidget::KStandardItemListWidget(KItemListWidgetInformant* informant, QGraphicsItem* parent) : @@ -319,6 +343,7 @@ void KStandardItemListWidget::paint(QPainter* painter, const QStyleOptionGraphic */ // Paint pixmap1 so that pixmap1 = m_pixmap * (1.0 - hoverOpacity()) QPixmap pixmap1(m_pixmap.size()); + pixmap1.setDevicePixelRatio(m_pixmap.devicePixelRatio()); pixmap1.fill(Qt::transparent); { QPainter p(&pixmap1); @@ -328,6 +353,7 @@ void KStandardItemListWidget::paint(QPainter* painter, const QStyleOptionGraphic // Paint pixmap2 so that pixmap2 = m_hoverPixmap * hoverOpacity() QPixmap pixmap2(pixmap1.size()); + pixmap2.setDevicePixelRatio(pixmap1.devicePixelRatio()); pixmap2.fill(Qt::transparent); { QPainter p(&pixmap2); @@ -470,6 +496,29 @@ QRectF KStandardItemListWidget::textFocusRect() const return m_textRect; } +QRectF KStandardItemListWidget::selectionRect() const +{ + const_cast(this)->triggerCacheRefreshing(); + + switch (m_layout) { + case IconsLayout: + return m_textRect; + + case CompactLayout: + case DetailsLayout: { + const int padding = styleOption().padding; + QRectF adjustedIconRect = iconRect().adjusted(-padding, -padding, padding, padding); + return adjustedIconRect | m_textRect; + } + + default: + Q_ASSERT(false); + break; + } + + return m_textRect; +} + QRectF KStandardItemListWidget::expansionToggleRect() const { const_cast(this)->triggerCacheRefreshing(); @@ -632,6 +681,12 @@ void KStandardItemListWidget::dataChanged(const QHash& cur dirtyRoles = roles; } + // The URL might have changed (i.e., if the sort order of the items has + // been changed). Therefore, the "is cut" state must be updated. + KFileItemClipboard* clipboard = KFileItemClipboard::instance(); + const QUrl itemUrl = data().value("url").toUrl(); + m_isCut = clipboard->isCut(itemUrl); + // The icon-state might depend from other roles and hence is // marked as dirty whenever a role has been changed dirtyRoles.insert("iconPixmap"); @@ -705,10 +760,10 @@ void KStandardItemListWidget::editedRoleChanged(const QByteArray& current, const if (m_roleEditor) { emit roleEditingCanceled(index(), current, data().value(current)); - disconnect(m_roleEditor, SIGNAL(roleEditingCanceled(QByteArray,QVariant)), - this, SLOT(slotRoleEditingCanceled(QByteArray,QVariant))); - disconnect(m_roleEditor, SIGNAL(roleEditingFinished(QByteArray,QVariant)), - this, SLOT(slotRoleEditingFinished(QByteArray,QVariant))); + disconnect(m_roleEditor, &KItemListRoleEditor::roleEditingCanceled, + this, &KStandardItemListWidget::slotRoleEditingCanceled); + disconnect(m_roleEditor, &KItemListRoleEditor::roleEditingFinished, + this, &KStandardItemListWidget::slotRoleEditingFinished); if (m_oldRoleEditor) { m_oldRoleEditor->deleteLater(); @@ -743,10 +798,10 @@ void KStandardItemListWidget::editedRoleChanged(const QByteArray& current, const m_roleEditor->setTextCursor(cursor); } - connect(m_roleEditor, SIGNAL(roleEditingCanceled(QByteArray,QVariant)), - this, SLOT(slotRoleEditingCanceled(QByteArray,QVariant))); - connect(m_roleEditor, SIGNAL(roleEditingFinished(QByteArray,QVariant)), - this, SLOT(slotRoleEditingFinished(QByteArray,QVariant))); + connect(m_roleEditor, &KItemListRoleEditor::roleEditingCanceled, + this, &KStandardItemListWidget::slotRoleEditingCanceled); + connect(m_roleEditor, &KItemListRoleEditor::roleEditingFinished, + this, &KStandardItemListWidget::slotRoleEditingFinished); // Adjust the geometry of the editor QRectF rect = roleEditingRect(current); @@ -780,24 +835,34 @@ void KStandardItemListWidget::showEvent(QShowEvent* 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(); + const QUrl itemUrl = data().value("url").toUrl(); m_isCut = clipboard->isCut(itemUrl); - connect(clipboard, SIGNAL(cutItemsChanged()), - this, SLOT(slotCutItemsChanged())); + connect(clipboard, &KFileItemClipboard::cutItemsChanged, + this, &KStandardItemListWidget::slotCutItemsChanged); } void KStandardItemListWidget::hideEvent(QHideEvent* event) { - disconnect(KFileItemClipboard::instance(), SIGNAL(cutItemsChanged()), - this, SLOT(slotCutItemsChanged())); + disconnect(KFileItemClipboard::instance(), &KFileItemClipboard::cutItemsChanged, + this, &KStandardItemListWidget::slotCutItemsChanged); KItemListWidget::hideEvent(event); } +bool KStandardItemListWidget::event(QEvent *event) +{ + if (event->type() == QEvent::WindowDeactivate || event->type() == QEvent::WindowActivate + || event->type() == QEvent::PaletteChange) { + m_dirtyContent = true; + } + + return KItemListWidget::event(event); +} + void KStandardItemListWidget::slotCutItemsChanged() { - const KUrl itemUrl = data().value("url").value(); + const QUrl itemUrl = data().value("url").toUrl(); const bool isCut = KFileItemClipboard::instance()->isCut(itemUrl); if (m_isCut != isCut) { m_isCut = isCut; @@ -896,14 +961,15 @@ void KStandardItemListWidget::updatePixmapCache() if (iconName.isEmpty()) { // The icon-name has not been not resolved by KFileItemModelRolesUpdater, // use a generic icon as fallback - iconName = QLatin1String("unknown"); + iconName = QStringLiteral("unknown"); } const QStringList overlays = values["iconOverlays"].toStringList(); - m_pixmap = pixmapForIcon(iconName, overlays, maxIconHeight); - } else if (m_pixmap.width() != maxIconWidth || m_pixmap.height() != maxIconHeight) { + m_pixmap = pixmapForIcon(iconName, overlays, maxIconHeight, isSelected() && isActiveWindow() ? QIcon::Selected : QIcon::Normal); + + } else if (m_pixmap.width() / m_pixmap.devicePixelRatio() != maxIconWidth || m_pixmap.height() / m_pixmap.devicePixelRatio() != 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)); + KPixmapModifier::scale(m_pixmap, QSize(maxIconWidth, maxIconHeight) * qApp->devicePixelRatio()); } if (m_isCut) { @@ -915,7 +981,7 @@ void KStandardItemListWidget::updatePixmapCache() KIconEffect::semiTransparent(m_pixmap); } - if (isSelected()) { + if (m_layout == IconsLayout && isSelected()) { const QColor color = palette().brush(QPalette::Normal, QPalette::Highlight).color(); QImage image = m_pixmap.toImage(); KIconEffect::colorize(image, color, 0.8f); @@ -1083,14 +1149,24 @@ 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()); - 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(); + qreal elidingWidth = maxWidth; + qreal lastLineWidth; + do { + QString lastTextLine = nameText.mid(line.textStart()); + lastTextLine = m_customizedFontMetrics.elidedText(lastTextLine, + Qt::ElideRight, + elidingWidth); + const QString elidedText = nameText.left(line.textStart()) + lastTextLine; + nameTextInfo->staticText.setText(elidedText); + + lastLineWidth = m_customizedFontMetrics.boundingRect(lastTextLine).width(); + + // We do the text eliding in a loop with decreasing width (1 px / iteration) + // to avoid problems related to different width calculation code paths + // within Qt. (see bug 337104) + elidingWidth -= 1.0; + } while (lastLineWidth > maxWidth); + nameWidth = qMax(nameWidth, lastLineWidth); } break; @@ -1289,9 +1365,10 @@ void KStandardItemListWidget::updateAdditionalInfoTextColor() void KStandardItemListWidget::drawPixmap(QPainter* painter, const QPixmap& pixmap) { - if (m_scaledPixmapSize != pixmap.size()) { + if (m_scaledPixmapSize != pixmap.size() / pixmap.devicePixelRatio()) { QPixmap scaledPixmap = pixmap; - KPixmapModifier::scale(scaledPixmap, m_scaledPixmapSize); + KPixmapModifier::scale(scaledPixmap, m_scaledPixmapSize * qApp->devicePixelRatio()); + scaledPixmap.setDevicePixelRatio(qApp->devicePixelRatio()); painter->drawPixmap(m_pixmapPos, scaledPixmap); #ifdef KSTANDARDITEMLISTWIDGET_DEBUG @@ -1323,7 +1400,7 @@ void KStandardItemListWidget::drawSiblingsInformation(QPainter* painter) if (m_isExpandable) { option.state |= QStyle::State_Children; } - if (data()["isExpanded"].toBool()) { + if (data().value("isExpanded").toBool()) { option.state |= QStyle::State_Open; } isItemSibling = false; @@ -1352,10 +1429,10 @@ 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))); + disconnect(m_roleEditor, &KItemListRoleEditor::roleEditingCanceled, + this, &KStandardItemListWidget::slotRoleEditingCanceled); + disconnect(m_roleEditor, &KItemListRoleEditor::roleEditingFinished, + this, &KStandardItemListWidget::slotRoleEditingFinished); if (m_roleEditor->hasFocus()) { // If the editing was not ended by a FocusOut event, we have @@ -1371,13 +1448,15 @@ void KStandardItemListWidget::closeRoleEditor() m_roleEditor = 0; } -QPixmap KStandardItemListWidget::pixmapForIcon(const QString& name, const QStringList& overlays, int size) +QPixmap KStandardItemListWidget::pixmapForIcon(const QString& name, const QStringList& overlays, int size, QIcon::Mode mode) { - const QString key = "KStandardItemListWidget:" % name % ":" % overlays.join(":") % ":" % QString::number(size); + static const QIcon fallbackIcon = QIcon::fromTheme(QStringLiteral("unknown")); + size *= qApp->devicePixelRatio(); + const QString key = "KStandardItemListWidget:" % name % ":" % overlays.join(QStringLiteral(":")) % ":" % QString::number(size) % ":" % QString::number(mode); QPixmap pixmap; if (!QPixmapCache::find(key, pixmap)) { - const KIcon icon(name); + const QIcon icon = QIcon::fromTheme(name, fallbackIcon); int requestedSize; if (size <= KIconLoader::SizeSmall) { @@ -1398,7 +1477,7 @@ QPixmap KStandardItemListWidget::pixmapForIcon(const QString& name, const QStrin requestedSize = size; } - pixmap = icon.pixmap(requestedSize, requestedSize); + pixmap = icon.pixmap(requestedSize / qApp->devicePixelRatio(), requestedSize / qApp->devicePixelRatio(), mode); if (requestedSize != size) { KPixmapModifier::scale(pixmap, QSize(size, size)); } @@ -1419,6 +1498,7 @@ QPixmap KStandardItemListWidget::pixmapForIcon(const QString& name, const QStrin QPixmapCache::insert(key, pixmap); } + pixmap.setDevicePixelRatio(qApp->devicePixelRatio()); return pixmap; } @@ -1434,4 +1514,3 @@ qreal KStandardItemListWidget::columnPadding(const KItemListStyleOption& option) return option.padding * 6; } -#include "kstandarditemlistwidget.moc"