fix tricky regression noticed by Vyacheslav Tokarev on Google Reader.
[kdelibs.git] / kio / kio / kfileitemdelegate.cpp
blobbe6fdb9cb8a7b9c0f6de9e1d95805309f064de21
1 /*
2 This file is part of the KDE project
4 Copyright © 2006-2007, 2008 Fredrik Höglund <fredrik@kde.org>
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
22 #include "kfileitemdelegate.h"
23 #include "imagefilter_p.h"
25 #include <config.h> // for HAVE_XRENDER
27 #include <QApplication>
28 #include <QStyle>
29 #include <QModelIndex>
30 #include <QPainter>
31 #include <QCache>
32 #include <QImage>
33 #include <QPainterPath>
34 #include <QTextLayout>
35 #include <QListView>
36 #include <QPaintEngine>
37 #include <qmath.h>
39 #include <kglobal.h>
40 #include <klocale.h>
41 #include <kiconloader.h>
42 #include <kiconeffect.h>
43 #include <kdirmodel.h>
44 #include <kfileitem.h>
45 #include <kcolorscheme.h>
46 #include <kglobalsettings.h>
47 #include <ktextedit.h>
49 #include "delegateanimationhandler_p.h"
51 #if defined(Q_WS_X11) && defined(HAVE_XRENDER)
52 # include <X11/Xlib.h>
53 # include <X11/extensions/Xrender.h>
54 # include <QX11Info>
55 # undef KeyPress
56 # undef FocusOut
57 #endif
60 struct Margin
62 int left, right, top, bottom;
66 class KFileItemDelegate::Private
68 public:
69 enum MarginType { ItemMargin = 0, TextMargin, IconMargin, NMargins };
71 Private(KFileItemDelegate *parent);
72 ~Private() {}
74 QSize decorationSizeHint(const QStyleOptionViewItemV4 &option, const QModelIndex &index) const;
75 QSize displaySizeHint(const QStyleOptionViewItemV4 &option, const QModelIndex &index) const;
76 QString replaceNewlines(const QString &string) const;
77 inline KFileItem fileItem(const QModelIndex &index) const;
78 QString elidedText(QTextLayout &layout, const QStyleOptionViewItemV4 &option, const QSize &maxSize) const;
79 QSize layoutText(QTextLayout &layout, const QStyleOptionViewItemV4 &option,
80 const QString &text, const QSize &constraints) const;
81 QSize layoutText(QTextLayout &layout, const QString &text, int maxWidth) const;
82 inline void setLayoutOptions(QTextLayout &layout, const QStyleOptionViewItemV4 &options) const;
83 inline bool verticalLayout(const QStyleOptionViewItemV4 &option) const;
84 inline QBrush brush(const QVariant &value, const QStyleOptionViewItemV4 &option) const;
85 QBrush foregroundBrush(const QStyleOptionViewItemV4 &option, const QModelIndex &index) const;
86 inline void setActiveMargins(Qt::Orientation layout);
87 void setVerticalMargin(MarginType type, int left, int right, int top, int bottom);
88 void setHorizontalMargin(MarginType type, int left, int right, int top, int bottom);
89 inline void setVerticalMargin(MarginType type, int hor, int ver);
90 inline void setHorizontalMargin(MarginType type, int hor, int ver);
91 inline QRect addMargin(const QRect &rect, MarginType type) const;
92 inline QRect subtractMargin(const QRect &rect, MarginType type) const;
93 inline QSize addMargin(const QSize &size, MarginType type) const;
94 inline QSize subtractMargin(const QSize &size, MarginType type) const;
95 QString itemSize(const QModelIndex &index, const KFileItem &item) const;
96 QString information(const QStyleOptionViewItemV4 &option, const QModelIndex &index, const KFileItem &item) const;
97 bool isListView(const QStyleOptionViewItemV4 &option) const;
98 QString display(const QModelIndex &index) const;
99 QIcon decoration(const QStyleOptionViewItemV4 &option, const QModelIndex &index) const;
100 QPoint iconPosition(const QStyleOptionViewItemV4 &option) const;
101 QRect labelRectangle(const QStyleOptionViewItemV4 &option) const;
102 void layoutTextItems(const QStyleOptionViewItemV4 &option, const QModelIndex &index,
103 QTextLayout *labelLayout, QTextLayout *infoLayout, QRect *textBoundingRect) const;
104 void drawTextItems(QPainter *painter, const QTextLayout &labelLayout, const QTextLayout &infoLayout,
105 const QRect &textBoundingRect) const;
106 KIO::AnimationState *animationState(const QStyleOptionViewItemV4 &option, const QModelIndex &index,
107 const QAbstractItemView *view) const;
108 QPixmap applyHoverEffect(const QPixmap &icon) const;
109 QPixmap transition(const QPixmap &from, const QPixmap &to, qreal amount) const;
110 void initStyleOption(QStyleOptionViewItemV4 *option, const QModelIndex &index) const;
111 void drawFocusRect(QPainter *painter, const QStyleOptionViewItemV4 &option, const QRect &rect) const;
113 public:
114 KFileItemDelegate::InformationList informationList;
115 QColor shadowColor;
116 QPointF shadowOffset;
117 qreal shadowBlur;
118 QSize maximumSize;
119 bool showToolTipWhenElided;
121 private:
122 KFileItemDelegate * const q;
123 KIO::DelegateAnimationHandler *animationHandler;
124 Margin verticalMargin[NMargins];
125 Margin horizontalMargin[NMargins];
126 Margin *activeMargins;
130 KFileItemDelegate::Private::Private(KFileItemDelegate *parent)
131 : shadowColor(Qt::transparent), shadowOffset(1, 1), shadowBlur(2), maximumSize(0, 0),
132 showToolTipWhenElided(true), q(parent),
133 animationHandler(new KIO::DelegateAnimationHandler(parent)), activeMargins(0)
138 void KFileItemDelegate::Private::setActiveMargins(Qt::Orientation layout)
140 activeMargins = (layout == Qt::Horizontal ?
141 horizontalMargin : verticalMargin);
145 void KFileItemDelegate::Private::setVerticalMargin(MarginType type, int left, int top, int right, int bottom)
147 verticalMargin[type].left = left;
148 verticalMargin[type].right = right;
149 verticalMargin[type].top = top;
150 verticalMargin[type].bottom = bottom;
154 void KFileItemDelegate::Private::setHorizontalMargin(MarginType type, int left, int top, int right, int bottom)
156 horizontalMargin[type].left = left;
157 horizontalMargin[type].right = right;
158 horizontalMargin[type].top = top;
159 horizontalMargin[type].bottom = bottom;
163 void KFileItemDelegate::Private::setVerticalMargin(MarginType type, int horizontal, int vertical)
165 setVerticalMargin(type, horizontal, vertical, horizontal, vertical);
169 void KFileItemDelegate::Private::setHorizontalMargin(MarginType type, int horizontal, int vertical)
171 setHorizontalMargin(type, horizontal, vertical, horizontal, vertical);
175 QRect KFileItemDelegate::Private::addMargin(const QRect &rect, MarginType type) const
177 Q_ASSERT(activeMargins != 0);
178 const Margin &m = activeMargins[type];
179 return rect.adjusted(-m.left, -m.top, m.right, m.bottom);
183 QRect KFileItemDelegate::Private::subtractMargin(const QRect &rect, MarginType type) const
185 Q_ASSERT(activeMargins != 0);
186 const Margin &m = activeMargins[type];
187 return rect.adjusted(m.left, m.top, -m.right, -m.bottom);
191 QSize KFileItemDelegate::Private::addMargin(const QSize &size, MarginType type) const
193 Q_ASSERT(activeMargins != 0);
194 const Margin &m = activeMargins[type];
195 return QSize(size.width() + m.left + m.right, size.height() + m.top + m.bottom);
199 QSize KFileItemDelegate::Private::subtractMargin(const QSize &size, MarginType type) const
201 Q_ASSERT(activeMargins != 0);
202 const Margin &m = activeMargins[type];
203 return QSize(size.width() - m.left - m.right, size.height() - m.top - m.bottom);
207 // Returns the size of a file, or the number of items in a directory, as a QString
208 QString KFileItemDelegate::Private::itemSize(const QModelIndex &index, const KFileItem &item) const
210 // Return a formatted string containing the file size, if the item is a file
211 if (item.isFile())
212 return KGlobal::locale()->formatByteSize(item.size());
214 // Return the number of items in the directory
215 const QVariant value = index.data(KDirModel::ChildCountRole);
216 const int count = value.type() == QVariant::Int ? value.toInt() : KDirModel::ChildCountUnknown;
218 if (count == KDirModel::ChildCountUnknown) {
219 // was: i18nc("Items in a folder", "? items");
220 // but this just looks useless in a remote directory listing,
221 // better not show anything.
222 return QString();
225 return i18ncp("Items in a folder", "1 item", "%1 items", count);
229 // Returns the additional information string, if one should be shown, or an empty string otherwise
230 QString KFileItemDelegate::Private::information(const QStyleOptionViewItemV4 &option, const QModelIndex &index,
231 const KFileItem &item) const
233 QString string;
235 if (informationList.isEmpty() || item.isNull() || !isListView(option))
236 return string;
238 foreach (KFileItemDelegate::Information info, informationList)
240 if (info == KFileItemDelegate::NoInformation)
241 continue;
243 if (!string.isEmpty())
244 string += QChar::LineSeparator;
246 switch (info)
248 case KFileItemDelegate::Size:
249 string += itemSize(index, item);
250 break;
252 case KFileItemDelegate::Permissions:
253 string += item.permissionsString();
254 break;
256 case KFileItemDelegate::OctalPermissions:
257 string += QString('0') + QString::number(item.permissions(), 8);
258 break;
260 case KFileItemDelegate::Owner:
261 string += item.user();
262 break;
264 case KFileItemDelegate::OwnerAndGroup:
265 string += item.user() + ':' + item.group();
266 break;
268 case KFileItemDelegate::CreationTime:
269 string += item.timeString(KFileItem::CreationTime);
270 break;
272 case KFileItemDelegate::ModificationTime:
273 string += item.timeString(KFileItem::ModificationTime);
274 break;
276 case KFileItemDelegate::AccessTime:
277 string += item.timeString(KFileItem::AccessTime);
278 break;
280 case KFileItemDelegate::MimeType:
281 string += item.isMimeTypeKnown() ? item.mimetype() : i18nc("@info mimetype","Unknown");
282 break;
284 case KFileItemDelegate::FriendlyMimeType:
285 string += item.isMimeTypeKnown() ? item.mimeComment() : i18nc("@info mimetype","Unknown");
286 break;
288 default:
289 break;
290 } // switch (info)
291 } // foreach (info, list)
293 return string;
297 // Returns the KFileItem for the index
298 KFileItem KFileItemDelegate::Private::fileItem(const QModelIndex &index) const
300 const QVariant value = index.data(KDirModel::FileItemRole);
301 return qvariant_cast<KFileItem>(value);
305 // Replaces any newline characters in the provided string, with QChar::LineSeparator
306 QString KFileItemDelegate::Private::replaceNewlines(const QString &text) const
308 QString string = text;
309 const QChar newline = QLatin1Char('\n');
311 for (int i = 0; i < string.length(); i++)
312 if (string[i] == newline)
313 string[i] = QChar::LineSeparator;
315 return string;
319 // Lays the text out in a rectangle no larger than constraints, eliding it as necessary
320 QSize KFileItemDelegate::Private::layoutText(QTextLayout &layout, const QStyleOptionViewItemV4 &option,
321 const QString &text, const QSize &constraints) const
323 const QSize size = layoutText(layout, text, constraints.width());
325 if (size.width() > constraints.width() || size.height() > constraints.height())
327 const QString elided = elidedText(layout, option, constraints);
328 return layoutText(layout, elided, constraints.width());
331 return size;
335 // Lays the text out in a rectangle no wider than maxWidth
336 QSize KFileItemDelegate::Private::layoutText(QTextLayout &layout, const QString &text, int maxWidth) const
338 QFontMetrics metrics(layout.font());
339 int leading = metrics.leading();
340 int height = 0;
341 qreal widthUsed = 0;
342 QTextLine line;
344 layout.setText(text);
346 layout.beginLayout();
347 while ((line = layout.createLine()).isValid())
349 line.setLineWidth(int(maxWidth));
350 height += leading;
351 line.setPosition(QPoint(0, height));
352 height += int(line.height());
353 widthUsed = qMax(widthUsed, line.naturalTextWidth());
355 layout.endLayout();
357 return QSize(int(widthUsed), height);
361 // Elides the text in the layout, by iterating over each line in the layout, eliding
362 // or word breaking the line if it's wider than the max width, and finally adding an
363 // ellipses at the end of the last line, if there are more lines than will fit within
364 // the vertical size constraints.
365 QString KFileItemDelegate::Private::elidedText(QTextLayout &layout, const QStyleOptionViewItemV4 &option,
366 const QSize &size) const
368 const QString text = layout.text();
369 int maxWidth = size.width();
370 int maxHeight = size.height();
371 qreal height = 0;
372 bool wrapText = (option.features & QStyleOptionViewItemV2::WrapText);
374 // If the string contains a single line of text that shouldn't be word wrapped
375 if (!wrapText && text.indexOf(QChar::LineSeparator) == -1)
376 return option.fontMetrics.elidedText(text, option.textElideMode, maxWidth);
378 // Elide each line that has already been laid out in the layout.
379 QString elided;
380 elided.reserve(text.length());
382 for (int i = 0; i < layout.lineCount(); i++)
384 QTextLine line = layout.lineAt(i);
385 int start = line.textStart();
386 int length = line.textLength();
388 height += option.fontMetrics.leading();
389 if (height + line.height() + option.fontMetrics.lineSpacing() > maxHeight)
391 // Unfortunately, if the line ends because of a line separator, elidedText() will be too
392 // clever and keep adding lines until it finds one that's too wide.
393 if (line.naturalTextWidth() < maxWidth && text[start + length - 1] == QChar::LineSeparator)
394 elided += text.mid(start, length - 1);
395 else
396 elided += option.fontMetrics.elidedText(text.mid(start), option.textElideMode, maxWidth);
397 break;
399 else if (line.naturalTextWidth() > maxWidth)
401 elided += option.fontMetrics.elidedText(text.mid(start, length), option.textElideMode, maxWidth);
402 if (!elided.endsWith(QChar::LineSeparator))
403 elided += QChar::LineSeparator;
405 else
406 elided += text.mid(start, length);
408 height += line.height();
411 return elided;
415 void KFileItemDelegate::Private::setLayoutOptions(QTextLayout &layout, const QStyleOptionViewItemV4 &option) const
417 QTextOption textoption;
418 textoption.setTextDirection(option.direction);
419 textoption.setAlignment(QStyle::visualAlignment(option.direction, option.displayAlignment));
420 textoption.setWrapMode((option.features & QStyleOptionViewItemV2::WrapText) ?
421 QTextOption::WrapAtWordBoundaryOrAnywhere : QTextOption::NoWrap);
423 layout.setFont(option.font);
424 layout.setTextOption(textoption);
428 QSize KFileItemDelegate::Private::displaySizeHint(const QStyleOptionViewItemV4 &option,
429 const QModelIndex &index) const
431 QString label = option.text;
432 int maxWidth = 0;
433 if (maximumSize.isEmpty()) {
434 maxWidth = verticalLayout(option) && (option.features & QStyleOptionViewItemV2::WrapText)
435 ? option.decorationSize.width() + 10 : 32757;
437 else {
438 const Margin &itemMargin = activeMargins[ItemMargin];
439 const Margin &textMargin = activeMargins[TextMargin];
440 maxWidth = maximumSize.width() -
441 (itemMargin.left + itemMargin.right) -
442 (textMargin.left + textMargin.right);
445 KFileItem item = fileItem(index);
447 // To compute the nominal size for the label + info, we'll just append
448 // the information string to the label
449 const QString info = information(option, index, item);
450 if (!info.isEmpty())
451 label += QString(QChar::LineSeparator) + info;
453 QTextLayout layout;
454 setLayoutOptions(layout, option);
456 QSize size = layoutText(layout, label, maxWidth);
457 return addMargin(size, TextMargin);
461 QSize KFileItemDelegate::Private::decorationSizeHint(const QStyleOptionViewItemV4 &option,
462 const QModelIndex &index) const
464 Q_UNUSED(index)
466 QSize iconSize = option.icon.actualSize(option.decorationSize);
467 if (!verticalLayout(option))
468 iconSize.rwidth() = option.decorationSize.width();
469 else if (iconSize.width() < option.decorationSize.width())
470 iconSize.rwidth() = qMin(iconSize.width() + 10, option.decorationSize.width());
471 if (iconSize.height() < option.decorationSize.height())
472 iconSize.rheight() = option.decorationSize.height();
474 return addMargin(iconSize, IconMargin);
478 bool KFileItemDelegate::Private::verticalLayout(const QStyleOptionViewItemV4 &option) const
480 return (option.decorationPosition == QStyleOptionViewItem::Top ||
481 option.decorationPosition == QStyleOptionViewItem::Bottom);
485 // Converts a QVariant of type Brush or Color to a QBrush
486 QBrush KFileItemDelegate::Private::brush(const QVariant &value, const QStyleOptionViewItemV4 &option) const
488 if (value.userType() == qMetaTypeId<KStatefulBrush>())
489 return qvariant_cast<KStatefulBrush>(value).brush(option.palette);
490 switch (value.type())
492 case QVariant::Color:
493 return QBrush(qvariant_cast<QColor>(value));
495 case QVariant::Brush:
496 return qvariant_cast<QBrush>(value);
498 default:
499 return QBrush(Qt::NoBrush);
504 QBrush KFileItemDelegate::Private::foregroundBrush(const QStyleOptionViewItemV4 &option, const QModelIndex &index) const
506 // Always use the highlight color for selected items
507 if (option.state & QStyle::State_Selected)
508 return option.palette.brush(QPalette::HighlightedText);
510 // If the model provides its own foreground color/brush for this item
511 const QVariant value = index.data(Qt::ForegroundRole);
512 if (value.isValid())
513 return brush(value, option);
515 return option.palette.brush(QPalette::Text);
519 bool KFileItemDelegate::Private::isListView(const QStyleOptionViewItemV4 &option) const
521 if (qobject_cast<const QListView*>(option.widget) || verticalLayout(option))
522 return true;
524 return false;
528 QPixmap KFileItemDelegate::Private::applyHoverEffect(const QPixmap &icon) const
530 KIconEffect *effect = KIconLoader::global()->iconEffect();
532 // Note that in KIconLoader terminology, active = hover.
533 // ### We're assuming that the icon group is desktop/filemanager, since this
534 // is KFileItemDelegate.
535 if (effect->hasEffect(KIconLoader::Desktop, KIconLoader::ActiveState))
536 return effect->apply(icon, KIconLoader::Desktop, KIconLoader::ActiveState);
538 return icon;
542 KIO::AnimationState *KFileItemDelegate::Private::animationState(const QStyleOptionViewItemV4 &option,
543 const QModelIndex &index,
544 const QAbstractItemView *view) const
546 if (!(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects)) {
547 return NULL;
550 if (index.column() == KDirModel::Name)
551 return animationHandler->animationState(option, index, view);
553 return NULL;
557 QPixmap KFileItemDelegate::Private::transition(const QPixmap &from, const QPixmap &to, qreal amount) const
559 int value = int(0xff * amount);
561 if (value == 0)
562 return from;
564 if (value == 1)
565 return to;
567 QColor color;
568 color.setAlphaF(amount);
570 // If the native paint engine supports Porter/Duff compositing and CompositionMode_Plus
571 if (from.paintEngine()->hasFeature(QPaintEngine::PorterDuff) &&
572 from.paintEngine()->hasFeature(QPaintEngine::BlendModes))
574 QPixmap under = from;
575 QPixmap over = to;
577 QPainter p;
578 p.begin(&over);
579 p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
580 p.fillRect(over.rect(), color);
581 p.end();
583 p.begin(&under);
584 p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
585 p.fillRect(under.rect(), color);
586 p.setCompositionMode(QPainter::CompositionMode_Plus);
587 p.drawPixmap(0, 0, over);
588 p.end();
590 return under;
592 #if defined(Q_WS_X11) && defined(HAVE_XRENDER)
593 else if (from.paintEngine()->hasFeature(QPaintEngine::PorterDuff)) // We have Xrender support
595 // QX11PaintEngine doesn't implement CompositionMode_Plus in Qt 4.3,
596 // which we need to be able to do a transition from one pixmap to
597 // another.
599 // In order to avoid the overhead of converting the pixmaps to images
600 // and doing the operation entirely in software, this function has a
601 // specialized path for X11 that uses Xrender directly to do the
602 // transition. This operation can be fully accelerated in HW.
604 // This specialization can be removed when QX11PaintEngine supports
605 // CompositionMode_Plus.
606 QPixmap source(to), destination(from);
608 source.detach();
609 destination.detach();
611 Display *dpy = QX11Info::display();
613 XRenderPictFormat *format = XRenderFindStandardFormat(dpy, PictStandardA8);
614 XRenderPictureAttributes pa;
615 pa.repeat = 1; // RepeatNormal
617 // Create a 1x1 8 bit repeating alpha picture
618 Pixmap pixmap = XCreatePixmap(dpy, destination.handle(), 1, 1, 8);
619 Picture alpha = XRenderCreatePicture(dpy, pixmap, format, CPRepeat, &pa);
620 XFreePixmap(dpy, pixmap);
622 // Fill the alpha picture with the opacity value
623 XRenderColor xcolor;
624 xcolor.alpha = quint16(0xffff * amount);
625 XRenderFillRectangle(dpy, PictOpSrc, alpha, &xcolor, 0, 0, 1, 1);
627 // Reduce the alpha of the destination with 1 - opacity
628 XRenderComposite(dpy, PictOpOutReverse, alpha, None, destination.x11PictureHandle(),
629 0, 0, 0, 0, 0, 0, destination.width(), destination.height());
631 // Add source * opacity to the destination
632 XRenderComposite(dpy, PictOpAdd, source.x11PictureHandle(), alpha,
633 destination.x11PictureHandle(),
634 0, 0, 0, 0, 0, 0, destination.width(), destination.height());
636 XRenderFreePicture(dpy, alpha);
637 return destination;
639 #endif
640 else
642 // Fall back to using QRasterPaintEngine to do the transition.
643 QImage under = from.toImage();
644 QImage over = to.toImage();
646 QPainter p;
647 p.begin(&over);
648 p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
649 p.fillRect(over.rect(), color);
650 p.end();
652 p.begin(&under);
653 p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
654 p.fillRect(under.rect(), color);
655 p.setCompositionMode(QPainter::CompositionMode_Plus);
656 p.drawImage(0, 0, over);
657 p.end();
659 return QPixmap::fromImage(under);
664 void KFileItemDelegate::Private::layoutTextItems(const QStyleOptionViewItemV4 &option, const QModelIndex &index,
665 QTextLayout *labelLayout, QTextLayout *infoLayout,
666 QRect *textBoundingRect) const
668 KFileItem item = fileItem(index);
669 const QString info = information(option, index, item);
670 bool showInformation = false;
672 setLayoutOptions(*labelLayout, option);
674 const QRect textArea = labelRectangle(option);
675 QRect textRect = subtractMargin(textArea, Private::TextMargin);
677 // Sizes and constraints for the different text parts
678 QSize maxLabelSize = textRect.size();
679 QSize maxInfoSize = textRect.size();
680 QSize labelSize;
681 QSize infoSize;
683 // If we have additional info text, and there's space for at least two lines of text,
684 // adjust the max label size to make room for at least one line of the info text
685 if (!info.isEmpty() && textRect.height() >= option.fontMetrics.lineSpacing() * 2)
687 infoLayout->setFont(labelLayout->font());
688 infoLayout->setTextOption(labelLayout->textOption());
690 maxLabelSize.rheight() -= option.fontMetrics.lineSpacing();
691 showInformation = true;
694 // Lay out the label text, and adjust the max info size based on the label size
695 labelSize = layoutText(*labelLayout, option, option.text, maxLabelSize);
696 maxInfoSize.rheight() -= labelSize.height();
698 // Lay out the info text
699 if (showInformation)
700 infoSize = layoutText(*infoLayout, option, info, maxInfoSize);
701 else
702 infoSize = QSize(0, 0);
704 // Compute the bounding rect of the text
705 const QSize size(qMax(labelSize.width(), infoSize.width()), labelSize.height() + infoSize.height());
706 *textBoundingRect = QStyle::alignedRect(option.direction, option.displayAlignment, size, textRect);
708 // Compute the positions where we should draw the layouts
709 labelLayout->setPosition(QPointF(textRect.x(), textBoundingRect->y()));
710 infoLayout->setPosition(QPointF(textRect.x(), textBoundingRect->y() + labelSize.height()));
714 void KFileItemDelegate::Private::drawTextItems(QPainter *painter, const QTextLayout &labelLayout,
715 const QTextLayout &infoLayout, const QRect &boundingRect) const
717 if (shadowColor.alpha() > 0)
719 QPixmap pixmap(boundingRect.size());
720 pixmap.fill(Qt::transparent);
722 QPainter p(&pixmap);
723 p.translate(-boundingRect.topLeft());
724 p.setPen(painter->pen());
725 labelLayout.draw(&p, QPoint());
727 if (!infoLayout.text().isEmpty())
729 QColor color = p.pen().color();
730 color.setAlphaF(0.6);
732 p.setPen(color);
733 infoLayout.draw(&p, QPoint());
735 p.end();
737 int padding = qCeil(shadowBlur);
738 int blurFactor = qRound(shadowBlur);
740 QImage image(boundingRect.size() + QSize(padding * 2, padding * 2), QImage::Format_ARGB32_Premultiplied);
741 image.fill(0);
742 p.begin(&image);
743 p.drawImage(padding, padding, pixmap.toImage());
744 p.end();
746 KIO::ImageFilter::shadowBlur(image, blurFactor, shadowColor);
748 painter->drawImage(boundingRect.topLeft() - QPoint(padding, padding) + shadowOffset.toPoint(), image);
749 painter->drawPixmap(boundingRect.topLeft(), pixmap);
750 return;
753 labelLayout.draw(painter, QPoint());
755 if (!infoLayout.text().isEmpty())
757 // TODO - for apps not doing funny things with the color palette,
758 // KColorScheme::InactiveText would be a much more correct choice. We
759 // should provide an API to specify what color to use for information.
760 QColor color = painter->pen().color();
761 color.setAlphaF(0.6);
763 painter->setPen(color);
764 infoLayout.draw(painter, QPoint());
769 void KFileItemDelegate::Private::initStyleOption(QStyleOptionViewItemV4 *option,
770 const QModelIndex &index) const
772 const KFileItem item = fileItem(index);
773 bool updateFontMetrics = false;
775 // Try to get the font from the model
776 QVariant value = index.data(Qt::FontRole);
777 if (value.isValid()) {
778 option->font = qvariant_cast<QFont>(value).resolve(option->font);
779 updateFontMetrics = true;
782 // Use an italic font for symlinks
783 if (!item.isNull() && item.isLink()) {
784 option->font.setItalic(true);
785 updateFontMetrics = true;
788 if (updateFontMetrics)
789 option->fontMetrics = QFontMetrics(option->font);
791 // Try to get the alignment for the item from the model
792 value = index.data(Qt::TextAlignmentRole);
793 if (value.isValid())
794 option->displayAlignment = Qt::Alignment(value.toInt());
796 value = index.data(Qt::BackgroundRole);
797 if (value.isValid())
798 option->backgroundBrush = brush(value, *option);
800 option->text = display(index);
801 if (!option->text.isEmpty())
802 option->features |= QStyleOptionViewItemV2::HasDisplay;
804 option->icon = decoration(*option, index);
805 if (!option->icon.isNull())
806 option->features |= QStyleOptionViewItemV2::HasDecoration;
808 // ### Make sure this value is always true for now
809 option->showDecorationSelected = true;
815 // ---------------------------------------------------------------------------
820 KFileItemDelegate::KFileItemDelegate(QObject *parent)
821 : QAbstractItemDelegate(parent), d(new Private(this))
823 int focusHMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin);
824 int focusVMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameVMargin);
826 // Margins for horizontal mode (list views, tree views, table views)
827 const int textMargin = focusHMargin * 4;
828 if (QApplication::isRightToLeft())
829 d->setHorizontalMargin(Private::TextMargin, textMargin, focusVMargin, focusHMargin, focusVMargin);
830 else
831 d->setHorizontalMargin(Private::TextMargin, focusHMargin, focusVMargin, textMargin, focusVMargin);
833 d->setHorizontalMargin(Private::IconMargin, focusHMargin, focusVMargin);
834 d->setHorizontalMargin(Private::ItemMargin, 0, 0);
836 // Margins for vertical mode (icon views)
837 d->setVerticalMargin(Private::TextMargin, 6, 2);
838 d->setVerticalMargin(Private::IconMargin, focusHMargin, focusVMargin);
839 d->setVerticalMargin(Private::ItemMargin, 0, 0);
841 setShowInformation(NoInformation);
845 KFileItemDelegate::~KFileItemDelegate()
847 delete d;
851 QSize KFileItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
853 // If the model wants to provide its own size hint for the item
854 const QVariant value = index.data(Qt::SizeHintRole);
855 if (value.isValid())
856 return qvariant_cast<QSize>(value);
858 QStyleOptionViewItemV4 opt(option);
859 d->initStyleOption(&opt, index);
860 d->setActiveMargins(d->verticalLayout(opt) ? Qt::Vertical : Qt::Horizontal);
862 const QSize displaySize = d->displaySizeHint(opt, index);
863 const QSize decorationSize = d->decorationSizeHint(opt, index);
865 QSize size;
867 if (d->verticalLayout(opt))
869 size.rwidth() = qMax(displaySize.width(), decorationSize.width());
870 size.rheight() = decorationSize.height() + displaySize.height() + 1;
872 else
874 size.rwidth() = decorationSize.width() + displaySize.width() + 1;
875 size.rheight() = qMax(decorationSize.height(), displaySize.height());
878 size = d->addMargin(size, Private::ItemMargin);
879 if (!d->maximumSize.isEmpty())
881 size = size.boundedTo(d->maximumSize);
884 return size;
888 QString KFileItemDelegate::Private::display(const QModelIndex &index) const
890 const QVariant value = index.data(Qt::DisplayRole);
892 switch (value.type())
894 case QVariant::String:
896 if (index.column() == KDirModel::Size)
897 return itemSize(index, fileItem(index));
898 else
899 return replaceNewlines(value.toString());
902 case QVariant::Double:
903 return KGlobal::locale()->formatNumber(value.toDouble());
905 case QVariant::Int:
906 case QVariant::UInt:
907 return KGlobal::locale()->formatLong(value.toInt());
909 default:
910 return QString();
915 void KFileItemDelegate::setShowInformation(const InformationList &list)
917 d->informationList = list;
921 void KFileItemDelegate::setShowInformation(Information value)
923 if (value != NoInformation)
924 d->informationList = InformationList() << value;
925 else
926 d->informationList = InformationList();
930 KFileItemDelegate::InformationList KFileItemDelegate::showInformation() const
932 return d->informationList;
936 void KFileItemDelegate::setShadowColor(const QColor &color)
938 d->shadowColor = color;
942 QColor KFileItemDelegate::shadowColor() const
944 return d->shadowColor;
948 void KFileItemDelegate::setShadowOffset(const QPointF &offset)
950 d->shadowOffset = offset;
954 QPointF KFileItemDelegate::shadowOffset() const
956 return d->shadowOffset;
960 void KFileItemDelegate::setShadowBlur(qreal factor)
962 d->shadowBlur = factor;
966 qreal KFileItemDelegate::shadowBlur() const
968 return d->shadowBlur;
972 void KFileItemDelegate::setMaximumSize(const QSize &size)
974 d->maximumSize = size;
978 QSize KFileItemDelegate::maximumSize() const
980 return d->maximumSize;
984 void KFileItemDelegate::setShowToolTipWhenElided(bool showToolTip)
986 d->showToolTipWhenElided = showToolTip;
990 bool KFileItemDelegate::showToolTipWhenElided() const
992 return d->showToolTipWhenElided;
996 QIcon KFileItemDelegate::Private::decoration(const QStyleOptionViewItemV4 &option, const QModelIndex &index) const
998 const QVariant value = index.data(Qt::DecorationRole);
999 QIcon icon;
1001 switch (value.type())
1003 case QVariant::Icon:
1004 icon = qvariant_cast<QIcon>(value);
1005 break;
1007 case QVariant::Pixmap:
1008 icon.addPixmap(qvariant_cast<QPixmap>(value));
1009 break;
1011 case QVariant::Color: {
1012 QPixmap pixmap(option.decorationSize);
1013 pixmap.fill(qvariant_cast<QColor>(value));
1014 icon.addPixmap(pixmap);
1015 break;
1018 default:
1019 break;
1022 return icon;
1026 QRect KFileItemDelegate::Private::labelRectangle(const QStyleOptionViewItemV4 &option) const
1028 if (option.icon.isNull())
1029 return subtractMargin(option.rect, Private::ItemMargin);
1031 const QSize decoSize = addMargin(option.decorationSize, Private::IconMargin);
1032 const QRect itemRect = subtractMargin(option.rect, Private::ItemMargin);
1033 QRect textArea(QPoint(0, 0), itemRect.size());
1035 switch (option.decorationPosition)
1037 case QStyleOptionViewItem::Top:
1038 textArea.setTop(decoSize.height() + 1);
1039 break;
1041 case QStyleOptionViewItem::Bottom:
1042 textArea.setBottom(itemRect.height() - decoSize.height() - 1);
1043 break;
1045 case QStyleOptionViewItem::Left:
1046 textArea.setLeft(decoSize.width() + 1);
1047 break;
1049 case QStyleOptionViewItem::Right:
1050 textArea.setRight(itemRect.width() - decoSize.width() - 1);
1051 break;
1054 textArea.translate(itemRect.topLeft());
1055 return QStyle::visualRect(option.direction, option.rect, textArea);
1059 QPoint KFileItemDelegate::Private::iconPosition(const QStyleOptionViewItemV4 &option) const
1061 const QRect itemRect = subtractMargin(option.rect, Private::ItemMargin);
1062 Qt::Alignment alignment;
1064 // Convert decorationPosition to the alignment the decoration will have in option.rect
1065 switch (option.decorationPosition)
1067 case QStyleOptionViewItem::Top:
1068 alignment = Qt::AlignHCenter | Qt::AlignTop;
1069 break;
1071 case QStyleOptionViewItem::Bottom:
1072 alignment = Qt::AlignHCenter | Qt::AlignBottom;
1073 break;
1075 case QStyleOptionViewItem::Left:
1076 alignment = Qt::AlignVCenter | Qt::AlignLeft;
1077 break;
1079 case QStyleOptionViewItem::Right:
1080 alignment = Qt::AlignVCenter | Qt::AlignRight;
1081 break;
1084 // Compute the nominal decoration rectangle
1085 const QSize size = addMargin(option.decorationSize, Private::IconMargin);
1086 const QRect rect = QStyle::alignedRect(option.direction, alignment, size, itemRect);
1088 // Position the icon in the center of the rectangle
1089 QRect iconRect = QRect(QPoint(), option.icon.actualSize(option.decorationSize));
1090 iconRect.moveCenter(rect.center());
1092 return iconRect.topLeft();
1096 void KFileItemDelegate::Private::drawFocusRect(QPainter *painter, const QStyleOptionViewItemV4 &option,
1097 const QRect &rect) const
1099 if (!(option.state & QStyle::State_HasFocus))
1100 return;
1102 QStyleOptionFocusRect opt;
1103 opt.direction = option.direction;
1104 opt.fontMetrics = option.fontMetrics;
1105 opt.palette = option.palette;
1106 opt.rect = rect;
1107 opt.state = option.state | QStyle::State_KeyboardFocusChange | QStyle::State_Item;
1108 opt.backgroundColor = option.palette.color(option.state & QStyle::State_Selected ?
1109 QPalette::Highlight : QPalette::Base);
1111 // Apparently some widget styles expect this hint to not be set
1112 painter->setRenderHint(QPainter::Antialiasing, false);
1114 QStyle *style = option.widget ? option.widget->style() : QApplication::style();
1115 style->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, painter, option.widget);
1117 painter->setRenderHint(QPainter::Antialiasing);
1121 void KFileItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
1122 const QModelIndex &index) const
1124 if (!index.isValid())
1125 return;
1127 QStyleOptionViewItemV4 opt(option);
1128 d->initStyleOption(&opt, index);
1130 // Unset the mouse over bit if we're not drawing the first column
1131 if (index.column() > 0)
1132 opt.state &= ~QStyle::State_MouseOver;
1133 else
1134 opt.viewItemPosition = QStyleOptionViewItemV4::OnlyOne;
1136 const QAbstractItemView *view = qobject_cast<const QAbstractItemView*>(opt.widget);
1139 // Check if the item is being animated
1140 // ========================================================================
1141 KIO::AnimationState *state = d->animationState(opt, index, view);
1142 KIO::CachedRendering *cache = 0;
1143 qreal progress = ((opt.state & QStyle::State_MouseOver) &&
1144 index.column() == KDirModel::Name) ? 1.0 : 0.0;
1146 if (state)
1148 cache = state->cachedRendering();
1149 progress = state->hoverProgress();
1151 // Clear the mouse over bit temporarily
1152 opt.state &= ~QStyle::State_MouseOver;
1154 // If we have a cached rendering, draw the item from the cache
1155 if (cache)
1157 if (cache->checkValidity(opt.state) && cache->regular.size() == opt.rect.size())
1159 const QPixmap pixmap = d->transition(cache->regular, cache->hover, progress);
1160 painter->drawPixmap(option.rect.topLeft(), pixmap);
1161 return;
1164 // If it wasn't valid, delete it
1165 state->setCachedRendering(0);
1166 delete cache;
1167 cache = 0;
1171 d->setActiveMargins(d->verticalLayout(opt) ? Qt::Vertical : Qt::Horizontal);
1174 // Compute the metrics, and lay out the text items
1175 // ========================================================================
1176 const QPoint iconPos = d->iconPosition(opt);
1177 QIcon::Mode iconMode = option.state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled;
1178 QIcon::State iconState = option.state & QStyle::State_Open ? QIcon::On : QIcon::Off;
1179 QPixmap icon = opt.icon.pixmap(opt.decorationSize, iconMode, iconState);
1180 const QPen pen = QPen(d->foregroundBrush(opt, index), 0);
1182 ///### Apply the selection effect to the icon when the item is selected and
1183 // showDecorationSelected is false.
1185 QTextLayout labelLayout, infoLayout;
1186 QRect textBoundingRect;
1188 d->layoutTextItems(opt, index, &labelLayout, &infoLayout, &textBoundingRect);
1190 QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
1192 int focusHMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin);
1193 int focusVMargin = style->pixelMetric(QStyle::PM_FocusFrameVMargin);
1194 QRect focusRect = textBoundingRect.adjusted(-focusHMargin, -focusVMargin,
1195 +focusHMargin, +focusVMargin);
1197 // Create a new cached rendering of a hovered and an unhovered item.
1198 // We don't create a new cache for a fully hovered item, since we don't
1199 // know yet if a hover out animation will be run.
1200 // ========================================================================
1201 if (state && progress < 1)
1203 cache = new KIO::CachedRendering(opt.state, option.rect.size());
1205 QPainter p;
1206 p.begin(&cache->regular);
1207 p.translate(-option.rect.topLeft());
1208 p.setRenderHint(QPainter::Antialiasing);
1209 p.setPen(pen);
1210 style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, &p, opt.widget);
1211 p.drawPixmap(iconPos, icon);
1212 d->drawTextItems(&p, labelLayout, infoLayout, textBoundingRect);
1213 d->drawFocusRect(&p, opt, focusRect);
1214 p.end();
1216 opt.state |= QStyle::State_MouseOver;
1217 icon = d->applyHoverEffect(icon);
1219 p.begin(&cache->hover);
1220 p.translate(-option.rect.topLeft());
1221 p.setRenderHint(QPainter::Antialiasing);
1222 p.setPen(pen);
1223 style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, &p, opt.widget);
1224 p.drawPixmap(iconPos, icon);
1225 d->drawTextItems(&p, labelLayout, infoLayout, textBoundingRect);
1226 d->drawFocusRect(&p, opt, focusRect);
1227 p.end();
1229 state->setCachedRendering(cache);
1231 const QPixmap pixmap = d->transition(cache->regular, cache->hover, progress);
1232 painter->drawPixmap(option.rect.topLeft(), pixmap);
1233 return;
1237 // Render the item directly if we're not using a cached rendering
1238 // ========================================================================
1239 painter->save();
1240 painter->setRenderHint(QPainter::Antialiasing);
1241 painter->setPen(pen);
1243 if (progress > 0 && !(opt.state & QStyle::State_MouseOver))
1245 opt.state |= QStyle::State_MouseOver;
1246 icon = d->applyHoverEffect(icon);
1249 style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget);
1250 painter->drawPixmap(iconPos, icon);
1251 d->drawTextItems(painter, labelLayout, infoLayout, textBoundingRect);
1252 d->drawFocusRect(painter, opt, focusRect);
1254 painter->restore();
1258 QWidget *KFileItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option,
1259 const QModelIndex &index) const
1261 QStyleOptionViewItemV4 opt(option);
1262 d->initStyleOption(&opt, index);
1264 KTextEdit *edit = new KTextEdit(parent);
1265 edit->setAcceptRichText(false);
1266 edit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1267 edit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1268 edit->setAlignment(opt.displayAlignment);
1269 return edit;
1273 bool KFileItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
1274 const QModelIndex &index)
1276 Q_UNUSED(event)
1277 Q_UNUSED(model)
1278 Q_UNUSED(option)
1279 Q_UNUSED(index)
1281 return false;
1285 void KFileItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
1287 KTextEdit *textedit = qobject_cast<KTextEdit*>(editor);
1288 Q_ASSERT(textedit != 0);
1290 const QVariant value = index.data(Qt::EditRole);
1291 const QString text = value.toString();
1292 textedit->insertPlainText(text);
1293 textedit->selectAll();
1295 const QString extension = KMimeType::extractKnownExtension(text);
1296 if (!extension.isEmpty()) {
1297 // The filename contains an extension. Assure that only the filename
1298 // gets selected.
1299 const int selectionLength = text.length() - extension.length() - 1;
1300 QTextCursor cursor = textedit->textCursor();
1301 cursor.movePosition(QTextCursor::StartOfBlock);
1302 cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, selectionLength);
1303 textedit->setTextCursor(cursor);
1308 void KFileItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
1310 KTextEdit *textedit = qobject_cast<KTextEdit*>(editor);
1311 Q_ASSERT(textedit != 0);
1313 model->setData(index, textedit->toPlainText(), Qt::EditRole);
1317 void KFileItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
1318 const QModelIndex &index) const
1320 QStyleOptionViewItemV4 opt(option);
1321 d->initStyleOption(&opt, index);
1322 d->setActiveMargins(d->verticalLayout(opt) ? Qt::Vertical : Qt::Horizontal);
1324 QRect r = d->labelRectangle(opt);
1326 // Use the full available width for the editor when maximumSize is set
1327 if (d->verticalLayout(option) && !d->maximumSize.isEmpty()) {
1328 int diff = qMax(r.width(), d->maximumSize.width()) - r.width();
1329 if (diff > 1)
1330 r.adjust(-(diff / 2), 0, diff / 2, 0);
1333 KTextEdit *textedit = qobject_cast<KTextEdit*>(editor);
1334 Q_ASSERT(textedit != 0);
1335 const int frame = textedit->frameWidth();
1336 r.adjust(-frame, -frame, frame, frame);
1338 editor->setGeometry(r);
1342 bool KFileItemDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option,
1343 const QModelIndex &index)
1345 Q_UNUSED(event)
1346 Q_UNUSED(view)
1348 // if the tooltip information the model keeps is different from the display information,
1349 // show it always
1350 const QVariant toolTip = index.data(Qt::ToolTipRole);
1352 if (!toolTip.isValid()) {
1353 return false;
1356 if (index.data() != toolTip) {
1357 return QAbstractItemDelegate::helpEvent(event, view, option, index);
1360 if (!d->showToolTipWhenElided) {
1361 return false;
1364 // in the case the tooltip information is the same as the display information,
1365 // show it only in the case the display information is elided
1366 QStyleOptionViewItemV4 opt(option);
1367 d->initStyleOption(&opt, index);
1368 d->setActiveMargins(d->verticalLayout(opt) ? Qt::Vertical : Qt::Horizontal);
1370 QTextLayout labelLayout;
1371 QTextLayout infoLayout;
1372 QRect textBoundingRect;
1373 d->layoutTextItems(opt, index, &labelLayout, &infoLayout, &textBoundingRect);
1374 const QString elidedText = d->elidedText(labelLayout, opt, textBoundingRect.size());
1376 if (elidedText != d->display(index)) {
1377 return QAbstractItemDelegate::helpEvent(event, view, option, index);
1380 return false;
1383 QRegion KFileItemDelegate::shape(const QStyleOptionViewItem &option, const QModelIndex &index)
1385 QStyleOptionViewItemV4 opt(option);
1386 d->initStyleOption(&opt, index);
1387 d->setActiveMargins(d->verticalLayout(opt) ? Qt::Vertical : Qt::Horizontal);
1389 QTextLayout labelLayout;
1390 QTextLayout infoLayout;
1391 QRect textBoundingRect;
1392 d->layoutTextItems(opt, index, &labelLayout, &infoLayout, &textBoundingRect);
1394 const QPoint pos = d->iconPosition(opt);
1395 QRect iconRect = QRect(pos, opt.icon.actualSize(opt.decorationSize));
1397 // Extend the icon rect so it touches the text rect
1398 switch (opt.decorationPosition)
1400 case QStyleOptionViewItem::Top:
1401 if (iconRect.width() < textBoundingRect.width())
1402 iconRect.setBottom(textBoundingRect.top());
1403 else
1404 textBoundingRect.setTop(iconRect.bottom());
1405 break;
1406 case QStyleOptionViewItem::Bottom:
1407 if (iconRect.width() < textBoundingRect.width())
1408 iconRect.setTop(textBoundingRect.bottom());
1409 else
1410 textBoundingRect.setBottom(iconRect.top());
1411 break;
1412 case QStyleOptionViewItem::Left:
1413 iconRect.setRight(textBoundingRect.left());
1414 break;
1415 case QStyleOptionViewItem::Right:
1416 iconRect.setLeft(textBoundingRect.right());
1417 break;
1420 QRegion region;
1421 region += iconRect;
1422 region += textBoundingRect;
1423 return region;
1426 bool KFileItemDelegate::eventFilter(QObject *object, QEvent *event)
1428 KTextEdit *editor = qobject_cast<KTextEdit*>(object);
1429 if (!editor)
1430 return false;
1432 switch (event->type())
1434 case QEvent::KeyPress:
1436 QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
1437 switch (keyEvent->key())
1439 case Qt::Key_Tab:
1440 case Qt::Key_Backtab:
1441 emit commitData(editor);
1442 emit closeEditor(editor, NoHint);
1443 return true;
1445 case Qt::Key_Enter:
1446 case Qt::Key_Return:
1447 if (editor->toPlainText().isEmpty())
1448 return true; // So a newline doesn't get inserted
1450 emit commitData(editor);
1451 emit closeEditor(editor, SubmitModelCache);
1452 return true;
1454 case Qt::Key_Escape:
1455 emit closeEditor(editor, RevertModelCache);
1456 return true;
1458 default:
1459 return false;
1460 } // switch (keyEvent->key())
1461 } // case QEvent::KeyPress
1463 case QEvent::FocusOut:
1465 emit commitData(editor);
1466 emit closeEditor(editor, NoHint);
1467 return true;
1470 default:
1471 return false;
1472 } // switch (event->type())
1476 #include "kfileitemdelegate.moc"
1479 // kate: space-indent on; indent-width 4; replace-tabs on;