QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
qgseditorwidgetregistry.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgseditorwidgetregistry.cpp
3 --------------------------------------
4 Date : 24.4.2013
5 Copyright : (C) 2013 Matthias Kuhn
6 Email : matthias at opengis dot ch
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
19#include "qgsmessagelog.h"
20#include "qgsproject.h"
21#include "qgsvectorlayer.h"
24#include "qgsapplication.h"
25
26// Editors
45
47{
48 mFallbackWidgetFactory.reset( new QgsTextEditWidgetFactory( tr( "Text Edit" ) ) );
49}
50
52{
53 registerWidget( QStringLiteral( "TextEdit" ), new QgsTextEditWidgetFactory( tr( "Text Edit" ) ) );
54 registerWidget( QStringLiteral( "Classification" ), new QgsClassificationWidgetWrapperFactory( tr( "Classification" ) ) );
55 registerWidget( QStringLiteral( "Range" ), new QgsRangeWidgetFactory( tr( "Range" ) ) );
56 registerWidget( QStringLiteral( "UniqueValues" ), new QgsUniqueValueWidgetFactory( tr( "Unique Values" ) ) );
57 registerWidget( QStringLiteral( "ValueMap" ), new QgsValueMapWidgetFactory( tr( "Value Map" ) ) );
58 registerWidget( QStringLiteral( "Enumeration" ), new QgsEnumerationWidgetFactory( tr( "Enumeration" ) ) );
59 registerWidget( QStringLiteral( "Hidden" ), new QgsHiddenWidgetFactory( tr( "Hidden" ) ) );
60 registerWidget( QStringLiteral( "CheckBox" ), new QgsCheckboxWidgetFactory( tr( "Checkbox" ) ) );
61 registerWidget( QStringLiteral( "ValueRelation" ), new QgsValueRelationWidgetFactory( tr( "Value Relation" ) ) );
62 registerWidget( QStringLiteral( "UuidGenerator" ), new QgsUuidWidgetFactory( tr( "Uuid Generator" ) ) );
63 registerWidget( QStringLiteral( "Color" ), new QgsColorWidgetFactory( tr( "Color" ) ) );
64 registerWidget( QStringLiteral( "RelationReference" ), new QgsRelationReferenceFactory( tr( "Relation Reference" ), mapCanvas, messageBar ) );
65 registerWidget( QStringLiteral( "DateTime" ), new QgsDateTimeEditFactory( tr( "Date/Time" ) ) );
66 registerWidget( QStringLiteral( "ExternalResource" ), new QgsExternalResourceWidgetFactory( tr( "Attachment" ), messageBar ) );
67 registerWidget( QStringLiteral( "KeyValue" ), new QgsKeyValueWidgetFactory( tr( "Key/Value" ) ) );
68 registerWidget( QStringLiteral( "List" ), new QgsListWidgetFactory( tr( "List" ) ) );
69 registerWidget( QStringLiteral( "Binary" ), new QgsBinaryWidgetFactory( tr( "Binary (BLOB)" ), messageBar ) );
70 registerWidget( QStringLiteral( "JsonEdit" ), new QgsJsonEditWidgetFactory( tr( "Json View" ) ) );
71}
72
74{
75 qDeleteAll( mWidgetFactories );
76}
77
78QgsEditorWidgetSetup QgsEditorWidgetRegistry::findBest( const QgsVectorLayer *vl, const QString &fieldName ) const
79{
80 const QgsFields fields = vl->fields();
81 const int index = fields.indexOf( fieldName );
82
83 if ( index > -1 )
84 {
85 QgsEditorWidgetSetup setup = fields.at( index ).editorWidgetSetup();
86 if ( !setup.isNull() )
87 return setup;
88 }
89 return mAutoConf.editorWidgetSetup( vl, fieldName );
90}
91
92QgsEditorWidgetWrapper *QgsEditorWidgetRegistry::create( QgsVectorLayer *vl, int fieldIdx, QWidget *editor, QWidget *parent, const QgsAttributeEditorContext &context )
93{
94 const QString fieldName = vl->fields().field( fieldIdx ).name();
95 const QgsEditorWidgetSetup setup = findBest( vl, fieldName );
96 return create( setup.type(), vl, fieldIdx, setup.config(), editor, parent, context );
97}
98
99QgsEditorWidgetWrapper *QgsEditorWidgetRegistry::create( const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, const QVariantMap &config, QWidget *editor, QWidget *parent, const QgsAttributeEditorContext &context )
100{
101 if ( mWidgetFactories.contains( widgetId ) )
102 {
103 QgsEditorWidgetWrapper *ww = mWidgetFactories[widgetId]->create( vl, fieldIdx, editor, parent );
104
105 if ( ww )
106 {
107 ww->setConfig( config );
108 ww->setContext( context );
109 // Make sure that there is a widget created at this point
110 // so setValue() et al won't crash
111 ww->widget();
112
113 // If we tried to set a widget which is not supported by this wrapper
114 if ( !ww->valid() )
115 {
116 delete ww;
117 const QString wid = findSuitableWrapper( editor, QStringLiteral( "TextEdit" ) );
118 ww = mWidgetFactories[wid]->create( vl, fieldIdx, editor, parent );
119 ww->setConfig( config );
120 ww->setContext( context );
121 }
122
123 return ww;
124 }
125 }
126
127 return nullptr;
128}
129
130QgsSearchWidgetWrapper *QgsEditorWidgetRegistry::createSearchWidget( const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, const QVariantMap &config, QWidget *parent, const QgsAttributeEditorContext &context )
131{
132 if ( mWidgetFactories.contains( widgetId ) )
133 {
134 QgsSearchWidgetWrapper *ww = mWidgetFactories[widgetId]->createSearchWidget( vl, fieldIdx, parent );
135
136 if ( ww )
137 {
138 ww->setConfig( config );
139 ww->setContext( context );
140 // Make sure that there is a widget created at this point
141 // so setValue() et al won't crash
142 ww->widget();
143 ww->clearWidget();
144 return ww;
145 }
146 }
147 return nullptr;
148}
149
150QgsEditorConfigWidget *QgsEditorWidgetRegistry::createConfigWidget( const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, QWidget *parent )
151{
152 if ( mWidgetFactories.contains( widgetId ) )
153 {
154 return mWidgetFactories[widgetId]->configWidget( vl, fieldIdx, parent );
155 }
156 return nullptr;
157}
158
159QString QgsEditorWidgetRegistry::name( const QString &widgetId )
160{
161 if ( mWidgetFactories.contains( widgetId ) )
162 {
163 return mWidgetFactories[widgetId]->name();
164 }
165
166 return QString();
167}
168
169QMap<QString, QgsEditorWidgetFactory *> QgsEditorWidgetRegistry::factories()
170{
171 return mWidgetFactories;
172}
173
175{
176 return mWidgetFactories.value( widgetId, mFallbackWidgetFactory.get() );
177}
178
179bool QgsEditorWidgetRegistry::registerWidget( const QString &widgetId, QgsEditorWidgetFactory *widgetFactory )
180{
181 if ( !widgetFactory )
182 {
183 QgsMessageLog::logMessage( tr( "QgsEditorWidgetRegistry: Factory not valid." ) );
184 return false;
185 }
186 else if ( mWidgetFactories.contains( widgetId ) )
187 {
188 QgsMessageLog::logMessage( tr( "QgsEditorWidgetRegistry: Factory with id %1 already registered." ).arg( widgetId ) );
189 return false;
190 }
191 else
192 {
193 mWidgetFactories.insert( widgetId, widgetFactory );
194
195 // Use this factory as default where it provides the highest priority
196 const QHash<const char *, int> types = widgetFactory->supportedWidgetTypes();
197 QHash<const char *, int>::ConstIterator it;
198 it = types.constBegin();
199
200 for ( ; it != types.constEnd(); ++it )
201 {
202 if ( it.value() > mFactoriesByType[it.key()].first )
203 {
204 mFactoriesByType[it.key()] = qMakePair( it.value(), widgetId );
205 }
206 }
207
208 return true;
209 }
210}
211
212QString QgsEditorWidgetRegistry::findSuitableWrapper( QWidget *editor, const QString &defaultWidget )
213{
214 QMap<const char *, QPair<int, QString> >::ConstIterator it;
215
216 QString widgetid;
217
218 // Editor can be null
219 if ( editor )
220 {
221 int weight = 0;
222
223 it = mFactoriesByType.constBegin();
224 for ( ; it != mFactoriesByType.constEnd(); ++it )
225 {
226 if ( QWidget::staticMetaObject.className() == it.key() )
227 {
228 // if it's a perfect match: return it directly
229 return it.value().second;
230 }
231 else if ( editor->inherits( it.key() ) )
232 {
233 // if it's a subclass, continue evaluating, maybe we find a more-specific or one with more weight
234 if ( it.value().first > weight )
235 {
236 weight = it.value().first;
237 widgetid = it.value().second;
238 }
239 }
240 }
241 }
242
243 if ( widgetid.isNull() )
244 widgetid = defaultWidget;
245 return widgetid;
246}
This class contains context information for attribute editor widgets.
Editor widget factory for binary (BLOB) widgets.
This class should be subclassed for every configurable editor widget type.
Every attribute editor widget needs a factory, which inherits this class.
virtual QHash< const char *, int > supportedWidgetTypes()
Returns a list of widget types which this editor widget supports.
~QgsEditorWidgetRegistry() override
Destructor.
QString name(const QString &widgetId)
Gets the human readable name for a widget type.
QgsEditorConfigWidget * createConfigWidget(const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, QWidget *parent)
Creates a configuration widget.
QMap< QString, QgsEditorWidgetFactory * > factories()
Gets access to all registered factories.
void initEditors(QgsMapCanvas *mapCanvas=nullptr, QgsMessageBar *messageBar=nullptr)
Registers all the default widgets.
QgsEditorWidgetSetup findBest(const QgsVectorLayer *vl, const QString &fieldName) const
Find the best editor widget and its configuration for a given field.
QgsEditorWidgetWrapper * create(const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, const QVariantMap &config, QWidget *editor, QWidget *parent, const QgsAttributeEditorContext &context=QgsAttributeEditorContext())
Create an attribute editor widget wrapper of a given type for a given field.
QgsEditorWidgetFactory * factory(const QString &widgetId)
Gets a factory for the given widget type id.
QgsSearchWidgetWrapper * createSearchWidget(const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, const QVariantMap &config, QWidget *parent, const QgsAttributeEditorContext &context=QgsAttributeEditorContext())
QgsEditorWidgetRegistry()
Constructor for QgsEditorWidgetRegistry.
bool registerWidget(const QString &widgetId, QgsEditorWidgetFactory *widgetFactory)
Register a new widget factory with the given id.
Holder for the widget type and its configuration for a field.
QVariantMap config() const
Manages an editor widget Widget and wrapper share the same parent.
QString name
Definition: qgsfield.h:60
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Definition: qgsfield.cpp:631
Container of fields for a vector layer.
Definition: qgsfields.h:45
int indexOf(const QString &fieldName) const
Gets the field index from the field name.
Definition: qgsfields.cpp:207
QgsField field(int fieldIdx) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:168
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:163
Editor widget factory for JSON edit widgets.
Factory for widgets for editing a QVariantMap.
Factory for widgets for editing a QVariantList or a QStringList.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:90
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:61
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Shows a search widget on a filter form.
virtual void clearWidget()
Clears the widget's current value and resets it back to the default state.
Represents a vector layer which manages a vector based data sets.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
virtual bool valid() const =0
Returns true if the widget has been properly initialized.
QWidget * widget()
Access the widget managed by this wrapper.
void setConfig(const QVariantMap &config)
Will set the config of this wrapper to the specified config.
void setContext(const QgsAttributeEditorContext &context)
Set the context in which this widget is shown.