• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KIO

kfileitemdelegate.cpp

Go to the documentation of this file.
00001 /*
00002    This file is part of the KDE project
00003 
00004    Copyright © 2006-2007, 2008 Fredrik Höglund <fredrik@kde.org>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019    Boston, MA 02110-1301, USA.
00020 */
00021 
00022 #include "kfileitemdelegate.h"
00023 #include "imagefilter_p.h"
00024 
00025 #include <config.h> // for HAVE_XRENDER
00026 
00027 #include <QApplication>
00028 #include <QStyle>
00029 #include <QModelIndex>
00030 #include <QPainter>
00031 #include <QCache>
00032 #include <QImage>
00033 #include <QPainterPath>
00034 #include <QTextLayout>
00035 #include <QListView>
00036 #include <QPaintEngine>
00037 #include <qmath.h>
00038 
00039 #include <kglobal.h>
00040 #include <klocale.h>
00041 #include <kiconloader.h>
00042 #include <kiconeffect.h>
00043 #include <kdirmodel.h>
00044 #include <kfileitem.h>
00045 #include <kcolorscheme.h>
00046 #include <kglobalsettings.h>
00047 #include <ktextedit.h>
00048 
00049 #include "delegateanimationhandler_p.h"
00050 
00051 #if defined(Q_WS_X11) && defined(HAVE_XRENDER)
00052 #  include <X11/Xlib.h>
00053 #  include <X11/extensions/Xrender.h>
00054 #  include <QX11Info>
00055 #  undef KeyPress
00056 #  undef FocusOut
00057 #endif
00058 
00059 
00060 struct Margin
00061 {
00062     int left, right, top, bottom;
00063 };
00064 
00065 
00066 class KFileItemDelegate::Private
00067 {
00068     public:
00069         enum MarginType { ItemMargin = 0, TextMargin, IconMargin, NMargins };
00070 
00071         Private(KFileItemDelegate *parent);
00072         ~Private() {}
00073 
00074         QSize decorationSizeHint(const QStyleOptionViewItemV4 &option, const QModelIndex &index) const;
00075         QSize displaySizeHint(const QStyleOptionViewItemV4 &option, const QModelIndex &index) const;
00076         QString replaceNewlines(const QString &string) const;
00077         inline KFileItem fileItem(const QModelIndex &index) const;
00078         QString elidedText(QTextLayout &layout, const QStyleOptionViewItemV4 &option, const QSize &maxSize) const;
00079         QSize layoutText(QTextLayout &layout, const QStyleOptionViewItemV4 &option,
00080                          const QString &text, const QSize &constraints) const;
00081         QSize layoutText(QTextLayout &layout, const QString &text, int maxWidth) const;
00082         inline void setLayoutOptions(QTextLayout &layout, const QStyleOptionViewItemV4 &options) const;
00083         inline bool verticalLayout(const QStyleOptionViewItemV4 &option) const;
00084         inline QBrush brush(const QVariant &value, const QStyleOptionViewItemV4 &option) const;
00085         QBrush foregroundBrush(const QStyleOptionViewItemV4 &option, const QModelIndex &index) const;
00086         inline void setActiveMargins(Qt::Orientation layout);
00087         void setVerticalMargin(MarginType type, int left, int right, int top, int bottom);
00088         void setHorizontalMargin(MarginType type, int left, int right, int top, int bottom);
00089         inline void setVerticalMargin(MarginType type, int hor, int ver);
00090         inline void setHorizontalMargin(MarginType type, int hor, int ver);
00091         inline QRect addMargin(const QRect &rect, MarginType type) const;
00092         inline QRect subtractMargin(const QRect &rect, MarginType type) const;
00093         inline QSize addMargin(const QSize &size, MarginType type) const;
00094         inline QSize subtractMargin(const QSize &size, MarginType type) const;
00095         QString itemSize(const QModelIndex &index, const KFileItem &item) const;
00096         QString information(const QStyleOptionViewItemV4 &option, const QModelIndex &index, const KFileItem &item) const;
00097         bool isListView(const QStyleOptionViewItemV4 &option) const;
00098         QString display(const QModelIndex &index) const;
00099         QIcon decoration(const QStyleOptionViewItemV4 &option, const QModelIndex &index) const;
00100         QPoint iconPosition(const QStyleOptionViewItemV4 &option) const;
00101         QRect labelRectangle(const QStyleOptionViewItemV4 &option) const;
00102         void layoutTextItems(const QStyleOptionViewItemV4 &option, const QModelIndex &index,
00103                              QTextLayout *labelLayout, QTextLayout *infoLayout, QRect *textBoundingRect) const;
00104         void drawTextItems(QPainter *painter, const QTextLayout &labelLayout, const QTextLayout &infoLayout,
00105                            const QRect &textBoundingRect) const;
00106         KIO::AnimationState *animationState(const QStyleOptionViewItemV4 &option, const QModelIndex &index,
00107                                             const QAbstractItemView *view) const;
00108         QPixmap applyHoverEffect(const QPixmap &icon) const;
00109         QPixmap transition(const QPixmap &from, const QPixmap &to, qreal amount) const;
00110         void initStyleOption(QStyleOptionViewItemV4 *option, const QModelIndex &index) const;
00111         void drawFocusRect(QPainter *painter, const QStyleOptionViewItemV4 &option, const QRect &rect) const;
00112 
00113     public:
00114         KFileItemDelegate::InformationList informationList;
00115         QColor shadowColor;
00116         QPointF shadowOffset;
00117         qreal shadowBlur;
00118         QSize maximumSize;
00119 
00120     private:
00121         KFileItemDelegate * const q;
00122         KIO::DelegateAnimationHandler *animationHandler;
00123         Margin verticalMargin[NMargins];
00124         Margin horizontalMargin[NMargins];
00125         Margin *activeMargins;
00126 };
00127 
00128 
00129 KFileItemDelegate::Private::Private(KFileItemDelegate *parent)
00130      : shadowColor(Qt::transparent), shadowOffset(1, 1), shadowBlur(2), maximumSize(0, 0),
00131        q(parent), animationHandler(new KIO::DelegateAnimationHandler(parent))
00132 {
00133 }
00134 
00135 
00136 void KFileItemDelegate::Private::setActiveMargins(Qt::Orientation layout)
00137 {
00138     activeMargins = (layout == Qt::Horizontal ?
00139             horizontalMargin : verticalMargin);
00140 }
00141 
00142 
00143 void KFileItemDelegate::Private::setVerticalMargin(MarginType type, int left, int top, int right, int bottom)
00144 {
00145     verticalMargin[type].left   = left;
00146     verticalMargin[type].right  = right;
00147     verticalMargin[type].top    = top;
00148     verticalMargin[type].bottom = bottom;
00149 }
00150 
00151 
00152 void KFileItemDelegate::Private::setHorizontalMargin(MarginType type, int left, int top, int right, int bottom)
00153 {
00154     horizontalMargin[type].left   = left;
00155     horizontalMargin[type].right  = right;
00156     horizontalMargin[type].top    = top;
00157     horizontalMargin[type].bottom = bottom;
00158 }
00159 
00160 
00161 void KFileItemDelegate::Private::setVerticalMargin(MarginType type, int horizontal, int vertical)
00162 {
00163     setVerticalMargin(type, horizontal, vertical, horizontal, vertical);
00164 }
00165 
00166 
00167 void KFileItemDelegate::Private::setHorizontalMargin(MarginType type, int horizontal, int vertical)
00168 {
00169     setHorizontalMargin(type, horizontal, vertical, horizontal, vertical);
00170 }
00171 
00172 
00173 QRect KFileItemDelegate::Private::addMargin(const QRect &rect, MarginType type) const
00174 {
00175     const Margin &m = activeMargins[type];
00176     return rect.adjusted(-m.left, -m.top, m.right, m.bottom);
00177 }
00178 
00179 
00180 QRect KFileItemDelegate::Private::subtractMargin(const QRect &rect, MarginType type) const
00181 {
00182     const Margin &m = activeMargins[type];
00183     return rect.adjusted(m.left, m.top, -m.right, -m.bottom);
00184 }
00185 
00186 
00187 QSize KFileItemDelegate::Private::addMargin(const QSize &size, MarginType type) const
00188 {
00189     const Margin &m = activeMargins[type];
00190     return QSize(size.width() + m.left + m.right, size.height() + m.top + m.bottom);
00191 }
00192 
00193 
00194 QSize KFileItemDelegate::Private::subtractMargin(const QSize &size, MarginType type) const
00195 {
00196     const Margin &m = activeMargins[type];
00197     return QSize(size.width() - m.left - m.right, size.height() - m.top - m.bottom);
00198 }
00199 
00200 
00201 // Returns the size of a file, or the number of items in a directory, as a QString
00202 QString KFileItemDelegate::Private::itemSize(const QModelIndex &index, const KFileItem &item) const
00203 {
00204     // Return a formatted string containing the file size, if the item is a file
00205     if (item.isFile())
00206         return KGlobal::locale()->formatByteSize(item.size());
00207 
00208     // Return the number of items in the directory
00209     const QVariant value = index.data(KDirModel::ChildCountRole);
00210     const int count = value.type() == QVariant::Int ? value.toInt() : KDirModel::ChildCountUnknown;
00211 
00212     if (count == KDirModel::ChildCountUnknown) {
00213         // was: i18nc("Items in a folder", "? items");
00214         // but this just looks useless in a remote directory listing,
00215         // better not show anything.
00216         return QString();
00217     }
00218 
00219     return i18ncp("Items in a folder", "1 item", "%1 items", count);
00220 }
00221 
00222 
00223 // Returns the additional information string, if one should be shown, or an empty string otherwise
00224 QString KFileItemDelegate::Private::information(const QStyleOptionViewItemV4 &option, const QModelIndex &index,
00225                                                 const KFileItem &item) const
00226 {
00227     QString string;
00228 
00229     if (informationList.isEmpty() || item.isNull() || !isListView(option))
00230         return string;
00231 
00232     foreach (KFileItemDelegate::Information info, informationList)
00233     {
00234         if (info == KFileItemDelegate::NoInformation)
00235             continue;
00236 
00237         if (!string.isEmpty())
00238             string += QChar::LineSeparator;
00239 
00240         switch (info)
00241         {
00242             case KFileItemDelegate::Size:
00243                 string += itemSize(index, item);
00244                 break;
00245 
00246             case KFileItemDelegate::Permissions:
00247                 string += item.permissionsString();
00248                 break;
00249 
00250             case KFileItemDelegate::OctalPermissions:
00251                 string += QString('0') + QString::number(item.permissions(), 8);
00252                 break;
00253 
00254             case KFileItemDelegate::Owner:
00255                 string += item.user();
00256                 break;
00257 
00258             case KFileItemDelegate::OwnerAndGroup:
00259                 string += item.user() + ':' + item.group();
00260                 break;
00261 
00262             case KFileItemDelegate::CreationTime:
00263                 string += item.timeString(KFileItem::CreationTime);
00264                 break;
00265 
00266             case KFileItemDelegate::ModificationTime:
00267                 string += item.timeString(KFileItem::ModificationTime);
00268                 break;
00269 
00270             case KFileItemDelegate::AccessTime:
00271                 string += item.timeString(KFileItem::AccessTime);
00272                 break;
00273 
00274             case KFileItemDelegate::MimeType:
00275                 string += item.isMimeTypeKnown() ? item.mimetype() : i18nc("@info mimetype","Unknown");
00276                 break;
00277 
00278             case KFileItemDelegate::FriendlyMimeType:
00279                 string += item.isMimeTypeKnown() ? item.mimeComment() : i18nc("@info mimetype","Unknown");
00280                 break;
00281 
00282             default:
00283                 break;
00284         } // switch (info)
00285     } // foreach (info, list)
00286 
00287     return string;
00288 }
00289 
00290 
00291 // Returns the KFileItem for the index
00292 KFileItem KFileItemDelegate::Private::fileItem(const QModelIndex &index) const
00293 {
00294     const QVariant value = index.data(KDirModel::FileItemRole);
00295     return qvariant_cast<KFileItem>(value);
00296 }
00297 
00298 
00299 // Replaces any newline characters in the provided string, with QChar::LineSeparator
00300 QString KFileItemDelegate::Private::replaceNewlines(const QString &text) const
00301 {
00302     QString string = text;
00303     const QChar newline = QLatin1Char('\n');
00304 
00305     for (int i = 0; i < string.length(); i++)
00306         if (string[i] == newline)
00307             string[i] = QChar::LineSeparator;
00308 
00309     return string;
00310 }
00311 
00312 
00313 // Lays the text out in a rectangle no larger than constraints, eliding it as necessary
00314 QSize KFileItemDelegate::Private::layoutText(QTextLayout &layout, const QStyleOptionViewItemV4 &option,
00315                                              const QString &text, const QSize &constraints) const
00316 {
00317     const QSize size = layoutText(layout, text, constraints.width());
00318 
00319     if (size.width() > constraints.width() || size.height() > constraints.height())
00320     {
00321         const QString elided = elidedText(layout, option, constraints);
00322         return layoutText(layout, elided, constraints.width());
00323     }
00324 
00325     return size;
00326 }
00327 
00328 
00329 // Lays the text out in a rectangle no wider than maxWidth
00330 QSize KFileItemDelegate::Private::layoutText(QTextLayout &layout, const QString &text, int maxWidth) const
00331 {
00332     QFontMetrics metrics(layout.font());
00333     int leading     = metrics.leading();
00334     int height      = 0;
00335     qreal widthUsed = 0;
00336     QTextLine line;
00337 
00338     layout.setText(text);
00339 
00340     layout.beginLayout();
00341     while ((line = layout.createLine()).isValid())
00342     {
00343         line.setLineWidth(int(maxWidth));
00344         height += leading;
00345         line.setPosition(QPoint(0, height));
00346         height += int(line.height());
00347         widthUsed = qMax(widthUsed, line.naturalTextWidth());
00348     }
00349     layout.endLayout();
00350 
00351     return QSize(int(widthUsed), height);
00352 }
00353 
00354 
00355 // Elides the text in the layout, by iterating over each line in the layout, eliding
00356 // or word breaking the line if it's wider than the max width, and finally adding an
00357 // ellipses at the end of the last line, if there are more lines than will fit within
00358 // the vertical size constraints.
00359 QString KFileItemDelegate::Private::elidedText(QTextLayout &layout, const QStyleOptionViewItemV4 &option,
00360                                                const QSize &size) const
00361 {
00362     const QString text = layout.text();
00363     int maxWidth       = size.width();
00364     int maxHeight      = size.height();
00365     qreal height       = 0;
00366     bool wrapText      = (option.features & QStyleOptionViewItemV2::WrapText);
00367 
00368     // If the string contains a single line of text that shouldn't be word wrapped
00369     if (!wrapText && text.indexOf(QChar::LineSeparator) == -1)
00370         return option.fontMetrics.elidedText(text, option.textElideMode, maxWidth);
00371 
00372     // Elide each line that has already been laid out in the layout.
00373     QString elided;
00374     elided.reserve(text.length());
00375 
00376     for (int i = 0; i < layout.lineCount(); i++)
00377     {
00378         QTextLine line = layout.lineAt(i);
00379         int start  = line.textStart();
00380         int length = line.textLength();
00381 
00382         height += option.fontMetrics.leading();
00383         if (height + line.height() + option.fontMetrics.lineSpacing() > maxHeight)
00384         {
00385             // Unfortunately, if the line ends because of a line separator, elidedText() will be too
00386             // clever and keep adding lines until it finds one that's too wide.
00387             if (line.naturalTextWidth() < maxWidth && text[start + length - 1] == QChar::LineSeparator)
00388                 elided += text.mid(start, length - 1);
00389             else
00390                 elided += option.fontMetrics.elidedText(text.mid(start), option.textElideMode, maxWidth);
00391             break;
00392         }
00393         else if (line.naturalTextWidth() > maxWidth)
00394         {
00395             elided += option.fontMetrics.elidedText(text.mid(start, length), option.textElideMode, maxWidth);
00396             if (!elided.endsWith(QChar::LineSeparator))
00397                 elided += QChar::LineSeparator;
00398         }
00399         else
00400             elided += text.mid(start, length);
00401 
00402         height += line.height();
00403     }
00404 
00405     return elided;
00406 }
00407 
00408 
00409 void KFileItemDelegate::Private::setLayoutOptions(QTextLayout &layout, const QStyleOptionViewItemV4 &option) const
00410 {
00411     QTextOption textoption;
00412     textoption.setTextDirection(option.direction);
00413     textoption.setAlignment(QStyle::visualAlignment(option.direction, option.displayAlignment));
00414     textoption.setWrapMode((option.features & QStyleOptionViewItemV2::WrapText) ?
00415                            QTextOption::WrapAtWordBoundaryOrAnywhere : QTextOption::NoWrap);
00416 
00417     layout.setFont(option.font);
00418     layout.setTextOption(textoption);
00419 }
00420 
00421 
00422 QSize KFileItemDelegate::Private::displaySizeHint(const QStyleOptionViewItemV4 &option,
00423                                                   const QModelIndex &index) const
00424 {
00425     QString label = option.text;
00426     int maxWidth = 0;
00427     if (maximumSize.isEmpty()) {
00428         maxWidth = verticalLayout(option) && (option.features & QStyleOptionViewItemV2::WrapText)
00429                    ? option.decorationSize.width() + 10 : 32757;
00430     }
00431     else {
00432         const Margin &itemMargin = activeMargins[ItemMargin];
00433         const Margin &textMargin = activeMargins[TextMargin];
00434         maxWidth = maximumSize.width() -
00435                    (itemMargin.left + itemMargin.right) -
00436                    (textMargin.left + textMargin.right);
00437     }
00438 
00439     KFileItem item = fileItem(index);
00440 
00441     // To compute the nominal size for the label + info, we'll just append
00442     // the information string to the label
00443     const QString info = information(option, index, item);
00444     if (!info.isEmpty())
00445         label += QString(QChar::LineSeparator) + info;
00446 
00447     QTextLayout layout;
00448     setLayoutOptions(layout, option);
00449 
00450     QSize size = layoutText(layout, label, maxWidth);
00451     return addMargin(size, TextMargin);
00452 }
00453 
00454 
00455 QSize KFileItemDelegate::Private::decorationSizeHint(const QStyleOptionViewItemV4 &option,
00456                                                      const QModelIndex &index) const
00457 {
00458     Q_UNUSED(index)
00459 
00460     QSize iconSize = option.icon.actualSize(option.decorationSize);
00461     if (iconSize.width() < option.decorationSize.width())
00462         iconSize.rwidth() = qMin(iconSize.width() + 10, option.decorationSize.width());
00463     if (iconSize.height() < option.decorationSize.height())
00464         iconSize.rheight() = option.decorationSize.height();
00465 
00466     return addMargin(iconSize, IconMargin);
00467 }
00468 
00469 
00470 bool KFileItemDelegate::Private::verticalLayout(const QStyleOptionViewItemV4 &option) const
00471 {
00472     return (option.decorationPosition == QStyleOptionViewItem::Top ||
00473             option.decorationPosition == QStyleOptionViewItem::Bottom);
00474 }
00475 
00476 
00477 // Converts a QVariant of type Brush or Color to a QBrush
00478 QBrush KFileItemDelegate::Private::brush(const QVariant &value, const QStyleOptionViewItemV4 &option) const
00479 {
00480     if (value.userType() == qMetaTypeId<KStatefulBrush>())
00481         return qvariant_cast<KStatefulBrush>(value).brush(option.palette);
00482     switch (value.type())
00483     {
00484         case QVariant::Color:
00485             return QBrush(qvariant_cast<QColor>(value));
00486 
00487         case QVariant::Brush:
00488             return qvariant_cast<QBrush>(value);
00489 
00490         default:
00491             return QBrush(Qt::NoBrush);
00492     }
00493 }
00494 
00495 
00496 QBrush KFileItemDelegate::Private::foregroundBrush(const QStyleOptionViewItemV4 &option, const QModelIndex &index) const
00497 {
00498     // Always use the highlight color for selected items
00499     if (option.state & QStyle::State_Selected)
00500         return option.palette.brush(QPalette::HighlightedText);
00501 
00502     // If the model provides its own foreground color/brush for this item
00503     const QVariant value = index.data(Qt::ForegroundRole);
00504     if (value.isValid())
00505         return brush(value, option);
00506 
00507     return option.palette.brush(QPalette::Text);
00508 }
00509 
00510 
00511 bool KFileItemDelegate::Private::isListView(const QStyleOptionViewItemV4 &option) const
00512 {
00513     if (qobject_cast<const QListView*>(option.widget) || verticalLayout(option))
00514         return true;
00515 
00516     return false;
00517 }
00518 
00519 
00520 QPixmap KFileItemDelegate::Private::applyHoverEffect(const QPixmap &icon) const
00521 {
00522     KIconEffect *effect = KIconLoader::global()->iconEffect();
00523 
00524     // Note that in KIconLoader terminology, active = hover.
00525     // ### We're assuming that the icon group is desktop/filemanager, since this
00526     //     is KFileItemDelegate.
00527     if (effect->hasEffect(KIconLoader::Desktop, KIconLoader::ActiveState))
00528         return effect->apply(icon, KIconLoader::Desktop, KIconLoader::ActiveState);
00529 
00530     return icon;
00531 }
00532 
00533 
00534 KIO::AnimationState *KFileItemDelegate::Private::animationState(const QStyleOptionViewItemV4 &option,
00535                                                                 const QModelIndex &index,
00536                                                                 const QAbstractItemView *view) const
00537 {
00538     if (!(KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects)) {
00539         return NULL;
00540     }
00541 
00542     if (index.column() == KDirModel::Name)
00543         return animationHandler->animationState(option, index, view);
00544 
00545     return NULL;
00546 }
00547 
00548 
00549 QPixmap KFileItemDelegate::Private::transition(const QPixmap &from, const QPixmap &to, qreal amount) const
00550 {
00551     int value = int(0xff * amount);
00552 
00553     if (value == 0)
00554         return from;
00555 
00556     if (value == 1)
00557         return to;
00558 
00559     QColor color;
00560     color.setAlphaF(amount);
00561 
00562     // If the native paint engine supports Porter/Duff compositing and CompositionMode_Plus
00563     if (from.paintEngine()->hasFeature(QPaintEngine::PorterDuff) &&
00564         from.paintEngine()->hasFeature(QPaintEngine::BlendModes))
00565     {
00566         QPixmap under = from;
00567         QPixmap over  = to;
00568 
00569         QPainter p;
00570         p.begin(&over);
00571         p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
00572         p.fillRect(over.rect(), color);
00573         p.end();
00574 
00575         p.begin(&under);
00576         p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
00577         p.fillRect(under.rect(), color);
00578         p.setCompositionMode(QPainter::CompositionMode_Plus);
00579         p.drawPixmap(0, 0, over);
00580         p.end();
00581 
00582         return under;
00583     }
00584 #if defined(Q_WS_X11) && defined(HAVE_XRENDER)
00585     else if (from.paintEngine()->hasFeature(QPaintEngine::PorterDuff)) // We have Xrender support
00586     {
00587         // QX11PaintEngine doesn't implement CompositionMode_Plus in Qt 4.3,
00588         // which we need to be able to do a transition from one pixmap to
00589         // another.
00590         //
00591         // In order to avoid the overhead of converting the pixmaps to images
00592         // and doing the operation entirely in software, this function has a
00593         // specialized path for X11 that uses Xrender directly to do the
00594         // transition. This operation can be fully accelerated in HW.
00595         //
00596         // This specialization can be removed when QX11PaintEngine supports
00597         // CompositionMode_Plus.
00598         QPixmap source(to), destination(from);
00599 
00600         source.detach();
00601         destination.detach();
00602 
00603         Display *dpy = QX11Info::display();
00604 
00605         XRenderPictFormat *format = XRenderFindStandardFormat(dpy, PictStandardA8);
00606         XRenderPictureAttributes pa;
00607         pa.repeat = 1; // RepeatNormal
00608 
00609         // Create a 1x1 8 bit repeating alpha picture
00610         Pixmap pixmap = XCreatePixmap(dpy, destination.handle(), 1, 1, 8);
00611         Picture alpha = XRenderCreatePicture(dpy, pixmap, format, CPRepeat, &pa);
00612         XFreePixmap(dpy, pixmap);
00613 
00614         // Fill the alpha picture with the opacity value
00615         XRenderColor xcolor;
00616         xcolor.alpha = quint16(0xffff * amount);
00617         XRenderFillRectangle(dpy, PictOpSrc, alpha, &xcolor, 0, 0, 1, 1);
00618 
00619         // Reduce the alpha of the destination with 1 - opacity
00620         XRenderComposite(dpy, PictOpOutReverse, alpha, None, destination.x11PictureHandle(),
00621                          0, 0, 0, 0, 0, 0, destination.width(), destination.height());
00622 
00623         // Add source * opacity to the destination
00624         XRenderComposite(dpy, PictOpAdd, source.x11PictureHandle(), alpha,
00625                          destination.x11PictureHandle(),
00626                          0, 0, 0, 0, 0, 0, destination.width(), destination.height());
00627 
00628         XRenderFreePicture(dpy, alpha);
00629         return destination;
00630     }
00631 #endif
00632     else
00633     {
00634         // Fall back to using QRasterPaintEngine to do the transition.
00635         QImage under = from.toImage();
00636         QImage over  = to.toImage();
00637 
00638         QPainter p;
00639         p.begin(&over);
00640         p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
00641         p.fillRect(over.rect(), color);
00642         p.end();
00643 
00644         p.begin(&under);
00645         p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
00646         p.fillRect(under.rect(), color);
00647         p.setCompositionMode(QPainter::CompositionMode_Plus);
00648         p.drawImage(0, 0, over);
00649         p.end();
00650 
00651         return QPixmap::fromImage(under);
00652     }
00653 }
00654 
00655 
00656 void KFileItemDelegate::Private::layoutTextItems(const QStyleOptionViewItemV4 &option, const QModelIndex &index,
00657                                                  QTextLayout *labelLayout, QTextLayout *infoLayout,
00658                                                  QRect *textBoundingRect) const
00659 {
00660     KFileItem item       = fileItem(index);
00661     const QString info   = information(option, index, item);
00662     bool showInformation = false;
00663 
00664     setLayoutOptions(*labelLayout, option);
00665 
00666     const QRect textArea = labelRectangle(option);
00667     QRect textRect       = subtractMargin(textArea, Private::TextMargin);
00668 
00669     // Sizes and constraints for the different text parts
00670     QSize maxLabelSize = textRect.size();
00671     QSize maxInfoSize  = textRect.size();
00672     QSize labelSize;
00673     QSize infoSize;
00674 
00675     // If we have additional info text, and there's space for at least two lines of text,
00676     // adjust the max label size to make room for at least one line of the info text
00677     if (!info.isEmpty() && textRect.height() >= option.fontMetrics.lineSpacing() * 2)
00678     {
00679         infoLayout->setFont(labelLayout->font());
00680         infoLayout->setTextOption(labelLayout->textOption());
00681 
00682         maxLabelSize.rheight() -= option.fontMetrics.lineSpacing();
00683         showInformation = true;
00684     }
00685 
00686     // Lay out the label text, and adjust the max info size based on the label size
00687     labelSize = layoutText(*labelLayout, option, option.text, maxLabelSize);
00688     maxInfoSize.rheight() -= labelSize.height();
00689 
00690     // Lay out the info text
00691     if (showInformation)
00692         infoSize = layoutText(*infoLayout, option, info, maxInfoSize);
00693     else
00694         infoSize = QSize(0, 0);
00695 
00696     // Compute the bounding rect of the text
00697     const QSize size(qMax(labelSize.width(), infoSize.width()), labelSize.height() + infoSize.height());
00698     *textBoundingRect = QStyle::alignedRect(option.direction, option.displayAlignment, size, textRect);
00699 
00700     // Compute the positions where we should draw the layouts
00701     labelLayout->setPosition(QPointF(textRect.x(), textBoundingRect->y()));
00702     infoLayout->setPosition(QPointF(textRect.x(), textBoundingRect->y() + labelSize.height()));
00703 }
00704 
00705 
00706 void KFileItemDelegate::Private::drawTextItems(QPainter *painter, const QTextLayout &labelLayout,
00707                                                const QTextLayout &infoLayout, const QRect &boundingRect) const
00708 {
00709     if (shadowColor.alpha() > 0)
00710     {
00711         QPixmap pixmap(boundingRect.size());
00712         pixmap.fill(Qt::transparent);
00713 
00714         QPainter p(&pixmap);
00715         p.translate(-boundingRect.topLeft());
00716         p.setPen(painter->pen());
00717         labelLayout.draw(&p, QPoint());
00718 
00719         if (!infoLayout.text().isEmpty())
00720         {
00721             QColor color = p.pen().color();
00722             color.setAlphaF(0.6);
00723 
00724             p.setPen(color);
00725             infoLayout.draw(&p, QPoint());
00726         }
00727         p.end();
00728 
00729         int padding = qCeil(shadowBlur);
00730         int blurFactor = qRound(shadowBlur);
00731 
00732         QImage image(boundingRect.size() + QSize(padding * 2, padding * 2), QImage::Format_ARGB32_Premultiplied);
00733         image.fill(Qt::transparent);
00734         p.begin(&image);
00735         p.drawImage(padding, padding, pixmap.toImage());
00736         p.end();
00737 
00738         KIO::ImageFilter::shadowBlur(image, blurFactor, shadowColor);
00739 
00740         painter->drawImage(boundingRect.topLeft() - QPoint(padding, padding) + shadowOffset.toPoint(), image);
00741         painter->drawPixmap(boundingRect.topLeft(), pixmap);
00742         return;
00743     }
00744 
00745     labelLayout.draw(painter, QPoint());
00746 
00747     if (!infoLayout.text().isEmpty())
00748     {
00749         // TODO - for apps not doing funny things with the color palette,
00750         // KColorScheme::InactiveText would be a much more correct choice. We
00751         // should provide an API to specify what color to use for information.
00752         QColor color = painter->pen().color();
00753         color.setAlphaF(0.6);
00754 
00755         painter->setPen(color);
00756         infoLayout.draw(painter, QPoint());
00757     }
00758 }
00759 
00760 
00761 void KFileItemDelegate::Private::initStyleOption(QStyleOptionViewItemV4 *option,
00762                                                  const QModelIndex &index) const
00763 {
00764     const KFileItem item = fileItem(index);
00765     bool updateFontMetrics = false;
00766 
00767     // Try to get the font from the model
00768     QVariant value = index.data(Qt::FontRole);
00769     if (value.isValid()) {
00770         option->font = qvariant_cast<QFont>(value).resolve(option->font);
00771         updateFontMetrics = true;
00772     }
00773 
00774     // Use an italic font for symlinks
00775     if (!item.isNull() && item.isLink()) {
00776         option->font.setItalic(true);
00777         updateFontMetrics = true;
00778     }
00779 
00780     if (updateFontMetrics)
00781         option->fontMetrics = QFontMetrics(option->font);
00782 
00783     // Try to get the alignment for the item from the model
00784     value = index.data(Qt::TextAlignmentRole);
00785     if (value.isValid())
00786         option->displayAlignment = Qt::Alignment(value.toInt());
00787 
00788     value = index.data(Qt::BackgroundRole);
00789     if (value.isValid())
00790         option->backgroundBrush = brush(value, *option);
00791 
00792     option->text = display(index);
00793     if (!option->text.isEmpty())
00794         option->features |= QStyleOptionViewItemV2::HasDisplay;
00795 
00796     option->icon = decoration(*option, index);
00797     if (!option->icon.isNull())
00798         option->features |= QStyleOptionViewItemV2::HasDecoration;
00799 
00800     // ### Make sure this value is always true for now
00801     option->showDecorationSelected = true;
00802 }
00803 
00804 
00805 
00806 
00807 // ---------------------------------------------------------------------------
00808 
00809 
00810 
00811 
00812 KFileItemDelegate::KFileItemDelegate(QObject *parent)
00813     : QAbstractItemDelegate(parent), d(new Private(this))
00814 {
00815     int focusHMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin);
00816     int focusVMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameVMargin);
00817 
00818     // Margins for horizontal mode (list views, tree views, table views)
00819     const int textMargin = focusHMargin * 4;
00820     if (QApplication::isRightToLeft())
00821         d->setHorizontalMargin(Private::TextMargin, textMargin, focusVMargin, focusHMargin, focusVMargin);
00822     else
00823         d->setHorizontalMargin(Private::TextMargin, focusHMargin, focusVMargin, textMargin, focusVMargin);
00824 
00825     d->setHorizontalMargin(Private::IconMargin, focusHMargin, focusVMargin);
00826     d->setHorizontalMargin(Private::ItemMargin, 0, 0);
00827 
00828     // Margins for vertical mode (icon views)
00829     d->setVerticalMargin(Private::TextMargin, 6, 2);
00830     d->setVerticalMargin(Private::IconMargin, focusHMargin, focusVMargin);
00831     d->setVerticalMargin(Private::ItemMargin, 0, 0);
00832 
00833     setShowInformation(NoInformation);
00834 }
00835 
00836 
00837 KFileItemDelegate::~KFileItemDelegate()
00838 {
00839     delete d;
00840 }
00841 
00842 
00843 QSize KFileItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
00844 {
00845     // If the model wants to provide its own size hint for the item
00846     const QVariant value = index.data(Qt::SizeHintRole);
00847     if (value.isValid())
00848         return qvariant_cast<QSize>(value);
00849 
00850     QStyleOptionViewItemV4 opt(option);
00851     d->initStyleOption(&opt, index);
00852     d->setActiveMargins(d->verticalLayout(opt) ? Qt::Vertical : Qt::Horizontal);
00853 
00854     const QSize displaySize    = d->displaySizeHint(opt, index);
00855     const QSize decorationSize = d->decorationSizeHint(opt, index);
00856 
00857     QSize size;
00858 
00859     if (d->verticalLayout(opt))
00860     {
00861         size.rwidth()  = qMax(displaySize.width(), decorationSize.width());
00862         size.rheight() = decorationSize.height() + displaySize.height() + 1;
00863     }
00864     else
00865     {
00866         size.rwidth()  = decorationSize.width() + displaySize.width() + 1;
00867         size.rheight() = qMax(decorationSize.height(), displaySize.height());
00868     }
00869 
00870     size = d->addMargin(size, Private::ItemMargin);
00871     if (!d->maximumSize.isEmpty())
00872     {
00873         size = size.boundedTo(d->maximumSize);
00874     }
00875 
00876     return size;
00877 }
00878 
00879 
00880 QString KFileItemDelegate::Private::display(const QModelIndex &index) const
00881 {
00882     const QVariant value = index.data(Qt::DisplayRole);
00883 
00884     switch (value.type())
00885     {
00886         case QVariant::String:
00887         {
00888             if (index.column() == KDirModel::Size)
00889                 return itemSize(index, fileItem(index));
00890             else
00891                 return replaceNewlines(value.toString());
00892         }
00893 
00894         case QVariant::Double:
00895             return KGlobal::locale()->formatNumber(value.toDouble());
00896 
00897         case QVariant::Int:
00898         case QVariant::UInt:
00899             return KGlobal::locale()->formatLong(value.toInt());
00900 
00901         default:
00902             return QString();
00903     }
00904 }
00905 
00906 
00907 void KFileItemDelegate::setShowInformation(const InformationList &list)
00908 {
00909     d->informationList = list;
00910 }
00911 
00912 
00913 void KFileItemDelegate::setShowInformation(Information value)
00914 {
00915     if (value != NoInformation)
00916         d->informationList = InformationList() << value;
00917     else
00918         d->informationList = InformationList();
00919 }
00920 
00921 
00922 KFileItemDelegate::InformationList KFileItemDelegate::showInformation() const
00923 {
00924     return d->informationList;
00925 }
00926 
00927 
00928 void KFileItemDelegate::setShadowColor(const QColor &color)
00929 {
00930     d->shadowColor = color;
00931 }
00932 
00933 
00934 QColor KFileItemDelegate::shadowColor() const
00935 {
00936     return d->shadowColor;
00937 }
00938 
00939 
00940 void KFileItemDelegate::setShadowOffset(const QPointF &offset)
00941 {
00942     d->shadowOffset = offset;
00943 }
00944 
00945 
00946 QPointF KFileItemDelegate::shadowOffset() const
00947 {
00948     return d->shadowOffset;
00949 }
00950 
00951 
00952 void KFileItemDelegate::setShadowBlur(qreal factor)
00953 {
00954     d->shadowBlur = factor;
00955 }
00956 
00957 
00958 qreal KFileItemDelegate::shadowBlur() const
00959 {
00960     return d->shadowBlur;
00961 }
00962 
00963 
00964 void KFileItemDelegate::setMaximumSize(const QSize &size)
00965 {
00966     d->maximumSize = size;
00967 }
00968 
00969 
00970 QSize KFileItemDelegate::maximumSize() const
00971 {
00972     return d->maximumSize;
00973 }
00974 
00975 
00976 QIcon KFileItemDelegate::Private::decoration(const QStyleOptionViewItemV4 &option, const QModelIndex &index) const
00977 {
00978     const QVariant value = index.data(Qt::DecorationRole);
00979     QIcon icon;
00980 
00981     switch (value.type())
00982     {
00983     case QVariant::Icon:
00984         icon = qvariant_cast<QIcon>(value);
00985         break;
00986 
00987     case QVariant::Pixmap:
00988         icon.addPixmap(qvariant_cast<QPixmap>(value));
00989         break;
00990 
00991     case QVariant::Color: {
00992         QPixmap pixmap(option.decorationSize);
00993         pixmap.fill(qvariant_cast<QColor>(value));
00994         icon.addPixmap(pixmap);
00995         break;
00996     }
00997 
00998     default:
00999         break;
01000     }
01001 
01002     return icon;
01003 }
01004 
01005 
01006 QRect KFileItemDelegate::Private::labelRectangle(const QStyleOptionViewItemV4 &option) const
01007 {
01008     if (option.icon.isNull())
01009         return subtractMargin(option.rect, Private::ItemMargin);
01010 
01011     const QSize decoSize = addMargin(option.decorationSize, Private::IconMargin);
01012     const QRect itemRect = subtractMargin(option.rect, Private::ItemMargin);
01013     QRect textArea(QPoint(0, 0), itemRect.size());
01014 
01015     switch (option.decorationPosition)
01016     {
01017         case QStyleOptionViewItem::Top:
01018             textArea.setTop(decoSize.height() + 1);
01019             break;
01020 
01021         case QStyleOptionViewItem::Bottom:
01022             textArea.setBottom(itemRect.height() - decoSize.height() - 1);
01023             break;
01024 
01025         case QStyleOptionViewItem::Left:
01026             textArea.setLeft(decoSize.width() + 1);
01027             break;
01028 
01029         case QStyleOptionViewItem::Right:
01030             textArea.setRight(itemRect.width() - decoSize.width() - 1);
01031             break;
01032     }
01033 
01034     textArea.translate(itemRect.topLeft());
01035     return QStyle::visualRect(option.direction, option.rect, textArea);
01036 }
01037 
01038 
01039 QPoint KFileItemDelegate::Private::iconPosition(const QStyleOptionViewItemV4 &option) const
01040 {
01041     const QRect itemRect = subtractMargin(option.rect, Private::ItemMargin);
01042     Qt::Alignment alignment;
01043 
01044     // Convert decorationPosition to the alignment the decoration will have in option.rect
01045     switch (option.decorationPosition)
01046     {
01047         case QStyleOptionViewItem::Top:
01048             alignment = Qt::AlignHCenter | Qt::AlignTop;
01049             break;
01050 
01051         case QStyleOptionViewItem::Bottom:
01052             alignment = Qt::AlignHCenter | Qt::AlignBottom;
01053             break;
01054 
01055         case QStyleOptionViewItem::Left:
01056             alignment = Qt::AlignVCenter | Qt::AlignLeft;
01057             break;
01058 
01059         case QStyleOptionViewItem::Right:
01060             alignment = Qt::AlignVCenter | Qt::AlignRight;
01061             break;
01062     }
01063 
01064     // Compute the nominal decoration rectangle
01065     const QSize size = addMargin(option.decorationSize, Private::IconMargin);
01066     const QRect rect = QStyle::alignedRect(option.direction, alignment, size, itemRect);
01067 
01068     // Position the icon in the center of the rectangle
01069     QRect iconRect = QRect(QPoint(), option.icon.actualSize(option.decorationSize));
01070     iconRect.moveCenter(rect.center());
01071 
01072     return iconRect.topLeft();
01073 }
01074 
01075 
01076 void KFileItemDelegate::Private::drawFocusRect(QPainter *painter, const QStyleOptionViewItemV4 &option,
01077                                                const QRect &rect) const
01078 {
01079     if (!(option.state & QStyle::State_HasFocus))
01080         return;
01081 
01082     QStyleOptionFocusRect opt;
01083     opt.direction       = option.direction;
01084     opt.fontMetrics     = option.fontMetrics;
01085     opt.palette         = option.palette;
01086     opt.rect            = rect;
01087     opt.state           = option.state | QStyle::State_KeyboardFocusChange | QStyle::State_Item;
01088     opt.backgroundColor = option.palette.color(option.state & QStyle::State_Selected ?
01089                                                QPalette::Highlight : QPalette::Base);
01090 
01091     // Apparently some widget styles expect this hint to not be set
01092     painter->setRenderHint(QPainter::Antialiasing, false);
01093 
01094     QStyle *style = option.widget ? option.widget->style() : QApplication::style();
01095     style->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, painter, option.widget);
01096 
01097     painter->setRenderHint(QPainter::Antialiasing);
01098 }
01099 
01100 
01101 void KFileItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
01102                               const QModelIndex &index) const
01103 {
01104     if (!index.isValid())
01105         return;
01106 
01107     QStyleOptionViewItemV4 opt(option);
01108     d->initStyleOption(&opt, index);
01109 
01110     // Unset the mouse over bit if we're not drawing the first column
01111     if (index.column() > 0)
01112         opt.state &= ~QStyle::State_MouseOver;
01113 
01114     const QAbstractItemView *view = qobject_cast<const QAbstractItemView*>(opt.widget);
01115 
01116 
01117     // Check if the item is being animated
01118     // ========================================================================
01119     KIO::AnimationState *state = d->animationState(opt, index, view);
01120     KIO::CachedRendering *cache = 0;
01121     qreal progress = ((opt.state & QStyle::State_MouseOver) &&
01122                 index.column() == KDirModel::Name) ? 1.0 : 0.0;
01123 
01124     if (state)
01125     {
01126         cache    = state->cachedRendering();
01127         progress = state->hoverProgress();
01128 
01129         // Clear the mouse over bit temporarily
01130         opt.state &= ~QStyle::State_MouseOver;
01131 
01132         // If we have a cached rendering, draw the item from the cache
01133         if (cache)
01134         {
01135             if (cache->checkValidity(opt.state) && cache->regular.size() == opt.rect.size())
01136             {
01137                 const QPixmap pixmap = d->transition(cache->regular, cache->hover, progress);
01138                 painter->drawPixmap(option.rect.topLeft(), pixmap);
01139                 return;
01140             }
01141 
01142             // If it wasn't valid, delete it
01143             state->setCachedRendering(0);
01144             delete cache;
01145             cache = 0;
01146         }
01147     }
01148 
01149     d->setActiveMargins(d->verticalLayout(opt) ? Qt::Vertical : Qt::Horizontal);
01150 
01151 
01152     // Compute the metrics, and lay out the text items
01153     // ========================================================================
01154     const QPoint iconPos   = d->iconPosition(opt);
01155     QIcon::Mode iconMode   = option.state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled;
01156     QIcon::State iconState = option.state & QStyle::State_Open ? QIcon::On : QIcon::Off;
01157     QPixmap icon           = opt.icon.pixmap(opt.decorationSize, iconMode, iconState);
01158     const QPen pen         = QPen(d->foregroundBrush(opt, index), 0);
01159 
01161     //     showDecorationSelected is false.
01162 
01163     QTextLayout labelLayout, infoLayout;
01164     QRect textBoundingRect;
01165 
01166     d->layoutTextItems(opt, index, &labelLayout, &infoLayout, &textBoundingRect);
01167 
01168     QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
01169 
01170     int focusHMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin);
01171     int focusVMargin = style->pixelMetric(QStyle::PM_FocusFrameVMargin);
01172     QRect focusRect = textBoundingRect.adjusted(-focusHMargin, -focusVMargin,
01173                                                 +focusHMargin, +focusVMargin);
01174 
01175     // Create a new cached rendering of a hovered and an unhovered item.
01176     // We don't create a new cache for a fully hovered item, since we don't
01177     // know yet if a hover out animation will be run.
01178     // ========================================================================
01179     if (state && progress < 1)
01180     {
01181         cache = new KIO::CachedRendering(opt.state, option.rect.size());
01182 
01183         QPainter p;
01184         p.begin(&cache->regular);
01185         p.translate(-option.rect.topLeft());
01186         p.setRenderHint(QPainter::Antialiasing);
01187         p.setPen(pen);
01188         style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, &p, opt.widget);
01189         p.drawPixmap(iconPos, icon);
01190         d->drawTextItems(&p, labelLayout, infoLayout, textBoundingRect);
01191         d->drawFocusRect(&p, opt, focusRect);
01192         p.end();
01193 
01194         opt.state |= QStyle::State_MouseOver;
01195         icon = d->applyHoverEffect(icon);
01196 
01197         p.begin(&cache->hover);
01198         p.translate(-option.rect.topLeft());
01199         p.setRenderHint(QPainter::Antialiasing);
01200         p.setPen(pen);
01201         style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, &p, opt.widget);
01202         p.drawPixmap(iconPos, icon);
01203         d->drawTextItems(&p, labelLayout, infoLayout, textBoundingRect);
01204         d->drawFocusRect(&p, opt, focusRect);
01205         p.end();
01206 
01207         state->setCachedRendering(cache);
01208 
01209         const QPixmap pixmap = d->transition(cache->regular, cache->hover, progress);
01210         painter->drawPixmap(option.rect.topLeft(), pixmap);
01211         return;
01212     }
01213 
01214 
01215     // Render the item directly if we're not using a cached rendering
01216     // ========================================================================
01217     painter->save();
01218     painter->setRenderHint(QPainter::Antialiasing);
01219     painter->setPen(pen);
01220 
01221     if (progress > 0 && !(opt.state & QStyle::State_MouseOver))
01222     {
01223         opt.state |= QStyle::State_MouseOver;
01224         icon = d->applyHoverEffect(icon);
01225     }
01226 
01227     style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget);
01228     painter->drawPixmap(iconPos, icon);
01229     d->drawTextItems(painter, labelLayout, infoLayout, textBoundingRect);
01230     d->drawFocusRect(painter, opt, focusRect);
01231 
01232     painter->restore();
01233 }
01234 
01235 
01236 QWidget *KFileItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option,
01237                                          const QModelIndex &index) const
01238 {
01239     QStyleOptionViewItemV4 opt(option);
01240     d->initStyleOption(&opt, index);
01241 
01242     KTextEdit *edit = new KTextEdit(parent);
01243     edit->setAcceptRichText(false);
01244     edit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
01245     edit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
01246     edit->setAlignment(opt.displayAlignment);
01247     return edit;
01248 }
01249 
01250 
01251 bool KFileItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
01252                                     const QModelIndex &index)
01253 {
01254     Q_UNUSED(event)
01255     Q_UNUSED(model)
01256     Q_UNUSED(option)
01257     Q_UNUSED(index)
01258 
01259     return false;
01260 }
01261 
01262 
01263 void KFileItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
01264 {
01265     KTextEdit *textedit = qobject_cast<KTextEdit*>(editor);
01266     Q_ASSERT(textedit != 0);
01267 
01268     const QVariant value = index.data(Qt::EditRole);
01269     const QString text = value.toString();
01270     textedit->insertPlainText(text);
01271     textedit->selectAll();
01272 
01273     const QString extension = KMimeType::extractKnownExtension(text);
01274     if (!extension.isEmpty()) {
01275         // The filename contains an extension. Assure that only the filename
01276         // gets selected.
01277         const int selectionLength = text.length() - extension.length() - 1;
01278         QTextCursor cursor = textedit->textCursor();
01279         cursor.movePosition(QTextCursor::StartOfBlock);
01280         cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, selectionLength);
01281         textedit->setTextCursor(cursor);
01282     }
01283 }
01284 
01285 
01286 void KFileItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
01287 {
01288     KTextEdit *textedit = qobject_cast<KTextEdit*>(editor);
01289     Q_ASSERT(textedit != 0);
01290 
01291     model->setData(index, textedit->toPlainText(), Qt::EditRole);
01292 }
01293 
01294 
01295 void KFileItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
01296                                              const QModelIndex &index) const
01297 {
01298     QStyleOptionViewItemV4 opt(option);
01299     d->initStyleOption(&opt, index);
01300 
01301     QRect r = d->labelRectangle(opt);
01302 
01303     // Use the full available width for the editor when maximumSize is set
01304     if (d->verticalLayout(option) && !d->maximumSize.isEmpty()) {
01305         int diff = qMax(r.width(), d->maximumSize.width()) - r.width();
01306         if (diff > 1)
01307             r.adjust(-(diff / 2), 0, diff / 2, 0);
01308     }
01309 
01310     KTextEdit *textedit = qobject_cast<KTextEdit*>(editor);
01311     Q_ASSERT(textedit != 0);
01312     const int frame = textedit->frameWidth();
01313     r.adjust(-frame, -frame, frame, frame);
01314 
01315     editor->setGeometry(r);
01316 }
01317 
01318 
01319 bool KFileItemDelegate::helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option,
01320                                   const QModelIndex &index)
01321 {
01322     Q_UNUSED(event)
01323     Q_UNUSED(view)
01324     Q_UNUSED(option)
01325     Q_UNUSED(index)
01326 
01327     return false;
01328 }
01329 
01330 
01331 bool KFileItemDelegate::eventFilter(QObject *object, QEvent *event)
01332 {
01333     KTextEdit *editor = qobject_cast<KTextEdit*>(object);
01334     if (!editor)
01335         return false;
01336 
01337     switch (event->type())
01338     {
01339     case QEvent::KeyPress:
01340     {
01341         QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
01342         switch (keyEvent->key())
01343         {
01344         case Qt::Key_Tab:
01345         case Qt::Key_Backtab:
01346             emit commitData(editor);
01347             emit closeEditor(editor, NoHint);
01348             return true;
01349 
01350         case Qt::Key_Enter:
01351         case Qt::Key_Return:
01352             if (editor->toPlainText().isEmpty())
01353                 return true; // So a newline doesn't get inserted
01354 
01355             emit commitData(editor);
01356             emit closeEditor(editor, SubmitModelCache);
01357             return true;
01358 
01359         case Qt::Key_Escape:
01360             emit closeEditor(editor, RevertModelCache);
01361             return true;
01362 
01363         default:
01364             return false;
01365         } // switch (keyEvent->key())
01366     } // case QEvent::KeyPress
01367 
01368     case QEvent::FocusOut:
01369     {
01370         emit commitData(editor);
01371         emit closeEditor(editor, NoHint);
01372         return true;
01373     }
01374 
01375     default:
01376         return false;
01377     } // switch (event->type())
01378 }
01379 
01380 
01381 #include "kfileitemdelegate.moc"
01382 
01383 
01384 // kate: space-indent on; indent-width 4; replace-tabs on;

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal