QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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 
16 #include "qgseditformconfig_p.h"
17 #include "qgseditformconfig.h"
19 #include "qgspathresolver.h"
20 #include "qgsproject.h"
21 #include "qgsreadwritecontext.h"
22 #include "qgsrelationmanager.h"
23 #include "qgslogger.h"
24 #include "qgsxmlutils.h"
25 #include "qgsapplication.h"
26 #include "qgsmessagelog.h"
30 #include <QUrl>
31 
33  : d( new QgsEditFormConfigPrivate() )
34 {
35 }
36 
37 void QgsEditFormConfig::setDataDefinedFieldProperties( const QString &fieldName, const QgsPropertyCollection &properties )
38 {
39  d.detach();
40  d->mDataDefinedFieldProperties[ fieldName ] = properties;
41 }
42 
44 {
45  return d->mDataDefinedFieldProperties.value( fieldName );
46 }
47 
49 {
50  return QgsEditFormConfigPrivate::propertyDefinitions();
51 }
52 
53 QVariantMap QgsEditFormConfig::widgetConfig( const QString &widgetName ) const
54 {
55  const int fieldIndex = d->mFields.indexOf( widgetName );
56  if ( fieldIndex != -1 )
57  return d->mFields.at( fieldIndex ).editorWidgetSetup().config();
58  else
59  return d->mWidgetConfigs.value( widgetName );
60 }
61 
62 void QgsEditFormConfig::setFields( const QgsFields &fields )
63 {
64  d.detach();
65  d->mFields = fields;
66 
67  if ( !d->mConfiguredRootContainer )
68  {
69  d->mInvisibleRootContainer->clear();
70  for ( int i = 0; i < d->mFields.size(); ++i )
71  {
72  QgsAttributeEditorField *field = new QgsAttributeEditorField( d->mFields.at( i ).name(), i, d->mInvisibleRootContainer );
73  d->mInvisibleRootContainer->addChildElement( field );
74  }
75  }
76 }
77 
78 void QgsEditFormConfig::onRelationsLoaded()
79 {
80  const QList<QgsAttributeEditorElement *> relations = d->mInvisibleRootContainer->findElements( QgsAttributeEditorElement::AeTypeRelation );
81 
82  for ( QgsAttributeEditorElement *relElem : relations )
83  {
84  QgsAttributeEditorRelation *rel = dynamic_cast< QgsAttributeEditorRelation * >( relElem );
85  if ( !rel )
86  continue;
87 
89  }
90 }
91 
92 bool QgsEditFormConfig::legacyUpdateRelationWidgetInTabs( QgsAttributeEditorContainer *container, const QString &widgetName, const QVariantMap &config )
93 {
94  const QList<QgsAttributeEditorElement *> children = container->children();
95  for ( QgsAttributeEditorElement *child : children )
96  {
97  if ( child->type() == QgsAttributeEditorElement::AeTypeContainer )
98  {
99  QgsAttributeEditorContainer *container = dynamic_cast<QgsAttributeEditorContainer *>( child );
100  if ( legacyUpdateRelationWidgetInTabs( container, widgetName, config ) )
101  {
102  //return when a relation has been set in a child or child child...
103  return true;
104  }
105  }
106  else if ( child->type() == QgsAttributeEditorElement::AeTypeRelation )
107  {
108  QgsAttributeEditorRelation *relation = dynamic_cast< QgsAttributeEditorRelation * >( child );
109  if ( relation )
110  {
111  if ( relation->relation().id() == widgetName )
112  {
113  if ( config.contains( QStringLiteral( "nm-rel" ) ) )
114  {
115  relation->setNmRelationId( config[QStringLiteral( "nm-rel" )] );
116  }
117  if ( config.contains( QStringLiteral( "force-suppress-popup" ) ) )
118  {
119  relation->setForceSuppressFormPopup( config[QStringLiteral( "force-suppress-popup" )].toBool() );
120  }
121  return true;
122  }
123  }
124  }
125  }
126  return false;
127 }
128 
129 bool QgsEditFormConfig::setWidgetConfig( const QString &widgetName, const QVariantMap &config )
130 {
131  if ( d->mFields.indexOf( widgetName ) != -1 )
132  {
133  QgsDebugMsg( QStringLiteral( "Trying to set a widget config for a field on QgsEditFormConfig. Use layer->setEditorWidgetSetup() instead." ) );
134  return false;
135  }
136 
137  //for legacy use it writes the relation editor configuration into the first instance of the widget
138  if ( config.contains( QStringLiteral( "force-suppress-popup" ) ) || config.contains( QStringLiteral( "nm-rel" ) ) )
139  {
140  QgsMessageLog::logMessage( QStringLiteral( "Deprecation Warning: Trying to set a relation config directly on the relation %1. Relation settings should be done for the specific widget instance instead. Use attributeEditorRelation->setNmRelationId() or attributeEditorRelation->setForceSuppressFormPopup() instead." ).arg( widgetName ) );
141  legacyUpdateRelationWidgetInTabs( d->mInvisibleRootContainer, widgetName, config );
142  }
143 
144  d.detach();
145  d->mWidgetConfigs[widgetName] = config;
146  return true;
147 }
148 
149 bool QgsEditFormConfig::removeWidgetConfig( const QString &widgetName )
150 {
151  d.detach();
152  return d->mWidgetConfigs.remove( widgetName ) != 0;
153 }
154 
156  : d( o.d )
157 {
158 }
159 
161 {}
162 
164 {
165  d = o.d;
166  return *this;
167 }
168 
170 {
171  return d == o.d;
172 }
173 
175 {
176  d.detach();
177  d->mInvisibleRootContainer->addChildElement( data );
178 }
179 
180 QList<QgsAttributeEditorElement *> QgsEditFormConfig::tabs() const
181 {
182  return d->mInvisibleRootContainer->children();
183 }
184 
186 {
187  d.detach();
188  d->mInvisibleRootContainer->clear();
189 }
190 
192 {
193  return d->mInvisibleRootContainer;
194 }
195 
197 {
198  return d->mEditorLayout;
199 }
200 
202 {
203  d.detach();
204  d->mEditorLayout = editorLayout;
205 
206  if ( editorLayout == TabLayout )
207  d->mConfiguredRootContainer = true;
208 }
209 
211 {
212  return d->mUiFormPath;
213 }
214 
215 void QgsEditFormConfig::setUiForm( const QString &ui )
216 {
217  if ( !ui.isEmpty() && !QUrl::fromUserInput( ui ).isLocalFile() )
218  {
219  // any existing download will not be restarted!
220  QgsApplication::networkContentFetcherRegistry()->fetch( ui, Qgis::ActionStart::Immediate );
221  }
222 
223  if ( ui.isEmpty() )
224  {
226  }
227  else
228  {
230  }
231  d->mUiFormPath = ui;
232 }
233 
234 bool QgsEditFormConfig::readOnly( int idx ) const
235 {
236  if ( idx >= 0 && idx < d->mFields.count() )
237  {
238  if ( d->mFields.fieldOrigin( idx ) == QgsFields::OriginJoin
239  || d->mFields.fieldOrigin( idx ) == QgsFields::OriginExpression )
240  return true;
241  return !d->mFieldEditables.value( d->mFields.at( idx ).name(), true );
242  }
243  else
244  return false;
245 }
246 
247 bool QgsEditFormConfig::labelOnTop( int idx ) const
248 {
249  if ( idx >= 0 && idx < d->mFields.count() )
250  return d->mLabelOnTop.value( d->mFields.at( idx ).name(), false );
251  else
252  return false;
253 }
254 
255 void QgsEditFormConfig::setReadOnly( int idx, bool readOnly )
256 {
257  if ( idx >= 0 && idx < d->mFields.count() )
258  {
259  d.detach();
260  d->mFieldEditables[ d->mFields.at( idx ).name()] = !readOnly;
261  }
262 }
263 
264 void QgsEditFormConfig::setLabelOnTop( int idx, bool onTop )
265 {
266  if ( idx >= 0 && idx < d->mFields.count() )
267  {
268  d.detach();
269  d->mLabelOnTop[ d->mFields.at( idx ).name()] = onTop;
270  }
271 }
272 
273 bool QgsEditFormConfig::reuseLastValue( int index ) const
274 {
275  if ( index >= 0 && index < d->mFields.count() )
276  return d->mReuseLastValue.value( d->mFields.at( index ).name(), false );
277  else
278  return false;
279 }
280 
281 void QgsEditFormConfig::setReuseLastValue( int index, bool reuse )
282 {
283  if ( index >= 0 && index < d->mFields.count() )
284  {
285  d.detach();
286  d->mReuseLastValue[ d->mFields.at( index ).name()] = reuse;
287  }
288 }
289 
291 {
292  return d->mInitFunction;
293 }
294 
295 void QgsEditFormConfig::setInitFunction( const QString &function )
296 {
297  d.detach();
298  d->mInitFunction = function;
299 }
300 
302 {
303  return d->mInitCode;
304 }
305 
306 void QgsEditFormConfig::setInitCode( const QString &code )
307 {
308  d.detach();
309  d->mInitCode = code;
310 }
311 
313 {
314  return d->mInitFilePath;
315 }
316 
317 void QgsEditFormConfig::setInitFilePath( const QString &filePath )
318 {
319  d.detach();
320  d->mInitFilePath = filePath;
321 
322  // if this is an URL, download file as there is a good chance it will be used later
323  if ( !filePath.isEmpty() && !QUrl::fromUserInput( filePath ).isLocalFile() )
324  {
325  // any existing download will not be restarted!
326  QgsApplication::networkContentFetcherRegistry()->fetch( filePath, Qgis::ActionStart::Immediate );
327  }
328 }
329 
331 {
332  return d->mInitCodeSource;
333 }
334 
336 {
337  d.detach();
338  d->mInitCodeSource = initCodeSource;
339 }
340 
342 {
343  return d->mSuppressForm;
344 }
345 
347 {
348  d.detach();
349  d->mSuppressForm = s;
350 }
351 
352 void QgsEditFormConfig::readXml( const QDomNode &node, QgsReadWriteContext &context )
353 {
354  const QgsReadWriteContextCategoryPopper p = context.enterCategory( QObject::tr( "Edit form config" ) );
355 
356  d.detach();
357 
358  const QDomNode editFormNode = node.namedItem( QStringLiteral( "editform" ) );
359  if ( !editFormNode.isNull() )
360  {
361  const QDomElement e = editFormNode.toElement();
362  const bool tolerantRemoteUrls = e.hasAttribute( QStringLiteral( "tolerant" ) );
363  if ( !e.text().isEmpty() )
364  {
365  const QString uiFormPath = context.pathResolver().readPath( e.text() );
366  // <= 3.2 had a bug where invalid ui paths would get written into projects on load
367  // to avoid restoring these invalid paths, we take a less-tolerant approach for older (untrustworthy) projects
368  // and only set ui forms paths IF they are local files OR start with "http(s)".
369  const bool localFile = QFileInfo::exists( uiFormPath );
370  if ( localFile || tolerantRemoteUrls || uiFormPath.startsWith( QLatin1String( "http" ) ) )
371  setUiForm( uiFormPath );
372  }
373  }
374 
375  const QDomNode editFormInitNode = node.namedItem( QStringLiteral( "editforminit" ) );
376  if ( !editFormInitNode.isNull() )
377  {
378  d->mInitFunction = editFormInitNode.toElement().text();
379  }
380 
381  const QDomNode editFormInitCodeSourceNode = node.namedItem( QStringLiteral( "editforminitcodesource" ) );
382  if ( !editFormInitCodeSourceNode.isNull() && !editFormInitCodeSourceNode.toElement().text().isEmpty() )
383  {
384  setInitCodeSource( static_cast< QgsEditFormConfig::PythonInitCodeSource >( editFormInitCodeSourceNode.toElement().text().toInt() ) );
385  }
386 
387  const QDomNode editFormInitCodeNode = node.namedItem( QStringLiteral( "editforminitcode" ) );
388  if ( !editFormInitCodeNode.isNull() )
389  {
390  setInitCode( editFormInitCodeNode.toElement().text() );
391  }
392 
393  // Temporary < 2.12 b/w compatibility "dot" support patch
394  // \see: https://github.com/qgis/QGIS/pull/2498
395  // For b/w compatibility, check if there's a dot in the function name
396  // and if yes, transform it in an import statement for the module
397  // and set the PythonInitCodeSource to CodeSourceDialog
398  const int dotPos = d->mInitFunction.lastIndexOf( '.' );
399  if ( dotPos >= 0 ) // It's a module
400  {
402  setInitCode( QStringLiteral( "from %1 import %2\n" ).arg( d->mInitFunction.left( dotPos ), d->mInitFunction.mid( dotPos + 1 ) ) );
403  setInitFunction( d->mInitFunction.mid( dotPos + 1 ) );
404  }
405 
406  const QDomNode editFormInitFilePathNode = node.namedItem( QStringLiteral( "editforminitfilepath" ) );
407  if ( !editFormInitFilePathNode.isNull() && !editFormInitFilePathNode.toElement().text().isEmpty() )
408  {
409  setInitFilePath( context.pathResolver().readPath( editFormInitFilePathNode.toElement().text() ) );
410  }
411 
412  const QDomNode fFSuppNode = node.namedItem( QStringLiteral( "featformsuppress" ) );
413  if ( fFSuppNode.isNull() )
414  {
415  d->mSuppressForm = QgsEditFormConfig::SuppressDefault;
416  }
417  else
418  {
419  const QDomElement e = fFSuppNode.toElement();
420  d->mSuppressForm = static_cast< QgsEditFormConfig::FeatureFormSuppress >( e.text().toInt() );
421  }
422 
423  // tab display
424  const QDomNode editorLayoutNode = node.namedItem( QStringLiteral( "editorlayout" ) );
425  if ( editorLayoutNode.isNull() )
426  {
427  d->mEditorLayout = QgsEditFormConfig::GeneratedLayout;
428  }
429  else
430  {
431  if ( editorLayoutNode.toElement().text() == QLatin1String( "uifilelayout" ) )
432  {
433  d->mEditorLayout = QgsEditFormConfig::UiFileLayout;
434  }
435  else if ( editorLayoutNode.toElement().text() == QLatin1String( "tablayout" ) )
436  {
437  d->mEditorLayout = QgsEditFormConfig::TabLayout;
438  }
439  else
440  {
441  d->mEditorLayout = QgsEditFormConfig::GeneratedLayout;
442  }
443  }
444 
445  d->mFieldEditables.clear();
446  const QDomNodeList editableNodeList = node.namedItem( QStringLiteral( "editable" ) ).toElement().childNodes();
447  for ( int i = 0; i < editableNodeList.size(); ++i )
448  {
449  const QDomElement editableElement = editableNodeList.at( i ).toElement();
450  d->mFieldEditables.insert( editableElement.attribute( QStringLiteral( "name" ) ), static_cast< bool >( editableElement.attribute( QStringLiteral( "editable" ) ).toInt() ) );
451  }
452 
453  d->mLabelOnTop.clear();
454  const QDomNodeList labelOnTopNodeList = node.namedItem( QStringLiteral( "labelOnTop" ) ).toElement().childNodes();
455  for ( int i = 0; i < labelOnTopNodeList.size(); ++i )
456  {
457  const QDomElement labelOnTopElement = labelOnTopNodeList.at( i ).toElement();
458  d->mLabelOnTop.insert( labelOnTopElement.attribute( QStringLiteral( "name" ) ), static_cast< bool >( labelOnTopElement.attribute( QStringLiteral( "labelOnTop" ) ).toInt() ) );
459  }
460 
461  d->mReuseLastValue.clear();
462  const QDomNodeList reuseLastValueNodeList = node.namedItem( QStringLiteral( "reuseLastValue" ) ).toElement().childNodes();
463  for ( int i = 0; i < reuseLastValueNodeList.size(); ++i )
464  {
465  const QDomElement reuseLastValueElement = reuseLastValueNodeList.at( i ).toElement();
466  d->mReuseLastValue.insert( reuseLastValueElement.attribute( QStringLiteral( "name" ) ), static_cast< bool >( reuseLastValueElement.attribute( QStringLiteral( "reuseLastValue" ) ).toInt() ) );
467  }
468 
469  // Read data defined field properties
470  const QDomNodeList fieldDDPropertiesNodeList = node.namedItem( QStringLiteral( "dataDefinedFieldProperties" ) ).toElement().childNodes();
471  for ( int i = 0; i < fieldDDPropertiesNodeList.size(); ++i )
472  {
473  const QDomElement DDElement = fieldDDPropertiesNodeList.at( i ).toElement();
474  QgsPropertyCollection collection;
475  collection.readXml( DDElement, propertyDefinitions() );
476  d->mDataDefinedFieldProperties.insert( DDElement.attribute( QStringLiteral( "name" ) ), collection );
477  }
478 
479  const QDomNodeList widgetsNodeList = node.namedItem( QStringLiteral( "widgets" ) ).toElement().childNodes();
480 
481  for ( int i = 0; i < widgetsNodeList.size(); ++i )
482  {
483  const QDomElement widgetElement = widgetsNodeList.at( i ).toElement();
484  const QVariant config = QgsXmlUtils::readVariant( widgetElement.firstChildElement( QStringLiteral( "config" ) ) );
485 
486  d->mWidgetConfigs[widgetElement.attribute( QStringLiteral( "name" ) )] = config.toMap();
487  }
488 
489  // tabs and groups display info
490  const QDomNode attributeEditorFormNode = node.namedItem( QStringLiteral( "attributeEditorForm" ) );
491  if ( !attributeEditorFormNode.isNull() )
492  {
493  const QDomNodeList attributeEditorFormNodeList = attributeEditorFormNode.toElement().childNodes();
494 
495  if ( attributeEditorFormNodeList.size() )
496  {
497  d->mConfiguredRootContainer = true;
498  clearTabs();
499 
500  for ( int i = 0; i < attributeEditorFormNodeList.size(); i++ )
501  {
502  QDomElement elem = attributeEditorFormNodeList.at( i ).toElement();
503 
504  fixLegacyConfig( elem );
505 
506  const QString layerId = node.namedItem( QStringLiteral( "id" ) ).toElement().text();
507  QgsAttributeEditorElement *attributeEditorWidget = QgsAttributeEditorElement::create( elem, layerId, d->mFields, context, nullptr );
508  if ( attributeEditorWidget )
509  addTab( attributeEditorWidget );
510  }
511 
512  onRelationsLoaded();
513  }
514  }
515 }
516 
517 void QgsEditFormConfig::fixLegacyConfig( QDomElement &el )
518 {
519  // recursive method to move widget config into attribute element config
520 
521  if ( el.tagName() == QLatin1String( "attributeEditorRelation" ) )
522  {
523  if ( !el.hasAttribute( QStringLiteral( "forceSuppressFormPopup" ) ) )
524  {
525  // pre QGIS 3.16 compatibility - the widgets section is read before
526  const bool forceSuppress = widgetConfig( el.attribute( QStringLiteral( "relation" ) ) ).value( QStringLiteral( "force-suppress-popup" ), false ).toBool();
527  el.setAttribute( QStringLiteral( "forceSuppressFormPopup" ), forceSuppress ? 1 : 0 );
528  }
529  if ( !el.hasAttribute( QStringLiteral( "nmRelationId" ) ) )
530  {
531  // pre QGIS 3.16 compatibility - the widgets section is read before
532  el.setAttribute( QStringLiteral( "nmRelationId" ), widgetConfig( el.attribute( QStringLiteral( "relation" ) ) ).value( QStringLiteral( "nm-rel" ) ).toString() );
533  }
534  }
535 
536  const QDomNodeList children = el.childNodes();
537  for ( int i = 0; i < children.size(); i++ )
538  {
539  QDomElement child = children.at( i ).toElement();
540  fixLegacyConfig( child );
541  el.replaceChild( child, children.at( i ) );
542  }
543 }
544 
545 void QgsEditFormConfig::writeXml( QDomNode &node, const QgsReadWriteContext &context ) const
546 {
547  QDomDocument doc( node.ownerDocument() );
548 
549  QDomElement efField = doc.createElement( QStringLiteral( "editform" ) );
550  efField.setAttribute( QStringLiteral( "tolerant" ), QStringLiteral( "1" ) );
551  const QDomText efText = doc.createTextNode( context.pathResolver().writePath( uiForm() ) );
552  efField.appendChild( efText );
553  node.appendChild( efField );
554 
555  QDomElement efiField = doc.createElement( QStringLiteral( "editforminit" ) );
556  if ( !initFunction().isEmpty() )
557  efiField.appendChild( doc.createTextNode( initFunction() ) );
558  node.appendChild( efiField );
559 
560  QDomElement eficsField = doc.createElement( QStringLiteral( "editforminitcodesource" ) );
561  eficsField.appendChild( doc.createTextNode( QString::number( initCodeSource() ) ) );
562  node.appendChild( eficsField );
563 
564  QDomElement efifpField = doc.createElement( QStringLiteral( "editforminitfilepath" ) );
565  efifpField.appendChild( doc.createTextNode( context.pathResolver().writePath( initFilePath() ) ) );
566  node.appendChild( efifpField );
567 
568  QDomElement eficField = doc.createElement( QStringLiteral( "editforminitcode" ) );
569  eficField.appendChild( doc.createCDATASection( initCode() ) );
570  node.appendChild( eficField );
571 
572  QDomElement fFSuppElem = doc.createElement( QStringLiteral( "featformsuppress" ) );
573  const QDomText fFSuppText = doc.createTextNode( QString::number( suppress() ) );
574  fFSuppElem.appendChild( fFSuppText );
575  node.appendChild( fFSuppElem );
576 
577  // tab display
578  QDomElement editorLayoutElem = doc.createElement( QStringLiteral( "editorlayout" ) );
579  switch ( layout() )
580  {
582  editorLayoutElem.appendChild( doc.createTextNode( QStringLiteral( "uifilelayout" ) ) );
583  break;
584 
586  editorLayoutElem.appendChild( doc.createTextNode( QStringLiteral( "tablayout" ) ) );
587  break;
588 
590  default:
591  editorLayoutElem.appendChild( doc.createTextNode( QStringLiteral( "generatedlayout" ) ) );
592  break;
593  }
594 
595  node.appendChild( editorLayoutElem );
596 
597  // tabs and groups of edit form
598  if ( !tabs().empty() && d->mConfiguredRootContainer )
599  {
600  QDomElement tabsElem = doc.createElement( QStringLiteral( "attributeEditorForm" ) );
601  const QDomElement rootElem = d->mInvisibleRootContainer->toDomElement( doc );
602  const QDomNodeList elemList = rootElem.childNodes();
603  while ( !elemList.isEmpty() )
604  {
605  tabsElem.appendChild( elemList.at( 0 ) );
606  }
607  node.appendChild( tabsElem );
608  }
609 
610  QDomElement editableElem = doc.createElement( QStringLiteral( "editable" ) );
611  for ( auto editIt = d->mFieldEditables.constBegin(); editIt != d->mFieldEditables.constEnd(); ++editIt )
612  {
613  QDomElement fieldElem = doc.createElement( QStringLiteral( "field" ) );
614  fieldElem.setAttribute( QStringLiteral( "name" ), editIt.key() );
615  fieldElem.setAttribute( QStringLiteral( "editable" ), editIt.value() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
616  editableElem.appendChild( fieldElem );
617  }
618  node.appendChild( editableElem );
619 
620  QDomElement labelOnTopElem = doc.createElement( QStringLiteral( "labelOnTop" ) );
621  for ( auto labelOnTopIt = d->mLabelOnTop.constBegin(); labelOnTopIt != d->mLabelOnTop.constEnd(); ++labelOnTopIt )
622  {
623  QDomElement fieldElem = doc.createElement( QStringLiteral( "field" ) );
624  fieldElem.setAttribute( QStringLiteral( "name" ), labelOnTopIt.key() );
625  fieldElem.setAttribute( QStringLiteral( "labelOnTop" ), labelOnTopIt.value() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
626  labelOnTopElem.appendChild( fieldElem );
627  }
628  node.appendChild( labelOnTopElem );
629 
630  QDomElement reuseLastValueElem = doc.createElement( QStringLiteral( "reuseLastValue" ) );
631  for ( auto reuseLastValueIt = d->mReuseLastValue.constBegin(); reuseLastValueIt != d->mReuseLastValue.constEnd(); ++reuseLastValueIt )
632  {
633  QDomElement fieldElem = doc.createElement( QStringLiteral( "field" ) );
634  fieldElem.setAttribute( QStringLiteral( "name" ), reuseLastValueIt.key() );
635  fieldElem.setAttribute( QStringLiteral( "reuseLastValue" ), reuseLastValueIt.value() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
636  reuseLastValueElem.appendChild( fieldElem );
637  }
638  node.appendChild( reuseLastValueElem );
639 
640  // Store data defined field properties
641  QDomElement ddFieldPropsElement = doc.createElement( QStringLiteral( "dataDefinedFieldProperties" ) );
642  for ( auto it = d->mDataDefinedFieldProperties.constBegin(); it != d->mDataDefinedFieldProperties.constEnd(); ++it )
643  {
644  QDomElement ddPropsElement = doc.createElement( QStringLiteral( "field" ) );
645  ddPropsElement.setAttribute( QStringLiteral( "name" ), it.key() );
646  it.value().writeXml( ddPropsElement, propertyDefinitions() );
647  ddFieldPropsElement.appendChild( ddPropsElement );
648  }
649  node.appendChild( ddFieldPropsElement );
650 
651  QDomElement widgetsElem = doc.createElement( QStringLiteral( "widgets" ) );
652 
653  QMap<QString, QVariantMap >::ConstIterator configIt( d->mWidgetConfigs.constBegin() );
654 
655  while ( configIt != d->mWidgetConfigs.constEnd() )
656  {
657  QDomElement widgetElem = doc.createElement( QStringLiteral( "widget" ) );
658  widgetElem.setAttribute( QStringLiteral( "name" ), configIt.key() );
659  // widgetElem.setAttribute( "notNull", );
660 
661  QDomElement configElem = QgsXmlUtils::writeVariant( configIt.value(), doc );
662  configElem.setTagName( QStringLiteral( "config" ) );
663  widgetElem.appendChild( configElem );
664  widgetsElem.appendChild( widgetElem );
665  ++configIt;
666  }
667 
668  node.appendChild( widgetsElem );
669 }
670 
672 {
673  return QgsAttributeEditorElement::create( elem, layerId, d->mFields, context, parent );
674 }
QgsAttributeEditorElement
This is an abstract base class for any elements of a drag and drop form.
Definition: qgsattributeeditorelement.h:37
QgsProject::relationManager
QgsRelationManager relationManager
Definition: qgsproject.h:114
QgsEditFormConfig::initCodeSource
PythonInitCodeSource initCodeSource() const
Returns Python code source for edit form initialization (if it shall be loaded from a file,...
Definition: qgseditformconfig.cpp:330
QgsEditFormConfig::~QgsEditFormConfig
~QgsEditFormConfig()
Definition: qgseditformconfig.cpp:160
QgsNetworkContentFetcherRegistry::fetch
QgsFetchedContent * fetch(const QString &url, Qgis::ActionStart fetchingMode=Qgis::ActionStart::Deferred, const QString &authConfig=QString())
Initialize a download for the given URL.
Definition: qgsnetworkcontentfetcherregistry.cpp:36
QgsEditFormConfig::GeneratedLayout
@ GeneratedLayout
Autogenerate a simple tabular layout for the form.
Definition: qgseditformconfig.h:49
QgsAttributeEditorElement::create
static QgsAttributeEditorElement * create(const QDomElement &element, const QString &layerId, const QgsFields &fields, const QgsReadWriteContext &context, QgsAttributeEditorElement *parent=nullptr)
Constructs the editor element from the given element.
Definition: qgsattributeeditorelement.cpp:58
QgsReadWriteContext
The class is used as a container of context for various read/write operations on other objects.
Definition: qgsreadwritecontext.h:34
qgsattributeeditorcontainer.h
QgsAttributeEditorElement::AeTypeRelation
@ AeTypeRelation
A relation.
Definition: qgsattributeeditorelement.h:121
QgsEditFormConfig::setInitFunction
void setInitFunction(const QString &function)
Set Python function for edit form initialization.
Definition: qgseditformconfig.cpp:295
QgsEditFormConfig::initFunction
QString initFunction() const
Gets Python function for edit form initialization.
Definition: qgseditformconfig.cpp:290
QgsEditFormConfig::QgsEditFormConfig
QgsEditFormConfig()
Create a new edit form config.
Definition: qgseditformconfig.cpp:32
QgsAttributeEditorField
This element will load a field's widget onto the form.
Definition: qgsattributeeditorfield.h:27
QgsEditFormConfig::PythonInitCodeSource
PythonInitCodeSource
The Python init code source options.
Definition: qgseditformconfig.h:95
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:247
qgsreadwritecontext.h
qgsattributeeditorrelation.h
QgsAbstractPropertyCollection::readXml
virtual bool readXml(const QDomElement &collectionElem, const QgsPropertiesDefinition &definitions)
Reads property collection state from an XML element.
Definition: qgspropertycollection.cpp:108
QgsFields
Container of fields for a vector layer.
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:201
qgspathresolver.h
QgsEditFormConfig::setDataDefinedFieldProperties
void setDataDefinedFieldProperties(const QString &fieldName, const QgsPropertyCollection &properties)
Set data defined properties for fieldName to properties.
Definition: qgseditformconfig.cpp:37
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:480
QgsEditFormConfig::reuseLastValue
bool reuseLastValue(int index) const
If this returns true, the widget at the given index will remember the previously entered value from t...
Definition: qgseditformconfig.cpp:273
QgsEditFormConfig::initFilePath
QString initFilePath() const
Gets Python external file path for edit form initialization.
Definition: qgseditformconfig.cpp:312
field
const QgsField & field
Definition: qgsfield.h:463
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: qgsattributeeditorcontainer.h:107
QgsEditFormConfig::addTab
void addTab(QgsAttributeEditorElement *data)
Adds a new element to the invisible root container in the layout.
Definition: qgseditformconfig.cpp:174
QgsEditFormConfig::FeatureFormSuppress
FeatureFormSuppress
Types of feature form suppression after feature creation.
Definition: qgseditformconfig.h:84
QgsAttributeEditorRelation::init
bool init(QgsRelationManager *relManager)
Initializes the relation from the id.
Definition: qgsattributeeditorrelation.cpp:20
QgsEditFormConfig::invisibleRootContainer
QgsAttributeEditorContainer * invisibleRootContainer()
Gets the invisible root container for the drag and drop designer form (EditorLayout::TabLayout).
Definition: qgseditformconfig.cpp:191
QgsRelation::id
QString id
Definition: qgsrelation.h:46
qgsapplication.h
qgsnetworkcontentfetcherregistry.h
QgsEditFormConfig::setInitFilePath
void setInitFilePath(const QString &filePath)
Set Python external file path for edit form initialization.
Definition: qgseditformconfig.cpp:317
QgsAttributeEditorRelation::setNmRelationId
void setNmRelationId(const QVariant &nmRelationId=QVariant())
Sets nmRelationId for the relation id of the second relation involved in an N:M relation.
Definition: qgsattributeeditorrelation.cpp:129
QgsEditFormConfig::setReuseLastValue
void setReuseLastValue(int index, bool reuse)
Sets whether the widget at the given index will remember the previously entered value from this QGIS ...
Definition: qgseditformconfig.cpp:281
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:225
QgsEditFormConfig::setInitCode
void setInitCode(const QString &code)
Set Python code for edit form initialization.
Definition: qgseditformconfig.cpp:306
QgsReadWriteContextCategoryPopper
Allows entering a context category and takes care of leaving this category on deletion of the class....
Definition: qgsreadwritecontext.h:178
QgsAttributeEditorElement::AeTypeContainer
@ AeTypeContainer
A container.
Definition: qgsattributeeditorelement.h:119
QgsReadWriteContext::enterCategory
MAYBE_UNUSED NODISCARD QgsReadWriteContextCategoryPopper enterCategory(const QString &category, const QString &details=QString()) const
Push a category to the stack.
Definition: qgsreadwritecontext.cpp:62
QgsEditFormConfig::operator=
QgsEditFormConfig & operator=(const QgsEditFormConfig &o)
Definition: qgseditformconfig.cpp:163
QgsEditFormConfig::CodeSourceDialog
@ CodeSourceDialog
Use the Python code provided in the dialog.
Definition: qgseditformconfig.h:99
QgsXmlUtils::readVariant
static QVariant readVariant(const QDomElement &element)
Read a QVariant from a QDomElement.
Definition: qgsxmlutils.cpp:251
QgsAttributeEditorRelation
This element will load a relation editor onto the form.
Definition: qgsattributeeditorrelation.h:32
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:255
QgsEditFormConfig::widgetConfig
QVariantMap widgetConfig(const QString &widgetName) const
Gets the configuration for the editor widget with the given name.
Definition: qgseditformconfig.cpp:53
QgsEditFormConfig::writeXml
void writeXml(QDomNode &node, const QgsReadWriteContext &context) const
Write XML information Serialize on project save.
Definition: qgseditformconfig.cpp:545
QgsEditFormConfig::SuppressDefault
@ SuppressDefault
Use the application-wide setting.
Definition: qgseditformconfig.h:86
QgsMessageLog::logMessage
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Definition: qgsmessagelog.cpp:27
QgsAttributeEditorRelation::relation
const QgsRelation & relation() const
Gets the id of the relation which shall be embedded.
Definition: qgsattributeeditorrelation.h:106
QgsEditFormConfig::setUiForm
void setUiForm(const QString &ui)
Set path to the .ui form.
Definition: qgseditformconfig.cpp:215
QgsEditFormConfig::TabLayout
@ TabLayout
Use a layout with tabs and group boxes. Needs to be configured.
Definition: qgseditformconfig.h:50
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:264
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:234
QgsEditFormConfig
Contains configuration settings for an editor form.
Definition: qgseditformconfig.h:39
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:129
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:37
QgsEditFormConfig::operator==
bool operator==(const QgsEditFormConfig &o) const
Definition: qgseditformconfig.cpp:169
QgsAttributeEditorRelation::setForceSuppressFormPopup
void setForceSuppressFormPopup(bool forceSuppressFormPopup)
Sets force suppress form popup status to forceSuppressFormPopup.
Definition: qgsattributeeditorrelation.cpp:119
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:149
QgsEditFormConfig::clearTabs
void clearTabs()
Clears all the tabs for the attribute editor form with EditorLayout::TabLayout.
Definition: qgseditformconfig.cpp:185
QgsAttributeEditorContainer
This is a container for attribute editors, used to group them visually in the attribute form if it is...
Definition: qgsattributeeditorcontainer.h:27
QgsEditFormConfig::layout
EditorLayout layout() const
Gets the active layout style for the attribute editor for this layer.
Definition: qgseditformconfig.cpp:196
QgsEditFormConfig::dataDefinedFieldProperties
QgsPropertyCollection dataDefinedFieldProperties(const QString &fieldName) const
Returns data defined properties for fieldName.
Definition: qgseditformconfig.cpp:43
QgsEditFormConfig::uiForm
QString uiForm() const
Returns the path or URL to the .ui form.
Definition: qgseditformconfig.cpp:210
qgseditformconfig_p.h
qgslogger.h
QgsEditFormConfig::propertyDefinitions
static const QgsPropertiesDefinition & propertyDefinitions()
Returns data defined property definitions.
Definition: qgseditformconfig.cpp:48
QgsEditFormConfig::setSuppress
void setSuppress(FeatureFormSuppress s)
Sets type of feature form pop-up suppression after feature creation (overrides app setting)
Definition: qgseditformconfig.cpp:346
QgsEditFormConfig::tabs
QList< QgsAttributeEditorElement * > tabs() const
Returns a list of tabs for EditorLayout::TabLayout obtained from the invisible root container.
Definition: qgseditformconfig.cpp:180
QgsEditFormConfig::attributeEditorElementFromDomElement
Q_DECL_DEPRECATED QgsAttributeEditorElement * attributeEditorElementFromDomElement(QDomElement &elem, QgsAttributeEditorElement *parent, const QString &layerId=QString(), const QgsReadWriteContext &context=QgsReadWriteContext())
Deserialize drag and drop designer elements.
Definition: qgseditformconfig.cpp:671
QgsXmlUtils::writeVariant
static QDomElement writeVariant(const QVariant &value, QDomDocument &doc)
Write a QVariant to a QDomElement.
Definition: qgsxmlutils.cpp:106
qgsattributeeditorfield.h
QgsEditFormConfig::EditorLayout
EditorLayout
The different types to layout the attribute editor.
Definition: qgseditformconfig.h:47
QgsEditFormConfig::initCode
QString initCode() const
Gets Python code for edit form initialization.
Definition: qgseditformconfig.cpp:301
QgsEditFormConfig::readXml
void readXml(const QDomNode &node, QgsReadWriteContext &context)
Read XML information Deserialize on project load.
Definition: qgseditformconfig.cpp:352
QgsApplication::networkContentFetcherRegistry
static QgsNetworkContentFetcherRegistry * networkContentFetcherRegistry()
Returns the application's network content registry used for fetching temporary files during QGIS sess...
Definition: qgsapplication.cpp:2375
qgsproject.h
QgsEditFormConfig::suppress
FeatureFormSuppress suppress() const
Type of feature form pop-up suppression after feature creation (overrides app setting)
Definition: qgseditformconfig.cpp:341
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:335
QgsReadWriteContext::pathResolver
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
Definition: qgsreadwritecontext.cpp:47
qgsmessagelog.h
QgsEditFormConfig::UiFileLayout
@ UiFileLayout
Load a .ui file for the layout. Needs to be configured.
Definition: qgseditformconfig.h:51