1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
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 #include <qmath.h>
73 
74 #include <limits.h>
75 
76 #ifndef DBL_DIG
77 #  define DBL_DIG 10
78 #endif
79 
80 QT_BEGIN_NAMESPACE
81 
82 class QItemDelegatePrivate : public QObjectPrivate
83 {
84     Q_DECLARE_PUBLIC(QItemDelegate)
85 
86 public:
QItemDelegatePrivate()87     QItemDelegatePrivate() : f(0), clipPainting(true) {}
88 
editorFactory() const89     inline const QItemEditorFactory *editorFactory() const
90         { return f ? f : QItemEditorFactory::defaultFactory(); }
91 
iconMode(QStyle::State state) const92     inline QIcon::Mode iconMode(QStyle::State state) const
93         {
94             if (!(state & QStyle::State_Enabled)) return QIcon::Disabled;
95             if (state & QStyle::State_Selected) return QIcon::Selected;
96             return QIcon::Normal;
97         }
98 
iconState(QStyle::State state) const99     inline QIcon::State iconState(QStyle::State state) const
100         { return state & QStyle::State_Open ? QIcon::On : QIcon::Off; }
101 
replaceNewLine(QString text)102     inline static QString replaceNewLine(QString text)
103         {
104             const QChar nl = QLatin1Char('\n');
105             for (int i = 0; i < text.count(); ++i)
106                 if (text.at(i) == nl)
107                     text[i] = QChar::LineSeparator;
108             return text;
109         }
110 
111     static QString valueToText(const QVariant &value, const QStyleOptionViewItemV4 &option);
112 
113     void _q_commitDataAndCloseEditor(QWidget *editor);
114 
115     QItemEditorFactory *f;
116     bool clipPainting;
117 
118     QRect textLayoutBounds(const QStyleOptionViewItemV2 &options) const;
119     QSizeF doTextLayout(int lineWidth) const;
120     mutable QTextLayout textLayout;
121     mutable QTextOption textOption;
122 
widget(const QStyleOptionViewItem & option) const123     const QWidget *widget(const QStyleOptionViewItem &option) const
124     {
125         if (const QStyleOptionViewItemV3 *v3 = qstyleoption_cast<const QStyleOptionViewItemV3 *>(&option))
126             return v3->widget;
127 
128         return 0;
129     }
130 
131     // ### temporary hack until we have QStandardItemDelegate
132     mutable struct Icon {
133         QIcon icon;
134         QIcon::Mode mode;
135         QIcon::State state;
136     } tmp;
137 };
138 
_q_commitDataAndCloseEditor(QWidget * editor)139 void QItemDelegatePrivate::_q_commitDataAndCloseEditor(QWidget *editor)
140 {
141     Q_Q(QItemDelegate);
142     emit q->commitData(editor);
143     emit q->closeEditor(editor, QAbstractItemDelegate::SubmitModelCache);
144 }
145 
textLayoutBounds(const QStyleOptionViewItemV2 & option) const146 QRect QItemDelegatePrivate::textLayoutBounds(const QStyleOptionViewItemV2 &option) const
147 {
148     QRect rect = option.rect;
149     const bool wrapText = option.features & QStyleOptionViewItemV2::WrapText;
150     switch (option.decorationPosition) {
151     case QStyleOptionViewItem::Left:
152     case QStyleOptionViewItem::Right:
153         rect.setWidth(wrapText && rect.isValid() ? rect.width() : (QFIXED_MAX));
154         break;
155     case QStyleOptionViewItem::Top:
156     case QStyleOptionViewItem::Bottom:
157         rect.setWidth(wrapText ? option.decorationSize.width() : (QFIXED_MAX));
158         break;
159     }
160 
161     return rect;
162 }
163 
doTextLayout(int lineWidth) const164 QSizeF QItemDelegatePrivate::doTextLayout(int lineWidth) const
165 {
166     qreal height = 0;
167     qreal widthUsed = 0;
168     textLayout.beginLayout();
169     while (true) {
170         QTextLine line = textLayout.createLine();
171         if (!line.isValid())
172             break;
173         line.setLineWidth(lineWidth);
174         line.setPosition(QPointF(0, height));
175         height += line.height();
176         widthUsed = qMax(widthUsed, line.naturalTextWidth());
177     }
178     textLayout.endLayout();
179     return QSizeF(widthUsed, height);
180 }
181 
182 /*!
183     \class QItemDelegate
184 
185     \brief The QItemDelegate class provides display and editing facilities for
186     data items from a model.
187 
188     \ingroup model-view
189 
190 
191     QItemDelegate can be used to provide custom display features and editor
192     widgets for item views based on QAbstractItemView subclasses. Using a
193     delegate for this purpose allows the display and editing mechanisms to be
194     customized and developed independently from the model and view.
195 
196     The QItemDelegate class is one of the \l{Model/View Classes} and
197     is part of Qt's \l{Model/View Programming}{model/view framework}.
198     Note that QStyledItemDelegate has taken over the job of drawing
199     Qt's item views. We recommend the use of QStyledItemDelegate when
200     creating new delegates.
201 
202     When displaying items from a custom model in a standard view, it is
203     often sufficient to simply ensure that the model returns appropriate
204     data for each of the \l{Qt::ItemDataRole}{roles} that determine the
205     appearance of items in views. The default delegate used by Qt's
206     standard views uses this role information to display items in most
207     of the common forms expected by users. However, it is sometimes
208     necessary to have even more control over the appearance of items than
209     the default delegate can provide.
210 
211     This class provides default implementations of the functions for
212     painting item data in a view and editing data from item models.
213     Default implementations of the paint() and sizeHint() virtual
214     functions, defined in QAbstractItemDelegate, are provided to
215     ensure that the delegate implements the correct basic behavior
216     expected by views. You can reimplement these functions in
217     subclasses to customize the appearance of items.
218 
219     When editing data in an item view, QItemDelegate provides an
220     editor widget, which is a widget that is placed on top of the view
221     while editing takes place. Editors are created with a
222     QItemEditorFactory; a default static instance provided by
223     QItemEditorFactory is installed on all item delegates. You can set
224     a custom factory using setItemEditorFactory() or set a new default
225     factory with QItemEditorFactory::setDefaultFactory(). It is the
226     data stored in the item model with the Qt::EditRole that is edited.
227 
228     Only the standard editing functions for widget-based delegates are
229     reimplemented here:
230 
231     \list
232         \o createEditor() returns the widget used to change data from the model
233            and can be reimplemented to customize editing behavior.
234         \o setEditorData() provides the widget with data to manipulate.
235         \o updateEditorGeometry() ensures that the editor is displayed correctly
236            with respect to the item view.
237         \o setModelData() returns updated data to the model.
238     \endlist
239 
240     The closeEditor() signal indicates that the user has completed editing the data,
241     and that the editor widget can be destroyed.
242 
243     \section1 Standard Roles and Data Types
244 
245     The default delegate used by the standard views supplied with Qt
246     associates each standard role (defined by Qt::ItemDataRole) with certain
247     data types. Models that return data in these types can influence the
248     appearance of the delegate as described in the following table.
249 
250     \table
251     \header \o Role \o Accepted Types
252     \omit
253     \row    \o \l Qt::AccessibleDescriptionRole \o QString
254     \row    \o \l Qt::AccessibleTextRole \o QString
255     \endomit
256     \row    \o \l Qt::BackgroundRole \o QBrush
257     \row    \o \l Qt::BackgroundColorRole \o QColor (obsolete; use Qt::BackgroundRole instead)
258     \row    \o \l Qt::CheckStateRole \o Qt::CheckState
259     \row    \o \l Qt::DecorationRole \o QIcon, QPixmap and QColor
260     \row    \o \l Qt::DisplayRole \o QString and types with a string representation
261     \row    \o \l Qt::EditRole \o See QItemEditorFactory for details
262     \row    \o \l Qt::FontRole \o QFont
263     \row    \o \l Qt::SizeHintRole \o QSize
264     \omit
265     \row    \o \l Qt::StatusTipRole \o
266     \endomit
267     \row    \o \l Qt::TextAlignmentRole \o Qt::Alignment
268     \row    \o \l Qt::ForegroundRole \o QBrush
269     \row    \o \l Qt::TextColorRole \o QColor (obsolete; use Qt::ForegroundRole instead)
270     \omit
271     \row    \o \l Qt::ToolTipRole
272     \row    \o \l Qt::WhatsThisRole
273     \endomit
274     \endtable
275 
276     If the default delegate does not allow the level of customization that
277     you need, either for display purposes or for editing data, it is possible to
278     subclass QItemDelegate to implement the desired behavior.
279 
280     \section1 Subclassing
281 
282     When subclassing QItemDelegate to create a delegate that displays items
283     using a custom renderer, it is important to ensure that the delegate can
284     render items suitably for all the required states; e.g. selected,
285     disabled, checked. The documentation for the paint() function contains
286     some hints to show how this can be achieved.
287 
288     You can provide custom editors by using a QItemEditorFactory. The
289     \l{Color Editor Factory Example} shows how a custom editor can be
290     made available to delegates with the default item editor
291     factory. This way, there is no need to subclass QItemDelegate.  An
292     alternative is to reimplement createEditor(), setEditorData(),
293     setModelData(), and updateEditorGeometry(). This process is
294     described in the \l{Spin Box Delegate Example}.
295 
296     \section1 QStyledItemDelegate vs. QItemDelegate
297 
298     Since Qt 4.4, there are two delegate classes: QItemDelegate and
299     QStyledItemDelegate. However, the default delegate is QStyledItemDelegate.
300     These two classes are independent alternatives to painting and providing
301     editors for items in views. The difference between them is that
302     QStyledItemDelegate uses the current style to paint its items. We therefore
303     recommend using QStyledItemDelegate as the base class when implementing
304     custom delegates or when working with Qt style sheets. The code required
305     for either class should be equal unless the custom delegate needs to use
306     the style for drawing.
307 
308     \sa {Delegate Classes}, QStyledItemDelegate, QAbstractItemDelegate,
309         {Spin Box Delegate Example}, {Settings Editor Example},
310         {Icons Example}
311 */
312 
313 /*!
314     Constructs an item delegate with the given \a parent.
315 */
316 
QItemDelegate(QObject * parent)317 QItemDelegate::QItemDelegate(QObject *parent)
318     : QAbstractItemDelegate(*new QItemDelegatePrivate(), parent)
319 {
320 
321 }
322 
323 /*!
324     Destroys the item delegate.
325 */
326 
~QItemDelegate()327 QItemDelegate::~QItemDelegate()
328 {
329 }
330 
331 /*!
332   \property QItemDelegate::clipping
333   \brief if the delegate should clip the paint events
334   \since 4.2
335 
336   This property will set the paint clip to the size of the item.
337   The default value is on. It is useful for cases such
338   as when images are larger than the size of the item.
339 */
340 
hasClipping() const341 bool QItemDelegate::hasClipping() const
342 {
343     Q_D(const QItemDelegate);
344     return d->clipPainting;
345 }
346 
setClipping(bool clip)347 void QItemDelegate::setClipping(bool clip)
348 {
349     Q_D(QItemDelegate);
350     d->clipPainting = clip;
351 }
352 
valueToText(const QVariant & value,const QStyleOptionViewItemV4 & option)353 QString QItemDelegatePrivate::valueToText(const QVariant &value, const QStyleOptionViewItemV4 &option)
354 {
355     QString text;
356     switch (value.userType()) {
357         case QMetaType::Float:
358             text = option.locale.toString(value.toFloat(), 'g');
359             break;
360         case QVariant::Double:
361             text = option.locale.toString(value.toDouble(), 'g', DBL_DIG);
362             break;
363         case QVariant::Int:
364         case QVariant::LongLong:
365             text = option.locale.toString(value.toLongLong());
366             break;
367         case QVariant::UInt:
368         case QVariant::ULongLong:
369             text = option.locale.toString(value.toULongLong());
370             break;
371         case QVariant::Date:
372             text = option.locale.toString(value.toDate(), QLocale::ShortFormat);
373             break;
374         case QVariant::Time:
375             text = option.locale.toString(value.toTime(), QLocale::ShortFormat);
376             break;
377         case QVariant::DateTime:
378             text = option.locale.toString(value.toDateTime().date(), QLocale::ShortFormat);
379             text += QLatin1Char(' ');
380             text += option.locale.toString(value.toDateTime().time(), QLocale::ShortFormat);
381             break;
382         default:
383             text = replaceNewLine(value.toString());
384             break;
385     }
386     return text;
387 }
388 
389 /*!
390     Renders the delegate using the given \a painter and style \a option for
391     the item specified by \a index.
392 
393     When reimplementing this function in a subclass, you should update the area
394     held by the option's \l{QStyleOption::rect}{rect} variable, using the
395     option's \l{QStyleOption::state}{state} variable to determine the state of
396     the item to be displayed, and adjust the way it is painted accordingly.
397 
398     For example, a selected item may need to be displayed differently to
399     unselected items, as shown in the following code:
400 
401     \snippet examples/itemviews/pixelator/pixeldelegate.cpp 2
402     \dots
403 
404     After painting, you should ensure that the painter is returned to its
405     the state it was supplied in when this function was called. For example,
406     it may be useful to call QPainter::save() before painting and
407     QPainter::restore() afterwards.
408 
409     \sa QStyle::State
410 */
paint(QPainter * painter,const QStyleOptionViewItem & option,const QModelIndex & index) const411 void QItemDelegate::paint(QPainter *painter,
412                           const QStyleOptionViewItem &option,
413                           const QModelIndex &index) const
414 {
415     Q_D(const QItemDelegate);
416     Q_ASSERT(index.isValid());
417 
418     QStyleOptionViewItemV4 opt = setOptions(index, option);
419 
420     const QStyleOptionViewItemV2 *v2 = qstyleoption_cast<const QStyleOptionViewItemV2 *>(&option);
421     opt.features = v2 ? v2->features
422                     : QStyleOptionViewItemV2::ViewItemFeatures(QStyleOptionViewItemV2::None);
423     const QStyleOptionViewItemV3 *v3 = qstyleoption_cast<const QStyleOptionViewItemV3 *>(&option);
424     opt.locale = v3 ? v3->locale : QLocale();
425     opt.widget = v3 ? v3->widget : 0;
426 
427     // prepare
428     painter->save();
429     if (d->clipPainting)
430         painter->setClipRect(opt.rect);
431 
432     // get the data and the rectangles
433 
434     QVariant value;
435 
436     QPixmap pixmap;
437     QRect decorationRect;
438     value = index.data(Qt::DecorationRole);
439     if (value.isValid()) {
440         // ### we need the pixmap to call the virtual function
441         pixmap = decoration(opt, value);
442         if (value.type() == QVariant::Icon) {
443             d->tmp.icon = qvariant_cast<QIcon>(value);
444             d->tmp.mode = d->iconMode(option.state);
445             d->tmp.state = d->iconState(option.state);
446             const QSize size = d->tmp.icon.actualSize(option.decorationSize,
447                                                       d->tmp.mode, d->tmp.state);
448             decorationRect = QRect(QPoint(0, 0), size);
449         } else {
450             d->tmp.icon = QIcon();
451             decorationRect = QRect(QPoint(0, 0), pixmap.size());
452         }
453     } else {
454         d->tmp.icon = QIcon();
455         decorationRect = QRect();
456     }
457 
458     QString text;
459     QRect displayRect;
460     value = index.data(Qt::DisplayRole);
461     if (value.isValid() && !value.isNull()) {
462         text = QItemDelegatePrivate::valueToText(value, opt);
463         displayRect = textRectangle(painter, d->textLayoutBounds(opt), opt.font, text);
464     }
465 
466     QRect checkRect;
467     Qt::CheckState checkState = Qt::Unchecked;
468     value = index.data(Qt::CheckStateRole);
469     if (value.isValid()) {
470         checkState = static_cast<Qt::CheckState>(value.toInt());
471         checkRect = check(opt, opt.rect, value);
472     }
473 
474     // do the layout
475 
476     doLayout(opt, &checkRect, &decorationRect, &displayRect, false);
477 
478     // draw the item
479 
480     drawBackground(painter, opt, index);
481     drawCheck(painter, opt, checkRect, checkState);
482     drawDecoration(painter, opt, decorationRect, pixmap);
483     drawDisplay(painter, opt, displayRect, text);
484     drawFocus(painter, opt, displayRect);
485 
486     // done
487     painter->restore();
488 }
489 
490 /*!
491     Returns the size needed by the delegate to display the item
492     specified by \a index, taking into account the style information
493     provided by \a option.
494 
495     When reimplementing this function, note that in case of text
496     items, QItemDelegate adds a margin (i.e. 2 *
497     QStyle::PM_FocusFrameHMargin) to the length of the text.
498 */
499 
sizeHint(const QStyleOptionViewItem & option,const QModelIndex & index) const500 QSize QItemDelegate::sizeHint(const QStyleOptionViewItem &option,
501                               const QModelIndex &index) const
502 {
503     QVariant value = index.data(Qt::SizeHintRole);
504     if (value.isValid())
505         return qvariant_cast<QSize>(value);
506     QRect decorationRect = rect(option, index, Qt::DecorationRole);
507     QRect displayRect = rect(option, index, Qt::DisplayRole);
508     QRect checkRect = rect(option, index, Qt::CheckStateRole);
509 
510     doLayout(option, &checkRect, &decorationRect, &displayRect, true);
511 
512     return (decorationRect|displayRect|checkRect).size();
513 }
514 
515 /*!
516     Returns the widget used to edit the item specified by \a index
517     for editing. The \a parent widget and style \a option are used to
518     control how the editor widget appears.
519 
520     \sa QAbstractItemDelegate::createEditor()
521 */
522 
createEditor(QWidget * parent,const QStyleOptionViewItem &,const QModelIndex & index) const523 QWidget *QItemDelegate::createEditor(QWidget *parent,
524                                      const QStyleOptionViewItem &,
525                                      const QModelIndex &index) const
526 {
527     Q_D(const QItemDelegate);
528     if (!index.isValid())
529         return 0;
530     QVariant::Type t = static_cast<QVariant::Type>(index.data(Qt::EditRole).userType());
531     const QItemEditorFactory *factory = d->f;
532     if (factory == 0)
533         factory = QItemEditorFactory::defaultFactory();
534     return factory->createEditor(t, parent);
535 }
536 
537 /*!
538     Sets the data to be displayed and edited by the \a editor from the
539     data model item specified by the model \a index.
540 
541     The default implementation stores the data in the \a editor
542     widget's \l {Qt's Property System} {user property}.
543 
544     \sa QMetaProperty::isUser()
545 */
546 
setEditorData(QWidget * editor,const QModelIndex & index) const547 void QItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
548 {
549 #ifdef QT_NO_PROPERTIES
550     Q_UNUSED(editor);
551     Q_UNUSED(index);
552 #else
553     Q_D(const QItemDelegate);
554     QVariant v = index.data(Qt::EditRole);
555     QByteArray n = editor->metaObject()->userProperty().name();
556 
557     // ### Qt 5: remove
558     // A work-around for missing "USER true" in qdatetimeedit.h for
559     // QTimeEdit's time property and QDateEdit's date property.
560     // It only triggers if the default user property "dateTime" is
561     // reported for QTimeEdit and QDateEdit.
562     if (n == "dateTime") {
563         if (editor->inherits("QTimeEdit"))
564             n = "time";
565         else if (editor->inherits("QDateEdit"))
566             n = "date";
567     }
568 
569     // ### Qt 5: give QComboBox a USER property
570     if (n.isEmpty() && editor->inherits("QComboBox"))
571         n = d->editorFactory()->valuePropertyName(static_cast<QVariant::Type>(v.userType()));
572     if (!n.isEmpty()) {
573         if (!v.isValid())
574             v = QVariant(editor->property(n).userType(), (const void *)0);
575         editor->setProperty(n, v);
576     }
577 #endif
578 }
579 
580 /*!
581     Gets data from the \a editor widget and stores it in the specified
582     \a model at the item \a index.
583 
584     The default implementation gets the value to be stored in the data
585     model from the \a editor widget's \l {Qt's Property System} {user
586     property}.
587 
588     \sa QMetaProperty::isUser()
589 */
590 
setModelData(QWidget * editor,QAbstractItemModel * model,const QModelIndex & index) const591 void QItemDelegate::setModelData(QWidget *editor,
592                                  QAbstractItemModel *model,
593                                  const QModelIndex &index) const
594 {
595 #ifdef QT_NO_PROPERTIES
596     Q_UNUSED(model);
597     Q_UNUSED(editor);
598     Q_UNUSED(index);
599 #else
600     Q_D(const QItemDelegate);
601     Q_ASSERT(model);
602     Q_ASSERT(editor);
603     QByteArray n = editor->metaObject()->userProperty().name();
604     if (n.isEmpty())
605         n = d->editorFactory()->valuePropertyName(
606             static_cast<QVariant::Type>(model->data(index, Qt::EditRole).userType()));
607     if (!n.isEmpty())
608         model->setData(index, editor->property(n), Qt::EditRole);
609 #endif
610 }
611 
612 /*!
613     Updates the \a editor for the item specified by \a index
614     according to the style \a option given.
615 */
616 
updateEditorGeometry(QWidget * editor,const QStyleOptionViewItem & option,const QModelIndex & index) const617 void QItemDelegate::updateEditorGeometry(QWidget *editor,
618                                          const QStyleOptionViewItem &option,
619                                          const QModelIndex &index) const
620 {
621     if (!editor)
622         return;
623     Q_ASSERT(index.isValid());
624     QPixmap pixmap = decoration(option, index.data(Qt::DecorationRole));
625     QString text = QItemDelegatePrivate::replaceNewLine(index.data(Qt::DisplayRole).toString());
626     QRect pixmapRect = QRect(QPoint(0, 0), option.decorationSize).intersected(pixmap.rect());
627     QRect textRect = textRectangle(0, option.rect, option.font, text);
628     QRect checkRect = check(option, textRect, index.data(Qt::CheckStateRole));
629     QStyleOptionViewItem opt = option;
630     opt.showDecorationSelected = true; // let the editor take up all available space
631     doLayout(opt, &checkRect, &pixmapRect, &textRect, false);
632     editor->setGeometry(textRect);
633 }
634 
635 /*!
636   Returns the editor factory used by the item delegate.
637   If no editor factory is set, the function will return null.
638 
639   \sa setItemEditorFactory()
640 */
itemEditorFactory() const641 QItemEditorFactory *QItemDelegate::itemEditorFactory() const
642 {
643     Q_D(const QItemDelegate);
644     return d->f;
645 }
646 
647 /*!
648   Sets the editor factory to be used by the item delegate to be the \a factory
649   specified. If no editor factory is set, the item delegate will use the
650   default editor factory.
651 
652   \sa itemEditorFactory()
653 */
setItemEditorFactory(QItemEditorFactory * factory)654 void QItemDelegate::setItemEditorFactory(QItemEditorFactory *factory)
655 {
656     Q_D(QItemDelegate);
657     d->f = factory;
658 }
659 
660 /*!
661    Renders the item view \a text within the rectangle specified by \a rect
662    using the given \a painter and style \a option.
663 */
664 
drawDisplay(QPainter * painter,const QStyleOptionViewItem & option,const QRect & rect,const QString & text) const665 void QItemDelegate::drawDisplay(QPainter *painter, const QStyleOptionViewItem &option,
666                                 const QRect &rect, const QString &text) const
667 {
668     Q_D(const QItemDelegate);
669 
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 */
drawDecoration(QPainter * painter,const QStyleOptionViewItem & option,const QRect & rect,const QPixmap & pixmap) const749 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 
drawFocus(QPainter * painter,const QStyleOptionViewItem & option,const QRect & rect) const777 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 
drawCheck(QPainter * painter,const QStyleOptionViewItem & option,const QRect & rect,Qt::CheckState state) const804 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 
drawBackground(QPainter * painter,const QStyleOptionViewItem & option,const QModelIndex & index) const840 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 (value.canConvert<QBrush>()) {
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 
doLayout(const QStyleOptionViewItem & option,QRect * checkRect,QRect * pixmapRect,QRect * textRect,bool hint) const869 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 
decoration(const QStyleOptionViewItem & option,const QVariant & variant) const1004 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)"
qPixmapSerial(quint64 i,bool 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, '-', ushort('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((const QChar *)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 */
selected(const QPixmap & pixmap,const QPalette & palette,bool enabled) const1045 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.byteCount() >> 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 
rect(const QStyleOptionViewItem & option,const QModelIndex & index,int role) const1076 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 */
check(const QStyleOptionViewItem & option,const QRect & bounding,const QVariant & value) const1125 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 */
textRectangle(QPainter *,const QRect & rect,const QFont & font,const QString & text) const1143 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     QSizeF fpSize = d->doTextLayout(rect.width());
1152     const QSize size = QSize(qCeil(fpSize.width()), qCeil(fpSize.height()));
1153     // ###: textRectangle should take style option as argument
1154     const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1;
1155     return QRect(0, 0, size.width() + 2 * textMargin, size.height());
1156 }
1157 
1158 /*!
1159     \fn bool QItemDelegate::eventFilter(QObject *editor, QEvent *event)
1160 
1161     Returns true if the given \a editor is a valid QWidget and the
1162     given \a event is handled; otherwise returns false. The following
1163     key press events are handled by default:
1164 
1165     \list
1166         \o \gui Tab
1167         \o \gui Backtab
1168         \o \gui Enter
1169         \o \gui Return
1170         \o \gui Esc
1171     \endlist
1172 
1173     In the case of \gui Tab, \gui Backtab, \gui Enter and \gui Return
1174     key press events, the \a editor's data is comitted to the model
1175     and the editor is closed. If the \a event is a \gui Tab key press
1176     the view will open an editor on the next item in the
1177     view. Likewise, if the \a event is a \gui Backtab key press the
1178     view will open an editor on the \e previous item in the view.
1179 
1180     If the event is a \gui Esc key press event, the \a editor is
1181     closed \e without committing its data.
1182 
1183     \sa commitData(), closeEditor()
1184 */
1185 
eventFilter(QObject * object,QEvent * event)1186 bool QItemDelegate::eventFilter(QObject *object, QEvent *event)
1187 {
1188     QWidget *editor = qobject_cast<QWidget*>(object);
1189     if (!editor)
1190         return false;
1191     if (event->type() == QEvent::KeyPress) {
1192         switch (static_cast<QKeyEvent *>(event)->key()) {
1193         case Qt::Key_Tab:
1194             emit commitData(editor);
1195             emit closeEditor(editor, QAbstractItemDelegate::EditNextItem);
1196             return true;
1197         case Qt::Key_Backtab:
1198             emit commitData(editor);
1199             emit closeEditor(editor, QAbstractItemDelegate::EditPreviousItem);
1200             return true;
1201         case Qt::Key_Enter:
1202         case Qt::Key_Return:
1203 #ifndef QT_NO_TEXTEDIT
1204             if (qobject_cast<QTextEdit *>(editor) || qobject_cast<QPlainTextEdit *>(editor))
1205                 return false; // don't filter enter key events for QTextEdit
1206             // We want the editor to be able to process the key press
1207             // before committing the data (e.g. so it can do
1208             // validation/fixup of the input).
1209 #endif // QT_NO_TEXTEDIT
1210 #ifndef QT_NO_LINEEDIT
1211             if (QLineEdit *e = qobject_cast<QLineEdit*>(editor))
1212                 if (!e->hasAcceptableInput())
1213                     return false;
1214 #endif // QT_NO_LINEEDIT
1215             QMetaObject::invokeMethod(this, "_q_commitDataAndCloseEditor",
1216                                       Qt::QueuedConnection, Q_ARG(QWidget*, editor));
1217             return false;
1218         case Qt::Key_Escape:
1219             // don't commit data
1220             emit closeEditor(editor, QAbstractItemDelegate::RevertModelCache);
1221             break;
1222         default:
1223             return false;
1224         }
1225         if (editor->parentWidget())
1226             editor->parentWidget()->setFocus();
1227         return true;
1228     } else if (event->type() == QEvent::FocusOut || (event->type() == QEvent::Hide && editor->isWindow())) {
1229         //the Hide event will take care of he editors that are in fact complete dialogs
1230         if (!editor->isActiveWindow() || (QApplication::focusWidget() != editor)) {
1231             QWidget *w = QApplication::focusWidget();
1232             while (w) { // don't worry about focus changes internally in the editor
1233                 if (w == editor)
1234                     return false;
1235                 w = w->parentWidget();
1236             }
1237 #ifndef QT_NO_DRAGANDDROP
1238             // The window may lose focus during an drag operation.
1239             // i.e when dragging involves the taskbar on Windows.
1240             if (QDragManager::self() && QDragManager::self()->object != 0)
1241                 return false;
1242 #endif
1243 
1244             emit commitData(editor);
1245             emit closeEditor(editor, NoHint);
1246         }
1247     } else if (event->type() == QEvent::ShortcutOverride) {
1248         if (static_cast<QKeyEvent*>(event)->key() == Qt::Key_Escape) {
1249             event->accept();
1250             return true;
1251         }
1252     }
1253     return false;
1254 }
1255 
1256 /*!
1257   \reimp
1258 */
1259 
editorEvent(QEvent * event,QAbstractItemModel * model,const QStyleOptionViewItem & option,const QModelIndex & index)1260 bool QItemDelegate::editorEvent(QEvent *event,
1261                                 QAbstractItemModel *model,
1262                                 const QStyleOptionViewItem &option,
1263                                 const QModelIndex &index)
1264 {
1265     Q_ASSERT(event);
1266     Q_ASSERT(model);
1267 
1268     // make sure that the item is checkable
1269     Qt::ItemFlags flags = model->flags(index);
1270     if (!(flags & Qt::ItemIsUserCheckable) || !(option.state & QStyle::State_Enabled)
1271         || !(flags & Qt::ItemIsEnabled))
1272         return false;
1273 
1274     // make sure that we have a check state
1275     QVariant value = index.data(Qt::CheckStateRole);
1276     if (!value.isValid())
1277         return false;
1278 
1279     // make sure that we have the right event type
1280     if ((event->type() == QEvent::MouseButtonRelease)
1281         || (event->type() == QEvent::MouseButtonDblClick)
1282         || (event->type() == QEvent::MouseButtonPress)) {
1283         QRect checkRect = check(option, option.rect, Qt::Checked);
1284         QRect emptyRect;
1285         doLayout(option, &checkRect, &emptyRect, &emptyRect, false);
1286         QMouseEvent *me = static_cast<QMouseEvent*>(event);
1287         if (me->button() != Qt::LeftButton || !checkRect.contains(me->pos()))
1288             return false;
1289 
1290         // eat the double click events inside the check rect
1291         if ((event->type() == QEvent::MouseButtonPress)
1292             || (event->type() == QEvent::MouseButtonDblClick))
1293             return true;
1294 
1295     } else if (event->type() == QEvent::KeyPress) {
1296         if (static_cast<QKeyEvent*>(event)->key() != Qt::Key_Space
1297          && static_cast<QKeyEvent*>(event)->key() != Qt::Key_Select)
1298             return false;
1299     } else {
1300         return false;
1301     }
1302 
1303     Qt::CheckState state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked
1304                             ? Qt::Unchecked : Qt::Checked);
1305     return model->setData(index, state, Qt::CheckStateRole);
1306 }
1307 
1308 /*!
1309   \internal
1310 */
1311 
setOptions(const QModelIndex & index,const QStyleOptionViewItem & option) const1312 QStyleOptionViewItem QItemDelegate::setOptions(const QModelIndex &index,
1313                                                const QStyleOptionViewItem &option) const
1314 {
1315     QStyleOptionViewItem opt = option;
1316 
1317     // set font
1318     QVariant value = index.data(Qt::FontRole);
1319     if (value.isValid()){
1320         opt.font = qvariant_cast<QFont>(value).resolve(opt.font);
1321         opt.fontMetrics = QFontMetrics(opt.font);
1322     }
1323 
1324     // set text alignment
1325     value = index.data(Qt::TextAlignmentRole);
1326     if (value.isValid())
1327         opt.displayAlignment = Qt::Alignment(value.toInt());
1328 
1329     // set foreground brush
1330     value = index.data(Qt::ForegroundRole);
1331     if (value.canConvert<QBrush>())
1332         opt.palette.setBrush(QPalette::Text, qvariant_cast<QBrush>(value));
1333 
1334     return opt;
1335 }
1336 
1337 QT_END_NAMESPACE
1338 
1339 #include "moc_qitemdelegate.cpp"
1340 
1341 #endif // QT_NO_ITEMVIEWS
1342