QGIS API Documentation  2.9.0-Master
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 dot kuhn at gmx 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 "qgseditorwidgetfactory.h"
20 #include "qgslegacyhelpers.h"
21 #include "qgsmessagelog.h"
22 #include "qgsproject.h"
23 #include "qgsvectorlayer.h"
24 #include "qgsmaplayerregistry.h"
25 
26 // Editors
28 #include "qgsrangewidgetfactory.h"
33 #include "qgshiddenwidgetfactory.h"
37 #include "qgsuuidwidgetfactory.h"
38 #include "qgsphotowidgetfactory.h"
40 #include "qgscolorwidgetfactory.h"
42 #include "qgsdatetimeeditfactory.h"
43 
45 {
46  static QgsEditorWidgetRegistry sInstance;
47  return &sInstance;
48 }
49 
51 {
53  reg->registerWidget( "Classification", new QgsClassificationWidgetWrapperFactory( tr( "Classification" ) ) );
54  reg->registerWidget( "Range", new QgsRangeWidgetFactory( tr( "Range" ) ) );
55  reg->registerWidget( "UniqueValues", new QgsUniqueValueWidgetFactory( tr( "Unique Values" ) ) );
56  reg->registerWidget( "FileName", new QgsFileNameWidgetFactory( tr( "File Name" ) ) );
57  reg->registerWidget( "ValueMap", new QgsValueMapWidgetFactory( tr( "Value Map" ) ) );
58  reg->registerWidget( "Enumeration", new QgsEnumerationWidgetFactory( tr( "Enumeration" ) ) );
59  reg->registerWidget( "Hidden", new QgsHiddenWidgetFactory( tr( "Hidden" ) ) );
60  reg->registerWidget( "CheckBox", new QgsCheckboxWidgetFactory( tr( "Check Box" ) ) );
61  reg->registerWidget( "TextEdit", new QgsTextEditWidgetFactory( tr( "Text Edit" ) ) );
62  reg->registerWidget( "ValueRelation", new QgsValueRelationWidgetFactory( tr( "Value Relation" ) ) );
63  reg->registerWidget( "UuidGenerator", new QgsUuidWidgetFactory( tr( "Uuid Generator" ) ) );
64  reg->registerWidget( "Photo", new QgsPhotoWidgetFactory( tr( "Photo" ) ) );
65 #ifdef WITH_QTWEBKIT
66  reg->registerWidget( "WebView", new QgsWebViewWidgetFactory( tr( "Web View" ) ) );
67 #endif
68  reg->registerWidget( "Color", new QgsColorWidgetFactory( tr( "Color" ) ) );
69  reg->registerWidget( "RelationReference", new QgsRelationReferenceFactory( tr( "Relation Reference" ), mapCanvas, messageBar ) );
70  reg->registerWidget( "DateTime", new QgsDateTimeEditFactory( tr( "Date/Time" ) ) );
71 }
72 
74 {
75  connect( QgsProject::instance(), SIGNAL( readMapLayer( QgsMapLayer*, const QDomElement& ) ), this, SLOT( readMapLayer( QgsMapLayer*, const QDomElement& ) ) );
76  connect( QgsProject::instance(), SIGNAL( writeMapLayer( QgsMapLayer*, QDomElement&, QDomDocument& ) ), this, SLOT( writeMapLayer( QgsMapLayer*, QDomElement&, QDomDocument& ) ) );
77 
78  connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWasAdded( QgsMapLayer* ) ), this, SLOT( mapLayerAdded( QgsMapLayer* ) ) );
79 }
80 
82 {
83  qDeleteAll( mWidgetFactories.values() );
84 }
85 
86 QgsEditorWidgetWrapper* QgsEditorWidgetRegistry::create( const QString& widgetId, QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, QWidget* editor, QWidget* parent, const QgsAttributeEditorContext &context )
87 {
88  if ( mWidgetFactories.contains( widgetId ) )
89  {
90  QgsEditorWidgetWrapper* ww = mWidgetFactories[widgetId]->create( vl, fieldIdx, editor, parent );
91 
92  if ( ww )
93  {
94  ww->setConfig( config );
95  ww->setContext( context );
96  // Make sure that there is a widget created at this point
97  // so setValue() et al won't crash
98  ww->widget();
99  return ww;
100  }
101  }
102  return 0;
103 }
104 
105 QgsEditorConfigWidget* QgsEditorWidgetRegistry::createConfigWidget( const QString& widgetId, QgsVectorLayer* vl, int fieldIdx, QWidget* parent )
106 {
107  if ( mWidgetFactories.contains( widgetId ) )
108  {
109  return mWidgetFactories[widgetId]->configWidget( vl, fieldIdx, parent );
110  }
111  return 0;
112 }
113 
114 QString QgsEditorWidgetRegistry::name( const QString& widgetId )
115 {
116  if ( mWidgetFactories.contains( widgetId ) )
117  {
118  return mWidgetFactories[widgetId]->name();
119  }
120 
121  return QString();
122 }
123 
124 const QMap<QString, QgsEditorWidgetFactory*>& QgsEditorWidgetRegistry::factories()
125 {
126  return mWidgetFactories;
127 }
128 
130 {
131  return mWidgetFactories.value( widgetId );
132 }
133 
134 bool QgsEditorWidgetRegistry::registerWidget( const QString& widgetId, QgsEditorWidgetFactory* widgetFactory )
135 {
136  if ( !widgetFactory )
137  {
138  QgsMessageLog::instance()->logMessage( "QgsEditorWidgetRegistry: Factory not valid." );
139  return false;
140  }
141  else if ( mWidgetFactories.contains( widgetId ) )
142  {
143  QgsMessageLog::instance()->logMessage( QString( "QgsEditorWidgetRegistry: Factory with id %1 already registered." ).arg( widgetId ) );
144  return false;
145  }
146  else
147  {
148  mWidgetFactories.insert( widgetId, widgetFactory );
149  return true;
150  }
151 }
152 
153 void QgsEditorWidgetRegistry::readMapLayer( QgsMapLayer* mapLayer, const QDomElement& layerElem )
154 {
155  if ( mapLayer->type() != QgsMapLayer::VectorLayer )
156  {
157  return;
158  }
159 
160  QgsVectorLayer* vectorLayer = qobject_cast<QgsVectorLayer*>( mapLayer );
161  Q_ASSERT( vectorLayer );
162 
163  QDomNodeList editTypeNodes = layerElem.namedItem( "edittypes" ).childNodes();
164 
165  for ( int i = 0; i < editTypeNodes.size(); i++ )
166  {
167  QDomNode editTypeNode = editTypeNodes.at( i );
168  QDomElement editTypeElement = editTypeNode.toElement();
169 
170  QString name = editTypeElement.attribute( "name" );
171 
172  int idx = vectorLayer->fieldNameIndex( name );
173  if ( idx == -1 )
174  continue;
175 
176  bool hasLegacyType;
177  QgsVectorLayer::EditType editType =
178  ( QgsVectorLayer::EditType ) editTypeElement.attribute( "type" ).toInt( &hasLegacyType );
179 
180  QString ewv2Type;
182 
183  if ( hasLegacyType && editType != QgsVectorLayer::EditorWidgetV2 )
184  {
186  ewv2Type = readLegacyConfig( vectorLayer, editTypeElement, cfg );
188  }
189  else
190  ewv2Type = editTypeElement.attribute( "widgetv2type" );
191 
192  if ( mWidgetFactories.contains( ewv2Type ) )
193  {
194  vectorLayer->setEditorWidgetV2( idx, ewv2Type );
195  QDomElement ewv2CfgElem = editTypeElement.namedItem( "widgetv2config" ).toElement();
196 
197  if ( !ewv2CfgElem.isNull() )
198  {
199  cfg = mWidgetFactories[ewv2Type]->readEditorConfig( ewv2CfgElem, vectorLayer, idx );
200  }
201 
202  vectorLayer->setFieldEditable( idx, ewv2CfgElem.attribute( "fieldEditable", "1" ) == "1" );
203  vectorLayer->setLabelOnTop( idx, ewv2CfgElem.attribute( "labelOnTop", "0" ) == "1" );
204  vectorLayer->setEditorWidgetV2Config( idx, cfg );
205  }
206  else
207  {
208  QgsMessageLog::logMessage( tr( "Unknown attribute editor widget '%1'" ).arg( ewv2Type ) );
209  }
210  }
211 }
212 
213 const QString QgsEditorWidgetRegistry::readLegacyConfig( QgsVectorLayer* vl, const QDomElement& editTypeElement, QgsEditorWidgetConfig& cfg )
214 {
215  QString name = editTypeElement.attribute( "name" );
216 
217  QgsVectorLayer::EditType editType = ( QgsVectorLayer::EditType ) editTypeElement.attribute( "type" ).toInt();
218 
220  return QgsLegacyHelpers::convertEditType( editType, cfg, vl, name, editTypeElement );
222 }
223 
224 void QgsEditorWidgetRegistry::writeMapLayer( QgsMapLayer* mapLayer, QDomElement& layerElem, QDomDocument& doc ) const
225 {
226  if ( mapLayer->type() != QgsMapLayer::VectorLayer )
227  {
228  return;
229  }
230 
231  QgsVectorLayer* vectorLayer = qobject_cast<QgsVectorLayer*>( mapLayer );
232  if ( !vectorLayer )
233  {
234  return;
235  }
236 
237  QDomNode editTypesNode = doc.createElement( "edittypes" );
238 
239  for ( int idx = 0; idx < vectorLayer->pendingFields().count(); ++idx )
240  {
241  const QgsField &field = vectorLayer->pendingFields()[ idx ];
242  const QString& widgetType = vectorLayer->editorWidgetV2( idx );
243  if ( !mWidgetFactories.contains( widgetType ) )
244  {
245  QgsMessageLog::logMessage( tr( "Could not save unknown editor widget type '%1'." ).arg( widgetType ) );
246  continue;
247  }
248 
249 
250  QDomElement editTypeElement = doc.createElement( "edittype" );
251  editTypeElement.setAttribute( "name", field.name() );
252  editTypeElement.setAttribute( "widgetv2type", widgetType );
253 
254  if ( mWidgetFactories.contains( widgetType ) )
255  {
256  QDomElement ewv2CfgElem = doc.createElement( "widgetv2config" );
257  ewv2CfgElem.setAttribute( "fieldEditable", vectorLayer->fieldEditable( idx ) );
258  ewv2CfgElem.setAttribute( "labelOnTop", vectorLayer->labelOnTop( idx ) );
259 
260  mWidgetFactories[widgetType]->writeConfig( vectorLayer->editorWidgetV2Config( idx ), ewv2CfgElem, doc, vectorLayer, idx );
261 
262  editTypeElement.appendChild( ewv2CfgElem );
263  }
264 
265  editTypesNode.appendChild( editTypeElement );
266  }
267 
268  layerElem.appendChild( editTypesNode );
269 }
270 
271 void QgsEditorWidgetRegistry::mapLayerAdded( QgsMapLayer* mapLayer )
272 {
273  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( mapLayer );
274 
275  if ( vl )
276  {
277  connect( vl, SIGNAL( readCustomSymbology( const QDomElement&, QString& ) ), this, SLOT( readSymbology( const QDomElement&, QString& ) ) );
278  connect( vl, SIGNAL( writeCustomSymbology( QDomElement&, QDomDocument&, QString& ) ), this, SLOT( writeSymbology( QDomElement&, QDomDocument&, QString& ) ) );
279  }
280 }
281 
282 void QgsEditorWidgetRegistry::readSymbology( const QDomElement& element, QString& errorMessage )
283 {
284  Q_UNUSED( errorMessage )
285  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( sender() );
286 
287  Q_ASSERT( vl );
288 
289  readMapLayer( vl, element );
290 }
291 
292 void QgsEditorWidgetRegistry::writeSymbology( QDomElement& element, QDomDocument& doc, QString& errorMessage )
293 {
294  Q_UNUSED( errorMessage )
295  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( sender() );
296 
297  Q_ASSERT( vl );
298 
299  writeMapLayer( vl, element, doc );
300 }
const QgsEditorWidgetConfig editorWidgetV2Config(int fieldIdx) const
Get the configuration for the editor widget used to represent the field at the given index...
const QString & name() const
Gets the name of the field.
Definition: qgsfield.cpp:69
bool fieldEditable(int idx)
is edit widget editable
Base class for all map layer types.
Definition: qgsmaplayer.h:49
QgsMapLayer::LayerType type() const
Get the type of the layer.
Definition: qgsmaplayer.cpp:93
This class should be subclassed for every configurable editor widget type.
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.
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:461
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:42
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:105
static void logMessage(QString message, QString tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
void setContext(const QgsAttributeEditorContext &context)
Set the context in which this widget is shown.
void setConfig(const QgsEditorWidgetConfig &config)
Will set the config of this wrapper to the specified config.
QgsEditorWidgetWrapper * create(const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, const QgsEditorWidgetConfig &config, QWidget *editor, QWidget *parent, const QgsAttributeEditorContext &context=QgsAttributeEditorContext())
Create an attribute editor widget wrapper of a given type for a given field.
const QString editorWidgetV2(int fieldIdx) const
Get the id for the editor widget used to represent the field at the given index.
const QMap< QString, QgsEditorWidgetFactory * > & factories()
Get access to all registered factories.
Every attribute editor widget needs a factory, which inherits this class.
int count() const
Return number of items.
Definition: qgsfield.cpp:279
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:38
bool labelOnTop(int idx)
label widget on top
void setEditorWidgetV2Config(int attrIdx, const QgsEditorWidgetConfig &config)
Set the editor widget config for a field.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:462
void setEditorWidgetV2(int attrIdx, const QString &widgetType)
Set the editor widget type for a field.
modularized edit widgets
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
static Q_DECL_DEPRECATED const QString convertEditType(QgsVectorLayer::EditType editType, QgsEditorWidgetConfig &cfg, QgsVectorLayer *vl, const QString &name, const QDomElement &editTypeElement=QDomElement())
static QgsMessageLog * instance()
QString name(const QString &widgetId)
Get the human readable name for a widget type.
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:351
void setFieldEditable(int idx, bool editable)
set edit widget editable
QMap< QString, QVariant > QgsEditorWidgetConfig
Holds a set of configuration parameters for a editor widget wrapper.
QWidget * widget()
Access the widget managed by this wrapper.
static void initEditors(QgsMapCanvas *mapCanvas=0, QgsMessageBar *messageBar=0)
Registers all the default widgets.
const QgsFields & pendingFields() const
returns field list in the to-be-committed state
void setLabelOnTop(int idx, bool onTop)
label widget on top
bool registerWidget(const QString &widgetId, QgsEditorWidgetFactory *widgetFactory)
Register a new widget factory with the given id.
Represents a vector layer which manages a vector based data sets.
int fieldNameIndex(const QString &fieldName) const
Returns the index of a field name or -1 if the field does not exist.
#define tr(sourceText)