-/***************************************************************************
- * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
- ***************************************************************************/
+/*
+ * SPDX-FileCopyrightText: 2011 Peter Penz <peter.penz19@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
#include "kfileitemlistwidget.h"
-
+#include "kfileitemlistview.h"
#include "kfileitemmodel.h"
#include "kitemlistview.h"
-#include "kpixmapmodifier_p.h"
-
-#include <KIcon>
-#include <KIconEffect>
-#include <KIconLoader>
-#include <KLocale>
-#include <KStringHandler>
-#include <KDebug>
-
-#include <QFontMetricsF>
-#include <QGraphicsSceneResizeEvent>
-#include <QPainter>
-#include <QStyleOption>
-#include <QTextLayout>
-#include <QTextLine>
-
-//#define KFILEITEMLISTWIDGET_DEBUG
-
-KFileItemListWidget::KFileItemListWidget(QGraphicsItem* parent) :
- KItemListWidget(parent),
- m_isDir(false),
- m_dirtyLayout(true),
- m_dirtyContent(true),
- m_dirtyContentRoles(),
- m_layout(IconsLayout),
- m_pixmapPos(),
- m_pixmap(),
- m_scaledPixmapSize(),
- m_hoverPixmapRect(),
- m_hoverPixmap(),
- m_textPos(),
- m_text(),
- m_textBoundingRect(),
- m_sortedVisibleRoles(),
- m_expansionArea(),
- m_customTextColor(0),
- m_additionalInfoTextColor()
-{
- for (int i = 0; i < TextIdCount; ++i) {
- m_text[i].setTextFormat(Qt::PlainText);
- m_text[i].setPerformanceHint(QStaticText::AggressiveCaching);
- }
-}
-KFileItemListWidget::~KFileItemListWidget()
-{
- delete m_customTextColor;
- m_customTextColor = 0;
-}
+#include "dolphin_detailsmodesettings.h"
+
+#include <KFormat>
+#include <KLocalizedString>
-void KFileItemListWidget::setLayout(Layout layout)
+#include <QGraphicsScene>
+#include <QGraphicsView>
+#include <QMimeDatabase>
+
+KFileItemListWidgetInformant::KFileItemListWidgetInformant()
+ : KStandardItemListWidgetInformant()
{
- if (m_layout != layout) {
- m_layout = layout;
- m_dirtyLayout = true;
- update();
- }
}
-KFileItemListWidget::Layout KFileItemListWidget::layout() const
+KFileItemListWidgetInformant::~KFileItemListWidgetInformant()
{
- return m_layout;
}
-void KFileItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
+QString KFileItemListWidgetInformant::itemText(int index, const KItemListView *view) const
{
- KItemListWidget::paint(painter, option, widget);
+ Q_ASSERT(qobject_cast<KFileItemModel *>(view->model()));
+ KFileItemModel *fileItemModel = static_cast<KFileItemModel *>(view->model());
- const_cast<KFileItemListWidget*>(this)->updateCache();
-
- // Draw expansion toggle '>' or 'V'
- if (m_isDir && !m_expansionArea.isEmpty()) {
- QStyleOption arrowOption;
- arrowOption.rect = m_expansionArea.toRect();
- const QStyle::PrimitiveElement arrow = data()["isExpanded"].toBool()
- ? QStyle::PE_IndicatorArrowDown : QStyle::PE_IndicatorArrowRight;
- style()->drawPrimitive(arrow, &arrowOption, painter);
- }
-
- 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);
- }
-
- const qreal opacity = painter->opacity();
- painter->setOpacity(hoverOpacity() * opacity);
- drawPixmap(painter, m_hoverPixmap);
- painter->setOpacity(opacity);
- } else {
- drawPixmap(painter, m_pixmap);
- }
-
- painter->setFont(itemListStyleOption.font);
- if (m_customTextColor) {
- painter->setPen(*m_customTextColor);
- } else {
- painter->setPen(itemListStyleOption.palette.text().color());
- }
- painter->drawStaticText(m_textPos[Name], m_text[Name]);
-
- painter->setPen(m_additionalInfoTextColor);
- painter->setFont(itemListStyleOption.font);
- for (int i = Name + 1; i < TextIdCount; ++i) {
- painter->drawStaticText(m_textPos[i], m_text[i]);
- }
-
-#ifdef KFILEITEMLISTWIDGET_DEBUG
- painter->setPen(Qt::red);
- painter->setBrush(Qt::NoBrush);
- painter->drawText(QPointF(0, itemListStyleOption.fontMetrics.height()), QString::number(index()));
- painter->drawRect(rect());
-#endif
+ const KFileItem item = fileItemModel->fileItem(index);
+ return item.text();
}
-QRectF KFileItemListWidget::iconBoundingRect() const
+bool KFileItemListWidgetInformant::itemIsLink(int index, const KItemListView *view) const
{
- const_cast<KFileItemListWidget*>(this)->updateCache();
+ Q_ASSERT(qobject_cast<KFileItemModel *>(view->model()));
+ KFileItemModel *fileItemModel = static_cast<KFileItemModel *>(view->model());
- QRectF bounds = m_hoverPixmapRect;
- const qreal margin = styleOption().margin;
- bounds.adjust(-margin, -margin, margin, margin);
- return bounds;
+ const KFileItem item = fileItemModel->fileItem(index);
+ return item.isLink();
}
-QRectF KFileItemListWidget::textBoundingRect() const
+QString KFileItemListWidgetInformant::roleText(const QByteArray &role, const QHash<QByteArray, QVariant> &values) const
{
- const_cast<KFileItemListWidget*>(this)->updateCache();
- return m_textBoundingRect;
-}
+ QString text;
+ const QVariant roleValue = values.value(role);
+ QLocale local;
+ KFormat formatter(local);
-QRectF KFileItemListWidget::expansionToggleRect() const
-{
- const_cast<KFileItemListWidget*>(this)->updateCache();
- return m_isDir ? m_expansionArea : QRectF();
-}
+ // Implementation note: In case if more roles require a custom handling
+ // use a hash + switch for a linear runtime.
-void KFileItemListWidget::setTextColor(const QColor& color)
-{
- if (color.isValid()) {
- if (!m_customTextColor) {
- m_customTextColor = new QColor(color);
+ auto formatDate = [formatter, local](const QDateTime &time) {
+ if (DetailsModeSettings::useShortRelativeDates()) {
+ return formatter.formatRelativeDateTime(time, QLocale::ShortFormat);
} else {
- *m_customTextColor = color;
+ return local.toString(time, QLocale::ShortFormat);
}
- } else {
- delete m_customTextColor;
- m_customTextColor = 0;
- }
- updateAdditionalInfoTextColor();
- update();
-}
-
-QColor KFileItemListWidget::textColor() const
-{
- return m_customTextColor ? *m_customTextColor : styleOption().palette.text().color();
-}
+ };
+
+ if (role == "size") {
+ if (values.value("isDir").toBool()) {
+ if (!roleValue.isNull() && roleValue != -1) {
+ // The item represents a directory.
+ if (DetailsModeSettings::directorySizeCount()) {
+ // Show the number of sub directories instead of the file size of the directory.
+ const int count = values.value("count").toInt();
+ text = i18ncp("@item:intable", "%1 item", "%1 items", count);
+ } else {
+ // if we have directory size available
+ const KIO::filesize_t size = roleValue.value<KIO::filesize_t>();
+ text = formatter.formatByteSize(size);
+ }
+ }
+ } else {
+ const KIO::filesize_t size = roleValue.value<KIO::filesize_t>();
+ text = formatter.formatByteSize(size);
+ }
+ } else if (role == "modificationtime" || role == "creationtime" || role == "accesstime") {
+ bool ok;
+ const long long time = roleValue.toLongLong(&ok);
+ if (ok && time != -1) {
+ const QDateTime dateTime = QDateTime::fromSecsSinceEpoch(time);
+ text = formatDate(dateTime);
+ }
+ } else if (role == "deletiontime" || role == "imageDateTime") {
+ const QDateTime dateTime = roleValue.toDateTime();
+ if (dateTime.isValid()) {
+ text = formatDate(dateTime);
+ }
+ } else if (role == "dimensions") {
+ const auto dimensions = roleValue.toSize();
+ if (dimensions.isValid()) {
+ text = i18nc("width × height", "%1 × %2", dimensions.width(), dimensions.height());
+ }
+ } else if (role == "permissions") {
+ const auto permissions = roleValue.value<QVariantList>();
-void KFileItemListWidget::dataChanged(const QHash<QByteArray, QVariant>& current,
- const QSet<QByteArray>& roles)
-{
- KItemListWidget::dataChanged(current, roles);
- m_dirtyContent = true;
-
- QSet<QByteArray> dirtyRoles;
- if (roles.isEmpty()) {
- dirtyRoles = visibleRoles().keys().toSet();
- dirtyRoles.insert("iconPixmap");
- dirtyRoles.insert("iconName");
+ switch (DetailsModeSettings::usePermissionsFormat()) {
+ case DetailsModeSettings::EnumUsePermissionsFormat::SymbolicFormat:
+ text = permissions.at(0).toString();
+ break;
+ case DetailsModeSettings::EnumUsePermissionsFormat::NumericFormat:
+ text = QString::number(permissions.at(1).toInt(), 8);
+ break;
+ case DetailsModeSettings::EnumUsePermissionsFormat::CombinedFormat:
+ text = QString("%1 (%2)").arg(permissions.at(0).toString()).arg(permissions.at(1).toInt(), 0, 8);
+ break;
+ }
} else {
- dirtyRoles = roles;
+ text = KStandardItemListWidgetInformant::roleText(role, values);
}
- QSetIterator<QByteArray> it(dirtyRoles);
- while (it.hasNext()) {
- const QByteArray& role = it.next();
- m_dirtyContentRoles.insert(role);
- }
+ return text;
}
-void KFileItemListWidget::visibleRolesChanged(const QHash<QByteArray, int>& current,
- const QHash<QByteArray, int>& previous)
+QFont KFileItemListWidgetInformant::customizedFontForLinks(const QFont &baseFont) const
{
- KItemListWidget::visibleRolesChanged(current, previous);
- m_dirtyLayout = true;
-
- // Cache the roles sorted into m_sortedVisibleRoles:
- const int visibleRolesCount = current.count();
- m_sortedVisibleRoles.clear();
- m_sortedVisibleRoles.reserve(visibleRolesCount);
- for (int i = 0; i < visibleRolesCount; ++i) {
- m_sortedVisibleRoles.append(QByteArray());
- }
-
- QHashIterator<QByteArray, int> it(current);
- while (it.hasNext()) {
- it.next();
-
- const int index = it.value();
- if (index < 0 || index >= visibleRolesCount || !m_sortedVisibleRoles.at(index).isEmpty()) {
- kWarning() << "The visible roles have an invalid sort order.";
- break;
- }
-
- const QByteArray& role = it.key();
- m_sortedVisibleRoles[index] = role;
- }
+ // The customized font should be italic if the file is a symbolic link.
+ QFont font(baseFont);
+ font.setItalic(true);
+ return font;
}
-void KFileItemListWidget::visibleRolesSizesChanged(const QHash<QByteArray, QSizeF>& current,
- const QHash<QByteArray, QSizeF>& previous)
+KFileItemListWidget::KFileItemListWidget(KItemListWidgetInformant *informant, QGraphicsItem *parent)
+ : KStandardItemListWidget(informant, parent)
{
- KItemListWidget::visibleRolesSizesChanged(current, previous);
- m_dirtyLayout = true;
}
-void KFileItemListWidget::styleOptionChanged(const KItemListStyleOption& current,
- const KItemListStyleOption& previous)
+KFileItemListWidget::~KFileItemListWidget()
{
- KItemListWidget::styleOptionChanged(current, previous);
- updateAdditionalInfoTextColor();
- m_dirtyLayout = true;
}
-void KFileItemListWidget::hoveredChanged(bool hovered)
+KItemListWidgetInformant *KFileItemListWidget::createInformant()
{
- Q_UNUSED(hovered);
- m_dirtyLayout = true;
+ return new KFileItemListWidgetInformant();
}
-void KFileItemListWidget::resizeEvent(QGraphicsSceneResizeEvent* event)
+bool KFileItemListWidget::isRoleRightAligned(const QByteArray &role) const
{
- KItemListWidget::resizeEvent(event);
- m_dirtyLayout = true;
+ return role == "size" || role == "permissions";
}
-void KFileItemListWidget::updateCache()
+bool KFileItemListWidget::isHidden() const
{
- if ((!m_dirtyContent && !m_dirtyLayout) || index() < 0) {
- return;
- }
-
- m_isDir = data()["isDir"].toBool();
-
- updateExpansionArea();
- updateTextsCache();
- updatePixmapCache();
-
- m_dirtyLayout = false;
- m_dirtyContent = false;
- m_dirtyContentRoles.clear();
+ return data().value("isHidden").toBool();
}
-void KFileItemListWidget::updateExpansionArea()
+QFont KFileItemListWidget::customizedFont(const QFont &baseFont) const
{
- if (m_layout == DetailsLayout) {
- const QHash<QByteArray, QVariant> values = data();
- 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();
- }
+ // The customized font should be italic if the file is a symbolic link.
+ QFont font(baseFont);
+ font.setItalic(data().value("isLink").toBool());
+ return font;
}
-void KFileItemListWidget::updatePixmapCache()
+int KFileItemListWidget::selectionLength(const QString &text) const
{
- // Precondition: Requires already updated m_textPos values to calculate
- // the remaining height when the alignment is vertical.
-
- const bool iconOnTop = (m_layout == IconsLayout);
- const KItemListStyleOption& option = styleOption();
- const int iconHeight = option.iconSize;
+ // Select the text without MIME-type extension
+ int selectionLength = text.length();
- const QHash<QByteArray, QVariant> values = data();
- const QSizeF widgetSize = size();
-
- int scaledIconHeight = 0;
- if (iconOnTop) {
- scaledIconHeight = static_cast<int>(m_textPos[Name].y() - 3 * option.margin);
- } else {
- const int textRowsCount = (m_layout == CompactLayout) ? visibleRoles().count() : 1;
- const qreal requiredTextHeight = textRowsCount * option.fontMetrics.height();
- scaledIconHeight = (requiredTextHeight < iconHeight) ? widgetSize.height() - 2 * option.margin : iconHeight;
+ // If item is a directory, use the whole text length for
+ // selection (ignore all points)
+ if (data().value("isDir").toBool()) {
+ return selectionLength;
}
- bool updatePixmap = (iconHeight != m_pixmap.height());
- if (!updatePixmap && m_dirtyContent) {
- updatePixmap = m_dirtyContentRoles.isEmpty()
- || m_dirtyContentRoles.contains("iconPixmap")
- || m_dirtyContentRoles.contains("iconName");
- }
-
- if (updatePixmap) {
- m_pixmap = values["iconPixmap"].value<QPixmap>();
- if (m_pixmap.isNull()) {
- // Use the icon that fits to the MIME-type
- QString iconName = values["iconName"].toString();
- if (iconName.isEmpty()) {
- // The icon-name has not been not resolved by KFileItemModelRolesUpdater,
- // use a generic icon as fallback
- iconName = QLatin1String("unknown");
- }
- m_pixmap = pixmapForIcon(iconName, iconHeight);
- m_hoverPixmapRect.setSize(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.
- const bool scale = m_pixmap.width() > iconHeight || m_pixmap.height() > iconHeight ||
- (m_pixmap.width() < iconHeight && m_pixmap.height() < iconHeight);
- if (scale) {
- KPixmapModifier::scale(m_pixmap, QSize(iconHeight, iconHeight));
- }
- m_hoverPixmapRect.setSize(m_pixmap.size());
-
- // To simplify the handling of scaling the original pixmap
- // will be embedded into a square pixmap.
- QPixmap squarePixmap(iconHeight, iconHeight);
- 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);
- }
+ QMimeDatabase db;
+ const QString extension = db.suffixForFileName(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('.'));
- m_pixmap = squarePixmap;
- } else {
- m_hoverPixmapRect.setSize(m_pixmap.size());
+ // If no point could be found, use whole text length for selection.
+ if (selectionLength < 1) {
+ selectionLength = text.length();
}
- Q_ASSERT(m_pixmap.height() == iconHeight);
- }
-
- m_scaledPixmapSize = QSize(scaledIconHeight, scaledIconHeight);
-
- if (iconOnTop) {
- m_pixmapPos.setX((widgetSize.width() - m_scaledPixmapSize.width()) / 2);
} else {
- m_pixmapPos.setX(m_textPos[Name].x() - 2 * option.margin - scaledIconHeight);
+ selectionLength -= extension.length() + 1;
}
- 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));
-
- // 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);
- } else {
- m_hoverPixmap = m_pixmap;
- }
- } else if (hoverOpacity() <= 0.0) {
- // No hover animation is ongoing. Clear m_hoverPixmap to save memory.
- m_hoverPixmap = QPixmap();
- }
-}
-
-void KFileItemListWidget::updateTextsCache()
-{
- QTextOption textOption;
- switch (m_layout) {
- case IconsLayout:
- textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
- textOption.setAlignment(Qt::AlignHCenter);
- break;
- case CompactLayout:
- case DetailsLayout:
- textOption.setAlignment(Qt::AlignLeft);
- textOption.setWrapMode(QTextOption::NoWrap);
- break;
- default:
- Q_ASSERT(false);
- break;
- }
-
- for (int i = 0; i < TextIdCount; ++i) {
- m_text[i].setText(QString());
- m_text[i].setTextOption(textOption);
- }
-
- switch (m_layout) {
- case IconsLayout: updateIconsLayoutTextCache(); break;
- case CompactLayout: updateCompactLayoutTextCache(); break;
- case DetailsLayout: updateDetailsLayoutTextCache(); break;
- default: Q_ASSERT(false); break;
- }
-}
-
-void KFileItemListWidget::updateIconsLayoutTextCache()
-{
- // +------+
- // | Icon |
- // +------+
- //
- // Name role that
- // might get wrapped above
- // several lines.
- // Additional role 1
- // Additional role 2
-
- const QHash<QByteArray, QVariant> values = data();
-
- const KItemListStyleOption& option = styleOption();
- const qreal maxWidth = size().width() - 2 * option.margin;
- const qreal widgetHeight = size().height();
- const qreal fontHeight = option.fontMetrics.height();
-
- // Initialize properties for the "name" role. It will be used as anchor
- // for initializing the position of the other roles.
- m_text[Name].setText(KStringHandler::preProcessWrap(values["name"].toString()));
-
- // Calculate the number of lines required for the name and the required width
- int textLinesCountForName = 0;
- qreal requiredWidthForName = 0;
- QTextLine line;
-
- QTextLayout layout(m_text[Name].text(), option.font);
- layout.setTextOption(m_text[Name].textOption());
- layout.beginLayout();
- while ((line = layout.createLine()).isValid()) {
- line.setLineWidth(maxWidth);
- requiredWidthForName = qMax(requiredWidthForName, line.naturalTextWidth());
- ++textLinesCountForName;
- }
- layout.endLayout();
-
- // Use one line for each additional information
- int textLinesCount = textLinesCountForName;
- const int additionalRolesCount = qMax(visibleRoles().count() - 1, 0);
- textLinesCount += additionalRolesCount;
-
- m_text[Name].setTextWidth(maxWidth);
- m_textPos[Name] = QPointF(option.margin, widgetHeight - textLinesCount * fontHeight - option.margin);
- m_textBoundingRect = QRectF(option.margin + (maxWidth - requiredWidthForName) / 2,
- m_textPos[Name].y(),
- requiredWidthForName,
- m_text[Name].size().height());
-
- // Calculate the position for each additional information
- qreal y = m_textPos[Name].y() + textLinesCountForName * fontHeight;
- foreach (const QByteArray& role, m_sortedVisibleRoles) {
- const TextId textId = roleTextId(role);
- if (textId == Name) {
- continue;
- }
-
- const QString text = roleText(textId, values[role]);
- m_text[textId].setText(text);
-
- qreal requiredWidth = 0;
-
- QTextLayout layout(text, option.font);
- layout.setTextOption(m_text[textId].textOption());
- layout.beginLayout();
- QTextLine textLine = layout.createLine();
- if (textLine.isValid()) {
- textLine.setLineWidth(maxWidth);
- requiredWidth = textLine.naturalTextWidth();
- if (textLine.textLength() < text.length()) {
- // TODO: QFontMetrics::elidedText() works different regarding the given width
- // in comparison to QTextLine::setLineWidth(). It might happen that the text does
- // not get elided although it does not fit into the given width. As workaround
- // the margin is substracted.
- const QString elidedText = option.fontMetrics.elidedText(text, Qt::ElideRight, maxWidth - option.margin);
- m_text[textId].setText(elidedText);
- }
- }
- layout.endLayout();
- m_textPos[textId] = QPointF(option.margin, y);
- m_text[textId].setTextWidth(maxWidth);
-
- const QRectF textBoundingRect(option.margin + (maxWidth - requiredWidth) / 2, y, requiredWidth, fontHeight);
- m_textBoundingRect |= textBoundingRect;
-
- y += fontHeight;
- }
-
- // Add a margin to the text bounding rectangle
- const qreal margin = option.margin;
- m_textBoundingRect.adjust(-margin, -margin, margin, margin);
+ return selectionLength;
}
-void KFileItemListWidget::updateCompactLayoutTextCache()
+void KFileItemListWidget::hoverSequenceStarted()
{
- // +------+ Name role
- // | Icon | Additional role 1
- // +------+ Additional role 2
-
- const QHash<QByteArray, QVariant> values = data();
-
- const KItemListStyleOption& option = styleOption();
- const qreal widgetHeight = size().height();
- const qreal fontHeight = option.fontMetrics.height();
- const qreal textLinesHeight = qMax(visibleRoles().count(), 1) * fontHeight;
- const int scaledIconSize = (textLinesHeight < option.iconSize) ? widgetHeight - 2 * option.margin : option.iconSize;
-
- qreal maximumRequiredTextWidth = 0;
- const qreal x = option.margin * 3 + scaledIconSize;
- qreal y = (widgetHeight - textLinesHeight) / 2;
- const qreal maxWidth = size().width() - x - option.margin;
- foreach (const QByteArray& role, m_sortedVisibleRoles) {
- const TextId textId = roleTextId(role);
-
- const QString text = roleText(textId, values[role]);
- m_text[textId].setText(text);
-
- qreal requiredWidth = option.fontMetrics.width(text);
- if (requiredWidth > maxWidth) {
- requiredWidth = maxWidth;
- const QString elidedText = option.fontMetrics.elidedText(text, Qt::ElideRight, maxWidth);
- m_text[textId].setText(elidedText);
- }
+ KFileItemListView *view = listView();
- m_textPos[textId] = QPointF(x, y);
- m_text[textId].setTextWidth(maxWidth);
-
- maximumRequiredTextWidth = qMax(maximumRequiredTextWidth, requiredWidth);
-
- y += fontHeight;
+ if (!view) {
+ return;
}
- m_textBoundingRect = QRectF(x - option.margin, 0, maximumRequiredTextWidth + 2 * option.margin, widgetHeight);
-}
-
-void KFileItemListWidget::updateDetailsLayoutTextCache()
-{
- // Precondition: Requires already updated m_expansionArea
- // to determine the left position.
-
- // +------+
- // | Icon | Name role Additional role 1 Additional role 2
- // +------+
- m_textBoundingRect = QRectF();
-
- const KItemListStyleOption& option = styleOption();
- const QHash<QByteArray, QVariant> values = data();
-
- const qreal widgetHeight = size().height();
- const int scaledIconSize = widgetHeight - 2 * option.margin;
- const int fontHeight = option.fontMetrics.height();
-
- qreal x = m_expansionArea.right() + option.margin * 3 + scaledIconSize;
- const qreal y = qMax(qreal(option.margin), (widgetHeight - fontHeight) / 2);
-
- foreach (const QByteArray& role, m_sortedVisibleRoles) {
- const TextId textId = roleTextId(role);
-
- const QString text = roleText(textId, values[role]);
- m_text[textId].setText(text);
-
- const qreal requiredWidth = option.fontMetrics.width(text);
- m_textPos[textId] = QPointF(x, y);
-
- const qreal columnWidth = visibleRolesSizes().value(role, QSizeF(0, 0)).width();
- x += columnWidth;
+ const QUrl itemUrl = data().value("url").toUrl();
- switch (textId) {
- case Name: {
- m_textBoundingRect = QRectF(m_textPos[textId].x() - option.margin, 0,
- requiredWidth + 2 * option.margin, 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
- x -= m_expansionArea.right();
- break;
- }
- case Size:
- // The values for the size should be right aligned
- m_textPos[textId].rx() += columnWidth - requiredWidth - 2 * option.margin;
- break;
-
- default:
- break;
- }
- }
+ view->setHoverSequenceState(itemUrl, 0);
}
-void KFileItemListWidget::updateAdditionalInfoTextColor()
+void KFileItemListWidget::hoverSequenceIndexChanged(int sequenceIndex)
{
- // 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 = m_customTextColor ? *m_customTextColor : styleOption().palette.text().color();
- const QColor c2 = styleOption().palette.background().color();
- const int p1 = 70;
- const int p2 = 100 - p1;
- m_additionalInfoTextColor = QColor((c1.red() * p1 + c2.red() * p2) / 100,
- (c1.green() * p1 + c2.green() * p2) / 100,
- (c1.blue() * p1 + c2.blue() * p2) / 100);
-}
-
-QString KFileItemListWidget::roleText(TextId textId, const QVariant& roleValue) const
-{
- QString text;
-
- switch (textId) {
- case Name:
- case Permissions:
- case Owner:
- case Group:
- case Type:
- case Destination:
- case Path:
- text = roleValue.toString();
- break;
-
- case Size: {
- if (data().value("isDir").toBool()) {
- // The item represents a directory. Show the number of sub directories
- // instead of the file size of the directory.
- if (!roleValue.isNull()) {
- const KIO::filesize_t size = roleValue.value<KIO::filesize_t>();
- text = i18ncp("@item:intable", "%1 item", "%1 items", size);
- }
- } else {
- const KIO::filesize_t size = roleValue.value<KIO::filesize_t>();
- text = KIO::convertSize(size);
- }
- break;
- }
-
- case Date: {
- const QDateTime dateTime = roleValue.toDateTime();
- text = KGlobal::locale()->formatDateTime(dateTime);
- break;
- }
+ KFileItemListView *view = listView();
- default:
- Q_ASSERT(false);
- break;
+ if (!view) {
+ return;
}
- return text;
-}
-
-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);
- }
+ const QUrl itemUrl = data().value("url").toUrl();
- if (m_scaledPixmapSize != pixmap.size()) {
- QPixmap scaledPixmap = pixmap;
- KPixmapModifier::scale(scaledPixmap, m_scaledPixmapSize);
- painter->drawPixmap(m_pixmapPos, scaledPixmap);
+ view->setHoverSequenceState(itemUrl, sequenceIndex);
-#ifdef KFILEITEMLISTWIDGET_DEBUG
- painter->setPen(Qt::green);
- painter->drawRect(QRectF(m_pixmapPos, QSizeF(scaledPixmap.size())));
-#endif
- } else {
- painter->drawPixmap(m_pixmapPos, pixmap);
- }
-
- if (isHiddenItem) {
- painter->setOpacity(opacity);
- }
+ // Force-update the displayed icon
+ invalidateIconCache();
+ update();
}
-QPixmap KFileItemListWidget::pixmapForIcon(const QString& name, int size)
+void KFileItemListWidget::hoverSequenceEnded()
{
- 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;
- }
+ KFileItemListView *view = listView();
- QPixmap pixmap = icon.pixmap(requestedSize, requestedSize);
- if (requestedSize != size) {
- KPixmapModifier::scale(pixmap, QSize(size, size));
+ if (!view) {
+ return;
}
- return pixmap;
+ view->setHoverSequenceState(QUrl(), 0);
}
-KFileItemListWidget::TextId KFileItemListWidget::roleTextId(const QByteArray& role)
+KFileItemListView *KFileItemListWidget::listView()
{
- static QHash<QByteArray, TextId> rolesHash;
- if (rolesHash.isEmpty()) {
- rolesHash.insert("name", Name);
- rolesHash.insert("size", Size);
- rolesHash.insert("date", Date);
- rolesHash.insert("permissions", Permissions);
- rolesHash.insert("owner", Owner);
- rolesHash.insert("group", Group);
- rolesHash.insert("type", Type);
- rolesHash.insert("destination", Destination);
- rolesHash.insert("path", Path);
- }
-
- return rolesHash.value(role);
+ return dynamic_cast<KFileItemListView *>(parentItem());
}
-
-#include "kfileitemlistwidget.moc"