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 | |
79 | QT_BEGIN_NAMESPACE |
80 | |
81 | class QStyledItemDelegatePrivate : public QAbstractItemDelegatePrivate |
82 | { |
83 | Q_DECLARE_PUBLIC(QStyledItemDelegate) |
84 | |
85 | public: |
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 | */ |
241 | QStyledItemDelegate::QStyledItemDelegate(QObject *parent) |
242 | : QAbstractItemDelegate(*new QStyledItemDelegatePrivate(), parent) |
243 | { |
244 | } |
245 | |
246 | /*! |
247 | Destroys the item delegate. |
248 | */ |
249 | QStyledItemDelegate::~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 | */ |
266 | QString 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 | */ |
278 | void 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 | */ |
379 | void 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 | */ |
402 | QSize 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 | */ |
423 | QWidget *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 | */ |
442 | void 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 | */ |
469 | void 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 | */ |
494 | void 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 | */ |
526 | QItemEditorFactory *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 | */ |
539 | void 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 | */ |
576 | bool QStyledItemDelegate::eventFilter(QObject *object, QEvent *event) |
577 | { |
578 | Q_D(QStyledItemDelegate); |
579 | return d->editorEventFilter(object, event); |
580 | } |
581 | |
582 | /*! |
583 | \reimp |
584 | */ |
585 | bool 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 | |
638 | QT_END_NAMESPACE |
639 | |
640 | #include "moc_qstyleditemdelegate.cpp" |
641 | |