-#include <KIcon>
-#include <KIconEffect>
-#include <KIconLoader>
-#include <KLocale>
-#include <kratingpainter.h>
-#include <KStringHandler>
-#include <KDebug>
-
-#include "private/kfileitemclipboard.h"
-#include "private/kpixmapmodifier.h"
-
-#include <QFontMetricsF>
-#include <QGraphicsSceneResizeEvent>
-#include <QPainter>
-#include <QStyleOption>
-#include <QTextLayout>
-#include <QTextLine>
-
-// #define KFILEITEMLISTWIDGET_DEBUG
-
-KFileItemListWidget::KFileItemListWidget(QGraphicsItem* parent) :
- KItemListWidget(parent),
- m_isCut(false),
- m_isHidden(false),
- m_isExpandable(false),
- m_supportsItemExpanding(false),
- m_dirtyLayout(true),
- m_dirtyContent(true),
- m_dirtyContentRoles(),
- m_layout(IconsLayout),
- m_pixmapPos(),
- m_pixmap(),
- m_scaledPixmapSize(),
- m_iconRect(),
- m_hoverPixmap(),
- m_textInfo(),
- m_textRect(),
- m_sortedVisibleRoles(),
- m_expansionArea(),
- m_customTextColor(),
- m_additionalInfoTextColor(),
- m_overlay(),
- m_rating()
-{
-}
-
-KFileItemListWidget::~KFileItemListWidget()
-{
- qDeleteAll(m_textInfo);
- m_textInfo.clear();
-}
-
-void KFileItemListWidget::setLayout(Layout layout)
-{
- if (m_layout != layout) {
- m_layout = layout;
- m_dirtyLayout = true;
- updateAdditionalInfoTextColor();
- update();
- }
-}
-
-KFileItemListWidget::Layout KFileItemListWidget::layout() const
-{
- return m_layout;
-}
-
-void KFileItemListWidget::setSupportsItemExpanding(bool supportsItemExpanding)
-{
- if (m_supportsItemExpanding != supportsItemExpanding) {
- m_supportsItemExpanding = supportsItemExpanding;
- m_dirtyLayout = true;
- update();
- }
-}
-
-bool KFileItemListWidget::supportsItemExpanding() const
-{
- return m_supportsItemExpanding;
-}
-
-void KFileItemListWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
-{
- const_cast<KFileItemListWidget*>(this)->triggerCacheRefreshing();
-
- KItemListWidget::paint(painter, option, widget);
-
- if (!m_expansionArea.isEmpty()) {
- drawSiblingsInformation(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);
- painter->setPen(textColor());
- const TextInfo* textInfo = m_textInfo.value("name");
- painter->drawStaticText(textInfo->pos, textInfo->staticText);
-
- bool clipAdditionalInfoBounds = false;
- if (m_supportsItemExpanding) {
- // Prevent a possible overlapping of the additional-information texts
- // with the icon. This can happen if the user has minimized the width
- // of the name-column to a very small value.
- const qreal minX = m_pixmapPos.x() + m_pixmap.width() + 4 * itemListStyleOption.padding;
- if (textInfo->pos.x() + columnWidth("name") > minX) {
- clipAdditionalInfoBounds = true;
- painter->save();
- painter->setClipRect(minX, 0, size().width() - minX, size().height(), Qt::IntersectClip);
- }
- }
-
- painter->setPen(m_additionalInfoTextColor);
- painter->setFont(itemListStyleOption.font);
-
- for (int i = 1; i < m_sortedVisibleRoles.count(); ++i) {
- const TextInfo* textInfo = m_textInfo.value(m_sortedVisibleRoles[i]);
- painter->drawStaticText(textInfo->pos, textInfo->staticText);
- }
-
- if (!m_rating.isNull()) {
- const TextInfo* ratingTextInfo = m_textInfo.value("rating");
- QPointF pos = ratingTextInfo->pos;
- const Qt::Alignment align = ratingTextInfo->staticText.textOption().alignment();
- if (align & Qt::AlignHCenter) {
- pos.rx() += (size().width() - m_rating.width()) / 2;
- }
- painter->drawPixmap(pos, m_rating);
- }
-
- if (clipAdditionalInfoBounds) {
- painter->restore();
- }
-
-#ifdef KFILEITEMLISTWIDGET_DEBUG
- 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
-}
-
-QRectF KFileItemListWidget::iconRect() const
-{
- const_cast<KFileItemListWidget*>(this)->triggerCacheRefreshing();
- return m_iconRect;
-}
-
-QRectF KFileItemListWidget::textRect() const
-{
- const_cast<KFileItemListWidget*>(this)->triggerCacheRefreshing();
- return m_textRect;
-}
-
-QRectF KFileItemListWidget::textFocusRect() const
-{
- // In the compact- and details-layout a larger textRect() is returned to be aligned
- // with the iconRect(). This is useful to have a larger selection/hover-area
- // when having a quite large icon size but only one line of text. Still the
- // focus rectangle should be shown as narrow as possible around the text.
-
- const_cast<KFileItemListWidget*>(this)->triggerCacheRefreshing();
-
- switch (m_layout) {
- case CompactLayout: {
- QRectF rect = m_textRect;
- const TextInfo* topText = m_textInfo.value(m_sortedVisibleRoles.first());
- const TextInfo* bottomText = m_textInfo.value(m_sortedVisibleRoles.last());
- rect.setTop(topText->pos.y());
- rect.setBottom(bottomText->pos.y() + bottomText->staticText.size().height());
- return rect;
- }
-
- case DetailsLayout: {
- QRectF rect = m_textRect;
- const TextInfo* textInfo = m_textInfo.value(m_sortedVisibleRoles.first());
- rect.setTop(textInfo->pos.y());
- rect.setBottom(textInfo->pos.y() + textInfo->staticText.size().height());
- return rect;
- }
-
- default:
- break;
- }
-
- return m_textRect;
-}
-
-QRectF KFileItemListWidget::expansionToggleRect() const
-{
- const_cast<KFileItemListWidget*>(this)->triggerCacheRefreshing();
- return m_isExpandable ? m_expansionArea : QRectF();
-}
-
-QRectF KFileItemListWidget::selectionToggleRect() const
-{
- const_cast<KFileItemListWidget*>(this)->triggerCacheRefreshing();
-
- const int iconHeight = styleOption().iconSize;
-
- 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) {
- pos.rx() -= (widgetHeight - toggleSize) / 2;
- toggleSize = widgetHeight;
- pos.setY(0);
- }
- if (toggleSize + minMargin * 2 >= widgetWidth) {
- pos.ry() -= (widgetWidth - toggleSize) / 2;
- toggleSize = widgetWidth;
- pos.setX(0);
- }
-
- return QRectF(pos, QSizeF(toggleSize, toggleSize));
-}
-
-QSizeF KFileItemListWidget::itemSizeHint(int index, const KItemListView* view)
-{
- const QHash<QByteArray, QVariant> values = view->model()->data(index);
- const KItemListStyleOption& option = view->styleOption();
- const int additionalRolesCount = qMax(view->visibleRoles().count() - 1, 0);
-
- switch (static_cast<const KFileItemListView*>(view)->itemLayout()) {
- case IconsLayout: {
- const QString text = KStringHandler::preProcessWrap(values["name"].toString());
-
- const qreal maxWidth = view->itemSize().width() - 2 * option.padding;
- QTextLine line;
-
- // Calculate the number of lines required for wrapping the name
- QTextOption textOption(Qt::AlignHCenter);
- textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
-
- qreal textHeight = 0;
- QTextLayout layout(text, option.font);
- layout.setTextOption(textOption);
- layout.beginLayout();
- while ((line = layout.createLine()).isValid()) {
- line.setLineWidth(maxWidth);
- line.naturalTextWidth();
- textHeight += line.height();
- }
- layout.endLayout();
-
- // Add one line for each additional information
- const qreal height = textHeight +
- additionalRolesCount * option.fontMetrics.lineSpacing() +
- option.iconSize +
- option.padding * 3;
- return QSizeF(view->itemSize().width(), height);
- }
-
- case CompactLayout: {
- // 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;
-
- foreach (const QByteArray& role, view->visibleRoles()) {
- const QString text = KFileItemListWidget::roleText(role, values);
- const qreal requiredWidth = option.fontMetrics.width(text);
- maximumRequiredWidth = qMax(maximumRequiredWidth, requiredWidth);
- }
-
- const qreal width = option.padding * 4 + option.iconSize + maximumRequiredWidth;
- const qreal height = option.padding * 2 + qMax(option.iconSize, (1 + additionalRolesCount) * option.fontMetrics.lineSpacing());
- return QSizeF(width, height);
- }
-
- case DetailsLayout: {
- const qreal height = option.padding * 2 + qMax(option.iconSize, option.fontMetrics.height());
- return QSizeF(-1, height);
- }
-
- default:
- Q_ASSERT(false);
- break;
- }
-
- return QSize();
-}
-
-qreal KFileItemListWidget::preferredRoleColumnWidth(const QByteArray& role,
- int index,
- const KItemListView* view)
-{