1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtWidgets 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 https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://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 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qstyleditemdelegate.h"
41
42#include <qabstractitemmodel.h>
43#include <qapplication.h>
44#include <qbrush.h>
45#if QT_CONFIG(lineedit)
46#include <qlineedit.h>
47#endif
48#if QT_CONFIG(textedit)
49#include <qtextedit.h>
50#include <qplaintextedit.h>
51#endif
52#include <qpainter.h>
53#include <qpalette.h>
54#include <qpoint.h>
55#include <qrect.h>
56#include <qsize.h>
57#include <qstyle.h>
58#include <qdatetime.h>
59#include <qstyleoption.h>
60#include <qevent.h>
61#include <qpixmap.h>
62#include <qbitmap.h>
63#include <qpixmapcache.h>
64#include <qitemeditorfactory.h>
65#include <private/qitemeditorfactory_p.h>
66#include <qmetaobject.h>
67#include <qtextlayout.h>
68#include <private/qabstractitemdelegate_p.h>
69#include <private/qtextengine_p.h>
70#include <private/qlayoutengine_p.h>
71#include <qdebug.h>
72#include <qlocale.h>
73#if QT_CONFIG(tableview)
74#include <qtableview.h>
75#endif
76
77#include <limits.h>
78
79QT_BEGIN_NAMESPACE
80
81class QStyledItemDelegatePrivate : public QAbstractItemDelegatePrivate
82{
83 Q_DECLARE_PUBLIC(QStyledItemDelegate)
84
85public:
86 QStyledItemDelegatePrivate() : factory(nullptr) { }
87
88 static const QWidget *widget(const QStyleOptionViewItem &option)
89 {
90 return option.widget;
91 }
92
93 const QItemEditorFactory *editorFactory() const
94 {
95 return factory ? factory : QItemEditorFactory::defaultFactory();
96 }
97
98 QItemEditorFactory *factory;
99};
100
101/*!
102 \class QStyledItemDelegate
103
104 \brief The QStyledItemDelegate class provides display and editing facilities for
105 data items from a model.
106
107 \ingroup model-view
108 \inmodule QtWidgets
109
110 \since 4.4
111
112 When displaying data from models in Qt item views, e.g., a
113 QTableView, the individual items are drawn by a delegate. Also,
114 when an item is edited, it provides an editor widget, which is
115 placed on top of the item view while editing takes place.
116 QStyledItemDelegate is the default delegate for all Qt item
117 views, and is installed upon them when they are created.
118
119 The QStyledItemDelegate class is one of the \l{Model/View Classes}
120 and is part of Qt's \l{Model/View Programming}{model/view
121 framework}. The delegate allows the display and editing of items
122 to be developed independently from the model and view.
123
124 The data of items in models are assigned an
125 \l{Qt::}{ItemDataRole}; each item can store a QVariant for each
126 role. QStyledItemDelegate implements display and editing for the
127 most common datatypes expected by users, including booleans,
128 integers, and strings.
129
130 The data will be drawn differently depending on which role they
131 have in the model. The following table describes the roles and the
132 data types the delegate can handle for each of them. It is often
133 sufficient to ensure that the model returns appropriate data for
134 each of the roles to determine the appearance of items in views.
135
136 \table
137 \header \li Role \li Accepted Types
138 \omit
139 \row \li \l Qt::AccessibleDescriptionRole \li QString
140 \row \li \l Qt::AccessibleTextRole \li QString
141 \endomit
142 \row \li \l Qt::BackgroundRole \li QBrush (\since 4.2)
143 \row \li \l Qt::BackgroundColorRole \li QColor (obsolete; use Qt::BackgroundRole instead)
144 \row \li \l Qt::CheckStateRole \li Qt::CheckState
145 \row \li \l Qt::DecorationRole \li QIcon, QPixmap, QImage and QColor
146 \row \li \l Qt::DisplayRole \li QString and types with a string representation
147 \row \li \l Qt::EditRole \li See QItemEditorFactory for details
148 \row \li \l Qt::FontRole \li QFont
149 \row \li \l Qt::SizeHintRole \li QSize
150 \omit
151 \row \li \l Qt::StatusTipRole \li
152 \endomit
153 \row \li \l Qt::TextAlignmentRole \li Qt::Alignment
154 \row \li \l Qt::ForegroundRole \li QBrush (\since 4.2)
155 \row \li \l Qt::TextColorRole \li QColor (obsolete; use Qt::ForegroundRole instead)
156 \omit
157 \row \li \l Qt::ToolTipRole
158 \row \li \l Qt::WhatsThisRole
159 \endomit
160 \endtable
161
162 Editors are created with a QItemEditorFactory; a default static
163 instance provided by QItemEditorFactory is installed on all item
164 delegates. You can set a custom factory using
165 setItemEditorFactory() or set a new default factory with
166 QItemEditorFactory::setDefaultFactory(). It is the data stored in
167 the item model with the \l{Qt::}{EditRole} that is edited. See the
168 QItemEditorFactory class for a more high-level introduction to
169 item editor factories. The \l{Color Editor Factory Example}{Color
170 Editor Factory} example shows how to create custom editors with a
171 factory.
172
173 \section1 Subclassing QStyledItemDelegate
174
175 If the delegate does not support painting of the data types you
176 need or you want to customize the drawing of items, you need to
177 subclass QStyledItemDelegate, and reimplement paint() and possibly
178 sizeHint(). The paint() function is called individually for each
179 item, and with sizeHint(), you can specify the hint for each
180 of them.
181
182 When reimplementing paint(), one would typically handle the
183 datatypes one would like to draw and use the superclass
184 implementation for other types.
185
186 The painting of check box indicators are performed by the current
187 style. The style also specifies the size and the bounding
188 rectangles in which to draw the data for the different data roles.
189 The bounding rectangle of the item itself is also calculated by
190 the style. When drawing already supported datatypes, it is
191 therefore a good idea to ask the style for these bounding
192 rectangles. The QStyle class description describes this in
193 more detail.
194
195 If you wish to change any of the bounding rectangles calculated by
196 the style or the painting of check box indicators, you can
197 subclass QStyle. Note, however, that the size of the items can
198 also be affected by reimplementing sizeHint().
199
200 It is possible for a custom delegate to provide editors
201 without the use of an editor item factory. In this case, the
202 following virtual functions must be reimplemented:
203
204 \list
205 \li createEditor() returns the widget used to change data from the model
206 and can be reimplemented to customize editing behavior.
207 \li setEditorData() provides the widget with data to manipulate.
208 \li updateEditorGeometry() ensures that the editor is displayed correctly
209 with respect to the item view.
210 \li setModelData() returns updated data to the model.
211 \endlist
212
213 The \l{Star Delegate Example}{Star Delegate} example creates
214 editors by reimplementing these methods.
215
216 \section1 QStyledItemDelegate vs. QItemDelegate
217
218 Since Qt 4.4, there are two delegate classes: QItemDelegate and
219 QStyledItemDelegate. However, the default delegate is QStyledItemDelegate.
220 These two classes are independent alternatives to painting and providing
221 editors for items in views. The difference between them is that
222 QStyledItemDelegate uses the current style to paint its items. We therefore
223 recommend using QStyledItemDelegate as the base class when implementing
224 custom delegates or when working with Qt style sheets. The code required
225 for either class should be equal unless the custom delegate needs to use
226 the style for drawing.
227
228 If you wish to customize the painting of item views, you should
229 implement a custom style. Please see the QStyle class
230 documentation for details.
231
232 \sa {Delegate Classes}, QItemDelegate, QAbstractItemDelegate, QStyle,
233 {Spin Box Delegate Example}, {Star Delegate Example}, {Color
234 Editor Factory Example}
235*/
236
237
238/*!
239 Constructs an item delegate with the given \a parent.
240*/
241QStyledItemDelegate::QStyledItemDelegate(QObject *parent)
242 : QAbstractItemDelegate(*new QStyledItemDelegatePrivate(), parent)
243{
244}
245
246/*!
247 Destroys the item delegate.
248*/
249QStyledItemDelegate::~QStyledItemDelegate()
250{
251}
252
253/*!
254 This function returns the string that the delegate will use to display the
255 Qt::DisplayRole of the model in \a locale. \a value is the value of the Qt::DisplayRole
256 provided by the model.
257
258 The default implementation uses the QLocale::toString to convert \a value into
259 a QString.
260
261 This function is not called for empty model indices, i.e., indices for which
262 the model returns an invalid QVariant.
263
264 \sa QAbstractItemModel::data()
265*/
266QString QStyledItemDelegate::displayText(const QVariant &value, const QLocale& locale) const
267{
268 return d_func()->textForRole(role: Qt::DisplayRole, value, locale);
269}
270
271/*!
272 Initialize \a option with the values using the index \a index. This method
273 is useful for subclasses when they need a QStyleOptionViewItem, but don't want
274 to fill in all the information themselves.
275
276 \sa QStyleOption::initFrom()
277*/
278void QStyledItemDelegate::initStyleOption(QStyleOptionViewItem *option,
279 const QModelIndex &index) const
280{
281 QVariant value = index.data(arole: Qt::FontRole);
282 if (value.isValid() && !value.isNull()) {
283 option->font = qvariant_cast<QFont>(v: value).resolve(option->font);
284 option->fontMetrics = QFontMetrics(option->font);
285 }
286
287 value = index.data(arole: Qt::TextAlignmentRole);
288 if (value.isValid() && !value.isNull())
289 option->displayAlignment = Qt::Alignment(value.toInt());
290
291 value = index.data(arole: Qt::ForegroundRole);
292 if (value.canConvert<QBrush>())
293 option->palette.setBrush(acr: QPalette::Text, abrush: qvariant_cast<QBrush>(v: value));
294
295 option->index = index;
296 value = index.data(arole: Qt::CheckStateRole);
297 if (value.isValid() && !value.isNull()) {
298 option->features |= QStyleOptionViewItem::HasCheckIndicator;
299 option->checkState = static_cast<Qt::CheckState>(value.toInt());
300 }
301
302 value = index.data(arole: Qt::DecorationRole);
303 if (value.isValid() && !value.isNull()) {
304 option->features |= QStyleOptionViewItem::HasDecoration;
305 switch (value.userType()) {
306 case QMetaType::QIcon: {
307 option->icon = qvariant_cast<QIcon>(v: value);
308 QIcon::Mode mode;
309 if (!(option->state & QStyle::State_Enabled))
310 mode = QIcon::Disabled;
311 else if (option->state & QStyle::State_Selected)
312 mode = QIcon::Selected;
313 else
314 mode = QIcon::Normal;
315 QIcon::State state = option->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
316 QSize actualSize = option->icon.actualSize(size: option->decorationSize, mode, state);
317 // For highdpi icons actualSize might be larger than decorationSize, which we don't want. Clamp it to decorationSize.
318 option->decorationSize = QSize(qMin(a: option->decorationSize.width(), b: actualSize.width()),
319 qMin(a: option->decorationSize.height(), b: actualSize.height()));
320 break;
321 }
322 case QMetaType::QColor: {
323 QPixmap pixmap(option->decorationSize);
324 pixmap.fill(fillColor: qvariant_cast<QColor>(v: value));
325 option->icon = QIcon(pixmap);
326 break;
327 }
328 case QMetaType::QImage: {
329 QImage image = qvariant_cast<QImage>(v: value);
330 option->icon = QIcon(QPixmap::fromImage(image));
331 option->decorationSize = image.size() / image.devicePixelRatio();
332 break;
333 }
334 case QMetaType::QPixmap: {
335 QPixmap pixmap = qvariant_cast<QPixmap>(v: value);
336 option->icon = QIcon(pixmap);
337 option->decorationSize = pixmap.size() / pixmap.devicePixelRatio();
338 break;
339 }
340 default:
341 break;
342 }
343 }
344
345 value = index.data(arole: Qt::DisplayRole);
346 if (value.isValid() && !value.isNull()) {
347 option->features |= QStyleOptionViewItem::HasDisplay;
348 option->text = displayText(value, locale: option->locale);
349 }
350
351 option->backgroundBrush = qvariant_cast<QBrush>(v: index.data(arole: Qt::BackgroundRole));
352
353 // disable style animations for checkboxes etc. within itemviews (QTBUG-30146)
354 option->styleObject = nullptr;
355}
356
357/*!
358 Renders the delegate using the given \a painter and style \a option for
359 the item specified by \a index.
360
361 This function paints the item using the view's QStyle.
362
363 When reimplementing paint in a subclass. Use the initStyleOption()
364 to set up the \a option in the same way as the
365 QStyledItemDelegate.
366
367 Whenever possible, use the \a option while painting.
368 Especially its \l{QStyleOption::}{rect} variable to decide
369 where to draw and its \l{QStyleOption::}{state} to determine
370 if it is enabled or selected.
371
372 After painting, you should ensure that the painter is returned to
373 the state it was supplied in when this function was called.
374 For example, it may be useful to call QPainter::save() before
375 painting and QPainter::restore() afterwards.
376
377 \sa QItemDelegate::paint(), QStyle::drawControl(), QStyle::CE_ItemViewItem
378*/
379void QStyledItemDelegate::paint(QPainter *painter,
380 const QStyleOptionViewItem &option, const QModelIndex &index) const
381{
382 Q_ASSERT(index.isValid());
383
384 QStyleOptionViewItem opt = option;
385 initStyleOption(option: &opt, index);
386
387 const QWidget *widget = QStyledItemDelegatePrivate::widget(option);
388 QStyle *style = widget ? widget->style() : QApplication::style();
389 style->drawControl(element: QStyle::CE_ItemViewItem, opt: &opt, p: painter, w: widget);
390}
391
392/*!
393 Returns the size needed by the delegate to display the item
394 specified by \a index, taking into account the style information
395 provided by \a option.
396
397 This function uses the view's QStyle to determine the size of the
398 item.
399
400 \sa QStyle::sizeFromContents(), QStyle::CT_ItemViewItem
401*/
402QSize QStyledItemDelegate::sizeHint(const QStyleOptionViewItem &option,
403 const QModelIndex &index) const
404{
405 QVariant value = index.data(arole: Qt::SizeHintRole);
406 if (value.isValid())
407 return qvariant_cast<QSize>(v: value);
408
409 QStyleOptionViewItem opt = option;
410 initStyleOption(option: &opt, index);
411 const QWidget *widget = QStyledItemDelegatePrivate::widget(option);
412 QStyle *style = widget ? widget->style() : QApplication::style();
413 return style->sizeFromContents(ct: QStyle::CT_ItemViewItem, opt: &opt, contentsSize: QSize(), w: widget);
414}
415
416/*!
417 Returns the widget used to edit the item specified by \a index
418 for editing. The \a parent widget and style \a option are used to
419 control how the editor widget appears.
420
421 \sa QAbstractItemDelegate::createEditor()
422*/
423QWidget *QStyledItemDelegate::createEditor(QWidget *parent,
424 const QStyleOptionViewItem &,
425 const QModelIndex &index) const
426{
427 Q_D(const QStyledItemDelegate);
428 if (!index.isValid())
429 return nullptr;
430 return d->editorFactory()->createEditor(userType: index.data(arole: Qt::EditRole).userType(), parent);
431}
432
433/*!
434 Sets the data to be displayed and edited by the \a editor from the
435 data model item specified by the model \a index.
436
437 The default implementation stores the data in the \a editor
438 widget's \l {Qt's Property System} {user property}.
439
440 \sa QMetaProperty::isUser()
441*/
442void QStyledItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
443{
444#ifdef QT_NO_PROPERTIES
445 Q_UNUSED(editor);
446 Q_UNUSED(index);
447#else
448 QVariant v = index.data(arole: Qt::EditRole);
449 QByteArray n = editor->metaObject()->userProperty().name();
450
451 if (!n.isEmpty()) {
452 if (!v.isValid())
453 v = QVariant(editor->property(name: n).userType(), (const void *)nullptr);
454 editor->setProperty(name: n, value: v);
455 }
456#endif
457}
458
459/*!
460 Gets data from the \a editor widget and stores it in the specified
461 \a model at the item \a index.
462
463 The default implementation gets the value to be stored in the data
464 model from the \a editor widget's \l {Qt's Property System} {user
465 property}.
466
467 \sa QMetaProperty::isUser()
468*/
469void QStyledItemDelegate::setModelData(QWidget *editor,
470 QAbstractItemModel *model,
471 const QModelIndex &index) const
472{
473#ifdef QT_NO_PROPERTIES
474 Q_UNUSED(model);
475 Q_UNUSED(editor);
476 Q_UNUSED(index);
477#else
478 Q_D(const QStyledItemDelegate);
479 Q_ASSERT(model);
480 Q_ASSERT(editor);
481 QByteArray n = editor->metaObject()->userProperty().name();
482 if (n.isEmpty())
483 n = d->editorFactory()->valuePropertyName(
484 userType: model->data(index, role: Qt::EditRole).userType());
485 if (!n.isEmpty())
486 model->setData(index, value: editor->property(name: n), role: Qt::EditRole);
487#endif
488}
489
490/*!
491 Updates the \a editor for the item specified by \a index
492 according to the style \a option given.
493*/
494void QStyledItemDelegate::updateEditorGeometry(QWidget *editor,
495 const QStyleOptionViewItem &option,
496 const QModelIndex &index) const
497{
498 if (!editor)
499 return;
500 Q_ASSERT(index.isValid());
501 const QWidget *widget = QStyledItemDelegatePrivate::widget(option);
502
503 QStyleOptionViewItem opt = option;
504 initStyleOption(option: &opt, index);
505 // let the editor take up all available space
506 //if the editor is not a QLineEdit
507 //or it is in a QTableView
508#if QT_CONFIG(tableview) && QT_CONFIG(lineedit)
509 if (qobject_cast<QExpandingLineEdit*>(object: editor) && !qobject_cast<const QTableView*>(object: widget))
510 opt.showDecorationSelected = editor->style()->styleHint(stylehint: QStyle::SH_ItemView_ShowDecorationSelected, opt: nullptr, widget: editor);
511 else
512#endif
513 opt.showDecorationSelected = true;
514
515 QStyle *style = widget ? widget->style() : QApplication::style();
516 QRect geom = style->subElementRect(subElement: QStyle::SE_ItemViewItemText, option: &opt, widget);
517 editor->setGeometry(geom);
518}
519
520/*!
521 Returns the editor factory used by the item delegate.
522 If no editor factory is set, the function will return null.
523
524 \sa setItemEditorFactory()
525*/
526QItemEditorFactory *QStyledItemDelegate::itemEditorFactory() const
527{
528 Q_D(const QStyledItemDelegate);
529 return d->factory;
530}
531
532/*!
533 Sets the editor factory to be used by the item delegate to be the \a factory
534 specified. If no editor factory is set, the item delegate will use the
535 default editor factory.
536
537 \sa itemEditorFactory()
538*/
539void QStyledItemDelegate::setItemEditorFactory(QItemEditorFactory *factory)
540{
541 Q_D(QStyledItemDelegate);
542 d->factory = factory;
543}
544
545
546/*!
547 \fn bool QStyledItemDelegate::eventFilter(QObject *editor, QEvent *event)
548
549 Returns \c true if the given \a editor is a valid QWidget and the
550 given \a event is handled; otherwise returns \c false. The following
551 key press events are handled by default:
552
553 \list
554 \li \uicontrol Tab
555 \li \uicontrol Backtab
556 \li \uicontrol Enter
557 \li \uicontrol Return
558 \li \uicontrol Esc
559 \endlist
560
561 If the \a editor's type is QTextEdit or QPlainTextEdit then \uicontrol Enter and
562 \uicontrol Return keys are \e not handled.
563
564 In the case of \uicontrol Tab, \uicontrol Backtab, \uicontrol Enter and \uicontrol Return
565 key press events, the \a editor's data is committed to the model
566 and the editor is closed. If the \a event is a \uicontrol Tab key press
567 the view will open an editor on the next item in the
568 view. Likewise, if the \a event is a \uicontrol Backtab key press the
569 view will open an editor on the \e previous item in the view.
570
571 If the event is a \uicontrol Esc key press event, the \a editor is
572 closed \e without committing its data.
573
574 \sa commitData(), closeEditor()
575*/
576bool QStyledItemDelegate::eventFilter(QObject *object, QEvent *event)
577{
578 Q_D(QStyledItemDelegate);
579 return d->editorEventFilter(object, event);
580}
581
582/*!
583 \reimp
584*/
585bool QStyledItemDelegate::editorEvent(QEvent *event,
586 QAbstractItemModel *model,
587 const QStyleOptionViewItem &option,
588 const QModelIndex &index)
589{
590 Q_ASSERT(event);
591 Q_ASSERT(model);
592
593 // make sure that the item is checkable
594 Qt::ItemFlags flags = model->flags(index);
595 if (!(flags & Qt::ItemIsUserCheckable) || !(option.state & QStyle::State_Enabled)
596 || !(flags & Qt::ItemIsEnabled))
597 return false;
598
599 // make sure that we have a check state
600 QVariant value = index.data(arole: Qt::CheckStateRole);
601 if (!value.isValid())
602 return false;
603
604 const QWidget *widget = QStyledItemDelegatePrivate::widget(option);
605 QStyle *style = widget ? widget->style() : QApplication::style();
606
607 // make sure that we have the right event type
608 if ((event->type() == QEvent::MouseButtonRelease)
609 || (event->type() == QEvent::MouseButtonDblClick)
610 || (event->type() == QEvent::MouseButtonPress)) {
611 QStyleOptionViewItem viewOpt(option);
612 initStyleOption(option: &viewOpt, index);
613 QRect checkRect = style->subElementRect(subElement: QStyle::SE_ItemViewItemCheckIndicator, option: &viewOpt, widget);
614 QMouseEvent *me = static_cast<QMouseEvent*>(event);
615 if (me->button() != Qt::LeftButton || !checkRect.contains(p: me->pos()))
616 return false;
617
618 if ((event->type() == QEvent::MouseButtonPress)
619 || (event->type() == QEvent::MouseButtonDblClick))
620 return true;
621
622 } else if (event->type() == QEvent::KeyPress) {
623 if (static_cast<QKeyEvent*>(event)->key() != Qt::Key_Space
624 && static_cast<QKeyEvent*>(event)->key() != Qt::Key_Select)
625 return false;
626 } else {
627 return false;
628 }
629
630 Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
631 if (flags & Qt::ItemIsUserTristate)
632 state = ((Qt::CheckState)((state + 1) % 3));
633 else
634 state = (state == Qt::Checked) ? Qt::Unchecked : Qt::Checked;
635 return model->setData(index, value: state, role: Qt::CheckStateRole);
636}
637
638QT_END_NAMESPACE
639
640#include "moc_qstyleditemdelegate.cpp"
641

source code of qtbase/src/widgets/itemviews/qstyleditemdelegate.cpp