QGIS API Documentation 4.1.0-Master (60fea48833c)
Loading...
Searching...
No Matches
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.h"
17
18#include "qgsapplication.h"
22#include "qgseditformconfig_p.h"
23#include "qgslogger.h"
24#include "qgsmessagelog.h"
26#include "qgspathresolver.h"
27#include "qgsproject.h"
28#include "qgsreadwritecontext.h"
29#include "qgsrelationmanager.h"
30#include "qgsxmlutils.h"
31
32#include <QString>
33#include <QUrl>
34
35#include "moc_qgseditformconfig.cpp"
36
37using namespace Qt::StringLiterals;
38
40 : d( new QgsEditFormConfigPrivate() )
41{}
42
43void QgsEditFormConfig::setDataDefinedFieldProperties( const QString &fieldName, const QgsPropertyCollection &properties )
44{
45 d.detach();
46 d->mDataDefinedFieldProperties[fieldName] = properties;
47}
48
50{
51 return d->mDataDefinedFieldProperties.value( fieldName );
52}
53
55{
56 return QgsEditFormConfigPrivate::propertyDefinitions();
57}
58
59QVariantMap QgsEditFormConfig::widgetConfig( const QString &widgetName ) const
60{
61 const int fieldIndex = d->mFields.indexOf( widgetName );
62 if ( fieldIndex != -1 )
63 return d->mFields.at( fieldIndex ).editorWidgetSetup().config();
64 else
65 return d->mWidgetConfigs.value( widgetName );
66}
67
68void QgsEditFormConfig::setFields( const QgsFields &fields )
69{
70 d.detach();
71 d->mFields = fields;
72
73 if ( !d->mConfiguredRootContainer )
74 {
75 d->mInvisibleRootContainer->clear();
76 for ( int i = 0; i < d->mFields.size(); ++i )
77 {
78 QgsAttributeEditorField *field = new QgsAttributeEditorField( d->mFields.at( i ).name(), i, d->mInvisibleRootContainer );
79 d->mInvisibleRootContainer->addChildElement( field );
80 }
81 }
82}
83
84void QgsEditFormConfig::onRelationsLoaded()
85{
86 const QList<QgsAttributeEditorElement *> relations = d->mInvisibleRootContainer->findElements( Qgis::AttributeEditorType::Relation );
87
88 for ( QgsAttributeEditorElement *relElem : relations )
89 {
90 QgsAttributeEditorRelation *rel = dynamic_cast< QgsAttributeEditorRelation * >( relElem );
91 if ( !rel )
92 continue;
93
94 rel->init( QgsProject::instance()->relationManager() ); // skip-keyword-check
95 }
96}
97
98bool QgsEditFormConfig::legacyUpdateRelationWidgetInTabs( QgsAttributeEditorContainer *container, const QString &widgetName, const QVariantMap &config )
99{
100 const QList<QgsAttributeEditorElement *> children = container->children();
101 for ( QgsAttributeEditorElement *child : children )
102 {
103 if ( child->type() == Qgis::AttributeEditorType::Container )
104 {
105 QgsAttributeEditorContainer *container = dynamic_cast<QgsAttributeEditorContainer *>( child );
106 if ( legacyUpdateRelationWidgetInTabs( container, widgetName, config ) )
107 {
108 //return when a relation has been set in a child or child child...
109 return true;
110 }
111 }
112 else if ( child->type() == Qgis::AttributeEditorType::Relation )
113 {
114 QgsAttributeEditorRelation *relation = dynamic_cast< QgsAttributeEditorRelation * >( child );
115 if ( relation )
116 {
117 if ( relation->relation().id() == widgetName )
118 {
119 if ( config.contains( u"nm-rel"_s ) )
120 {
121 relation->setNmRelationId( config[u"nm-rel"_s] );
122 }
123 if ( config.contains( u"force-suppress-popup"_s ) )
124 {
125 relation->setForceSuppressFormPopup( config[u"force-suppress-popup"_s].toBool() );
126 }
127 return true;
128 }
129 }
130 }
131 }
132 return false;
133}
134
135bool QgsEditFormConfig::setWidgetConfig( const QString &widgetName, const QVariantMap &config )
136{
137 if ( d->mFields.indexOf( widgetName ) != -1 )
138 {
139 QgsDebugError( u"Trying to set a widget config for a field on QgsEditFormConfig. Use layer->setEditorWidgetSetup() instead."_s );
140 return false;
141 }
142
143 //for legacy use it writes the relation editor configuration into the first instance of the widget
144 if ( config.contains( u"force-suppress-popup"_s ) || config.contains( u"nm-rel"_s ) )
145 {
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
148 .arg( widgetName )
149 );
150 legacyUpdateRelationWidgetInTabs( d->mInvisibleRootContainer, widgetName, config );
151 }
152
153 d.detach();
154 d->mWidgetConfigs[widgetName] = config;
155 return true;
156}
157
158bool QgsEditFormConfig::removeWidgetConfig( const QString &widgetName )
159{
160 d.detach();
161 return d->mWidgetConfigs.remove( widgetName ) != 0;
162}
163
165 : d( o.d )
166{}
167
170
172{
173 if ( &o == this )
174 return *this;
175
176 d = o.d;
177 return *this;
178}
179
181{
182 return d == o.d;
183}
184
186{
187 d.detach();
188 d->mInvisibleRootContainer->addChildElement( data );
189}
190
191QList<QgsAttributeEditorElement *> QgsEditFormConfig::tabs() const
192{
193 return d->mInvisibleRootContainer->children();
194}
195
197{
198 d.detach();
199 d->mInvisibleRootContainer->clear();
200}
201
203{
204 return d->mInvisibleRootContainer;
205}
206
208{
209 return d->mEditorLayout;
210}
211
213{
214 d.detach();
215 d->mEditorLayout = editorLayout;
216
217 if ( editorLayout == Qgis::AttributeFormLayout::DragAndDrop )
218 d->mConfiguredRootContainer = true;
219}
220
222{
223 return d->mUiFormPath;
224}
225
226void QgsEditFormConfig::setUiForm( const QString &ui )
227{
228 if ( !ui.isEmpty() && !QUrl::fromUserInput( ui ).isLocalFile() )
229 {
230 // any existing download will not be restarted!
232 }
233
234 if ( ui.isEmpty() )
235 {
237 }
238 else
239 {
241 }
242 d->mUiFormPath = ui;
243}
244
245bool QgsEditFormConfig::readOnly( int idx ) const
246{
247 if ( idx >= 0 && idx < d->mFields.count() )
248 {
249 if ( d->mFields.fieldOrigin( idx ) == Qgis::FieldOrigin::Join || d->mFields.fieldOrigin( idx ) == Qgis::FieldOrigin::Expression )
250 return true;
251 if ( d->mFields.at( idx ).isReadOnly() )
252 return true;
253 return !d->mFieldEditables.value( d->mFields.at( idx ).name(), true );
254 }
255 else
256 return false;
257}
258
259bool QgsEditFormConfig::labelOnTop( int idx ) const
260{
261 if ( idx >= 0 && idx < d->mFields.count() )
262 return d->mLabelOnTop.value( d->mFields.at( idx ).name(), false );
263 else
264 return false;
265}
266
268{
269 if ( idx >= 0 && idx < d->mFields.count() )
270 {
271 d.detach();
272 d->mFieldEditables[d->mFields.at( idx ).name()] = !readOnly;
273 }
274}
275
276void QgsEditFormConfig::setLabelOnTop( int idx, bool onTop )
277{
278 if ( idx >= 0 && idx < d->mFields.count() )
279 {
280 d.detach();
281 d->mLabelOnTop[d->mFields.at( idx ).name()] = onTop;
282 }
283}
284
286{
287 if ( index >= 0 && index < d->mFields.count() )
288 return d->mReuseLastValuePolicy.value( d->mFields.at( index ).name(), Qgis::AttributeFormReuseLastValuePolicy::NotAllowed ) != Qgis::AttributeFormReuseLastValuePolicy::NotAllowed;
289 else
290 return false;
291}
292
293void QgsEditFormConfig::setReuseLastValue( int index, bool reuse )
294{
295 if ( index >= 0 && index < d->mFields.count() )
296 {
297 d.detach();
298 d->mReuseLastValuePolicy[d->mFields.at( index ).name()] = reuse ? Qgis::AttributeFormReuseLastValuePolicy::AllowedDefaultOn : Qgis::AttributeFormReuseLastValuePolicy::NotAllowed;
299 }
300}
301
303{
304 if ( index >= 0 && index < d->mFields.count() )
305 return d->mReuseLastValuePolicy.value( d->mFields.at( index ).name(), Qgis::AttributeFormReuseLastValuePolicy::NotAllowed );
306 else
308}
309
311{
312 if ( index >= 0 && index < d->mFields.count() )
313 {
314 d.detach();
315 d->mReuseLastValuePolicy[d->mFields.at( index ).name()] = policy;
316 }
317}
318
320{
321 return d->mInitFunction;
322}
323
324void QgsEditFormConfig::setInitFunction( const QString &function )
325{
326 d.detach();
327 d->mInitFunction = function;
328}
329
331{
332 return d->mInitCode;
333}
334
335void QgsEditFormConfig::setInitCode( const QString &code )
336{
337 d.detach();
338 d->mInitCode = code;
339}
340
342{
343 return d->mInitFilePath;
344}
345
346void QgsEditFormConfig::setInitFilePath( const QString &filePath )
347{
348 d.detach();
349 d->mInitFilePath = filePath;
350
351 // if this is an URL, download file as there is a good chance it will be used later
352 if ( !filePath.isEmpty() && !QUrl::fromUserInput( filePath ).isLocalFile() )
353 {
354 // any existing download will not be restarted!
356 }
357}
358
360{
361 return d->mInitCodeSource;
362}
363
369
371{
372 return d->mSuppressForm;
373}
374
376{
377 d.detach();
378 d->mSuppressForm = s;
379}
380
381void QgsEditFormConfig::readXml( const QDomNode &node, QgsReadWriteContext &context )
382{
383 const QgsReadWriteContextCategoryPopper p = context.enterCategory( QObject::tr( "Edit form config" ) );
384
385 d.detach();
386
387 const QDomNode editFormNode = node.namedItem( u"editform"_s );
388 if ( !editFormNode.isNull() )
389 {
390 const QDomElement e = editFormNode.toElement();
391 const bool tolerantRemoteUrls = e.hasAttribute( u"tolerant"_s );
392 if ( !e.text().isEmpty() )
393 {
394 const QString uiFormPath = context.pathResolver().readPath( e.text() );
395 // <= 3.2 had a bug where invalid ui paths would get written into projects on load
396 // to avoid restoring these invalid paths, we take a less-tolerant approach for older (untrustworthy) projects
397 // and only set ui forms paths IF they are local files OR start with "http(s)".
398 const bool localFile = QFileInfo::exists( uiFormPath );
399 if ( localFile || tolerantRemoteUrls || uiFormPath.startsWith( "http"_L1 ) )
400 setUiForm( uiFormPath );
401 }
402 }
403
404 const QDomNode editFormInitNode = node.namedItem( u"editforminit"_s );
405 if ( !editFormInitNode.isNull() )
406 {
407 d->mInitFunction = editFormInitNode.toElement().text();
408 }
409
410 const QDomNode editFormInitCodeSourceNode = node.namedItem( u"editforminitcodesource"_s );
411 if ( !editFormInitCodeSourceNode.isNull() && !editFormInitCodeSourceNode.toElement().text().isEmpty() )
412 {
413 setInitCodeSource( static_cast< Qgis::AttributeFormPythonInitCodeSource >( editFormInitCodeSourceNode.toElement().text().toInt() ) );
414 }
415
416 const QDomNode editFormInitCodeNode = node.namedItem( u"editforminitcode"_s );
417 if ( !editFormInitCodeNode.isNull() )
418 {
419 setInitCode( editFormInitCodeNode.toElement().text() );
420 }
421
422 // Temporary < 2.12 b/w compatibility "dot" support patch
423 // \see: https://github.com/qgis/QGIS/pull/2498
424 // For b/w compatibility, check if there's a dot in the function name
425 // and if yes, transform it in an import statement for the module
426 // and set the PythonInitCodeSource to CodeSourceDialog
427 const int dotPos = d->mInitFunction.lastIndexOf( '.' );
428 if ( dotPos >= 0 ) // It's a module
429 {
431 setInitCode( u"from %1 import %2\n"_s.arg( d->mInitFunction.left( dotPos ), d->mInitFunction.mid( dotPos + 1 ) ) );
432 setInitFunction( d->mInitFunction.mid( dotPos + 1 ) );
433 }
434
435 const QDomNode editFormInitFilePathNode = node.namedItem( u"editforminitfilepath"_s );
436 if ( !editFormInitFilePathNode.isNull() && !editFormInitFilePathNode.toElement().text().isEmpty() )
437 {
438 setInitFilePath( context.pathResolver().readPath( editFormInitFilePathNode.toElement().text() ) );
439 }
440
441 const QDomNode fFSuppNode = node.namedItem( u"featformsuppress"_s );
442 if ( fFSuppNode.isNull() )
443 {
445 }
446 else
447 {
448 const QDomElement e = fFSuppNode.toElement();
449 d->mSuppressForm = static_cast< Qgis::AttributeFormSuppression >( e.text().toInt() );
450 }
451
452 // tab display
453 const QDomNode editorLayoutNode = node.namedItem( u"editorlayout"_s );
454 if ( editorLayoutNode.isNull() )
455 {
457 }
458 else
459 {
460 if ( editorLayoutNode.toElement().text() == "uifilelayout"_L1 )
461 {
462 d->mEditorLayout = Qgis::AttributeFormLayout::UiFile;
463 }
464 else if ( editorLayoutNode.toElement().text() == "tablayout"_L1 )
465 {
467 }
468 else
469 {
471 }
472 }
473
474 d->mFieldEditables.clear();
475 const QDomNodeList editableNodeList = node.namedItem( u"editable"_s ).toElement().childNodes();
476 for ( int i = 0; i < editableNodeList.size(); ++i )
477 {
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() ) );
480 }
481
482 d->mLabelOnTop.clear();
483 const QDomNodeList labelOnTopNodeList = node.namedItem( u"labelOnTop"_s ).toElement().childNodes();
484 for ( int i = 0; i < labelOnTopNodeList.size(); ++i )
485 {
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() ) );
488 }
489
490 d->mReuseLastValuePolicy.clear();
491 // Compatibility with QGIS projects saved prior to 4.0
492 const QDomNodeList reuseLastValueNodeList = node.namedItem( u"reuseLastValue"_s ).toElement().childNodes();
493 for ( int i = 0; i < reuseLastValueNodeList.size(); ++i )
494 {
495 const QDomElement reuseLastValueElement = reuseLastValueNodeList.at( i ).toElement();
496 d->mReuseLastValuePolicy
497 .insert( reuseLastValueElement.attribute( u"name"_s ), static_cast< bool >( reuseLastValueElement.attribute( u"reuseLastValue"_s ).toInt() ) ? Qgis::AttributeFormReuseLastValuePolicy::AllowedDefaultOn : Qgis::AttributeFormReuseLastValuePolicy::NotAllowed );
498 }
499 const QDomNodeList reuseLastValuePolicyNodeList = node.namedItem( u"reuseLastValuePolicy"_s ).toElement().childNodes();
500 for ( int i = 0; i < reuseLastValuePolicyNodeList.size(); ++i )
501 {
502 const QDomElement reuseLastValuePolicyElement = reuseLastValuePolicyNodeList.at( i ).toElement();
503 d->mReuseLastValuePolicy
504 .insert( reuseLastValuePolicyElement.attribute( u"name"_s ), qgsEnumKeyToValue( reuseLastValuePolicyElement.attribute( u"reuseLastValuePolicy"_s ), Qgis::AttributeFormReuseLastValuePolicy::NotAllowed ) );
505 }
506
507 // Read data defined field properties
508 const QDomNodeList fieldDDPropertiesNodeList = node.namedItem( u"dataDefinedFieldProperties"_s ).toElement().childNodes();
509 for ( int i = 0; i < fieldDDPropertiesNodeList.size(); ++i )
510 {
511 const QDomElement DDElement = fieldDDPropertiesNodeList.at( i ).toElement();
512 QgsPropertyCollection collection;
513 collection.readXml( DDElement, propertyDefinitions() );
514 d->mDataDefinedFieldProperties.insert( DDElement.attribute( u"name"_s ), collection );
515 }
516
517 const QDomNodeList widgetsNodeList = node.namedItem( u"widgets"_s ).toElement().childNodes();
518
519 for ( int i = 0; i < widgetsNodeList.size(); ++i )
520 {
521 const QDomElement widgetElement = widgetsNodeList.at( i ).toElement();
522 const QVariant config = QgsXmlUtils::readVariant( widgetElement.firstChildElement( u"config"_s ) );
523
524 d->mWidgetConfigs[widgetElement.attribute( u"name"_s )] = config.toMap();
525 }
526
527 // tabs and groups display info
528 const QDomNode attributeEditorFormNode = node.namedItem( u"attributeEditorForm"_s );
529 if ( !attributeEditorFormNode.isNull() )
530 {
531 const QDomNodeList attributeEditorFormNodeList = attributeEditorFormNode.toElement().childNodes();
532
533 if ( attributeEditorFormNodeList.size() )
534 {
535 d->mConfiguredRootContainer = true;
536 clearTabs();
537
538 for ( int i = 0; i < attributeEditorFormNodeList.size(); i++ )
539 {
540 QDomElement elem = attributeEditorFormNodeList.at( i ).toElement();
541
542 fixLegacyConfig( elem );
543
544 const QString layerId = node.namedItem( u"id"_s ).toElement().text();
545 QgsAttributeEditorElement *attributeEditorWidget = QgsAttributeEditorElement::create( elem, layerId, d->mFields, context, nullptr );
546 if ( attributeEditorWidget )
547 addTab( attributeEditorWidget );
548 }
549
550 onRelationsLoaded();
551 }
552 }
553}
554
555void QgsEditFormConfig::fixLegacyConfig( QDomElement &el ) const
556{
557 // recursive method to move widget config into attribute element config
558
559 if ( el.tagName() == "attributeEditorRelation"_L1 )
560 {
561 if ( !el.hasAttribute( u"forceSuppressFormPopup"_s ) )
562 {
563 // pre QGIS 3.16 compatibility - the widgets section is read before
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 );
566 }
567 if ( !el.hasAttribute( u"nmRelationId"_s ) )
568 {
569 // pre QGIS 3.16 compatibility - the widgets section is read before
570 el.setAttribute( u"nmRelationId"_s, widgetConfig( el.attribute( u"relation"_s ) ).value( u"nm-rel"_s ).toString() );
571 }
572 }
573
574 const QDomNodeList children = el.childNodes();
575 for ( int i = 0; i < children.size(); i++ )
576 {
577 QDomElement child = children.at( i ).toElement();
578 fixLegacyConfig( child );
579 el.replaceChild( child, children.at( i ) );
580 }
581}
582
583void QgsEditFormConfig::writeXml( QDomNode &node, const QgsReadWriteContext &context ) const
584{
585 QDomDocument doc( node.ownerDocument() );
586
587 QDomElement efField = doc.createElement( u"editform"_s );
588 efField.setAttribute( u"tolerant"_s, u"1"_s );
589 const QDomText efText = doc.createTextNode( context.pathResolver().writePath( uiForm() ) );
590 efField.appendChild( efText );
591 node.appendChild( efField );
592
593 QDomElement efiField = doc.createElement( u"editforminit"_s );
594 if ( !initFunction().isEmpty() )
595 efiField.appendChild( doc.createTextNode( initFunction() ) );
596 node.appendChild( efiField );
597
598 QDomElement eficsField = doc.createElement( u"editforminitcodesource"_s );
599 eficsField.appendChild( doc.createTextNode( QString::number( static_cast< int >( initCodeSource() ) ) ) );
600 node.appendChild( eficsField );
601
602 QDomElement efifpField = doc.createElement( u"editforminitfilepath"_s );
603 efifpField.appendChild( doc.createTextNode( context.pathResolver().writePath( initFilePath() ) ) );
604 node.appendChild( efifpField );
605
606 QDomElement eficField = doc.createElement( u"editforminitcode"_s );
607 eficField.appendChild( doc.createCDATASection( initCode() ) );
608 node.appendChild( eficField );
609
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 );
614
615 // tab display
616 QDomElement editorLayoutElem = doc.createElement( u"editorlayout"_s );
617 switch ( layout() )
618 {
620 editorLayoutElem.appendChild( doc.createTextNode( u"uifilelayout"_s ) );
621 break;
622
624 editorLayoutElem.appendChild( doc.createTextNode( u"tablayout"_s ) );
625 break;
626
628 default:
629 editorLayoutElem.appendChild( doc.createTextNode( u"generatedlayout"_s ) );
630 break;
631 }
632
633 node.appendChild( editorLayoutElem );
634
635 // tabs and groups of edit form
636 if ( !tabs().empty() && d->mConfiguredRootContainer )
637 {
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() )
642 {
643 tabsElem.appendChild( elemList.at( 0 ) );
644 }
645 node.appendChild( tabsElem );
646 }
647
648 QDomElement editableElem = doc.createElement( u"editable"_s );
649 for ( auto editIt = d->mFieldEditables.constBegin(); editIt != d->mFieldEditables.constEnd(); ++editIt )
650 {
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 );
655 }
656 node.appendChild( editableElem );
657
658 QDomElement labelOnTopElem = doc.createElement( u"labelOnTop"_s );
659 for ( auto labelOnTopIt = d->mLabelOnTop.constBegin(); labelOnTopIt != d->mLabelOnTop.constEnd(); ++labelOnTopIt )
660 {
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 );
665 }
666 node.appendChild( labelOnTopElem );
667
668 QDomElement reuseLastValuePolicyElem = doc.createElement( u"reuseLastValuePolicy"_s );
669 for ( auto reuseLastValuePolicyIt = d->mReuseLastValuePolicy.constBegin(); reuseLastValuePolicyIt != d->mReuseLastValuePolicy.constEnd(); ++reuseLastValuePolicyIt )
670 {
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 );
675 }
676 node.appendChild( reuseLastValuePolicyElem );
677
678 // Store data defined field properties
679 QDomElement ddFieldPropsElement = doc.createElement( u"dataDefinedFieldProperties"_s );
680 for ( auto it = d->mDataDefinedFieldProperties.constBegin(); it != d->mDataDefinedFieldProperties.constEnd(); ++it )
681 {
682 QDomElement ddPropsElement = doc.createElement( u"field"_s );
683 ddPropsElement.setAttribute( u"name"_s, it.key() );
684 it.value().writeXml( ddPropsElement, propertyDefinitions() );
685 ddFieldPropsElement.appendChild( ddPropsElement );
686 }
687 node.appendChild( ddFieldPropsElement );
688
689 QDomElement widgetsElem = doc.createElement( u"widgets"_s );
690
691 QMap<QString, QVariantMap >::ConstIterator configIt( d->mWidgetConfigs.constBegin() );
692
693 while ( configIt != d->mWidgetConfigs.constEnd() )
694 {
695 QDomElement widgetElem = doc.createElement( u"widget"_s );
696 widgetElem.setAttribute( u"name"_s, configIt.key() );
697 // widgetElem.setAttribute( "notNull", );
698
699 QDomElement configElem = QgsXmlUtils::writeVariant( configIt.value(), doc );
700 configElem.setTagName( u"config"_s );
701 widgetElem.appendChild( configElem );
702 widgetsElem.appendChild( widgetElem );
703 ++configIt;
704 }
705
706 node.appendChild( widgetsElem );
707}
708
710{
711 return QgsAttributeEditorElement::create( elem, layerId, d->mFields, context, parent );
712}
AttributeFormReuseLastValuePolicy
Attribute form policy for reusing last entered values.
Definition qgis.h:5885
@ AllowedDefaultOn
Reuse of last values allowed and enabled by default.
Definition qgis.h:5887
@ NotAllowed
Reuse of last values not allowed.
Definition qgis.h:5886
AttributeFormSuppression
Available form types for layout of the attribute form editor.
Definition qgis.h:5856
@ Default
Use the application-wide setting.
Definition qgis.h:5857
AttributeFormPythonInitCodeSource
The Python init code source for attribute forms.
Definition qgis.h:5871
@ Dialog
Use the Python code provided in the dialog.
Definition qgis.h:5874
AttributeFormLayout
Available form types for layout of the attribute form editor.
Definition qgis.h:5841
@ DragAndDrop
"Drag and drop" layout. Needs to be configured.
Definition qgis.h:5843
@ AutoGenerated
Autogenerate a simple tabular layout for the form.
Definition qgis.h:5842
@ UiFile
Load a .ui file for the layout. Needs to be configured.
Definition qgis.h:5844
@ Immediate
Action will start immediately.
Definition qgis.h:1171
@ Expression
Field is calculated from an expression.
Definition qgis.h:1788
@ Join
Field originates from a joined layer.
Definition qgis.h:1786
@ Container
A container.
Definition qgis.h:5808
@ Relation
A relation.
Definition qgis.h:5810
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.
QgsAttributeEditorContainer * invisibleRootContainer()
Gets the invisible root container for the drag and drop designer form (EditorLayout::TabLayout).
Q_DECL_DEPRECATED QgsAttributeEditorElement * attributeEditorElementFromDomElement(QDomElement &elem, QgsAttributeEditorElement *parent, const QString &layerId=QString(), const QgsReadWriteContext &context=QgsReadWriteContext())
Deserialize drag and drop designer elements.
Qgis::AttributeFormPythonInitCodeSource initCodeSource() const
Returns Python code source for edit form initialization (if it shall be loaded from a file,...
Q_DECL_DEPRECATED bool reuseLastValue(int index) const
If this returns true, the widget at the given index will reuse the last value within a QGIS session w...
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 ...
QString initCode() const
Gets Python code for edit form initialization.
static const QgsPropertiesDefinition & propertyDefinitions()
Returns data defined property definitions.
void readXml(const QDomNode &node, QgsReadWriteContext &context)
Read XML information Deserialize on project load.
void setInitFunction(const QString &function)
Set Python function for edit form initialization.
QVariantMap widgetConfig(const QString &widgetName) const
Gets the configuration for the editor widget with the given name.
void addTab(QgsAttributeEditorElement *data)
Adds a new element to the invisible root container in the layout.
QString initFilePath() const
Gets Python external file path for edit form initialization.
void setReadOnly(int idx, bool readOnly=true)
If set to false, the widget at the given index will be read-only.
QgsPropertyCollection dataDefinedFieldProperties(const QString &fieldName) const
Returns data defined properties for fieldName.
bool operator==(const QgsEditFormConfig &o) const
QgsEditFormConfig(const QgsEditFormConfig &o)
void setSuppress(Qgis::AttributeFormSuppression s)
Sets type of feature form pop-up suppression after feature creation (overrides app setting).
bool setWidgetConfig(const QString &widgetName, const QVariantMap &config)
Set the editor widget config for a widget which is not for a simple field.
void setLayout(Qgis::AttributeFormLayout editorLayout)
Sets the active layout style for the attribute editor for this layer.
void clearTabs()
Clears all the tabs for the attribute editor form with EditorLayout::TabLayout.
bool labelOnTop(int idx) const
If this returns true, the widget at the given index will receive its label on the previous line while...
Qgis::AttributeFormSuppression suppress() const
Type of feature form pop-up suppression after feature creation (overrides app setting).
QString uiForm() const
Returns the path or URL to the .ui form.
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...
Qgis::AttributeFormReuseLastValuePolicy reuseLastValuePolicy(int index) const
Returns the reuse of last value policy for an attribute index.
void setInitCodeSource(Qgis::AttributeFormPythonInitCodeSource initCodeSource)
Sets if Python code shall be used for edit form initialization and its origin.
void setDataDefinedFieldProperties(const QString &fieldName, const QgsPropertyCollection &properties)
Set data defined properties for fieldName to properties.
void writeXml(QDomNode &node, const QgsReadWriteContext &context) const
Write XML information Serialize on project save.
QString initFunction() const
Gets Python function for edit form initialization.
QgsEditFormConfig()
Create a new edit form config.
QList< QgsAttributeEditorElement * > tabs() const
Returns a list of tabs for EditorLayout::TabLayout obtained from the invisible root container.
Q_DECL_DEPRECATED void setReuseLastValue(int index, bool reuse)
Sets whether the widget at the given index will reuse the last value within a QGIS session when creat...
void setUiForm(const QString &ui)
Set path to the .ui form.
QgsEditFormConfig & operator=(const QgsEditFormConfig &o)
void setInitFilePath(const QString &filePath)
Set Python external file path for edit form initialization.
void setInitCode(const QString &code)
Set Python code for edit form initialization.
Qgis::AttributeFormLayout layout() const
Gets the active layout style for the attribute editor for this layer.
void setReuseLastValuePolicy(int index, Qgis::AttributeFormReuseLastValuePolicy policy)
Sets the reuse of last value policy for an attribute index.
bool removeWidgetConfig(const QString &widgetName)
Remove the configuration for the editor widget with the given name.
Container of fields for a vector layer.
Definition qgsfields.h:46
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.
QString id
Definition qgsrelation.h:45
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.
Definition qgis.h:7176
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:7157
#define QgsDebugError(str)
Definition qgslogger.h:59
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.