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 "qabstractitemdelegate.h"
41
42 #include <qabstractitemmodel.h>
43 #include <qabstractitemview.h>
44 #include <qfontmetrics.h>
45 #if QT_CONFIG(whatsthis)
46 #include <qwhatsthis.h>
47 #endif
48 #include <qtooltip.h>
49 #include <qevent.h>
50 #include <qstring.h>
51 #include <qdebug.h>
52 #if QT_CONFIG(lineedit)
53 #include <qlineedit.h>
54 #endif
55 #if QT_CONFIG(textedit)
56 #include <qtextedit.h>
57 #include <qplaintextedit.h>
58 #endif
59 #include <qapplication.h>
60 #include <qvalidator.h>
61 #include <qjsonvalue.h>
62 #include <private/qtextengine_p.h>
63 #include <private/qabstractitemdelegate_p.h>
64
65 #include <qpa/qplatformintegration.h>
66 #if QT_CONFIG(draganddrop)
67 #include <qpa/qplatformdrag.h>
68 #include <private/qdnd_p.h>
69 #endif
70 #include <private/qguiapplication_p.h>
71
72 QT_BEGIN_NAMESPACE
73
74 /*!
75 \class QAbstractItemDelegate
76
77 \brief The QAbstractItemDelegate class is used to display and edit
78 data items from a model.
79
80 \ingroup model-view
81 \inmodule QtWidgets
82
83 A QAbstractItemDelegate provides the interface and common functionality
84 for delegates in the model/view architecture. Delegates display
85 individual items in views, and handle the editing of model data.
86
87 The QAbstractItemDelegate class is one of the \l{Model/View Classes}
88 and is part of Qt's \l{Model/View Programming}{model/view framework}.
89
90 To render an item in a custom way, you must implement paint() and
91 sizeHint(). The QStyledItemDelegate class provides default implementations for
92 these functions; if you do not need custom rendering, subclass that
93 class instead.
94
95 We give an example of drawing a progress bar in items; in our case
96 for a package management program.
97
98 \image widgetdelegate.png
99
100 We create the \c WidgetDelegate class, which inherits from
101 QStyledItemDelegate. We do the drawing in the paint() function:
102
103 \snippet widgetdelegate.cpp 0
104
105 Notice that we use a QStyleOptionProgressBar and initialize its
106 members. We can then use the current QStyle to draw it.
107
108 To provide custom editing, there are two approaches that can be
109 used. The first approach is to create an editor widget and display
110 it directly on top of the item. To do this you must reimplement
111 createEditor() to provide an editor widget, setEditorData() to populate
112 the editor with the data from the model, and setModelData() so that the
113 delegate can update the model with data from the editor.
114
115 The second approach is to handle user events directly by reimplementing
116 editorEvent().
117
118 \sa {model-view-programming}{Model/View Programming}, QStyledItemDelegate,
119 {Pixelator Example}, QStyledItemDelegate, QStyle
120 */
121
122 /*!
123 \enum QAbstractItemDelegate::EndEditHint
124
125 This enum describes the different hints that the delegate can give to the
126 model and view components to make editing data in a model a comfortable
127 experience for the user.
128
129 \value NoHint There is no recommended action to be performed.
130
131 These hints let the delegate influence the behavior of the view:
132
133 \value EditNextItem The view should use the delegate to open an
134 editor on the next item in the view.
135 \value EditPreviousItem The view should use the delegate to open an
136 editor on the previous item in the view.
137
138 Note that custom views may interpret the concepts of next and previous
139 differently.
140
141 The following hints are most useful when models are used that cache
142 data, such as those that manipulate data locally in order to increase
143 performance or conserve network bandwidth.
144
145 \value SubmitModelCache If the model caches data, it should write out
146 cached data to the underlying data store.
147 \value RevertModelCache If the model caches data, it should discard
148 cached data and replace it with data from the
149 underlying data store.
150
151 Although models and views should respond to these hints in appropriate
152 ways, custom components may ignore any or all of them if they are not
153 relevant.
154 */
155
156 /*!
157 \fn void QAbstractItemDelegate::commitData(QWidget *editor)
158
159 This signal must be emitted when the \a editor widget has completed
160 editing the data, and wants to write it back into the model.
161 */
162
163 /*!
164 \fn void QAbstractItemDelegate::closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint)
165
166 This signal is emitted when the user has finished editing an item using
167 the specified \a editor.
168
169 The \a hint provides a way for the delegate to influence how the model and
170 view behave after editing is completed. It indicates to these components
171 what action should be performed next to provide a comfortable editing
172 experience for the user. For example, if \c EditNextItem is specified,
173 the view should use a delegate to open an editor on the next item in the
174 model.
175
176 \sa EndEditHint
177 */
178
179 /*!
180 \fn void QAbstractItemDelegate::sizeHintChanged(const QModelIndex &index)
181 \since 4.4
182
183 This signal must be emitted when the sizeHint() of \a index changed.
184
185 Views automatically connect to this signal and relayout items as necessary.
186 */
187
188
189 /*!
190 Creates a new abstract item delegate with the given \a parent.
191 */
QAbstractItemDelegate(QObject * parent)192 QAbstractItemDelegate::QAbstractItemDelegate(QObject *parent)
193 : QObject(*new QAbstractItemDelegatePrivate, parent)
194 {
195
196 }
197
198 /*!
199 \internal
200
201 Creates a new abstract item delegate with the given \a parent.
202 */
QAbstractItemDelegate(QObjectPrivate & dd,QObject * parent)203 QAbstractItemDelegate::QAbstractItemDelegate(QObjectPrivate &dd, QObject *parent)
204 : QObject(dd, parent)
205 {
206
207 }
208
209 /*!
210 Destroys the abstract item delegate.
211 */
~QAbstractItemDelegate()212 QAbstractItemDelegate::~QAbstractItemDelegate()
213 {
214
215 }
216
217 /*!
218 \fn void QAbstractItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const = 0;
219
220 This pure abstract function must be reimplemented if you want to
221 provide custom rendering. Use the \a painter and style \a option to
222 render the item specified by the item \a index.
223
224 If you reimplement this you must also reimplement sizeHint().
225 */
226
227 /*!
228 \fn QSize QAbstractItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const = 0
229
230 This pure abstract function must be reimplemented if you want to
231 provide custom rendering. The options are specified by \a option
232 and the model item by \a index.
233
234 If you reimplement this you must also reimplement paint().
235 */
236
237 /*!
238 Returns the editor to be used for editing the data item with the
239 given \a index. Note that the index contains information about the
240 model being used. The editor's parent widget is specified by \a parent,
241 and the item options by \a option.
242
243 The base implementation returns \nullptr. If you want custom editing you
244 will need to reimplement this function.
245
246 The returned editor widget should have Qt::StrongFocus;
247 otherwise, \l{QMouseEvent}s received by the widget will propagate
248 to the view. The view's background will shine through unless the
249 editor paints its own background (e.g., with
250 \l{QWidget::}{setAutoFillBackground()}).
251
252 \sa destroyEditor(), setModelData(), setEditorData()
253 */
createEditor(QWidget *,const QStyleOptionViewItem &,const QModelIndex &) const254 QWidget *QAbstractItemDelegate::createEditor(QWidget *,
255 const QStyleOptionViewItem &,
256 const QModelIndex &) const
257 {
258 return nullptr;
259 }
260
261
262 /*!
263 Called when the \a editor is no longer needed for editing the data item
264 with the given \a index and should be destroyed. The default behavior is a
265 call to deleteLater on the editor. It is possible e.g. to avoid this delete by
266 reimplementing this function.
267
268 \since 5.0
269 \sa createEditor()
270 */
destroyEditor(QWidget * editor,const QModelIndex & index) const271 void QAbstractItemDelegate::destroyEditor(QWidget *editor, const QModelIndex &index) const
272 {
273 Q_UNUSED(index);
274 editor->deleteLater();
275 }
276
277 /*!
278 Sets the contents of the given \a editor to the data for the item
279 at the given \a index. Note that the index contains information
280 about the model being used.
281
282 The base implementation does nothing. If you want custom editing
283 you will need to reimplement this function.
284
285 \sa setModelData()
286 */
setEditorData(QWidget *,const QModelIndex &) const287 void QAbstractItemDelegate::setEditorData(QWidget *,
288 const QModelIndex &) const
289 {
290 // do nothing
291 }
292
293 /*!
294 Sets the data for the item at the given \a index in the \a model
295 to the contents of the given \a editor.
296
297 The base implementation does nothing. If you want custom editing
298 you will need to reimplement this function.
299
300 \sa setEditorData()
301 */
setModelData(QWidget *,QAbstractItemModel *,const QModelIndex &) const302 void QAbstractItemDelegate::setModelData(QWidget *,
303 QAbstractItemModel *,
304 const QModelIndex &) const
305 {
306 // do nothing
307 }
308
309 /*!
310 Updates the geometry of the \a editor for the item with the given
311 \a index, according to the rectangle specified in the \a option.
312 If the item has an internal layout, the editor will be laid out
313 accordingly. Note that the index contains information about the
314 model being used.
315
316 The base implementation does nothing. If you want custom editing
317 you must reimplement this function.
318 */
updateEditorGeometry(QWidget *,const QStyleOptionViewItem &,const QModelIndex &) const319 void QAbstractItemDelegate::updateEditorGeometry(QWidget *,
320 const QStyleOptionViewItem &,
321 const QModelIndex &) const
322 {
323 // do nothing
324 }
325
326 /*!
327 When editing of an item starts, this function is called with the
328 \a event that triggered the editing, the \a model, the \a index of
329 the item, and the \a option used for rendering the item.
330
331 Mouse events are sent to editorEvent() even if they don't start
332 editing of the item. This can, for instance, be useful if you wish
333 to open a context menu when the right mouse button is pressed on
334 an item.
335
336 The base implementation returns \c false (indicating that it has not
337 handled the event).
338 */
editorEvent(QEvent *,QAbstractItemModel *,const QStyleOptionViewItem &,const QModelIndex &)339 bool QAbstractItemDelegate::editorEvent(QEvent *,
340 QAbstractItemModel *,
341 const QStyleOptionViewItem &,
342 const QModelIndex &)
343 {
344 // do nothing
345 return false;
346 }
347
348 #if QT_DEPRECATED_SINCE(5, 13)
349 /*!
350 \obsolete
351
352 Use QFontMetrics::elidedText() instead.
353
354 \oldcode
355 QFontMetrics fm = ...
356 QString str = QAbstractItemDelegate::elidedText(fm, width, mode, text);
357 \newcode
358 QFontMetrics fm = ...
359 QString str = fm.elidedText(text, mode, width);
360 \endcode
361 */
362
elidedText(const QFontMetrics & fontMetrics,int width,Qt::TextElideMode mode,const QString & text)363 QString QAbstractItemDelegate::elidedText(const QFontMetrics &fontMetrics, int width,
364 Qt::TextElideMode mode, const QString &text)
365 {
366 return fontMetrics.elidedText(text, mode, width);
367 }
368 #endif
369
370 /*!
371 \since 4.3
372 Whenever a help event occurs, this function is called with the \a event
373 \a view \a option and the \a index that corresponds to the item where the
374 event occurs.
375
376 Returns \c true if the delegate can handle the event; otherwise returns \c false.
377 A return value of true indicates that the data obtained using the index had
378 the required role.
379
380 For QEvent::ToolTip and QEvent::WhatsThis events that were handled successfully,
381 the relevant popup may be shown depending on the user's system configuration.
382
383 \sa QHelpEvent
384 */
helpEvent(QHelpEvent * event,QAbstractItemView * view,const QStyleOptionViewItem & option,const QModelIndex & index)385 bool QAbstractItemDelegate::helpEvent(QHelpEvent *event,
386 QAbstractItemView *view,
387 const QStyleOptionViewItem &option,
388 const QModelIndex &index)
389 {
390 if (!event || !view)
391 return false;
392 Q_D(QAbstractItemDelegate);
393 switch (event->type()) {
394 #ifndef QT_NO_TOOLTIP
395 case QEvent::ToolTip: {
396 QHelpEvent *he = static_cast<QHelpEvent*>(event);
397 const int precision = inherits("QItemDelegate") ? 10 : 6; // keep in sync with DBL_DIG in qitemdelegate.cpp
398 const QString tooltip = index.isValid() ?
399 d->textForRole(Qt::ToolTipRole, index.data(Qt::ToolTipRole), option.locale, precision) :
400 QString();
401 QRect rect;
402 if (index.isValid()) {
403 const QRect r = view->visualRect(index);
404 rect = QRect(view->mapToGlobal(r.topLeft()), r.size());
405 }
406 QToolTip::showText(he->globalPos(), tooltip, view, rect);
407 event->setAccepted(!tooltip.isEmpty());
408 break;
409 }
410 #endif
411 #if QT_CONFIG(whatsthis)
412 case QEvent::QueryWhatsThis:
413 event->setAccepted(index.data(Qt::WhatsThisRole).isValid());
414 break;
415 case QEvent::WhatsThis: {
416 QHelpEvent *he = static_cast<QHelpEvent*>(event);
417 const int precision = inherits("QItemDelegate") ? 10 : 6; // keep in sync with DBL_DIG in qitemdelegate.cpp
418 const QString whatsthis = index.isValid() ?
419 d->textForRole(Qt::WhatsThisRole, index.data(Qt::WhatsThisRole), option.locale, precision) :
420 QString();
421 QWhatsThis::showText(he->globalPos(), whatsthis, view);
422 event->setAccepted(!whatsthis.isEmpty());
423 break;
424 }
425 #endif
426 default:
427 break;
428 }
429 return event->isAccepted();
430 }
431
432 /*!
433 \internal
434
435 This virtual method is reserved and will be used in Qt 5.1.
436 */
paintingRoles() const437 QVector<int> QAbstractItemDelegate::paintingRoles() const
438 {
439 return QVector<int>();
440 }
441
QAbstractItemDelegatePrivate()442 QAbstractItemDelegatePrivate::QAbstractItemDelegatePrivate()
443 : QObjectPrivate()
444 {
445 }
446
editorHandlesKeyEvent(QWidget * editor,const QKeyEvent * event)447 static bool editorHandlesKeyEvent(QWidget *editor, const QKeyEvent *event)
448 {
449 #if QT_CONFIG(textedit)
450 // do not filter enter / return / tab / backtab for QTextEdit or QPlainTextEdit
451 if (qobject_cast<QTextEdit *>(editor) || qobject_cast<QPlainTextEdit *>(editor)) {
452 switch (event->key()) {
453 case Qt::Key_Tab:
454 case Qt::Key_Backtab:
455 case Qt::Key_Enter:
456 case Qt::Key_Return:
457 return true;
458
459 default:
460 break;
461 }
462 }
463 #endif // QT_CONFIG(textedit)
464
465 Q_UNUSED(editor);
466 Q_UNUSED(event);
467 return false;
468 }
469
editorEventFilter(QObject * object,QEvent * event)470 bool QAbstractItemDelegatePrivate::editorEventFilter(QObject *object, QEvent *event)
471 {
472 Q_Q(QAbstractItemDelegate);
473
474 QWidget *editor = qobject_cast<QWidget*>(object);
475 if (!editor)
476 return false;
477 if (event->type() == QEvent::KeyPress) {
478 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
479 if (editorHandlesKeyEvent(editor, keyEvent))
480 return false;
481
482 #ifndef QT_NO_SHORTCUT
483 if (keyEvent->matches(QKeySequence::Cancel)) {
484 // don't commit data
485 emit q->closeEditor(editor, QAbstractItemDelegate::RevertModelCache);
486 return true;
487 }
488 #endif
489
490 switch (keyEvent->key()) {
491 case Qt::Key_Tab:
492 if (tryFixup(editor)) {
493 emit q->commitData(editor);
494 emit q->closeEditor(editor, QAbstractItemDelegate::EditNextItem);
495 }
496 return true;
497 case Qt::Key_Backtab:
498 if (tryFixup(editor)) {
499 emit q->commitData(editor);
500 emit q->closeEditor(editor, QAbstractItemDelegate::EditPreviousItem);
501 }
502 return true;
503 case Qt::Key_Enter:
504 case Qt::Key_Return:
505 // We want the editor to be able to process the key press
506 // before committing the data (e.g. so it can do
507 // validation/fixup of the input).
508 if (!tryFixup(editor))
509 return true;
510
511 QMetaObject::invokeMethod(q, "_q_commitDataAndCloseEditor",
512 Qt::QueuedConnection, Q_ARG(QWidget*, editor));
513 return false;
514 default:
515 return false;
516 }
517 } else if (event->type() == QEvent::FocusOut || (event->type() == QEvent::Hide && editor->isWindow())) {
518 //the Hide event will take care of he editors that are in fact complete dialogs
519 if (!editor->isActiveWindow() || (QApplication::focusWidget() != editor)) {
520 QWidget *w = QApplication::focusWidget();
521 while (w) { // don't worry about focus changes internally in the editor
522 if (w == editor)
523 return false;
524 w = w->parentWidget();
525 }
526 #if QT_CONFIG(draganddrop)
527 // The window may lose focus during an drag operation.
528 // i.e when dragging involves the taskbar on Windows.
529 QPlatformDrag *platformDrag = QGuiApplicationPrivate::instance()->platformIntegration()->drag();
530 if (platformDrag && platformDrag->currentDrag()) {
531 return false;
532 }
533 #endif
534 if (tryFixup(editor))
535 emit q->commitData(editor);
536
537 // If the application loses focus while editing, then the focus needs to go back
538 // to the itemview when the editor closes. This ensures that when the application
539 // is active again it will have the focus on the itemview as expected.
540 const bool manuallyFixFocus = (event->type() == QEvent::FocusOut) && !editor->hasFocus() &&
541 editor->parentWidget() &&
542 (static_cast<QFocusEvent *>(event)->reason() == Qt::ActiveWindowFocusReason);
543 emit q->closeEditor(editor, QAbstractItemDelegate::NoHint);
544 if (manuallyFixFocus)
545 editor->parentWidget()->setFocus();
546 }
547 #ifndef QT_NO_SHORTCUT
548 } else if (event->type() == QEvent::ShortcutOverride) {
549 if (static_cast<QKeyEvent*>(event)->matches(QKeySequence::Cancel)) {
550 event->accept();
551 return true;
552 }
553 #endif
554 }
555 return false;
556 }
557
tryFixup(QWidget * editor)558 bool QAbstractItemDelegatePrivate::tryFixup(QWidget *editor)
559 {
560 #if QT_CONFIG(lineedit)
561 if (QLineEdit *e = qobject_cast<QLineEdit*>(editor)) {
562 if (!e->hasAcceptableInput()) {
563 #if QT_CONFIG(validator)
564 if (const QValidator *validator = e->validator()) {
565 QString text = e->text();
566 validator->fixup(text);
567 e->setText(text);
568 }
569 #endif
570 return e->hasAcceptableInput();
571 }
572 }
573 #else
574 Q_UNUSED(editor)
575 #endif // QT_CONFIG(lineedit)
576
577 return true;
578 }
579
textForRole(Qt::ItemDataRole role,const QVariant & value,const QLocale & locale,int precision) const580 QString QAbstractItemDelegatePrivate::textForRole(Qt::ItemDataRole role, const QVariant &value, const QLocale &locale, int precision) const
581 {
582 const QLocale::FormatType formatType = (role == Qt::DisplayRole) ? QLocale::ShortFormat : QLocale::LongFormat;
583 QString text;
584 switch (value.userType()) {
585 case QMetaType::Float:
586 text = locale.toString(value.toFloat());
587 break;
588 case QMetaType::Double:
589 text = locale.toString(value.toDouble(), 'g', precision);
590 break;
591 case QMetaType::Int:
592 case QMetaType::LongLong:
593 text = locale.toString(value.toLongLong());
594 break;
595 case QMetaType::UInt:
596 case QMetaType::ULongLong:
597 text = locale.toString(value.toULongLong());
598 break;
599 case QMetaType::QDate:
600 text = locale.toString(value.toDate(), formatType);
601 break;
602 case QMetaType::QTime:
603 text = locale.toString(value.toTime(), formatType);
604 break;
605 case QMetaType::QDateTime:
606 text = locale.toString(value.toDateTime(), formatType);
607 break;
608 case QMetaType::QJsonValue: {
609 const QJsonValue val = value.toJsonValue();
610 if (val.isBool()) {
611 text = QVariant(val.toBool()).toString();
612 break;
613 }
614 if (val.isDouble()) {
615 text = locale.toString(val.toDouble(), 'g', precision);
616 break;
617 }
618 // val is a string (or null) here
619 Q_FALLTHROUGH();
620 }
621 default: {
622 text = value.toString();
623 if (role == Qt::DisplayRole)
624 text.replace(QLatin1Char('\n'), QChar::LineSeparator);
625 break;
626 }
627 }
628 return text;
629 }
630
_q_commitDataAndCloseEditor(QWidget * editor)631 void QAbstractItemDelegatePrivate::_q_commitDataAndCloseEditor(QWidget *editor)
632 {
633 Q_Q(QAbstractItemDelegate);
634 emit q->commitData(editor);
635 emit q->closeEditor(editor, QAbstractItemDelegate::SubmitModelCache);
636 }
637
638 QT_END_NAMESPACE
639
640 #include "moc_qabstractitemdelegate.cpp"
641