source: trunk/src/gui/itemviews/qstyleditemdelegate.cpp@ 106

Last change on this file since 106 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 28.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qstyleditemdelegate.h"
43
44#ifndef QT_NO_ITEMVIEWS
45#include <qabstractitemmodel.h>
46#include <qapplication.h>
47#include <qbrush.h>
48#include <qlineedit.h>
49#include <qtextedit.h>
50#include <qpainter.h>
51#include <qpalette.h>
52#include <qpoint.h>
53#include <qrect.h>
54#include <qsize.h>
55#include <qstyle.h>
56#include <qdatetime.h>
57#include <qstyleoption.h>
58#include <qevent.h>
59#include <qpixmap.h>
60#include <qbitmap.h>
61#include <qpixmapcache.h>
62#include <qitemeditorfactory.h>
63#include <private/qitemeditorfactory_p.h>
64#include <qmetaobject.h>
65#include <qtextlayout.h>
66#include <private/qobject_p.h>
67#include <private/qdnd_p.h>
68#include <private/qtextengine_p.h>
69#include <private/qlayoutengine_p.h>
70#include <qdebug.h>
71#include <qlocale.h>
72#include <qdialog.h>
73#include <qtableview.h>
74
75#include <limits.h>
76
77QT_BEGIN_NAMESPACE
78
79class QStyledItemDelegatePrivate : public QObjectPrivate
80{
81 Q_DECLARE_PUBLIC(QStyledItemDelegate)
82
83public:
84 QStyledItemDelegatePrivate() : factory(0) { }
85
86 static const QWidget *widget(const QStyleOptionViewItem &option)
87 {
88 if (const QStyleOptionViewItemV3 *v3 = qstyleoption_cast<const QStyleOptionViewItemV3 *>(&option))
89 return v3->widget;
90 return 0;
91 }
92
93 const QItemEditorFactory *editorFactory() const
94 {
95 return factory ? factory : QItemEditorFactory::defaultFactory();
96 }
97
98 void _q_commitDataAndCloseEditor(QWidget *editor)
99 {
100 Q_Q(QStyledItemDelegate);
101 emit q->commitData(editor);
102 emit q->closeEditor(editor, QAbstractItemDelegate::SubmitModelCache);
103 }
104 QItemEditorFactory *factory;
105};
106
107/*!
108 \class QStyledItemDelegate
109
110 \brief The QStyledItemDelegate class provides display and editing facilities for
111 data items from a model.
112
113 \ingroup model-view
114 \mainclass
115 \since 4.4
116
117 When displaying data from models in Qt item views, e.g., a
118 QTableView, the individual items are drawn by a delegate. Also,
119 when an item is edited, it provides an editor widget, which is
120 placed on top of the item view while editing takes place.
121 QStyledItemDelegate is the default delegate for all Qt item
122 views, and is installed upon them when they are created.
123
124 The QStyledItemDelegate class is one of the \l{Model/View Classes}
125 and is part of Qt's \l{Model/View Programming}{model/view
126 framework}. The delegate allows the display and editing of items
127 to be developed independently from the model and view.
128
129 The data of items in models are assigned an
130 \l{Qt::}{ItemDataRole}; each item can store a QVariant for each
131 role. QStyledItemDelegate implements display and editing for the
132 most common datatypes expected by users, including booleans,
133 integers, and strings.
134
135 The data will be drawn differently depending on which role they
136 have in the model. The following table describes the roles and the
137 data types the delegate can handle for each of them. It is often
138 sufficient to ensure that the model returns appropriate data for
139 each of the roles to determine the appearance of items in views.
140
141 \table
142 \header \o Role \o Accepted Types
143 \omit
144 \row \o \l Qt::AccessibleDescriptionRole \o QString
145 \row \o \l Qt::AccessibleTextRole \o QString
146 \endomit
147 \row \o \l Qt::BackgroundRole \o QBrush
148 \row \o \l Qt::BackgroundColorRole \o QColor (obsolete; use Qt::BackgroundRole instead)
149 \row \o \l Qt::CheckStateRole \o Qt::CheckState
150 \row \o \l Qt::DecorationRole \o QIcon and QColor
151 \row \o \l Qt::DisplayRole \o QString and types with a string representation
152 \row \o \l Qt::EditRole \o See QItemEditorFactory for details
153 \row \o \l Qt::FontRole \o QFont
154 \row \o \l Qt::SizeHintRole \o QSize
155 \omit
156 \row \o \l Qt::StatusTipRole \o
157 \endomit
158 \row \o \l Qt::TextAlignmentRole \o Qt::Alignment
159 \row \o \l Qt::ForegroundRole \o QBrush
160 \row \o \l Qt::TextColorRole \o QColor (obsolete; use Qt::ForegroundRole instead)
161 \omit
162 \row \o \l Qt::ToolTipRole
163 \row \o \l Qt::WhatsThisRole
164 \endomit
165 \endtable
166
167 Editors are created with a QItemEditorFactory; a default static
168 instance provided by QItemEditorFactory is installed on all item
169 delegates. You can set a custom factory using
170 setItemEditorFactory() or set a new default factory with
171 QItemEditorFactory::setDefaultFactory(). It is the data stored in
172 the item model with the \l{Qt::}{EditRole} that is edited. See the
173 QItemEditorFactory class for a more high-level introduction to
174 item editor factories. The \l{Color Editor Factory Example}{Color
175 Editor Factory} example shows how to create custom editors with a
176 factory.
177
178 \section1 Subclassing QStyledItemDelegate
179
180 If the delegate does not support painting of the data types you
181 need or you want to customize the drawing of items, you need to
182 subclass QStyledItemDelegate, and reimplement paint() and possibly
183 sizeHint(). The paint() function is called individually for each
184 item, and with sizeHint(), you can specify the hint for each
185 of them.
186
187 When reimplementing paint(), one would typically handle the
188 datatypes one would like to draw and use the superclass
189 implementation for other types.
190
191 The painting of check box indicators are performed by the current
192 style. The style also specifies the size and the bounding
193 rectangles in which to draw the data for the different data roles.
194 The bounding rectangle of the item itself is also calculated by
195 the style. When drawing already supported datatypes, it is
196 therefore a good idea to ask the style for these bounding
197 rectangles. The QStyle class description describes this in
198 more detail.
199
200 If you wish to change any of the bounding rectangles calculated by
201 the style or the painting of check box indicators, you can
202 subclass QStyle. Note, however, that the size of the items can
203 also be affected by reimplementing sizeHint().
204
205 It is possible for a custom delegate to provide editors
206 without the use of an editor item factory. In this case, the
207 following virtual functions must be reimplemented:
208
209 \list
210 \o createEditor() returns the widget used to change data from the model
211 and can be reimplemented to customize editing behavior.
212 \o setEditorData() provides the widget with data to manipulate.
213 \o updateEditorGeometry() ensures that the editor is displayed correctly
214 with respect to the item view.
215 \o setModelData() returns updated data to the model.
216 \endlist
217
218 The \l{Star Delegate Example}{Star Delegate} example creates
219 editors by reimplementing these methods.
220
221 \section1 QStyledItemDelegate vs. QItemDelegate
222
223 Since Qt 4.4, there are two delegate classes: QItemDelegate and
224 QStyledItemDelegate. However, the default delegate is QStyledItemDelegate.
225 These two classes are independent alternatives to painting and providing
226 editors for items in views. The difference between them is that
227 QStyledItemDelegate uses the current style to paint its items. We therefore
228 recommend using QStyledItemDelegate as the base class when implementing
229 custom delegates or when working with Qt style sheets. The code required
230 for either class should be equal unless the custom delegate needs to use
231 the style for drawing.
232
233 If you wish to customize the painting of item views, you should
234 implement a custom style. Please see the QStyle class
235 documentation for details.
236
237 \sa {Delegate Classes}, QItemDelegate, QAbstractItemDelegate, QStyle,
238 {Spin Box Delegate Example}, {Star Delegate Example}, {Color
239 Editor Factory Example}
240*/
241
242
243/*!
244 Constructs an item delegate with the given \a parent.
245*/
246QStyledItemDelegate::QStyledItemDelegate(QObject *parent)
247 : QAbstractItemDelegate(*new QStyledItemDelegatePrivate(), parent)
248{
249}
250
251/*!
252 Destroys the item delegate.
253*/
254QStyledItemDelegate::~QStyledItemDelegate()
255{
256}
257
258/*!
259 This function returns the string that the delegate will use to display the
260 Qt::DisplayRole of the model in \a locale. \a value is the value of the Qt::DisplayRole
261 provided by the model.
262
263 The default implementation uses the QLocale::toString to convert \a value into
264 a QString.
265*/
266QString QStyledItemDelegate::displayText(const QVariant &value, const QLocale& locale) const
267{
268 QString text;
269 switch (value.type()) {
270 case QVariant::Double:
271 text = locale.toString(value.toDouble());
272 break;
273 case QVariant::Int:
274 case QVariant::LongLong:
275 text = locale.toString(value.toLongLong());
276 break;
277 case QVariant::UInt:
278 case QVariant::ULongLong:
279 text = locale.toString(value.toULongLong());
280 break;
281 case QVariant::Date:
282 text = locale.toString(value.toDate(), QLocale::ShortFormat);
283 break;
284 case QVariant::Time:
285 text = locale.toString(value.toTime(), QLocale::ShortFormat);
286 break;
287 case QVariant::DateTime:
288 text = locale.toString(value.toDateTime().date(), QLocale::ShortFormat);
289 text += QLatin1Char(' ');
290 text += locale.toString(value.toDateTime().time(), QLocale::ShortFormat);
291 break;
292 default:
293 // convert new lines into line separators
294 text = value.toString();
295 for (int i = 0; i < text.count(); ++i) {
296 if (text.at(i) == QLatin1Char('\n'))
297 text[i] = QChar::LineSeparator;
298 }
299 break;
300 }
301 return text;
302}
303
304/*!
305 Initialize \a option with the values using the index \a index. This method
306 is useful for subclasses when they need a QStyleOptionViewItem, but don't want
307 to fill in all the information themselves. This function will check the version
308 of the QStyleOptionViewItem and fill in the additional values for a
309 QStyleOptionViewItemV2, QStyleOptionViewItemV3 and QStyleOptionViewItemV4.
310
311 \sa QStyleOption::initFrom()
312*/
313void QStyledItemDelegate::initStyleOption(QStyleOptionViewItem *option,
314 const QModelIndex &index) const
315{
316 QVariant value = index.data(Qt::FontRole);
317 if (value.isValid() && !value.isNull()) {
318 option->font = qvariant_cast<QFont>(value).resolve(option->font);
319 option->fontMetrics = QFontMetrics(option->font);
320 }
321
322 value = index.data(Qt::TextAlignmentRole);
323 if (value.isValid() && !value.isNull())
324 option->displayAlignment = (Qt::Alignment)value.toInt();
325
326 value = index.data(Qt::ForegroundRole);
327 if (qVariantCanConvert<QBrush>(value))
328 option->palette.setBrush(QPalette::Text, qvariant_cast<QBrush>(value));
329
330 if (QStyleOptionViewItemV4 *v4 = qstyleoption_cast<QStyleOptionViewItemV4 *>(option)) {
331 v4->index = index;
332 QVariant value = index.data(Qt::CheckStateRole);
333 if (value.isValid() && !value.isNull()) {
334 v4->features |= QStyleOptionViewItemV2::HasCheckIndicator;
335 v4->checkState = static_cast<Qt::CheckState>(value.toInt());
336 }
337
338 value = index.data(Qt::DecorationRole);
339 if (value.isValid() && !value.isNull()) {
340 v4->features |= QStyleOptionViewItemV2::HasDecoration;
341 switch (value.type()) {
342 case QVariant::Icon: {
343 v4->icon = qvariant_cast<QIcon>(value);
344 QIcon::Mode mode;
345 if (!(option->state & QStyle::State_Enabled))
346 mode = QIcon::Disabled;
347 else if (option->state & QStyle::State_Selected)
348 mode = QIcon::Selected;
349 else
350 mode = QIcon::Normal;
351 QIcon::State state = option->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
352 v4->decorationSize = v4->icon.actualSize(option->decorationSize, mode, state);
353 break;
354 }
355 case QVariant::Color: {
356 QPixmap pixmap(option->decorationSize);
357 pixmap.fill(qvariant_cast<QColor>(value));
358 v4->icon = QIcon(pixmap);
359 break;
360 }
361 case QVariant::Image: {
362 QImage image = qvariant_cast<QImage>(value);
363 v4->icon = QIcon(QPixmap::fromImage(image));
364 v4->decorationSize = image.size();
365 break;
366 }
367 case QVariant::Pixmap: {
368 QPixmap pixmap = qvariant_cast<QPixmap>(value);
369 v4->icon = QIcon(pixmap);
370 v4->decorationSize = pixmap.size();
371 break;
372 }
373 default:
374 break;
375 }
376 }
377
378 value = index.data(Qt::DisplayRole);
379 if (value.isValid() && !value.isNull()) {
380 v4->features |= QStyleOptionViewItemV2::HasDisplay;
381 v4->text = displayText(value, v4->locale);
382 }
383
384 v4->backgroundBrush = qvariant_cast<QBrush>(index.data(Qt::BackgroundRole));
385 }
386}
387
388/*!
389 Renders the delegate using the given \a painter and style \a option for
390 the item specified by \a index.
391
392 This function paints the item using the view's QStyle.
393
394 When reimplementing paint in a subclass. Use the initStyleOption()
395 to set up the \a option in the same way as the
396 QStyledItemDelegate; the option will always be an instance of
397 QStyleOptionViewItemV4. Please see its class description for
398 information on its contents.
399
400 Whenever possible, use the \a option while painting.
401 Especially its \l{QStyleOption::}{rect} variable to decide
402 where to draw and its \l{QStyleOption::}{state} to determine
403 if it is enabled or selected.
404
405 After painting, you should ensure that the painter is returned to
406 its the state it was supplied in when this function was called.
407 For example, it may be useful to call QPainter::save() before
408 painting and QPainter::restore() afterwards.
409
410 \sa QItemDelegate::paint(), QStyle::drawControl(), QStyle::CE_ItemViewItem
411*/
412void QStyledItemDelegate::paint(QPainter *painter,
413 const QStyleOptionViewItem &option, const QModelIndex &index) const
414{
415 Q_ASSERT(index.isValid());
416
417 QStyleOptionViewItemV4 opt = option;
418 initStyleOption(&opt, index);
419
420 const QWidget *widget = QStyledItemDelegatePrivate::widget(option);
421 QStyle *style = widget ? widget->style() : QApplication::style();
422 style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget);
423}
424
425/*!
426 Returns the size needed by the delegate to display the item
427 specified by \a index, taking into account the style information
428 provided by \a option.
429
430 This function uses the view's QStyle to determine the size of the
431 item.
432
433 \sa QStyle::sizeFromContents(), QStyle::CT_ItemViewItem
434*/
435QSize QStyledItemDelegate::sizeHint(const QStyleOptionViewItem &option,
436 const QModelIndex &index) const
437{
438 QVariant value = index.data(Qt::SizeHintRole);
439 if (value.isValid())
440 return qvariant_cast<QSize>(value);
441
442 QStyleOptionViewItemV4 opt = option;
443 initStyleOption(&opt, index);
444 const QWidget *widget = QStyledItemDelegatePrivate::widget(option);
445 QStyle *style = widget ? widget->style() : QApplication::style();
446 return style->sizeFromContents(QStyle::CT_ItemViewItem, &opt, QSize(), widget);
447}
448
449/*!
450 Returns the widget used to edit the item specified by \a index
451 for editing. The \a parent widget and style \a option are used to
452 control how the editor widget appears.
453
454 \sa QAbstractItemDelegate::createEditor()
455*/
456QWidget *QStyledItemDelegate::createEditor(QWidget *parent,
457 const QStyleOptionViewItem &,
458 const QModelIndex &index) const
459{
460 Q_D(const QStyledItemDelegate);
461 if (!index.isValid())
462 return 0;
463 QVariant::Type t = static_cast<QVariant::Type>(index.data(Qt::EditRole).userType());
464 return d->editorFactory()->createEditor(t, parent);
465}
466
467/*!
468 Sets the data to be displayed and edited by the \a editor from the
469 data model item specified by the model \a index.
470
471 The default implementation stores the data in the \a editor
472 widget's \l {Qt's Property System} {user property}.
473
474 \sa QMetaProperty::isUser()
475*/
476void QStyledItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
477{
478#ifdef QT_NO_PROPERTIES
479 Q_UNUSED(editor);
480 Q_UNUSED(index);
481#else
482 Q_D(const QStyledItemDelegate);
483 QVariant v = index.data(Qt::EditRole);
484 QByteArray n = editor->metaObject()->userProperty().name();
485
486 // ### Qt 5: remove
487 // A work-around for missing "USER true" in qdatetimeedit.h for
488 // QTimeEdit's time property and QDateEdit's date property.
489 // It only triggers if the default user property "dateTime" is
490 // reported for QTimeEdit and QDateEdit.
491 if (n == "dateTime") {
492 if (editor->inherits("QTimeEdit"))
493 n = "time";
494 else if (editor->inherits("QDateEdit"))
495 n = "date";
496 }
497
498 // ### Qt 5: give QComboBox a USER property
499 if (n.isEmpty() && editor->inherits("QComboBox"))
500 n = d->editorFactory()->valuePropertyName(static_cast<QVariant::Type>(v.userType()));
501 if (!n.isEmpty()) {
502 if (!v.isValid())
503 v = QVariant(editor->property(n).userType(), (const void *)0);
504 editor->setProperty(n, v);
505 }
506#endif
507}
508
509/*!
510 Gets data drom the \a editor widget and stores it in the specified
511 \a model at the item \a index.
512
513 The default implementation gets the value to be stored in the data
514 model from the \a editor widget's \l {Qt's Property System} {user
515 property}.
516
517 \sa QMetaProperty::isUser()
518*/
519void QStyledItemDelegate::setModelData(QWidget *editor,
520 QAbstractItemModel *model,
521 const QModelIndex &index) const
522{
523#ifdef QT_NO_PROPERTIES
524 Q_UNUSED(model);
525 Q_UNUSED(editor);
526 Q_UNUSED(index);
527#else
528 Q_D(const QStyledItemDelegate);
529 Q_ASSERT(model);
530 Q_ASSERT(editor);
531 QByteArray n = editor->metaObject()->userProperty().name();
532 if (n.isEmpty())
533 n = d->editorFactory()->valuePropertyName(
534 static_cast<QVariant::Type>(model->data(index, Qt::EditRole).userType()));
535 if (!n.isEmpty())
536 model->setData(index, editor->property(n), Qt::EditRole);
537#endif
538}
539
540/*!
541 Updates the \a editor for the item specified by \a index
542 according to the style \a option given.
543*/
544void QStyledItemDelegate::updateEditorGeometry(QWidget *editor,
545 const QStyleOptionViewItem &option,
546 const QModelIndex &index) const
547{
548 if (!editor)
549 return;
550 Q_ASSERT(index.isValid());
551 const QWidget *widget = QStyledItemDelegatePrivate::widget(option);
552
553 QStyleOptionViewItemV4 opt = option;
554 initStyleOption(&opt, index);
555 // let the editor take up all available space
556 //if the editor is not a QLineEdit
557 //or it is in a QTableView
558#if !defined(QT_NO_TABLEVIEW) && !defined(QT_NO_LINEEDIT)
559 if (qobject_cast<QExpandingLineEdit*>(editor) && !qobject_cast<const QTableView*>(widget))
560 opt.showDecorationSelected = editor->style()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected, 0, editor);
561 else
562#endif
563 opt.showDecorationSelected = true;
564
565 QStyle *style = widget ? widget->style() : QApplication::style();
566 QRect geom = style->subElementRect(QStyle::SE_ItemViewItemText, &opt, widget);
567 if ( editor->layoutDirection() == Qt::RightToLeft) {
568 const int delta = qSmartMinSize(editor).width() - geom.width();
569 if (delta > 0) {
570 //we need to widen the geometry
571 geom.adjust(-delta, 0, 0, 0);
572 }
573 }
574
575 editor->setGeometry(geom);
576}
577
578/*!
579 Returns the editor factory used by the item delegate.
580 If no editor factory is set, the function will return null.
581
582 \sa setItemEditorFactory()
583*/
584QItemEditorFactory *QStyledItemDelegate::itemEditorFactory() const
585{
586 Q_D(const QStyledItemDelegate);
587 return d->factory;
588}
589
590/*!
591 Sets the editor factory to be used by the item delegate to be the \a factory
592 specified. If no editor factory is set, the item delegate will use the
593 default editor factory.
594
595 \sa itemEditorFactory()
596*/
597void QStyledItemDelegate::setItemEditorFactory(QItemEditorFactory *factory)
598{
599 Q_D(QStyledItemDelegate);
600 d->factory = factory;
601}
602
603
604/*!
605 \fn bool QStyledItemDelegate::eventFilter(QObject *editor, QEvent *event)
606
607 Returns true if the given \a editor is a valid QWidget and the
608 given \a event is handled; otherwise returns false. The following
609 key press events are handled by default:
610
611 \list
612 \o \gui Tab
613 \o \gui Backtab
614 \o \gui Enter
615 \o \gui Return
616 \o \gui Esc
617 \endlist
618
619 In the case of \gui Tab, \gui Backtab, \gui Enter and \gui Return
620 key press events, the \a editor's data is comitted to the model
621 and the editor is closed. If the \a event is a \gui Tab key press
622 the view will open an editor on the next item in the
623 view. Likewise, if the \a event is a \gui Backtab key press the
624 view will open an editor on the \e previous item in the view.
625
626 If the event is a \gui Esc key press event, the \a editor is
627 closed \e without committing its data.
628
629 \sa commitData(), closeEditor()
630*/
631bool QStyledItemDelegate::eventFilter(QObject *object, QEvent *event)
632{
633 QWidget *editor = qobject_cast<QWidget*>(object);
634 if (!editor)
635 return false;
636 if (event->type() == QEvent::KeyPress) {
637 switch (static_cast<QKeyEvent *>(event)->key()) {
638 case Qt::Key_Tab:
639 emit commitData(editor);
640 emit closeEditor(editor, QAbstractItemDelegate::EditNextItem);
641 return true;
642 case Qt::Key_Backtab:
643 emit commitData(editor);
644 emit closeEditor(editor, QAbstractItemDelegate::EditPreviousItem);
645 return true;
646 case Qt::Key_Enter:
647 case Qt::Key_Return:
648#ifndef QT_NO_TEXTEDIT
649 if (qobject_cast<QTextEdit*>(editor))
650 return false; // don't filter enter key events for QTextEdit
651 // We want the editor to be able to process the key press
652 // before committing the data (e.g. so it can do
653 // validation/fixup of the input).
654#endif // QT_NO_TEXTEDIT
655#ifndef QT_NO_LINEEDIT
656 if (QLineEdit *e = qobject_cast<QLineEdit*>(editor))
657 if (!e->hasAcceptableInput())
658 return false;
659#endif // QT_NO_LINEEDIT
660 QMetaObject::invokeMethod(this, "_q_commitDataAndCloseEditor",
661 Qt::QueuedConnection, Q_ARG(QWidget*, editor));
662 return false;
663 case Qt::Key_Escape:
664 // don't commit data
665 emit closeEditor(editor, QAbstractItemDelegate::RevertModelCache);
666 break;
667 default:
668 return false;
669 }
670 if (editor->parentWidget())
671 editor->parentWidget()->setFocus();
672 return true;
673 } else if (event->type() == QEvent::FocusOut || event->type() == QEvent::Hide) {
674 //the Hide event will take care of he editors that are in fact complete dialogs
675 if (!editor->isActiveWindow() || (QApplication::focusWidget() != editor)) {
676 QWidget *w = QApplication::focusWidget();
677 while (w) { // don't worry about focus changes internally in the editor
678 if (w == editor)
679 return false;
680 w = w->parentWidget();
681 }
682#ifndef QT_NO_DRAGANDDROP
683 // The window may lose focus during an drag operation.
684 // i.e when dragging involves the taskbar on Windows.
685 if (QDragManager::self() && QDragManager::self()->object != 0)
686 return false;
687#endif
688 // Opening a modal dialog will start a new eventloop
689 // that will process the deleteLater event.
690 QWidget *activeModalWidget = QApplication::activeModalWidget();
691 if (activeModalWidget
692 && !activeModalWidget->isAncestorOf(editor)
693 && qobject_cast<QDialog*>(activeModalWidget))
694 return false;
695 emit commitData(editor);
696 emit closeEditor(editor, NoHint);
697 }
698 } else if (event->type() == QEvent::ShortcutOverride) {
699 if (static_cast<QKeyEvent*>(event)->key() == Qt::Key_Escape) {
700 event->accept();
701 return true;
702 }
703 }
704 return false;
705}
706
707/*!
708 \reimp
709*/
710bool QStyledItemDelegate::editorEvent(QEvent *event,
711 QAbstractItemModel *model,
712 const QStyleOptionViewItem &option,
713 const QModelIndex &index)
714{
715 Q_ASSERT(event);
716 Q_ASSERT(model);
717
718 // make sure that the item is checkable
719 Qt::ItemFlags flags = model->flags(index);
720 if (!(flags & Qt::ItemIsUserCheckable) || !(option.state & QStyle::State_Enabled)
721 || !(flags & Qt::ItemIsEnabled))
722 return false;
723
724 // make sure that we have a check state
725 QVariant value = index.data(Qt::CheckStateRole);
726 if (!value.isValid())
727 return false;
728
729 const QWidget *widget = QStyledItemDelegatePrivate::widget(option);
730 QStyle *style = widget ? widget->style() : QApplication::style();
731
732 // make sure that we have the right event type
733 if ((event->type() == QEvent::MouseButtonRelease)
734 || (event->type() == QEvent::MouseButtonDblClick)) {
735 QStyleOptionViewItemV4 viewOpt(option);
736 initStyleOption(&viewOpt, index);
737 QRect checkRect = style->subElementRect(QStyle::SE_ItemViewItemCheckIndicator, &viewOpt, widget);
738 QMouseEvent *me = static_cast<QMouseEvent*>(event);
739 if (me->button() != Qt::LeftButton || !checkRect.contains(me->pos()))
740 return false;
741
742 // eat the double click events inside the check rect
743 if (event->type() == QEvent::MouseButtonDblClick)
744 return true;
745
746 } else if (event->type() == QEvent::KeyPress) {
747 if (static_cast<QKeyEvent*>(event)->key() != Qt::Key_Space
748 && static_cast<QKeyEvent*>(event)->key() != Qt::Key_Select)
749 return false;
750 } else {
751 return false;
752 }
753
754 Qt::CheckState state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked
755 ? Qt::Unchecked : Qt::Checked);
756 return model->setData(index, state, Qt::CheckStateRole);
757}
758
759QT_END_NAMESPACE
760
761#include "moc_qstyleditemdelegate.cpp"
762
763#endif // QT_NO_ITEMVIEWS
Note: See TracBrowser for help on using the repository browser.