#include <QTextLayout>
#include <QTextLine>
-// #define KFILEITEMLISTWIDGET_DEBUG
+// #define KSTANDARDITEMLISTWIDGET_DEBUG
KStandardItemListWidgetInformant::KStandardItemListWidgetInformant() :
KItemListWidgetInformant()
width += option.fontMetrics.width(text);
if (role == "text") {
- // Increase the width by the expansion-toggle and the current expansion level
- const int expandedParentsCount = values.value("expandedParentsCount", 0).toInt();
- width += option.padding + (expandedParentsCount + 1) * view->itemSize().height() + KIconLoader::SizeSmall;
+ 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());
+ width += (expandedParentsCount + 1) * height;
+ }
// Increase the width by the required space for the icon
width += option.padding * 2 + option.iconSize;
KItemListWidget(informant, parent),
m_isCut(false),
m_isHidden(false),
+ m_customizedFont(),
+ m_customizedFontMetrics(m_customizedFont),
m_isExpandable(false),
m_supportsItemExpanding(false),
m_dirtyLayout(true),
drawPixmap(painter, m_pixmap);
}
- painter->setFont(itemListStyleOption.font);
- painter->setPen(textColor());
+ painter->setFont(m_customizedFont);
+ painter->setPen(m_isHidden ? m_additionalInfoTextColor : 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;
}
painter->setPen(m_additionalInfoTextColor);
- painter->setFont(itemListStyleOption.font);
+ painter->setFont(m_customizedFont);
for (int i = 1; i < m_sortedVisibleRoles.count(); ++i) {
const TextInfo* textInfo = m_textInfo.value(m_sortedVisibleRoles[i]);
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->restore();
}
-#ifdef KFILEITEMLISTWIDGET_DEBUG
+#ifdef KSTANDARDITEMLISTWIDGET_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->drawText(QPointF(0, m_customizedFontMetrics.height()), QString::number(index()));
painter->drawRect(rect());
#endif
}
const KItemListStyleOption& option = styleOption();
if (option.extendedSelectionRegion) {
const QString text = textInfo->staticText.text();
- rect.setWidth(option.fontMetrics.width(text) + 2 * option.padding);
+ rect.setWidth(m_customizedFontMetrics.width(text) + 2 * option.padding);
}
return rect;
return QRectF(pos, QSizeF(toggleSize, toggleSize));
}
+QPixmap KStandardItemListWidget::createDragPixmap(const QStyleOptionGraphicsItem* option,
+ QWidget* widget)
+{
+ QPixmap pixmap = KItemListWidget::createDragPixmap(option, widget);
+ if (m_layout != DetailsLayout) {
+ return pixmap;
+ }
+
+ // Only return the content of the text-column as pixmap
+ const int leftClip = m_pixmapPos.x();
+
+ const TextInfo* textInfo = m_textInfo.value("text");
+ const int rightClip = textInfo->pos.x() +
+ textInfo->staticText.size().width() +
+ 2 * styleOption().padding;
+
+ QPixmap clippedPixmap(rightClip - leftClip + 1, pixmap.height());
+ clippedPixmap.fill(Qt::transparent);
+
+ QPainter painter(&clippedPixmap);
+ painter.drawPixmap(-leftClip, 0, pixmap);
+
+ return clippedPixmap;
+}
+
+
KItemListWidgetInformant* KStandardItemListWidget::createInformant()
{
return new KStandardItemListWidgetInformant();
return false;
}
+bool KStandardItemListWidget::isHidden() const
+{
+ return false;
+}
+
+QFont KStandardItemListWidget::customizedFont(const QFont& baseFont) const
+{
+ return baseFont;
+}
+
+QPalette::ColorRole KStandardItemListWidget::normalTextColorRole() const
+{
+ return QPalette::Text;
+}
+
void KStandardItemListWidget::setTextColor(const QColor& color)
{
if (color != 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)
QSet<QByteArray> dirtyRoles;
if (roles.isEmpty()) {
dirtyRoles = visibleRoles().toSet();
- dirtyRoles.insert("iconPixmap");
- dirtyRoles.insert("iconName");
} else {
dirtyRoles = roles;
}
+ // The icon-state might depend from other roles and hence is
+ // marked as dirty whenever a role has been changed
+ dirtyRoles.insert("iconPixmap");
+ dirtyRoles.insert("iconName");
+
QSetIterator<QByteArray> it(dirtyRoles);
while (it.hasNext()) {
const QByteArray& role = it.next();
{
Q_UNUSED(selected);
updateAdditionalInfoTextColor();
+ m_dirtyContent = true;
}
void KStandardItemListWidget::siblingsInformationChanged(const QBitArray& current, const QBitArray& previous)
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);
if (current.isEmpty() || !parent || current != "text") {
if (m_roleEditor) {
emit roleEditingCanceled(index(), current, data().value(current));
- m_roleEditor->deleteLater();
+
+ disconnect(m_roleEditor, SIGNAL(roleEditingCanceled(int,QByteArray,QVariant)),
+ this, SLOT(slotRoleEditingCanceled(int,QByteArray,QVariant)));
+ disconnect(m_roleEditor, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)),
+ this, SLOT(slotRoleEditingFinished(int,QByteArray,QVariant)));
+ // Do not delete the role editor using deleteLater() because we might be
+ // inside a nested event loop which has been started by one of its event
+ // handlers (contextMenuEvent() or drag&drop inside mouseMoveEvent()).
+ m_roleEditor->deleteWhenIdle();
m_roleEditor = 0;
}
return;
m_roleEditor = new KItemListRoleEditor(parent);
m_roleEditor->setIndex(index());
m_roleEditor->setRole(current);
+ m_roleEditor->setFont(styleOption().font);
const QString text = data().value(current).toString();
m_roleEditor->setPlainText(text);
QTextOption textOption = textInfo->staticText.textOption();
m_roleEditor->document()->setDefaultTextOption(textOption);
- // Select the text without MIME-type extension
- int selectionLength = text.length();
+ const int textSelectionLength = selectionLength(text);
- const QString extension = KMimeType::extractKnownExtension(text);
- if (!extension.isEmpty()) {
- selectionLength -= extension.length() + 1;
- }
-
- 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);
}
}
void KStandardItemListWidget::slotRoleEditingCanceled(int index,
- const QByteArray& role,
- const QVariant& value)
+ const QByteArray& role,
+ const QVariant& value)
{
- m_roleEditor->deleteLater();
- m_roleEditor = 0;
+ closeRoleEditor();
emit roleEditingCanceled(index, role, value);
setEditedRole(QByteArray());
}
void KStandardItemListWidget::slotRoleEditingFinished(int index,
- const QByteArray& role,
- const QVariant& value)
+ const QByteArray& role,
+ const QVariant& value)
{
- m_roleEditor->deleteLater();
- m_roleEditor = 0;
+ closeRoleEditor();
emit roleEditingFinished(index, role, value);
setEditedRole(QByteArray());
}
const QHash<QByteArray, QVariant> values = data();
m_isExpandable = m_supportsItemExpanding && values["isExpandable"].toBool();
- m_isHidden = values["text"].toString().startsWith(QLatin1Char('.'));
+ m_isHidden = isHidden();
+ m_customizedFont = customizedFont(styleOption().font);
+ m_customizedFontMetrics = QFontMetrics(m_customizedFont);
updateExpansionArea();
updateTextsCache();
}
if (m_isCut) {
- applyCutEffect(m_pixmap);
+ KIconEffect* effect = KIconLoader::global()->iconEffect();
+ m_pixmap = effect->apply(m_pixmap, KIconLoader::Desktop, KIconLoader::DisabledState);
}
if (m_isHidden) {
- applyHiddenEffect(m_pixmap);
+ KIconEffect::semiTransparent(m_pixmap);
+ }
+
+ if (isSelected()) {
+ const QColor color = palette().brush(QPalette::Normal, QPalette::Highlight).color();
+ QImage image = m_pixmap.toImage();
+ KIconEffect::colorize(image, color, 1.0f);
+ m_pixmap = QPixmap::fromImage(image);
}
}
scaledIconSize = static_cast<int>(textInfo->pos.y() - 2 * padding);
} else {
const int textRowsCount = (m_layout == CompactLayout) ? visibleRoles().count() : 1;
- const qreal requiredTextHeight = textRowsCount * option.fontMetrics.height();
+ const qreal requiredTextHeight = textRowsCount * m_customizedFontMetrics.height();
scaledIconSize = (requiredTextHeight < maxIconHeight) ?
widgetSize.height() - 2 * padding : maxIconHeight;
}
const qreal availableWidth = (m_layout == DetailsLayout)
? columnWidth("rating") - columnPadding(option)
- : m_textRect.width();
+ : size().width();
if (ratingSize.width() > availableWidth) {
ratingSize.rwidth() = availableWidth;
}
const qreal padding = option.padding;
const qreal maxWidth = size().width() - 2 * padding;
const qreal widgetHeight = size().height();
- const qreal lineSpacing = option.fontMetrics.lineSpacing();
+ const qreal lineSpacing = m_customizedFontMetrics.lineSpacing();
// Initialize properties for the "text" role. It will be used as anchor
// for initializing the position of the other roles.
const int additionalRolesCount = qMax(visibleRoles().count() - 1, 0);
const int maxNameLines = (option.maxTextSize.height() / int(lineSpacing)) - additionalRolesCount;
- QTextLayout layout(nameTextInfo->staticText.text(), option.font);
+ QTextLayout layout(nameTextInfo->staticText.text(), m_customizedFont);
layout.setTextOption(nameTextInfo->staticText.textOption());
layout.beginLayout();
int nameLineIndex = 0;
if (textLength < nameText.length()) {
// Elide the last line of the text
QString lastTextLine = nameText.mid(line.textStart(), line.textLength());
- lastTextLine = option.fontMetrics.elidedText(lastTextLine,
- Qt::ElideRight,
- line.naturalTextWidth() - 1);
+ lastTextLine = m_customizedFontMetrics.elidedText(lastTextLine,
+ Qt::ElideRight,
+ line.naturalTextWidth() - 1);
const QString elidedText = nameText.left(line.textStart()) + lastTextLine;
nameTextInfo->staticText.setText(elidedText);
}
qreal requiredWidth = 0;
- QTextLayout layout(text, option.font);
+ QTextLayout layout(text, m_customizedFont);
QTextOption textOption;
textOption.setWrapMode(QTextOption::NoWrap);
layout.setTextOption(textOption);
textLine.setLineWidth(maxWidth);
requiredWidth = textLine.naturalTextWidth();
if (requiredWidth > maxWidth) {
- const QString elidedText = option.fontMetrics.elidedText(text, Qt::ElideRight, maxWidth);
+ const QString elidedText = m_customizedFontMetrics.elidedText(text, Qt::ElideRight, maxWidth);
textInfo->staticText.setText(elidedText);
- requiredWidth = option.fontMetrics.width(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();
const KItemListStyleOption& option = styleOption();
const qreal widgetHeight = size().height();
- const qreal lineSpacing = option.fontMetrics.lineSpacing();
+ const qreal lineSpacing = m_customizedFontMetrics.lineSpacing();
const qreal textLinesHeight = qMax(visibleRoles().count(), 1) * lineSpacing;
const int scaledIconSize = (textLinesHeight < option.iconSize) ? widgetHeight - 2 * option.padding : option.iconSize;
TextInfo* textInfo = m_textInfo.value(role);
textInfo->staticText.setText(text);
- qreal requiredWidth = option.fontMetrics.width(text);
+ qreal requiredWidth = m_customizedFontMetrics.width(text);
if (requiredWidth > maxWidth) {
requiredWidth = maxWidth;
- const QString elidedText = option.fontMetrics.elidedText(text, Qt::ElideRight, maxWidth);
+ const QString elidedText = m_customizedFontMetrics.elidedText(text, Qt::ElideRight, maxWidth);
textInfo->staticText.setText(elidedText);
}
const qreal widgetHeight = size().height();
const int scaledIconSize = widgetHeight - 2 * option.padding;
- const int fontHeight = option.fontMetrics.height();
+ const int fontHeight = m_customizedFontMetrics.height();
const qreal columnWidthInc = columnPadding(option);
qreal firstColumnInc = scaledIconSize;
QString text = roleText(role, values);
// Elide the text in case it does not fit into the available column-width
- qreal requiredWidth = option.fontMetrics.width(text);
+ qreal requiredWidth = m_customizedFontMetrics.width(text);
const qreal roleWidth = columnWidth(role);
qreal availableTextWidth = roleWidth - columnWidthInc;
}
if (requiredWidth > availableTextWidth) {
- text = option.fontMetrics.elidedText(text, Qt::ElideRight, availableTextWidth);
- requiredWidth = option.fontMetrics.width(text);
+ text = m_customizedFontMetrics.elidedText(text, Qt::ElideRight, availableTextWidth);
+ requiredWidth = m_customizedFontMetrics.width(text);
}
TextInfo* textInfo = m_textInfo.value(role);
KPixmapModifier::scale(scaledPixmap, m_scaledPixmapSize);
painter->drawPixmap(m_pixmapPos, scaledPixmap);
-#ifdef KFILEITEMLISTWIDGET_DEBUG
+#ifdef KSTANDARDITEMLISTWIDGET_DEBUG
painter->setPen(Qt::blue);
painter->drawRect(QRectF(m_pixmapPos, QSizeF(m_scaledPixmapSize)));
#endif
QRect siblingRect(x, 0, siblingSize, siblingSize);
QStyleOption option;
+ option.palette.setColor(QPalette::Text, option.palette.color(normalTextColorRole()));
bool isItemSibling = true;
const QBitArray siblings = siblingsInformation();
return rect;
}
+void KStandardItemListWidget::closeRoleEditor()
+{
+ 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();
+ }
+
+ disconnect(m_roleEditor, SIGNAL(roleEditingCanceled(int,QByteArray,QVariant)),
+ this, SLOT(slotRoleEditingCanceled(int,QByteArray,QVariant)));
+ disconnect(m_roleEditor, SIGNAL(roleEditingFinished(int,QByteArray,QVariant)),
+ this, SLOT(slotRoleEditingFinished(int,QByteArray,QVariant)));
+
+ // Do not delete the role editor using deleteLater() because we might be
+ // inside a nested event loop which has been started by one of its event
+ // handlers (contextMenuEvent() or drag&drop inside mouseMoveEvent()).
+ m_roleEditor->deleteWhenIdle();
+ m_roleEditor = 0;
+}
+
QPixmap KStandardItemListWidget::pixmapForIcon(const QString& name, int size)
{
const KIcon icon(name);
return pixmap;
}
-void KStandardItemListWidget::applyCutEffect(QPixmap& pixmap)
-{
- KIconEffect* effect = KIconLoader::global()->iconEffect();
- pixmap = effect->apply(pixmap, KIconLoader::Desktop, KIconLoader::DisabledState);
-}
-
-void KStandardItemListWidget::applyHiddenEffect(QPixmap& pixmap)
-{
- KIconEffect::semiTransparent(pixmap);
-}
-
QSizeF KStandardItemListWidget::preferredRatingSize(const KItemListStyleOption& option)
{
const qreal height = option.fontMetrics.ascent();