QGIS API Documentation 3.99.0-Master (8e76e220402)
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}
43
44void QgsEditFormConfig::setDataDefinedFieldProperties( const QString &fieldName, const QgsPropertyCollection &properties )
45{
46 d.detach();
47 d->mDataDefinedFieldProperties[ fieldName ] = properties;
48}
49
51{
52 return d->mDataDefinedFieldProperties.value( fieldName );
53}
54
56{
57 return QgsEditFormConfigPrivate::propertyDefinitions();
58}
59
60QVariantMap QgsEditFormConfig::widgetConfig( const QString &widgetName ) const
61{
62 const int fieldIndex = d->mFields.indexOf( widgetName );
63 if ( fieldIndex != -1 )
64 return d->mFields.at( fieldIndex ).editorWidgetSetup().config();
65 else
66 return d->mWidgetConfigs.value( widgetName );
67}
68
69void QgsEditFormConfig::setFields( const QgsFields &fields )
70{
71 d.detach();
72 d->mFields = fields;
73
74 if ( !d->mConfiguredRootContainer )
75 {
76 d->mInvisibleRootContainer->clear();
77 for ( int i = 0; i < d->mFields.size(); ++i )
78 {
79 QgsAttributeEditorField *field = new QgsAttributeEditorField( d->mFields.at( i ).name(), i, d->mInvisibleRootContainer );
80 d->mInvisibleRootContainer->addChildElement( field );
81 }
82 }
83}
84
85void QgsEditFormConfig::onRelationsLoaded()
86{
87 const QList<QgsAttributeEditorElement *> relations = d->mInvisibleRootContainer->findElements( Qgis::AttributeEditorType::Relation );
88
89 for ( QgsAttributeEditorElement *relElem : relations )
90 {
91 QgsAttributeEditorRelation *rel = dynamic_cast< QgsAttributeEditorRelation * >( relElem );
92 if ( !rel )
93 continue;
94
95 rel->init( QgsProject::instance()->relationManager() ); // skip-keyword-check
96 }
97}
98
99bool QgsEditFormConfig::legacyUpdateRelationWidgetInTabs( QgsAttributeEditorContainer *container, const QString &widgetName, const QVariantMap &config )
100{
101 const QList<QgsAttributeEditorElement *> children = container->children();
102 for ( QgsAttributeEditorElement *child : children )
103 {
104 if ( child->type() == Qgis::AttributeEditorType::Container )
105 {
106 QgsAttributeEditorContainer *container = dynamic_cast<QgsAttributeEditorContainer *>( child );
107 if ( legacyUpdateRelationWidgetInTabs( container, widgetName, config ) )
108 {
109 //return when a relation has been set in a child or child child...
110 return true;
111 }
112 }
113 else if ( child->type() == Qgis::AttributeEditorType::Relation )
114 {
115 QgsAttributeEditorRelation *relation = dynamic_cast< QgsAttributeEditorRelation * >( child );
116 if ( relation )
117 {
118 if ( relation->relation().id() == widgetName )
119 {
120 if ( config.contains( u"nm-rel"_s ) )
121 {
122 relation->setNmRelationId( config[u"nm-rel"_s] );
123 }
124 if ( config.contains( u"force-suppress-popup"_s ) )
125 {
126 relation->setForceSuppressFormPopup( config[u"force-suppress-popup"_s].toBool() );
127 }
128 return true;
129 }
130 }
131 }
132 }
133 return false;
134}
135
136bool QgsEditFormConfig::setWidgetConfig( const QString &widgetName, const QVariantMap &config )
137{
138 if ( d->mFields.indexOf( widgetName ) != -1 )
139 {
140 QgsDebugError( u"Trying to set a widget config for a field on QgsEditFormConfig. Use layer->setEditorWidgetSetup() instead."_s );
141 return false;
142 }
143
144 //for legacy use it writes the relation editor configuration into the first instance of the widget
145 if ( config.contains( u"force-suppress-popup"_s ) || config.contains( u"nm-rel"_s ) )
146 {
147 QgsMessageLog::logMessage( 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.arg( widgetName ) );
148 legacyUpdateRelationWidgetInTabs( d->mInvisibleRootContainer, widgetName, config );
149 }
150
151 d.detach();
152 d->mWidgetConfigs[widgetName] = config;
153 return true;
154}
155
156bool QgsEditFormConfig::removeWidgetConfig( const QString &widgetName )
157{
158 d.detach();
159 return d->mWidgetConfigs.remove( widgetName ) != 0;
160}
161
163 : d( o.d )
164{
165}
166
169
171{
172 if ( &o == this )
173 return *this;
174
175 d = o.d;
176 return *this;
177}
178
180{
181 return d == o.d;
182}
183
185{
186 d.detach();
187 d->mInvisibleRootContainer->addChildElement( data );
188}
189
190QList<QgsAttributeEditorElement *> QgsEditFormConfig::tabs() const
191{
192 return d->mInvisibleRootContainer->children();
193}
194
196{
197 d.detach();
198 d->mInvisibleRootContainer->clear();
199}
200
202{
203 return d->mInvisibleRootContainer;
204}
205
207{
208 return d->mEditorLayout;
209}
210
212{
213 d.detach();
214 d->mEditorLayout = editorLayout;
215
216 if ( editorLayout == Qgis::AttributeFormLayout::DragAndDrop )
217 d->mConfiguredRootContainer = true;
218}
219
221{
222 return d->mUiFormPath;
223}
224
225void QgsEditFormConfig::setUiForm( const QString &ui )
226{
227 if ( !ui.isEmpty() && !QUrl::fromUserInput( ui ).isLocalFile() )
228 {
229 // any existing download will not be restarted!
231 }
232
233 if ( ui.isEmpty() )
234 {
236 }
237 else
238 {
240 }
241 d->mUiFormPath = ui;
242}
243
244bool QgsEditFormConfig::readOnly( int idx ) const
245{
246 if ( idx >= 0 && idx < d->mFields.count() )
247 {
248 if ( d->mFields.fieldOrigin( idx ) == Qgis::FieldOrigin::Join
249 || 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.insert( reuseLastValueElement.attribute( u"name"_s ), static_cast< bool >( reuseLastValueElement.attribute( u"reuseLastValue"_s ).toInt() ) ? Qgis::AttributeFormReuseLastValuePolicy::AllowedDefaultOn : Qgis::AttributeFormReuseLastValuePolicy::NotAllowed );
497 }
498 const QDomNodeList reuseLastValuePolicyNodeList = node.namedItem( u"reuseLastValuePolicy"_s ).toElement().childNodes();
499 for ( int i = 0; i < reuseLastValuePolicyNodeList.size(); ++i )
500 {
501 const QDomElement reuseLastValuePolicyElement = reuseLastValuePolicyNodeList.at( i ).toElement();
502 d->mReuseLastValuePolicy.insert( reuseLastValuePolicyElement.attribute( u"name"_s ), qgsEnumKeyToValue( reuseLastValuePolicyElement.attribute( u"reuseLastValuePolicy"_s ), Qgis::AttributeFormReuseLastValuePolicy::NotAllowed ) );
503 }
504
505 // Read data defined field properties
506 const QDomNodeList fieldDDPropertiesNodeList = node.namedItem( u"dataDefinedFieldProperties"_s ).toElement().childNodes();
507 for ( int i = 0; i < fieldDDPropertiesNodeList.size(); ++i )
508 {
509 const QDomElement DDElement = fieldDDPropertiesNodeList.at( i ).toElement();
510 QgsPropertyCollection collection;
511 collection.readXml( DDElement, propertyDefinitions() );
512 d->mDataDefinedFieldProperties.insert( DDElement.attribute( u"name"_s ), collection );
513 }
514
515 const QDomNodeList widgetsNodeList = node.namedItem( u"widgets"_s ).toElement().childNodes();
516
517 for ( int i = 0; i < widgetsNodeList.size(); ++i )
518 {
519 const QDomElement widgetElement = widgetsNodeList.at( i ).toElement();
520 const QVariant config = QgsXmlUtils::readVariant( widgetElement.firstChildElement( u"config"_s ) );
521
522 d->mWidgetConfigs[widgetElement.attribute( u"name"_s )] = config.toMap();
523 }
524
525 // tabs and groups display info
526 const QDomNode attributeEditorFormNode = node.namedItem( u"attributeEditorForm"_s );
527 if ( !attributeEditorFormNode.isNull() )
528 {
529 const QDomNodeList attributeEditorFormNodeList = attributeEditorFormNode.toElement().childNodes();
530
531 if ( attributeEditorFormNodeList.size() )
532 {
533 d->mConfiguredRootContainer = true;
534 clearTabs();
535
536 for ( int i = 0; i < attributeEditorFormNodeList.size(); i++ )
537 {
538 QDomElement elem = attributeEditorFormNodeList.at( i ).toElement();
539
540 fixLegacyConfig( elem );
541
542 const QString layerId = node.namedItem( u"id"_s ).toElement().text();
543 QgsAttributeEditorElement *attributeEditorWidget = QgsAttributeEditorElement::create( elem, layerId, d->mFields, context, nullptr );
544 if ( attributeEditorWidget )
545 addTab( attributeEditorWidget );
546 }
547
548 onRelationsLoaded();
549 }
550 }
551}
552
553void QgsEditFormConfig::fixLegacyConfig( QDomElement &el ) const
554{
555 // recursive method to move widget config into attribute element config
556
557 if ( el.tagName() == "attributeEditorRelation"_L1 )
558 {
559 if ( !el.hasAttribute( u"forceSuppressFormPopup"_s ) )
560 {
561 // pre QGIS 3.16 compatibility - the widgets section is read before
562 const bool forceSuppress = widgetConfig( el.attribute( u"relation"_s ) ).value( u"force-suppress-popup"_s, false ).toBool();
563 el.setAttribute( u"forceSuppressFormPopup"_s, forceSuppress ? 1 : 0 );
564 }
565 if ( !el.hasAttribute( u"nmRelationId"_s ) )
566 {
567 // pre QGIS 3.16 compatibility - the widgets section is read before
568 el.setAttribute( u"nmRelationId"_s, widgetConfig( el.attribute( u"relation"_s ) ).value( u"nm-rel"_s ).toString() );
569 }
570 }
571
572 const QDomNodeList children = el.childNodes();
573 for ( int i = 0; i < children.size(); i++ )
574 {
575 QDomElement child = children.at( i ).toElement();
576 fixLegacyConfig( child );
577 el.replaceChild( child, children.at( i ) );
578 }
579}
580
581void QgsEditFormConfig::writeXml( QDomNode &node, const QgsReadWriteContext &context ) const
582{
583 QDomDocument doc( node.ownerDocument() );
584
585 QDomElement efField = doc.createElement( u"editform"_s );
586 efField.setAttribute( u"tolerant"_s, u"1"_s );
587 const QDomText efText = doc.createTextNode( context.pathResolver().writePath( uiForm() ) );
588 efField.appendChild( efText );
589 node.appendChild( efField );
590
591 QDomElement efiField = doc.createElement( u"editforminit"_s );
592 if ( !initFunction().isEmpty() )
593 efiField.appendChild( doc.createTextNode( initFunction() ) );
594 node.appendChild( efiField );
595
596 QDomElement eficsField = doc.createElement( u"editforminitcodesource"_s );
597 eficsField.appendChild( doc.createTextNode( QString::number( static_cast< int >( initCodeSource() ) ) ) );
598 node.appendChild( eficsField );
599
600 QDomElement efifpField = doc.createElement( u"editforminitfilepath"_s );
601 efifpField.appendChild( doc.createTextNode( context.pathResolver().writePath( initFilePath() ) ) );
602 node.appendChild( efifpField );
603
604 QDomElement eficField = doc.createElement( u"editforminitcode"_s );
605 eficField.appendChild( doc.createCDATASection( initCode() ) );
606 node.appendChild( eficField );
607
608 QDomElement fFSuppElem = doc.createElement( u"featformsuppress"_s );
609 const QDomText fFSuppText = doc.createTextNode( QString::number( static_cast< int >( suppress() ) ) );
610 fFSuppElem.appendChild( fFSuppText );
611 node.appendChild( fFSuppElem );
612
613 // tab display
614 QDomElement editorLayoutElem = doc.createElement( u"editorlayout"_s );
615 switch ( layout() )
616 {
618 editorLayoutElem.appendChild( doc.createTextNode( u"uifilelayout"_s ) );
619 break;
620
622 editorLayoutElem.appendChild( doc.createTextNode( u"tablayout"_s ) );
623 break;
624
626 default:
627 editorLayoutElem.appendChild( doc.createTextNode( u"generatedlayout"_s ) );
628 break;
629 }
630
631 node.appendChild( editorLayoutElem );
632
633 // tabs and groups of edit form
634 if ( !tabs().empty() && d->mConfiguredRootContainer )
635 {
636 QDomElement tabsElem = doc.createElement( u"attributeEditorForm"_s );
637 const QDomElement rootElem = d->mInvisibleRootContainer->toDomElement( doc );
638 const QDomNodeList elemList = rootElem.childNodes();
639 while ( !elemList.isEmpty() )
640 {
641 tabsElem.appendChild( elemList.at( 0 ) );
642 }
643 node.appendChild( tabsElem );
644 }
645
646 QDomElement editableElem = doc.createElement( u"editable"_s );
647 for ( auto editIt = d->mFieldEditables.constBegin(); editIt != d->mFieldEditables.constEnd(); ++editIt )
648 {
649 QDomElement fieldElem = doc.createElement( u"field"_s );
650 fieldElem.setAttribute( u"name"_s, editIt.key() );
651 fieldElem.setAttribute( u"editable"_s, editIt.value() ? u"1"_s : u"0"_s );
652 editableElem.appendChild( fieldElem );
653 }
654 node.appendChild( editableElem );
655
656 QDomElement labelOnTopElem = doc.createElement( u"labelOnTop"_s );
657 for ( auto labelOnTopIt = d->mLabelOnTop.constBegin(); labelOnTopIt != d->mLabelOnTop.constEnd(); ++labelOnTopIt )
658 {
659 QDomElement fieldElem = doc.createElement( u"field"_s );
660 fieldElem.setAttribute( u"name"_s, labelOnTopIt.key() );
661 fieldElem.setAttribute( u"labelOnTop"_s, labelOnTopIt.value() ? u"1"_s : u"0"_s );
662 labelOnTopElem.appendChild( fieldElem );
663 }
664 node.appendChild( labelOnTopElem );
665
666 QDomElement reuseLastValuePolicyElem = doc.createElement( u"reuseLastValuePolicy"_s );
667 for ( auto reuseLastValuePolicyIt = d->mReuseLastValuePolicy.constBegin(); reuseLastValuePolicyIt != d->mReuseLastValuePolicy.constEnd(); ++reuseLastValuePolicyIt )
668 {
669 QDomElement fieldElem = doc.createElement( u"field"_s );
670 fieldElem.setAttribute( u"name"_s, reuseLastValuePolicyIt.key() );
671 fieldElem.setAttribute( u"reuseLastValuePolicy"_s, qgsEnumValueToKey( reuseLastValuePolicyIt.value() ) );
672 reuseLastValuePolicyElem.appendChild( fieldElem );
673 }
674 node.appendChild( reuseLastValuePolicyElem );
675
676 // Store data defined field properties
677 QDomElement ddFieldPropsElement = doc.createElement( u"dataDefinedFieldProperties"_s );
678 for ( auto it = d->mDataDefinedFieldProperties.constBegin(); it != d->mDataDefinedFieldProperties.constEnd(); ++it )
679 {
680 QDomElement ddPropsElement = doc.createElement( u"field"_s );
681 ddPropsElement.setAttribute( u"name"_s, it.key() );
682 it.value().writeXml( ddPropsElement, propertyDefinitions() );
683 ddFieldPropsElement.appendChild( ddPropsElement );
684 }
685 node.appendChild( ddFieldPropsElement );
686
687 QDomElement widgetsElem = doc.createElement( u"widgets"_s );
688
689 QMap<QString, QVariantMap >::ConstIterator configIt( d->mWidgetConfigs.constBegin() );
690
691 while ( configIt != d->mWidgetConfigs.constEnd() )
692 {
693 QDomElement widgetElem = doc.createElement( u"widget"_s );
694 widgetElem.setAttribute( u"name"_s, configIt.key() );
695 // widgetElem.setAttribute( "notNull", );
696
697 QDomElement configElem = QgsXmlUtils::writeVariant( configIt.value(), doc );
698 configElem.setTagName( u"config"_s );
699 widgetElem.appendChild( configElem );
700 widgetsElem.appendChild( widgetElem );
701 ++configIt;
702 }
703
704 node.appendChild( widgetsElem );
705}
706
708{
709 return QgsAttributeEditorElement::create( elem, layerId, d->mFields, context, parent );
710}
AttributeFormReuseLastValuePolicy
Attribute form policy for reusing last entered values.
Definition qgis.h:5830
@ AllowedDefaultOn
Reuse of last values allowed and enabled by default.
Definition qgis.h:5832
@ NotAllowed
Reuse of last values not allowed.
Definition qgis.h:5831
AttributeFormSuppression
Available form types for layout of the attribute form editor.
Definition qgis.h:5801
@ Default
Use the application-wide setting.
Definition qgis.h:5802
AttributeFormPythonInitCodeSource
The Python init code source for attribute forms.
Definition qgis.h:5816
@ Dialog
Use the Python code provided in the dialog.
Definition qgis.h:5819
AttributeFormLayout
Available form types for layout of the attribute form editor.
Definition qgis.h:5786
@ DragAndDrop
"Drag and drop" layout. Needs to be configured.
Definition qgis.h:5788
@ AutoGenerated
Autogenerate a simple tabular layout for the form.
Definition qgis.h:5787
@ UiFile
Load a .ui file for the layout. Needs to be configured.
Definition qgis.h:5789
@ Immediate
Action will start immediately.
Definition qgis.h:1164
@ Expression
Field is calculated from an expression.
Definition qgis.h:1767
@ Join
Field originates from a joined layer.
Definition qgis.h:1765
@ Container
A container.
Definition qgis.h:5753
@ Relation
A relation.
Definition qgis.h:5755
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())
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:7145
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:7126
#define QgsDebugError(str)
Definition qgslogger.h:59
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.