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