QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
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"
36 #include "qgslistwidgetfactory.h"
37 #include "qgsrangewidgetfactory.h"
41 #include "qgsuuidwidgetfactory.h"
44 
46 {
47  mFallbackWidgetFactory.reset( new QgsTextEditWidgetFactory( tr( "Text Edit" ) ) );
48 }
49 
51 {
52  registerWidget( QStringLiteral( "TextEdit" ), new QgsTextEditWidgetFactory( tr( "Text Edit" ) ) );
53  registerWidget( QStringLiteral( "Classification" ), new QgsClassificationWidgetWrapperFactory( tr( "Classification" ) ) );
54  registerWidget( QStringLiteral( "Range" ), new QgsRangeWidgetFactory( tr( "Range" ) ) );
55  registerWidget( QStringLiteral( "UniqueValues" ), new QgsUniqueValueWidgetFactory( tr( "Unique Values" ) ) );
56  registerWidget( QStringLiteral( "ValueMap" ), new QgsValueMapWidgetFactory( tr( "Value Map" ) ) );
57  registerWidget( QStringLiteral( "Enumeration" ), new QgsEnumerationWidgetFactory( tr( "Enumeration" ) ) );
58  registerWidget( QStringLiteral( "Hidden" ), new QgsHiddenWidgetFactory( tr( "Hidden" ) ) );
59  registerWidget( QStringLiteral( "CheckBox" ), new QgsCheckboxWidgetFactory( tr( "Checkbox" ) ) );
60  registerWidget( QStringLiteral( "ValueRelation" ), new QgsValueRelationWidgetFactory( tr( "Value Relation" ) ) );
61  registerWidget( QStringLiteral( "UuidGenerator" ), new QgsUuidWidgetFactory( tr( "Uuid Generator" ) ) );
62  registerWidget( QStringLiteral( "Color" ), new QgsColorWidgetFactory( tr( "Color" ) ) );
63  registerWidget( QStringLiteral( "RelationReference" ), new QgsRelationReferenceFactory( tr( "Relation Reference" ), mapCanvas, messageBar ) );
64  registerWidget( QStringLiteral( "DateTime" ), new QgsDateTimeEditFactory( tr( "Date/Time" ) ) );
65  registerWidget( QStringLiteral( "ExternalResource" ), new QgsExternalResourceWidgetFactory( tr( "Attachment" ) ) );
66  registerWidget( QStringLiteral( "KeyValue" ), new QgsKeyValueWidgetFactory( tr( "Key/Value" ) ) );
67  registerWidget( QStringLiteral( "List" ), new QgsListWidgetFactory( tr( "List" ) ) );
68  registerWidget( QStringLiteral( "Binary" ), new QgsBinaryWidgetFactory( tr( "Binary (BLOB)" ), messageBar ) );
69 }
70 
72 {
73  qDeleteAll( mWidgetFactories );
74 }
75 
76 QgsEditorWidgetSetup QgsEditorWidgetRegistry::findBest( const QgsVectorLayer *vl, const QString &fieldName ) const
77 {
78  QgsFields fields = vl->fields();
79  int index = fields.indexOf( fieldName );
80 
81  if ( index > -1 )
82  {
83  QgsEditorWidgetSetup setup = fields.at( index ).editorWidgetSetup();
84  if ( !setup.isNull() )
85  return setup;
86  }
87  return mAutoConf.editorWidgetSetup( vl, fieldName );
88 }
89 
90 QgsEditorWidgetWrapper *QgsEditorWidgetRegistry::create( QgsVectorLayer *vl, int fieldIdx, QWidget *editor, QWidget *parent, const QgsAttributeEditorContext &context )
91 {
92  const QString fieldName = vl->fields().field( fieldIdx ).name();
93  const QgsEditorWidgetSetup setup = findBest( vl, fieldName );
94  return create( setup.type(), vl, fieldIdx, setup.config(), editor, parent, context );
95 }
96 
97 QgsEditorWidgetWrapper *QgsEditorWidgetRegistry::create( const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, const QVariantMap &config, QWidget *editor, QWidget *parent, const QgsAttributeEditorContext &context )
98 {
99  if ( mWidgetFactories.contains( widgetId ) )
100  {
101  QgsEditorWidgetWrapper *ww = mWidgetFactories[widgetId]->create( vl, fieldIdx, editor, parent );
102 
103  if ( ww )
104  {
105  ww->setConfig( config );
106  ww->setContext( context );
107  // Make sure that there is a widget created at this point
108  // so setValue() et al won't crash
109  ww->widget();
110 
111  // If we tried to set a widget which is not supported by this wrapper
112  if ( !ww->valid() )
113  {
114  delete ww;
115  QString wid = findSuitableWrapper( editor, QStringLiteral( "TextEdit" ) );
116  ww = mWidgetFactories[wid]->create( vl, fieldIdx, editor, parent );
117  ww->setConfig( config );
118  ww->setContext( context );
119  }
120 
121  return ww;
122  }
123  }
124 
125  return nullptr;
126 }
127 
128 QgsSearchWidgetWrapper *QgsEditorWidgetRegistry::createSearchWidget( const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, const QVariantMap &config, QWidget *parent, const QgsAttributeEditorContext &context )
129 {
130  if ( mWidgetFactories.contains( widgetId ) )
131  {
132  QgsSearchWidgetWrapper *ww = mWidgetFactories[widgetId]->createSearchWidget( vl, fieldIdx, parent );
133 
134  if ( ww )
135  {
136  ww->setConfig( config );
137  ww->setContext( context );
138  // Make sure that there is a widget created at this point
139  // so setValue() et al won't crash
140  ww->widget();
141  ww->clearWidget();
142  return ww;
143  }
144  }
145  return nullptr;
146 }
147 
148 QgsEditorConfigWidget *QgsEditorWidgetRegistry::createConfigWidget( const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, QWidget *parent )
149 {
150  if ( mWidgetFactories.contains( widgetId ) )
151  {
152  return mWidgetFactories[widgetId]->configWidget( vl, fieldIdx, parent );
153  }
154  return nullptr;
155 }
156 
157 QString QgsEditorWidgetRegistry::name( const QString &widgetId )
158 {
159  if ( mWidgetFactories.contains( widgetId ) )
160  {
161  return mWidgetFactories[widgetId]->name();
162  }
163 
164  return QString();
165 }
166 
167 QMap<QString, QgsEditorWidgetFactory *> QgsEditorWidgetRegistry::factories()
168 {
169  return mWidgetFactories;
170 }
171 
173 {
174  return mWidgetFactories.value( widgetId, mFallbackWidgetFactory.get() );
175 }
176 
177 bool QgsEditorWidgetRegistry::registerWidget( const QString &widgetId, QgsEditorWidgetFactory *widgetFactory )
178 {
179  if ( !widgetFactory )
180  {
181  QgsApplication::messageLog()->logMessage( tr( "QgsEditorWidgetRegistry: Factory not valid." ) );
182  return false;
183  }
184  else if ( mWidgetFactories.contains( widgetId ) )
185  {
186  QgsApplication::messageLog()->logMessage( tr( "QgsEditorWidgetRegistry: Factory with id %1 already registered." ).arg( widgetId ) );
187  return false;
188  }
189  else
190  {
191  mWidgetFactories.insert( widgetId, widgetFactory );
192 
193  // Use this factory as default where it provides the highest priority
194  QHash<const char *, int> types = widgetFactory->supportedWidgetTypes();
195  QHash<const char *, int>::ConstIterator it;
196  it = types.constBegin();
197 
198  for ( ; it != types.constEnd(); ++it )
199  {
200  if ( it.value() > mFactoriesByType[it.key()].first )
201  {
202  mFactoriesByType[it.key()] = qMakePair( it.value(), widgetId );
203  }
204  }
205 
206  return true;
207  }
208 }
209 
210 QString QgsEditorWidgetRegistry::findSuitableWrapper( QWidget *editor, const QString &defaultWidget )
211 {
212  QMap<const char *, QPair<int, QString> >::ConstIterator it;
213 
214  QString widgetid;
215 
216  // Editor can be null
217  if ( editor )
218  {
219  int weight = 0;
220 
221  it = mFactoriesByType.constBegin();
222  for ( ; it != mFactoriesByType.constEnd(); ++it )
223  {
224  if ( editor->staticMetaObject.className() == it.key() )
225  {
226  // if it's a perfect match: return it directly
227  return it.value().second;
228  }
229  else if ( editor->inherits( it.key() ) )
230  {
231  // if it's a subclass, continue evaluating, maybe we find a more-specific or one with more weight
232  if ( it.value().first > weight )
233  {
234  weight = it.value().first;
235  widgetid = it.value().second;
236  }
237  }
238  }
239  }
240 
241  if ( widgetid.isNull() )
242  widgetid = defaultWidget;
243  return widgetid;
244 }
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:559
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
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:168
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
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:86
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::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.