#include <QStyleOption>
#include <QTextLayout>
#include <QTextLine>
+#include <QPixmapCache>
// #define KSTANDARDITEMLISTWIDGET_DEBUG
{
}
-QSizeF KStandardItemListWidgetInformant::itemSizeHint(int index, const KItemListView* view) const
+void KStandardItemListWidgetInformant::calculateItemSizeHints(QVector<qreal>& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const
{
- 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 KStandardItemListView*>(view)->itemLayout()) {
- case KStandardItemListWidget::IconsLayout: {
- const QString text = KStringHandler::preProcessWrap(values["text"].toString());
-
- const qreal itemWidth = view->itemSize().width();
- const qreal maxWidth = itemWidth - 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
- textHeight += additionalRolesCount * option.fontMetrics.lineSpacing();
-
- const qreal maxTextHeight = option.maxTextSize.height();
- if (maxTextHeight > 0 && textHeight > maxTextHeight) {
- textHeight = maxTextHeight;
- }
-
- return QSizeF(itemWidth, textHeight + option.iconSize + option.padding * 3);
- }
-
- case KStandardItemListWidget::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 = roleText(role, values);
- const qreal requiredWidth = option.fontMetrics.width(text);
- maximumRequiredWidth = qMax(maximumRequiredWidth, requiredWidth);
- }
+ case KStandardItemListWidget::IconsLayout:
+ calculateIconsLayoutItemSizeHints(logicalHeightHints, logicalWidthHint, view);
+ break;
- qreal width = option.padding * 4 + option.iconSize + maximumRequiredWidth;
- const qreal maxWidth = option.maxTextSize.width();
- if (maxWidth > 0 && width > maxWidth) {
- width = maxWidth;
- }
- const qreal height = option.padding * 2 + qMax(option.iconSize, (1 + additionalRolesCount) * option.fontMetrics.lineSpacing());
- return QSizeF(width, height);
- }
+ case KStandardItemListWidget::CompactLayout:
+ calculateCompactLayoutItemSizeHints(logicalHeightHints, logicalWidthHint, view);
+ break;
- case KStandardItemListWidget::DetailsLayout: {
- const qreal height = option.padding * 2 + qMax(option.iconSize, option.fontMetrics.height());
- return QSizeF(-1, height);
- }
+ case KStandardItemListWidget::DetailsLayout:
+ calculateDetailsLayoutItemSizeHints(logicalHeightHints, logicalWidthHint, view);
+ break;
default:
Q_ASSERT(false);
break;
}
-
- return QSize();
}
qreal KStandardItemListWidgetInformant::preferredRoleColumnWidth(const QByteArray& role,
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;
}
return width;
}
+QString KStandardItemListWidgetInformant::itemText(int index, const KItemListView* view) const
+{
+ return view->model()->data(index).value("text").toString();
+}
+
+bool KStandardItemListWidgetInformant::itemIsLink(int index, const KItemListView* view) const
+{
+ return false;
+}
+
QString KStandardItemListWidgetInformant::roleText(const QByteArray& role,
const QHash<QByteArray, QVariant>& values) const
{
return values.value(role).toString();
}
+QFont KStandardItemListWidgetInformant::customizedFontForLinks(const QFont& baseFont) const
+{
+ return baseFont;
+}
+
+void KStandardItemListWidgetInformant::calculateIconsLayoutItemSizeHints(QVector<qreal>& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const
+{
+ const KItemListStyleOption& option = view->styleOption();
+ const QFont& normalFont = option.font;
+ const int additionalRolesCount = qMax(view->visibleRoles().count() - 1, 0);
+
+ const qreal itemWidth = view->itemSize().width();
+ const qreal maxWidth = itemWidth - 2 * option.padding;
+ 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 < 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
+ qreal textHeight = 0;
+ QTextLayout layout(text, font);
+ layout.setTextOption(textOption);
+ layout.beginLayout();
+ QTextLine line;
+ int lineCount = 0;
+ while ((line = layout.createLine()).isValid()) {
+ line.setLineWidth(maxWidth);
+ line.naturalTextWidth();
+ textHeight += line.height();
+
+ ++lineCount;
+ if (lineCount == option.maxTextLines) {
+ break;
+ }
+ }
+ layout.endLayout();
+
+ // Add one line for each additional information
+ textHeight += additionalRolesSpacing;
+
+ logicalHeightHints[index] = textHeight + spacingAndIconHeight;
+ }
+
+ logicalWidthHint = itemWidth;
+}
+
+void KStandardItemListWidgetInformant::calculateCompactLayoutItemSizeHints(QVector<qreal>& logicalHeightHints, qreal& logicalWidthHint, const KItemListView* view) const
+{
+ const KItemListStyleOption& option = view->styleOption();
+ const QFontMetrics& normalFontMetrics = option.fontMetrics;
+ const int additionalRolesCount = qMax(view->visibleRoles().count() - 1, 0);
+
+ const QList<QByteArray>& 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) * normalFontMetrics.lineSpacing());
+
+ 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;
+
+ if (showOnlyTextRole) {
+ maximumRequiredWidth = fontMetrics.width(itemText(index, view));
+ } else {
+ const QHash<QByteArray, QVariant>& values = view->model()->data(index);
+ foreach (const QByteArray& role, visibleRoles) {
+ const QString& text = roleText(role, values);
+ const qreal requiredWidth = fontMetrics.width(text);
+ maximumRequiredWidth = qMax(maximumRequiredWidth, requiredWidth);
+ }
+ }
+
+ qreal width = paddingAndIconWidth + maximumRequiredWidth;
+ if (maxWidth > 0 && width > maxWidth) {
+ width = maxWidth;
+ }
+
+ logicalHeightHints[index] = width;
+ }
+
+ logicalWidthHint = height;
+}
+
+void KStandardItemListWidgetInformant::calculateDetailsLayoutItemSizeHints(QVector<qreal>& 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);
+ logicalWidthHint = -1.0;
+}
+
KStandardItemListWidget::KStandardItemListWidget(KItemListWidgetInformant* informant, QGraphicsItem* parent) :
KItemListWidget(informant, parent),
m_isCut(false),
m_additionalInfoTextColor(),
m_overlay(),
m_rating(),
- m_roleEditor(0)
+ m_roleEditor(0),
+ m_oldRoleEditor(0)
{
}
qDeleteAll(m_textInfo);
m_textInfo.clear();
- delete m_roleEditor;
+ if (m_roleEditor) {
+ m_roleEditor->deleteLater();
+ }
+
+ if (m_oldRoleEditor) {
+ m_oldRoleEditor->deleteLater();
+ }
}
void KStandardItemListWidget::setLayout(Layout layout)
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);
- }
+ /*
+ * Linear interpolation between m_pixmap and m_hoverPixmap.
+ *
+ * Note that this cannot be achieved by painting m_hoverPixmap over
+ * m_pixmap, even if the opacities are adjusted. For details see
+ * https://git.reviewboard.kde.org/r/109614/
+ */
+ // Paint pixmap1 so that pixmap1 = m_pixmap * (1.0 - hoverOpacity())
+ QPixmap pixmap1(m_pixmap.size());
+ pixmap1.fill(Qt::transparent);
+ {
+ QPainter p(&pixmap1);
+ p.setOpacity(1.0 - hoverOpacity());
+ p.drawPixmap(0, 0, m_pixmap);
+ }
+
+ // Paint pixmap2 so that pixmap2 = m_hoverPixmap * hoverOpacity()
+ QPixmap pixmap2(pixmap1.size());
+ pixmap2.fill(Qt::transparent);
+ {
+ QPainter p(&pixmap2);
+ p.setOpacity(hoverOpacity());
+ p.drawPixmap(0, 0, m_hoverPixmap);
+ }
+
+ // Paint pixmap2 on pixmap1 using CompositionMode_Plus
+ // Now pixmap1 = pixmap2 + m_pixmap * (1.0 - hoverOpacity())
+ // = m_hoverPixmap * hoverOpacity() + m_pixmap * (1.0 - hoverOpacity())
+ {
+ QPainter p(&pixmap1);
+ p.setCompositionMode(QPainter::CompositionMode_Plus);
+ p.drawPixmap(0, 0, pixmap2);
+ }
- const qreal opacity = painter->opacity();
- painter->setOpacity(hoverOpacity() * opacity);
- drawPixmap(painter, m_hoverPixmap);
- painter->setOpacity(opacity);
+ // Finally paint pixmap1 on the widget
+ drawPixmap(painter, pixmap1);
+ } else {
+ drawPixmap(painter, m_hoverPixmap);
+ }
} else {
drawPixmap(painter, m_pixmap);
}
painter->setFont(m_customizedFont);
- painter->setPen(m_isHidden ? m_additionalInfoTextColor : textColor());
+ painter->setPen(textColor());
const TextInfo* textInfo = m_textInfo.value("text");
+
+ if (!textInfo) {
+ // It seems that we can end up here even if m_textInfo does not contain
+ // the key "text", see bug 306167. According to triggerCacheRefreshing(),
+ // this can only happen if the index is negative. This can happen when
+ // the item is about to be removed, see KItemListView::slotItemsRemoved().
+ // TODO: try to reproduce the crash and find a better fix.
+ return;
+ }
+
painter->drawStaticText(textInfo->pos, textInfo->staticText);
bool clipAdditionalInfoBounds = false;
QPointF pos = ratingTextInfo->pos;
const Qt::Alignment align = ratingTextInfo->staticText.textOption().alignment();
if (align & Qt::AlignHCenter) {
- pos.rx() += (size().width() - m_rating.width()) / 2;
+ pos.rx() += (size().width() - m_rating.width()) / 2 - 2;
}
painter->drawPixmap(pos, m_rating);
}
painter->setPen(Qt::green);
painter->drawRect(m_iconRect);
+ painter->setPen(Qt::blue);
+ painter->drawRect(m_textRect);
+
painter->setPen(Qt::red);
painter->drawText(QPointF(0, m_customizedFontMetrics.height()), QString::number(index()));
painter->drawRect(rect());
return m_textRect;
}
+QRectF KStandardItemListWidget::selectionRect() const
+{
+ const_cast<KStandardItemListWidget*>(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<KStandardItemListWidget*>(this)->triggerCacheRefreshing();
return baseFont;
}
+QPalette::ColorRole KStandardItemListWidget::normalTextColorRole() const
+{
+ return QPalette::Text;
+}
+
void KStandardItemListWidget::setTextColor(const QColor& color)
{
if (color != m_customTextColor) {
QColor KStandardItemListWidget::textColor() const
{
- if (m_customTextColor.isValid() && !isSelected()) {
- return m_customTextColor;
+ if (!isSelected()) {
+ if (m_isHidden) {
+ return m_additionalInfoTextColor;
+ } else if (m_customTextColor.isValid()) {
+ 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();
+ const QPalette::ColorRole role = isSelected() ? QPalette::HighlightedText : normalTextColorRole();
+ return styleOption().palette.color(group, role);
}
void KStandardItemListWidget::setOverlay(const QPixmap& overlay)
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 KUrl itemUrl = data().value("url").value<KUrl>();
+ 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");
m_dirtyLayout = true;
}
+int KStandardItemListWidget::selectionLength(const QString& text) const
+{
+ return text.length();
+}
+
void KStandardItemListWidget::editedRoleChanged(const QByteArray& current, const QByteArray& previous)
{
Q_UNUSED(previous);
- QGraphicsView* parent = scene()->views()[0];
- if (current.isEmpty() || !parent || current != "text") {
+ QGraphicsView* parent = scene()->views()[0];
+ if (current.isEmpty() || !parent || current != "text") {
if (m_roleEditor) {
emit roleEditingCanceled(index(), current, data().value(current));
- m_roleEditor->deleteLater();
+
+ disconnect(m_roleEditor, &KItemListRoleEditor::roleEditingCanceled,
+ this, &KStandardItemListWidget::slotRoleEditingCanceled);
+ disconnect(m_roleEditor, &KItemListRoleEditor::roleEditingFinished,
+ this, &KStandardItemListWidget::slotRoleEditingFinished);
+
+ if (m_oldRoleEditor) {
+ m_oldRoleEditor->deleteLater();
+ }
+ m_oldRoleEditor = m_roleEditor;
+ m_roleEditor->hide();
m_roleEditor = 0;
}
return;
const TextInfo* textInfo = m_textInfo.value("text");
m_roleEditor = new KItemListRoleEditor(parent);
- m_roleEditor->setIndex(index());
m_roleEditor->setRole(current);
m_roleEditor->setFont(styleOption().font);
QTextOption textOption = textInfo->staticText.textOption();
m_roleEditor->document()->setDefaultTextOption(textOption);
- // Select the text without MIME-type extension
- // TODO: This is file-item-specific and should be moved
- // into KFileItemListWidget.
- int selectionLength = text.length();
-
- const QString extension = KMimeType::extractKnownExtension(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('.'));
- } else {
- selectionLength -= extension.length() + 1;
- }
+ const int textSelectionLength = selectionLength(text);
- if (selectionLength > 0) {
+ if (textSelectionLength > 0) {
QTextCursor cursor = m_roleEditor->textCursor();
cursor.movePosition(QTextCursor::StartOfBlock);
- cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, selectionLength);
+ cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, textSelectionLength);
m_roleEditor->setTextCursor(cursor);
}
- connect(m_roleEditor, SIGNAL(roleEditingCanceled(int,QByteArray,QVariant)),
- this, SLOT(slotRoleEditingCanceled(int,QByteArray,QVariant)));
- connect(m_roleEditor, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)),
- this, SLOT(slotRoleEditingFinished(int,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);
const KUrl itemUrl = data().value("url").value<KUrl>();
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);
}
}
}
-void KStandardItemListWidget::slotRoleEditingCanceled(int index,
- const QByteArray& role,
+void KStandardItemListWidget::slotRoleEditingCanceled(const QByteArray& role,
const QVariant& value)
{
closeRoleEditor();
- emit roleEditingCanceled(index, role, value);
+ emit roleEditingCanceled(index(), role, value);
setEditedRole(QByteArray());
}
-void KStandardItemListWidget::slotRoleEditingFinished(int index,
- const QByteArray& role,
+void KStandardItemListWidget::slotRoleEditingFinished(const QByteArray& role,
const QVariant& value)
{
closeRoleEditor();
- emit roleEditingFinished(index, role, value);
+ emit roleEditingFinished(index(), role, value);
setEditedRole(QByteArray());
}
{
if (m_supportsItemExpanding) {
const QHash<QByteArray, QVariant> values = data();
- Q_ASSERT(values.contains("expandedParentsCount"));
const int expandedParentsCount = values.value("expandedParentsCount", 0).toInt();
if (expandedParentsCount >= 0) {
+ const KItemListStyleOption& option = styleOption();
const qreal widgetHeight = size().height();
- const qreal inc = (widgetHeight - KIconLoader::SizeSmall) / 2;
+ const qreal inc = (widgetHeight - option.iconSize) / 2;
const qreal x = expandedParentsCount * widgetHeight + inc;
const qreal y = inc;
- m_expansionArea = QRectF(x, y, KIconLoader::SizeSmall, KIconLoader::SizeSmall);
+ m_expansionArea = QRectF(x, y, option.iconSize, option.iconSize);
return;
}
}
// use a generic icon as fallback
iconName = QLatin1String("unknown");
}
- m_pixmap = pixmapForIcon(iconName, maxIconHeight);
+ const QStringList overlays = values["iconOverlays"].toStringList();
+ m_pixmap = pixmapForIcon(iconName, overlays, maxIconHeight);
} else if (m_pixmap.width() != maxIconWidth || m_pixmap.height() != 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));
}
- 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) {
KIconEffect* effect = KIconLoader::global()->iconEffect();
m_pixmap = effect->apply(m_pixmap, KIconLoader::Desktop, KIconLoader::DisabledState);
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, 1.0f);
+ KIconEffect::colorize(image, color, 0.8f);
m_pixmap = QPixmap::fromImage(image);
}
}
const qreal availableWidth = (m_layout == DetailsLayout)
? columnWidth("rating") - columnPadding(option)
- : m_textRect.width();
+ : size().width();
if (ratingSize.width() > availableWidth) {
ratingSize.rwidth() = availableWidth;
}
qreal nameHeight = 0;
QTextLine line;
- const int additionalRolesCount = qMax(visibleRoles().count() - 1, 0);
- const int maxNameLines = (option.maxTextSize.height() / int(lineSpacing)) - additionalRolesCount;
-
QTextLayout layout(nameTextInfo->staticText.text(), m_customizedFont);
layout.setTextOption(nameTextInfo->staticText.textOption());
layout.beginLayout();
nameHeight += line.height();
++nameLineIndex;
- if (nameLineIndex == maxNameLines) {
+ if (nameLineIndex == option.maxTextLines) {
// The maximum number of textlines has been reached. If this is
// the case provide an elided text if necessary.
const int textLength = line.textStart() + line.textLength();
if (textLength < nameText.length()) {
// Elide the last line of the text
- QString lastTextLine = nameText.mid(line.textStart(), line.textLength());
+ QString lastTextLine = nameText.mid(line.textStart());
lastTextLine = m_customizedFontMetrics.elidedText(lastTextLine,
Qt::ElideRight,
- line.naturalTextWidth() - 1);
+ maxWidth);
const QString elidedText = nameText.left(line.textStart()) + lastTextLine;
nameTextInfo->staticText.setText(elidedText);
+
+ const qreal lastLineWidth = m_customizedFontMetrics.boundingRect(lastTextLine).width();
+ nameWidth = qMax(nameWidth, lastLineWidth);
}
break;
}
layout.endLayout();
// Use one line for each additional information
+ const int additionalRolesCount = qMax(visibleRoles().count() - 1, 0);
nameTextInfo->staticText.setTextWidth(maxWidth);
nameTextInfo->pos = QPointF(padding, widgetHeight -
nameHeight -
const QString elidedText = m_customizedFontMetrics.elidedText(text, Qt::ElideRight, maxWidth);
textInfo->staticText.setText(elidedText);
requiredWidth = m_customizedFontMetrics.width(elidedText);
+ } else if (role == "rating") {
+ // Use the width of the rating pixmap, because the rating text is empty.
+ requiredWidth = m_rating.width();
}
}
layout.endLayout();
y += lineSpacing;
}
- m_textRect = QRectF(x - option.padding, 0, maximumRequiredTextWidth + 2 * option.padding, widgetHeight);
+ m_textRect = QRectF(x - 2 * option.padding, 0, maximumRequiredTextWidth + 3 * option.padding, widgetHeight);
}
void KStandardItemListWidget::updateDetailsLayoutTextCache()
const qreal textWidth = option.extendedSelectionRegion
? size().width() - textInfo->pos.x()
: requiredWidth + 2 * option.padding;
- m_textRect = QRectF(textInfo->pos.x() - option.padding, 0,
- textWidth, size().height());
+ m_textRect = QRectF(textInfo->pos.x() - 2 * option.padding, 0,
+ textWidth + option.padding, 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
QRect siblingRect(x, 0, siblingSize, siblingSize);
QStyleOption option;
+ option.palette.setColor(QPalette::Text, option.palette.color(normalTextColorRole()));
bool isItemSibling = true;
const QBitArray siblings = siblingsInformation();
void KStandardItemListWidget::closeRoleEditor()
{
+ 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
// to transfer the keyboard focus back to the KItemListContainer.
scene()->views()[0]->parentWidget()->setFocus();
}
- m_roleEditor->deleteLater();
+
+ if (m_oldRoleEditor) {
+ m_oldRoleEditor->deleteLater();
+ }
+ m_oldRoleEditor = m_roleEditor;
+ m_roleEditor->hide();
m_roleEditor = 0;
}
-QPixmap KStandardItemListWidget::pixmapForIcon(const QString& name, int size)
-{
- 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;
- }
+QPixmap KStandardItemListWidget::pixmapForIcon(const QString& name, const QStringList& overlays, int size)
+{
+ const QString key = "KStandardItemListWidget:" % name % ":" % overlays.join(":") % ":" % QString::number(size);
+ QPixmap pixmap;
+
+ if (!QPixmapCache::find(key, pixmap)) {
+ 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;
+ }
+
+ pixmap = icon.pixmap(requestedSize, requestedSize);
+ if (requestedSize != size) {
+ KPixmapModifier::scale(pixmap, QSize(size, size));
+ }
+
+ // 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, pixmap, KIconLoader::Desktop);
+ break;
+ }
+ }
- QPixmap pixmap = icon.pixmap(requestedSize, requestedSize);
- if (requestedSize != size) {
- KPixmapModifier::scale(pixmap, QSize(size, size));
+ QPixmapCache::insert(key, pixmap);
}
return pixmap;
return option.padding * 6;
}
-#include "kstandarditemlistwidget.moc"