| 1 | /**************************************************************************** | 
|---|
| 2 | ** | 
|---|
| 3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). | 
|---|
| 4 | ** Contact: Qt Software Information (qt-info@nokia.com) | 
|---|
| 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 qt-sales@nokia.com. | 
|---|
| 38 | ** $QT_END_LICENSE$ | 
|---|
| 39 | ** | 
|---|
| 40 | ****************************************************************************/ | 
|---|
| 41 |  | 
|---|
| 42 | #include "qitemdelegate.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 <qmetaobject.h> | 
|---|
| 64 | #include <qtextlayout.h> | 
|---|
| 65 | #include <private/qobject_p.h> | 
|---|
| 66 | #include <private/qdnd_p.h> | 
|---|
| 67 | #include <private/qtextengine_p.h> | 
|---|
| 68 | #include <qdebug.h> | 
|---|
| 69 | #include <qlocale.h> | 
|---|
| 70 | #include <qdialog.h> | 
|---|
| 71 |  | 
|---|
| 72 | #include <limits.h> | 
|---|
| 73 |  | 
|---|
| 74 | #ifndef DBL_DIG | 
|---|
| 75 | #  define DBL_DIG 10 | 
|---|
| 76 | #endif | 
|---|
| 77 |  | 
|---|
| 78 | QT_BEGIN_NAMESPACE | 
|---|
| 79 |  | 
|---|
| 80 | class QItemDelegatePrivate : public QObjectPrivate | 
|---|
| 81 | { | 
|---|
| 82 | Q_DECLARE_PUBLIC(QItemDelegate) | 
|---|
| 83 |  | 
|---|
| 84 | public: | 
|---|
| 85 | QItemDelegatePrivate() : f(0), clipPainting(true) {} | 
|---|
| 86 |  | 
|---|
| 87 | inline const QItemEditorFactory *editorFactory() const | 
|---|
| 88 | { return f ? f : QItemEditorFactory::defaultFactory(); } | 
|---|
| 89 |  | 
|---|
| 90 | inline QIcon::Mode iconMode(QStyle::State state) const | 
|---|
| 91 | { | 
|---|
| 92 | if (!(state & QStyle::State_Enabled)) return QIcon::Disabled; | 
|---|
| 93 | if (state & QStyle::State_Selected) return QIcon::Selected; | 
|---|
| 94 | return QIcon::Normal; | 
|---|
| 95 | } | 
|---|
| 96 |  | 
|---|
| 97 | inline QIcon::State iconState(QStyle::State state) const | 
|---|
| 98 | { return state & QStyle::State_Open ? QIcon::On : QIcon::Off; } | 
|---|
| 99 |  | 
|---|
| 100 | inline static QString replaceNewLine(QString text) | 
|---|
| 101 | { | 
|---|
| 102 | const QChar nl = QLatin1Char('\n'); | 
|---|
| 103 | for (int i = 0; i < text.count(); ++i) | 
|---|
| 104 | if (text.at(i) == nl) | 
|---|
| 105 | text[i] = QChar::LineSeparator; | 
|---|
| 106 | return text; | 
|---|
| 107 | } | 
|---|
| 108 |  | 
|---|
| 109 | static QString valueToText(const QVariant &value, const QStyleOptionViewItemV4 &option); | 
|---|
| 110 |  | 
|---|
| 111 | void _q_commitDataAndCloseEditor(QWidget *editor); | 
|---|
| 112 |  | 
|---|
| 113 | QItemEditorFactory *f; | 
|---|
| 114 | bool clipPainting; | 
|---|
| 115 |  | 
|---|
| 116 | QRect textLayoutBounds(const QStyleOptionViewItemV2 &options) const; | 
|---|
| 117 | QSizeF doTextLayout(int lineWidth) const; | 
|---|
| 118 | mutable QTextLayout textLayout; | 
|---|
| 119 | mutable QTextOption textOption; | 
|---|
| 120 |  | 
|---|
| 121 | const QWidget *widget(const QStyleOptionViewItem &option) const | 
|---|
| 122 | { | 
|---|
| 123 | if (const QStyleOptionViewItemV3 *v3 = qstyleoption_cast<const QStyleOptionViewItemV3 *>(&option)) | 
|---|
| 124 | return v3->widget; | 
|---|
| 125 |  | 
|---|
| 126 | return 0; | 
|---|
| 127 | } | 
|---|
| 128 |  | 
|---|
| 129 | // ### temporary hack until we have QStandardItemDelegate | 
|---|
| 130 | mutable struct Icon { | 
|---|
| 131 | QIcon icon; | 
|---|
| 132 | QIcon::Mode mode; | 
|---|
| 133 | QIcon::State state; | 
|---|
| 134 | } tmp; | 
|---|
| 135 | }; | 
|---|
| 136 |  | 
|---|
| 137 | void QItemDelegatePrivate::_q_commitDataAndCloseEditor(QWidget *editor) | 
|---|
| 138 | { | 
|---|
| 139 | Q_Q(QItemDelegate); | 
|---|
| 140 | emit q->commitData(editor); | 
|---|
| 141 | emit q->closeEditor(editor, QAbstractItemDelegate::SubmitModelCache); | 
|---|
| 142 | } | 
|---|
| 143 |  | 
|---|
| 144 | QRect QItemDelegatePrivate::textLayoutBounds(const QStyleOptionViewItemV2 &option) const | 
|---|
| 145 | { | 
|---|
| 146 | QRect rect = option.rect; | 
|---|
| 147 | const bool wrapText = option.features & QStyleOptionViewItemV2::WrapText; | 
|---|
| 148 | switch (option.decorationPosition) { | 
|---|
| 149 | case QStyleOptionViewItem::Left: | 
|---|
| 150 | case QStyleOptionViewItem::Right: | 
|---|
| 151 | rect.setWidth(wrapText && rect.isValid() ? rect.width() : (QFIXED_MAX)); | 
|---|
| 152 | break; | 
|---|
| 153 | case QStyleOptionViewItem::Top: | 
|---|
| 154 | case QStyleOptionViewItem::Bottom: | 
|---|
| 155 | rect.setWidth(wrapText ? option.decorationSize.width() : (QFIXED_MAX)); | 
|---|
| 156 | break; | 
|---|
| 157 | } | 
|---|
| 158 |  | 
|---|
| 159 | return rect; | 
|---|
| 160 | } | 
|---|
| 161 |  | 
|---|
| 162 | QSizeF QItemDelegatePrivate::doTextLayout(int lineWidth) const | 
|---|
| 163 | { | 
|---|
| 164 | qreal height = 0; | 
|---|
| 165 | qreal widthUsed = 0; | 
|---|
| 166 | textLayout.beginLayout(); | 
|---|
| 167 | while (true) { | 
|---|
| 168 | QTextLine line = textLayout.createLine(); | 
|---|
| 169 | if (!line.isValid()) | 
|---|
| 170 | break; | 
|---|
| 171 | line.setLineWidth(lineWidth); | 
|---|
| 172 | line.setPosition(QPointF(0, height)); | 
|---|
| 173 | height += line.height(); | 
|---|
| 174 | widthUsed = qMax(widthUsed, line.naturalTextWidth()); | 
|---|
| 175 | } | 
|---|
| 176 | textLayout.endLayout(); | 
|---|
| 177 | return QSizeF(widthUsed, height); | 
|---|
| 178 | } | 
|---|
| 179 |  | 
|---|
| 180 | /*! | 
|---|
| 181 | \class QItemDelegate | 
|---|
| 182 |  | 
|---|
| 183 | \brief The QItemDelegate class provides display and editing facilities for | 
|---|
| 184 | data items from a model. | 
|---|
| 185 |  | 
|---|
| 186 | \ingroup model-view | 
|---|
| 187 | \mainclass | 
|---|
| 188 |  | 
|---|
| 189 | QItemDelegate can be used to provide custom display features and editor | 
|---|
| 190 | widgets for item views based on QAbstractItemView subclasses. Using a | 
|---|
| 191 | delegate for this purpose allows the display and editing mechanisms to be | 
|---|
| 192 | customized and developed independently from the model and view. | 
|---|
| 193 |  | 
|---|
| 194 | The QItemDelegate class is one of the \l{Model/View Classes} and | 
|---|
| 195 | is part of Qt's \l{Model/View Programming}{model/view framework}. | 
|---|
| 196 | Note that QStyledItemDelegate has taken over the job of drawing | 
|---|
| 197 | Qt's item views. We recommend the use of QStyledItemDelegate when | 
|---|
| 198 | creating new delegates. | 
|---|
| 199 |  | 
|---|
| 200 | When displaying items from a custom model in a standard view, it is | 
|---|
| 201 | often sufficient to simply ensure that the model returns appropriate | 
|---|
| 202 | data for each of the \l{Qt::ItemDataRole}{roles} that determine the | 
|---|
| 203 | appearance of items in views. The default delegate used by Qt's | 
|---|
| 204 | standard views uses this role information to display items in most | 
|---|
| 205 | of the common forms expected by users. However, it is sometimes | 
|---|
| 206 | necessary to have even more control over the appearance of items than | 
|---|
| 207 | the default delegate can provide. | 
|---|
| 208 |  | 
|---|
| 209 | This class provides default implementations of the functions for | 
|---|
| 210 | painting item data in a view and editing data from item models. | 
|---|
| 211 | Default implementations of the paint() and sizeHint() virtual | 
|---|
| 212 | functions, defined in QAbstractItemDelegate, are provided to | 
|---|
| 213 | ensure that the delegate implements the correct basic behavior | 
|---|
| 214 | expected by views. You can reimplement these functions in | 
|---|
| 215 | subclasses to customize the appearance of items. | 
|---|
| 216 |  | 
|---|
| 217 | When editing data in an item view, QItemDelegate provides an | 
|---|
| 218 | editor widget, which is a widget that is placed on top of the view | 
|---|
| 219 | while editing takes place. Editors are created with a | 
|---|
| 220 | QItemEditorFactory; a default static instance provided by | 
|---|
| 221 | QItemEditorFactory is installed on all item delagates. You can set | 
|---|
| 222 | a custom factory using setItemEditorFactory() or set a new default | 
|---|
| 223 | factory with QItemEditorFactory::setDefaultFactory(). It is the | 
|---|
| 224 | data stored in the item model with the Qt::EditRole that is edited. | 
|---|
| 225 |  | 
|---|
| 226 | Only the standard editing functions for widget-based delegates are | 
|---|
| 227 | reimplemented here: | 
|---|
| 228 |  | 
|---|
| 229 | \list | 
|---|
| 230 | \o createEditor() returns the widget used to change data from the model | 
|---|
| 231 | and can be reimplemented to customize editing behavior. | 
|---|
| 232 | \o setEditorData() provides the widget with data to manipulate. | 
|---|
| 233 | \o updateEditorGeometry() ensures that the editor is displayed correctly | 
|---|
| 234 | with respect to the item view. | 
|---|
| 235 | \o setModelData() returns updated data to the model. | 
|---|
| 236 | \endlist | 
|---|
| 237 |  | 
|---|
| 238 | The closeEditor() signal indicates that the user has completed editing the data, | 
|---|
| 239 | and that the editor widget can be destroyed. | 
|---|
| 240 |  | 
|---|
| 241 | \section1 Standard Roles and Data Types | 
|---|
| 242 |  | 
|---|
| 243 | The default delegate used by the standard views supplied with Qt | 
|---|
| 244 | associates each standard role (defined by Qt::ItemDataRole) with certain | 
|---|
| 245 | data types. Models that return data in these types can influence the | 
|---|
| 246 | appearance of the delegate as described in the following table. | 
|---|
| 247 |  | 
|---|
| 248 | \table | 
|---|
| 249 | \header \o Role \o Accepted Types | 
|---|
| 250 | \omit | 
|---|
| 251 | \row    \o \l Qt::AccessibleDescriptionRole \o QString | 
|---|
| 252 | \row    \o \l Qt::AccessibleTextRole \o QString | 
|---|
| 253 | \endomit | 
|---|
| 254 | \row    \o \l Qt::BackgroundRole \o QBrush | 
|---|
| 255 | \row    \o \l Qt::BackgroundColorRole \o QColor (obsolete; use Qt::BackgroundRole instead) | 
|---|
| 256 | \row    \o \l Qt::CheckStateRole \o Qt::CheckState | 
|---|
| 257 | \row    \o \l Qt::DecorationRole \o QIcon and QColor | 
|---|
| 258 | \row    \o \l Qt::DisplayRole \o QString and types with a string representation | 
|---|
| 259 | \row    \o \l Qt::EditRole \o See QItemEditorFactory for details | 
|---|
| 260 | \row    \o \l Qt::FontRole \o QFont | 
|---|
| 261 | \row    \o \l Qt::SizeHintRole \o QSize | 
|---|
| 262 | \omit | 
|---|
| 263 | \row    \o \l Qt::StatusTipRole \o | 
|---|
| 264 | \endomit | 
|---|
| 265 | \row    \o \l Qt::TextAlignmentRole \o Qt::Alignment | 
|---|
| 266 | \row    \o \l Qt::ForegroundRole \o QBrush | 
|---|
| 267 | \row    \o \l Qt::TextColorRole \o QColor (obsolete; use Qt::ForegroundRole instead) | 
|---|
| 268 | \omit | 
|---|
| 269 | \row    \o \l Qt::ToolTipRole | 
|---|
| 270 | \row    \o \l Qt::WhatsThisRole | 
|---|
| 271 | \endomit | 
|---|
| 272 | \endtable | 
|---|
| 273 |  | 
|---|
| 274 | If the default delegate does not allow the level of customization that | 
|---|
| 275 | you need, either for display purposes or for editing data, it is possible to | 
|---|
| 276 | subclass QItemDelegate to implement the desired behavior. | 
|---|
| 277 |  | 
|---|
| 278 | \section1 Subclassing | 
|---|
| 279 |  | 
|---|
| 280 | When subclassing QItemDelegate to create a delegate that displays items | 
|---|
| 281 | using a custom renderer, it is important to ensure that the delegate can | 
|---|
| 282 | render items suitably for all the required states; e.g. selected, | 
|---|
| 283 | disabled, checked. The documentation for the paint() function contains | 
|---|
| 284 | some hints to show how this can be achieved. | 
|---|
| 285 |  | 
|---|
| 286 | You can provide custom editors by using a QItemEditorFactory. The | 
|---|
| 287 | \l{Color Editor Factory Example} shows how a custom editor can be | 
|---|
| 288 | made available to delegates with the default item editor | 
|---|
| 289 | factory. This way, there is no need to subclass QItemDelegate.  An | 
|---|
| 290 | alternative is to reimplement createEditor(), setEditorData(), | 
|---|
| 291 | setModelData(), and updateEditorGeometry(). This process is | 
|---|
| 292 | described in the \l{Spin Box Delegate Example}. | 
|---|
| 293 |  | 
|---|
| 294 | \section1 QStyledItemDelegate vs. QItemDelegate | 
|---|
| 295 |  | 
|---|
| 296 | Since Qt 4.4, there are two delegate classes: QItemDelegate and | 
|---|
| 297 | QStyledItemDelegate. However, the default delegate is QStyledItemDelegate. | 
|---|
| 298 | These two classes are independent alternatives to painting and providing | 
|---|
| 299 | editors for items in views. The difference between them is that | 
|---|
| 300 | QStyledItemDelegate uses the current style to paint its items. We therefore | 
|---|
| 301 | recommend using QStyledItemDelegate as the base class when implementing | 
|---|
| 302 | custom delegates or when working with Qt style sheets. The code required | 
|---|
| 303 | for either class should be equal unless the custom delegate needs to use | 
|---|
| 304 | the style for drawing. | 
|---|
| 305 |  | 
|---|
| 306 | \sa {Delegate Classes}, QStyledItemDelegate, QAbstractItemDelegate, | 
|---|
| 307 | {Spin Box Delegate Example}, {Settings Editor Example}, | 
|---|
| 308 | {Icons Example} | 
|---|
| 309 | */ | 
|---|
| 310 |  | 
|---|
| 311 | /*! | 
|---|
| 312 | Constructs an item delegate with the given \a parent. | 
|---|
| 313 | */ | 
|---|
| 314 |  | 
|---|
| 315 | QItemDelegate::QItemDelegate(QObject *parent) | 
|---|
| 316 | : QAbstractItemDelegate(*new QItemDelegatePrivate(), parent) | 
|---|
| 317 | { | 
|---|
| 318 |  | 
|---|
| 319 | } | 
|---|
| 320 |  | 
|---|
| 321 | /*! | 
|---|
| 322 | Destroys the item delegate. | 
|---|
| 323 | */ | 
|---|
| 324 |  | 
|---|
| 325 | QItemDelegate::~QItemDelegate() | 
|---|
| 326 | { | 
|---|
| 327 | } | 
|---|
| 328 |  | 
|---|
| 329 | /*! | 
|---|
| 330 | \property QItemDelegate::clipping | 
|---|
| 331 | \brief if the delegate should clip the paint events | 
|---|
| 332 | \since 4.2 | 
|---|
| 333 |  | 
|---|
| 334 | This property will set the paint clip to the size of the item. | 
|---|
| 335 | The default value is on. It is useful for cases such | 
|---|
| 336 | as when images are larger than the size of the item. | 
|---|
| 337 | */ | 
|---|
| 338 |  | 
|---|
| 339 | bool QItemDelegate::hasClipping() const | 
|---|
| 340 | { | 
|---|
| 341 | Q_D(const QItemDelegate); | 
|---|
| 342 | return d->clipPainting; | 
|---|
| 343 | } | 
|---|
| 344 |  | 
|---|
| 345 | void QItemDelegate::setClipping(bool clip) | 
|---|
| 346 | { | 
|---|
| 347 | Q_D(QItemDelegate); | 
|---|
| 348 | d->clipPainting = clip; | 
|---|
| 349 | } | 
|---|
| 350 |  | 
|---|
| 351 | QString QItemDelegatePrivate::valueToText(const QVariant &value, const QStyleOptionViewItemV4 &option) | 
|---|
| 352 | { | 
|---|
| 353 | QString text; | 
|---|
| 354 | switch (value.type()) { | 
|---|
| 355 | case QVariant::Double: | 
|---|
| 356 | text = option.locale.toString(value.toDouble(), 'g', DBL_DIG); | 
|---|
| 357 | break; | 
|---|
| 358 | case QVariant::Int: | 
|---|
| 359 | case QVariant::LongLong: | 
|---|
| 360 | text = option.locale.toString(value.toLongLong()); | 
|---|
| 361 | break; | 
|---|
| 362 | case QVariant::UInt: | 
|---|
| 363 | case QVariant::ULongLong: | 
|---|
| 364 | text = option.locale.toString(value.toULongLong()); | 
|---|
| 365 | break; | 
|---|
| 366 | case QVariant::Date: | 
|---|
| 367 | text = option.locale.toString(value.toDate(), QLocale::ShortFormat); | 
|---|
| 368 | break; | 
|---|
| 369 | case QVariant::Time: | 
|---|
| 370 | text = option.locale.toString(value.toTime(), QLocale::ShortFormat); | 
|---|
| 371 | break; | 
|---|
| 372 | case QVariant::DateTime: | 
|---|
| 373 | text = option.locale.toString(value.toDateTime().date(), QLocale::ShortFormat); | 
|---|
| 374 | text += QLatin1Char(' '); | 
|---|
| 375 | text += option.locale.toString(value.toDateTime().time(), QLocale::ShortFormat); | 
|---|
| 376 | break; | 
|---|
| 377 | default: | 
|---|
| 378 | text = replaceNewLine(value.toString()); | 
|---|
| 379 | break; | 
|---|
| 380 | } | 
|---|
| 381 | return text; | 
|---|
| 382 | } | 
|---|
| 383 |  | 
|---|
| 384 | /*! | 
|---|
| 385 | Renders the delegate using the given \a painter and style \a option for | 
|---|
| 386 | the item specified by \a index. | 
|---|
| 387 |  | 
|---|
| 388 | When reimplementing this function in a subclass, you should update the area | 
|---|
| 389 | held by the option's \l{QStyleOption::rect}{rect} variable, using the | 
|---|
| 390 | option's \l{QStyleOption::state}{state} variable to determine the state of | 
|---|
| 391 | the item to be displayed, and adjust the way it is painted accordingly. | 
|---|
| 392 |  | 
|---|
| 393 | For example, a selected item may need to be displayed differently to | 
|---|
| 394 | unselected items, as shown in the following code: | 
|---|
| 395 |  | 
|---|
| 396 | \snippet examples/itemviews/pixelator/pixeldelegate.cpp 2 | 
|---|
| 397 | \dots | 
|---|
| 398 |  | 
|---|
| 399 | After painting, you should ensure that the painter is returned to its | 
|---|
| 400 | the state it was supplied in when this function was called. For example, | 
|---|
| 401 | it may be useful to call QPainter::save() before painting and | 
|---|
| 402 | QPainter::restore() afterwards. | 
|---|
| 403 |  | 
|---|
| 404 | \sa QStyle::State | 
|---|
| 405 | */ | 
|---|
| 406 | void QItemDelegate::paint(QPainter *painter, | 
|---|
| 407 | const QStyleOptionViewItem &option, | 
|---|
| 408 | const QModelIndex &index) const | 
|---|
| 409 | { | 
|---|
| 410 | Q_D(const QItemDelegate); | 
|---|
| 411 | Q_ASSERT(index.isValid()); | 
|---|
| 412 |  | 
|---|
| 413 | QStyleOptionViewItemV4 opt = setOptions(index, option); | 
|---|
| 414 |  | 
|---|
| 415 | const QStyleOptionViewItemV2 *v2 = qstyleoption_cast<const QStyleOptionViewItemV2 *>(&option); | 
|---|
| 416 | opt.features = v2 ? v2->features | 
|---|
| 417 | : QStyleOptionViewItemV2::ViewItemFeatures(QStyleOptionViewItemV2::None); | 
|---|
| 418 | const QStyleOptionViewItemV3 *v3 = qstyleoption_cast<const QStyleOptionViewItemV3 *>(&option); | 
|---|
| 419 | opt.locale = v3 ? v3->locale : QLocale(); | 
|---|
| 420 | opt.widget = v3 ? v3->widget : 0; | 
|---|
| 421 |  | 
|---|
| 422 | // prepare | 
|---|
| 423 | painter->save(); | 
|---|
| 424 | if (d->clipPainting) | 
|---|
| 425 | painter->setClipRect(opt.rect); | 
|---|
| 426 |  | 
|---|
| 427 | // get the data and the rectangles | 
|---|
| 428 |  | 
|---|
| 429 | QVariant value; | 
|---|
| 430 |  | 
|---|
| 431 | QPixmap pixmap; | 
|---|
| 432 | QRect decorationRect; | 
|---|
| 433 | value = index.data(Qt::DecorationRole); | 
|---|
| 434 | if (value.isValid()) { | 
|---|
| 435 | // ### we need the pixmap to call the virtual function | 
|---|
| 436 | pixmap = decoration(opt, value); | 
|---|
| 437 | if (value.type() == QVariant::Icon) { | 
|---|
| 438 | d->tmp.icon = qvariant_cast<QIcon>(value); | 
|---|
| 439 | d->tmp.mode = d->iconMode(option.state); | 
|---|
| 440 | d->tmp.state = d->iconState(option.state); | 
|---|
| 441 | const QSize size = d->tmp.icon.actualSize(option.decorationSize, | 
|---|
| 442 | d->tmp.mode, d->tmp.state); | 
|---|
| 443 | decorationRect = QRect(QPoint(0, 0), size); | 
|---|
| 444 | } else { | 
|---|
| 445 | d->tmp.icon = QIcon(); | 
|---|
| 446 | decorationRect = QRect(QPoint(0, 0), pixmap.size()); | 
|---|
| 447 | } | 
|---|
| 448 | } else { | 
|---|
| 449 | d->tmp.icon = QIcon(); | 
|---|
| 450 | decorationRect = QRect(); | 
|---|
| 451 | } | 
|---|
| 452 |  | 
|---|
| 453 | QString text; | 
|---|
| 454 | QRect displayRect; | 
|---|
| 455 | value = index.data(Qt::DisplayRole); | 
|---|
| 456 | if (value.isValid() && !value.isNull()) { | 
|---|
| 457 | text = QItemDelegatePrivate::valueToText(value, opt); | 
|---|
| 458 | displayRect = textRectangle(painter, d->textLayoutBounds(opt), opt.font, text); | 
|---|
| 459 | } | 
|---|
| 460 |  | 
|---|
| 461 | QRect checkRect; | 
|---|
| 462 | Qt::CheckState checkState = Qt::Unchecked; | 
|---|
| 463 | value = index.data(Qt::CheckStateRole); | 
|---|
| 464 | if (value.isValid()) { | 
|---|
| 465 | checkState = static_cast<Qt::CheckState>(value.toInt()); | 
|---|
| 466 | checkRect = check(opt, opt.rect, value); | 
|---|
| 467 | } | 
|---|
| 468 |  | 
|---|
| 469 | // do the layout | 
|---|
| 470 |  | 
|---|
| 471 | doLayout(opt, &checkRect, &decorationRect, &displayRect, false); | 
|---|
| 472 |  | 
|---|
| 473 | // draw the item | 
|---|
| 474 |  | 
|---|
| 475 | drawBackground(painter, opt, index); | 
|---|
| 476 | drawCheck(painter, opt, checkRect, checkState); | 
|---|
| 477 | drawDecoration(painter, opt, decorationRect, pixmap); | 
|---|
| 478 | drawDisplay(painter, opt, displayRect, text); | 
|---|
| 479 | drawFocus(painter, opt, displayRect); | 
|---|
| 480 |  | 
|---|
| 481 | // done | 
|---|
| 482 | painter->restore(); | 
|---|
| 483 | } | 
|---|
| 484 |  | 
|---|
| 485 | /*! | 
|---|
| 486 | Returns the size needed by the delegate to display the item | 
|---|
| 487 | specified by \a index, taking into account the style information | 
|---|
| 488 | provided by \a option. | 
|---|
| 489 |  | 
|---|
| 490 | When reimplementing this function, note that in case of text | 
|---|
| 491 | items, QItemDelegate adds a margin (i.e. 2 * | 
|---|
| 492 | QStyle::PM_FocusFrameHMargin) to the length of the text. | 
|---|
| 493 | */ | 
|---|
| 494 |  | 
|---|
| 495 | QSize QItemDelegate::sizeHint(const QStyleOptionViewItem &option, | 
|---|
| 496 | const QModelIndex &index) const | 
|---|
| 497 | { | 
|---|
| 498 | QVariant value = index.data(Qt::SizeHintRole); | 
|---|
| 499 | if (value.isValid()) | 
|---|
| 500 | return qvariant_cast<QSize>(value); | 
|---|
| 501 | QRect decorationRect = rect(option, index, Qt::DecorationRole); | 
|---|
| 502 | QRect displayRect = rect(option, index, Qt::DisplayRole); | 
|---|
| 503 | QRect checkRect = rect(option, index, Qt::CheckStateRole); | 
|---|
| 504 |  | 
|---|
| 505 | doLayout(option, &checkRect, &decorationRect, &displayRect, true); | 
|---|
| 506 |  | 
|---|
| 507 | return (decorationRect|displayRect|checkRect).size(); | 
|---|
| 508 | } | 
|---|
| 509 |  | 
|---|
| 510 | /*! | 
|---|
| 511 | Returns the widget used to edit the item specified by \a index | 
|---|
| 512 | for editing. The \a parent widget and style \a option are used to | 
|---|
| 513 | control how the editor widget appears. | 
|---|
| 514 |  | 
|---|
| 515 | \sa QAbstractItemDelegate::createEditor() | 
|---|
| 516 | */ | 
|---|
| 517 |  | 
|---|
| 518 | QWidget *QItemDelegate::createEditor(QWidget *parent, | 
|---|
| 519 | const QStyleOptionViewItem &, | 
|---|
| 520 | const QModelIndex &index) const | 
|---|
| 521 | { | 
|---|
| 522 | Q_D(const QItemDelegate); | 
|---|
| 523 | if (!index.isValid()) | 
|---|
| 524 | return 0; | 
|---|
| 525 | QVariant::Type t = static_cast<QVariant::Type>(index.data(Qt::EditRole).userType()); | 
|---|
| 526 | const QItemEditorFactory *factory = d->f; | 
|---|
| 527 | if (factory == 0) | 
|---|
| 528 | factory = QItemEditorFactory::defaultFactory(); | 
|---|
| 529 | return factory->createEditor(t, parent); | 
|---|
| 530 | } | 
|---|
| 531 |  | 
|---|
| 532 | /*! | 
|---|
| 533 | Sets the data to be displayed and edited by the \a editor from the | 
|---|
| 534 | data model item specified by the model \a index. | 
|---|
| 535 |  | 
|---|
| 536 | The default implementation stores the data in the \a editor | 
|---|
| 537 | widget's \l {Qt's Property System} {user property}. | 
|---|
| 538 |  | 
|---|
| 539 | \sa QMetaProperty::isUser() | 
|---|
| 540 | */ | 
|---|
| 541 |  | 
|---|
| 542 | void QItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const | 
|---|
| 543 | { | 
|---|
| 544 | #ifdef QT_NO_PROPERTIES | 
|---|
| 545 | Q_UNUSED(editor); | 
|---|
| 546 | Q_UNUSED(index); | 
|---|
| 547 | #else | 
|---|
| 548 | Q_D(const QItemDelegate); | 
|---|
| 549 | QVariant v = index.data(Qt::EditRole); | 
|---|
| 550 | QByteArray n = editor->metaObject()->userProperty().name(); | 
|---|
| 551 |  | 
|---|
| 552 | // ### Qt 5: remove | 
|---|
| 553 | // A work-around for missing "USER true" in qdatetimeedit.h for | 
|---|
| 554 | // QTimeEdit's time property and QDateEdit's date property. | 
|---|
| 555 | // It only triggers if the default user property "dateTime" is | 
|---|
| 556 | // reported for QTimeEdit and QDateEdit. | 
|---|
| 557 | if (n == "dateTime") { | 
|---|
| 558 | if (editor->inherits("QTimeEdit")) | 
|---|
| 559 | n = "time"; | 
|---|
| 560 | else if (editor->inherits("QDateEdit")) | 
|---|
| 561 | n = "date"; | 
|---|
| 562 | } | 
|---|
| 563 |  | 
|---|
| 564 | // ### Qt 5: give QComboBox a USER property | 
|---|
| 565 | if (n.isEmpty() && editor->inherits("QComboBox")) | 
|---|
| 566 | n = d->editorFactory()->valuePropertyName(static_cast<QVariant::Type>(v.userType())); | 
|---|
| 567 | if (!n.isEmpty()) { | 
|---|
| 568 | if (!v.isValid()) | 
|---|
| 569 | v = QVariant(editor->property(n).userType(), (const void *)0); | 
|---|
| 570 | editor->setProperty(n, v); | 
|---|
| 571 | } | 
|---|
| 572 | #endif | 
|---|
| 573 | } | 
|---|
| 574 |  | 
|---|
| 575 | /*! | 
|---|
| 576 | Gets data drom the \a editor widget and stores it in the specified | 
|---|
| 577 | \a model at the item \a index. | 
|---|
| 578 |  | 
|---|
| 579 | The default implementation gets the value to be stored in the data | 
|---|
| 580 | model from the \a editor widget's \l {Qt's Property System} {user | 
|---|
| 581 | property}. | 
|---|
| 582 |  | 
|---|
| 583 | \sa QMetaProperty::isUser() | 
|---|
| 584 | */ | 
|---|
| 585 |  | 
|---|
| 586 | void QItemDelegate::setModelData(QWidget *editor, | 
|---|
| 587 | QAbstractItemModel *model, | 
|---|
| 588 | const QModelIndex &index) const | 
|---|
| 589 | { | 
|---|
| 590 | #ifdef QT_NO_PROPERTIES | 
|---|
| 591 | Q_UNUSED(model); | 
|---|
| 592 | Q_UNUSED(editor); | 
|---|
| 593 | Q_UNUSED(index); | 
|---|
| 594 | #else | 
|---|
| 595 | Q_D(const QItemDelegate); | 
|---|
| 596 | Q_ASSERT(model); | 
|---|
| 597 | Q_ASSERT(editor); | 
|---|
| 598 | QByteArray n = editor->metaObject()->userProperty().name(); | 
|---|
| 599 | if (n.isEmpty()) | 
|---|
| 600 | n = d->editorFactory()->valuePropertyName( | 
|---|
| 601 | static_cast<QVariant::Type>(model->data(index, Qt::EditRole).userType())); | 
|---|
| 602 | if (!n.isEmpty()) | 
|---|
| 603 | model->setData(index, editor->property(n), Qt::EditRole); | 
|---|
| 604 | #endif | 
|---|
| 605 | } | 
|---|
| 606 |  | 
|---|
| 607 | /*! | 
|---|
| 608 | Updates the \a editor for the item specified by \a index | 
|---|
| 609 | according to the style \a option given. | 
|---|
| 610 | */ | 
|---|
| 611 |  | 
|---|
| 612 | void QItemDelegate::updateEditorGeometry(QWidget *editor, | 
|---|
| 613 | const QStyleOptionViewItem &option, | 
|---|
| 614 | const QModelIndex &index) const | 
|---|
| 615 | { | 
|---|
| 616 | if (!editor) | 
|---|
| 617 | return; | 
|---|
| 618 | Q_ASSERT(index.isValid()); | 
|---|
| 619 | QPixmap pixmap = decoration(option, index.data(Qt::DecorationRole)); | 
|---|
| 620 | QString text = QItemDelegatePrivate::replaceNewLine(index.data(Qt::DisplayRole).toString()); | 
|---|
| 621 | QRect pixmapRect = QRect(QPoint(0, 0), option.decorationSize).intersected(pixmap.rect()); | 
|---|
| 622 | QRect textRect = textRectangle(0, option.rect, option.font, text); | 
|---|
| 623 | QRect checkRect = check(option, textRect, index.data(Qt::CheckStateRole)); | 
|---|
| 624 | QStyleOptionViewItem opt = option; | 
|---|
| 625 | opt.showDecorationSelected = true; // let the editor take up all available space | 
|---|
| 626 | doLayout(opt, &checkRect, &pixmapRect, &textRect, false); | 
|---|
| 627 | editor->setGeometry(textRect); | 
|---|
| 628 | } | 
|---|
| 629 |  | 
|---|
| 630 | /*! | 
|---|
| 631 | Returns the editor factory used by the item delegate. | 
|---|
| 632 | If no editor factory is set, the function will return null. | 
|---|
| 633 |  | 
|---|
| 634 | \sa setItemEditorFactory() | 
|---|
| 635 | */ | 
|---|
| 636 | QItemEditorFactory *QItemDelegate::itemEditorFactory() const | 
|---|
| 637 | { | 
|---|
| 638 | Q_D(const QItemDelegate); | 
|---|
| 639 | return d->f; | 
|---|
| 640 | } | 
|---|
| 641 |  | 
|---|
| 642 | /*! | 
|---|
| 643 | Sets the editor factory to be used by the item delegate to be the \a factory | 
|---|
| 644 | specified. If no editor factory is set, the item delegate will use the | 
|---|
| 645 | default editor factory. | 
|---|
| 646 |  | 
|---|
| 647 | \sa itemEditorFactory() | 
|---|
| 648 | */ | 
|---|
| 649 | void QItemDelegate::setItemEditorFactory(QItemEditorFactory *factory) | 
|---|
| 650 | { | 
|---|
| 651 | Q_D(QItemDelegate); | 
|---|
| 652 | d->f = factory; | 
|---|
| 653 | } | 
|---|
| 654 |  | 
|---|
| 655 | /*! | 
|---|
| 656 | Renders the item view \a text within the rectangle specified by \a rect | 
|---|
| 657 | using the given \a painter and style \a option. | 
|---|
| 658 | */ | 
|---|
| 659 |  | 
|---|
| 660 | void QItemDelegate::drawDisplay(QPainter *painter, const QStyleOptionViewItem &option, | 
|---|
| 661 | const QRect &rect, const QString &text) const | 
|---|
| 662 | { | 
|---|
| 663 | Q_D(const QItemDelegate); | 
|---|
| 664 |  | 
|---|
| 665 | QPen pen = painter->pen(); | 
|---|
| 666 | QPalette::ColorGroup cg = option.state & QStyle::State_Enabled | 
|---|
| 667 | ? QPalette::Normal : QPalette::Disabled; | 
|---|
| 668 | if (cg == QPalette::Normal && !(option.state & QStyle::State_Active)) | 
|---|
| 669 | cg = QPalette::Inactive; | 
|---|
| 670 | if (option.state & QStyle::State_Selected) { | 
|---|
| 671 | painter->fillRect(rect, option.palette.brush(cg, QPalette::Highlight)); | 
|---|
| 672 | painter->setPen(option.palette.color(cg, QPalette::HighlightedText)); | 
|---|
| 673 | } else { | 
|---|
| 674 | painter->setPen(option.palette.color(cg, QPalette::Text)); | 
|---|
| 675 | } | 
|---|
| 676 |  | 
|---|
| 677 | if (text.isEmpty()) | 
|---|
| 678 | return; | 
|---|
| 679 |  | 
|---|
| 680 | if (option.state & QStyle::State_Editing) { | 
|---|
| 681 | painter->save(); | 
|---|
| 682 | painter->setPen(option.palette.color(cg, QPalette::Text)); | 
|---|
| 683 | painter->drawRect(rect.adjusted(0, 0, -1, -1)); | 
|---|
| 684 | painter->restore(); | 
|---|
| 685 | } | 
|---|
| 686 |  | 
|---|
| 687 | const QStyleOptionViewItemV4 opt = option; | 
|---|
| 688 |  | 
|---|
| 689 | const QWidget *widget = d->widget(option); | 
|---|
| 690 | QStyle *style = widget ? widget->style() : QApplication::style(); | 
|---|
| 691 | const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, widget) + 1; | 
|---|
| 692 | QRect textRect = rect.adjusted(textMargin, 0, -textMargin, 0); // remove width padding | 
|---|
| 693 | const bool wrapText = opt.features & QStyleOptionViewItemV2::WrapText; | 
|---|
| 694 | d->textOption.setWrapMode(wrapText ? QTextOption::WordWrap : QTextOption::ManualWrap); | 
|---|
| 695 | d->textOption.setTextDirection(option.direction); | 
|---|
| 696 | d->textOption.setAlignment(QStyle::visualAlignment(option.direction, option.displayAlignment)); | 
|---|
| 697 | d->textLayout.setTextOption(d->textOption); | 
|---|
| 698 | d->textLayout.setFont(option.font); | 
|---|
| 699 | d->textLayout.setText(QItemDelegatePrivate::replaceNewLine(text)); | 
|---|
| 700 |  | 
|---|
| 701 | QSizeF textLayoutSize = d->doTextLayout(textRect.width()); | 
|---|
| 702 |  | 
|---|
| 703 | if (textRect.width() < textLayoutSize.width() | 
|---|
| 704 | || textRect.height() < textLayoutSize.height()) { | 
|---|
| 705 | QString elided; | 
|---|
| 706 | int start = 0; | 
|---|
| 707 | int end = text.indexOf(QChar::LineSeparator, start); | 
|---|
| 708 | if (end == -1) { | 
|---|
| 709 | elided += option.fontMetrics.elidedText(text, option.textElideMode, textRect.width()); | 
|---|
| 710 | } else { | 
|---|
| 711 | while (end != -1) { | 
|---|
| 712 | elided += option.fontMetrics.elidedText(text.mid(start, end - start), | 
|---|
| 713 | option.textElideMode, textRect.width()); | 
|---|
| 714 | elided += QChar::LineSeparator; | 
|---|
| 715 | start = end + 1; | 
|---|
| 716 | end = text.indexOf(QChar::LineSeparator, start); | 
|---|
| 717 | } | 
|---|
| 718 | //let's add the last line (after the last QChar::LineSeparator) | 
|---|
| 719 | elided += option.fontMetrics.elidedText(text.mid(start), | 
|---|
| 720 | option.textElideMode, textRect.width()); | 
|---|
| 721 | if (end != -1) | 
|---|
| 722 | elided += QChar::LineSeparator; | 
|---|
| 723 | } | 
|---|
| 724 | d->textLayout.setText(elided); | 
|---|
| 725 | textLayoutSize = d->doTextLayout(textRect.width()); | 
|---|
| 726 | } | 
|---|
| 727 |  | 
|---|
| 728 | const QSize layoutSize(textRect.width(), int(textLayoutSize.height())); | 
|---|
| 729 | const QRect layoutRect = QStyle::alignedRect(option.direction, option.displayAlignment, | 
|---|
| 730 | layoutSize, textRect); | 
|---|
| 731 | // if we still overflow even after eliding the text, enable clipping | 
|---|
| 732 | if (!hasClipping() && (textRect.width() < textLayoutSize.width() | 
|---|
| 733 | || textRect.height() < textLayoutSize.height())) { | 
|---|
| 734 | painter->save(); | 
|---|
| 735 | painter->setClipRect(layoutRect); | 
|---|
| 736 | d->textLayout.draw(painter, layoutRect.topLeft(), QVector<QTextLayout::FormatRange>(), layoutRect); | 
|---|
| 737 | painter->restore(); | 
|---|
| 738 | } else { | 
|---|
| 739 | d->textLayout.draw(painter, layoutRect.topLeft(), QVector<QTextLayout::FormatRange>(), layoutRect); | 
|---|
| 740 | } | 
|---|
| 741 | } | 
|---|
| 742 |  | 
|---|
| 743 | /*! | 
|---|
| 744 | Renders the decoration \a pixmap within the rectangle specified by | 
|---|
| 745 | \a rect using the given \a painter and style \a option. | 
|---|
| 746 | */ | 
|---|
| 747 | void QItemDelegate::drawDecoration(QPainter *painter, const QStyleOptionViewItem &option, | 
|---|
| 748 | const QRect &rect, const QPixmap &pixmap) const | 
|---|
| 749 | { | 
|---|
| 750 | Q_D(const QItemDelegate); | 
|---|
| 751 | // if we have an icon, we ignore the pixmap | 
|---|
| 752 | if (!d->tmp.icon.isNull()) { | 
|---|
| 753 | d->tmp.icon.paint(painter, rect, option.decorationAlignment, | 
|---|
| 754 | d->tmp.mode, d->tmp.state); | 
|---|
| 755 | return; | 
|---|
| 756 | } | 
|---|
| 757 |  | 
|---|
| 758 | if (pixmap.isNull() || !rect.isValid()) | 
|---|
| 759 | return; | 
|---|
| 760 | QPoint p = QStyle::alignedRect(option.direction, option.decorationAlignment, | 
|---|
| 761 | pixmap.size(), rect).topLeft(); | 
|---|
| 762 | if (option.state & QStyle::State_Selected) { | 
|---|
| 763 | QPixmap *pm = selected(pixmap, option.palette, option.state & QStyle::State_Enabled); | 
|---|
| 764 | painter->drawPixmap(p, *pm); | 
|---|
| 765 | } else { | 
|---|
| 766 | painter->drawPixmap(p, pixmap); | 
|---|
| 767 | } | 
|---|
| 768 | } | 
|---|
| 769 |  | 
|---|
| 770 | /*! | 
|---|
| 771 | Renders the region within the rectangle specified by \a rect, indicating | 
|---|
| 772 | that it has the focus, using the given \a painter and style \a option. | 
|---|
| 773 | */ | 
|---|
| 774 |  | 
|---|
| 775 | void QItemDelegate::drawFocus(QPainter *painter, | 
|---|
| 776 | const QStyleOptionViewItem &option, | 
|---|
| 777 | const QRect &rect) const | 
|---|
| 778 | { | 
|---|
| 779 | Q_D(const QItemDelegate); | 
|---|
| 780 | if ((option.state & QStyle::State_HasFocus) == 0 || !rect.isValid()) | 
|---|
| 781 | return; | 
|---|
| 782 | QStyleOptionFocusRect o; | 
|---|
| 783 | o.QStyleOption::operator=(option); | 
|---|
| 784 | o.rect = rect; | 
|---|
| 785 | o.state |= QStyle::State_KeyboardFocusChange; | 
|---|
| 786 | o.state |= QStyle::State_Item; | 
|---|
| 787 | QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled) | 
|---|
| 788 | ? QPalette::Normal : QPalette::Disabled; | 
|---|
| 789 | o.backgroundColor = option.palette.color(cg, (option.state & QStyle::State_Selected) | 
|---|
| 790 | ? QPalette::Highlight : QPalette::Window); | 
|---|
| 791 | const QWidget *widget = d->widget(option); | 
|---|
| 792 | QStyle *style = widget ? widget->style() : QApplication::style(); | 
|---|
| 793 | style->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter, widget); | 
|---|
| 794 | } | 
|---|
| 795 |  | 
|---|
| 796 | /*! | 
|---|
| 797 | Renders a check indicator within the rectangle specified by \a | 
|---|
| 798 | rect, using the given \a painter and style \a option, using the | 
|---|
| 799 | given \a state. | 
|---|
| 800 | */ | 
|---|
| 801 |  | 
|---|
| 802 | void QItemDelegate::drawCheck(QPainter *painter, | 
|---|
| 803 | const QStyleOptionViewItem &option, | 
|---|
| 804 | const QRect &rect, Qt::CheckState state) const | 
|---|
| 805 | { | 
|---|
| 806 | Q_D(const QItemDelegate); | 
|---|
| 807 | if (!rect.isValid()) | 
|---|
| 808 | return; | 
|---|
| 809 |  | 
|---|
| 810 | QStyleOptionViewItem opt(option); | 
|---|
| 811 | opt.rect = rect; | 
|---|
| 812 | opt.state = opt.state & ~QStyle::State_HasFocus; | 
|---|
| 813 |  | 
|---|
| 814 | switch (state) { | 
|---|
| 815 | case Qt::Unchecked: | 
|---|
| 816 | opt.state |= QStyle::State_Off; | 
|---|
| 817 | break; | 
|---|
| 818 | case Qt::PartiallyChecked: | 
|---|
| 819 | opt.state |= QStyle::State_NoChange; | 
|---|
| 820 | break; | 
|---|
| 821 | case Qt::Checked: | 
|---|
| 822 | opt.state |= QStyle::State_On; | 
|---|
| 823 | break; | 
|---|
| 824 | } | 
|---|
| 825 |  | 
|---|
| 826 | const QWidget *widget = d->widget(option); | 
|---|
| 827 | QStyle *style = widget ? widget->style() : QApplication::style(); | 
|---|
| 828 | style->drawPrimitive(QStyle::PE_IndicatorViewItemCheck, &opt, painter, widget); | 
|---|
| 829 | } | 
|---|
| 830 |  | 
|---|
| 831 | /*! | 
|---|
| 832 | \since 4.2 | 
|---|
| 833 |  | 
|---|
| 834 | Renders the item background for the given \a index, | 
|---|
| 835 | using the given \a painter and style \a option. | 
|---|
| 836 | */ | 
|---|
| 837 |  | 
|---|
| 838 | void QItemDelegate::drawBackground(QPainter *painter, | 
|---|
| 839 | const QStyleOptionViewItem &option, | 
|---|
| 840 | const QModelIndex &index) const | 
|---|
| 841 | { | 
|---|
| 842 | if (option.showDecorationSelected && (option.state & QStyle::State_Selected)) { | 
|---|
| 843 | QPalette::ColorGroup cg = option.state & QStyle::State_Enabled | 
|---|
| 844 | ? QPalette::Normal : QPalette::Disabled; | 
|---|
| 845 | if (cg == QPalette::Normal && !(option.state & QStyle::State_Active)) | 
|---|
| 846 | cg = QPalette::Inactive; | 
|---|
| 847 |  | 
|---|
| 848 | painter->fillRect(option.rect, option.palette.brush(cg, QPalette::Highlight)); | 
|---|
| 849 | } else { | 
|---|
| 850 | QVariant value = index.data(Qt::BackgroundRole); | 
|---|
| 851 | if (qVariantCanConvert<QBrush>(value)) { | 
|---|
| 852 | QPointF oldBO = painter->brushOrigin(); | 
|---|
| 853 | painter->setBrushOrigin(option.rect.topLeft()); | 
|---|
| 854 | painter->fillRect(option.rect, qvariant_cast<QBrush>(value)); | 
|---|
| 855 | painter->setBrushOrigin(oldBO); | 
|---|
| 856 | } | 
|---|
| 857 | } | 
|---|
| 858 | } | 
|---|
| 859 |  | 
|---|
| 860 |  | 
|---|
| 861 | /*! | 
|---|
| 862 | \internal | 
|---|
| 863 | */ | 
|---|
| 864 |  | 
|---|
| 865 | void QItemDelegate::doLayout(const QStyleOptionViewItem &option, | 
|---|
| 866 | QRect *checkRect, QRect *pixmapRect, QRect *textRect, | 
|---|
| 867 | bool hint) const | 
|---|
| 868 | { | 
|---|
| 869 | Q_ASSERT(checkRect && pixmapRect && textRect); | 
|---|
| 870 | Q_D(const QItemDelegate); | 
|---|
| 871 | const QWidget *widget = d->widget(option); | 
|---|
| 872 | QStyle *style = widget ? widget->style() : QApplication::style(); | 
|---|
| 873 | const bool hasCheck = checkRect->isValid(); | 
|---|
| 874 | const bool hasPixmap = pixmapRect->isValid(); | 
|---|
| 875 | const bool hasText = textRect->isValid(); | 
|---|
| 876 | const int textMargin = hasText ? style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, widget) + 1 : 0; | 
|---|
| 877 | const int pixmapMargin = hasPixmap ? style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, widget) + 1 : 0; | 
|---|
| 878 | const int checkMargin = hasCheck ? style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, widget) + 1 : 0; | 
|---|
| 879 | int x = option.rect.left(); | 
|---|
| 880 | int y = option.rect.top(); | 
|---|
| 881 | int w, h; | 
|---|
| 882 |  | 
|---|
| 883 | textRect->adjust(-textMargin, 0, textMargin, 0); // add width padding | 
|---|
| 884 | if (textRect->height() == 0 && !hasPixmap) | 
|---|
| 885 | textRect->setHeight(option.fontMetrics.height()); | 
|---|
| 886 |  | 
|---|
| 887 | QSize pm(0, 0); | 
|---|
| 888 | if (hasPixmap) { | 
|---|
| 889 | pm = pixmapRect->size(); | 
|---|
| 890 | pm.rwidth() += 2 * pixmapMargin; | 
|---|
| 891 | } | 
|---|
| 892 | if (hint) { | 
|---|
| 893 | h = qMax(checkRect->height(), qMax(textRect->height(), pm.height())); | 
|---|
| 894 | if (option.decorationPosition == QStyleOptionViewItem::Left | 
|---|
| 895 | || option.decorationPosition == QStyleOptionViewItem::Right) { | 
|---|
| 896 | w = textRect->width() + pm.width(); | 
|---|
| 897 | } else { | 
|---|
| 898 | w = qMax(textRect->width(), pm.width()); | 
|---|
| 899 | } | 
|---|
| 900 | } else { | 
|---|
| 901 | w = option.rect.width(); | 
|---|
| 902 | h = option.rect.height(); | 
|---|
| 903 | } | 
|---|
| 904 |  | 
|---|
| 905 | int cw = 0; | 
|---|
| 906 | QRect check; | 
|---|
| 907 | if (hasCheck) { | 
|---|
| 908 | cw = checkRect->width() + 2 * checkMargin; | 
|---|
| 909 | if (hint) w += cw; | 
|---|
| 910 | if (option.direction == Qt::RightToLeft) { | 
|---|
| 911 | check.setRect(x + w - cw, y, cw, h); | 
|---|
| 912 | } else { | 
|---|
| 913 | check.setRect(x + checkMargin, y, cw, h); | 
|---|
| 914 | } | 
|---|
| 915 | } | 
|---|
| 916 |  | 
|---|
| 917 | // at this point w should be the *total* width | 
|---|
| 918 |  | 
|---|
| 919 | QRect display; | 
|---|
| 920 | QRect decoration; | 
|---|
| 921 | switch (option.decorationPosition) { | 
|---|
| 922 | case QStyleOptionViewItem::Top: { | 
|---|
| 923 | if (hasPixmap) | 
|---|
| 924 | pm.setHeight(pm.height() + pixmapMargin); // add space | 
|---|
| 925 | h = hint ? textRect->height() : h - pm.height(); | 
|---|
| 926 |  | 
|---|
| 927 | if (option.direction == Qt::RightToLeft) { | 
|---|
| 928 | decoration.setRect(x, y, w - cw, pm.height()); | 
|---|
| 929 | display.setRect(x, y + pm.height(), w - cw, h); | 
|---|
| 930 | } else { | 
|---|
| 931 | decoration.setRect(x + cw, y, w - cw, pm.height()); | 
|---|
| 932 | display.setRect(x + cw, y + pm.height(), w - cw, h); | 
|---|
| 933 | } | 
|---|
| 934 | break; } | 
|---|
| 935 | case QStyleOptionViewItem::Bottom: { | 
|---|
| 936 | if (hasText) | 
|---|
| 937 | textRect->setHeight(textRect->height() + textMargin); // add space | 
|---|
| 938 | h = hint ? textRect->height() + pm.height() : h; | 
|---|
| 939 |  | 
|---|
| 940 | if (option.direction == Qt::RightToLeft) { | 
|---|
| 941 | display.setRect(x, y, w - cw, textRect->height()); | 
|---|
| 942 | decoration.setRect(x, y + textRect->height(), w - cw, h - textRect->height()); | 
|---|
| 943 | } else { | 
|---|
| 944 | display.setRect(x + cw, y, w - cw, textRect->height()); | 
|---|
| 945 | decoration.setRect(x + cw, y + textRect->height(), w - cw, h - textRect->height()); | 
|---|
| 946 | } | 
|---|
| 947 | break; } | 
|---|
| 948 | case QStyleOptionViewItem::Left: { | 
|---|
| 949 | if (option.direction == Qt::LeftToRight) { | 
|---|
| 950 | decoration.setRect(x + cw, y, pm.width(), h); | 
|---|
| 951 | display.setRect(decoration.right() + 1, y, w - pm.width() - cw, h); | 
|---|
| 952 | } else { | 
|---|
| 953 | display.setRect(x, y, w - pm.width() - cw, h); | 
|---|
| 954 | decoration.setRect(display.right() + 1, y, pm.width(), h); | 
|---|
| 955 | } | 
|---|
| 956 | break; } | 
|---|
| 957 | case QStyleOptionViewItem::Right: { | 
|---|
| 958 | if (option.direction == Qt::LeftToRight) { | 
|---|
| 959 | display.setRect(x + cw, y, w - pm.width() - cw, h); | 
|---|
| 960 | decoration.setRect(display.right() + 1, y, pm.width(), h); | 
|---|
| 961 | } else { | 
|---|
| 962 | decoration.setRect(x, y, pm.width(), h); | 
|---|
| 963 | display.setRect(decoration.right() + 1, y, w - pm.width() - cw, h); | 
|---|
| 964 | } | 
|---|
| 965 | break; } | 
|---|
| 966 | default: | 
|---|
| 967 | qWarning("doLayout: decoration position is invalid"); | 
|---|
| 968 | decoration = *pixmapRect; | 
|---|
| 969 | break; | 
|---|
| 970 | } | 
|---|
| 971 |  | 
|---|
| 972 | if (!hint) { // we only need to do the internal layout if we are going to paint | 
|---|
| 973 | *checkRect = QStyle::alignedRect(option.direction, Qt::AlignCenter, | 
|---|
| 974 | checkRect->size(), check); | 
|---|
| 975 | *pixmapRect = QStyle::alignedRect(option.direction, option.decorationAlignment, | 
|---|
| 976 | pixmapRect->size(), decoration); | 
|---|
| 977 | // the text takes up all available space, unless the decoration is not shown as selected | 
|---|
| 978 | if (option.showDecorationSelected) | 
|---|
| 979 | *textRect = display; | 
|---|
| 980 | else | 
|---|
| 981 | *textRect = QStyle::alignedRect(option.direction, option.displayAlignment, | 
|---|
| 982 | textRect->size().boundedTo(display.size()), display); | 
|---|
| 983 | } else { | 
|---|
| 984 | *checkRect = check; | 
|---|
| 985 | *pixmapRect = decoration; | 
|---|
| 986 | *textRect = display; | 
|---|
| 987 | } | 
|---|
| 988 | } | 
|---|
| 989 |  | 
|---|
| 990 | /*! | 
|---|
| 991 | \internal | 
|---|
| 992 |  | 
|---|
| 993 | Returns the pixmap used to decorate the root of the item view. | 
|---|
| 994 | The style \a option controls the appearance of the root; the \a variant | 
|---|
| 995 | refers to the data associated with an item. | 
|---|
| 996 | */ | 
|---|
| 997 |  | 
|---|
| 998 | QPixmap QItemDelegate::decoration(const QStyleOptionViewItem &option, const QVariant &variant) const | 
|---|
| 999 | { | 
|---|
| 1000 | Q_D(const QItemDelegate); | 
|---|
| 1001 | switch (variant.type()) { | 
|---|
| 1002 | case QVariant::Icon: { | 
|---|
| 1003 | QIcon::Mode mode = d->iconMode(option.state); | 
|---|
| 1004 | QIcon::State state = d->iconState(option.state); | 
|---|
| 1005 | return qvariant_cast<QIcon>(variant).pixmap(option.decorationSize, mode, state); } | 
|---|
| 1006 | case QVariant::Color: { | 
|---|
| 1007 | static QPixmap pixmap(option.decorationSize); | 
|---|
| 1008 | pixmap.fill(qvariant_cast<QColor>(variant)); | 
|---|
| 1009 | return pixmap; } | 
|---|
| 1010 | default: | 
|---|
| 1011 | break; | 
|---|
| 1012 | } | 
|---|
| 1013 |  | 
|---|
| 1014 | return qvariant_cast<QPixmap>(variant); | 
|---|
| 1015 | } | 
|---|
| 1016 |  | 
|---|
| 1017 | // hacky but faster version of "QString::sprintf("%d-%d", i, enabled)" | 
|---|
| 1018 | static QString qPixmapSerial(quint64 i, bool enabled) | 
|---|
| 1019 | { | 
|---|
| 1020 | ushort arr[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', '0' + enabled }; | 
|---|
| 1021 | ushort *ptr = &arr[16]; | 
|---|
| 1022 |  | 
|---|
| 1023 | while (i > 0) { | 
|---|
| 1024 | // hey - it's our internal representation, so use the ascii character after '9' | 
|---|
| 1025 | // instead of 'a' for hex | 
|---|
| 1026 | *(--ptr) = '0' + i % 16; | 
|---|
| 1027 | i >>= 4; | 
|---|
| 1028 | } | 
|---|
| 1029 |  | 
|---|
| 1030 | return QString::fromUtf16(ptr, int(&arr[sizeof(arr) / sizeof(ushort)] - ptr)); | 
|---|
| 1031 | } | 
|---|
| 1032 |  | 
|---|
| 1033 | /*! | 
|---|
| 1034 | \internal | 
|---|
| 1035 | Returns the selected version of the given \a pixmap using the given \a palette. | 
|---|
| 1036 | The \a enabled argument decides whether the normal or disabled highlight color of | 
|---|
| 1037 | the palette is used. | 
|---|
| 1038 | */ | 
|---|
| 1039 | QPixmap *QItemDelegate::selected(const QPixmap &pixmap, const QPalette &palette, bool enabled) const | 
|---|
| 1040 | { | 
|---|
| 1041 | QString key = qPixmapSerial(qt_pixmap_id(pixmap), enabled); | 
|---|
| 1042 | QPixmap *pm = QPixmapCache::find(key); | 
|---|
| 1043 | if (!pm) { | 
|---|
| 1044 | QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied); | 
|---|
| 1045 |  | 
|---|
| 1046 | QColor color = palette.color(enabled ? QPalette::Normal : QPalette::Disabled, | 
|---|
| 1047 | QPalette::Highlight); | 
|---|
| 1048 | color.setAlphaF((qreal)0.3); | 
|---|
| 1049 |  | 
|---|
| 1050 | QPainter painter(&img); | 
|---|
| 1051 | painter.setCompositionMode(QPainter::CompositionMode_SourceAtop); | 
|---|
| 1052 | painter.fillRect(0, 0, img.width(), img.height(), color); | 
|---|
| 1053 | painter.end(); | 
|---|
| 1054 |  | 
|---|
| 1055 | QPixmap selected = QPixmap(QPixmap::fromImage(img)); | 
|---|
| 1056 | int n = (img.numBytes() >> 10) + 1; | 
|---|
| 1057 | if (QPixmapCache::cacheLimit() < n) | 
|---|
| 1058 | QPixmapCache::setCacheLimit(n); | 
|---|
| 1059 |  | 
|---|
| 1060 | QPixmapCache::insert(key, selected); | 
|---|
| 1061 | pm = QPixmapCache::find(key); | 
|---|
| 1062 | } | 
|---|
| 1063 | return pm; | 
|---|
| 1064 | } | 
|---|
| 1065 |  | 
|---|
| 1066 | /*! | 
|---|
| 1067 | \internal | 
|---|
| 1068 | */ | 
|---|
| 1069 |  | 
|---|
| 1070 | QRect QItemDelegate::rect(const QStyleOptionViewItem &option, | 
|---|
| 1071 | const QModelIndex &index, int role) const | 
|---|
| 1072 | { | 
|---|
| 1073 | Q_D(const QItemDelegate); | 
|---|
| 1074 | QVariant value = index.data(role); | 
|---|
| 1075 | if (role == Qt::CheckStateRole) | 
|---|
| 1076 | return check(option, option.rect, value); | 
|---|
| 1077 | if (value.isValid() && !value.isNull()) { | 
|---|
| 1078 | switch (value.type()) { | 
|---|
| 1079 | case QVariant::Invalid: | 
|---|
| 1080 | break; | 
|---|
| 1081 | case QVariant::Pixmap: | 
|---|
| 1082 | return QRect(QPoint(0, 0), qvariant_cast<QPixmap>(value).size()); | 
|---|
| 1083 | case QVariant::Image: | 
|---|
| 1084 | return QRect(QPoint(0, 0), qvariant_cast<QImage>(value).size()); | 
|---|
| 1085 | case QVariant::Icon: { | 
|---|
| 1086 | QIcon::Mode mode = d->iconMode(option.state); | 
|---|
| 1087 | QIcon::State state = d->iconState(option.state); | 
|---|
| 1088 | QIcon icon = qvariant_cast<QIcon>(value); | 
|---|
| 1089 | QSize size = icon.actualSize(option.decorationSize, mode, state); | 
|---|
| 1090 | return QRect(QPoint(0, 0), size); } | 
|---|
| 1091 | case QVariant::Color: | 
|---|
| 1092 | return QRect(QPoint(0, 0), option.decorationSize); | 
|---|
| 1093 | case QVariant::String: | 
|---|
| 1094 | default: { | 
|---|
| 1095 | QString text = QItemDelegatePrivate::valueToText(value, option); | 
|---|
| 1096 | value = index.data(Qt::FontRole); | 
|---|
| 1097 | QFont fnt = qvariant_cast<QFont>(value).resolve(option.font); | 
|---|
| 1098 | return textRectangle(0, d->textLayoutBounds(option), fnt, text); } | 
|---|
| 1099 | } | 
|---|
| 1100 | } | 
|---|
| 1101 | return QRect(); | 
|---|
| 1102 | } | 
|---|
| 1103 |  | 
|---|
| 1104 | /*! | 
|---|
| 1105 | \internal | 
|---|
| 1106 |  | 
|---|
| 1107 | Note that on Mac, if /usr/include/AssertMacros.h is included prior | 
|---|
| 1108 | to QItemDelegate, and the application is building in debug mode, the | 
|---|
| 1109 | check(assertion) will conflict with QItemDelegate::check. | 
|---|
| 1110 |  | 
|---|
| 1111 | To avoid this problem, add | 
|---|
| 1112 |  | 
|---|
| 1113 | #ifdef check | 
|---|
| 1114 | #undef check | 
|---|
| 1115 | #endif | 
|---|
| 1116 |  | 
|---|
| 1117 | after including AssertMacros.h | 
|---|
| 1118 | */ | 
|---|
| 1119 | QRect QItemDelegate::check(const QStyleOptionViewItem &option, | 
|---|
| 1120 | const QRect &bounding, const QVariant &value) const | 
|---|
| 1121 | { | 
|---|
| 1122 | if (value.isValid()) { | 
|---|
| 1123 | Q_D(const QItemDelegate); | 
|---|
| 1124 | QStyleOptionButton opt; | 
|---|
| 1125 | opt.QStyleOption::operator=(option); | 
|---|
| 1126 | opt.rect = bounding; | 
|---|
| 1127 | const QWidget *widget = d->widget(option); // cast | 
|---|
| 1128 | QStyle *style = widget ? widget->style() : QApplication::style(); | 
|---|
| 1129 | return style->subElementRect(QStyle::SE_ViewItemCheckIndicator, &opt, widget); | 
|---|
| 1130 | } | 
|---|
| 1131 | return QRect(); | 
|---|
| 1132 | } | 
|---|
| 1133 |  | 
|---|
| 1134 | /*! | 
|---|
| 1135 | \internal | 
|---|
| 1136 | */ | 
|---|
| 1137 | QRect QItemDelegate::textRectangle(QPainter * /*painter*/, const QRect &rect, | 
|---|
| 1138 | const QFont &font, const QString &text) const | 
|---|
| 1139 | { | 
|---|
| 1140 | Q_D(const QItemDelegate); | 
|---|
| 1141 | d->textOption.setWrapMode(QTextOption::WordWrap); | 
|---|
| 1142 | d->textLayout.setTextOption(d->textOption); | 
|---|
| 1143 | d->textLayout.setFont(font); | 
|---|
| 1144 | d->textLayout.setText(QItemDelegatePrivate::replaceNewLine(text)); | 
|---|
| 1145 | const QSize size = d->doTextLayout(rect.width()).toSize(); | 
|---|
| 1146 | // ###: textRectangle should take style option as argument | 
|---|
| 1147 | const int textMargin = QApplication::style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; | 
|---|
| 1148 | return QRect(0, 0, size.width() + 2 * textMargin, size.height()); | 
|---|
| 1149 | } | 
|---|
| 1150 |  | 
|---|
| 1151 | /*! | 
|---|
| 1152 | \fn bool QItemDelegate::eventFilter(QObject *editor, QEvent *event) | 
|---|
| 1153 |  | 
|---|
| 1154 | Returns true if the given \a editor is a valid QWidget and the | 
|---|
| 1155 | given \a event is handled; otherwise returns false. The following | 
|---|
| 1156 | key press events are handled by default: | 
|---|
| 1157 |  | 
|---|
| 1158 | \list | 
|---|
| 1159 | \o \gui Tab | 
|---|
| 1160 | \o \gui Backtab | 
|---|
| 1161 | \o \gui Enter | 
|---|
| 1162 | \o \gui Return | 
|---|
| 1163 | \o \gui Esc | 
|---|
| 1164 | \endlist | 
|---|
| 1165 |  | 
|---|
| 1166 | In the case of \gui Tab, \gui Backtab, \gui Enter and \gui Return | 
|---|
| 1167 | key press events, the \a editor's data is comitted to the model | 
|---|
| 1168 | and the editor is closed. If the \a event is a \gui Tab key press | 
|---|
| 1169 | the view will open an editor on the next item in the | 
|---|
| 1170 | view. Likewise, if the \a event is a \gui Backtab key press the | 
|---|
| 1171 | view will open an editor on the \e previous item in the view. | 
|---|
| 1172 |  | 
|---|
| 1173 | If the event is a \gui Esc key press event, the \a editor is | 
|---|
| 1174 | closed \e without committing its data. | 
|---|
| 1175 |  | 
|---|
| 1176 | \sa commitData(), closeEditor() | 
|---|
| 1177 | */ | 
|---|
| 1178 |  | 
|---|
| 1179 | bool QItemDelegate::eventFilter(QObject *object, QEvent *event) | 
|---|
| 1180 | { | 
|---|
| 1181 | QWidget *editor = qobject_cast<QWidget*>(object); | 
|---|
| 1182 | if (!editor) | 
|---|
| 1183 | return false; | 
|---|
| 1184 | if (event->type() == QEvent::KeyPress) { | 
|---|
| 1185 | switch (static_cast<QKeyEvent *>(event)->key()) { | 
|---|
| 1186 | case Qt::Key_Tab: | 
|---|
| 1187 | emit commitData(editor); | 
|---|
| 1188 | emit closeEditor(editor, QAbstractItemDelegate::EditNextItem); | 
|---|
| 1189 | return true; | 
|---|
| 1190 | case Qt::Key_Backtab: | 
|---|
| 1191 | emit commitData(editor); | 
|---|
| 1192 | emit closeEditor(editor, QAbstractItemDelegate::EditPreviousItem); | 
|---|
| 1193 | return true; | 
|---|
| 1194 | case Qt::Key_Enter: | 
|---|
| 1195 | case Qt::Key_Return: | 
|---|
| 1196 | #ifndef QT_NO_TEXTEDIT | 
|---|
| 1197 | if (qobject_cast<QTextEdit*>(editor)) | 
|---|
| 1198 | return false; // don't filter enter key events for QTextEdit | 
|---|
| 1199 | // We want the editor to be able to process the key press | 
|---|
| 1200 | // before committing the data (e.g. so it can do | 
|---|
| 1201 | // validation/fixup of the input). | 
|---|
| 1202 | #endif // QT_NO_TEXTEDIT | 
|---|
| 1203 | #ifndef QT_NO_LINEEDIT | 
|---|
| 1204 | if (QLineEdit *e = qobject_cast<QLineEdit*>(editor)) | 
|---|
| 1205 | if (!e->hasAcceptableInput()) | 
|---|
| 1206 | return false; | 
|---|
| 1207 | #endif // QT_NO_LINEEDIT | 
|---|
| 1208 | QMetaObject::invokeMethod(this, "_q_commitDataAndCloseEditor", | 
|---|
| 1209 | Qt::QueuedConnection, Q_ARG(QWidget*, editor)); | 
|---|
| 1210 | return false; | 
|---|
| 1211 | case Qt::Key_Escape: | 
|---|
| 1212 | // don't commit data | 
|---|
| 1213 | emit closeEditor(editor, QAbstractItemDelegate::RevertModelCache); | 
|---|
| 1214 | break; | 
|---|
| 1215 | default: | 
|---|
| 1216 | return false; | 
|---|
| 1217 | } | 
|---|
| 1218 | if (editor->parentWidget()) | 
|---|
| 1219 | editor->parentWidget()->setFocus(); | 
|---|
| 1220 | return true; | 
|---|
| 1221 | } else if (event->type() == QEvent::FocusOut || event->type() == QEvent::Hide) { | 
|---|
| 1222 | //the Hide event will take care of he editors that are in fact complete dialogs | 
|---|
| 1223 | if (!editor->isActiveWindow() || (QApplication::focusWidget() != editor)) { | 
|---|
| 1224 | QWidget *w = QApplication::focusWidget(); | 
|---|
| 1225 | while (w) { // don't worry about focus changes internally in the editor | 
|---|
| 1226 | if (w == editor) | 
|---|
| 1227 | return false; | 
|---|
| 1228 | w = w->parentWidget(); | 
|---|
| 1229 | } | 
|---|
| 1230 | #ifndef QT_NO_DRAGANDDROP | 
|---|
| 1231 | // The window may lose focus during an drag operation. | 
|---|
| 1232 | // i.e when dragging involves the taskbar on Windows. | 
|---|
| 1233 | if (QDragManager::self() && QDragManager::self()->object != 0) | 
|---|
| 1234 | return false; | 
|---|
| 1235 | #endif | 
|---|
| 1236 | // Opening a modal dialog will start a new eventloop | 
|---|
| 1237 | // that will process the deleteLater event. | 
|---|
| 1238 | if (QApplication::activeModalWidget() | 
|---|
| 1239 | && !QApplication::activeModalWidget()->isAncestorOf(editor) | 
|---|
| 1240 | && qobject_cast<QDialog*>(QApplication::activeModalWidget())) | 
|---|
| 1241 | return false; | 
|---|
| 1242 | emit commitData(editor); | 
|---|
| 1243 | emit closeEditor(editor, NoHint); | 
|---|
| 1244 | } | 
|---|
| 1245 | } else if (event->type() == QEvent::ShortcutOverride) { | 
|---|
| 1246 | if (static_cast<QKeyEvent*>(event)->key() == Qt::Key_Escape) { | 
|---|
| 1247 | event->accept(); | 
|---|
| 1248 | return true; | 
|---|
| 1249 | } | 
|---|
| 1250 | } | 
|---|
| 1251 | return false; | 
|---|
| 1252 | } | 
|---|
| 1253 |  | 
|---|
| 1254 | /*! | 
|---|
| 1255 | \reimp | 
|---|
| 1256 | */ | 
|---|
| 1257 |  | 
|---|
| 1258 | bool QItemDelegate::editorEvent(QEvent *event, | 
|---|
| 1259 | QAbstractItemModel *model, | 
|---|
| 1260 | const QStyleOptionViewItem &option, | 
|---|
| 1261 | const QModelIndex &index) | 
|---|
| 1262 | { | 
|---|
| 1263 | Q_ASSERT(event); | 
|---|
| 1264 | Q_ASSERT(model); | 
|---|
| 1265 |  | 
|---|
| 1266 | // make sure that the item is checkable | 
|---|
| 1267 | Qt::ItemFlags flags = model->flags(index); | 
|---|
| 1268 | if (!(flags & Qt::ItemIsUserCheckable) || !(option.state & QStyle::State_Enabled) | 
|---|
| 1269 | || !(flags & Qt::ItemIsEnabled)) | 
|---|
| 1270 | return false; | 
|---|
| 1271 |  | 
|---|
| 1272 | // make sure that we have a check state | 
|---|
| 1273 | QVariant value = index.data(Qt::CheckStateRole); | 
|---|
| 1274 | if (!value.isValid()) | 
|---|
| 1275 | return false; | 
|---|
| 1276 |  | 
|---|
| 1277 | // make sure that we have the right event type | 
|---|
| 1278 | if ((event->type() == QEvent::MouseButtonRelease) | 
|---|
| 1279 | || (event->type() == QEvent::MouseButtonDblClick)) { | 
|---|
| 1280 | QRect checkRect = check(option, option.rect, Qt::Checked); | 
|---|
| 1281 | QRect emptyRect; | 
|---|
| 1282 | doLayout(option, &checkRect, &emptyRect, &emptyRect, false); | 
|---|
| 1283 | QMouseEvent *me = static_cast<QMouseEvent*>(event); | 
|---|
| 1284 | if (me->button() != Qt::LeftButton || !checkRect.contains(me->pos())) | 
|---|
| 1285 | return false; | 
|---|
| 1286 |  | 
|---|
| 1287 | // eat the double click events inside the check rect | 
|---|
| 1288 | if (event->type() == QEvent::MouseButtonDblClick) | 
|---|
| 1289 | return true; | 
|---|
| 1290 |  | 
|---|
| 1291 | } else if (event->type() == QEvent::KeyPress) { | 
|---|
| 1292 | if (static_cast<QKeyEvent*>(event)->key() != Qt::Key_Space | 
|---|
| 1293 | && static_cast<QKeyEvent*>(event)->key() != Qt::Key_Select) | 
|---|
| 1294 | return false; | 
|---|
| 1295 | } else { | 
|---|
| 1296 | return false; | 
|---|
| 1297 | } | 
|---|
| 1298 |  | 
|---|
| 1299 | Qt::CheckState state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked | 
|---|
| 1300 | ? Qt::Unchecked : Qt::Checked); | 
|---|
| 1301 | return model->setData(index, state, Qt::CheckStateRole); | 
|---|
| 1302 | } | 
|---|
| 1303 |  | 
|---|
| 1304 | /*! | 
|---|
| 1305 | \internal | 
|---|
| 1306 | */ | 
|---|
| 1307 |  | 
|---|
| 1308 | QStyleOptionViewItem QItemDelegate::setOptions(const QModelIndex &index, | 
|---|
| 1309 | const QStyleOptionViewItem &option) const | 
|---|
| 1310 | { | 
|---|
| 1311 | QStyleOptionViewItem opt = option; | 
|---|
| 1312 |  | 
|---|
| 1313 | // set font | 
|---|
| 1314 | QVariant value = index.data(Qt::FontRole); | 
|---|
| 1315 | if (value.isValid()){ | 
|---|
| 1316 | opt.font = qvariant_cast<QFont>(value).resolve(opt.font); | 
|---|
| 1317 | opt.fontMetrics = QFontMetrics(opt.font); | 
|---|
| 1318 | } | 
|---|
| 1319 |  | 
|---|
| 1320 | // set text alignment | 
|---|
| 1321 | value = index.data(Qt::TextAlignmentRole); | 
|---|
| 1322 | if (value.isValid()) | 
|---|
| 1323 | opt.displayAlignment = (Qt::Alignment)value.toInt(); | 
|---|
| 1324 |  | 
|---|
| 1325 | // set foreground brush | 
|---|
| 1326 | value = index.data(Qt::ForegroundRole); | 
|---|
| 1327 | if (qVariantCanConvert<QBrush>(value)) | 
|---|
| 1328 | opt.palette.setBrush(QPalette::Text, qvariant_cast<QBrush>(value)); | 
|---|
| 1329 |  | 
|---|
| 1330 | return opt; | 
|---|
| 1331 | } | 
|---|
| 1332 |  | 
|---|
| 1333 | QT_END_NAMESPACE | 
|---|
| 1334 |  | 
|---|
| 1335 | #include "moc_qitemdelegate.cpp" | 
|---|
| 1336 |  | 
|---|
| 1337 | #endif // QT_NO_ITEMVIEWS | 
|---|