QGIS API Documentation  2.14.0-Essen
qgseditformconfig.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgseditformconfig.cpp
3  ---------------------
4  begin : November 2015
5  copyright : (C) 2015 by 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 #include "qgseditformconfig.h"
16 #include "qgsproject.h"
17 
19  : QObject( parent )
20  , mEditorLayout( GeneratedLayout )
21  , mInitCodeSource( CodeSourceNone )
22  , mSuppressForm( SuppressDefault )
23 {
24  connect( QgsProject::instance()->relationManager(), SIGNAL( relationsLoaded() ), this, SLOT( onRelationsLoaded() ) );
25 }
26 
28 {
29  if ( fieldIdx < 0 || fieldIdx >= mFields.count() )
30  return "TextEdit";
31 
32  return mEditorWidgetV2Types.value( mFields[fieldIdx].name(), "TextEdit" );
33 }
34 
36 {
37  return mEditorWidgetV2Types.value( fieldName, "TextEdit" );
38 }
39 
41 {
42  if ( fieldIdx < 0 || fieldIdx >= mFields.count() )
43  return QgsEditorWidgetConfig();
44 
45  return mWidgetConfigs.value( mFields[fieldIdx].name() );
46 }
47 
49 {
50  return mWidgetConfigs.value( widgetName );
51 }
52 
53 void QgsEditFormConfig::setFields( const QgsFields& fields )
54 {
55  mFields = fields;
56 }
57 
59 {
60  if ( attrIdx >= 0 && attrIdx < mFields.count() )
61  mEditorWidgetV2Types[ mFields.at( attrIdx ).name()] = widgetType;
62 }
63 
65 {
66  if ( attrIdx >= 0 && attrIdx < mFields.count() )
67  mWidgetConfigs[ mFields.at( attrIdx ).name()] = config;
68 }
69 
70 void QgsEditFormConfig::setWidgetConfig( const QString& widgetName, const QgsEditorWidgetConfig& config )
71 {
72  mWidgetConfigs[widgetName] = config;
73 }
74 
76 {
77  return mWidgetConfigs.remove( widgetName ) != 0;
78 }
79 
81 {
82  if ( fieldIdx < 0 || fieldIdx >= mFields.count() )
83  return false;
84 
85  return mWidgetConfigs.remove( mFields[fieldIdx].name() );
86 }
87 
89 {
90  if ( ui.isEmpty() || ui.isNull() )
91  {
93  }
94  else
95  {
97  }
98  mUiFormPath = ui;
99 }
100 
101 bool QgsEditFormConfig::readOnly( int idx ) const
102 {
103  if ( idx >= 0 && idx < mFields.count() )
104  {
105  if ( mFields.fieldOrigin( idx ) == QgsFields::OriginJoin
106  || mFields.fieldOrigin( idx ) == QgsFields::OriginExpression )
107  return true;
108  return !mFieldEditables.value( mFields.at( idx ).name(), true );
109  }
110  else
111  return false;
112 }
113 
114 bool QgsEditFormConfig::labelOnTop( int idx ) const
115 {
116  if ( idx >= 0 && idx < mFields.count() )
117  return mLabelOnTop.value( mFields.at( idx ).name(), false );
118  else
119  return false;
120 }
121 
123 {
124  if ( idx >= 0 && idx < mFields.count() )
125  mFieldEditables[ mFields.at( idx ).name()] = !readOnly;
126 }
127 
128 void QgsEditFormConfig::setLabelOnTop( int idx, bool onTop )
129 {
130  if ( idx >= 0 && idx < mFields.count() )
131  mLabelOnTop[ mFields.at( idx ).name()] = onTop;
132 }
133 
135 {
136  QDomNode editFormNode = node.namedItem( "editform" );
137  if ( !editFormNode.isNull() )
138  {
139  QDomElement e = editFormNode.toElement();
140  mUiFormPath = QgsProject::instance()->readPath( e.text() );
141  }
142 
143  QDomNode editFormInitNode = node.namedItem( "editforminit" );
144  if ( !editFormInitNode.isNull() )
145  {
146  mInitFunction = editFormInitNode.toElement().text();
147  }
148 
149  QDomNode editFormInitCodeSourceNode = node.namedItem( "editforminitcodesource" );
150  if ( !editFormInitCodeSourceNode.isNull() || ( !editFormInitCodeSourceNode.isNull() && !editFormInitCodeSourceNode.toElement().text().isEmpty() ) )
151  {
152  setInitCodeSource( static_cast< QgsEditFormConfig::PythonInitCodeSource >( editFormInitCodeSourceNode.toElement().text().toInt() ) );
153  }
154 
155  QDomNode editFormInitCodeNode = node.namedItem( "editforminitcode" );
156  if ( !editFormInitCodeNode.isNull() )
157  {
158  setInitCode( editFormInitCodeNode.toElement().text() );
159  }
160 
161  // Temporary < 2.12 b/w compatibility "dot" support patch
162  // @see: https://github.com/qgis/QGIS/pull/2498
163  // For b/w compatibility, check if there's a dot in the function name
164  // and if yes, transform it in an import statement for the module
165  // and set the PythonInitCodeSource to CodeSourceDialog
166  int dotPos = mInitFunction.lastIndexOf( '.' );
167  if ( dotPos >= 0 ) // It's a module
168  {
170  setInitCode( QString( "from %1 import %2\n" ).arg( mInitFunction.left( dotPos ), mInitFunction.mid( dotPos + 1 ) ) );
171  setInitFunction( mInitFunction.mid( dotPos + 1 ) );
172  }
173 
174  QDomNode editFormInitFilePathNode = node.namedItem( "editforminitfilepath" );
175  if ( !editFormInitFilePathNode.isNull() || ( !editFormInitFilePathNode.isNull() && !editFormInitFilePathNode.toElement().text().isEmpty() ) )
176  {
177  setInitFilePath( QgsProject::instance()->readPath( editFormInitFilePathNode.toElement().text() ) );
178  }
179 
180  QDomNode fFSuppNode = node.namedItem( "featformsuppress" );
181  if ( fFSuppNode.isNull() )
182  {
183  mSuppressForm = QgsEditFormConfig::SuppressDefault;
184  }
185  else
186  {
187  QDomElement e = fFSuppNode.toElement();
188  mSuppressForm = static_cast< QgsEditFormConfig::FeatureFormSuppress >( e.text().toInt() );
189  }
190 
191  // tab display
192  QDomNode editorLayoutNode = node.namedItem( "editorlayout" );
193  if ( editorLayoutNode.isNull() )
194  {
195  mEditorLayout = QgsEditFormConfig::GeneratedLayout;
196  }
197  else
198  {
199  if ( editorLayoutNode.toElement().text() == "uifilelayout" )
200  {
201  mEditorLayout = QgsEditFormConfig::UiFileLayout;
202  }
203  else if ( editorLayoutNode.toElement().text() == "tablayout" )
204  {
205  mEditorLayout = QgsEditFormConfig::TabLayout;
206  }
207  else
208  {
209  mEditorLayout = QgsEditFormConfig::GeneratedLayout;
210  }
211  }
212 
213  // tabs and groups display info
214  clearTabs();
215  QDomNode attributeEditorFormNode = node.namedItem( "attributeEditorForm" );
216  QDomNodeList attributeEditorFormNodeList = attributeEditorFormNode.toElement().childNodes();
217 
218  for ( int i = 0; i < attributeEditorFormNodeList.size(); i++ )
219  {
220  QDomElement elem = attributeEditorFormNodeList.at( i ).toElement();
221 
222  QgsAttributeEditorElement *attributeEditorWidget = attributeEditorElementFromDomElement( elem, this );
223  addTab( attributeEditorWidget );
224  }
225 
226 
229 
230  QDomElement widgetsElem = node.namedItem( "widgets" ).toElement();
231 
232  QDomNodeList widgetConfigsElems = widgetsElem.childNodes();
233 
234  for ( int i = 0; i < widgetConfigsElems.size(); ++i )
235  {
237 
238  QDomElement wdgElem = widgetConfigsElems.at( i ).toElement();
239 
240  QDomElement cfgElem = wdgElem.namedItem( "config" ).toElement();
241 
242  for ( int j = 0; j < cfgElem.attributes().size(); ++j )
243  {
244  QDomAttr attr = cfgElem.attributes().item( j ).toAttr();
245  cfg.insert( attr.name(), attr.value() );
246  }
247 
248  QDomNodeList optionElements = cfgElem.elementsByTagName( "option" );
249  for ( int j = 0; j < optionElements.size(); ++j )
250  {
251  QString key = optionElements.at( j ).toElement().attribute( "key" );
252  QString value = optionElements.at( j ).toElement().attribute( "value" );
253  cfg.insert( key, value );
254  }
255 
256  setWidgetConfig( wdgElem.attribute( "name" ), cfg );
257  }
259 }
260 
262 {
263  QDomDocument doc( node.ownerDocument() );
264 
265  QDomElement efField = doc.createElement( "editform" );
266  QDomText efText = doc.createTextNode( QgsProject::instance()->writePath( uiForm() ) );
267  efField.appendChild( efText );
268  node.appendChild( efField );
269 
270  QDomElement efiField = doc.createElement( "editforminit" );
271  if ( !initFunction().isEmpty() )
272  efiField.appendChild( doc.createTextNode( initFunction() ) );
273  node.appendChild( efiField );
274 
275  QDomElement eficsField = doc.createElement( "editforminitcodesource" );
276  eficsField.appendChild( doc.createTextNode( QString::number( initCodeSource() ) ) );
277  node.appendChild( eficsField );
278 
279  QDomElement efifpField = doc.createElement( "editforminitfilepath" );
280  efifpField.appendChild( doc.createTextNode( QgsProject::instance()->writePath( initFilePath() ) ) );
281  node.appendChild( efifpField );
282 
283 
284  QDomElement eficField = doc.createElement( "editforminitcode" );
285  eficField.appendChild( doc.createCDATASection( initCode() ) );
286  node.appendChild( eficField );
287 
288  QDomElement fFSuppElem = doc.createElement( "featformsuppress" );
289  QDomText fFSuppText = doc.createTextNode( QString::number( suppress() ) );
290  fFSuppElem.appendChild( fFSuppText );
291  node.appendChild( fFSuppElem );
292 
293  // tab display
294  QDomElement editorLayoutElem = doc.createElement( "editorlayout" );
295  switch ( layout() )
296  {
298  editorLayoutElem.appendChild( doc.createTextNode( "uifilelayout" ) );
299  break;
300 
302  editorLayoutElem.appendChild( doc.createTextNode( "tablayout" ) );
303  break;
304 
306  default:
307  editorLayoutElem.appendChild( doc.createTextNode( "generatedlayout" ) );
308  break;
309  }
310 
311  node.appendChild( editorLayoutElem );
312 
313  // tabs and groups of edit form
314  if ( tabs().size() > 0 )
315  {
316  QDomElement tabsElem = doc.createElement( "attributeEditorForm" );
317 
318  for ( QList< QgsAttributeEditorElement* >::const_iterator it = mAttributeEditorElements.constBegin(); it != mAttributeEditorElements.constEnd(); ++it )
319  {
320  QDomElement attributeEditorWidgetElem = ( *it )->toDomElement( doc );
321  tabsElem.appendChild( attributeEditorWidgetElem );
322  }
323 
324  node.appendChild( tabsElem );
325  }
326 
329 
330  QDomElement widgetsElem = doc.createElement( "widgets" );
331 
332  QMap<QString, QgsEditorWidgetConfig >::ConstIterator configIt( mWidgetConfigs.constBegin() );
333 
334  while ( configIt != mWidgetConfigs.constEnd() )
335  {
336  if ( mFields.indexFromName( configIt.key() ) == -1 )
337  {
338  QDomElement widgetElem = doc.createElement( "widget" );
339  widgetElem.setAttribute( "name", configIt.key() );
340 
341  QDomElement configElem = doc.createElement( "config" );
342  widgetElem.appendChild( configElem );
343 
344  QgsEditorWidgetConfig::ConstIterator cfgIt( configIt.value().constBegin() );
345 
346  while ( cfgIt != configIt.value().constEnd() )
347  {
348  QDomElement optionElem = doc.createElement( "option" );
349  optionElem.setAttribute( "key", cfgIt.key() );
350  optionElem.setAttribute( "value", cfgIt.value().toString() );
351  configElem.appendChild( optionElem );
352  ++cfgIt;
353  }
354 
355  widgetsElem.appendChild( widgetElem );
356  }
357  ++configIt;
358  }
359 
360  node.appendChild( widgetsElem );
361 
363 }
364 
366 {
367  QgsAttributeEditorElement* newElement = nullptr;
368 
369  if ( elem.tagName() == "attributeEditorContainer" )
370  {
371  QgsAttributeEditorContainer* container = new QgsAttributeEditorContainer( elem.attribute( "name" ), parent );
372 
373  QDomNodeList childNodeList = elem.childNodes();
374 
375  for ( int i = 0; i < childNodeList.size(); i++ )
376  {
377  QDomElement childElem = childNodeList.at( i ).toElement();
378  QgsAttributeEditorElement *myElem = attributeEditorElementFromDomElement( childElem, container );
379  if ( myElem )
380  container->addChildElement( myElem );
381  }
382 
383  newElement = container;
384  }
385  else if ( elem.tagName() == "attributeEditorField" )
386  {
387  QString name = elem.attribute( "name" );
388  int idx = mFields.fieldNameIndex( name );
389  newElement = new QgsAttributeEditorField( name, idx, parent );
390  }
391  else if ( elem.tagName() == "attributeEditorRelation" )
392  {
393  // At this time, the relations are not loaded
394  // So we only grab the id and delegate the rest to onRelationsLoaded()
395  QString name = elem.attribute( "name" );
396  newElement = new QgsAttributeEditorRelation( name, elem.attribute( "relation", "[None]" ), parent );
397  }
398  return newElement;
399 }
400 
401 void QgsEditFormConfig::onRelationsLoaded()
402 {
403  Q_FOREACH ( QgsAttributeEditorElement* elem, mAttributeEditorElements )
404  {
406  {
407  QgsAttributeEditorContainer* cont = dynamic_cast< QgsAttributeEditorContainer* >( elem );
408  if ( !cont )
409  continue;
410 
412  Q_FOREACH ( QgsAttributeEditorElement* relElem, relations )
413  {
414  QgsAttributeEditorRelation* rel = dynamic_cast< QgsAttributeEditorRelation* >( relElem );
415  if ( !rel )
416  continue;
417 
418  rel->init( QgsProject::instance()->relationManager() );
419  }
420  }
421  }
422 }
QDomNodeList elementsByTagName(const QString &tagname) const
Use the python code provided in the dialog.
QString writePath(const QString &filename, const QString &relativeBasePath=QString::null) const
Prepare a filename to save it to the project file.
bool init(QgsRelationManager *relManager)
Initializes the relation from the id.
field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
Definition: qgsfield.h:195
This is an abstract base class for any elements of a drag and drop form.
void setWidgetConfig(int attrIdx, const QgsEditorWidgetConfig &config)
Set the editor widget config for a field.
QString name() const
PythonInitCodeSource initCodeSource() const
Return python code source for edit form initialization (if it shall be loaded from a file...
QDomNode appendChild(const QDomNode &newChild)
void setInitFilePath(const QString &filePath)
Set python external file path for edit form initialization.
void setInitCodeSource(const PythonInitCodeSource initCodeSource)
Set if python code shall be used for edit form initialization and its origin.
bool removeWidgetConfig(int fieldIdx)
Remove the configuration for the editor widget used to represent the field at the given index...
QString attribute(const QString &name, const QString &defValue) const
FeatureFormSuppress suppress() const
Type of feature form pop-up suppression after feature creation (overrides app setting) ...
int fieldNameIndex(const QString &fieldName) const
Look up field&#39;s index from name also looks up case-insensitive if there is no match otherwise...
Definition: qgsfield.cpp:503
Use a layout with tabs and group boxes. Needs to be configured.
QgsEditFormConfig(QObject *parent=nullptr)
Create a new edit form config.
Container of fields for a vector layer.
Definition: qgsfield.h:187
bool readOnly(int idx) const
This returns true if the field is manually set to read only or if the field does not support editing ...
This element will load a field&#39;s widget onto the form.
This element will load a relation editor onto the form.
void setInitFunction(const QString &function)
Set python function for edit form initialization.
void setWidgetType(int fieldIdx, const QString &widgetType)
Set the editor widget type for a field.
QString widgetType(int fieldIdx) const
Get the id for the editor widget used to represent the field at the given index.
QDomNodeList childNodes() const
QString readPath(QString filename) const
Turn filename read from the project file to an absolute path.
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
bool isNull() const
bool labelOnTop(int idx) const
If this returns true, the widget at the given index will receive its label on the previous line while...
Use the application-wide setting.
EditorLayout layout() const
Get the active layout style for the attribute editor for this layer.
QString uiForm() const
Get path to the .ui form.
void setLabelOnTop(int idx, bool onTop)
If this is set to true, the widget at the given index will receive its label on the previous line whi...
QDomElement toElement() const
void writeXml(QDomNode &node) const
Write XML information Serialize on project save.
const char * name() const
QString number(int n, int base)
QDomDocument ownerDocument() const
QString text() const
void setLayout(EditorLayout editorLayout)
Set the active layout style for the attribute editor for this layer.
void setAttribute(const QString &name, const QString &value)
void addTab(QgsAttributeEditorElement *data)
This is only useful in combination with EditorLayout::TabLayout.
QString name() const
Gets the name of the field.
Definition: qgsfield.cpp:84
int toInt(bool *ok, int base) const
FeatureFormSuppress
Types of feature form suppression after feature creation.
bool isEmpty() const
AttributeEditorType type() const
The type of this element.
QgsEditorWidgetConfig widgetConfig(int fieldIdx) const
Get the configuration for the editor widget used to represent the field at the given index...
int count() const
Return number of items.
Definition: qgsfield.cpp:365
void setInitCode(const QString &code)
Set python code for edit form initialization.
const QgsField & at(int i) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfield.cpp:385
void clearTabs()
Clears all the tabs for the attribute editor form with EditorLayout::TabLayout.
int indexFromName(const QString &name) const
Look up field&#39;s index from name. Returns -1 on error.
Definition: qgsfield.cpp:424
QgsAttributeEditorElement * attributeEditorElementFromDomElement(QDomElement &elem, QObject *parent)
Deserialize drag and drop designer elements.
QDomNode namedItem(const QString &name) const
QString value() const
bool isNull() const
void setUiForm(const QString &ui)
Set path to the .ui form.
QString mid(int position, int n) const
Autogenerate a simple tabular layout for the form.
void setReadOnly(int idx, bool readOnly=true)
If set to false, the widget at the given index will be read-only.
Load a .ui file for the layout. Needs to be configured.
QString initFunction() const
Get python function for edit form initialization.
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:381
QList< QgsAttributeEditorElement * > tabs() const
Returns a list of tabs for EditorLayout::TabLayout.
QDomAttr toAttr() const
FieldOrigin fieldOrigin(int fieldIdx) const
Get field&#39;s origin (value from an enumeration)
Definition: qgsfield.cpp:411
This is a container for attribute editors, used to group them visually in the attribute form if it is...
QString left(int n) const
QString initCode() const
Get python code for edit form initialization.
QMap< QString, QVariant > QgsEditorWidgetConfig
Holds a set of configuration parameters for a editor widget wrapper.
void readXml(const QDomNode &node)
Read XML information Deserialize on project load.
virtual void addChildElement(QgsAttributeEditorElement *element)
Add a child element to this container.
iterator insert(const Key &key, const T &value)
QString tagName() const
int size() const
const_iterator constEnd() const
const_iterator constBegin() const
typedef ConstIterator
QDomNode item(int index) const
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const
field is calculated from an expression
Definition: qgsfield.h:197
int size() const
virtual QList< QgsAttributeEditorElement * > findElements(AttributeEditorType type) const
Traverses the element tree to find any element of the specified type.
QDomNode at(int index) const
const T value(const Key &key) const
QDomNamedNodeMap attributes() const
QString initFilePath() const
Get python external file path for edit form initialization.