Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qitemeditorfactory.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include <qplatformdefs.h>
8
9#if QT_CONFIG(combobox)
10#include <qcombobox.h>
11#endif
12#if QT_CONFIG(datetimeedit)
13#include <qdatetimeedit.h>
14#endif
15#if QT_CONFIG(label)
16#include <qlabel.h>
17#endif
18#if QT_CONFIG(lineedit)
19#include <qlineedit.h>
20#endif
21#if QT_CONFIG(spinbox)
22#include <qspinbox.h>
23#endif
24#include <qstyle.h>
25#include <qstyleoption.h>
26#include <limits.h>
27#include <float.h>
28#include <qapplication.h>
29#include <qdebug.h>
30
31#include <vector>
32#include <algorithm>
34
35
36#if QT_CONFIG(combobox)
37
38class QBooleanComboBox : public QComboBox
39{
42
43public:
45 void setValue(bool);
46 bool value() const;
47};
48
49#endif // QT_CONFIG(combobox)
50
51
52#if QT_CONFIG(spinbox)
53
54class QUIntSpinBox : public QSpinBox
55{
58public:
59 explicit QUIntSpinBox(QWidget *parent = nullptr)
61 {
63 }
64
66 {
67 return value();
68 }
69
71 {
72 return setValue(value_);
73 }
74
76 void uintValueChanged();
77};
78
79#endif // QT_CONFIG(spinbox)
80
81/*!
82 \class QItemEditorFactory
83 \brief The QItemEditorFactory class provides widgets for editing item data
84 in views and delegates.
85 \ingroup model-view
86 \inmodule QtWidgets
87
88 When editing data in an item view, editors are created and
89 displayed by a delegate. QStyledItemDelegate, which is the delegate by
90 default installed on Qt's item views, uses a QItemEditorFactory to
91 create editors for it. A default unique instance provided by
92 QItemEditorFactory is used by all item delegates. If you set a
93 new default factory with setDefaultFactory(), the new factory will
94 be used by existing and new delegates.
95
96 A factory keeps a collection of QItemEditorCreatorBase
97 instances, which are specialized editors that produce editors
98 for one particular QVariant data type (All Qt models store
99 their data in \l{QVariant}s).
100
101 \section1 Standard Editing Widgets
102
103 The standard factory implementation provides editors for a variety of data
104 types. These are created whenever a delegate needs to provide an editor for
105 data supplied by a model. The following table shows the relationship between
106 types and the standard editors provided.
107
108 \table
109 \header \li Type \li Editor Widget
110 \row \li bool \li QComboBox
111 \row \li double \li QDoubleSpinBox
112 \row \li int \li{1,2} QSpinBox
113 \row \li unsigned int
114 \row \li QDate \li QDateEdit
115 \row \li QDateTime \li QDateTimeEdit
116 \row \li QPixmap \li QLabel
117 \row \li QString \li QLineEdit
118 \row \li QTime \li QTimeEdit
119 \endtable
120
121 Additional editors can be registered with the registerEditor() function.
122
123 \sa QStyledItemDelegate, {Model/View Programming}
124*/
125
126/*!
127 \fn QItemEditorFactory::QItemEditorFactory()
128
129 Constructs a new item editor factory.
130*/
131
132/*!
133 Creates an editor widget with the given \a parent for the specified \a userType of data,
134 and returns it as a QWidget.
135
136 \sa registerEditor()
137*/
138QWidget *QItemEditorFactory::createEditor(int userType, QWidget *parent) const
139{
140 QItemEditorCreatorBase *creator = creatorMap.value(userType, 0);
141 if (!creator) {
142 const QItemEditorFactory *dfactory = defaultFactory();
143 return dfactory == this ? nullptr : dfactory->createEditor(userType, parent);
144 }
145 return creator->createWidget(parent);
146}
147
148/*!
149 Returns the property name used to access data for the given \a userType of data.
150*/
151QByteArray QItemEditorFactory::valuePropertyName(int userType) const
152{
153 QItemEditorCreatorBase *creator = creatorMap.value(userType, 0);
154 if (!creator) {
155 const QItemEditorFactory *dfactory = defaultFactory();
156 return dfactory == this ? QByteArray() : dfactory->valuePropertyName(userType);
157 }
158 return creator->valuePropertyName();
159}
160
161/*!
162 Destroys the item editor factory.
163*/
164QItemEditorFactory::~QItemEditorFactory()
165{
166 //we make sure we delete all the QItemEditorCreatorBase
167 //this has to be done only once, hence the sort-unique idiom
168 std::vector<QItemEditorCreatorBase*> creators(creatorMap.cbegin(), creatorMap.cend());
169 std::sort(creators.begin(), creators.end());
170 const auto it = std::unique(creators.begin(), creators.end());
171 qDeleteAll(creators.begin(), it);
172}
173
174/*!
175 Registers an item editor creator specified by \a creator for the given \a userType of data.
176
177 \b{Note:} The factory takes ownership of the item editor creator and will destroy
178 it if a new creator for the same type is registered later.
179
180 \sa createEditor()
181*/
182void QItemEditorFactory::registerEditor(int userType, QItemEditorCreatorBase *creator)
183{
184 const auto it = creatorMap.constFind(userType);
185 if (it != creatorMap.cend()) {
186 QItemEditorCreatorBase *oldCreator = it.value();
187 Q_ASSERT(oldCreator);
188 creatorMap.erase(it);
189 if (std::find(creatorMap.cbegin(), creatorMap.cend(), oldCreator) == creatorMap.cend())
190 delete oldCreator; // if it is no more in use we can delete it
191 }
192
193 creatorMap[userType] = creator;
194}
195
197{
198public:
200 QWidget *createEditor(int userType, QWidget *parent) const override;
201 QByteArray valuePropertyName(int) const override;
202};
203
205{
206 switch (userType) {
207#if QT_CONFIG(combobox)
208 case QMetaType::Bool: {
209 QBooleanComboBox *cb = new QBooleanComboBox(parent);
210 cb->setFrame(false);
211 cb->setSizePolicy(QSizePolicy::Ignored, cb->sizePolicy().verticalPolicy());
212 return cb; }
213#endif
214#if QT_CONFIG(spinbox)
215 case QMetaType::UInt: {
216 QSpinBox *sb = new QUIntSpinBox(parent);
217 sb->setFrame(false);
218 sb->setMinimum(0);
219 sb->setMaximum(INT_MAX);
220 sb->setSizePolicy(QSizePolicy::Ignored, sb->sizePolicy().verticalPolicy());
221 return sb; }
222 case QMetaType::Int: {
223 QSpinBox *sb = new QSpinBox(parent);
224 sb->setFrame(false);
225 sb->setMinimum(INT_MIN);
226 sb->setMaximum(INT_MAX);
227 sb->setSizePolicy(QSizePolicy::Ignored, sb->sizePolicy().verticalPolicy());
228 return sb; }
229#endif
230#if QT_CONFIG(datetimeedit)
231 case QMetaType::QDate: {
232 QDateTimeEdit *ed = new QDateEdit(parent);
233 ed->setFrame(false);
234 return ed; }
235 case QMetaType::QTime: {
236 QDateTimeEdit *ed = new QTimeEdit(parent);
237 ed->setFrame(false);
238 return ed; }
239 case QMetaType::QDateTime: {
240 QDateTimeEdit *ed = new QDateTimeEdit(parent);
241 ed->setFrame(false);
242 return ed; }
243#endif
244#if QT_CONFIG(label)
245 case QMetaType::QPixmap:
246 return new QLabel(parent);
247#endif
248#if QT_CONFIG(spinbox)
249 case QMetaType::Double: {
250 QDoubleSpinBox *sb = new QDoubleSpinBox(parent);
251 sb->setFrame(false);
252 sb->setMinimum(-DBL_MAX);
253 sb->setMaximum(DBL_MAX);
254 sb->setSizePolicy(QSizePolicy::Ignored, sb->sizePolicy().verticalPolicy());
255 return sb; }
256#endif
257#if QT_CONFIG(lineedit)
258 case QMetaType::QString:
259 default: {
260 // the default editor is a lineedit
261 QExpandingLineEdit *le = new QExpandingLineEdit(parent);
262 le->setFrame(le->style()->styleHint(QStyle::SH_ItemView_DrawDelegateFrame, nullptr, le));
263 if (!le->style()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected, nullptr, le))
264 le->setWidgetOwnsGeometry(true);
265 return le; }
266#else
267 default:
268 break;
269#endif
270 }
271 return nullptr;
272}
273
275{
276 switch (userType) {
277#if QT_CONFIG(combobox)
278 case QMetaType::Bool:
279 return "currentIndex";
280#endif
281#if QT_CONFIG(spinbox)
282 case QMetaType::UInt:
283 case QMetaType::Int:
284 case QMetaType::Double:
285 return "value";
286#endif
287#if QT_CONFIG(datetimeedit)
288 case QMetaType::QDate:
289 return "date";
290 case QMetaType::QTime:
291 return "time";
292 case QMetaType::QDateTime:
293 return "dateTime";
294#endif
295 case QMetaType::QString:
296 default:
297 // the default editor is a lineedit
298 return "text";
299 }
300}
301
304{
306 ~QDefaultFactoryCleaner() { delete q_default_factory; q_default_factory = nullptr; }
307};
308
309/*!
310 Returns the default item editor factory.
311
312 \sa setDefaultFactory()
313*/
314const QItemEditorFactory *QItemEditorFactory::defaultFactory()
315{
316 static const QDefaultItemEditorFactory factory;
317 if (q_default_factory)
318 return q_default_factory;
319 return &factory;
320}
321
322/*!
323 Sets the default item editor factory to the given \a factory.
324 Both new and existing delegates will use the new factory.
325
326 \sa defaultFactory()
327*/
328void QItemEditorFactory::setDefaultFactory(QItemEditorFactory *factory)
329{
330 static const QDefaultFactoryCleaner cleaner;
331 delete q_default_factory;
332 q_default_factory = factory;
333}
334
335/*!
336 \class QItemEditorCreatorBase
337 \brief The QItemEditorCreatorBase class provides an abstract base class that
338 must be subclassed when implementing new item editor creators.
339 \ingroup model-view
340 \inmodule QtWidgets
341
342 QItemEditorCreatorBase objects are specialized widget factories that
343 provide editor widgets for one particular QVariant data type. They
344 are used by QItemEditorFactory to create editors for
345 \l{QStyledItemDelegate}s. Creator bases must be registered with
346 QItemEditorFactory::registerEditor().
347
348 An editor should provide a user property for the data it edits.
349 QItemDelagates can then access the property using Qt's
350 \l{Meta-Object System}{meta-object system} to set and retrieve the
351 editing data. A property is set as the user property with the USER
352 keyword:
353
354 \snippet code/src_gui_itemviews_qitemeditorfactory.cpp 0
355
356 If the editor does not provide a user property, it must return the
357 name of the property from valuePropertyName(); delegates will then
358 use the name to access the property. If a user property exists,
359 item delegates will not call valuePropertyName().
360
361 QStandardItemEditorCreator is a convenience template class that can be used
362 to register widgets without the need to subclass QItemEditorCreatorBase.
363
364 \sa QStandardItemEditorCreator, QItemEditorFactory,
365 {Model/View Programming}
366*/
367
368/*!
369 \fn QItemEditorCreatorBase::~QItemEditorCreatorBase()
370
371 Destroys the editor creator object.
372*/
373QItemEditorCreatorBase::~QItemEditorCreatorBase()
374{
375
376}
377
378/*!
379 \fn QWidget *QItemEditorCreatorBase::createWidget(QWidget *parent) const
380
381 Returns an editor widget with the given \a parent.
382
383 When implementing this function in subclasses of this class, you must
384 construct and return new editor widgets with the parent widget specified.
385*/
386
387/*!
388 \fn QByteArray QItemEditorCreatorBase::valuePropertyName() const
389
390 Returns the name of the property used to get and set values in the creator's
391 editor widgets.
392
393 When implementing this function in subclasses, you must ensure that the
394 editor widget's property specified by this function can accept the type
395 the creator is registered for. For example, a creator which constructs
396 QCheckBox widgets to edit boolean values would return the
397 \l{QCheckBox::checkable}{checkable} property name from this function,
398 and must be registered in the item editor factory for the QMetaType::Bool
399 type.
400
401 Note: Since Qt 4.2 the item delegates query the user property of widgets,
402 and only call this function if the widget has no user property. You can
403 override this behavior by reimplementing QAbstractItemDelegate::setModelData()
404 and QAbstractItemDelegate::setEditorData().
405
406 \sa QMetaObject::userProperty(), QItemEditorFactory::registerEditor()
407*/
408
409/*!
410 \class QItemEditorCreator
411 \brief The QItemEditorCreator class makes it possible to create
412 item editor creator bases without subclassing
413 QItemEditorCreatorBase.
414
415 \ingroup model-view
416 \inmodule QtWidgets
417
418 QItemEditorCreator is a convenience template class. It uses
419 the template class to create editors for QItemEditorFactory.
420 This way, it is not necessary to subclass
421 QItemEditorCreatorBase.
422
423 \snippet code/src_gui_itemviews_qitemeditorfactory.cpp 1
424
425 The constructor takes the name of the property that contains the
426 editing data. QStyledItemDelegate can then access the property by name
427 when it sets and retrieves editing data. Only use this class if
428 your editor does not define a user property (using the USER
429 keyword in the Q_PROPERTY macro). If the widget has a user
430 property, you should use QStandardItemEditorCreator instead.
431
432 \sa QItemEditorCreatorBase, QStandardItemEditorCreator,
433 QItemEditorFactory
434*/
435
436/*!
437 \fn template <class T> QItemEditorCreator<T>::QItemEditorCreator(const QByteArray &valuePropertyName)
438
439 Constructs an editor creator object using \a valuePropertyName
440 as the name of the property to be used for editing. The
441 property name is used by QStyledItemDelegate when setting and
442 getting editor data.
443
444 Note that the \a valuePropertyName is only used if the editor
445 widget does not have a user property defined.
446*/
447
448/*!
449 \fn template <class T> QWidget *QItemEditorCreator<T>::createWidget(QWidget *parent) const
450 \reimp
451*/
452
453/*!
454 \fn template <class T> QByteArray QItemEditorCreator<T>::valuePropertyName() const
455 \reimp
456*/
457
458/*!
459 \class QStandardItemEditorCreator
460
461 \brief The QStandardItemEditorCreator class provides the
462 possibility to register widgets without having to subclass
463 QItemEditorCreatorBase.
464
465 \ingroup model-view
466 \inmodule QtWidgets
467
468 This convenience template class makes it possible to register widgets without
469 having to subclass QItemEditorCreatorBase.
470
471 Example:
472
473 \snippet code/src_gui_itemviews_qitemeditorfactory.cpp 2
474
475 Setting the \c editorFactory created above in an item delegate via
476 QStyledItemDelegate::setItemEditorFactory() makes sure that all values of type
477 QMetaType::QDateTime will be edited in \c{MyFancyDateTimeEdit}.
478
479 The editor must provide a user property that will contain the
480 editing data. The property is used by \l{QStyledItemDelegate}s to set
481 and retrieve the data (using Qt's \l{Meta-Object
482 System}{meta-object system}). You set the user property with
483 the USER keyword:
484
485 \snippet code/src_gui_itemviews_qitemeditorfactory.cpp 3
486
487 \sa QItemEditorCreatorBase, QItemEditorCreator,
488 QItemEditorFactory, QStyledItemDelegate
489*/
490
491/*!
492 \fn template <class T> QStandardItemEditorCreator<T>::QStandardItemEditorCreator()
493
494 Constructs an editor creator object.
495*/
496
497/*!
498 \fn template <class T> QWidget *QStandardItemEditorCreator<T>::createWidget(QWidget *parent) const
499 \reimp
500*/
501
502/*!
503 \fn template <class T> QByteArray QStandardItemEditorCreator<T>::valuePropertyName() const
504 \reimp
505*/
506
507#if QT_CONFIG(lineedit)
508
509QExpandingLineEdit::QExpandingLineEdit(QWidget *parent)
510 : QLineEdit(parent), originalWidth(-1), widgetOwnsGeometry(false)
511{
512 connect(this, SIGNAL(textChanged(QString)), this, SLOT(resizeToContents()));
513 updateMinimumWidth();
514}
515
516void QExpandingLineEdit::changeEvent(QEvent *e)
517{
518 switch (e->type())
519 {
520 case QEvent::FontChange:
521 case QEvent::StyleChange:
522 case QEvent::ContentsRectChange:
523 updateMinimumWidth();
524 break;
525 default:
526 break;
527 }
528
529 QLineEdit::changeEvent(e);
530}
531
532void QExpandingLineEdit::updateMinimumWidth()
533{
534 const QMargins tm = textMargins();
535 const QMargins cm = contentsMargins();
536 const int width = tm.left() + tm.right() + cm.left() + cm.right() + 4 /*horizontalMargin in qlineedit.cpp*/;
537
538 QStyleOptionFrame opt;
539 initStyleOption(&opt);
540
541 int minWidth = style()->sizeFromContents(QStyle::CT_LineEdit, &opt, QSize(width, 0), this).width();
542 setMinimumWidth(minWidth);
543}
544
545void QExpandingLineEdit::resizeToContents()
546{
547 int oldWidth = width();
548 if (originalWidth == -1)
549 originalWidth = oldWidth;
550 if (QWidget *parent = parentWidget()) {
551 QPoint position = pos();
552 int hintWidth = minimumWidth() + fontMetrics().horizontalAdvance(displayText());
553 int parentWidth = parent->width();
554 int maxWidth = isRightToLeft() ? position.x() + oldWidth : parentWidth - position.x();
555 int newWidth = qBound(qMin(originalWidth, maxWidth), hintWidth, maxWidth);
556 if (widgetOwnsGeometry)
557 setMaximumWidth(newWidth);
558 if (isRightToLeft())
559 move(position.x() - newWidth + oldWidth, position.y());
560 resize(newWidth, height());
561 }
562}
563
564#endif // QT_CONFIG(lineedit)
565
566#if QT_CONFIG(combobox)
567
568QBooleanComboBox::QBooleanComboBox(QWidget *parent)
569 : QComboBox(parent)
570{
571 addItem(QComboBox::tr("False"));
572 addItem(QComboBox::tr("True"));
573}
574
575void QBooleanComboBox::setValue(bool value)
576{
577 setCurrentIndex(value ? 1 : 0);
578}
579
580bool QBooleanComboBox::value() const
581{
582 return (currentIndex() == 1);
583}
584
585#endif // QT_CONFIG(combobox)
586
587QT_END_NAMESPACE
588
589#if QT_CONFIG(lineedit) || QT_CONFIG(combobox)
590#include "qitemeditorfactory.moc"
591#endif
592
593#include "moc_qitemeditorfactory_p.cpp"
QWidget * createEditor(int userType, QWidget *parent) const override
Creates an editor widget with the given parent for the specified userType of data,...
QByteArray valuePropertyName(int) const override
Returns the property name used to access data for the given userType of data.
friend class QWidget
Definition qpainter.h:431
The QWidget class is the base class of all user interface objects.
Definition qwidget.h:99
static QItemEditorFactory * q_default_factory