QGIS API Documentation  3.2.0-Bonn (bc43194)
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.
QVariantMap config() const
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.
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:395
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:74
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:145
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 override
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.
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:189
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:150
void initEditors(QgsMapCanvas *mapCanvas=nullptr, QgsMessageBar *messageBar=nullptr)
Registers all the default widgets.