src/gui/itemviews/qitemdelegate.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qitemdelegate.h"
       
    43 
       
    44 #ifndef QT_NO_ITEMVIEWS
       
    45 #include <qabstractitemmodel.h>
       
    46 #include <qapplication.h>
       
    47 #include <qbrush.h>
       
    48 #include <qlineedit.h>
       
    49 #include <qtextedit.h>
       
    50 #include <qplaintextedit.h>
       
    51 #include <qpainter.h>
       
    52 #include <qpalette.h>
       
    53 #include <qpoint.h>
       
    54 #include <qrect.h>
       
    55 #include <qsize.h>
       
    56 #include <qstyle.h>
       
    57 #include <qdatetime.h>
       
    58 #include <qstyleoption.h>
       
    59 #include <qevent.h>
       
    60 #include <qpixmap.h>
       
    61 #include <qbitmap.h>
       
    62 #include <qpixmapcache.h>
       
    63 #include <qitemeditorfactory.h>
       
    64 #include <qmetaobject.h>
       
    65 #include <qtextlayout.h>
       
    66 #include <private/qobject_p.h>
       
    67 #include <private/qdnd_p.h>
       
    68 #include <private/qtextengine_p.h>
       
    69 #include <qdebug.h>
       
    70 #include <qlocale.h>
       
    71 #include <qdialog.h>
       
    72 
       
    73 #include <limits.h>
       
    74 
       
    75 #ifndef DBL_DIG
       
    76 #  define DBL_DIG 10
       
    77 #endif
       
    78 
       
    79 QT_BEGIN_NAMESPACE
       
    80 
       
    81 class QItemDelegatePrivate : public QObjectPrivate
       
    82 {
       
    83     Q_DECLARE_PUBLIC(QItemDelegate)
       
    84 
       
    85 public:
       
    86     QItemDelegatePrivate() : f(0), clipPainting(true) {}
       
    87 
       
    88     inline const QItemEditorFactory *editorFactory() const
       
    89         { return f ? f : QItemEditorFactory::defaultFactory(); }
       
    90 
       
    91     inline QIcon::Mode iconMode(QStyle::State state) const
       
    92         {
       
    93             if (!(state & QStyle::State_Enabled)) return QIcon::Disabled;
       
    94             if (state & QStyle::State_Selected) return QIcon::Selected;
       
    95             return QIcon::Normal;
       
    96         }
       
    97 
       
    98     inline QIcon::State iconState(QStyle::State state) const
       
    99         { return state & QStyle::State_Open ? QIcon::On : QIcon::Off; }
       
   100 
       
   101     inline static QString replaceNewLine(QString text)
       
   102         {
       
   103             const QChar nl = QLatin1Char('\n');
       
   104             for (int i = 0; i < text.count(); ++i)
       
   105                 if (text.at(i) == nl)
       
   106                     text[i] = QChar::LineSeparator;
       
   107             return text;
       
   108         }
       
   109 
       
   110     static QString valueToText(const QVariant &value, const QStyleOptionViewItemV4 &option);
       
   111 
       
   112     void _q_commitDataAndCloseEditor(QWidget *editor);
       
   113 
       
   114     QItemEditorFactory *f;
       
   115     bool clipPainting;
       
   116 
       
   117     QRect textLayoutBounds(const QStyleOptionViewItemV2 &options) const;
       
   118     QSizeF doTextLayout(int lineWidth) const;
       
   119     mutable QTextLayout textLayout;
       
   120     mutable QTextOption textOption;
       
   121 
       
   122     const QWidget *widget(const QStyleOptionViewItem &option) const
       
   123     {
       
   124         if (const QStyleOptionViewItemV3 *v3 = qstyleoption_cast<const QStyleOptionViewItemV3 *>(&option))
       
   125             return v3->widget;
       
   126 
       
   127         return 0;
       
   128     }
       
   129 
       
   130     // ### temporary hack until we have QStandardItemDelegate
       
   131     mutable struct Icon {
       
   132         QIcon icon;
       
   133         QIcon::Mode mode;
       
   134         QIcon::State state;
       
   135     } tmp;
       
   136 };
       
   137 
       
   138 void QItemDelegatePrivate::_q_commitDataAndCloseEditor(QWidget *editor)
       
   139 {
       
   140     Q_Q(QItemDelegate);
       
   141     emit q->commitData(editor);
       
   142     emit q->closeEditor(editor, QAbstractItemDelegate::SubmitModelCache);
       
   143 }
       
   144 
       
   145 QRect QItemDelegatePrivate::textLayoutBounds(const QStyleOptionViewItemV2 &option) const
       
   146 {
       
   147     QRect rect = option.rect;
       
   148     const bool wrapText = option.features & QStyleOptionViewItemV2::WrapText;
       
   149     switch (option.decorationPosition) {
       
   150     case QStyleOptionViewItem::Left:
       
   151     case QStyleOptionViewItem::Right:
       
   152         rect.setWidth(wrapText && rect.isValid() ? rect.width() : (QFIXED_MAX));
       
   153         break;
       
   154     case QStyleOptionViewItem::Top:
       
   155     case QStyleOptionViewItem::Bottom:
       
   156         rect.setWidth(wrapText ? option.decorationSize.width() : (QFIXED_MAX));
       
   157         break;
       
   158     }
       
   159 
       
   160     return rect;
       
   161 }
       
   162 
       
   163 QSizeF QItemDelegatePrivate::doTextLayout(int lineWidth) const
       
   164 {
       
   165     qreal height = 0;
       
   166     qreal widthUsed = 0;
       
   167     textLayout.beginLayout();
       
   168     while (true) {
       
   169         QTextLine line = textLayout.createLine();
       
   170         if (!line.isValid())
       
   171             break;
       
   172         line.setLineWidth(lineWidth);
       
   173         line.setPosition(QPointF(0, height));
       
   174         height += line.height();
       
   175         widthUsed = qMax(widthUsed, line.naturalTextWidth());
       
   176     }
       
   177     textLayout.endLayout();
       
   178     return QSizeF(widthUsed, height);
       
   179 }
       
   180 
       
   181 /*!
       
   182     \class QItemDelegate
       
   183 
       
   184     \brief The QItemDelegate class provides display and editing facilities for
       
   185     data items from a model.
       
   186 
       
   187     \ingroup model-view
       
   188 
       
   189 
       
   190     QItemDelegate can be used to provide custom display features and editor
       
   191     widgets for item views based on QAbstractItemView subclasses. Using a
       
   192     delegate for this purpose allows the display and editing mechanisms to be
       
   193     customized and developed independently from the model and view.
       
   194 
       
   195     The QItemDelegate class is one of the \l{Model/View Classes} and
       
   196     is part of Qt's \l{Model/View Programming}{model/view framework}.
       
   197     Note that QStyledItemDelegate has taken over the job of drawing
       
   198     Qt's item views. We recommend the use of QStyledItemDelegate when
       
   199     creating new delegates.
       
   200 
       
   201     When displaying items from a custom model in a standard view, it is
       
   202     often sufficient to simply ensure that the model returns appropriate
       
   203     data for each of the \l{Qt::ItemDataRole}{roles} that determine the
       
   204     appearance of items in views. The default delegate used by Qt's
       
   205     standard views uses this role information to display items in most
       
   206     of the common forms expected by users. However, it is sometimes
       
   207     necessary to have even more control over the appearance of items than
       
   208     the default delegate can provide.
       
   209 
       
   210     This class provides default implementations of the functions for
       
   211     painting item data in a view and editing data from item models.
       
   212     Default implementations of the paint() and sizeHint() virtual
       
   213     functions, defined in QAbstractItemDelegate, are provided to
       
   214     ensure that the delegate implements the correct basic behavior
       
   215     expected by views. You can reimplement these functions in
       
   216     subclasses to customize the appearance of items.
       
   217 
       
   218     When editing data in an item view, QItemDelegate provides an
       
   219     editor widget, which is a widget that is placed on top of the view
       
   220     while editing takes place. Editors are created with a
       
   221     QItemEditorFactory; a default static instance provided by
       
   222     QItemEditorFactory is installed on all item delegates. You can set
       
   223     a custom factory using setItemEditorFactory() or set a new default
       
   224     factory with QItemEditorFactory::setDefaultFactory(). It is the
       
   225     data stored in the item model with the Qt::EditRole that is edited.
       
   226 
       
   227     Only the standard editing functions for widget-based delegates are
       
   228     reimplemented here:
       
   229 
       
   230     \list
       
   231         \o createEditor() returns the widget used to change data from the model
       
   232            and can be reimplemented to customize editing behavior.
       
   233         \o setEditorData() provides the widget with data to manipulate.
       
   234         \o updateEditorGeometry() ensures that the editor is displayed correctly
       
   235            with respect to the item view.
       
   236         \o setModelData() returns updated data to the model.
       
   237     \endlist
       
   238 
       
   239     The closeEditor() signal indicates that the user has completed editing the data,
       
   240     and that the editor widget can be destroyed.
       
   241 
       
   242     \section1 Standard Roles and Data Types
       
   243 
       
   244     The default delegate used by the standard views supplied with Qt
       
   245     associates each standard role (defined by Qt::ItemDataRole) with certain
       
   246     data types. Models that return data in these types can influence the
       
   247     appearance of the delegate as described in the following table.
       
   248 
       
   249     \table
       
   250     \header \o Role \o Accepted Types
       
   251     \omit
       
   252     \row    \o \l Qt::AccessibleDescriptionRole \o QString
       
   253     \row    \o \l Qt::AccessibleTextRole \o QString
       
   254     \endomit
       
   255     \row    \o \l Qt::BackgroundRole \o QBrush
       
   256     \row    \o \l Qt::BackgroundColorRole \o QColor (obsolete; use Qt::BackgroundRole instead)
       
   257     \row    \o \l Qt::CheckStateRole \o Qt::CheckState
       
   258     \row    \o \l Qt::DecorationRole \o QIcon and QColor
       
   259     \row    \o \l Qt::DisplayRole \o QString and types with a string representation
       
   260     \row    \o \l Qt::EditRole \o See QItemEditorFactory for details
       
   261     \row    \o \l Qt::FontRole \o QFont
       
   262     \row    \o \l Qt::SizeHintRole \o QSize
       
   263     \omit
       
   264     \row    \o \l Qt::StatusTipRole \o
       
   265     \endomit
       
   266     \row    \o \l Qt::TextAlignmentRole \o Qt::Alignment
       
   267     \row    \o \l Qt::ForegroundRole \o QBrush
       
   268     \row    \o \l Qt::TextColorRole \o QColor (obsolete; use Qt::ForegroundRole instead)
       
   269     \omit
       
   270     \row    \o \l Qt::ToolTipRole
       
   271     \row    \o \l Qt::WhatsThisRole
       
   272     \endomit
       
   273     \endtable
       
   274 
       
   275     If the default delegate does not allow the level of customization that
       
   276     you need, either for display purposes or for editing data, it is possible to
       
   277     subclass QItemDelegate to implement the desired behavior.
       
   278 
       
   279     \section1 Subclassing
       
   280 
       
   281     When subclassing QItemDelegate to create a delegate that displays items
       
   282     using a custom renderer, it is important to ensure that the delegate can
       
   283     render items suitably for all the required states; e.g. selected,
       
   284     disabled, checked. The documentation for the paint() function contains
       
   285     some hints to show how this can be achieved.
       
   286 
       
   287     You can provide custom editors by using a QItemEditorFactory. The
       
   288     \l{Color Editor Factory Example} shows how a custom editor can be
       
   289     made available to delegates with the default item editor
       
   290     factory. This way, there is no need to subclass QItemDelegate.  An
       
   291     alternative is to reimplement createEditor(), setEditorData(),
       
   292     setModelData(), and updateEditorGeometry(). This process is
       
   293     described in the \l{Spin Box Delegate Example}.
       
   294 
       
   295     \section1 QStyledItemDelegate vs. QItemDelegate
       
   296 
       
   297     Since Qt 4.4, there are two delegate classes: QItemDelegate and
       
   298     QStyledItemDelegate. However, the default delegate is QStyledItemDelegate.
       
   299     These two classes are independent alternatives to painting and providing
       
   300     editors for items in views. The difference between them is that
       
   301     QStyledItemDelegate uses the current style to paint its items. We therefore
       
   302     recommend using QStyledItemDelegate as the base class when implementing
       
   303     custom delegates or when working with Qt style sheets. The code required
       
   304     for either class should be equal unless the custom delegate needs to use
       
   305     the style for drawing.
       
   306 
       
   307     \sa {Delegate Classes}, QStyledItemDelegate, QAbstractItemDelegate,
       
   308         {Spin Box Delegate Example}, {Settings Editor Example},
       
   309         {Icons Example}
       
   310 */
       
   311 
       
   312 /*!
       
   313     Constructs an item delegate with the given \a parent.
       
   314 */
       
   315 
       
   316 QItemDelegate::QItemDelegate(QObject *parent)
       
   317     : QAbstractItemDelegate(*new QItemDelegatePrivate(), parent)
       
   318 {
       
   319 
       
   320 }
       
   321 
       
   322 /*!
       
   323     Destroys the item delegate.
       
   324 */
       
   325 
       
   326 QItemDelegate::~QItemDelegate()
       
   327 {
       
   328 }
       
   329 
       
   330 /*!
       
   331   \property QItemDelegate::clipping
       
   332   \brief if the delegate should clip the paint events
       
   333   \since 4.2
       
   334 
       
   335   This property will set the paint clip to the size of the item.
       
   336   The default value is on. It is useful for cases such
       
   337   as when images are larger than the size of the item.
       
   338 */
       
   339 
       
   340 bool QItemDelegate::hasClipping() const
       
   341 {
       
   342     Q_D(const QItemDelegate);
       
   343     return d->clipPainting;
       
   344 }
       
   345 
       
   346 void QItemDelegate::setClipping(bool clip)
       
   347 {
       
   348     Q_D(QItemDelegate);
       
   349     d->clipPainting = clip;
       
   350 }
       
   351 
       
   352 QString QItemDelegatePrivate::valueToText(const QVariant &value, const QStyleOptionViewItemV4 &option)
       
   353 {
       
   354     QString text;
       
   355     switch (value.userType()) {
       
   356         case QMetaType::Float:
       
   357             text = option.locale.toString(value.toFloat(), 'g');
       
   358             break;
       
   359         case QVariant::Double:
       
   360             text = option.locale.toString(value.toDouble(), 'g', DBL_DIG);
       
   361             break;
       
   362         case QVariant::Int:
       
   363         case QVariant::LongLong:
       
   364             text = option.locale.toString(value.toLongLong());
       
   365             break;
       
   366         case QVariant::UInt:
       
   367         case QVariant::ULongLong:
       
   368             text = option.locale.toString(value.toULongLong());
       
   369             break;
       
   370         case QVariant::Date:
       
   371             text = option.locale.toString(value.toDate(), QLocale::ShortFormat);
       
   372             break;
       
   373         case QVariant::Time:
       
   374             text = option.locale.toString(value.toTime(), QLocale::ShortFormat);
       
   375             break;
       
   376         case QVariant::DateTime:
       
   377             text = option.locale.toString(value.toDateTime().date(), QLocale::ShortFormat);
       
   378             text += QLatin1Char(' ');
       
   379             text += option.locale.toString(value.toDateTime().time(), QLocale::ShortFormat);
       
   380             break;
       
   381         default:
       
   382             text = replaceNewLine(value.toString());
       
   383             break;
       
   384     }
       
   385     return text;
       
   386 }
       
   387 
       
   388 /*!
       
   389     Renders the delegate using the given \a painter and style \a option for
       
   390     the item specified by \a index.
       
   391 
       
   392     When reimplementing this function in a subclass, you should update the area
       
   393     held by the option's \l{QStyleOption::rect}{rect} variable, using the
       
   394     option's \l{QStyleOption::state}{state} variable to determine the state of
       
   395     the item to be displayed, and adjust the way it is painted accordingly.
       
   396 
       
   397     For example, a selected item may need to be displayed differently to
       
   398     unselected items, as shown in the following code:
       
   399 
       
   400     \snippet examples/itemviews/pixelator/pixeldelegate.cpp 2
       
   401     \dots
       
   402 
       
   403     After painting, you should ensure that the painter is returned to its
       
   404     the state it was supplied in when this function was called. For example,
       
   405     it may be useful to call QPainter::save() before painting and
       
   406     QPainter::restore() afterwards.
       
   407 
       
   408     \sa QStyle::State
       
   409 */
       
   410 void QItemDelegate::paint(QPainter *painter,
       
   411                           const QStyleOptionViewItem &option,
       
   412                           const QModelIndex &index) const
       
   413 {
       
   414     Q_D(const QItemDelegate);
       
   415     Q_ASSERT(index.isValid());
       
   416 
       
   417     QStyleOptionViewItemV4 opt = setOptions(index, option);
       
   418 
       
   419     const QStyleOptionViewItemV2 *v2 = qstyleoption_cast<const QStyleOptionViewItemV2 *>(&option);
       
   420     opt.features = v2 ? v2->features
       
   421                     : QStyleOptionViewItemV2::ViewItemFeatures(QStyleOptionViewItemV2::None);
       
   422     const QStyleOptionViewItemV3 *v3 = qstyleoption_cast<const QStyleOptionViewItemV3 *>(&option);
       
   423     opt.locale = v3 ? v3->locale : QLocale();
       
   424     opt.widget = v3 ? v3->widget : 0;
       
   425 
       
   426     // prepare
       
   427     painter->save();
       
   428     if (d->clipPainting)
       
   429         painter->setClipRect(opt.rect);
       
   430 
       
   431     // get the data and the rectangles
       
   432 
       
   433     QVariant value;
       
   434 
       
   435     QPixmap pixmap;
       
   436     QRect decorationRect;
       
   437     value = index.data(Qt::DecorationRole);
       
   438     if (value.isValid()) {
       
   439         // ### we need the pixmap to call the virtual function
       
   440         pixmap = decoration(opt, value);
       
   441         if (value.type() == QVariant::Icon) {
       
   442             d->tmp.icon = qvariant_cast<QIcon>(value);
       
   443             d->tmp.mode = d->iconMode(option.state);
       
   444             d->tmp.state = d->iconState(option.state);
       
   445             const QSize size = d->tmp.icon.actualSize(option.decorationSize,
       
   446                                                       d->tmp.mode, d->tmp.state);
       
   447             decorationRect = QRect(QPoint(0, 0), size);
       
   448         } else {
       
   449             d->tmp.icon = QIcon();
       
   450             decorationRect = QRect(QPoint(0, 0), pixmap.size());
       
   451         }
       
   452     } else {
       
   453         d->tmp.icon = QIcon();
       
   454         decorationRect = QRect();
       
   455     }
       
   456 
       
   457     QString text;
       
   458     QRect displayRect;
       
   459     value = index.data(Qt::DisplayRole);
       
   460     if (value.isValid() && !value.isNull()) {
       
   461         text = QItemDelegatePrivate::valueToText(value, opt);
       
   462         displayRect = textRectangle(painter, d->textLayoutBounds(opt), opt.font, text);
       
   463     }
       
   464 
       
   465     QRect checkRect;
       
   466     Qt::CheckState checkState = Qt::Unchecked;
       
   467     value = index.data(Qt::CheckStateRole);
       
   468     if (value.isValid()) {
       
   469         checkState = static_cast<Qt::CheckState>(value.toInt());
       
   470         checkRect = check(opt, opt.rect, value);
       
   471     }
       
   472 
       
   473     // do the layout
       
   474 
       
   475     doLayout(opt, &checkRect, &decorationRect, &displayRect, false);
       
   476 
       
   477     // draw the item
       
   478 
       
   479     drawBackground(painter, opt, index);
       
   480     drawCheck(painter, opt, checkRect, checkState);
       
   481     drawDecoration(painter, opt, decorationRect, pixmap);
       
   482     drawDisplay(painter, opt, displayRect, text);
       
   483     drawFocus(painter, opt, displayRect);
       
   484 
       
   485     // done
       
   486     painter->restore();
       
   487 }
       
   488 
       
   489 /*!
       
   490     Returns the size needed by the delegate to display the item
       
   491     specified by \a index, taking into account the style information
       
   492     provided by \a option.
       
   493 
       
   494     When reimplementing this function, note that in case of text
       
   495     items, QItemDelegate adds a margin (i.e. 2 *
       
   496     QStyle::PM_FocusFrameHMargin) to the length of the text.
       
   497 */
       
   498 
       
   499 QSize QItemDelegate::sizeHint(const QStyleOptionViewItem &option,
       
   500                               const QModelIndex &index) const
       
   501 {
       
   502     QVariant value = index.data(Qt::SizeHintRole);
       
   503     if (value.isValid())
       
   504         return qvariant_cast<QSize>(value);
       
   505     QRect decorationRect = rect(option, index, Qt::DecorationRole);
       
   506     QRect displayRect = rect(option, index, Qt::DisplayRole);
       
   507     QRect checkRect = rect(option, index, Qt::CheckStateRole);
       
   508 
       
   509     doLayout(option, &checkRect, &decorationRect, &displayRect, true);
       
   510 
       
   511     return (decorationRect|displayRect|checkRect).size();
       
   512 }
       
   513 
       
   514 /*!
       
   515     Returns the widget used to edit the item specified by \a index
       
   516     for editing. The \a parent widget and style \a option are used to
       
   517     control how the editor widget appears.
       
   518 
       
   519     \sa QAbstractItemDelegate::createEditor()
       
   520 */
       
   521 
       
   522 QWidget *QItemDelegate::createEditor(QWidget *parent,
       
   523                                      const QStyleOptionViewItem &,
       
   524                                      const QModelIndex &index) const
       
   525 {
       
   526     Q_D(const QItemDelegate);
       
   527     if (!index.isValid())
       
   528         return 0;
       
   529     QVariant::Type t = static_cast<QVariant::Type>(index.data(Qt::EditRole).userType());
       
   530     const QItemEditorFactory *factory = d->f;
       
   531     if (factory == 0)
       
   532         factory = QItemEditorFactory::defaultFactory();
       
   533     return factory->createEditor(t, parent);
       
   534 }
       
   535 
       
   536 /*!
       
   537     Sets the data to be displayed and edited by the \a editor from the
       
   538     data model item specified by the model \a index.
       
   539 
       
   540     The default implementation stores the data in the \a editor
       
   541     widget's \l {Qt's Property System} {user property}.
       
   542 
       
   543     \sa QMetaProperty::isUser()
       
   544 */
       
   545 
       
   546 void QItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
       
   547 {
       
   548 #ifdef QT_NO_PROPERTIES
       
   549     Q_UNUSED(editor);
       
   550     Q_UNUSED(index);
       
   551 #else
       
   552     Q_D(const QItemDelegate);
       
   553     QVariant v = index.data(Qt::EditRole);
       
   554     QByteArray n = editor->metaObject()->userProperty().name();
       
   555 
       
   556     // ### Qt 5: remove
       
   557     // A work-around for missing "USER true" in qdatetimeedit.h for
       
   558     // QTimeEdit's time property and QDateEdit's date property.
       
   559     // It only triggers if the default user property "dateTime" is
       
   560     // reported for QTimeEdit and QDateEdit.
       
   561     if (n == "dateTime") {
       
   562         if (editor->inherits("QTimeEdit"))
       
   563             n = "time";
       
   564         else if (editor->inherits("QDateEdit"))
       
   565             n = "date";
       
   566     }
       
   567 
       
   568     // ### Qt 5: give QComboBox a USER property
       
   569     if (n.isEmpty() && editor->inherits("QComboBox"))
       
   570         n = d->editorFactory()->valuePropertyName(static_cast<QVariant::Type>(v.userType()));
       
   571     if (!n.isEmpty()) {
       
   572         if (!v.isValid())
       
   573             v = QVariant(editor->property(n).userType(), (const void *)0);
       
   574         editor->setProperty(n, v);
       
   575     }
       
   576 #endif
       
   577 }
       
   578 
       
   579 /*!
       
   580     Gets data from the \a editor widget and stores it in the specified
       
   581     \a model at the item \a index.
       
   582 
       
   583     The default implementation gets the value to be stored in the data
       
   584     model from the \a editor widget's \l {Qt's Property System} {user
       
   585     property}.
       
   586 
       
   587     \sa QMetaProperty::isUser()
       
   588 */
       
   589 
       
   590 void QItemDelegate::setModelData(QWidget *editor,
       
   591                                  QAbstractItemModel *model,
       
   592                                  const QModelIndex &index) const
       
   593 {
       
   594 #ifdef QT_NO_PROPERTIES
       
   595     Q_UNUSED(model);
       
   596     Q_UNUSED(editor);
       
   597     Q_UNUSED(index);
       
   598 #else
       
   599     Q_D(const QItemDelegate);
       
   600     Q_ASSERT(model);
       
   601     Q_ASSERT(editor);
       
   602     QByteArray n = editor->metaObject()->userProperty().name();
       
   603     if (n.isEmpty())
       
   604         n = d->editorFactory()->valuePropertyName(
       
   605             static_cast<QVariant::Type>(model->data(index, Qt::EditRole).userType()));
       
   606     if (!n.isEmpty())
       
   607         model->setData(index, editor->property(n), Qt::EditRole);
       
   608 #endif
       
   609 }
       
   610 
       
   611 /*!
       
   612     Updates the \a editor for the item specified by \a index
       
   613     according to the style \a option given.
       
   614 */
       
   615 
       
   616 void QItemDelegate::updateEditorGeometry(QWidget *editor,
       
   617                                          const QStyleOptionViewItem &option,
       
   618                                          const QModelIndex &index) const
       
   619 {
       
   620     if (!editor)
       
   621         return;
       
   622     Q_ASSERT(index.isValid());
       
   623     QPixmap pixmap = decoration(option, index.data(Qt::DecorationRole));
       
   624     QString text = QItemDelegatePrivate::replaceNewLine(index.data(Qt::DisplayRole).toString());
       
   625     QRect pixmapRect = QRect(QPoint(0, 0), option.decorationSize).intersected(pixmap.rect());
       
   626     QRect textRect = textRectangle(0, option.rect, option.font, text);
       
   627     QRect checkRect = check(option, textRect, index.data(Qt::CheckStateRole));
       
   628     QStyleOptionViewItem opt = option;
       
   629     opt.showDecorationSelected = true; // let the editor take up all available space
       
   630     doLayout(opt, &checkRect, &pixmapRect, &textRect, false);
       
   631     editor->setGeometry(textRect);
       
   632 }
       
   633 
       
   634 /*!
       
   635   Returns the editor factory used by the item delegate.
       
   636   If no editor factory is set, the function will return null.
       
   637 
       
   638   \sa setItemEditorFactory()
       
   639 */
       
   640 QItemEditorFactory *QItemDelegate::itemEditorFactory() const
       
   641 {
       
   642     Q_D(const QItemDelegate);
       
   643     return d->f;
       
   644 }
       
   645 
       
   646 /*!
       
   647   Sets the editor factory to be used by the item delegate to be the \a factory
       
   648   specified. If no editor factory is set, the item delegate will use the
       
   649   default editor factory.
       
   650 
       
   651   \sa itemEditorFactory()
       
   652 */
       
   653 void QItemDelegate::setItemEditorFactory(QItemEditorFactory *factory)
       
   654 {
       
   655     Q_D(QItemDelegate);
       
   656     d->f = factory;
       
   657 }
       
   658 
       
   659 /*!
       
   660    Renders the item view \a text within the rectangle specified by \a rect
       
   661    using the given \a painter and style \a option.
       
   662 */
       
   663 
       
   664 void QItemDelegate::drawDisplay(QPainter *painter, const QStyleOptionViewItem &option,
       
   665                                 const QRect &rect, const QString &text) const
       
   666 {
       
   667     Q_D(const QItemDelegate);
       
   668 
       
   669     QPen pen = painter->pen();
       
   670     QPalette::ColorGroup cg = option.state & QStyle::State_Enabled
       
   671                               ? QPalette::Normal : QPalette::Disabled;
       
   672     if (cg == QPalette::Normal && !(option.state & QStyle::State_Active))
       
   673         cg = QPalette::Inactive;
       
   674     if (option.state & QStyle::State_Selected) {
       
   675         painter->fillRect(rect, option.palette.brush(cg, QPalette::Highlight));
       
   676         painter->setPen(option.palette.color(cg, QPalette::HighlightedText));
       
   677     } else {
       
   678         painter->setPen(option.palette.color(cg, QPalette::Text));
       
   679     }
       
   680 
       
   681     if (text.isEmpty())
       
   682         return;
       
   683 
       
   684     if (option.state & QStyle::State_Editing) {
       
   685         painter->save();
       
   686         painter->setPen(option.palette.color(cg, QPalette::Text));
       
   687         painter->drawRect(rect.adjusted(0, 0, -1, -1));
       
   688         painter->restore();
       
   689     }
       
   690 
       
   691     const QStyleOptionViewItemV4 opt = option;
       
   692 
       
   693     const QWidget *widget = d->widget(option);
       
   694     QStyle *style = widget ? widget->style() : QApplication::style();
       
   695     const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, widget) + 1;
       
   696     QRect textRect = rect.adjusted(textMargin, 0, -textMargin, 0); // remove width padding
       
   697     const bool wrapText = opt.features & QStyleOptionViewItemV2::WrapText;
       
   698     d->textOption.setWrapMode(wrapText ? QTextOption::WordWrap : QTextOption::ManualWrap);
       
   699     d->textOption.setTextDirection(option.direction);
       
   700     d->textOption.setAlignment(QStyle::visualAlignment(option.direction, option.displayAlignment));
       
   701     d->textLayout.setTextOption(d->textOption);
       
   702     d->textLayout.setFont(option.font);
       
   703     d->textLayout.setText(QItemDelegatePrivate::replaceNewLine(text));
       
   704 
       
   705     QSizeF textLayoutSize = d->doTextLayout(textRect.width());
       
   706 
       
   707     if (textRect.width() < textLayoutSize.width()
       
   708         || textRect.height() < textLayoutSize.height()) {
       
   709         QString elided;
       
   710         int start = 0;
       
   711         int end = text.indexOf(QChar::LineSeparator, start);
       
   712         if (end == -1) {
       
   713             elided += option.fontMetrics.elidedText(text, option.textElideMode, textRect.width());
       
   714         } else {
       
   715             while (end != -1) {
       
   716                 elided += option.fontMetrics.elidedText(text.mid(start, end - start),
       
   717                                                         option.textElideMode, textRect.width());
       
   718                 elided += QChar::LineSeparator;
       
   719                 start = end + 1;
       
   720                 end = text.indexOf(QChar::LineSeparator, start);
       
   721             }
       
   722             //let's add the last line (after the last QChar::LineSeparator)
       
   723             elided += option.fontMetrics.elidedText(text.mid(start),
       
   724                                                     option.textElideMode, textRect.width());
       
   725         }
       
   726         d->textLayout.setText(elided);
       
   727         textLayoutSize = d->doTextLayout(textRect.width());
       
   728     }
       
   729 
       
   730     const QSize layoutSize(textRect.width(), int(textLayoutSize.height()));
       
   731     const QRect layoutRect = QStyle::alignedRect(option.direction, option.displayAlignment,
       
   732                                                   layoutSize, textRect);
       
   733     // if we still overflow even after eliding the text, enable clipping
       
   734     if (!hasClipping() && (textRect.width() < textLayoutSize.width()
       
   735                            || textRect.height() < textLayoutSize.height())) {
       
   736         painter->save();
       
   737         painter->setClipRect(layoutRect);
       
   738         d->textLayout.draw(painter, layoutRect.topLeft(), QVector<QTextLayout::FormatRange>(), layoutRect);
       
   739         painter->restore();
       
   740     } else {
       
   741         d->textLayout.draw(painter, layoutRect.topLeft(), QVector<QTextLayout::FormatRange>(), layoutRect);
       
   742     }
       
   743 }
       
   744 
       
   745 /*!
       
   746     Renders the decoration \a pixmap within the rectangle specified by
       
   747     \a rect using the given \a painter and style \a option.
       
   748 */
       
   749 void QItemDelegate::drawDecoration(QPainter *painter, const QStyleOptionViewItem &option,
       
   750                                    const QRect &rect, const QPixmap &pixmap) const
       
   751 {
       
   752     Q_D(const QItemDelegate);
       
   753     // if we have an icon, we ignore the pixmap
       
   754     if (!d->tmp.icon.isNull()) {
       
   755         d->tmp.icon.paint(painter, rect, option.decorationAlignment,
       
   756                           d->tmp.mode, d->tmp.state);
       
   757         return;
       
   758     }
       
   759 
       
   760     if (pixmap.isNull() || !rect.isValid())
       
   761         return;
       
   762     QPoint p = QStyle::alignedRect(option.direction, option.decorationAlignment,
       
   763                                    pixmap.size(), rect).topLeft();
       
   764     if (option.state & QStyle::State_Selected) {
       
   765         QPixmap *pm = selected(pixmap, option.palette, option.state & QStyle::State_Enabled);
       
   766         painter->drawPixmap(p, *pm);
       
   767     } else {
       
   768         painter->drawPixmap(p, pixmap);
       
   769     }
       
   770 }
       
   771 
       
   772 /*!
       
   773     Renders the region within the rectangle specified by \a rect, indicating
       
   774     that it has the focus, using the given \a painter and style \a option.
       
   775 */
       
   776 
       
   777 void QItemDelegate::drawFocus(QPainter *painter,
       
   778                               const QStyleOptionViewItem &option,
       
   779                               const QRect &rect) const
       
   780 {
       
   781     Q_D(const QItemDelegate);
       
   782     if ((option.state & QStyle::State_HasFocus) == 0 || !rect.isValid())
       
   783         return;
       
   784     QStyleOptionFocusRect o;
       
   785     o.QStyleOption::operator=(option);
       
   786     o.rect = rect;
       
   787     o.state |= QStyle::State_KeyboardFocusChange;
       
   788     o.state |= QStyle::State_Item;
       
   789     QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled)
       
   790                               ? QPalette::Normal : QPalette::Disabled;
       
   791     o.backgroundColor = option.palette.color(cg, (option.state & QStyle::State_Selected)
       
   792                                              ? QPalette::Highlight : QPalette::Window);
       
   793     const QWidget *widget = d->widget(option);
       
   794     QStyle *style = widget ? widget->style() : QApplication::style();
       
   795     style->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter, widget);
       
   796 }
       
   797 
       
   798 /*!
       
   799     Renders a check indicator within the rectangle specified by \a
       
   800     rect, using the given \a painter and style \a option, using the
       
   801     given \a state.
       
   802 */
       
   803 
       
   804 void QItemDelegate::drawCheck(QPainter *painter,
       
   805                               const QStyleOptionViewItem &option,
       
   806                               const QRect &rect, Qt::CheckState state) const
       
   807 {
       
   808     Q_D(const QItemDelegate);
       
   809     if (!rect.isValid())
       
   810         return;
       
   811 
       
   812     QStyleOptionViewItem opt(option);
       
   813     opt.rect = rect;
       
   814     opt.state = opt.state & ~QStyle::State_HasFocus;
       
   815 
       
   816     switch (state) {
       
   817     case Qt::Unchecked:
       
   818         opt.state |= QStyle::State_Off;
       
   819         break;
       
   820     case Qt::PartiallyChecked:
       
   821         opt.state |= QStyle::State_NoChange;
       
   822         break;
       
   823     case Qt::Checked:
       
   824         opt.state |= QStyle::State_On;
       
   825         break;
       
   826     }
       
   827 
       
   828     const QWidget *widget = d->widget(option);
       
   829     QStyle *style = widget ? widget->style() : QApplication::style();
       
   830     style->drawPrimitive(QStyle::PE_IndicatorViewItemCheck, &opt, painter, widget);
       
   831 }
       
   832 
       
   833 /*!
       
   834     \since 4.2
       
   835 
       
   836     Renders the item background for the given \a index,
       
   837     using the given \a painter and style \a option.
       
   838 */
       
   839 
       
   840 void QItemDelegate::drawBackground(QPainter *painter,
       
   841                                    const QStyleOptionViewItem &option,
       
   842                                    const QModelIndex &index) const
       
   843 {
       
   844     if (option.showDecorationSelected && (option.state & QStyle::State_Selected)) {
       
   845         QPalette::ColorGroup cg = option.state & QStyle::State_Enabled
       
   846                                   ? QPalette::Normal : QPalette::Disabled;
       
   847         if (cg == QPalette::Normal && !(option.state & QStyle::State_Active))
       
   848             cg = QPalette::Inactive;
       
   849 
       
   850         painter->fillRect(option.rect, option.palette.brush(cg, QPalette::Highlight));
       
   851     } else {
       
   852         QVariant value = index.data(Qt::BackgroundRole);
       
   853         if (qVariantCanConvert<QBrush>(value)) {
       
   854             QPointF oldBO = painter->brushOrigin();
       
   855             painter->setBrushOrigin(option.rect.topLeft());
       
   856             painter->fillRect(option.rect, qvariant_cast<QBrush>(value));
       
   857             painter->setBrushOrigin(oldBO);
       
   858         }
       
   859     }
       
   860 }
       
   861 
       
   862 
       
   863 /*!
       
   864     \internal
       
   865 
       
   866     Code duplicated in QCommonStylePrivate::viewItemLayout
       
   867 */
       
   868 
       
   869 void QItemDelegate::doLayout(const QStyleOptionViewItem &option,
       
   870                              QRect *checkRect, QRect *pixmapRect, QRect *textRect,
       
   871                              bool hint) const
       
   872 {
       
   873     Q_ASSERT(checkRect && pixmapRect && textRect);
       
   874     Q_D(const QItemDelegate);
       
   875     const QWidget *widget = d->widget(option);
       
   876     QStyle *style = widget ? widget->style() : QApplication::style();
       
   877     const bool hasCheck = checkRect->isValid();
       
   878     const bool hasPixmap = pixmapRect->isValid();
       
   879     const bool hasText = textRect->isValid();
       
   880     const int textMargin = hasText ? style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, widget) + 1 : 0;
       
   881     const int pixmapMargin = hasPixmap ? style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, widget) + 1 : 0;
       
   882     const int checkMargin = hasCheck ? style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, widget) + 1 : 0;
       
   883     int x = option.rect.left();
       
   884     int y = option.rect.top();
       
   885     int w, h;
       
   886 
       
   887     textRect->adjust(-textMargin, 0, textMargin, 0); // add width padding
       
   888     if (textRect->height() == 0 && (!hasPixmap || !hint)) {
       
   889         //if there is no text, we still want to have a decent height for the item sizeHint and the editor size
       
   890         textRect->setHeight(option.fontMetrics.height());
       
   891     }
       
   892 
       
   893     QSize pm(0, 0);
       
   894     if (hasPixmap) {
       
   895         pm = pixmapRect->size();
       
   896         pm.rwidth() += 2 * pixmapMargin;
       
   897     }
       
   898     if (hint) {
       
   899         h = qMax(checkRect->height(), qMax(textRect->height(), pm.height()));
       
   900         if (option.decorationPosition == QStyleOptionViewItem::Left
       
   901             || option.decorationPosition == QStyleOptionViewItem::Right) {
       
   902             w = textRect->width() + pm.width();
       
   903         } else {
       
   904             w = qMax(textRect->width(), pm.width());
       
   905         }
       
   906     } else {
       
   907         w = option.rect.width();
       
   908         h = option.rect.height();
       
   909     }
       
   910 
       
   911     int cw = 0;
       
   912     QRect check;
       
   913     if (hasCheck) {
       
   914         cw = checkRect->width() + 2 * checkMargin;
       
   915         if (hint) w += cw;
       
   916         if (option.direction == Qt::RightToLeft) {
       
   917             check.setRect(x + w - cw, y, cw, h);
       
   918         } else {
       
   919             check.setRect(x + checkMargin, y, cw, h);
       
   920         }
       
   921     }
       
   922 
       
   923     // at this point w should be the *total* width
       
   924 
       
   925     QRect display;
       
   926     QRect decoration;
       
   927     switch (option.decorationPosition) {
       
   928     case QStyleOptionViewItem::Top: {
       
   929         if (hasPixmap)
       
   930             pm.setHeight(pm.height() + pixmapMargin); // add space
       
   931         h = hint ? textRect->height() : h - pm.height();
       
   932 
       
   933         if (option.direction == Qt::RightToLeft) {
       
   934             decoration.setRect(x, y, w - cw, pm.height());
       
   935             display.setRect(x, y + pm.height(), w - cw, h);
       
   936         } else {
       
   937             decoration.setRect(x + cw, y, w - cw, pm.height());
       
   938             display.setRect(x + cw, y + pm.height(), w - cw, h);
       
   939         }
       
   940         break; }
       
   941     case QStyleOptionViewItem::Bottom: {
       
   942         if (hasText)
       
   943             textRect->setHeight(textRect->height() + textMargin); // add space
       
   944         h = hint ? textRect->height() + pm.height() : h;
       
   945 
       
   946         if (option.direction == Qt::RightToLeft) {
       
   947             display.setRect(x, y, w - cw, textRect->height());
       
   948             decoration.setRect(x, y + textRect->height(), w - cw, h - textRect->height());
       
   949         } else {
       
   950             display.setRect(x + cw, y, w - cw, textRect->height());
       
   951             decoration.setRect(x + cw, y + textRect->height(), w - cw, h - textRect->height());
       
   952         }
       
   953         break; }
       
   954     case QStyleOptionViewItem::Left: {
       
   955         if (option.direction == Qt::LeftToRight) {
       
   956             decoration.setRect(x + cw, y, pm.width(), h);
       
   957             display.setRect(decoration.right() + 1, y, w - pm.width() - cw, h);
       
   958         } else {
       
   959             display.setRect(x, y, w - pm.width() - cw, h);
       
   960             decoration.setRect(display.right() + 1, y, pm.width(), h);
       
   961         }
       
   962         break; }
       
   963     case QStyleOptionViewItem::Right: {
       
   964         if (option.direction == Qt::LeftToRight) {
       
   965             display.setRect(x + cw, y, w - pm.width() - cw, h);
       
   966             decoration.setRect(display.right() + 1, y, pm.width(), h);
       
   967         } else {
       
   968             decoration.setRect(x, y, pm.width(), h);
       
   969             display.setRect(decoration.right() + 1, y, w - pm.width() - cw, h);
       
   970         }
       
   971         break; }
       
   972     default:
       
   973         qWarning("doLayout: decoration position is invalid");
       
   974         decoration = *pixmapRect;
       
   975         break;
       
   976     }
       
   977 
       
   978     if (!hint) { // we only need to do the internal layout if we are going to paint
       
   979         *checkRect = QStyle::alignedRect(option.direction, Qt::AlignCenter,
       
   980                                          checkRect->size(), check);
       
   981         *pixmapRect = QStyle::alignedRect(option.direction, option.decorationAlignment,
       
   982                                           pixmapRect->size(), decoration);
       
   983         // the text takes up all available space, unless the decoration is not shown as selected
       
   984         if (option.showDecorationSelected)
       
   985             *textRect = display;
       
   986         else
       
   987             *textRect = QStyle::alignedRect(option.direction, option.displayAlignment,
       
   988                                             textRect->size().boundedTo(display.size()), display);
       
   989     } else {
       
   990         *checkRect = check;
       
   991         *pixmapRect = decoration;
       
   992         *textRect = display;
       
   993     }
       
   994 }
       
   995 
       
   996 /*!
       
   997     \internal
       
   998 
       
   999     Returns the pixmap used to decorate the root of the item view.
       
  1000     The style \a option controls the appearance of the root; the \a variant
       
  1001     refers to the data associated with an item.
       
  1002 */
       
  1003 
       
  1004 QPixmap QItemDelegate::decoration(const QStyleOptionViewItem &option, const QVariant &variant) const
       
  1005 {
       
  1006     Q_D(const QItemDelegate);
       
  1007     switch (variant.type()) {
       
  1008     case QVariant::Icon: {
       
  1009         QIcon::Mode mode = d->iconMode(option.state);
       
  1010         QIcon::State state = d->iconState(option.state);
       
  1011         return qvariant_cast<QIcon>(variant).pixmap(option.decorationSize, mode, state); }
       
  1012     case QVariant::Color: {
       
  1013         static QPixmap pixmap(option.decorationSize);
       
  1014         pixmap.fill(qvariant_cast<QColor>(variant));
       
  1015         return pixmap; }
       
  1016     default:
       
  1017         break;
       
  1018     }
       
  1019 
       
  1020     return qvariant_cast<QPixmap>(variant);
       
  1021 }
       
  1022 
       
  1023 // hacky but faster version of "QString::sprintf("%d-%d", i, enabled)"
       
  1024 static QString qPixmapSerial(quint64 i, bool enabled)
       
  1025 {
       
  1026     ushort arr[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', '0' + enabled };
       
  1027     ushort *ptr = &arr[16];
       
  1028 
       
  1029     while (i > 0) {
       
  1030         // hey - it's our internal representation, so use the ascii character after '9'
       
  1031         // instead of 'a' for hex
       
  1032         *(--ptr) = '0' + i % 16;
       
  1033         i >>= 4;
       
  1034     }
       
  1035 
       
  1036     return QString::fromUtf16(ptr, int(&arr[sizeof(arr) / sizeof(ushort)] - ptr));
       
  1037 }
       
  1038 
       
  1039 /*!
       
  1040   \internal
       
  1041   Returns the selected version of the given \a pixmap using the given \a palette.
       
  1042   The \a enabled argument decides whether the normal or disabled highlight color of
       
  1043   the palette is used.
       
  1044 */
       
  1045 QPixmap *QItemDelegate::selected(const QPixmap &pixmap, const QPalette &palette, bool enabled) const
       
  1046 {
       
  1047     QString key = qPixmapSerial(qt_pixmap_id(pixmap), enabled);
       
  1048     QPixmap *pm = QPixmapCache::find(key);
       
  1049     if (!pm) {
       
  1050         QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied);
       
  1051 
       
  1052         QColor color = palette.color(enabled ? QPalette::Normal : QPalette::Disabled,
       
  1053                                      QPalette::Highlight);
       
  1054         color.setAlphaF((qreal)0.3);
       
  1055 
       
  1056         QPainter painter(&img);
       
  1057         painter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
       
  1058         painter.fillRect(0, 0, img.width(), img.height(), color);
       
  1059         painter.end();
       
  1060 
       
  1061         QPixmap selected = QPixmap(QPixmap::fromImage(img));
       
  1062         int n = (img.numBytes() >> 10) + 1;
       
  1063         if (QPixmapCache::cacheLimit() < n)
       
  1064             QPixmapCache::setCacheLimit(n);
       
  1065 
       
  1066         QPixmapCache::insert(key, selected);
       
  1067         pm = QPixmapCache::find(key);
       
  1068     }
       
  1069     return pm;
       
  1070 }
       
  1071 
       
  1072 /*!
       
  1073   \internal
       
  1074 */
       
  1075 
       
  1076 QRect QItemDelegate::rect(const QStyleOptionViewItem &option,
       
  1077                           const QModelIndex &index, int role) const
       
  1078 {
       
  1079     Q_D(const QItemDelegate);
       
  1080     QVariant value = index.data(role);
       
  1081     if (role == Qt::CheckStateRole)
       
  1082         return check(option, option.rect, value);
       
  1083     if (value.isValid() && !value.isNull()) {
       
  1084         switch (value.type()) {
       
  1085         case QVariant::Invalid:
       
  1086             break;
       
  1087         case QVariant::Pixmap:
       
  1088             return QRect(QPoint(0, 0), qvariant_cast<QPixmap>(value).size());
       
  1089         case QVariant::Image:
       
  1090             return QRect(QPoint(0, 0), qvariant_cast<QImage>(value).size());
       
  1091         case QVariant::Icon: {
       
  1092             QIcon::Mode mode = d->iconMode(option.state);
       
  1093             QIcon::State state = d->iconState(option.state);
       
  1094             QIcon icon = qvariant_cast<QIcon>(value);
       
  1095             QSize size = icon.actualSize(option.decorationSize, mode, state);
       
  1096             return QRect(QPoint(0, 0), size); }
       
  1097         case QVariant::Color:
       
  1098             return QRect(QPoint(0, 0), option.decorationSize);
       
  1099         case QVariant::String:
       
  1100         default: {
       
  1101             QString text = QItemDelegatePrivate::valueToText(value, option);
       
  1102             value = index.data(Qt::FontRole);
       
  1103             QFont fnt = qvariant_cast<QFont>(value).resolve(option.font);
       
  1104             return textRectangle(0, d->textLayoutBounds(option), fnt, text); }
       
  1105         }
       
  1106     }
       
  1107     return QRect();
       
  1108 }
       
  1109 
       
  1110 /*!
       
  1111   \internal
       
  1112 
       
  1113   Note that on Mac, if /usr/include/AssertMacros.h is included prior
       
  1114   to QItemDelegate, and the application is building in debug mode, the
       
  1115   check(assertion) will conflict with QItemDelegate::check.
       
  1116 
       
  1117   To avoid this problem, add
       
  1118 
       
  1119   #ifdef check
       
  1120 	#undef check
       
  1121   #endif
       
  1122 
       
  1123   after including AssertMacros.h
       
  1124 */
       
  1125 QRect QItemDelegate::check(const QStyleOptionViewItem &option,
       
  1126                            const QRect &bounding, const QVariant &value) const
       
  1127 {
       
  1128     if (value.isValid()) {
       
  1129         Q_D(const QItemDelegate);
       
  1130         QStyleOptionButton opt;
       
  1131         opt.QStyleOption::operator=(option);
       
  1132         opt.rect = bounding;
       
  1133         const QWidget *widget = d->widget(option); // cast
       
  1134         QStyle *style = widget ? widget->style() : QApplication::style();
       
  1135         return style->subElementRect(QStyle::SE_ViewItemCheckIndicator, &opt, widget);
       
  1136     }
       
  1137     return QRect();
       
  1138 }
       
  1139 
       
  1140 /*!
       
  1141   \internal
       
  1142 */
       
  1143 QRect QItemDelegate::textRectangle(QPainter * /*painter*/, const QRect &rect,
       
  1144                                    const QFont &font, const QString &text) const
       
  1145 {
       
  1146     Q_D(const QItemDelegate);
       
  1147     d->textOption.setWrapMode(QTextOption::WordWrap);
       
  1148     d->textLayout.setTextOption(d->textOption);
       
  1149     d->textLayout.setFont(font);
       
  1150     d->textLayout.setText(QItemDelegatePrivate::replaceNewLine(text));
       
  1151     const QSize size = d->doTextLayout(rect.width()).toSize();
       
  1152     // ###: textRectangle should take style option as argument
       
  1153     const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1;
       
  1154     return QRect(0, 0, size.width() + 2 * textMargin, size.height());
       
  1155 }
       
  1156 
       
  1157 /*!
       
  1158     \fn bool QItemDelegate::eventFilter(QObject *editor, QEvent *event)
       
  1159 
       
  1160     Returns true if the given \a editor is a valid QWidget and the
       
  1161     given \a event is handled; otherwise returns false. The following
       
  1162     key press events are handled by default:
       
  1163 
       
  1164     \list
       
  1165         \o \gui Tab
       
  1166         \o \gui Backtab
       
  1167         \o \gui Enter
       
  1168         \o \gui Return
       
  1169         \o \gui Esc
       
  1170     \endlist
       
  1171 
       
  1172     In the case of \gui Tab, \gui Backtab, \gui Enter and \gui Return
       
  1173     key press events, the \a editor's data is comitted to the model
       
  1174     and the editor is closed. If the \a event is a \gui Tab key press
       
  1175     the view will open an editor on the next item in the
       
  1176     view. Likewise, if the \a event is a \gui Backtab key press the
       
  1177     view will open an editor on the \e previous item in the view.
       
  1178 
       
  1179     If the event is a \gui Esc key press event, the \a editor is
       
  1180     closed \e without committing its data.
       
  1181 
       
  1182     \sa commitData(), closeEditor()
       
  1183 */
       
  1184 
       
  1185 bool QItemDelegate::eventFilter(QObject *object, QEvent *event)
       
  1186 {
       
  1187     QWidget *editor = qobject_cast<QWidget*>(object);
       
  1188     if (!editor)
       
  1189         return false;
       
  1190     if (event->type() == QEvent::KeyPress) {
       
  1191         switch (static_cast<QKeyEvent *>(event)->key()) {
       
  1192         case Qt::Key_Tab:
       
  1193             emit commitData(editor);
       
  1194             emit closeEditor(editor, QAbstractItemDelegate::EditNextItem);
       
  1195             return true;
       
  1196         case Qt::Key_Backtab:
       
  1197             emit commitData(editor);
       
  1198             emit closeEditor(editor, QAbstractItemDelegate::EditPreviousItem);
       
  1199             return true;
       
  1200         case Qt::Key_Enter:
       
  1201         case Qt::Key_Return:
       
  1202 #ifndef QT_NO_TEXTEDIT
       
  1203             if (qobject_cast<QTextEdit *>(editor) || qobject_cast<QPlainTextEdit *>(editor))
       
  1204                 return false; // don't filter enter key events for QTextEdit
       
  1205             // We want the editor to be able to process the key press
       
  1206             // before committing the data (e.g. so it can do
       
  1207             // validation/fixup of the input).
       
  1208 #endif // QT_NO_TEXTEDIT
       
  1209 #ifndef QT_NO_LINEEDIT
       
  1210             if (QLineEdit *e = qobject_cast<QLineEdit*>(editor))
       
  1211                 if (!e->hasAcceptableInput())
       
  1212                     return false;
       
  1213 #endif // QT_NO_LINEEDIT
       
  1214             QMetaObject::invokeMethod(this, "_q_commitDataAndCloseEditor",
       
  1215                                       Qt::QueuedConnection, Q_ARG(QWidget*, editor));
       
  1216             return false;
       
  1217         case Qt::Key_Escape:
       
  1218             // don't commit data
       
  1219             emit closeEditor(editor, QAbstractItemDelegate::RevertModelCache);
       
  1220             break;
       
  1221         default:
       
  1222             return false;
       
  1223         }
       
  1224         if (editor->parentWidget())
       
  1225             editor->parentWidget()->setFocus();
       
  1226         return true;
       
  1227     } else if (event->type() == QEvent::FocusOut || (event->type() == QEvent::Hide && editor->isWindow())) {
       
  1228         //the Hide event will take care of he editors that are in fact complete dialogs
       
  1229         if (!editor->isActiveWindow() || (QApplication::focusWidget() != editor)) {
       
  1230             QWidget *w = QApplication::focusWidget();
       
  1231             while (w) { // don't worry about focus changes internally in the editor
       
  1232                 if (w == editor)
       
  1233                     return false;
       
  1234                 w = w->parentWidget();
       
  1235             }
       
  1236 #ifndef QT_NO_DRAGANDDROP
       
  1237             // The window may lose focus during an drag operation.
       
  1238             // i.e when dragging involves the taskbar on Windows.
       
  1239             if (QDragManager::self() && QDragManager::self()->object != 0)
       
  1240                 return false;
       
  1241 #endif
       
  1242 
       
  1243             emit commitData(editor);
       
  1244             emit closeEditor(editor, NoHint);
       
  1245         }
       
  1246     } else if (event->type() == QEvent::ShortcutOverride) {
       
  1247         if (static_cast<QKeyEvent*>(event)->key() == Qt::Key_Escape) {
       
  1248             event->accept();
       
  1249             return true;
       
  1250         }
       
  1251     }
       
  1252     return false;
       
  1253 }
       
  1254 
       
  1255 /*!
       
  1256   \reimp
       
  1257 */
       
  1258 
       
  1259 bool QItemDelegate::editorEvent(QEvent *event,
       
  1260                                 QAbstractItemModel *model,
       
  1261                                 const QStyleOptionViewItem &option,
       
  1262                                 const QModelIndex &index)
       
  1263 {
       
  1264     Q_ASSERT(event);
       
  1265     Q_ASSERT(model);
       
  1266 
       
  1267     // make sure that the item is checkable
       
  1268     Qt::ItemFlags flags = model->flags(index);
       
  1269     if (!(flags & Qt::ItemIsUserCheckable) || !(option.state & QStyle::State_Enabled)
       
  1270         || !(flags & Qt::ItemIsEnabled))
       
  1271         return false;
       
  1272 
       
  1273     // make sure that we have a check state
       
  1274     QVariant value = index.data(Qt::CheckStateRole);
       
  1275     if (!value.isValid())
       
  1276         return false;
       
  1277 
       
  1278     // make sure that we have the right event type
       
  1279     if ((event->type() == QEvent::MouseButtonRelease)
       
  1280         || (event->type() == QEvent::MouseButtonDblClick)) {
       
  1281         QRect checkRect = check(option, option.rect, Qt::Checked);
       
  1282         QRect emptyRect;
       
  1283         doLayout(option, &checkRect, &emptyRect, &emptyRect, false);
       
  1284         QMouseEvent *me = static_cast<QMouseEvent*>(event);
       
  1285         if (me->button() != Qt::LeftButton || !checkRect.contains(me->pos()))
       
  1286             return false;
       
  1287 
       
  1288         // eat the double click events inside the check rect
       
  1289         if (event->type() == QEvent::MouseButtonDblClick)
       
  1290             return true;
       
  1291 
       
  1292     } else if (event->type() == QEvent::KeyPress) {
       
  1293         if (static_cast<QKeyEvent*>(event)->key() != Qt::Key_Space
       
  1294          && static_cast<QKeyEvent*>(event)->key() != Qt::Key_Select)
       
  1295             return false;
       
  1296     } else {
       
  1297         return false;
       
  1298     }
       
  1299 
       
  1300     Qt::CheckState state;
       
  1301     if ( flags & Qt::ItemIsTristate ) {
       
  1302         state = static_cast<Qt::CheckState>( (value.toInt() + 1) % 3 );
       
  1303     } else {
       
  1304         state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked
       
  1305                             ? Qt::Unchecked : Qt::Checked);
       
  1306     }
       
  1307 
       
  1308     return model->setData(index, state, Qt::CheckStateRole);
       
  1309 }
       
  1310 
       
  1311 /*!
       
  1312   \internal
       
  1313 */
       
  1314 
       
  1315 QStyleOptionViewItem QItemDelegate::setOptions(const QModelIndex &index,
       
  1316                                                const QStyleOptionViewItem &option) const
       
  1317 {
       
  1318     QStyleOptionViewItem opt = option;
       
  1319 
       
  1320     // set font
       
  1321     QVariant value = index.data(Qt::FontRole);
       
  1322     if (value.isValid()){
       
  1323         opt.font = qvariant_cast<QFont>(value).resolve(opt.font);
       
  1324         opt.fontMetrics = QFontMetrics(opt.font);
       
  1325     }
       
  1326 
       
  1327     // set text alignment
       
  1328     value = index.data(Qt::TextAlignmentRole);
       
  1329     if (value.isValid())
       
  1330         opt.displayAlignment = Qt::Alignment(value.toInt());
       
  1331 
       
  1332     // set foreground brush
       
  1333     value = index.data(Qt::ForegroundRole);
       
  1334     if (qVariantCanConvert<QBrush>(value))
       
  1335         opt.palette.setBrush(QPalette::Text, qvariant_cast<QBrush>(value));
       
  1336 
       
  1337     return opt;
       
  1338 }
       
  1339 
       
  1340 QT_END_NAMESPACE
       
  1341 
       
  1342 #include "moc_qitemdelegate.cpp"
       
  1343 
       
  1344 #endif // QT_NO_ITEMVIEWS