QGIS API Documentation  2.99.0-Master (53aba61)
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 
25 // Editors
28 #include "qgscolorwidgetfactory.h"
29 #include "qgsdatetimeeditfactory.h"
32 #include "qgshiddenwidgetfactory.h"
34 #include "qgslistwidgetfactory.h"
35 #include "qgsrangewidgetfactory.h"
39 #include "qgsuuidwidgetfactory.h"
42 
44 {
45  registerWidget( QStringLiteral( "TextEdit" ), new QgsTextEditWidgetFactory( tr( "Text Edit" ) ) );
46  registerWidget( QStringLiteral( "Classification" ), new QgsClassificationWidgetWrapperFactory( tr( "Classification" ) ) );
47  registerWidget( QStringLiteral( "Range" ), new QgsRangeWidgetFactory( tr( "Range" ) ) );
48  registerWidget( QStringLiteral( "UniqueValues" ), new QgsUniqueValueWidgetFactory( tr( "Unique Values" ) ) );
49  registerWidget( QStringLiteral( "ValueMap" ), new QgsValueMapWidgetFactory( tr( "Value Map" ) ) );
50  registerWidget( QStringLiteral( "Enumeration" ), new QgsEnumerationWidgetFactory( tr( "Enumeration" ) ) );
51  registerWidget( QStringLiteral( "Hidden" ), new QgsHiddenWidgetFactory( tr( "Hidden" ) ) );
52  registerWidget( QStringLiteral( "CheckBox" ), new QgsCheckboxWidgetFactory( tr( "Checkbox" ) ) );
53  registerWidget( QStringLiteral( "ValueRelation" ), new QgsValueRelationWidgetFactory( tr( "Value Relation" ) ) );
54  registerWidget( QStringLiteral( "UuidGenerator" ), new QgsUuidWidgetFactory( tr( "Uuid Generator" ) ) );
55  registerWidget( QStringLiteral( "Color" ), new QgsColorWidgetFactory( tr( "Color" ) ) );
56  registerWidget( QStringLiteral( "RelationReference" ), new QgsRelationReferenceFactory( tr( "Relation Reference" ), mapCanvas, messageBar ) );
57  registerWidget( QStringLiteral( "DateTime" ), new QgsDateTimeEditFactory( tr( "Date/Time" ) ) );
58  registerWidget( QStringLiteral( "ExternalResource" ), new QgsExternalResourceWidgetFactory( tr( "Attachment" ) ) );
59  registerWidget( QStringLiteral( "KeyValue" ), new QgsKeyValueWidgetFactory( tr( "Key/Value" ) ) );
60  registerWidget( QStringLiteral( "List" ), new QgsListWidgetFactory( tr( "List" ) ) );
61 }
62 
64 {
65  qDeleteAll( mWidgetFactories );
66 }
67 
68 QgsEditorWidgetSetup QgsEditorWidgetRegistry::findBest( const QgsVectorLayer *vl, const QString &fieldName ) const
69 {
70  QgsFields fields = vl->fields();
71  int index = fields.indexOf( fieldName );
72 
73  if ( index > -1 )
74  {
75  QgsEditorWidgetSetup setup = vl->fields().at( index ).editorWidgetSetup();
76  if ( !setup.isNull() )
77  return setup;
78  }
79  return mAutoConf.editorWidgetSetup( vl, fieldName );
80 }
81 
82 QgsEditorWidgetWrapper *QgsEditorWidgetRegistry::create( QgsVectorLayer *vl, int fieldIdx, QWidget *editor, QWidget *parent, const QgsAttributeEditorContext &context )
83 {
84  const QString fieldName = vl->fields().field( fieldIdx ).name();
85  const QgsEditorWidgetSetup setup = findBest( vl, fieldName );
86  return create( setup.type(), vl, fieldIdx, setup.config(), editor, parent, context );
87 }
88 
89 QgsEditorWidgetWrapper *QgsEditorWidgetRegistry::create( const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, const QVariantMap &config, QWidget *editor, QWidget *parent, const QgsAttributeEditorContext &context )
90 {
91  if ( mWidgetFactories.contains( widgetId ) )
92  {
93  QgsEditorWidgetWrapper *ww = mWidgetFactories[widgetId]->create( vl, fieldIdx, editor, parent );
94 
95  if ( ww )
96  {
97  ww->setConfig( config );
98  ww->setContext( context );
99  // Make sure that there is a widget created at this point
100  // so setValue() et al won't crash
101  ww->widget();
102 
103  // If we tried to set a widget which is not supported by this wrapper
104  if ( !ww->valid() )
105  {
106  delete ww;
107  QString wid = findSuitableWrapper( editor, QStringLiteral( "TextEdit" ) );
108  ww = mWidgetFactories[wid]->create( vl, fieldIdx, editor, parent );
109  ww->setConfig( config );
110  ww->setContext( context );
111  }
112 
113  return ww;
114  }
115  }
116 
117  return nullptr;
118 }
119 
120 QgsSearchWidgetWrapper *QgsEditorWidgetRegistry::createSearchWidget( const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, const QVariantMap &config, QWidget *parent, const QgsAttributeEditorContext &context )
121 {
122  if ( mWidgetFactories.contains( widgetId ) )
123  {
124  QgsSearchWidgetWrapper *ww = mWidgetFactories[widgetId]->createSearchWidget( vl, fieldIdx, parent );
125 
126  if ( ww )
127  {
128  ww->setConfig( config );
129  ww->setContext( context );
130  // Make sure that there is a widget created at this point
131  // so setValue() et al won't crash
132  ww->widget();
133  ww->clearWidget();
134  return ww;
135  }
136  }
137  return nullptr;
138 }
139 
140 QgsEditorConfigWidget *QgsEditorWidgetRegistry::createConfigWidget( const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, QWidget *parent )
141 {
142  if ( mWidgetFactories.contains( widgetId ) )
143  {
144  return mWidgetFactories[widgetId]->configWidget( vl, fieldIdx, parent );
145  }
146  return nullptr;
147 }
148 
149 QString QgsEditorWidgetRegistry::name( const QString &widgetId )
150 {
151  if ( mWidgetFactories.contains( widgetId ) )
152  {
153  return mWidgetFactories[widgetId]->name();
154  }
155 
156  return QString();
157 }
158 
159 QMap<QString, QgsEditorWidgetFactory *> QgsEditorWidgetRegistry::factories()
160 {
161  return mWidgetFactories;
162 }
163 
165 {
166  return mWidgetFactories.value( widgetId );
167 }
168 
169 bool QgsEditorWidgetRegistry::registerWidget( const QString &widgetId, QgsEditorWidgetFactory *widgetFactory )
170 {
171  if ( !widgetFactory )
172  {
173  QgsApplication::messageLog()->logMessage( QStringLiteral( "QgsEditorWidgetRegistry: Factory not valid." ) );
174  return false;
175  }
176  else if ( mWidgetFactories.contains( widgetId ) )
177  {
178  QgsApplication::messageLog()->logMessage( QStringLiteral( "QgsEditorWidgetRegistry: Factory with id %1 already registered." ).arg( widgetId ) );
179  return false;
180  }
181  else
182  {
183  mWidgetFactories.insert( widgetId, widgetFactory );
184 
185  // Use this factory as default where it provides the highest priority
186  QHash<const char *, int> types = widgetFactory->supportedWidgetTypes();
187  QHash<const char *, int>::ConstIterator it;
188  it = types.constBegin();
189 
190  for ( ; it != types.constEnd(); ++it )
191  {
192  if ( it.value() > mFactoriesByType[it.key()].first )
193  {
194  mFactoriesByType[it.key()] = qMakePair( it.value(), widgetId );
195  }
196  }
197 
198  return true;
199  }
200 }
201 
202 QString QgsEditorWidgetRegistry::findSuitableWrapper( QWidget *editor, const QString &defaultWidget )
203 {
204  QMap<const char *, QPair<int, QString> >::ConstIterator it;
205 
206  QString widgetid;
207 
208  // Editor can be null
209  if ( editor )
210  {
211  int weight = 0;
212 
213  it = mFactoriesByType.constBegin();
214  for ( ; it != mFactoriesByType.constEnd(); ++it )
215  {
216  if ( editor->staticMetaObject.className() == it.key() )
217  {
218  // if it's a perfect match: return it directly
219  return it.value().second;
220  }
221  else if ( editor->inherits( it.key() ) )
222  {
223  // if it's a subclass, continue evaluating, maybe we find a more-specific or one with more weight
224  if ( it.value().first > weight )
225  {
226  weight = it.value().first;
227  widgetid = it.value().second;
228  }
229  }
230  }
231  }
232 
233  if ( widgetid.isNull() )
234  widgetid = defaultWidget;
235  return widgetid;
236 }
Manages an editor widget Widget and wrapper share the same parent.
QVariantMap config() const
This class should be subclassed for every configurable editor widget type.
QString name
Definition: qgsfield.h:54
QgsEditorWidgetFactory * factory(const QString &widgetId)
Get a factory for the given widget type id.
This class contains context information for attribute editor widgets.
Manages an editor widget Widget and wrapper share the same parent.
Factory for widgets for editing a QVariantList or a QStringList.
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:44
Container of fields for a vector layer.
Definition: qgsfields.h:41
QgsEditorWidgetSetup editorWidgetSetup() const
Get the editor widget setup for the field.
Definition: qgsfield.cpp:290
virtual QHash< const char *, int > supportedWidgetTypes()
Returns a list of widget types which this editor widget supports.
QgsEditorConfigWidget * createConfigWidget(const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, QWidget *parent)
Creates a configuration widget.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:73
QgsField at(int i) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:135
QMap< QString, QgsEditorWidgetFactory * > factories()
Get access to all registered factories.
static QgsMessageLog * messageLog()
Returns the application&#39;s message log.
virtual void clearWidget()
Clears the widget&#39;s current value and resets it back to the default state.
void setContext(const QgsAttributeEditorContext &context)
Set the context in which this widget is shown.
QgsFields fields() const override
Returns the list of fields of this layer.
virtual bool valid() const =0
Return true if the widget has been properly initialized.
Every attribute editor widget needs a factory, which inherits this class.
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.
static void logMessage(const QString &message, const QString &tag=QString(), MessageLevel level=QgsMessageLog::WARNING)
add a message to the instance (and create it if necessary)
int indexOf(const QString &fieldName) const
Get the field index from the field name.
Definition: qgsfields.cpp:179
QgsEditorWidgetSetup findBest(const QgsVectorLayer *vl, const QString &fieldName) const
Find the best editor widget and its configuration for a given field.
Holder for the widget type and its configuration for a field.
Factory for widgets for editing a QVariantMap.
QString name(const QString &widgetId)
Get the human readable name for a widget type.
QgsSearchWidgetWrapper * createSearchWidget(const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, const QVariantMap &config, QWidget *parent, const QgsAttributeEditorContext &context=QgsAttributeEditorContext())
QWidget * widget()
Access the widget managed by this wrapper.
bool registerWidget(const QString &widgetId, QgsEditorWidgetFactory *widgetFactory)
Register a new widget factory with the given id.
void setConfig(const QVariantMap &config)
Will set the config of this wrapper to the specified config.
Represents a vector layer which manages a vector based data sets.
QgsField field(int fieldIdx) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:140
void initEditors(QgsMapCanvas *mapCanvas=nullptr, QgsMessageBar *messageBar=nullptr)
Registers all the default widgets.