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