35#include "moc_qgseditformconfig.cpp"
37using namespace Qt::StringLiterals;
40 : d( new QgsEditFormConfigPrivate() )
46 d->mDataDefinedFieldProperties[fieldName] = properties;
51 return d->mDataDefinedFieldProperties.
value( fieldName );
56 return QgsEditFormConfigPrivate::propertyDefinitions();
61 const int fieldIndex = d->mFields.indexOf( widgetName );
62 if ( fieldIndex != -1 )
63 return d->mFields.at( fieldIndex ).editorWidgetSetup().config();
65 return d->mWidgetConfigs.value( widgetName );
68void QgsEditFormConfig::setFields(
const QgsFields &fields )
73 if ( !d->mConfiguredRootContainer )
75 d->mInvisibleRootContainer->clear();
76 for (
int i = 0; i < d->mFields.size(); ++i )
79 d->mInvisibleRootContainer->addChildElement( field );
84void QgsEditFormConfig::onRelationsLoaded()
88 for ( QgsAttributeEditorElement *relElem : relations )
90 QgsAttributeEditorRelation *rel =
dynamic_cast< QgsAttributeEditorRelation *
>( relElem );
98bool QgsEditFormConfig::legacyUpdateRelationWidgetInTabs(
QgsAttributeEditorContainer *container,
const QString &widgetName,
const QVariantMap &config )
100 const QList<QgsAttributeEditorElement *> children = container->
children();
101 for ( QgsAttributeEditorElement *child : children )
105 QgsAttributeEditorContainer *container =
dynamic_cast<QgsAttributeEditorContainer *
>( child );
106 if ( legacyUpdateRelationWidgetInTabs( container, widgetName, config ) )
114 QgsAttributeEditorRelation *relation =
dynamic_cast< QgsAttributeEditorRelation *
>( child );
117 if ( relation->
relation().
id() == widgetName )
119 if ( config.contains( u
"nm-rel"_s ) )
123 if ( config.contains( u
"force-suppress-popup"_s ) )
137 if ( d->mFields.indexOf( widgetName ) != -1 )
139 QgsDebugError( u
"Trying to set a widget config for a field on QgsEditFormConfig. Use layer->setEditorWidgetSetup() instead."_s );
144 if ( config.contains( u
"force-suppress-popup"_s ) || config.contains( u
"nm-rel"_s ) )
147 u
"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."_s
150 legacyUpdateRelationWidgetInTabs( d->mInvisibleRootContainer, widgetName, config );
154 d->mWidgetConfigs[widgetName] = config;
161 return d->mWidgetConfigs.remove( widgetName ) != 0;
188 d->mInvisibleRootContainer->addChildElement( data );
193 return d->mInvisibleRootContainer->children();
199 d->mInvisibleRootContainer->clear();
204 return d->mInvisibleRootContainer;
209 return d->mEditorLayout;
215 d->mEditorLayout = editorLayout;
218 d->mConfiguredRootContainer =
true;
223 return d->mUiFormPath;
228 if ( !ui.isEmpty() && !QUrl::fromUserInput( ui ).isLocalFile() )
247 if ( idx >= 0 && idx < d->mFields.count() )
251 if ( d->mFields.at( idx ).isReadOnly() )
253 return !d->mFieldEditables.value( d->mFields.at( idx ).name(),
true );
261 if ( idx >= 0 && idx < d->mFields.count() )
262 return d->mLabelOnTop.value( d->mFields.at( idx ).name(),
false );
269 if ( idx >= 0 && idx < d->mFields.count() )
272 d->mFieldEditables[d->mFields.at( idx ).name()] = !
readOnly;
278 if ( idx >= 0 && idx < d->mFields.count() )
281 d->mLabelOnTop[d->mFields.at( idx ).name()] = onTop;
287 if ( index >= 0 && index < d->mFields.count() )
295 if ( index >= 0 && index < d->mFields.count() )
304 if ( index >= 0 && index < d->mFields.count() )
312 if ( index >= 0 && index < d->mFields.count() )
315 d->mReuseLastValuePolicy[d->mFields.at( index ).name()] = policy;
321 return d->mInitFunction;
327 d->mInitFunction = function;
343 return d->mInitFilePath;
349 d->mInitFilePath = filePath;
352 if ( !filePath.isEmpty() && !QUrl::fromUserInput( filePath ).isLocalFile() )
361 return d->mInitCodeSource;
372 return d->mSuppressForm;
378 d->mSuppressForm = s;
387 const QDomNode editFormNode = node.namedItem( u
"editform"_s );
388 if ( !editFormNode.isNull() )
390 const QDomElement e = editFormNode.toElement();
391 const bool tolerantRemoteUrls = e.hasAttribute( u
"tolerant"_s );
392 if ( !e.text().isEmpty() )
398 const bool localFile = QFileInfo::exists( uiFormPath );
399 if ( localFile || tolerantRemoteUrls || uiFormPath.startsWith(
"http"_L1 ) )
404 const QDomNode editFormInitNode = node.namedItem( u
"editforminit"_s );
405 if ( !editFormInitNode.isNull() )
407 d->mInitFunction = editFormInitNode.toElement().text();
410 const QDomNode editFormInitCodeSourceNode = node.namedItem( u
"editforminitcodesource"_s );
411 if ( !editFormInitCodeSourceNode.isNull() && !editFormInitCodeSourceNode.toElement().text().isEmpty() )
416 const QDomNode editFormInitCodeNode = node.namedItem( u
"editforminitcode"_s );
417 if ( !editFormInitCodeNode.isNull() )
419 setInitCode( editFormInitCodeNode.toElement().text() );
427 const int dotPos = d->mInitFunction.lastIndexOf(
'.' );
431 setInitCode( u
"from %1 import %2\n"_s.arg( d->mInitFunction.left( dotPos ), d->mInitFunction.mid( dotPos + 1 ) ) );
435 const QDomNode editFormInitFilePathNode = node.namedItem( u
"editforminitfilepath"_s );
436 if ( !editFormInitFilePathNode.isNull() && !editFormInitFilePathNode.toElement().text().isEmpty() )
441 const QDomNode fFSuppNode = node.namedItem( u
"featformsuppress"_s );
442 if ( fFSuppNode.isNull() )
448 const QDomElement e = fFSuppNode.toElement();
453 const QDomNode editorLayoutNode = node.namedItem( u
"editorlayout"_s );
454 if ( editorLayoutNode.isNull() )
460 if ( editorLayoutNode.toElement().text() ==
"uifilelayout"_L1 )
464 else if ( editorLayoutNode.toElement().text() ==
"tablayout"_L1 )
474 d->mFieldEditables.clear();
475 const QDomNodeList editableNodeList = node.namedItem( u
"editable"_s ).toElement().childNodes();
476 for (
int i = 0; i < editableNodeList.size(); ++i )
478 const QDomElement editableElement = editableNodeList.at( i ).toElement();
479 d->mFieldEditables.insert( editableElement.attribute( u
"name"_s ),
static_cast< bool >( editableElement.attribute( u
"editable"_s ).toInt() ) );
482 d->mLabelOnTop.clear();
483 const QDomNodeList labelOnTopNodeList = node.namedItem( u
"labelOnTop"_s ).toElement().childNodes();
484 for (
int i = 0; i < labelOnTopNodeList.size(); ++i )
486 const QDomElement labelOnTopElement = labelOnTopNodeList.at( i ).toElement();
487 d->mLabelOnTop.insert( labelOnTopElement.attribute( u
"name"_s ),
static_cast< bool >( labelOnTopElement.attribute( u
"labelOnTop"_s ).toInt() ) );
490 d->mReuseLastValuePolicy.clear();
492 const QDomNodeList reuseLastValueNodeList = node.namedItem( u
"reuseLastValue"_s ).toElement().childNodes();
493 for (
int i = 0; i < reuseLastValueNodeList.size(); ++i )
495 const QDomElement reuseLastValueElement = reuseLastValueNodeList.at( i ).toElement();
496 d->mReuseLastValuePolicy
499 const QDomNodeList reuseLastValuePolicyNodeList = node.namedItem( u
"reuseLastValuePolicy"_s ).toElement().childNodes();
500 for (
int i = 0; i < reuseLastValuePolicyNodeList.size(); ++i )
502 const QDomElement reuseLastValuePolicyElement = reuseLastValuePolicyNodeList.at( i ).toElement();
503 d->mReuseLastValuePolicy
508 const QDomNodeList fieldDDPropertiesNodeList = node.namedItem( u
"dataDefinedFieldProperties"_s ).toElement().childNodes();
509 for (
int i = 0; i < fieldDDPropertiesNodeList.size(); ++i )
511 const QDomElement DDElement = fieldDDPropertiesNodeList.at( i ).toElement();
514 d->mDataDefinedFieldProperties.insert( DDElement.attribute( u
"name"_s ), collection );
517 const QDomNodeList widgetsNodeList = node.namedItem( u
"widgets"_s ).toElement().childNodes();
519 for (
int i = 0; i < widgetsNodeList.size(); ++i )
521 const QDomElement widgetElement = widgetsNodeList.at( i ).toElement();
524 d->mWidgetConfigs[widgetElement.attribute( u
"name"_s )] = config.toMap();
528 const QDomNode attributeEditorFormNode = node.namedItem( u
"attributeEditorForm"_s );
529 if ( !attributeEditorFormNode.isNull() )
531 const QDomNodeList attributeEditorFormNodeList = attributeEditorFormNode.toElement().childNodes();
533 if ( attributeEditorFormNodeList.size() )
535 d->mConfiguredRootContainer =
true;
538 for (
int i = 0; i < attributeEditorFormNodeList.size(); i++ )
540 QDomElement elem = attributeEditorFormNodeList.at( i ).toElement();
542 fixLegacyConfig( elem );
544 const QString layerId = node.namedItem( u
"id"_s ).toElement().text();
546 if ( attributeEditorWidget )
547 addTab( attributeEditorWidget );
555void QgsEditFormConfig::fixLegacyConfig( QDomElement &el )
const
559 if ( el.tagName() ==
"attributeEditorRelation"_L1 )
561 if ( !el.hasAttribute( u
"forceSuppressFormPopup"_s ) )
564 const bool forceSuppress =
widgetConfig( el.attribute( u
"relation"_s ) ).value( u
"force-suppress-popup"_s,
false ).toBool();
565 el.setAttribute( u
"forceSuppressFormPopup"_s, forceSuppress ? 1 : 0 );
567 if ( !el.hasAttribute( u
"nmRelationId"_s ) )
570 el.setAttribute( u
"nmRelationId"_s,
widgetConfig( el.attribute( u
"relation"_s ) ).value( u
"nm-rel"_s ).toString() );
574 const QDomNodeList children = el.childNodes();
575 for (
int i = 0; i < children.size(); i++ )
577 QDomElement child = children.at( i ).toElement();
578 fixLegacyConfig( child );
579 el.replaceChild( child, children.at( i ) );
585 QDomDocument doc( node.ownerDocument() );
587 QDomElement efField = doc.createElement( u
"editform"_s );
588 efField.setAttribute( u
"tolerant"_s, u
"1"_s );
590 efField.appendChild( efText );
591 node.appendChild( efField );
593 QDomElement efiField = doc.createElement( u
"editforminit"_s );
595 efiField.appendChild( doc.createTextNode(
initFunction() ) );
596 node.appendChild( efiField );
598 QDomElement eficsField = doc.createElement( u
"editforminitcodesource"_s );
599 eficsField.appendChild( doc.createTextNode( QString::number(
static_cast< int >(
initCodeSource() ) ) ) );
600 node.appendChild( eficsField );
602 QDomElement efifpField = doc.createElement( u
"editforminitfilepath"_s );
604 node.appendChild( efifpField );
606 QDomElement eficField = doc.createElement( u
"editforminitcode"_s );
607 eficField.appendChild( doc.createCDATASection(
initCode() ) );
608 node.appendChild( eficField );
610 QDomElement fFSuppElem = doc.createElement( u
"featformsuppress"_s );
611 const QDomText fFSuppText = doc.createTextNode( QString::number(
static_cast< int >(
suppress() ) ) );
612 fFSuppElem.appendChild( fFSuppText );
613 node.appendChild( fFSuppElem );
616 QDomElement editorLayoutElem = doc.createElement( u
"editorlayout"_s );
620 editorLayoutElem.appendChild( doc.createTextNode( u
"uifilelayout"_s ) );
624 editorLayoutElem.appendChild( doc.createTextNode( u
"tablayout"_s ) );
629 editorLayoutElem.appendChild( doc.createTextNode( u
"generatedlayout"_s ) );
633 node.appendChild( editorLayoutElem );
636 if ( !
tabs().empty() && d->mConfiguredRootContainer )
638 QDomElement tabsElem = doc.createElement( u
"attributeEditorForm"_s );
639 const QDomElement rootElem = d->mInvisibleRootContainer->toDomElement( doc );
640 const QDomNodeList elemList = rootElem.childNodes();
641 while ( !elemList.isEmpty() )
643 tabsElem.appendChild( elemList.at( 0 ) );
645 node.appendChild( tabsElem );
648 QDomElement editableElem = doc.createElement( u
"editable"_s );
649 for (
auto editIt = d->mFieldEditables.constBegin(); editIt != d->mFieldEditables.constEnd(); ++editIt )
651 QDomElement fieldElem = doc.createElement( u
"field"_s );
652 fieldElem.setAttribute( u
"name"_s, editIt.key() );
653 fieldElem.setAttribute( u
"editable"_s, editIt.value() ? u
"1"_s : u
"0"_s );
654 editableElem.appendChild( fieldElem );
656 node.appendChild( editableElem );
658 QDomElement labelOnTopElem = doc.createElement( u
"labelOnTop"_s );
659 for (
auto labelOnTopIt = d->mLabelOnTop.constBegin(); labelOnTopIt != d->mLabelOnTop.constEnd(); ++labelOnTopIt )
661 QDomElement fieldElem = doc.createElement( u
"field"_s );
662 fieldElem.setAttribute( u
"name"_s, labelOnTopIt.key() );
663 fieldElem.setAttribute( u
"labelOnTop"_s, labelOnTopIt.value() ? u
"1"_s : u
"0"_s );
664 labelOnTopElem.appendChild( fieldElem );
666 node.appendChild( labelOnTopElem );
668 QDomElement reuseLastValuePolicyElem = doc.createElement( u
"reuseLastValuePolicy"_s );
669 for (
auto reuseLastValuePolicyIt = d->mReuseLastValuePolicy.constBegin(); reuseLastValuePolicyIt != d->mReuseLastValuePolicy.constEnd(); ++reuseLastValuePolicyIt )
671 QDomElement fieldElem = doc.createElement( u
"field"_s );
672 fieldElem.setAttribute( u
"name"_s, reuseLastValuePolicyIt.key() );
673 fieldElem.setAttribute( u
"reuseLastValuePolicy"_s,
qgsEnumValueToKey( reuseLastValuePolicyIt.value() ) );
674 reuseLastValuePolicyElem.appendChild( fieldElem );
676 node.appendChild( reuseLastValuePolicyElem );
679 QDomElement ddFieldPropsElement = doc.createElement( u
"dataDefinedFieldProperties"_s );
680 for (
auto it = d->mDataDefinedFieldProperties.constBegin(); it != d->mDataDefinedFieldProperties.constEnd(); ++it )
682 QDomElement ddPropsElement = doc.createElement( u
"field"_s );
683 ddPropsElement.setAttribute( u
"name"_s, it.key() );
685 ddFieldPropsElement.appendChild( ddPropsElement );
687 node.appendChild( ddFieldPropsElement );
689 QDomElement widgetsElem = doc.createElement( u
"widgets"_s );
691 QMap<QString, QVariantMap >::ConstIterator configIt( d->mWidgetConfigs.constBegin() );
693 while ( configIt != d->mWidgetConfigs.constEnd() )
695 QDomElement widgetElem = doc.createElement( u
"widget"_s );
696 widgetElem.setAttribute( u
"name"_s, configIt.key() );
700 configElem.setTagName( u
"config"_s );
701 widgetElem.appendChild( configElem );
702 widgetsElem.appendChild( widgetElem );
706 node.appendChild( widgetsElem );
AttributeFormReuseLastValuePolicy
Attribute form policy for reusing last entered values.
@ AllowedDefaultOn
Reuse of last values allowed and enabled by default.
@ NotAllowed
Reuse of last values not allowed.
AttributeFormSuppression
Available form types for layout of the attribute form editor.
@ Default
Use the application-wide setting.
AttributeFormPythonInitCodeSource
The Python init code source for attribute forms.
@ Dialog
Use the Python code provided in the dialog.
AttributeFormLayout
Available form types for layout of the attribute form editor.
@ DragAndDrop
"Drag and drop" layout. Needs to be configured.
@ AutoGenerated
Autogenerate a simple tabular layout for the form.
@ UiFile
Load a .ui file for the layout. Needs to be configured.
@ Immediate
Action will start immediately.
@ Expression
Field is calculated from an expression.
@ Join
Field originates from a joined layer.
virtual bool readXml(const QDomElement &collectionElem, const QgsPropertiesDefinition &definitions)
Reads property collection state from an XML element.
static QgsNetworkContentFetcherRegistry * networkContentFetcherRegistry()
Returns the application's network content registry used for fetching temporary files during QGIS sess...
A container for attribute editors, used to group them visually in the attribute form if it is set to ...
QList< QgsAttributeEditorElement * > children() const
Gets a list of the children elements of this container.
An abstract base class for any elements of a drag and drop form.
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.
This element will load a field's widget onto the form.
void setNmRelationId(const QVariant &nmRelationId=QVariant())
Sets nmRelationId for the relation id of the second relation involved in an N:M relation.
bool init(QgsRelationManager *relManager)
Initializes the relation from the id.
const QgsRelation & relation() const
Gets the id of the relation which shall be embedded.
void setForceSuppressFormPopup(bool forceSuppressFormPopup)
Sets force suppress form popup status to forceSuppressFormPopup.
Container of fields for a vector layer.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
Adds a message to the log instance (and creates it if necessary).
QgsFetchedContent * fetch(const QString &url, Qgis::ActionStart fetchingMode=Qgis::ActionStart::Deferred, const QString &authConfig=QString(), const QgsHttpHeaders &headers=QgsHttpHeaders())
Initialize a download for the given URL.
QString writePath(const QString &filename) const
Prepare a filename to save it to the project file.
QString readPath(const QString &filename) const
Turn filename read from the project file to an absolute path.
static QgsProject * instance()
Returns the QgsProject singleton instance.
A grouped map of multiple QgsProperty objects, each referenced by an integer key value.
QVariant value(int key, const QgsExpressionContext &context, const QVariant &defaultValue=QVariant()) const final
Returns the calculated value of the property with the specified key from within the collection.
Allows entering a context category and takes care of leaving this category on deletion of the class.
A container for the context for various read/write operations on objects.
QgsReadWriteContextCategoryPopper enterCategory(const QString &category, const QString &details=QString()) const
Push a category to the stack.
const QgsPathResolver & pathResolver() const
Returns path resolver for conversion between relative and absolute paths.
static QDomElement writeVariant(const QVariant &value, QDomDocument &doc)
Write a QVariant to a QDomElement.
static QVariant readVariant(const QDomElement &element)
Read a QVariant from a QDomElement.
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
#define QgsDebugError(str)
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.