QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
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"
22 #include "qgseditorwidgetwrapper.h"
23 #include "qgssearchwidgetwrapper.h"
24 #include "qgsapplication.h"
25 
26 // Editors
27 #include "qgsbinarywidgetfactory.h"
30 #include "qgscolorwidgetfactory.h"
31 #include "qgsdatetimeeditfactory.h"
34 #include "qgshiddenwidgetfactory.h"
37 #include "qgslistwidgetfactory.h"
38 #include "qgsrangewidgetfactory.h"
42 #include "qgsuuidwidgetfactory.h"
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 
78 QgsEditorWidgetSetup 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 
92 QgsEditorWidgetWrapper *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 
99 QgsEditorWidgetWrapper *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 
130 QgsSearchWidgetWrapper *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 
150 QgsEditorConfigWidget *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 
159 QString QgsEditorWidgetRegistry::name( const QString &widgetId )
160 {
161  if ( mWidgetFactories.contains( widgetId ) )
162  {
163  return mWidgetFactories[widgetId]->name();
164  }
165 
166  return QString();
167 }
168 
169 QMap<QString, QgsEditorWidgetFactory *> QgsEditorWidgetRegistry::factories()
170 {
171  return mWidgetFactories;
172 }
173 
175 {
176  return mWidgetFactories.value( widgetId, mFallbackWidgetFactory.get() );
177 }
178 
179 bool QgsEditorWidgetRegistry::registerWidget( const QString &widgetId, QgsEditorWidgetFactory *widgetFactory )
180 {
181  if ( !widgetFactory )
182  {
183  QgsApplication::messageLog()->logMessage( tr( "QgsEditorWidgetRegistry: Factory not valid." ) );
184  return false;
185  }
186  else if ( mWidgetFactories.contains( widgetId ) )
187  {
188  QgsApplication::messageLog()->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 
212 QString 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 ( editor->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 }
static QgsMessageLog * messageLog()
Returns the application's message log.
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:572
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:89
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.