18#include "moc_qgseditformconfig.cpp"
34 : d( new QgsEditFormConfigPrivate() )
41 d->mDataDefinedFieldProperties[ fieldName ] = properties;
46 return d->mDataDefinedFieldProperties.value( fieldName );
51 return QgsEditFormConfigPrivate::propertyDefinitions();
56 const int fieldIndex = d->mFields.indexOf( widgetName );
57 if ( fieldIndex != -1 )
58 return d->mFields.at( fieldIndex ).editorWidgetSetup().config();
60 return d->mWidgetConfigs.value( widgetName );
63void QgsEditFormConfig::setFields(
const QgsFields &fields )
68 if ( !d->mConfiguredRootContainer )
70 d->mInvisibleRootContainer->clear();
71 for (
int i = 0; i < d->mFields.size(); ++i )
74 d->mInvisibleRootContainer->addChildElement( field );
79void QgsEditFormConfig::onRelationsLoaded()
93bool QgsEditFormConfig::legacyUpdateRelationWidgetInTabs(
QgsAttributeEditorContainer *container,
const QString &widgetName,
const QVariantMap &config )
95 const QList<QgsAttributeEditorElement *> children = container->
children();
101 if ( legacyUpdateRelationWidgetInTabs( container, widgetName, config ) )
112 if ( relation->
relation().
id() == widgetName )
114 if ( config.contains( QStringLiteral(
"nm-rel" ) ) )
118 if ( config.contains( QStringLiteral(
"force-suppress-popup" ) ) )
132 if ( d->mFields.indexOf( widgetName ) != -1 )
134 QgsDebugError( QStringLiteral(
"Trying to set a widget config for a field on QgsEditFormConfig. Use layer->setEditorWidgetSetup() instead." ) );
139 if ( config.contains( QStringLiteral(
"force-suppress-popup" ) ) || config.contains( QStringLiteral(
"nm-rel" ) ) )
141 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 ) );
142 legacyUpdateRelationWidgetInTabs( d->mInvisibleRootContainer, widgetName, config );
146 d->mWidgetConfigs[widgetName] = config;
153 return d->mWidgetConfigs.remove( widgetName ) != 0;
178 d->mInvisibleRootContainer->addChildElement( data );
183 return d->mInvisibleRootContainer->children();
189 d->mInvisibleRootContainer->clear();
194 return d->mInvisibleRootContainer;
199 return d->mEditorLayout;
205 d->mEditorLayout = editorLayout;
208 d->mConfiguredRootContainer =
true;
213 return d->mUiFormPath;
218 if ( !ui.isEmpty() && !QUrl::fromUserInput( ui ).isLocalFile() )
237 if ( idx >= 0 && idx < d->mFields.count() )
242 if ( d->mFields.at( idx ).isReadOnly() )
244 return !d->mFieldEditables.value( d->mFields.at( idx ).name(),
true );
252 if ( idx >= 0 && idx < d->mFields.count() )
253 return d->mLabelOnTop.value( d->mFields.at( idx ).name(),
false );
260 if ( idx >= 0 && idx < d->mFields.count() )
263 d->mFieldEditables[ d->mFields.at( idx ).name()] = !
readOnly;
269 if ( idx >= 0 && idx < d->mFields.count() )
272 d->mLabelOnTop[ d->mFields.at( idx ).name()] = onTop;
278 if ( index >= 0 && index < d->mFields.count() )
279 return d->mReuseLastValue.value( d->mFields.at( index ).name(),
false );
286 if ( index >= 0 && index < d->mFields.count() )
289 d->mReuseLastValue[ d->mFields.at( index ).name()] = reuse;
295 return d->mInitFunction;
301 d->mInitFunction = function;
317 return d->mInitFilePath;
323 d->mInitFilePath = filePath;
326 if ( !filePath.isEmpty() && !QUrl::fromUserInput( filePath ).isLocalFile() )
335 return d->mInitCodeSource;
346 return d->mSuppressForm;
352 d->mSuppressForm = s;
361 const QDomNode editFormNode = node.namedItem( QStringLiteral(
"editform" ) );
362 if ( !editFormNode.isNull() )
364 const QDomElement e = editFormNode.toElement();
365 const bool tolerantRemoteUrls = e.hasAttribute( QStringLiteral(
"tolerant" ) );
366 if ( !e.text().isEmpty() )
372 const bool localFile = QFileInfo::exists( uiFormPath );
373 if ( localFile || tolerantRemoteUrls || uiFormPath.startsWith( QLatin1String(
"http" ) ) )
378 const QDomNode editFormInitNode = node.namedItem( QStringLiteral(
"editforminit" ) );
379 if ( !editFormInitNode.isNull() )
381 d->mInitFunction = editFormInitNode.toElement().text();
384 const QDomNode editFormInitCodeSourceNode = node.namedItem( QStringLiteral(
"editforminitcodesource" ) );
385 if ( !editFormInitCodeSourceNode.isNull() && !editFormInitCodeSourceNode.toElement().text().isEmpty() )
390 const QDomNode editFormInitCodeNode = node.namedItem( QStringLiteral(
"editforminitcode" ) );
391 if ( !editFormInitCodeNode.isNull() )
393 setInitCode( editFormInitCodeNode.toElement().text() );
401 const int dotPos = d->mInitFunction.lastIndexOf(
'.' );
405 setInitCode( QStringLiteral(
"from %1 import %2\n" ).arg( d->mInitFunction.left( dotPos ), d->mInitFunction.mid( dotPos + 1 ) ) );
409 const QDomNode editFormInitFilePathNode = node.namedItem( QStringLiteral(
"editforminitfilepath" ) );
410 if ( !editFormInitFilePathNode.isNull() && !editFormInitFilePathNode.toElement().text().isEmpty() )
415 const QDomNode fFSuppNode = node.namedItem( QStringLiteral(
"featformsuppress" ) );
416 if ( fFSuppNode.isNull() )
422 const QDomElement e = fFSuppNode.toElement();
427 const QDomNode editorLayoutNode = node.namedItem( QStringLiteral(
"editorlayout" ) );
428 if ( editorLayoutNode.isNull() )
434 if ( editorLayoutNode.toElement().text() == QLatin1String(
"uifilelayout" ) )
438 else if ( editorLayoutNode.toElement().text() == QLatin1String(
"tablayout" ) )
448 d->mFieldEditables.clear();
449 const QDomNodeList editableNodeList = node.namedItem( QStringLiteral(
"editable" ) ).toElement().childNodes();
450 for (
int i = 0; i < editableNodeList.size(); ++i )
452 const QDomElement editableElement = editableNodeList.at( i ).toElement();
453 d->mFieldEditables.insert( editableElement.attribute( QStringLiteral(
"name" ) ),
static_cast< bool >( editableElement.attribute( QStringLiteral(
"editable" ) ).toInt() ) );
456 d->mLabelOnTop.clear();
457 const QDomNodeList labelOnTopNodeList = node.namedItem( QStringLiteral(
"labelOnTop" ) ).toElement().childNodes();
458 for (
int i = 0; i < labelOnTopNodeList.size(); ++i )
460 const QDomElement labelOnTopElement = labelOnTopNodeList.at( i ).toElement();
461 d->mLabelOnTop.insert( labelOnTopElement.attribute( QStringLiteral(
"name" ) ),
static_cast< bool >( labelOnTopElement.attribute( QStringLiteral(
"labelOnTop" ) ).toInt() ) );
464 d->mReuseLastValue.clear();
465 const QDomNodeList reuseLastValueNodeList = node.namedItem( QStringLiteral(
"reuseLastValue" ) ).toElement().childNodes();
466 for (
int i = 0; i < reuseLastValueNodeList.size(); ++i )
468 const QDomElement reuseLastValueElement = reuseLastValueNodeList.at( i ).toElement();
469 d->mReuseLastValue.insert( reuseLastValueElement.attribute( QStringLiteral(
"name" ) ),
static_cast< bool >( reuseLastValueElement.attribute( QStringLiteral(
"reuseLastValue" ) ).toInt() ) );
473 const QDomNodeList fieldDDPropertiesNodeList = node.namedItem( QStringLiteral(
"dataDefinedFieldProperties" ) ).toElement().childNodes();
474 for (
int i = 0; i < fieldDDPropertiesNodeList.size(); ++i )
476 const QDomElement DDElement = fieldDDPropertiesNodeList.at( i ).toElement();
479 d->mDataDefinedFieldProperties.insert( DDElement.attribute( QStringLiteral(
"name" ) ), collection );
482 const QDomNodeList widgetsNodeList = node.namedItem( QStringLiteral(
"widgets" ) ).toElement().childNodes();
484 for (
int i = 0; i < widgetsNodeList.size(); ++i )
486 const QDomElement widgetElement = widgetsNodeList.at( i ).toElement();
489 d->mWidgetConfigs[widgetElement.attribute( QStringLiteral(
"name" ) )] = config.toMap();
493 const QDomNode attributeEditorFormNode = node.namedItem( QStringLiteral(
"attributeEditorForm" ) );
494 if ( !attributeEditorFormNode.isNull() )
496 const QDomNodeList attributeEditorFormNodeList = attributeEditorFormNode.toElement().childNodes();
498 if ( attributeEditorFormNodeList.size() )
500 d->mConfiguredRootContainer =
true;
503 for (
int i = 0; i < attributeEditorFormNodeList.size(); i++ )
505 QDomElement elem = attributeEditorFormNodeList.at( i ).toElement();
507 fixLegacyConfig( elem );
509 const QString layerId = node.namedItem( QStringLiteral(
"id" ) ).toElement().text();
511 if ( attributeEditorWidget )
512 addTab( attributeEditorWidget );
520void QgsEditFormConfig::fixLegacyConfig( QDomElement &el )
const
524 if ( el.tagName() == QLatin1String(
"attributeEditorRelation" ) )
526 if ( !el.hasAttribute( QStringLiteral(
"forceSuppressFormPopup" ) ) )
529 const bool forceSuppress =
widgetConfig( el.attribute( QStringLiteral(
"relation" ) ) ).value( QStringLiteral(
"force-suppress-popup" ),
false ).toBool();
530 el.setAttribute( QStringLiteral(
"forceSuppressFormPopup" ), forceSuppress ? 1 : 0 );
532 if ( !el.hasAttribute( QStringLiteral(
"nmRelationId" ) ) )
535 el.setAttribute( QStringLiteral(
"nmRelationId" ),
widgetConfig( el.attribute( QStringLiteral(
"relation" ) ) ).value( QStringLiteral(
"nm-rel" ) ).toString() );
539 const QDomNodeList children = el.childNodes();
540 for (
int i = 0; i < children.size(); i++ )
542 QDomElement child = children.at( i ).toElement();
543 fixLegacyConfig( child );
544 el.replaceChild( child, children.at( i ) );
550 QDomDocument doc( node.ownerDocument() );
552 QDomElement efField = doc.createElement( QStringLiteral(
"editform" ) );
553 efField.setAttribute( QStringLiteral(
"tolerant" ), QStringLiteral(
"1" ) );
555 efField.appendChild( efText );
556 node.appendChild( efField );
558 QDomElement efiField = doc.createElement( QStringLiteral(
"editforminit" ) );
560 efiField.appendChild( doc.createTextNode(
initFunction() ) );
561 node.appendChild( efiField );
563 QDomElement eficsField = doc.createElement( QStringLiteral(
"editforminitcodesource" ) );
564 eficsField.appendChild( doc.createTextNode( QString::number(
static_cast< int >(
initCodeSource() ) ) ) );
565 node.appendChild( eficsField );
567 QDomElement efifpField = doc.createElement( QStringLiteral(
"editforminitfilepath" ) );
569 node.appendChild( efifpField );
571 QDomElement eficField = doc.createElement( QStringLiteral(
"editforminitcode" ) );
572 eficField.appendChild( doc.createCDATASection(
initCode() ) );
573 node.appendChild( eficField );
575 QDomElement fFSuppElem = doc.createElement( QStringLiteral(
"featformsuppress" ) );
576 const QDomText fFSuppText = doc.createTextNode( QString::number(
static_cast< int >(
suppress() ) ) );
577 fFSuppElem.appendChild( fFSuppText );
578 node.appendChild( fFSuppElem );
581 QDomElement editorLayoutElem = doc.createElement( QStringLiteral(
"editorlayout" ) );
585 editorLayoutElem.appendChild( doc.createTextNode( QStringLiteral(
"uifilelayout" ) ) );
589 editorLayoutElem.appendChild( doc.createTextNode( QStringLiteral(
"tablayout" ) ) );
594 editorLayoutElem.appendChild( doc.createTextNode( QStringLiteral(
"generatedlayout" ) ) );
598 node.appendChild( editorLayoutElem );
601 if ( !
tabs().empty() && d->mConfiguredRootContainer )
603 QDomElement tabsElem = doc.createElement( QStringLiteral(
"attributeEditorForm" ) );
604 const QDomElement rootElem = d->mInvisibleRootContainer->toDomElement( doc );
605 const QDomNodeList elemList = rootElem.childNodes();
606 while ( !elemList.isEmpty() )
608 tabsElem.appendChild( elemList.at( 0 ) );
610 node.appendChild( tabsElem );
613 QDomElement editableElem = doc.createElement( QStringLiteral(
"editable" ) );
614 for (
auto editIt = d->mFieldEditables.constBegin(); editIt != d->mFieldEditables.constEnd(); ++editIt )
616 QDomElement fieldElem = doc.createElement( QStringLiteral(
"field" ) );
617 fieldElem.setAttribute( QStringLiteral(
"name" ), editIt.key() );
618 fieldElem.setAttribute( QStringLiteral(
"editable" ), editIt.value() ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
619 editableElem.appendChild( fieldElem );
621 node.appendChild( editableElem );
623 QDomElement labelOnTopElem = doc.createElement( QStringLiteral(
"labelOnTop" ) );
624 for (
auto labelOnTopIt = d->mLabelOnTop.constBegin(); labelOnTopIt != d->mLabelOnTop.constEnd(); ++labelOnTopIt )
626 QDomElement fieldElem = doc.createElement( QStringLiteral(
"field" ) );
627 fieldElem.setAttribute( QStringLiteral(
"name" ), labelOnTopIt.key() );
628 fieldElem.setAttribute( QStringLiteral(
"labelOnTop" ), labelOnTopIt.value() ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
629 labelOnTopElem.appendChild( fieldElem );
631 node.appendChild( labelOnTopElem );
633 QDomElement reuseLastValueElem = doc.createElement( QStringLiteral(
"reuseLastValue" ) );
634 for (
auto reuseLastValueIt = d->mReuseLastValue.constBegin(); reuseLastValueIt != d->mReuseLastValue.constEnd(); ++reuseLastValueIt )
636 QDomElement fieldElem = doc.createElement( QStringLiteral(
"field" ) );
637 fieldElem.setAttribute( QStringLiteral(
"name" ), reuseLastValueIt.key() );
638 fieldElem.setAttribute( QStringLiteral(
"reuseLastValue" ), reuseLastValueIt.value() ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
639 reuseLastValueElem.appendChild( fieldElem );
641 node.appendChild( reuseLastValueElem );
644 QDomElement ddFieldPropsElement = doc.createElement( QStringLiteral(
"dataDefinedFieldProperties" ) );
645 for (
auto it = d->mDataDefinedFieldProperties.constBegin(); it != d->mDataDefinedFieldProperties.constEnd(); ++it )
647 QDomElement ddPropsElement = doc.createElement( QStringLiteral(
"field" ) );
648 ddPropsElement.setAttribute( QStringLiteral(
"name" ), it.key() );
650 ddFieldPropsElement.appendChild( ddPropsElement );
652 node.appendChild( ddFieldPropsElement );
654 QDomElement widgetsElem = doc.createElement( QStringLiteral(
"widgets" ) );
656 QMap<QString, QVariantMap >::ConstIterator configIt( d->mWidgetConfigs.constBegin() );
658 while ( configIt != d->mWidgetConfigs.constEnd() )
660 QDomElement widgetElem = doc.createElement( QStringLiteral(
"widget" ) );
661 widgetElem.setAttribute( QStringLiteral(
"name" ), configIt.key() );
665 configElem.setTagName( QStringLiteral(
"config" ) );
666 widgetElem.appendChild( configElem );
667 widgetsElem.appendChild( widgetElem );
671 node.appendChild( widgetsElem );
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...
This is a container for attribute editors, used to group them visually in the attribute form if it is...
QList< QgsAttributeEditorElement * > children() const
Gets a list of the children elements of this container.
This is 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.
This element will load a relation editor 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)
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())
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.
QgsRelationManager * relationManager
static QgsProject * instance()
Returns the QgsProject singleton instance.
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
Allows entering a context category and takes care of leaving this category on deletion of the class.
The class is used as a container of context for various read/write operations on other objects.
MAYBE_UNUSED NODISCARD 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.
#define QgsDebugError(str)
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.