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