QGIS API Documentation  3.14.0-Pi (9f7028fd23)
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_p.h"
16 #include "qgseditformconfig.h"
18 #include "qgspathresolver.h"
19 #include "qgsproject.h"
20 #include "qgsreadwritecontext.h"
21 #include "qgsrelationmanager.h"
22 #include "qgslogger.h"
23 #include "qgsxmlutils.h"
24 #include "qgsapplication.h"
25 
27 {
28  qDeleteAll( mChildren );
29 }
30 
32  : d( new QgsEditFormConfigPrivate() )
33 {
34 }
35 
36 void QgsEditFormConfig::setDataDefinedFieldProperties( const QString &fieldName, const QgsPropertyCollection &properties )
37 {
38  d.detach();
39  d->mDataDefinedFieldProperties[ fieldName ] = properties;
40 }
41 
43 {
44  return d->mDataDefinedFieldProperties.value( fieldName );
45 }
46 
48 {
49  return QgsEditFormConfigPrivate::propertyDefinitions();
50 }
51 
52 QVariantMap QgsEditFormConfig::widgetConfig( const QString &widgetName ) const
53 {
54  int fieldIndex = d->mFields.indexOf( widgetName );
55  if ( fieldIndex != -1 )
56  return d->mFields.at( fieldIndex ).editorWidgetSetup().config();
57  else
58  return d->mWidgetConfigs.value( widgetName );
59 }
60 
61 void QgsEditFormConfig::setFields( const QgsFields &fields )
62 {
63  d.detach();
64  d->mFields = fields;
65 
66  if ( !d->mConfiguredRootContainer )
67  {
68  d->mInvisibleRootContainer->clear();
69  for ( int i = 0; i < d->mFields.size(); ++i )
70  {
71  QgsAttributeEditorField *field = new QgsAttributeEditorField( d->mFields.at( i ).name(), i, d->mInvisibleRootContainer );
72  d->mInvisibleRootContainer->addChildElement( field );
73  }
74  }
75 }
76 
77 void QgsEditFormConfig::onRelationsLoaded()
78 {
79  const QList<QgsAttributeEditorElement *> relations = d->mInvisibleRootContainer->findElements( QgsAttributeEditorElement::AeTypeRelation );
80 
81  for ( QgsAttributeEditorElement *relElem : relations )
82  {
83  QgsAttributeEditorRelation *rel = dynamic_cast< QgsAttributeEditorRelation * >( relElem );
84  if ( !rel )
85  continue;
86 
88  }
89 }
90 
91 bool QgsEditFormConfig::setWidgetConfig( const QString &widgetName, const QVariantMap &config )
92 {
93  if ( d->mFields.indexOf( widgetName ) != -1 )
94  {
95  QgsDebugMsg( QStringLiteral( "Trying to set a widget config for a field on QgsEditFormConfig. Use layer->setEditorWidgetSetup() instead." ) );
96  return false;
97  }
98 
99  d.detach();
100  d->mWidgetConfigs[widgetName] = config;
101  return true;
102 }
103 
104 bool QgsEditFormConfig::removeWidgetConfig( const QString &widgetName )
105 {
106  d.detach();
107  return d->mWidgetConfigs.remove( widgetName ) != 0;
108 }
109 
111  : d( o.d )
112 {
113 }
114 
116 {}
117 
119 {
120  d = o.d;
121  return *this;
122 }
123 
125 {
126  return d == o.d;
127 }
128 
130 {
131  d.detach();
132  d->mInvisibleRootContainer->addChildElement( data );
133 }
134 
135 QList<QgsAttributeEditorElement *> QgsEditFormConfig::tabs() const
136 {
137  return d->mInvisibleRootContainer->children();
138 }
139 
141 {
142  d.detach();
143  d->mInvisibleRootContainer->clear();
144 }
145 
147 {
148  return d->mInvisibleRootContainer;
149 }
150 
152 {
153  return d->mEditorLayout;
154 }
155 
157 {
158  d.detach();
159  d->mEditorLayout = editorLayout;
160 
161  if ( editorLayout == TabLayout )
162  d->mConfiguredRootContainer = true;
163 }
164 
166 {
167  return d->mUiFormPath;
168 }
169 
170 void QgsEditFormConfig::setUiForm( const QString &ui )
171 {
172  if ( !ui.isEmpty() && !QUrl::fromUserInput( ui ).isLocalFile() )
173  {
174  // any existing download will not be restarted!
176  }
177 
178  if ( ui.isEmpty() )
179  {
181  }
182  else
183  {
185  }
186  d->mUiFormPath = ui;
187 }
188 
189 bool QgsEditFormConfig::readOnly( int idx ) const
190 {
191  if ( idx >= 0 && idx < d->mFields.count() )
192  {
193  if ( d->mFields.fieldOrigin( idx ) == QgsFields::OriginJoin
194  || d->mFields.fieldOrigin( idx ) == QgsFields::OriginExpression )
195  return true;
196  return !d->mFieldEditables.value( d->mFields.at( idx ).name(), true );
197  }
198  else
199  return false;
200 }
201 
202 bool QgsEditFormConfig::labelOnTop( int idx ) const
203 {
204  if ( idx >= 0 && idx < d->mFields.count() )
205  return d->mLabelOnTop.value( d->mFields.at( idx ).name(), false );
206  else
207  return false;
208 }
209 
210 void QgsEditFormConfig::setReadOnly( int idx, bool readOnly )
211 {
212  if ( idx >= 0 && idx < d->mFields.count() )
213  {
214  d.detach();
215  d->mFieldEditables[ d->mFields.at( idx ).name()] = !readOnly;
216  }
217 }
218 
219 void QgsEditFormConfig::setLabelOnTop( int idx, bool onTop )
220 {
221  if ( idx >= 0 && idx < d->mFields.count() )
222  {
223  d.detach();
224  d->mLabelOnTop[ d->mFields.at( idx ).name()] = onTop;
225  }
226 }
227 
229 {
230  return d->mInitFunction;
231 }
232 
233 void QgsEditFormConfig::setInitFunction( const QString &function )
234 {
235  d.detach();
236  d->mInitFunction = function;
237 }
238 
240 {
241  return d->mInitCode;
242 }
243 
244 void QgsEditFormConfig::setInitCode( const QString &code )
245 {
246  d.detach();
247  d->mInitCode = code;
248 }
249 
251 {
252  return d->mInitFilePath;
253 }
254 
255 void QgsEditFormConfig::setInitFilePath( const QString &filePath )
256 {
257  d.detach();
258  d->mInitFilePath = filePath;
259 
260  // if this is an URL, download file as there is a good chance it will be used later
261  if ( !filePath.isEmpty() && !QUrl::fromUserInput( filePath ).isLocalFile() )
262  {
263  // any existing download will not be restarted!
265  }
266 }
267 
269 {
270  return d->mInitCodeSource;
271 }
272 
274 {
275  d.detach();
276  d->mInitCodeSource = initCodeSource;
277 }
278 
280 {
281  return d->mSuppressForm;
282 }
283 
285 {
286  d.detach();
287  d->mSuppressForm = s;
288 }
289 
290 void QgsEditFormConfig::readXml( const QDomNode &node, QgsReadWriteContext &context )
291 {
292  QgsReadWriteContextCategoryPopper p = context.enterCategory( QObject::tr( "Edit form config" ) );
293 
294  d.detach();
295 
296  QDomNode editFormNode = node.namedItem( QStringLiteral( "editform" ) );
297  if ( !editFormNode.isNull() )
298  {
299  QDomElement e = editFormNode.toElement();
300  const bool tolerantRemoteUrls = e.hasAttribute( QStringLiteral( "tolerant" ) );
301  if ( !e.text().isEmpty() )
302  {
303  const QString uiFormPath = context.pathResolver().readPath( e.text() );
304  // <= 3.2 had a bug where invalid ui paths would get written into projects on load
305  // to avoid restoring these invalid paths, we take a less-tolerant approach for older (untrustworthy) projects
306  // and only set ui forms paths IF they are local files OR start with "http(s)".
307  const bool localFile = QFileInfo::exists( uiFormPath );
308  if ( localFile || tolerantRemoteUrls || uiFormPath.startsWith( QLatin1String( "http" ) ) )
309  setUiForm( uiFormPath );
310  }
311  }
312 
313  QDomNode editFormInitNode = node.namedItem( QStringLiteral( "editforminit" ) );
314  if ( !editFormInitNode.isNull() )
315  {
316  d->mInitFunction = editFormInitNode.toElement().text();
317  }
318 
319  QDomNode editFormInitCodeSourceNode = node.namedItem( QStringLiteral( "editforminitcodesource" ) );
320  if ( !editFormInitCodeSourceNode.isNull() && !editFormInitCodeSourceNode.toElement().text().isEmpty() )
321  {
322  setInitCodeSource( static_cast< QgsEditFormConfig::PythonInitCodeSource >( editFormInitCodeSourceNode.toElement().text().toInt() ) );
323  }
324 
325  QDomNode editFormInitCodeNode = node.namedItem( QStringLiteral( "editforminitcode" ) );
326  if ( !editFormInitCodeNode.isNull() )
327  {
328  setInitCode( editFormInitCodeNode.toElement().text() );
329  }
330 
331  // Temporary < 2.12 b/w compatibility "dot" support patch
332  // \see: https://github.com/qgis/QGIS/pull/2498
333  // For b/w compatibility, check if there's a dot in the function name
334  // and if yes, transform it in an import statement for the module
335  // and set the PythonInitCodeSource to CodeSourceDialog
336  int dotPos = d->mInitFunction.lastIndexOf( '.' );
337  if ( dotPos >= 0 ) // It's a module
338  {
340  setInitCode( QStringLiteral( "from %1 import %2\n" ).arg( d->mInitFunction.left( dotPos ), d->mInitFunction.mid( dotPos + 1 ) ) );
341  setInitFunction( d->mInitFunction.mid( dotPos + 1 ) );
342  }
343 
344  QDomNode editFormInitFilePathNode = node.namedItem( QStringLiteral( "editforminitfilepath" ) );
345  if ( !editFormInitFilePathNode.isNull() && !editFormInitFilePathNode.toElement().text().isEmpty() )
346  {
347  setInitFilePath( context.pathResolver().readPath( editFormInitFilePathNode.toElement().text() ) );
348  }
349 
350  QDomNode fFSuppNode = node.namedItem( QStringLiteral( "featformsuppress" ) );
351  if ( fFSuppNode.isNull() )
352  {
353  d->mSuppressForm = QgsEditFormConfig::SuppressDefault;
354  }
355  else
356  {
357  QDomElement e = fFSuppNode.toElement();
358  d->mSuppressForm = static_cast< QgsEditFormConfig::FeatureFormSuppress >( e.text().toInt() );
359  }
360 
361  // tab display
362  QDomNode editorLayoutNode = node.namedItem( QStringLiteral( "editorlayout" ) );
363  if ( editorLayoutNode.isNull() )
364  {
365  d->mEditorLayout = QgsEditFormConfig::GeneratedLayout;
366  }
367  else
368  {
369  if ( editorLayoutNode.toElement().text() == QLatin1String( "uifilelayout" ) )
370  {
371  d->mEditorLayout = QgsEditFormConfig::UiFileLayout;
372  }
373  else if ( editorLayoutNode.toElement().text() == QLatin1String( "tablayout" ) )
374  {
375  d->mEditorLayout = QgsEditFormConfig::TabLayout;
376  }
377  else
378  {
379  d->mEditorLayout = QgsEditFormConfig::GeneratedLayout;
380  }
381  }
382 
383  d->mFieldEditables.clear();
384  QDomNodeList editableNodeList = node.namedItem( QStringLiteral( "editable" ) ).toElement().childNodes();
385  for ( int i = 0; i < editableNodeList.size(); ++i )
386  {
387  QDomElement editableElement = editableNodeList.at( i ).toElement();
388  d->mFieldEditables.insert( editableElement.attribute( QStringLiteral( "name" ) ), static_cast< bool >( editableElement.attribute( QStringLiteral( "editable" ) ).toInt() ) );
389  }
390 
391  d->mLabelOnTop.clear();
392  QDomNodeList labelOnTopNodeList = node.namedItem( QStringLiteral( "labelOnTop" ) ).toElement().childNodes();
393  for ( int i = 0; i < labelOnTopNodeList.size(); ++i )
394  {
395  QDomElement labelOnTopElement = labelOnTopNodeList.at( i ).toElement();
396  d->mLabelOnTop.insert( labelOnTopElement.attribute( QStringLiteral( "name" ) ), static_cast< bool >( labelOnTopElement.attribute( QStringLiteral( "labelOnTop" ) ).toInt() ) );
397  }
398 
399  // Read data defined field properties
400  QDomNodeList fieldDDPropertiesNodeList = node.namedItem( QStringLiteral( "dataDefinedFieldProperties" ) ).toElement().childNodes();
401  for ( int i = 0; i < fieldDDPropertiesNodeList.size(); ++i )
402  {
403  QDomElement DDElement = fieldDDPropertiesNodeList.at( i ).toElement();
404  QgsPropertyCollection collection;
405  collection.readXml( DDElement, propertyDefinitions() );
406  d->mDataDefinedFieldProperties.insert( DDElement.attribute( QStringLiteral( "name" ) ), collection );
407  }
408 
409  QDomNodeList widgetsNodeList = node.namedItem( QStringLiteral( "widgets" ) ).toElement().childNodes();
410 
411  for ( int i = 0; i < widgetsNodeList.size(); ++i )
412  {
413  QDomElement widgetElement = widgetsNodeList.at( i ).toElement();
414  QVariant config = QgsXmlUtils::readVariant( widgetElement.firstChildElement( QStringLiteral( "config" ) ) );
415 
416  d->mWidgetConfigs[widgetElement.attribute( QStringLiteral( "name" ) )] = config.toMap();
417  }
418 
419  // tabs and groups display info
420  QDomNode attributeEditorFormNode = node.namedItem( QStringLiteral( "attributeEditorForm" ) );
421  if ( !attributeEditorFormNode.isNull() )
422  {
423  QDomNodeList attributeEditorFormNodeList = attributeEditorFormNode.toElement().childNodes();
424 
425  if ( attributeEditorFormNodeList.size() )
426  {
427  d->mConfiguredRootContainer = true;
428  clearTabs();
429 
430  for ( int i = 0; i < attributeEditorFormNodeList.size(); i++ )
431  {
432  QDomElement elem = attributeEditorFormNodeList.at( i ).toElement();
433 
434  QgsAttributeEditorElement *attributeEditorWidget = attributeEditorElementFromDomElement( elem, nullptr, node.namedItem( QStringLiteral( "id" ) ).toElement().text(), context );
435  if ( attributeEditorWidget )
436  addTab( attributeEditorWidget );
437  }
438 
439  onRelationsLoaded();
440  }
441  }
442 }
443 
444 void QgsEditFormConfig::writeXml( QDomNode &node, const QgsReadWriteContext &context ) const
445 {
446  QDomDocument doc( node.ownerDocument() );
447 
448  QDomElement efField = doc.createElement( QStringLiteral( "editform" ) );
449  efField.setAttribute( QStringLiteral( "tolerant" ), QStringLiteral( "1" ) );
450  QDomText efText = doc.createTextNode( context.pathResolver().writePath( uiForm() ) );
451  efField.appendChild( efText );
452  node.appendChild( efField );
453 
454  QDomElement efiField = doc.createElement( QStringLiteral( "editforminit" ) );
455  if ( !initFunction().isEmpty() )
456  efiField.appendChild( doc.createTextNode( initFunction() ) );
457  node.appendChild( efiField );
458 
459  QDomElement eficsField = doc.createElement( QStringLiteral( "editforminitcodesource" ) );
460  eficsField.appendChild( doc.createTextNode( QString::number( initCodeSource() ) ) );
461  node.appendChild( eficsField );
462 
463  QDomElement efifpField = doc.createElement( QStringLiteral( "editforminitfilepath" ) );
464  efifpField.appendChild( doc.createTextNode( context.pathResolver().writePath( initFilePath() ) ) );
465  node.appendChild( efifpField );
466 
467  QDomElement eficField = doc.createElement( QStringLiteral( "editforminitcode" ) );
468  eficField.appendChild( doc.createCDATASection( initCode() ) );
469  node.appendChild( eficField );
470 
471  QDomElement fFSuppElem = doc.createElement( QStringLiteral( "featformsuppress" ) );
472  QDomText fFSuppText = doc.createTextNode( QString::number( suppress() ) );
473  fFSuppElem.appendChild( fFSuppText );
474  node.appendChild( fFSuppElem );
475 
476  // tab display
477  QDomElement editorLayoutElem = doc.createElement( QStringLiteral( "editorlayout" ) );
478  switch ( layout() )
479  {
481  editorLayoutElem.appendChild( doc.createTextNode( QStringLiteral( "uifilelayout" ) ) );
482  break;
483 
485  editorLayoutElem.appendChild( doc.createTextNode( QStringLiteral( "tablayout" ) ) );
486  break;
487 
489  default:
490  editorLayoutElem.appendChild( doc.createTextNode( QStringLiteral( "generatedlayout" ) ) );
491  break;
492  }
493 
494  node.appendChild( editorLayoutElem );
495 
496  // tabs and groups of edit form
497  if ( !tabs().empty() && d->mConfiguredRootContainer )
498  {
499  QDomElement tabsElem = doc.createElement( QStringLiteral( "attributeEditorForm" ) );
500 
501  QDomElement rootElem = d->mInvisibleRootContainer->toDomElement( doc );
502  QDomNodeList elemList = rootElem.childNodes();
503 
504  while ( !elemList.isEmpty() )
505  {
506  tabsElem.appendChild( elemList.at( 0 ) );
507  }
508 
509  node.appendChild( tabsElem );
510  }
511 
512  QDomElement editableElem = doc.createElement( QStringLiteral( "editable" ) );
513  for ( auto editIt = d->mFieldEditables.constBegin(); editIt != d->mFieldEditables.constEnd(); ++editIt )
514  {
515  QDomElement fieldElem = doc.createElement( QStringLiteral( "field" ) );
516  fieldElem.setAttribute( QStringLiteral( "name" ), editIt.key() );
517  fieldElem.setAttribute( QStringLiteral( "editable" ), editIt.value() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
518  editableElem.appendChild( fieldElem );
519  }
520  node.appendChild( editableElem );
521 
522  QDomElement labelOnTopElem = doc.createElement( QStringLiteral( "labelOnTop" ) );
523  for ( auto labelOnTopIt = d->mLabelOnTop.constBegin(); labelOnTopIt != d->mLabelOnTop.constEnd(); ++labelOnTopIt )
524  {
525  QDomElement fieldElem = doc.createElement( QStringLiteral( "field" ) );
526  fieldElem.setAttribute( QStringLiteral( "name" ), labelOnTopIt.key() );
527  fieldElem.setAttribute( QStringLiteral( "labelOnTop" ), labelOnTopIt.value() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
528  labelOnTopElem.appendChild( fieldElem );
529  }
530  node.appendChild( labelOnTopElem );
531 
532  // Store data defined field properties
533  QDomElement ddFieldPropsElement = doc.createElement( QStringLiteral( "dataDefinedFieldProperties" ) );
534  for ( auto it = d->mDataDefinedFieldProperties.constBegin(); it != d->mDataDefinedFieldProperties.constEnd(); ++it )
535  {
536  QDomElement ddPropsElement = doc.createElement( QStringLiteral( "field" ) );
537  ddPropsElement.setAttribute( QStringLiteral( "name" ), it.key() );
538  it.value().writeXml( ddPropsElement, propertyDefinitions() );
539  ddFieldPropsElement.appendChild( ddPropsElement );
540  }
541  node.appendChild( ddFieldPropsElement );
542 
543  QDomElement widgetsElem = doc.createElement( QStringLiteral( "widgets" ) );
544 
545  QMap<QString, QVariantMap >::ConstIterator configIt( d->mWidgetConfigs.constBegin() );
546 
547  while ( configIt != d->mWidgetConfigs.constEnd() )
548  {
549  QDomElement widgetElem = doc.createElement( QStringLiteral( "widget" ) );
550  widgetElem.setAttribute( QStringLiteral( "name" ), configIt.key() );
551  // widgetElem.setAttribute( "notNull", );
552 
553  QDomElement configElem = QgsXmlUtils::writeVariant( configIt.value(), doc );
554  configElem.setTagName( QStringLiteral( "config" ) );
555  widgetElem.appendChild( configElem );
556  widgetsElem.appendChild( widgetElem );
557  ++configIt;
558  }
559 
560  node.appendChild( widgetsElem );
561 
563 }
564 
566 {
567  QgsAttributeEditorElement *newElement = nullptr;
568 
569  if ( elem.tagName() == QLatin1String( "attributeEditorContainer" ) )
570  {
571  QColor backgroundColor( elem.attribute( QStringLiteral( "backgroundColor" ), QString() ) );
572  QgsAttributeEditorContainer *container = new QgsAttributeEditorContainer( context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:formcontainers" ).arg( layerId ),
573  elem.attribute( QStringLiteral( "name" ) ) ), parent, backgroundColor );
574  bool ok;
575  int cc = elem.attribute( QStringLiteral( "columnCount" ) ).toInt( &ok );
576  if ( !ok )
577  cc = 0;
578  container->setColumnCount( cc );
579 
580  bool isGroupBox = elem.attribute( QStringLiteral( "groupBox" ) ).toInt( &ok );
581  if ( ok )
582  container->setIsGroupBox( isGroupBox );
583  else
584  container->setIsGroupBox( parent );
585 
586  bool visibilityExpressionEnabled = elem.attribute( QStringLiteral( "visibilityExpressionEnabled" ) ).toInt( &ok );
587  QgsOptionalExpression visibilityExpression;
588  if ( ok )
589  {
590  visibilityExpression.setEnabled( visibilityExpressionEnabled );
591  visibilityExpression.setData( QgsExpression( elem.attribute( QStringLiteral( "visibilityExpression" ) ) ) );
592  }
593  container->setVisibilityExpression( visibilityExpression );
594 
595  QDomNodeList childNodeList = elem.childNodes();
596 
597  for ( int i = 0; i < childNodeList.size(); i++ )
598  {
599  QDomElement childElem = childNodeList.at( i ).toElement();
600  QgsAttributeEditorElement *myElem = attributeEditorElementFromDomElement( childElem, container, layerId, context );
601  if ( myElem )
602  container->addChildElement( myElem );
603  }
604 
605  newElement = container;
606  }
607  else if ( elem.tagName() == QLatin1String( "attributeEditorField" ) )
608  {
609  QString name = elem.attribute( QStringLiteral( "name" ) );
610  int idx = d->mFields.lookupField( name );
611  newElement = new QgsAttributeEditorField( name, idx, parent );
612  }
613  else if ( elem.tagName() == QLatin1String( "attributeEditorRelation" ) )
614  {
615  // At this time, the relations are not loaded
616  // So we only grab the id and delegate the rest to onRelationsLoaded()
617  QgsAttributeEditorRelation *relElement = new QgsAttributeEditorRelation( elem.attribute( QStringLiteral( "relation" ), QStringLiteral( "[None]" ) ), parent );
618  relElement->setShowLinkButton( elem.attribute( QStringLiteral( "showLinkButton" ), QStringLiteral( "1" ) ).toInt() );
619  relElement->setShowUnlinkButton( elem.attribute( QStringLiteral( "showUnlinkButton" ), QStringLiteral( "1" ) ).toInt() );
620  relElement->setShowSaveChildEditsButton( elem.attribute( QStringLiteral( "showSaveChildEditsButton" ), QStringLiteral( "1" ) ).toInt() );
621  newElement = relElement;
622  }
623  else if ( elem.tagName() == QLatin1String( "attributeEditorQmlElement" ) )
624  {
625  QgsAttributeEditorQmlElement *qmlElement = new QgsAttributeEditorQmlElement( elem.attribute( QStringLiteral( "name" ) ), parent );
626  qmlElement->setQmlCode( elem.text() );
627  newElement = qmlElement;
628  }
629  else if ( elem.tagName() == QLatin1String( "attributeEditorHtmlElement" ) )
630  {
631  QgsAttributeEditorHtmlElement *htmlElement = new QgsAttributeEditorHtmlElement( elem.attribute( QStringLiteral( "name" ) ), parent );
632  htmlElement->setHtmlCode( elem.text() );
633  newElement = htmlElement;
634  }
635 
636  if ( newElement )
637  {
638  if ( elem.hasAttribute( QStringLiteral( "showLabel" ) ) )
639  newElement->setShowLabel( elem.attribute( QStringLiteral( "showLabel" ) ).toInt() );
640  else
641  newElement->setShowLabel( true );
642  }
643 
644  return newElement;
645 }
646 
648 {
649  return mColumnCount;
650 }
651 
653 {
654  mColumnCount = columnCount;
655 }
656 
658 {
660 
661  const auto childElements = children();
662 
663  for ( QgsAttributeEditorElement *child : childElements )
664  {
665  element->addChildElement( child->clone( element ) );
666  }
667  element->mIsGroupBox = mIsGroupBox;
668  element->mColumnCount = mColumnCount;
669  element->mVisibilityExpression = mVisibilityExpression;
670 
671  return element;
672 }
673 
674 void QgsAttributeEditorContainer::saveConfiguration( QDomElement &elem ) const
675 {
676  elem.setAttribute( QStringLiteral( "columnCount" ), mColumnCount );
677  elem.setAttribute( QStringLiteral( "groupBox" ), mIsGroupBox ? 1 : 0 );
678  elem.setAttribute( QStringLiteral( "visibilityExpressionEnabled" ), mVisibilityExpression.enabled() ? 1 : 0 );
679  elem.setAttribute( QStringLiteral( "visibilityExpression" ), mVisibilityExpression->expression() );
680  if ( mBackgroundColor.isValid() )
681  elem.setAttribute( QStringLiteral( "backgroundColor" ), mBackgroundColor.name( ) );
682  const auto constMChildren = mChildren;
683  for ( QgsAttributeEditorElement *child : constMChildren )
684  {
685  QDomDocument doc = elem.ownerDocument();
686  elem.appendChild( child->toDomElement( doc ) );
687  }
688 }
689 
690 QString QgsAttributeEditorContainer::typeIdentifier() const
691 {
692  return QStringLiteral( "attributeEditorContainer" );
693 }
QgsAttributeEditorContainer::setVisibilityExpression
void setVisibilityExpression(const QgsOptionalExpression &visibilityExpression)
The visibility expression is used in the attribute form to show or hide this container based on an ex...
Definition: qgsattributeeditorelement.cpp:35
QgsAttributeEditorElement
Definition: qgsattributeeditorelement.h:38
QgsProject::relationManager
QgsRelationManager relationManager
Definition: qgsproject.h:103
QgsEditFormConfig::initCodeSource
PythonInitCodeSource initCodeSource() const
Returns Python code source for edit form initialization (if it shall be loaded from a file,...
Definition: qgseditformconfig.cpp:268
QgsAttributeEditorContainer::~QgsAttributeEditorContainer
~QgsAttributeEditorContainer() override
Definition: qgseditformconfig.cpp:26
QgsOptional::enabled
bool enabled() const
Check if this optional is enabled.
Definition: qgsoptional.h:103
QgsAttributeEditorContainer::QgsAttributeEditorContainer
QgsAttributeEditorContainer(const QString &name, QgsAttributeEditorElement *parent, const QColor &backgroundColor=QColor())
Creates a new attribute editor container.
Definition: qgsattributeeditorelement.h:181
QgsEditFormConfig::~QgsEditFormConfig
~QgsEditFormConfig()
Definition: qgseditformconfig.cpp:115
QgsAttributeEditorContainer::columnCount
int columnCount() const
Gets the number of columns in this group.
Definition: qgseditformconfig.cpp:647
QgsEditFormConfig::GeneratedLayout
@ GeneratedLayout
Autogenerate a simple tabular layout for the form.
Definition: qgseditformconfig.h:47
QgsReadWriteContext
Definition: qgsreadwritecontext.h:34
QgsAttributeEditorElement::AeTypeRelation
@ AeTypeRelation
A relation.
Definition: qgsattributeeditorelement.h:65
QgsEditFormConfig::setInitFunction
void setInitFunction(const QString &function)
Set Python function for edit form initialization.
Definition: qgseditformconfig.cpp:233
QgsAttributeEditorContainer::clone
QgsAttributeEditorElement * clone(QgsAttributeEditorElement *parent) const override
Creates a deep copy of this element.
Definition: qgseditformconfig.cpp:657
QgsEditFormConfig::initFunction
QString initFunction() const
Gets Python function for edit form initialization.
Definition: qgseditformconfig.cpp:228
QgsEditFormConfig::QgsEditFormConfig
QgsEditFormConfig()
Create a new edit form config.
Definition: qgseditformconfig.cpp:31
QgsAttributeEditorField
Definition: qgsattributeeditorelement.h:300
QgsEditFormConfig::PythonInitCodeSource
PythonInitCodeSource
The Python init code source options.
Definition: qgseditformconfig.h:93
QgsEditFormConfig::labelOnTop
bool labelOnTop(int idx) const
If this returns true, the widget at the given index will receive its label on the previous line while...
Definition: qgseditformconfig.cpp:202
qgsreadwritecontext.h
QgsAttributeEditorElement::setShowLabel
void setShowLabel(bool showLabel)
Controls if this element should be labeled with a title (field, relation or groupname).
Definition: qgsattributeeditorelement.cpp:128
QgsAbstractPropertyCollection::readXml
virtual bool readXml(const QDomElement &collectionElem, const QgsPropertiesDefinition &definitions)
Reads property collection state from an XML element.
Definition: qgspropertycollection.cpp:108
QgsFields
Definition: qgsfields.h:44
QgsEditFormConfig::setLayout
void setLayout(EditorLayout editorLayout)
Sets the active layout style for the attribute editor for this layer.
Definition: qgseditformconfig.cpp:156
qgspathresolver.h
QgsAttributeEditorRelation::setShowUnlinkButton
void setShowUnlinkButton(bool showUnlinkButton)
Determines if the "unlink feature" button should be shown.
Definition: qgsattributeeditorelement.cpp:161
QgsEditFormConfig::setDataDefinedFieldProperties
void setDataDefinedFieldProperties(const QString &fieldName, const QgsPropertyCollection &properties)
Set data defined properties for fieldName to properties.
Definition: qgseditformconfig.cpp:36
QgsAttributeEditorRelation::setShowSaveChildEditsButton
void setShowSaveChildEditsButton(bool showSaveChildEditsButton)
Determines if the "save child layer edits" button should be shown.
Definition: qgsattributeeditorelement.cpp:166
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:458
QgsNetworkContentFetcherRegistry::DownloadImmediately
@ DownloadImmediately
The download will start immediately, not need to run QgsFecthedContent::download()
Definition: qgsnetworkcontentfetcherregistry.h:131
QgsApplication::instance
static QgsApplication * instance()
Returns the singleton instance of the QgsApplication.
Definition: qgsapplication.cpp:390
QgsEditFormConfig::initFilePath
QString initFilePath() const
Gets Python external file path for edit form initialization.
Definition: qgseditformconfig.cpp:250
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsAttributeEditorContainer::children
QList< QgsAttributeEditorElement * > children() const
Gets a list of the children elements of this container.
Definition: qgsattributeeditorelement.h:217
QgsReadWriteContext::enterCategory
MAYBE_UNUSED NODISCARD QgsReadWriteContextCategoryPopper enterCategory(const QString &category, const QString &details=QString())
Push a category to the stack.
Definition: qgsreadwritecontext.cpp:62
QgsEditFormConfig::addTab
void addTab(QgsAttributeEditorElement *data)
Adds a new element to the invisible root container in the layout.
Definition: qgseditformconfig.cpp:129
QgsEditFormConfig::FeatureFormSuppress
FeatureFormSuppress
Types of feature form suppression after feature creation.
Definition: qgseditformconfig.h:82
QgsAttributeEditorRelation::init
bool init(QgsRelationManager *relManager)
Initializes the relation from the id.
Definition: qgsattributeeditorelement.cpp:89
QgsEditFormConfig::invisibleRootContainer
QgsAttributeEditorContainer * invisibleRootContainer()
Gets the invisible root container for the drag and drop designer form (EditorLayout::TabLayout).
Definition: qgseditformconfig.cpp:146
QgsAttributeEditorRelation::setShowLinkButton
void setShowLinkButton(bool showLinkButton)
Determines if the "link feature" button should be shown.
Definition: qgsattributeeditorelement.cpp:151
qgsapplication.h
qgsnetworkcontentfetcherregistry.h
QgsEditFormConfig::setInitFilePath
void setInitFilePath(const QString &filePath)
Set Python external file path for edit form initialization.
Definition: qgseditformconfig.cpp:255
QgsPropertiesDefinition
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
Definition: qgspropertycollection.h:29
QgsPathResolver::writePath
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
Definition: qgspathresolver.cpp:187
QgsEditFormConfig::setInitCode
void setInitCode(const QString &code)
Set Python code for edit form initialization.
Definition: qgseditformconfig.cpp:244
QgsReadWriteContextCategoryPopper
Definition: qgsreadwritecontext.h:158
QgsReadWriteContext::projectTranslator
const QgsProjectTranslator * projectTranslator() const
Returns the project translator.
Definition: qgsreadwritecontext.h:108
QgsAttributeEditorQmlElement
Definition: qgsattributeeditorelement.h:454
QgsEditFormConfig::operator=
QgsEditFormConfig & operator=(const QgsEditFormConfig &o)
Definition: qgseditformconfig.cpp:118
QgsEditFormConfig::CodeSourceDialog
@ CodeSourceDialog
Use the Python code provided in the dialog.
Definition: qgseditformconfig.h:97
QgsNetworkContentFetcherRegistry::fetch
const QgsFetchedContent * fetch(const QString &url, FetchingMode fetchingMode=DownloadLater)
Initialize a download for the given URL.
Definition: qgsnetworkcontentfetcherregistry.cpp:33
QgsXmlUtils::readVariant
static QVariant readVariant(const QDomElement &element)
Read a QVariant from a QDomElement.
Definition: qgsxmlutils.cpp:251
QgsAttributeEditorRelation
Definition: qgsattributeeditorelement.h:333
QgsEditFormConfig::setReadOnly
void setReadOnly(int idx, bool readOnly=true)
If set to false, the widget at the given index will be read-only.
Definition: qgseditformconfig.cpp:210
QgsEditFormConfig::widgetConfig
QVariantMap widgetConfig(const QString &widgetName) const
Gets the configuration for the editor widget with the given name.
Definition: qgseditformconfig.cpp:52
QgsOptional::setData
void setData(const T &data)
Set the payload data.
Definition: qgsoptional.h:143
QgsEditFormConfig::writeXml
void writeXml(QDomNode &node, const QgsReadWriteContext &context) const
Write XML information Serialize on project save.
Definition: qgseditformconfig.cpp:444
QgsAttributeEditorQmlElement::setQmlCode
void setQmlCode(const QString &qmlCode)
Sets the QML code that will be represented within this widget to qmlCode.
Definition: qgsattributeeditorelement.cpp:189
QgsEditFormConfig::SuppressDefault
@ SuppressDefault
Use the application-wide setting.
Definition: qgseditformconfig.h:84
QgsEditFormConfig::operator==
bool operator==(const QgsEditFormConfig &o)
Definition: qgseditformconfig.cpp:124
QgsEditFormConfig::setUiForm
void setUiForm(const QString &ui)
Set path to the .ui form.
Definition: qgseditformconfig.cpp:170
QgsAttributeEditorHtmlElement::setHtmlCode
void setHtmlCode(const QString &htmlCode)
Sets the HTML code that will be represented within this widget to htmlCode.
Definition: qgsattributeeditorelement.cpp:218
QgsEditFormConfig::TabLayout
@ TabLayout
Use a layout with tabs and group boxes. Needs to be configured.
Definition: qgseditformconfig.h:48
QgsAttributeEditorContainer::setColumnCount
void setColumnCount(int columnCount)
Set the number of columns in this group.
Definition: qgseditformconfig.cpp:652
QgsOptionalExpression
Definition: qgsoptionalexpression.h:39
qgsrelationmanager.h
QgsEditFormConfig::setLabelOnTop
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...
Definition: qgseditformconfig.cpp:219
QgsEditFormConfig::readOnly
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 ...
Definition: qgseditformconfig.cpp:189
QgsEditFormConfig
Definition: qgseditformconfig.h:37
QgsAttributeEditorContainer::setIsGroupBox
virtual void setIsGroupBox(bool isGroupBox)
Determines if this container is rendered as collapsible group box or tab in a tabwidget.
Definition: qgsattributeeditorelement.h:203
qgsxmlutils.h
QgsEditFormConfig::setWidgetConfig
bool setWidgetConfig(const QString &widgetName, const QVariantMap &config)
Set the editor widget config for a widget which is not for a simple field.
Definition: qgseditformconfig.cpp:91
qgseditformconfig.h
QgsPropertyCollection
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
Definition: qgspropertycollection.h:318
QgsPathResolver::readPath
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
Definition: qgspathresolver.cpp:35
QgsFields::OriginExpression
@ OriginExpression
Field is calculated from an expression.
Definition: qgsfields.h:54
QgsEditFormConfig::removeWidgetConfig
bool removeWidgetConfig(const QString &widgetName)
Remove the configuration for the editor widget with the given name.
Definition: qgseditformconfig.cpp:104
QgsOptional::setEnabled
void setEnabled(bool enabled)
Set if this optional is enabled.
Definition: qgsoptional.h:113
QgsEditFormConfig::clearTabs
void clearTabs()
Clears all the tabs for the attribute editor form with EditorLayout::TabLayout.
Definition: qgseditformconfig.cpp:140
QgsAttributeEditorContainer
Definition: qgsattributeeditorelement.h:170
QgsEditFormConfig::layout
EditorLayout layout() const
Gets the active layout style for the attribute editor for this layer.
Definition: qgseditformconfig.cpp:151
QgsEditFormConfig::dataDefinedFieldProperties
QgsPropertyCollection dataDefinedFieldProperties(const QString &fieldName) const
Returns data defined properties for fieldName.
Definition: qgseditformconfig.cpp:42
QgsEditFormConfig::uiForm
QString uiForm() const
Returns the path or URL to the .ui form.
Definition: qgseditformconfig.cpp:165
QgsAttributeEditorElement::name
QString name() const
Returns the name of this element.
Definition: qgsattributeeditorelement.h:92
qgseditformconfig_p.h
qgslogger.h
QgsEditFormConfig::propertyDefinitions
static const QgsPropertiesDefinition & propertyDefinitions()
Returns data defined property definitions.
Definition: qgseditformconfig.cpp:47
QgsEditFormConfig::setSuppress
void setSuppress(FeatureFormSuppress s)
Sets type of feature form pop-up suppression after feature creation (overrides app setting)
Definition: qgseditformconfig.cpp:284
QgsExpression
Definition: qgsexpression.h:113
QgsEditFormConfig::tabs
QList< QgsAttributeEditorElement * > tabs() const
Returns a list of tabs for EditorLayout::TabLayout obtained from the invisible root container.
Definition: qgseditformconfig.cpp:135
QgsEditFormConfig::attributeEditorElementFromDomElement
QgsAttributeEditorElement * attributeEditorElementFromDomElement(QDomElement &elem, QgsAttributeEditorElement *parent, const QString &layerId=QString(), const QgsReadWriteContext &context=QgsReadWriteContext())
Deserialize drag and drop designer elements.
Definition: qgseditformconfig.cpp:565
QgsXmlUtils::writeVariant
static QDomElement writeVariant(const QVariant &value, QDomDocument &doc)
Write a QVariant to a QDomElement.
Definition: qgsxmlutils.cpp:106
QgsEditFormConfig::EditorLayout
EditorLayout
The different types to layout the attribute editor.
Definition: qgseditformconfig.h:45
QgsEditFormConfig::initCode
QString initCode() const
Gets Python code for edit form initialization.
Definition: qgseditformconfig.cpp:239
QgsEditFormConfig::readXml
void readXml(const QDomNode &node, QgsReadWriteContext &context)
Read XML information Deserialize on project load.
Definition: qgseditformconfig.cpp:290
QgsApplication::networkContentFetcherRegistry
static QgsNetworkContentFetcherRegistry * networkContentFetcherRegistry()
Returns the application's network content registry used for fetching temporary files during QGIS sess...
Definition: qgsapplication.cpp:2139
qgsproject.h
QgsEditFormConfig::suppress
FeatureFormSuppress suppress() const
Type of feature form pop-up suppression after feature creation (overrides app setting)
Definition: qgseditformconfig.cpp:279
QgsFields::OriginJoin
@ OriginJoin
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
Definition: qgsfields.h:52
QgsEditFormConfig::setInitCodeSource
void setInitCodeSource(PythonInitCodeSource initCodeSource)
Sets if Python code shall be used for edit form initialization and its origin.
Definition: qgseditformconfig.cpp:273
QgsAttributeEditorContainer::addChildElement
virtual void addChildElement(QgsAttributeEditorElement *element)
Add a child element to this container.
Definition: qgsattributeeditorelement.cpp:20
QgsProjectTranslator::translate
virtual QString translate(const QString &context, const QString &sourceText, const char *disambiguation=nullptr, int n=-1) const =0
The derived translate() translates with QTranslator and qm file the sourceText.
QgsReadWriteContext::pathResolver
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
Definition: qgsreadwritecontext.cpp:47
QgsAttributeEditorHtmlElement
Definition: qgsattributeeditorelement.h:495
QgsAttributeEditorElement::parent
QgsAttributeEditorElement * parent() const
Gets the parent of this element.
Definition: qgsattributeeditorelement.h:106
QgsEditFormConfig::UiFileLayout
@ UiFileLayout
Load a .ui file for the layout. Needs to be configured.
Definition: qgseditformconfig.h:49