source: trunk/src/gui/itemviews/qitemeditorfactory.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 17.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this 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 have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include <qplatformdefs.h>
43#include "qitemeditorfactory.h"
44#include "qitemeditorfactory_p.h"
45
46#ifndef QT_NO_ITEMVIEWS
47
48#include <qcombobox.h>
49#include <qdatetimeedit.h>
50#include <qlabel.h>
51#include <qlineedit.h>
52#include <qspinbox.h>
53#include <limits.h>
54#include <float.h>
55#include <qapplication.h>
56#include <qdebug.h>
57
58QT_BEGIN_NAMESPACE
59
60
61#ifndef QT_NO_COMBOBOX
62
63class QBooleanComboBox : public QComboBox
64{
65 Q_OBJECT
66 Q_PROPERTY(bool value READ value WRITE setValue USER true)
67
68public:
69 QBooleanComboBox(QWidget *parent);
70 void setValue(bool);
71 bool value() const;
72};
73
74#endif // QT_NO_COMBOBOX
75
76/*!
77 \class QItemEditorFactory
78 \brief The QItemEditorFactory class provides widgets for editing item data
79 in views and delegates.
80 \since 4.2
81 \ingroup model-view
82
83 When editing data in an item view, editors are created and
84 displayed by a delegate. QItemDelegate, which is the delegate by
85 default installed on Qt's item views, uses a QItemEditorFactory to
86 create editors for it. A default unique instance provided by
87 QItemEditorFactory is used by all item delegates. If you set a
88 new default factory with setDefaultFactory(), the new factory will
89 be used by existing and new delegates.
90
91 A factory keeps a collection of QItemEditorCreatorBase
92 instances, which are specialized editors that produce editors
93 for one particular QVariant data type (All Qt models store
94 their data in \l{QVariant}s).
95
96 \section1 Standard Editing Widgets
97
98 The standard factory implementation provides editors for a variety of data
99 types. These are created whenever a delegate needs to provide an editor for
100 data supplied by a model. The following table shows the relationship between
101 types and the standard editors provided.
102
103 \table
104 \header \o Type \o Editor Widget
105 \row \o bool \o QComboBox
106 \row \o double \o QDoubleSpinBox
107 \row \o int \o{1,2} QSpinBox
108 \row \o unsigned int
109 \row \o QDate \o QDateEdit
110 \row \o QDateTime \o QDateTimeEdit
111 \row \o QPixmap \o QLabel
112 \row \o QString \o QLineEdit
113 \row \o QTime \o QTimeEdit
114 \endtable
115
116 Additional editors can be registered with the registerEditor() function.
117
118 \sa QItemDelegate, {Model/View Programming}, {Color Editor Factory Example}
119*/
120
121/*!
122 \fn QItemEditorFactory::QItemEditorFactory()
123
124 Constructs a new item editor factory.
125*/
126
127/*!
128 Creates an editor widget with the given \a parent for the specified \a type of data,
129 and returns it as a QWidget.
130
131 \sa registerEditor()
132*/
133QWidget *QItemEditorFactory::createEditor(QVariant::Type type, QWidget *parent) const
134{
135 QItemEditorCreatorBase *creator = creatorMap.value(type, 0);
136 if (!creator) {
137 const QItemEditorFactory *dfactory = defaultFactory();
138 return dfactory == this ? 0 : dfactory->createEditor(type, parent);
139 }
140 return creator->createWidget(parent);
141}
142
143/*!
144 Returns the property name used to access data for the given \a type of data.
145*/
146QByteArray QItemEditorFactory::valuePropertyName(QVariant::Type type) const
147{
148 QItemEditorCreatorBase *creator = creatorMap.value(type, 0);
149 if (!creator) {
150 const QItemEditorFactory *dfactory = defaultFactory();
151 return dfactory == this ? QByteArray() : dfactory->valuePropertyName(type);
152 }
153 return creator->valuePropertyName();
154}
155
156/*!
157 Destroys the item editor factory.
158*/
159QItemEditorFactory::~QItemEditorFactory()
160{
161 //we make sure we delete all the QItemEditorCreatorBase
162 //this has to be done only once, hence the QSet
163 QSet<QItemEditorCreatorBase*> set = creatorMap.values().toSet();
164 qDeleteAll(set);
165}
166
167/*!
168 Registers an item editor creator specified by \a creator for the given \a type of data.
169
170 \bold{Note:} The factory takes ownership of the item editor creator and will destroy
171 it if a new creator for the same type is registered later.
172
173 \sa createEditor()
174*/
175void QItemEditorFactory::registerEditor(QVariant::Type type, QItemEditorCreatorBase *creator)
176{
177 QHash<QVariant::Type, QItemEditorCreatorBase *>::iterator it = creatorMap.find(type);
178 if (it != creatorMap.end()) {
179 QItemEditorCreatorBase *oldCreator = it.value();
180 Q_ASSERT(oldCreator);
181 creatorMap.erase(it);
182 if (!creatorMap.values().contains(oldCreator))
183 delete oldCreator; // if it is no more in use we can delete it
184 }
185
186 creatorMap[type] = creator;
187}
188
189class QDefaultItemEditorFactory : public QItemEditorFactory
190{
191public:
192 inline QDefaultItemEditorFactory() {}
193 QWidget *createEditor(QVariant::Type type, QWidget *parent) const;
194 QByteArray valuePropertyName(QVariant::Type) const;
195};
196
197QWidget *QDefaultItemEditorFactory::createEditor(QVariant::Type type, QWidget *parent) const
198{
199 switch (type) {
200#ifndef QT_NO_COMBOBOX
201 case QVariant::Bool: {
202 QBooleanComboBox *cb = new QBooleanComboBox(parent);
203 cb->setFrame(false);
204 return cb; }
205#endif
206#ifndef QT_NO_SPINBOX
207 case QVariant::UInt: {
208 QSpinBox *sb = new QSpinBox(parent);
209 sb->setFrame(false);
210 sb->setMaximum(INT_MAX);
211 return sb; }
212 case QVariant::Int: {
213 QSpinBox *sb = new QSpinBox(parent);
214 sb->setFrame(false);
215 sb->setMinimum(INT_MIN);
216 sb->setMaximum(INT_MAX);
217 return sb; }
218#endif
219#ifndef QT_NO_DATETIMEEDIT
220 case QVariant::Date: {
221 QDateTimeEdit *ed = new QDateEdit(parent);
222 ed->setFrame(false);
223 return ed; }
224 case QVariant::Time: {
225 QDateTimeEdit *ed = new QTimeEdit(parent);
226 ed->setFrame(false);
227 return ed; }
228 case QVariant::DateTime: {
229 QDateTimeEdit *ed = new QDateTimeEdit(parent);
230 ed->setFrame(false);
231 return ed; }
232#endif
233 case QVariant::Pixmap:
234 return new QLabel(parent);
235#ifndef QT_NO_SPINBOX
236 case QVariant::Double: {
237 QDoubleSpinBox *sb = new QDoubleSpinBox(parent);
238 sb->setFrame(false);
239 sb->setMinimum(-DBL_MAX);
240 sb->setMaximum(DBL_MAX);
241 return sb; }
242#endif
243#ifndef QT_NO_LINEEDIT
244 case QVariant::String:
245 default: {
246 // the default editor is a lineedit
247 QExpandingLineEdit *le = new QExpandingLineEdit(parent);
248 le->setFrame(le->style()->styleHint(QStyle::SH_ItemView_DrawDelegateFrame, 0, le));
249 if (!le->style()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected, 0, le))
250 le->setWidgetOwnsGeometry(true);
251 return le; }
252#else
253 default:
254 break;
255#endif
256 }
257 return 0;
258}
259
260QByteArray QDefaultItemEditorFactory::valuePropertyName(QVariant::Type type) const
261{
262 switch (type) {
263#ifndef QT_NO_COMBOBOX
264 case QVariant::Bool:
265 return "currentIndex";
266#endif
267#ifndef QT_NO_SPINBOX
268 case QVariant::UInt:
269 case QVariant::Int:
270 case QVariant::Double:
271 return "value";
272#endif
273#ifndef QT_NO_DATETIMEEDIT
274 case QVariant::Date:
275 return "date";
276 case QVariant::Time:
277 return "time";
278 case QVariant::DateTime:
279 return "dateTime";
280#endif
281 case QVariant::String:
282 default:
283 // the default editor is a lineedit
284 return "text";
285 }
286}
287
288static QItemEditorFactory *q_default_factory = 0;
289struct QDefaultFactoryCleaner
290{
291 inline QDefaultFactoryCleaner() {}
292 ~QDefaultFactoryCleaner() { delete q_default_factory; q_default_factory = 0; }
293};
294
295/*!
296 Returns the default item editor factory.
297
298 \sa setDefaultFactory()
299*/
300const QItemEditorFactory *QItemEditorFactory::defaultFactory()
301{
302 static const QDefaultItemEditorFactory factory;
303 if (q_default_factory)
304 return q_default_factory;
305 return &factory;
306}
307
308/*!
309 Sets the default item editor factory to the given \a factory.
310 Both new and existing delegates will use the new factory.
311
312 \sa defaultFactory()
313*/
314void QItemEditorFactory::setDefaultFactory(QItemEditorFactory *factory)
315{
316 static const QDefaultFactoryCleaner cleaner;
317 delete q_default_factory;
318 q_default_factory = factory;
319}
320
321/*!
322 \class QItemEditorCreatorBase
323 \brief The QItemEditorCreatorBase class provides an abstract base class that
324 must be subclassed when implementing new item editor creators.
325 \since 4.2
326 \ingroup model-view
327
328 QItemEditorCreatorBase objects are specialized widget factories that
329 provide editor widgets for one particular QVariant data type. They
330 are used by QItemEditorFactory to create editors for
331 \l{QItemDelegate}s. Creator bases must be registered with
332 QItemEditorFactory::registerEditor().
333
334 An editor should provide a user property for the data it edits.
335 QItemDelagates can then access the property using Qt's
336 \l{Meta-Object System}{meta-object system} to set and retrieve the
337 editing data. A property is set as the user property with the USER
338 keyword:
339
340 \snippet doc/src/snippets/code/src_gui_itemviews_qitemeditorfactory.cpp 0
341
342 If the editor does not provide a user property, it must return the
343 name of the property from valuePropertyName(); delegates will then
344 use the name to access the property. If a user property exists,
345 item delegates will not call valuePropertyName().
346
347 QStandardItemEditorCreator is a convenience template class that can be used
348 to register widgets without the need to subclass QItemEditorCreatorBase.
349
350 \sa QStandardItemEditorCreator, QItemEditorFactory,
351 {Model/View Programming}, {Color Editor Factory Example}
352*/
353
354/*!
355 \fn QItemEditorCreatorBase::~QItemEditorCreatorBase()
356
357 Destroys the editor creator object.
358*/
359
360/*!
361 \fn QWidget *QItemEditorCreatorBase::createWidget(QWidget *parent) const
362
363 Returns an editor widget with the given \a parent.
364
365 When implementing this function in subclasses of this class, you must
366 construct and return new editor widgets with the parent widget specified.
367*/
368
369/*!
370 \fn QByteArray QItemEditorCreatorBase::valuePropertyName() const
371
372 Returns the name of the property used to get and set values in the creator's
373 editor widgets.
374
375 When implementing this function in subclasses, you must ensure that the
376 editor widget's property specified by this function can accept the type
377 the creator is registered for. For example, a creator which constructs
378 QCheckBox widgets to edit boolean values would return the
379 \l{QCheckBox::checkable}{checkable} property name from this function,
380 and must be registered in the item editor factory for the QVariant::Bool
381 type.
382
383 Note: Since Qt 4.2 the item delegates query the user property of widgets,
384 and only call this function if the widget has no user property. You can
385 override this behavior by reimplementing QAbstractItemDelegate::setModelData()
386 and QAbstractItemDelegate::setEditorData().
387
388 \sa QMetaObject::userProperty(), QItemEditorFactory::registerEditor()
389*/
390
391/*!
392 \class QItemEditorCreator
393 \brief The QItemEditorCreator class makes it possible to create
394 item editor creator bases without subclassing
395 QItemEditorCreatorBase.
396
397 \since 4.2
398 \ingroup model-view
399
400 QItemEditorCreator is a convenience template class. It uses
401 the template class to create editors for QItemEditorFactory.
402 This way, it is not necessary to subclass
403 QItemEditorCreatorBase.
404
405 \snippet doc/src/snippets/code/src_gui_itemviews_qitemeditorfactory.cpp 1
406
407 The constructor takes the name of the property that contains the
408 editing data. QItemDelegate can then access the property by name
409 when it sets and retrieves editing data. Only use this class if
410 your editor does not define a user property (using the USER
411 keyword in the Q_PROPERTY macro). If the widget has a user
412 property, you should use QStandardItemEditorCreator instead.
413
414 \sa QItemEditorCreatorBase, QStandardItemEditorCreator,
415 QItemEditorFactory, {Color Editor Factory Example}
416*/
417
418/*!
419 \fn QItemEditorCreator::QItemEditorCreator(const QByteArray &valuePropertyName)
420
421 Constructs an editor creator object using \a valuePropertyName
422 as the name of the property to be used for editing. The
423 property name is used by QItemDelegate when setting and
424 getting editor data.
425
426 Note that the \a valuePropertyName is only used if the editor
427 widget does not have a user property defined.
428*/
429
430/*!
431 \fn QWidget *QItemEditorCreator::createWidget(QWidget *parent) const
432 \reimp
433*/
434
435/*!
436 \fn QByteArray QItemEditorCreator::valuePropertyName() const
437 \reimp
438*/
439
440/*!
441 \class QStandardItemEditorCreator
442
443 \brief The QStandardItemEditorCreator class provides the
444 possibility to register widgets without having to subclass
445 QItemEditorCreatorBase.
446
447 \since 4.2
448 \ingroup model-view
449
450 This convenience template class makes it possible to register widgets without
451 having to subclass QItemEditorCreatorBase.
452
453 Example:
454
455 \snippet doc/src/snippets/code/src_gui_itemviews_qitemeditorfactory.cpp 2
456
457 Setting the \c editorFactory created above in an item delegate via
458 QItemDelegate::setItemEditorFactory() makes sure that all values of type
459 QVariant::DateTime will be edited in \c{MyFancyDateTimeEdit}.
460
461 The editor must provide a user property that will contain the
462 editing data. The property is used by \l{QItemDelegate}s to set
463 and retrieve the data (using Qt's \l{Meta-Object
464 System}{meta-object system}). You set the user property with
465 the USER keyword:
466
467 \snippet doc/src/snippets/code/src_gui_itemviews_qitemeditorfactory.cpp 3
468
469 \sa QItemEditorCreatorBase, QItemEditorCreator,
470 QItemEditorFactory, QItemDelegate, {Color Editor Factory Example}
471*/
472
473/*!
474 \fn QStandardItemEditorCreator::QStandardItemEditorCreator()
475
476 Constructs an editor creator object.
477*/
478
479/*!
480 \fn QWidget *QStandardItemEditorCreator::createWidget(QWidget *parent) const
481 \reimp
482*/
483
484/*!
485 \fn QByteArray QStandardItemEditorCreator::valuePropertyName() const
486 \reimp
487*/
488
489#ifndef QT_NO_LINEEDIT
490
491QExpandingLineEdit::QExpandingLineEdit(QWidget *parent)
492 : QLineEdit(parent), originalWidth(-1), widgetOwnsGeometry(false)
493{
494 connect(this, SIGNAL(textChanged(QString)), this, SLOT(resizeToContents()));
495 updateMinimumWidth();
496}
497
498void QExpandingLineEdit::changeEvent(QEvent *e)
499{
500 switch (e->type())
501 {
502 case QEvent::FontChange:
503 case QEvent::StyleChange:
504 case QEvent::ContentsRectChange:
505 updateMinimumWidth();
506 break;
507 default:
508 break;
509 }
510
511 QLineEdit::changeEvent(e);
512}
513
514void QExpandingLineEdit::updateMinimumWidth()
515{
516 int left, right;
517 getTextMargins(&left, 0, &right, 0);
518 int width = left + right + 4 /*horizontalMargin in qlineedit.cpp*/;
519 getContentsMargins(&left, 0, &right, 0);
520 width += left + right;
521
522 QStyleOptionFrameV2 opt;
523 initStyleOption(&opt);
524
525 int minWidth = style()->sizeFromContents(QStyle::CT_LineEdit, &opt, QSize(width, 0).
526 expandedTo(QApplication::globalStrut()), this).width();
527 setMinimumWidth(minWidth);
528}
529
530void QExpandingLineEdit::resizeToContents()
531{
532 int oldWidth = width();
533 if (originalWidth == -1)
534 originalWidth = oldWidth;
535 if (QWidget *parent = parentWidget()) {
536 QPoint position = pos();
537 int hintWidth = minimumWidth() + fontMetrics().width(displayText());
538 int parentWidth = parent->width();
539 int maxWidth = isRightToLeft() ? position.x() + oldWidth : parentWidth - position.x();
540 int newWidth = qBound(originalWidth, hintWidth, maxWidth);
541 if (widgetOwnsGeometry)
542 setMaximumWidth(newWidth);
543 if (isRightToLeft())
544 move(position.x() - newWidth + oldWidth, position.y());
545 resize(newWidth, height());
546 }
547}
548
549#endif // QT_NO_LINEEDIT
550
551#ifndef QT_NO_COMBOBOX
552
553QBooleanComboBox::QBooleanComboBox(QWidget *parent)
554 : QComboBox(parent)
555{
556 addItem(QComboBox::tr("False"));
557 addItem(QComboBox::tr("True"));
558}
559
560void QBooleanComboBox::setValue(bool value)
561{
562 setCurrentIndex(value ? 1 : 0);
563}
564
565bool QBooleanComboBox::value() const
566{
567 return (currentIndex() == 1);
568}
569
570#endif // QT_NO_COMBOBOX
571
572QT_END_NAMESPACE
573
574#if !defined(QT_NO_LINEEDIT) || !defined(QT_NO_COMBOBOX)
575#include "qitemeditorfactory.moc"
576#endif
577
578#endif // QT_NO_ITEMVIEWS
Note: See TracBrowser for help on using the repository browser.