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