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