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