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