QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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  reg->registerWidget( "WebView", new QgsWebViewWidgetFactory( tr( "Web View" ) ) );
66  reg->registerWidget( "Color", new QgsColorWidgetFactory( tr( "Color" ) ) );
67  reg->registerWidget( "RelationReference", new QgsRelationReferenceFactory( tr( "Relation Reference" ), mapCanvas, messageBar ) );
68  reg->registerWidget( "DateTime", new QgsDateTimeEditFactory( tr( "Date/Time" ) ) );
69 }
70 
72 {
73  connect( QgsProject::instance(), SIGNAL( readMapLayer( QgsMapLayer*, const QDomElement& ) ), this, SLOT( readMapLayer( QgsMapLayer*, const QDomElement& ) ) );
74  connect( QgsProject::instance(), SIGNAL( writeMapLayer( QgsMapLayer*, QDomElement&, QDomDocument& ) ), this, SLOT( writeMapLayer( QgsMapLayer*, QDomElement&, QDomDocument& ) ) );
75 
76  connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWasAdded( QgsMapLayer* ) ), this, SLOT( mapLayerAdded( QgsMapLayer* ) ) );
77 }
78 
80 {
81  qDeleteAll( mWidgetFactories.values() );
82 }
83 
84 QgsEditorWidgetWrapper* QgsEditorWidgetRegistry::create( const QString& widgetId, QgsVectorLayer* vl, int fieldIdx, const QgsEditorWidgetConfig& config, QWidget* editor, QWidget* parent, const QgsAttributeEditorContext context )
85 {
86  if ( mWidgetFactories.contains( widgetId ) )
87  {
88  QgsEditorWidgetWrapper* ww = mWidgetFactories[widgetId]->create( vl, fieldIdx, editor, parent );
89 
90  if ( ww )
91  {
92  ww->setConfig( config );
93  ww->setContext( context );
94  // Make sure that there is a widget created at this point
95  // so setValue() et al won't crash
96  ww->widget();
97  return ww;
98  }
99  }
100  return 0;
101 }
102 
103 QgsEditorConfigWidget* QgsEditorWidgetRegistry::createConfigWidget( const QString& widgetId, QgsVectorLayer* vl, int fieldIdx, QWidget* parent )
104 {
105  if ( mWidgetFactories.contains( widgetId ) )
106  {
107  return mWidgetFactories[widgetId]->configWidget( vl, fieldIdx, parent );
108  }
109  return 0;
110 }
111 
112 QString QgsEditorWidgetRegistry::name( const QString& widgetId )
113 {
114  if ( mWidgetFactories.contains( widgetId ) )
115  {
116  return mWidgetFactories[widgetId]->name();
117  }
118 
119  return QString();
120 }
121 
122 const QMap<QString, QgsEditorWidgetFactory*>& QgsEditorWidgetRegistry::factories()
123 {
124  return mWidgetFactories;
125 }
126 
128 {
129  return mWidgetFactories.value( widgetId );
130 }
131 
132 bool QgsEditorWidgetRegistry::registerWidget( const QString& widgetId, QgsEditorWidgetFactory* widgetFactory )
133 {
134  if ( !widgetFactory )
135  {
136  QgsMessageLog::instance()->logMessage( "QgsEditorWidgetRegistry: Factory not valid." );
137  return false;
138  }
139  else if ( mWidgetFactories.contains( widgetId ) )
140  {
141  QgsMessageLog::instance()->logMessage( QString( "QgsEditorWidgetRegistry: Factory with id %1 already registered." ).arg( widgetId ) );
142  return false;
143  }
144  else
145  {
146  mWidgetFactories.insert( widgetId, widgetFactory );
147  return true;
148  }
149 }
150 
151 void QgsEditorWidgetRegistry::readMapLayer( QgsMapLayer* mapLayer, const QDomElement& layerElem )
152 {
153  if ( mapLayer->type() != QgsMapLayer::VectorLayer )
154  {
155  return;
156  }
157 
158  QgsVectorLayer* vectorLayer = qobject_cast<QgsVectorLayer*>( mapLayer );
159  Q_ASSERT( vectorLayer );
160 
161  QDomNodeList editTypeNodes = layerElem.namedItem( "edittypes" ).childNodes();
162 
163  for ( int i = 0; i < editTypeNodes.size(); i++ )
164  {
165  QDomNode editTypeNode = editTypeNodes.at( i );
166  QDomElement editTypeElement = editTypeNode.toElement();
167 
168  QString name = editTypeElement.attribute( "name" );
169 
170  int idx = vectorLayer->fieldNameIndex( name );
171  if ( idx == -1 )
172  continue;
173 
174  bool hasLegacyType;
175  QgsVectorLayer::EditType editType =
176  ( QgsVectorLayer::EditType ) editTypeElement.attribute( "type" ).toInt( &hasLegacyType );
177 
178  QString ewv2Type;
180 
181  if ( hasLegacyType && editType != QgsVectorLayer::EditorWidgetV2 )
182  {
184  ewv2Type = readLegacyConfig( vectorLayer, editTypeElement, cfg );
186  }
187  else
188  ewv2Type = editTypeElement.attribute( "widgetv2type" );
189 
190  if ( mWidgetFactories.contains( ewv2Type ) )
191  {
192  vectorLayer->setEditorWidgetV2( idx, ewv2Type );
193  QDomElement ewv2CfgElem = editTypeElement.namedItem( "widgetv2config" ).toElement();
194 
195  if ( !ewv2CfgElem.isNull() )
196  {
197  cfg = mWidgetFactories[ewv2Type]->readEditorConfig( ewv2CfgElem, vectorLayer, idx );
198  }
199 
200  vectorLayer->setFieldEditable( idx, ewv2CfgElem.attribute( "fieldEditable", "1" ) == "1" );
201  vectorLayer->setLabelOnTop( idx, ewv2CfgElem.attribute( "labelOnTop", "0" ) == "1" );
202  vectorLayer->setEditorWidgetV2Config( idx, cfg );
203  }
204  else
205  {
206  QgsMessageLog::logMessage( tr( "Unknown attribute editor widget '%1'" ).arg( ewv2Type ) );
207  }
208  }
209 }
210 
211 const QString QgsEditorWidgetRegistry::readLegacyConfig( QgsVectorLayer* vl, const QDomElement& editTypeElement, QgsEditorWidgetConfig& cfg )
212 {
213  QString name = editTypeElement.attribute( "name" );
214 
215  QgsVectorLayer::EditType editType = ( QgsVectorLayer::EditType ) editTypeElement.attribute( "type" ).toInt();
216 
218  return QgsLegacyHelpers::convertEditType( editType, cfg, vl, name, editTypeElement );
220 }
221 
222 void QgsEditorWidgetRegistry::writeMapLayer( QgsMapLayer* mapLayer, QDomElement& layerElem, QDomDocument& doc ) const
223 {
224  if ( mapLayer->type() != QgsMapLayer::VectorLayer )
225  {
226  return;
227  }
228 
229  QgsVectorLayer* vectorLayer = qobject_cast<QgsVectorLayer*>( mapLayer );
230  if ( !vectorLayer )
231  {
232  return;
233  }
234 
235  QDomNode editTypesNode = doc.createElement( "edittypes" );
236 
237  for ( int idx = 0; idx < vectorLayer->pendingFields().count(); ++idx )
238  {
239  const QgsField &field = vectorLayer->pendingFields()[ idx ];
240  const QString& widgetType = vectorLayer->editorWidgetV2( idx );
241  if ( !mWidgetFactories.contains( widgetType ) )
242  {
243  QgsMessageLog::logMessage( tr( "Could not save unknown editor widget type '%1'." ).arg( widgetType ) );
244  continue;
245  }
246 
247 
248  QDomElement editTypeElement = doc.createElement( "edittype" );
249  editTypeElement.setAttribute( "name", field.name() );
250  editTypeElement.setAttribute( "widgetv2type", widgetType );
251 
252  if ( mWidgetFactories.contains( widgetType ) )
253  {
254  QDomElement ewv2CfgElem = doc.createElement( "widgetv2config" );
255  ewv2CfgElem.setAttribute( "fieldEditable", vectorLayer->fieldEditable( idx ) );
256  ewv2CfgElem.setAttribute( "labelOnTop", vectorLayer->labelOnTop( idx ) );
257 
258  mWidgetFactories[widgetType]->writeConfig( vectorLayer->editorWidgetV2Config( idx ), ewv2CfgElem, doc, vectorLayer, idx );
259 
260  editTypeElement.appendChild( ewv2CfgElem );
261  }
262 
263  editTypesNode.appendChild( editTypeElement );
264  }
265 
266  layerElem.appendChild( editTypesNode );
267 }
268 
269 void QgsEditorWidgetRegistry::mapLayerAdded( QgsMapLayer* mapLayer )
270 {
271  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( mapLayer );
272 
273  if ( vl )
274  {
275  connect( vl, SIGNAL( readCustomSymbology( const QDomElement&, QString& ) ), this, SLOT( readSymbology( const QDomElement&, QString& ) ) );
276  connect( vl, SIGNAL( writeCustomSymbology( QDomElement&, QDomDocument&, QString& ) ), this, SLOT( writeSymbology( QDomElement&, QDomDocument&, QString& ) ) );
277  }
278 }
279 
280 void QgsEditorWidgetRegistry::readSymbology( const QDomElement& element, QString& errorMessage )
281 {
282  Q_UNUSED( errorMessage )
283  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( sender() );
284 
285  Q_ASSERT( vl );
286 
287  readMapLayer( vl, element );
288 }
289 
290 void QgsEditorWidgetRegistry::writeSymbology( QDomElement& element, QDomDocument& doc, QString& errorMessage )
291 {
292  Q_UNUSED( errorMessage )
293  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( sender() );
294 
295  Q_ASSERT( vl );
296 
297  writeMapLayer( vl, element, doc );
298 }
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:59
bool fieldEditable(int idx)
is edit widget editable
Base class for all map layer types.
Definition: qgsmaplayer.h:48
QgsMapLayer::LayerType type() const
Get the type of the layer.
Definition: qgsmaplayer.cpp:89
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.
static QgsMapLayerRegistry * instance()
Definition: qgssingleton.h:23
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:439
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:104
static void logMessage(QString message, QString tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
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.h:214
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:33
bool labelOnTop(int idx)
label widget on top
void setContext(const QgsAttributeEditorContext context)
Set the context in which this widget is shown.
void setEditorWidgetV2Config(int attrIdx, const QgsEditorWidgetConfig &config)
Set the editor widget config for a field.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:440
void setEditorWidgetV2(int attrIdx, const QString &widgetType)
Set the editor widget type for a field.
modularized edit widgets
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:362
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)