QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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 = vl->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 }
Shows a search widget on a filter form.
QVariantMap config() const
This class should be subclassed for every configurable editor widget type.
QString name
Definition: qgsfield.h:58
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.
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
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Definition: qgsfield.cpp:438
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:75
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
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.
Editor widget factory for binary (BLOB) widgets.
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.
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.
int indexOf(const QString &fieldName) const
Gets the field index from the field name.
Definition: qgsfields.cpp:207
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)
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.
QgsField field(int fieldIdx) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:168
void initEditors(QgsMapCanvas *mapCanvas=nullptr, QgsMessageBar *messageBar=nullptr)
Registers all the default widgets.