QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
Loading...
Searching...
No Matches
qgsattributesformproperties.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsattributesformproperties.cpp
3 ---------------------
4 begin : August 2017
5 copyright : (C) 2017 by David Signer
6 email : david 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
17
18#include "qgsactionmanager.h"
19#include "qgsaddtaborgroup.h"
20#include "qgsapplication.h"
21#include "qgsattributedialog.h"
23#include "qgsattributeformcontaineredit.h"
27#include "qgsattributetypedialog.h"
28#include "qgsattributewidgetedit.h"
29#include "qgscodeeditor.h"
32#include "qgsfieldcombobox.h"
33#include "qgsgui.h"
37#include "qgsvectorlayerutils.h"
38#include "qgsxmlutils.h"
39
40#include <QString>
41
42#include "moc_qgsattributesformproperties.cpp"
43
44using namespace Qt::StringLiterals;
45
46#ifdef ENABLE_MODELTEST
47#include "modeltest.h"
48#endif
49
51 = new QgsSettingsEntryBool( u"show-aliases"_s, sTreeAttributesForm, false, u"Whether to show aliases (true) or names (false) in both the Available Widgets and the Form Layout panels."_s );
52
54 : QWidget( parent )
55 , mLayer( layer )
56 , mSourceFieldsProperties( sourceFieldsProperties )
57{
58 if ( !layer )
59 return;
60
61 setupUi( this );
62
63 mEditorLayoutComboBox->addItem( tr( "Autogenerate" ), QVariant::fromValue( Qgis::AttributeFormLayout::AutoGenerated ) );
64 mEditorLayoutComboBox->addItem( tr( "Drag and Drop Designer" ), QVariant::fromValue( Qgis::AttributeFormLayout::DragAndDrop ) );
65 mEditorLayoutComboBox->addItem( tr( "Provide ui-file" ), QVariant::fromValue( Qgis::AttributeFormLayout::UiFile ) );
66 mShowAliasesButton->setChecked( settingShowAliases->value() );
67
68 // available widgets tree
69 QGridLayout *availableWidgetsWidgetLayout = new QGridLayout;
71 availableWidgetsWidgetLayout->addWidget( mAvailableWidgetsView );
72 availableWidgetsWidgetLayout->setContentsMargins( 0, 0, 0, 0 );
73 mAvailableWidgetsWidget->setLayout( availableWidgetsWidgetLayout );
74 mAvailableWidgetsView->setContextMenuPolicy( Qt::CustomContextMenu );
75
76 // we need a custom item delegate in order to draw indicators
77 mAvailableWidgetsView->setItemDelegate( new QgsAttributesFormTreeViewItemDelegate( mAvailableWidgetsView ) );
78 mAvailableWidgetsView->setStyle( new QgsAttributesFormTreeViewProxyStyle( mAvailableWidgetsView ) );
79
80 mAvailableWidgetsModel = new QgsAttributesAvailableWidgetsModel( mLayer, QgsProject().instance(), this );
81 mAvailableWidgetsProxyModel = new QgsAttributesFormProxyModel( this );
82 mAvailableWidgetsProxyModel->setAttributesFormSourceModel( mAvailableWidgetsModel );
83 mAvailableWidgetsProxyModel->setRecursiveFilteringEnabled( true );
84 mAvailableWidgetsView->setModel( mAvailableWidgetsProxyModel );
85
86 mConstraintIndicatorProviderAvailableWidgets = new QgsFieldConstraintIndicatorProvider( mAvailableWidgetsView ); // gets parented to the available widgets view
87 mDefaultValueIndicatorProviderAvailableWidgets = new QgsFieldDefaultValueIndicatorProvider( mAvailableWidgetsView ); // gets parented to the available widgets view
88
89#ifdef ENABLE_MODELTEST
90 new ModelTest( mAvailableWidgetsProxyModel, this );
91#endif
92
93 // form layout tree
94 QGridLayout *formLayoutWidgetLayout = new QGridLayout;
96 formLayoutWidgetLayout->addWidget( mFormLayoutView );
97 formLayoutWidgetLayout->setContentsMargins( 0, 0, 0, 0 );
98 mFormLayoutWidget->setLayout( formLayoutWidgetLayout );
99
100 // we need a custom item delegate in order to draw indicators
101 mFormLayoutView->setItemDelegate( new QgsAttributesFormTreeViewItemDelegate( mFormLayoutView ) );
102 mFormLayoutView->setStyle( new QgsAttributesFormTreeViewProxyStyle( mFormLayoutView ) );
103
104 mFormLayoutModel = new QgsAttributesFormLayoutModel( mLayer, QgsProject().instance(), this );
105 mFormLayoutProxyModel = new QgsAttributesFormProxyModel( this );
106 mFormLayoutProxyModel->setAttributesFormSourceModel( mFormLayoutModel );
107 mFormLayoutProxyModel->setRecursiveFilteringEnabled( true );
108 mFormLayoutView->setModel( mFormLayoutProxyModel );
109
110 mConstraintIndicatorProviderFormLayout = new QgsFieldConstraintIndicatorProvider( mFormLayoutView ); // gets parented to the form layout view
111 mDefaultValueIndicatorProviderFormLayout = new QgsFieldDefaultValueIndicatorProvider( mFormLayoutView ); // gets parented to the form layout view
112
113#ifdef ENABLE_MODELTEST
114 new ModelTest( mFormLayoutProxyModel, this );
115#endif
116
117 connect( mAvailableWidgetsView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsAttributesFormProperties::onAttributeSelectionChanged );
118 connect( mFormLayoutView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsAttributesFormProperties::onFormLayoutSelectionChanged );
119
120 connect( mAvailableWidgetsView, &QWidget::customContextMenuRequested, this, &QgsAttributesFormProperties::onContextMenuRequested );
121
122 connect( mAddContainerButton, &QAbstractButton::clicked, this, &QgsAttributesFormProperties::addContainer );
123 connect( mRemoveLayoutItemButton, &QAbstractButton::clicked, this, &QgsAttributesFormProperties::removeTabOrGroupButton );
124 connect( mInvertSelectionButton, &QAbstractButton::clicked, this, &QgsAttributesFormProperties::onInvertSelectionButtonClicked );
125 connect( mShowAliasesButton, &QAbstractButton::toggled, this, &QgsAttributesFormProperties::toggleShowAliases );
126 connect( mEditorLayoutComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsAttributesFormProperties::mEditorLayoutComboBox_currentIndexChanged );
127 connect( pbnSelectEditForm, &QToolButton::clicked, this, &QgsAttributesFormProperties::pbnSelectEditForm_clicked );
128 connect( mTbInitCode, &QPushButton::clicked, this, &QgsAttributesFormProperties::mTbInitCode_clicked );
129
130 connect( mSearchLineEdit, &QgsFilterLineEdit::textChanged, this, &QgsAttributesFormProperties::updateFilteredItems );
131
132 connect( mLayer, &QgsVectorLayer::updatedFields, this, [this] {
133 if ( !mBlockUpdates )
134 updatedFields();
135 } );
136
137 // Context menu and children actions
138 mAvailableWidgetsContextMenu = new QMenu( this );
139 mActionCopyWidgetConfiguration = new QAction( tr( "Copy widget configuration" ), this );
140 mActionPasteWidgetConfiguration = new QAction( tr( "Paste widget configuration" ), this );
141
142 connect( mActionCopyWidgetConfiguration, &QAction::triggered, this, &QgsAttributesFormProperties::copyWidgetConfiguration );
143 connect( mActionPasteWidgetConfiguration, &QAction::triggered, this, &QgsAttributesFormProperties::pasteWidgetConfiguration );
144
145 mAvailableWidgetsContextMenu->addAction( mActionCopyWidgetConfiguration );
146 mAvailableWidgetsContextMenu->addAction( mActionPasteWidgetConfiguration );
147
148 mMessageBar = new QgsMessageBar();
149 mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
150 gridLayout->addWidget( mMessageBar, 0, 0 );
151
152 // Assign initial size to splitter widgets. By doing so, we can
153 // show an eventual horizontal scrollbar in the right-hand side panel
154 splitter->setSizes( { widget->minimumSizeHint().width(), 600 } );
155
156 if ( mSourceFieldsProperties )
157 {
158 connect( mFormPreviewButton, &QAbstractButton::clicked, this, &QgsAttributesFormProperties::previewForm );
159 }
160 else
161 {
162 mFormPreviewButton->setVisible( false );
163 }
164}
165
175
177{
178 mAvailableWidgetsView->setSortingEnabled( false );
179 mAvailableWidgetsView->setSelectionBehavior( QAbstractItemView::SelectRows );
180 mAvailableWidgetsView->setSelectionMode( QAbstractItemView::SelectionMode::ExtendedSelection );
181 mAvailableWidgetsView->setAcceptDrops( false );
182 mAvailableWidgetsView->setDragDropMode( QAbstractItemView::DragDropMode::DragOnly );
183
184 mAvailableWidgetsModel->populate();
185 mAvailableWidgetsModel->setShowAliases( settingShowAliases->value() );
186 mAvailableWidgetsView->expandAll();
187}
188
190{
191 // tabs and groups info
192 mFormLayoutView->setSortingEnabled( false );
193 mFormLayoutView->setSelectionBehavior( QAbstractItemView::SelectRows );
194 mFormLayoutView->setSelectionMode( QAbstractItemView::SelectionMode::ExtendedSelection );
195 mFormLayoutView->setAcceptDrops( true );
196 mFormLayoutView->setDragDropMode( QAbstractItemView::DragDropMode::DragDrop );
197 mFormLayoutView->setDefaultDropAction( Qt::MoveAction );
198
199 mFormLayoutView->selectionModel()->clear();
200 mFormLayoutModel->populate();
201 mFormLayoutModel->setShowAliases( settingShowAliases->value() );
202 mFormLayoutView->expandAll();
203}
204
205
207{
209 {
210 mFormSuppressCmbBx->addItem( tr( "Hide Form on Add Feature (global settings)" ), QVariant::fromValue( Qgis::AttributeFormSuppression::Default ) );
211 }
212 else
213 {
214 mFormSuppressCmbBx->addItem( tr( "Show Form on Add Feature (global settings)" ), QVariant::fromValue( Qgis::AttributeFormSuppression::Default ) );
215 }
216 mFormSuppressCmbBx->addItem( tr( "Hide Form on Add Feature" ), QVariant::fromValue( Qgis::AttributeFormSuppression::On ) );
217 mFormSuppressCmbBx->addItem( tr( "Show Form on Add Feature" ), QVariant::fromValue( Qgis::AttributeFormSuppression::Off ) );
218
219 mFormSuppressCmbBx->setCurrentIndex( mFormSuppressCmbBx->findData( QVariant::fromValue( mLayer->editFormConfig().suppress() ) ) );
220}
221
222void QgsAttributesFormProperties::initAvailableWidgetsActions( const QList< QgsAction > actions )
223{
224 mAvailableWidgetsModel->populateLayerActions( actions );
225}
226
233
235{
236 mEditorLayoutComboBox->setCurrentIndex( mEditorLayoutComboBox->findData( QVariant::fromValue( mLayer->editFormConfig().layout() ) ) );
237
238 mEditorLayoutComboBox_currentIndexChanged( mEditorLayoutComboBox->currentIndex() );
239
240 const QgsEditFormConfig cfg = mLayer->editFormConfig();
241 mEditFormLineEdit->setText( cfg.uiForm() );
242}
243
245{
246 const QgsEditFormConfig cfg = mLayer->editFormConfig();
247
248 mInitCodeSource = cfg.initCodeSource();
249 mInitFunction = cfg.initFunction();
250 mInitFilePath = cfg.initFilePath();
251 mInitCode = cfg.initCode();
252
253 if ( mInitCode.isEmpty() )
254 {
255 mInitCode.append( tr(
256 "# -*- coding: utf-8 -*-\n\"\"\"\n"
257 "QGIS forms can have a Python function that is called when the form is\n"
258 "opened.\n"
259 "\n"
260 "Use this function to add extra logic to your forms.\n"
261 "\n"
262 "Enter the name of the function in the \"Python Init function\"\n"
263 "field.\n"
264 "An example follows:\n"
265 "\"\"\"\n"
266 "from qgis.PyQt.QtWidgets import QWidget\n\n"
267 "def my_form_open(dialog, layer, feature):\n"
268 " geom = feature.geometry()\n"
269 " control = dialog.findChild(QWidget, \"MyLineEdit\")\n"
270 ) );
271 }
272}
273
274void QgsAttributesFormProperties::loadAttributeTypeDialog()
275{
276 if ( mAvailableWidgetsView->selectionModel()->selectedRows( 0 ).count() != 1 )
277 return;
278
279 const QModelIndex index = mAvailableWidgetsView->firstSelectedIndex();
280
282 const QString fieldName = mAvailableWidgetsModel->data( index, QgsAttributesFormModel::ItemNameRole ).toString();
283 const int fieldIndex = mLayer->fields().indexOf( fieldName );
284
285 if ( fieldIndex < 0 )
286 return;
287
288 mAttributeTypeDialog = new QgsAttributeTypeDialog( mLayer, fieldIndex, mAttributeTypeFrame );
289
290 loadAttributeTypeDialogFromConfiguration( cfg );
291
292 mAttributeTypeDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
293 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
294
295 mAttributeTypeFrame->layout()->addWidget( mAttributeTypeDialog );
296}
297
298void QgsAttributesFormProperties::loadAttributeTypeDialogFromConfiguration( const QgsAttributesFormData::FieldConfig &config )
299{
300 const QgsFieldConstraints constraints = config.mFieldConstraints;
301
302 mAttributeTypeDialog->setAlias( config.mAlias );
303 mAttributeTypeDialog->setDataDefinedProperties( config.mDataDefinedProperties );
304 mAttributeTypeDialog->setComment( config.mComment );
305 mAttributeTypeDialog->setFieldEditable( config.mEditable );
306 mAttributeTypeDialog->setLabelOnTop( config.mLabelOnTop );
307 mAttributeTypeDialog->setReuseLastValuePolicy( config.mReuseLastValuePolicy );
312 mAttributeTypeDialog->setSplitPolicy( config.mSplitPolicy );
313 mAttributeTypeDialog->setDuplicatePolicy( config.mDuplicatePolicy );
314 mAttributeTypeDialog->setMergePolicy( config.mMergePolicy );
315 mAttributeTypeDialog->setDefaultValueExpression( config.mDefaultValueExpression );
316 mAttributeTypeDialog->setApplyDefaultValueOnUpdate( config.mApplyDefaultValueOnUpdate );
317
320 providerConstraints |= QgsFieldConstraints::ConstraintNotNull;
322 providerConstraints |= QgsFieldConstraints::ConstraintUnique;
324 providerConstraints |= QgsFieldConstraints::ConstraintExpression;
325 mAttributeTypeDialog->setProviderConstraints( providerConstraints );
326
327 mAttributeTypeDialog->setConstraintExpression( constraints.constraintExpression() );
328 mAttributeTypeDialog->setConstraintExpressionDescription( constraints.constraintDescription() );
330
331 // Make sure the widget is refreshed, even if
332 // the new widget type matches the current one
333 mAttributeTypeDialog->setEditorWidgetConfig( config.mEditorWidgetConfig );
334 mAttributeTypeDialog->setEditorWidgetType( config.mEditorWidgetType, true );
335}
336
337void QgsAttributesFormProperties::storeAttributeTypeDialog()
338{
340 return;
341
342 if ( mAttributeTypeDialog->fieldIdx() < 0 || mAttributeTypeDialog->fieldIdx() >= mLayer->fields().count() )
343 return;
344
345 QgsAttributesFormData::FieldConfig cfg;
346
347 cfg.mComment = mLayer->fields().at( mAttributeTypeDialog->fieldIdx() ).comment();
348 cfg.mEditable = mAttributeTypeDialog->fieldEditable();
349 cfg.mLabelOnTop = mAttributeTypeDialog->labelOnTop();
350 cfg.mReuseLastValuePolicy = mAttributeTypeDialog->reuseLastValuePolicy();
351 cfg.mAlias = mAttributeTypeDialog->alias();
352 cfg.mDataDefinedProperties = mAttributeTypeDialog->dataDefinedProperties();
353
354 QgsFieldConstraints constraints;
355 if ( mAttributeTypeDialog->notNull() )
356 {
358 }
359 else if ( mAttributeTypeDialog->notNullFromProvider() )
360 {
362 }
363
364 if ( mAttributeTypeDialog->unique() )
365 {
367 }
368 else if ( mAttributeTypeDialog->uniqueFromProvider() )
369 {
371 }
372
373 if ( !mAttributeTypeDialog->constraintExpression().isEmpty() )
374 {
376 }
377
378 constraints.setConstraintExpression( mAttributeTypeDialog->constraintExpression(), mAttributeTypeDialog->constraintExpressionDescription() );
379
383
384 // The call to mLayer->setDefaultValueDefinition will possibly emit updatedFields
385 // which will set mAttributeTypeDialog to nullptr so we need to store any value before calling it
386 cfg.mFieldConstraints = constraints;
387 cfg.mEditorWidgetType = mAttributeTypeDialog->editorWidgetType();
388 cfg.mEditorWidgetConfig = mAttributeTypeDialog->editorWidgetConfig();
389 cfg.mSplitPolicy = mAttributeTypeDialog->splitPolicy();
390 cfg.mDuplicatePolicy = mAttributeTypeDialog->duplicatePolicy();
391 cfg.mMergePolicy = mAttributeTypeDialog->mergePolicy();
392
393 cfg.mApplyDefaultValueOnUpdate = mAttributeTypeDialog->applyDefaultValueOnUpdate();
394 cfg.mDefaultValueExpression = mAttributeTypeDialog->defaultValueExpression();
395
396 const int fieldIndex = mAttributeTypeDialog->fieldIdx();
397 const QString fieldName = mLayer->fields().at( fieldIndex ).name();
398
399 QModelIndex index = mAvailableWidgetsModel->fieldModelIndex( fieldName );
400 if ( index.isValid() )
401 {
402 mAvailableWidgetsModel->setData( index, QVariant::fromValue<QgsAttributesFormData::FieldConfig>( cfg ), QgsAttributesFormModel::ItemFieldConfigRole );
403 mAvailableWidgetsModel->setData( index, mAttributeTypeDialog->alias(), QgsAttributesFormModel::ItemDisplayRole );
404 }
405
406 // Save field config to each matching field item in Form Layout model
407 mFormLayoutModel->updateFieldConfigForFieldItems( fieldName, cfg );
408
409 // Save alias to each matching field item in Form Layout model
410 mFormLayoutModel->updateAliasForFieldItems( fieldName, mAttributeTypeDialog->alias() );
411}
412
413void QgsAttributesFormProperties::storeAttributeWidgetEdit()
414{
416 return;
417
418 if ( mFormLayoutView->selectionModel()->selectedRows().count() != 1 )
419 return;
420
421 QModelIndex index = mFormLayoutView->firstSelectedIndex();
422 storeAttributeWidgetEdit( index );
423}
424
425void QgsAttributesFormProperties::storeAttributeWidgetEdit( const QModelIndex &index )
426{
428 return;
429
430 if ( !index.isValid() )
431 return;
432
433 auto itemData = index.data( QgsAttributesFormLayoutModel::ItemDataRole ).value< QgsAttributesFormData::AttributeFormItemData >();
434 mAttributeWidgetEdit->updateItemData( itemData );
435
437 {
438 QgsAttributesFormData::RelationEditorConfiguration config = mAttributeWidgetEdit->updatedRelationConfiguration();
439 itemData.setRelationEditorConfiguration( config );
440 mFormLayoutModel->setData( index, config.label, QgsAttributesFormLayoutModel::ItemDisplayRole );
441 }
442 mFormLayoutModel->setData( index, itemData, QgsAttributesFormLayoutModel::ItemDataRole );
443}
444
445void QgsAttributesFormProperties::loadAttributeWidgetEdit()
446{
447 if ( mFormLayoutView->selectionModel()->selectedRows().count() != 1 )
448 return;
449
450 const QModelIndex currentIndex = mFormLayoutView->firstSelectedIndex();
451 const QgsAttributesFormData::AttributeFormItemData itemData = currentIndex.data( QgsAttributesFormModel::ItemDataRole ).value< QgsAttributesFormData::AttributeFormItemData >();
452 mAttributeWidgetEdit = new QgsAttributeWidgetEdit( itemData, this );
454 {
455 mAttributeWidgetEdit->setRelationSpecificWidget( itemData.relationEditorConfiguration(), currentIndex.data( QgsAttributesFormModel::ItemIdRole ).toString() );
456 }
457 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
458 mAttributeTypeFrame->layout()->addWidget( mAttributeWidgetEdit );
459}
460
461void QgsAttributesFormProperties::loadInfoWidget( const QString &infoText )
462{
463 mInfoTextWidget = new QLabel( infoText );
464 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
465 mAttributeTypeFrame->layout()->addWidget( mInfoTextWidget );
466}
467
468void QgsAttributesFormProperties::storeAttributeContainerEdit()
469{
471 return;
472
473 if ( mFormLayoutView->selectionModel()->selectedRows().count() != 1 )
474 return;
475
476 const QModelIndex currentIndex = mFormLayoutView->firstSelectedIndex();
477 storeAttributeContainerEdit( currentIndex );
478}
479
480void QgsAttributesFormProperties::storeAttributeContainerEdit( const QModelIndex &index )
481{
483 return;
484
485 if ( !index.isValid() )
486 return;
487
488 auto itemData = index.data( QgsAttributesFormModel::ItemDataRole ).value< QgsAttributesFormData::AttributeFormItemData >();
489 QString containerName;
490
491 mAttributeContainerEdit->updateItemData( itemData, containerName );
492 mFormLayoutModel->setData( index, itemData, QgsAttributesFormLayoutModel::ItemDataRole );
493 mFormLayoutModel->setData( index, containerName, QgsAttributesFormLayoutModel::ItemNameRole );
494}
495
496void QgsAttributesFormProperties::loadAttributeContainerEdit()
497{
498 if ( mFormLayoutView->selectionModel()->selectedRows().count() != 1 )
499 return;
500
501 const QModelIndex currentIndex = mFormLayoutView->firstSelectedIndex();
502 const QgsAttributesFormData::AttributeFormItemData itemData = currentIndex.data( QgsAttributesFormModel::ItemDataRole ).value< QgsAttributesFormData::AttributeFormItemData >();
503 mAttributeContainerEdit = new QgsAttributeFormContainerEdit( itemData, mLayer, this );
504 mAttributeContainerEdit->setTitle( currentIndex.data( QgsAttributesFormModel::ItemNameRole ).toString() );
505 mAttributeContainerEdit->setUpContainerTypeComboBox( !currentIndex.parent().isValid(), itemData.containerType() );
506
507 mAttributeContainerEdit->registerExpressionContextGenerator( this );
508 mAttributeContainerEdit->layout()->setContentsMargins( 0, 0, 0, 0 );
509 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
510 mAttributeTypeFrame->layout()->addWidget( mAttributeContainerEdit );
511}
512
513void QgsAttributesFormProperties::onAttributeSelectionChanged( const QItemSelection &, const QItemSelection & )
514{
515 disconnect( mFormLayoutView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsAttributesFormProperties::onFormLayoutSelectionChanged );
516
517 QModelIndex index;
518 if ( mFormLayoutView->selectionModel()->selectedRows( 0 ).count() == 1 )
519 {
520 // Go to the form layout view and store the single-selected index, as
521 // it will be used to store its current settings before being deselected
522 index = mFormLayoutView->firstSelectedIndex();
523 }
524
525 loadAttributeSpecificEditor( mAvailableWidgetsView, mFormLayoutView, index );
526 connect( mFormLayoutView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsAttributesFormProperties::onFormLayoutSelectionChanged );
527}
528
529void QgsAttributesFormProperties::onFormLayoutSelectionChanged( const QItemSelection &, const QItemSelection &deselected )
530{
531 // when the selection changes in the DnD layout, sync the main tree
532 disconnect( mAvailableWidgetsView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsAttributesFormProperties::onAttributeSelectionChanged );
533 QModelIndex index;
534 if ( deselected.indexes().count() == 1 )
535 {
536 index = mFormLayoutProxyModel->mapToSource( deselected.indexes().at( 0 ) );
537 }
538 else if ( deselected.indexes().count() == 0 && mFormLayoutView->selectionModel()->selectedIndexes().count() == 2 )
539 {
540 // There was 1 selected, it was not deselected, but instead a new item was added to selection
541 index = mFormLayoutView->firstSelectedIndex();
542 }
543
544 loadAttributeSpecificEditor( mFormLayoutView, mAvailableWidgetsView, index );
545 connect( mAvailableWidgetsView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsAttributesFormProperties::onAttributeSelectionChanged );
546}
547
548void QgsAttributesFormProperties::loadAttributeSpecificEditor( QgsAttributesFormBaseView *emitter, QgsAttributesFormBaseView *receiver, QModelIndex &deselectedFormLayoutIndex )
549{
550 const Qgis::AttributeFormLayout layout = mEditorLayoutComboBox->currentData().value<Qgis::AttributeFormLayout>();
551
553 {
554 storeAttributeWidgetEdit( deselectedFormLayoutIndex );
555 storeAttributeContainerEdit( deselectedFormLayoutIndex );
556 }
558 {
559 storeAttributeTypeDialog();
560 }
561
562 clearAttributeTypeFrame();
563
564 if ( emitter->selectionModel()->selectedRows( 0 ).count() != 1 )
565 {
566 receiver->clearSelection();
567 }
568 else
569 {
570 const QModelIndex index = emitter->firstSelectedIndex();
571 const auto indexType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
572 switch ( indexType )
573 {
575 {
578 {
579 loadAttributeWidgetEdit();
580 }
581 else
582 {
583 loadInfoWidget( tr( "This configuration is available in the Drag and Drop Designer" ) );
584 }
585 break;
586 }
588 {
591 {
592 loadAttributeWidgetEdit();
593 }
594 loadAttributeTypeDialog();
595 break;
596 }
598 {
599 receiver->clearSelection();
600 loadAttributeContainerEdit();
601 break;
602 }
604 {
606 const QgsAction action { mLayer->actions()->action( index.data( QgsAttributesFormModel::ItemIdRole ).toString() ) };
607 loadInfoWidget( action.html() );
608 break;
609 }
614 {
616 {
617 loadInfoWidget( tr( "This configuration is available with double-click in the Drag and Drop Designer" ) );
618 }
619 else
620 {
621 loadInfoWidget( tr( "This configuration is available with double-click in the Form Layout panel" ) );
622 }
623 receiver->clearSelection();
624 break;
625 }
627 {
628 receiver->clearSelection();
629 break;
630 }
631 }
632 }
633}
634
635void QgsAttributesFormProperties::clearAttributeTypeFrame()
636{
638 {
639 mAttributeTypeFrame->layout()->removeWidget( mAttributeWidgetEdit );
640 mAttributeWidgetEdit->deleteLater();
641 mAttributeWidgetEdit = nullptr;
642 }
644 {
645 mAttributeTypeFrame->layout()->removeWidget( mAttributeTypeDialog );
646 mAttributeTypeDialog->deleteLater();
647 mAttributeTypeDialog = nullptr;
648 }
650 {
651 mAttributeTypeFrame->layout()->removeWidget( mAttributeContainerEdit );
652 mAttributeContainerEdit->deleteLater();
653 mAttributeContainerEdit = nullptr;
654 }
655 if ( mInfoTextWidget )
656 {
657 mAttributeTypeFrame->layout()->removeWidget( mInfoTextWidget );
658 mInfoTextWidget->deleteLater();
659 mInfoTextWidget = nullptr;
660 }
661}
662
663void QgsAttributesFormProperties::onInvertSelectionButtonClicked( bool checked )
664{
665 Q_UNUSED( checked )
666 for ( int i = 0; i < mFormLayoutProxyModel->rowCount(); ++i )
667 {
668 QModelIndex index = mFormLayoutProxyModel->index( i, 0 );
669 mFormLayoutView->selectionModel()->select( index, QItemSelectionModel::Toggle );
670 }
671}
672
673void QgsAttributesFormProperties::toggleShowAliases( bool checked )
674{
675 settingShowAliases->setValue( checked );
676 mAvailableWidgetsModel->setShowAliases( checked );
677 mFormLayoutModel->setShowAliases( checked );
678}
679
680void QgsAttributesFormProperties::addContainer()
681{
682 QList<QgsAddAttributeFormContainerDialog::ContainerPair> existingContainerList = mFormLayoutModel->listOfContainers();
683
684 QModelIndex currentItem;
685 if ( mFormLayoutView->selectionModel()->selectedRows().count() > 0 )
686 currentItem = mFormLayoutView->firstSelectedIndex();
687
688 QgsAddAttributeFormContainerDialog dialog( mLayer, existingContainerList, currentItem, this );
689
690 if ( !dialog.exec() )
691 return;
692
693 const QString name = dialog.name();
694 QModelIndex parentContainerItem = dialog.parentContainerItem();
695
696 mFormLayoutModel->addContainer( parentContainerItem, name, dialog.columnCount(), dialog.containerType() );
697 if ( parentContainerItem.isValid() )
698 mFormLayoutView->setExpanded( parentContainerItem, true );
699}
700
701void QgsAttributesFormProperties::removeTabOrGroupButton()
702{
703 // deleting an item may delete any number of nested child items -- so we delete
704 // them one at a time and then see if there's any selection left
705 while ( true )
706 {
707 const QModelIndexList items = mFormLayoutView->selectionModel()->selectedRows();
708 if ( items.empty() )
709 break;
710
711 const QModelIndex item = mFormLayoutProxyModel->mapToSource( items.at( 0 ) );
712 mFormLayoutModel->removeRow( item.row(), item.parent() );
713 }
714}
715
716void QgsAttributesFormProperties::mEditorLayoutComboBox_currentIndexChanged( int )
717{
718 // Refresh the right-hand side panel: first, save selection to recover it later
719 const QItemSelection selection = mAvailableWidgetsView->selectionModel()->selection();
720 if ( selection.count() > 0 )
721 {
722 mAvailableWidgetsView->selectionModel()->clear();
723 }
724
725 if ( mFormLayoutView->selectionModel()->selectedRows().count() > 0 )
726 {
727 mFormLayoutView->selectionModel()->clear(); // Get rid of e.g., container selection
728 }
729
730 const Qgis::AttributeFormLayout layout = mEditorLayoutComboBox->currentData().value<Qgis::AttributeFormLayout>();
731 switch ( layout )
732 {
734 mFormLayoutWidget->setVisible( false );
735 mTreeViewHorizontalSpacer->changeSize( 0, 20, QSizePolicy::Fixed, QSizePolicy::Fixed );
736 mUiFileFrame->setVisible( false );
737 mAddContainerButton->setVisible( false );
738 mRemoveLayoutItemButton->setVisible( false );
739 mInvertSelectionButton->setVisible( false );
740
741 setAvailableWidgetsIndicatorProvidersEnabled( true );
742 setFormLayoutIndicatorProvidersEnabled( false );
743 break;
744
746 mFormLayoutWidget->setVisible( true );
747 mTreeViewHorizontalSpacer->changeSize( 6, 20, QSizePolicy::Fixed, QSizePolicy::Fixed );
748 mUiFileFrame->setVisible( false );
749 mAddContainerButton->setVisible( true );
750 mRemoveLayoutItemButton->setVisible( true );
751 mInvertSelectionButton->setVisible( true );
752
753 setAvailableWidgetsIndicatorProvidersEnabled( false );
754 setFormLayoutIndicatorProvidersEnabled( true );
755 break;
756
758 // ui file
759 mFormLayoutWidget->setVisible( false );
760 mTreeViewHorizontalSpacer->changeSize( 0, 20, QSizePolicy::Fixed, QSizePolicy::Fixed );
761 mUiFileFrame->setVisible( true );
762 mAddContainerButton->setVisible( false );
763 mRemoveLayoutItemButton->setVisible( false );
764 mInvertSelectionButton->setVisible( false );
765
766 setAvailableWidgetsIndicatorProvidersEnabled( true );
767 setFormLayoutIndicatorProvidersEnabled( false );
768 break;
769 }
770
771 // Get the selection back so that we refresh the right-hand side panel
772 if ( selection.count() > 0 )
773 {
774 mAvailableWidgetsView->selectionModel()->select( selection, QItemSelectionModel::Select );
775 }
776}
777
778void QgsAttributesFormProperties::mTbInitCode_clicked()
779{
780 QgsAttributesFormInitCode attributesFormInitCode;
781
782 attributesFormInitCode.setCodeSource( mInitCodeSource );
783 attributesFormInitCode.setInitCode( mInitCode );
784 attributesFormInitCode.setInitFilePath( mInitFilePath );
785 attributesFormInitCode.setInitFunction( mInitFunction );
786
787 if ( !attributesFormInitCode.exec() )
788 return;
789
790 mInitCodeSource = attributesFormInitCode.codeSource();
791 mInitCode = attributesFormInitCode.initCode();
792 mInitFilePath = attributesFormInitCode.initFilePath();
793 mInitFunction = attributesFormInitCode.initFunction();
794}
795
796void QgsAttributesFormProperties::pbnSelectEditForm_clicked()
797{
798 QgsSettings myQSettings;
799 const QString lastUsedDir = myQSettings.value( u"style/lastUIDir"_s, QDir::homePath() ).toString();
800 const QString uifilename = QFileDialog::getOpenFileName( this, tr( "Select edit form" ), lastUsedDir, tr( "UI file" ) + " (*.ui)" );
801
802 if ( uifilename.isNull() )
803 return;
804
805 const QFileInfo fi( uifilename );
806 myQSettings.setValue( u"style/lastUIDir"_s, fi.path() );
807 mEditFormLineEdit->setText( uifilename );
808}
809
811{
812 storeAttributeWidgetEdit();
813 storeAttributeContainerEdit();
814 storeAttributeTypeDialog();
815}
816
818{
819 mBlockUpdates++;
820 applyToLayer( mLayer );
821 mBlockUpdates--;
822}
823
824void QgsAttributesFormProperties::applyToLayer( QgsVectorLayer *layer )
825{
826 store();
827 QgsEditFormConfig editFormConfig = layer->editFormConfig();
828
829 const QModelIndex fieldContainer = mAvailableWidgetsModel->fieldContainer();
830 QModelIndex index;
831
832 for ( int i = 0; i < mAvailableWidgetsModel->rowCount( fieldContainer ); i++ )
833 {
834 index = mAvailableWidgetsModel->index( i, 0, fieldContainer );
836
837 const QString fieldName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
838 const int idx = layer->fields().indexOf( fieldName );
839
840 //continue in case field does not exist anymore
841 if ( idx < 0 )
842 continue;
843
844 editFormConfig.setReadOnly( idx, !cfg.mEditable );
845 editFormConfig.setLabelOnTop( idx, cfg.mLabelOnTop );
846 editFormConfig.setReuseLastValuePolicy( idx, cfg.mReuseLastValuePolicy );
847
848 if ( cfg.mDataDefinedProperties.count() > 0 )
849 {
850 editFormConfig.setDataDefinedFieldProperties( fieldName, cfg.mDataDefinedProperties );
851 }
852
853 layer->setEditorWidgetSetup( idx, QgsEditorWidgetSetup( cfg.mEditorWidgetType, cfg.mEditorWidgetConfig ) );
854
855 const QgsFieldConstraints constraints = cfg.mFieldConstraints;
856 layer->setConstraintExpression( idx, constraints.constraintExpression(), constraints.constraintDescription() );
858 {
860 }
861 else
862 {
864 }
866 {
868 }
869 else
870 {
872 }
874 {
876 }
877 else
878 {
880 }
881
882 layer->setFieldAlias( idx, cfg.mAlias );
883 layer->setFieldSplitPolicy( idx, cfg.mSplitPolicy );
884 layer->setFieldDuplicatePolicy( idx, cfg.mDuplicatePolicy );
885 layer->setFieldMergePolicy( idx, cfg.mMergePolicy );
886
887 layer->setDefaultValueDefinition( idx, QgsDefaultValue( cfg.mDefaultValueExpression, cfg.mApplyDefaultValueOnUpdate ) );
888 }
889
890 // // tabs and groups
891 editFormConfig.clearTabs();
892
893 for ( int t = 0; t < mFormLayoutModel->rowCount(); t++ )
894 {
895 QModelIndex index = mFormLayoutModel->index( t, 0 );
896 QgsAttributeEditorElement *editorElement { mFormLayoutModel->createAttributeEditorWidget( index, nullptr ) };
897 if ( editorElement )
898 editFormConfig.addTab( editorElement );
899 }
900
901 editFormConfig.setUiForm( mEditFormLineEdit->text() );
902
903 editFormConfig.setLayout( mEditorLayoutComboBox->currentData().value<Qgis::AttributeFormLayout>() );
904
905 editFormConfig.setInitCodeSource( mInitCodeSource );
906 editFormConfig.setInitFunction( mInitFunction );
907 editFormConfig.setInitFilePath( mInitFilePath );
908 editFormConfig.setInitCode( mInitCode );
909
910 editFormConfig.setSuppress( mFormSuppressCmbBx->currentData().value<Qgis::AttributeFormSuppression>() );
911
912 // write the legacy config of relation widgets to support settings read by the API
913 const QModelIndex relationContainer = mAvailableWidgetsModel->relationContainer();
914
915 for ( int i = 0; i < mAvailableWidgetsModel->rowCount( relationContainer ); i++ )
916 {
917 const QModelIndex relationIndex = mAvailableWidgetsModel->index( i, 0, relationContainer );
918
919 const QgsAttributesFormData::AttributeFormItemData itemData = relationIndex.data( QgsAttributesFormModel::ItemDataRole ).value<QgsAttributesFormData::AttributeFormItemData>();
920 const auto indexType = static_cast< QgsAttributesFormData::AttributesFormItemType >( relationIndex.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
921 const QString indexId = relationIndex.data( QgsAttributesFormModel::ItemIdRole ).toString();
922
923 const QModelIndex layoutIndex = mFormLayoutModel->firstRecursiveMatchingModelIndex( indexType, indexId );
924 if ( layoutIndex.isValid() )
925 {
926 QVariantMap config;
927
928 const QgsAttributesFormData::AttributeFormItemData tabIndexData = layoutIndex.data( QgsAttributesFormModel::ItemDataRole ).value<QgsAttributesFormData::AttributeFormItemData>();
929 config[u"nm-rel"_s] = tabIndexData.relationEditorConfiguration().nmRelationId;
930 config[u"force-suppress-popup"_s] = tabIndexData.relationEditorConfiguration().forceSuppressFormPopup;
931
932 editFormConfig.setWidgetConfig( indexId, config );
933 break;
934 }
935 }
936
937 layer->setEditFormConfig( editFormConfig );
938}
939
940void QgsAttributesFormProperties::updatedFields()
941{
942 // Store configuration to insure changes made are kept after refreshing the list
943 QMap<QString, QgsAttributesFormData::FieldConfig> fieldConfigs;
944
945 const QModelIndex fieldContainerBefore = mAvailableWidgetsModel->fieldContainer();
946 QModelIndex index;
947
948 for ( int i = 0; i < mAvailableWidgetsModel->rowCount( fieldContainerBefore ); i++ )
949 {
950 index = mAvailableWidgetsModel->index( i, 0, fieldContainerBefore );
951 const QString fieldName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
952 const QgsAttributesFormData::FieldConfig config = index.data( QgsAttributesFormModel::ItemFieldConfigRole ).value< QgsAttributesFormData::FieldConfig >();
953 fieldConfigs[fieldName] = config;
954 }
955
957
958 const QModelIndex fieldContainerAfter = mAvailableWidgetsModel->fieldContainer();
959
960 for ( int i = 0; i < mAvailableWidgetsModel->rowCount( fieldContainerAfter ); i++ )
961 {
962 index = mAvailableWidgetsModel->index( i, 0, fieldContainerAfter );
963 const QString fieldName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
964
965 if ( fieldConfigs.contains( fieldName ) )
966 {
967 mAvailableWidgetsModel->setData( index, fieldConfigs[fieldName], QgsAttributesFormModel::ItemFieldConfigRole );
968 mAvailableWidgetsModel->setData( index, fieldConfigs[fieldName].mAlias, QgsAttributesFormModel::ItemDisplayRole );
969 }
970 }
971}
972
973void QgsAttributesFormProperties::updateFilteredItems( const QString &filterText )
974{
975 const int availableWidgetsPreviousSelectionCount = mAvailableWidgetsView->selectionModel()->selectedRows().count();
976 const int formLayoutPreviousSelectionCount = mFormLayoutView->selectionModel()->selectedRows().count();
977
978 static_cast< QgsAttributesAvailableWidgetsView *>( mAvailableWidgetsView )->setFilterText( filterText );
979 mAvailableWidgetsView->expandAll();
980
981 static_cast< QgsAttributesFormLayoutView *>( mFormLayoutView )->setFilterText( filterText );
982 mFormLayoutView->expandAll();
983
984 // If there was no previous selection leave as is, since
985 // after a filter change no new selection may be added (only lost).
986 if ( !( availableWidgetsPreviousSelectionCount == 0 && formLayoutPreviousSelectionCount == 0 ) )
987 {
988 const int selectedAvailableWidgetItemCount = mAvailableWidgetsView->selectionModel()->selectedRows().count();
989 const int selectedFormLayoutItemCount = mFormLayoutView->selectionModel()->selectedRows().count();
990
991 if ( selectedAvailableWidgetItemCount == 0 && selectedFormLayoutItemCount == 0 )
992 {
993 // Clear right-hand side panel since all selected items have been filtered out
994 clearAttributeTypeFrame();
995 }
996 }
997}
998
999void QgsAttributesFormProperties::onContextMenuRequested( QPoint point )
1000{
1001 if ( mAvailableWidgetsView->selectionModel()->selectedRows().count() != 1 )
1002 return;
1003
1004 QPoint globalPos = mAvailableWidgetsView->viewport()->mapToGlobal( point );
1005
1006 const QModelIndex index = mAvailableWidgetsView->indexAt( point );
1007 const auto itemType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
1008 if ( itemType == QgsAttributesFormData::Field )
1009 {
1010 const QClipboard *clipboard = QApplication::clipboard();
1011 const QMimeData *mimeData = clipboard->mimeData();
1012 if ( !mimeData )
1013 return;
1014
1015 const bool pasteEnabled = mimeData->hasFormat( u"application/x-qgsattributetabledesignerelementclipboard"_s );
1016 mActionPasteWidgetConfiguration->setEnabled( pasteEnabled );
1017 mAvailableWidgetsContextMenu->popup( globalPos );
1018 }
1019}
1020
1021void QgsAttributesFormProperties::copyWidgetConfiguration()
1022{
1023 if ( mAvailableWidgetsView->selectionModel()->selectedRows().count() != 1 )
1024 return;
1025
1026 const QModelIndex index = mAvailableWidgetsView->firstSelectedIndex();
1027 const auto itemType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
1028
1029 if ( itemType != QgsAttributesFormData::Field )
1030 return;
1031
1032 const QString fieldName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
1033 const int fieldIndex = mLayer->fields().indexOf( fieldName );
1034
1035 if ( fieldIndex < 0 )
1036 return;
1037
1038 const QgsField field = mLayer->fields().field( fieldIndex );
1039
1040 // We'll copy everything but field aliases or comments
1041 QDomDocument doc;
1042 QDomElement documentElement = doc.createElement( u"FormWidgetClipboard"_s );
1043 documentElement.setAttribute( u"name"_s, field.name() );
1044
1045 // Editor widget setup
1046 QgsEditorWidgetSetup widgetSetup = field.editorWidgetSetup();
1047
1048 QDomElement editWidgetElement = doc.createElement( u"editWidget"_s );
1049 documentElement.appendChild( editWidgetElement );
1050 editWidgetElement.setAttribute( u"type"_s, widgetSetup.type() );
1051 QDomElement editWidgetConfigElement = doc.createElement( u"config"_s );
1052
1053 editWidgetConfigElement.appendChild( QgsXmlUtils::writeVariant( widgetSetup.config(), doc ) );
1054 editWidgetElement.appendChild( editWidgetConfigElement );
1055
1056 // Split policy
1057 QDomElement splitPolicyElement = doc.createElement( u"splitPolicy"_s );
1058 splitPolicyElement.setAttribute( u"policy"_s, qgsEnumValueToKey( field.splitPolicy() ) );
1059 documentElement.appendChild( splitPolicyElement );
1060
1061 // Duplicate policy
1062 QDomElement duplicatePolicyElement = doc.createElement( u"duplicatePolicy"_s );
1063 duplicatePolicyElement.setAttribute( u"policy"_s, qgsEnumValueToKey( field.duplicatePolicy() ) );
1064 documentElement.appendChild( duplicatePolicyElement );
1065
1066 // Merge policy
1067 QDomElement mergePolicyElement = doc.createElement( u"mergePolicy"_s );
1068 mergePolicyElement.setAttribute( u"policy"_s, qgsEnumValueToKey( field.mergePolicy() ) );
1069 documentElement.appendChild( mergePolicyElement );
1070
1071 // Default expressions
1072 QDomElement defaultElem = doc.createElement( u"default"_s );
1073 defaultElem.setAttribute( u"expression"_s, field.defaultValueDefinition().expression() );
1074 defaultElem.setAttribute( u"applyOnUpdate"_s, field.defaultValueDefinition().applyOnUpdate() ? u"1"_s : u"0"_s );
1075 documentElement.appendChild( defaultElem );
1076
1077 // Constraints
1078 QDomElement constraintElem = doc.createElement( u"constraint"_s );
1079 constraintElem.setAttribute( u"constraints"_s, field.constraints().constraints() );
1080 constraintElem.setAttribute( u"unique_strength"_s, field.constraints().constraintStrength( QgsFieldConstraints::ConstraintUnique ) );
1081 constraintElem.setAttribute( u"notnull_strength"_s, field.constraints().constraintStrength( QgsFieldConstraints::ConstraintNotNull ) );
1082 constraintElem.setAttribute( u"exp_strength"_s, field.constraints().constraintStrength( QgsFieldConstraints::ConstraintExpression ) );
1083 documentElement.appendChild( constraintElem );
1084
1085 // Constraint expressions
1086 QDomElement constraintExpressionElem = doc.createElement( u"constraintExpression"_s );
1087 constraintExpressionElem.setAttribute( u"exp"_s, field.constraints().constraintExpression() );
1088 constraintExpressionElem.setAttribute( u"desc"_s, field.constraints().constraintDescription() );
1089 documentElement.appendChild( constraintExpressionElem );
1090
1091 // Widget general settings
1093 {
1094 QDomElement widgetGeneralSettingsElem = doc.createElement( u"widgetGeneralSettings"_s );
1095 widgetGeneralSettingsElem.setAttribute( u"editable"_s, mAttributeTypeDialog->fieldEditable() );
1096 widgetGeneralSettingsElem.setAttribute( u"label_on_top"_s, mAttributeTypeDialog->labelOnTop() );
1097 widgetGeneralSettingsElem.setAttribute( u"reuse_last_value_policy"_s, qgsEnumValueToKey( mAttributeTypeDialog->reuseLastValuePolicy() ) );
1098 documentElement.appendChild( widgetGeneralSettingsElem );
1099 }
1100
1101 // Widget display section
1103 {
1104 // Go for the corresponding form layout item and extract its display settings
1105 if ( mFormLayoutView->selectionModel()->selectedRows().count() != 1 )
1106 return;
1107
1108 const QModelIndex indexLayout = mFormLayoutView->firstSelectedIndex();
1109 const auto layoutData = indexLayout.data( QgsAttributesFormModel::ItemDataRole ).value< QgsAttributesFormData::AttributeFormItemData >();
1110
1111 QDomElement displayElement = doc.createElement( u"widgetDisplay"_s );
1112 displayElement.setAttribute( u"showLabel"_s, layoutData.showLabel() );
1113 displayElement.setAttribute( u"horizontalStretch"_s, layoutData.horizontalStretch() );
1114 displayElement.setAttribute( u"verticalStretch"_s, layoutData.verticalStretch() );
1115 displayElement.appendChild( layoutData.labelStyle().writeXml( doc ) );
1116 documentElement.appendChild( displayElement );
1117 }
1118
1119 doc.appendChild( documentElement );
1120
1121 QMimeData *mimeData = new QMimeData;
1122 mimeData->setData( u"application/x-qgsattributetabledesignerelementclipboard"_s, doc.toByteArray() );
1123 QClipboard *clipboard = QApplication::clipboard();
1124 clipboard->setMimeData( mimeData );
1125}
1126
1127void QgsAttributesFormProperties::pasteWidgetConfiguration()
1128{
1129 if ( mAvailableWidgetsView->selectionModel()->selectedRows().count() != 1 )
1130 return;
1131
1132 QModelIndex index = mAvailableWidgetsView->firstSelectedIndex();
1133
1134 const QString fieldName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
1135 const int fieldIndex = mLayer->fields().indexOf( fieldName );
1136
1137 if ( fieldIndex < 0 )
1138 return;
1139
1140 // Get base config from target item and ovewrite settings when possible
1141 auto config = index.data( QgsAttributesFormModel::ItemFieldConfigRole ).value< QgsAttributesFormData::FieldConfig >();
1142
1143 QDomDocument doc;
1144 QClipboard *clipboard = QApplication::clipboard();
1145 const QMimeData *mimeData = clipboard->mimeData();
1146 if ( !mimeData )
1147 return;
1148
1149 if ( doc.setContent( mimeData->data( u"application/x-qgsattributetabledesignerelementclipboard"_s ) ) )
1150 {
1151 QgsReadWriteContext context;
1152 QDomElement docElem = doc.documentElement();
1153 if ( docElem.tagName() != "FormWidgetClipboard"_L1 )
1154 return;
1155
1156 // When pasting, the target item has already been selected and
1157 // has triggered attribute type dialog loading. Therefore, we'll
1158 // only overwrite GUI settings instead of destroying and recreating
1159 // the whole dialog.
1160
1161 // Editor widget configuration
1162 const QDomElement fieldWidgetElement = docElem.firstChildElement( u"editWidget"_s );
1163 if ( !fieldWidgetElement.isNull() )
1164 {
1165 const QString widgetType = fieldWidgetElement.attribute( u"type"_s );
1166
1167 // Only paste if source editor widget type is supported by target field
1168 const QgsEditorWidgetFactory *factory = QgsGui::editorWidgetRegistry()->factory( widgetType );
1169 if ( factory->supportsField( mLayer, fieldIndex ) )
1170 {
1171 const QDomElement configElement = fieldWidgetElement.firstChildElement( u"config"_s );
1172 if ( !configElement.isNull() )
1173 {
1174 const QDomElement optionsElem = configElement.childNodes().at( 0 ).toElement();
1175 QVariantMap optionsMap = QgsXmlUtils::readVariant( optionsElem ).toMap();
1176 config.mEditorWidgetType = widgetType;
1177 config.mEditorWidgetConfig = optionsMap;
1178 }
1179 }
1180 else
1181 {
1182 mMessageBar->pushMessage( QString(), tr( "Unable to paste widget configuration. The target field (%1) does not support the %2 widget type." ).arg( fieldName, widgetType ), Qgis::MessageLevel::Warning );
1183 }
1184 }
1185
1186 // Split policy
1187 const QDomElement splitPolicyElement = docElem.firstChildElement( u"splitPolicy"_s );
1188 if ( !splitPolicyElement.isNull() )
1189 {
1190 const Qgis::FieldDomainSplitPolicy policy = qgsEnumKeyToValue( splitPolicyElement.attribute( u"policy"_s ), Qgis::FieldDomainSplitPolicy::Duplicate );
1191 config.mSplitPolicy = policy;
1192 }
1193
1194 // Duplicate policy
1195 const QDomElement duplicatePolicyElement = docElem.firstChildElement( u"duplicatePolicy"_s );
1196 if ( !duplicatePolicyElement.isNull() )
1197 {
1198 const Qgis::FieldDuplicatePolicy policy = qgsEnumKeyToValue( duplicatePolicyElement.attribute( u"policy"_s ), Qgis::FieldDuplicatePolicy::Duplicate );
1199 config.mDuplicatePolicy = policy;
1200 }
1201
1202 // Merge policy
1203 const QDomElement mergePolicyElement = docElem.firstChildElement( u"mergePolicy"_s );
1204 if ( !mergePolicyElement.isNull() )
1205 {
1206 const Qgis::FieldDomainMergePolicy policy = qgsEnumKeyToValue( mergePolicyElement.attribute( u"policy"_s ), Qgis::FieldDomainMergePolicy::DefaultValue );
1207 config.mMergePolicy = policy;
1208 }
1209
1210 // Default expressions
1211 const QDomElement defaultElement = docElem.firstChildElement( u"default"_s );
1212 if ( !defaultElement.isNull() )
1213 {
1214 config.mDefaultValueExpression = defaultElement.attribute( u"expression"_s );
1215 config.mApplyDefaultValueOnUpdate = defaultElement.attribute( u"applyOnUpdate"_s ).toInt();
1216 }
1217
1218 // Constraints
1219 // take target field constraints as a basis
1220 QgsFieldConstraints fieldConstraints = config.mFieldConstraints;
1221 const QDomElement constraintElement = docElem.firstChildElement( u"constraint"_s );
1222 if ( !constraintElement.isNull() )
1223 {
1224 const int intConstraints = constraintElement.attribute( u"constraints"_s, u"0"_s ).toInt();
1225 QgsFieldConstraints::Constraints constraints = static_cast< QgsFieldConstraints::Constraints >( intConstraints );
1226
1227 // always keep provider constraints intact
1229 {
1230 if ( constraints & QgsFieldConstraints::ConstraintNotNull )
1232 else
1234 }
1236 {
1237 if ( constraints & QgsFieldConstraints::ConstraintUnique )
1239 else
1241 }
1243 {
1246 else
1248 }
1249
1250 const int uniqueStrength = constraintElement.attribute( u"unique_strength"_s, u"1"_s ).toInt();
1251 const int notNullStrength = constraintElement.attribute( u"notnull_strength"_s, u"1"_s ).toInt();
1252 const int expStrength = constraintElement.attribute( u"exp_strength"_s, u"1"_s ).toInt();
1253
1257 }
1258
1259 // Constraint expressions
1260 // always keep provider constraints intact
1262 {
1263 const QDomElement constraintExpressionElement = docElem.firstChildElement( u"constraintExpression"_s );
1264 if ( !constraintExpressionElement.isNull() )
1265 {
1266 QString expression = constraintExpressionElement.attribute( u"exp"_s, QString() );
1267 QString description = constraintExpressionElement.attribute( u"desc"_s, QString() );
1268 fieldConstraints.setConstraintExpression( expression, description );
1269 }
1270 }
1271 config.mFieldConstraints = fieldConstraints;
1272
1273 const QDomElement widgetGeneralSettingsElement = docElem.firstChildElement( u"widgetGeneralSettings"_s );
1274 if ( !widgetGeneralSettingsElement.isNull() )
1275 {
1276 const int editable = widgetGeneralSettingsElement.attribute( u"editable"_s, u"0"_s ).toInt();
1278 if ( widgetGeneralSettingsElement.hasAttribute( u"reuse_last_values"_s ) )
1279 {
1280 reusePolicy = widgetGeneralSettingsElement.attribute( u"reuse_last_values"_s, u"0"_s ).toInt() == 1 ? Qgis::AttributeFormReuseLastValuePolicy::AllowedDefaultOn
1282 }
1283 else
1284 {
1285 reusePolicy = qgsEnumKeyToValue( widgetGeneralSettingsElement.attribute( u"reuse_last_values"_s ), Qgis::AttributeFormReuseLastValuePolicy::NotAllowed );
1286 }
1287 const int labelOnTop = widgetGeneralSettingsElement.attribute( u"label_on_top"_s, u"0"_s ).toInt();
1288
1289 config.mEditable = editable;
1290 config.mReuseLastValuePolicy = reusePolicy;
1291 config.mLabelOnTop = labelOnTop;
1292 }
1293
1294 loadAttributeTypeDialogFromConfiguration( config );
1295
1296 // Widget display section
1298 {
1299 const QDomElement displayElement = docElem.firstChildElement( u"widgetDisplay"_s );
1300 if ( !displayElement.isNull() )
1301 {
1302 const int showLabel = displayElement.attribute( u"showLabel"_s, u"0"_s ).toInt();
1303 const int horizontalStretch = displayElement.attribute( u"horizontalStretch"_s, u"0"_s ).toInt();
1304 const int verticalStretch = displayElement.attribute( u"verticalStretch"_s, u"0"_s ).toInt();
1305 QgsAttributeEditorElement::LabelStyle style;
1306 style.readXml( displayElement );
1307
1308 // Update current GUI controls
1309 mAttributeWidgetEdit->setShowLabel( showLabel );
1310 mAttributeWidgetEdit->setHorizontalStretch( horizontalStretch );
1311 mAttributeWidgetEdit->setVerticalStretch( verticalStretch );
1312 mAttributeWidgetEdit->setLabelStyle( style );
1313 }
1314 }
1315 }
1316}
1317
1318void QgsAttributesFormProperties::setAvailableWidgetsIndicatorProvidersEnabled( bool enabled )
1319{
1320 // Only enable if the provider is disabled and only disable if it's enabled
1321 if ( enabled && !mDefaultValueIndicatorProviderAvailableWidgets->isEnabled() )
1322 {
1323 connect( mAvailableWidgetsModel, &QgsAttributesFormModel::fieldConfigDataChanged, mDefaultValueIndicatorProviderAvailableWidgets, &QgsFieldDefaultValueIndicatorProvider::updateItemIndicator );
1324 mDefaultValueIndicatorProviderAvailableWidgets->setEnabled( enabled );
1325 }
1326 else if ( !enabled && mDefaultValueIndicatorProviderAvailableWidgets->isEnabled() )
1327 {
1328 disconnect( mAvailableWidgetsModel, &QgsAttributesFormModel::fieldConfigDataChanged, mDefaultValueIndicatorProviderAvailableWidgets, &QgsFieldDefaultValueIndicatorProvider::updateItemIndicator );
1329 mDefaultValueIndicatorProviderAvailableWidgets->setEnabled( enabled );
1330 }
1331
1332 if ( enabled && !mConstraintIndicatorProviderAvailableWidgets->isEnabled() )
1333 {
1334 connect( mAvailableWidgetsModel, &QgsAttributesFormModel::fieldConfigDataChanged, mConstraintIndicatorProviderAvailableWidgets, &QgsFieldConstraintIndicatorProvider::updateItemIndicator );
1335 mConstraintIndicatorProviderAvailableWidgets->setEnabled( enabled );
1336 }
1337 else if ( !enabled && mConstraintIndicatorProviderAvailableWidgets->isEnabled() )
1338 {
1339 disconnect( mAvailableWidgetsModel, &QgsAttributesFormModel::fieldConfigDataChanged, mConstraintIndicatorProviderAvailableWidgets, &QgsFieldConstraintIndicatorProvider::updateItemIndicator );
1340 mConstraintIndicatorProviderAvailableWidgets->setEnabled( enabled );
1341 }
1342}
1343
1344void QgsAttributesFormProperties::setFormLayoutIndicatorProvidersEnabled( bool enabled )
1345{
1346 // Only enable if the provider is disabled and only disable if it's enabled
1347 if ( enabled && !mDefaultValueIndicatorProviderFormLayout->isEnabled() )
1348 {
1349 connect( mFormLayoutModel, &QgsAttributesFormModel::fieldConfigDataChanged, mDefaultValueIndicatorProviderFormLayout, &QgsFieldDefaultValueIndicatorProvider::updateItemIndicator );
1350 mDefaultValueIndicatorProviderFormLayout->setEnabled( enabled );
1351 }
1352 else if ( !enabled && mDefaultValueIndicatorProviderFormLayout->isEnabled() )
1353 {
1354 disconnect( mFormLayoutModel, &QgsAttributesFormModel::fieldConfigDataChanged, mDefaultValueIndicatorProviderFormLayout, &QgsFieldDefaultValueIndicatorProvider::updateItemIndicator );
1355 mDefaultValueIndicatorProviderFormLayout->setEnabled( enabled );
1356 }
1357
1358 if ( enabled && !mConstraintIndicatorProviderFormLayout->isEnabled() )
1359 {
1360 connect( mFormLayoutModel, &QgsAttributesFormModel::fieldConfigDataChanged, mConstraintIndicatorProviderFormLayout, &QgsFieldConstraintIndicatorProvider::updateItemIndicator );
1361 mConstraintIndicatorProviderFormLayout->setEnabled( enabled );
1362 }
1363 else if ( !enabled && mConstraintIndicatorProviderFormLayout->isEnabled() )
1364 {
1365 disconnect( mFormLayoutModel, &QgsAttributesFormModel::fieldConfigDataChanged, mConstraintIndicatorProviderFormLayout, &QgsFieldConstraintIndicatorProvider::updateItemIndicator );
1366 mConstraintIndicatorProviderFormLayout->setEnabled( enabled );
1367 }
1368}
1369
1370void QgsAttributesFormProperties::previewForm()
1371{
1372 if ( !mSourceFieldsProperties )
1373 {
1374 return;
1375 }
1376
1377 auto projectDirtyBlocker = std::make_unique<QgsProjectDirtyBlocker>( QgsProject::instance() );
1378
1379
1380 QgsFields fields;
1381 QList<QPair<QgsField, QString>> expressionFields;
1382
1383 for ( int i = 0; i < mLayer->fields().size(); i++ )
1384 {
1385 if ( mLayer->fields().fieldOrigin( i ) == Qgis::FieldOrigin::Expression )
1386 {
1387 expressionFields << qMakePair( mLayer->fields().at( i ), mLayer->expressionField( i ) );
1388 }
1389 else
1390 {
1391 fields.append( mLayer->fields().at( i ) );
1392 }
1393 }
1394
1395 std::unique_ptr<QgsVectorLayer> vlayer;
1396 vlayer.reset( QgsMemoryProviderUtils::createMemoryLayer( "preview"_L1, fields, mLayer->wkbType(), mLayer->crs() ) );
1397 for ( const QPair<QgsField, QString> &expressionField : std::as_const( expressionFields ) )
1398 {
1399 vlayer->addExpressionField( expressionField.second, expressionField.first );
1400 }
1401
1402 mSourceFieldsProperties->applyToLayer( vlayer.get() );
1403 applyToLayer( vlayer.get() );
1404
1405 QgsFeature feature = QgsVectorLayerUtils::createFeature( vlayer.get() );
1406 QgsAttributeDialog form( vlayer.get(), &feature, false, this, true );
1408 form.exec();
1409
1410 projectDirtyBlocker.reset();
1411}
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
@ On
Always suppress feature form.
Definition qgis.h:5858
@ Default
Use the application-wide setting.
Definition qgis.h:5857
@ Off
Never suppress feature form.
Definition qgis.h:5859
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
FieldDomainMergePolicy
Merge policy for field domains.
Definition qgis.h:4040
@ DefaultValue
Use default field value.
Definition qgis.h:4041
@ Warning
Warning message.
Definition qgis.h:162
FieldDomainSplitPolicy
Split policy for field domains.
Definition qgis.h:4023
@ Duplicate
Duplicate original value.
Definition qgis.h:4025
FieldDuplicatePolicy
Duplicate policy for fields.
Definition qgis.h:4060
@ Duplicate
Duplicate original value.
Definition qgis.h:4062
@ Expression
Field is calculated from an expression.
Definition qgis.h:1788
QString html() const
Returns an HTML table with the basic information about this action.
@ PreviewMode
Preview mode, for previewing attribute configurations.
Manages available widgets when configuring attributes forms.
QModelIndex fieldContainer() const
Returns the field container in this model, expected to be placed at the first top-level row.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
Graphical representation for the available widgets while configuring attributes forms.
Graphical representation for the attribute drag and drop editor.
void selectFirstMatchingItem(const QgsAttributesFormData::AttributesFormItemType &itemType, const QString &itemId)
Selects the first item that matches a itemType and a itemId.
QModelIndex firstSelectedIndex() const
Returns the source model index corresponding to the first selected row.
RelationEditorConfiguration relationEditorConfiguration() const
Returns the relation editor configuration.
Qgis::AttributeEditorContainerType containerType() const
Returns the container type.
AttributesFormItemType
Custom item types.
@ Container
Container for the form, which may be tab, group or row.
@ Relation
Relation between two vector layers.
@ Field
Vector layer field.
@ SpacerWidget
Spacer widget type,.
@ WidgetType
In the available widgets tree, the type of widget.
@ TextWidget
Text widget type,.
QString initFilePath() const
Returns the file path for the file containing the init code.
void setCodeSource(Qgis::AttributeFormPythonInitCodeSource source)
Sets the Python init code source.
void setInitFilePath(const QString &initFilePath)
Sets the file path for the file containing the init code.
void setInitFunction(const QString &initFunction)
Sets the name of the init function.
QString initFunction() const
Returns the name of the init function.
void setInitCode(const QString &initCode)
Sets the init code contents.
Qgis::AttributeFormPythonInitCodeSource codeSource() const
Returns the Python init code source.
QString initCode() const
Returns the init code contents.
Manages form layouts when configuring attributes forms via drag and drop designer.
Graphical representation for the form layout while configuring attributes forms.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
@ ItemFieldConfigRole
Prior to QGIS 3.44, this was available as FieldConfigRole.
@ ItemDisplayRole
Display text for the item.
@ ItemNameRole
Prior to QGIS 3.44, this was available as FieldNameRole.
@ ItemDataRole
Prior to QGIS 3.44, this was available as DnDTreeRole.
@ ItemIdRole
Items may have ids to ease comparison. Used by Relations, fields, actions and containers.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
void fieldConfigDataChanged(QgsAttributesFormItem *item)
Notifies other objects that the field config data has changed in the item.
QgsAttributesFormBaseView * mFormLayoutView
void initAvailableWidgetsActions(const QList< QgsAction > actions)
Refresh layer actions in the Available Widgets view.
QgsAttributeFormContainerEdit * mAttributeContainerEdit
static const QgsSettingsEntryBool * settingShowAliases
QgsAttributesFormBaseView * mAvailableWidgetsView
QgsAttributeTypeDialog * mAttributeTypeDialog
void store()
Stores currently opened widget configuration.
QgsAttributesFormProperties(QgsVectorLayer *layer, QWidget *parent=nullptr, QgsSourceFieldsProperties *sourceFieldsProperties=nullptr)
The QgsAttributesFormProperties constructor.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QgsAttributeWidgetEdit * mAttributeWidgetEdit
void apply()
Applies the attribute from properties to the vector layer.
void initFormLayoutView()
Initializes the form layout tree view, repopulating the underlying model.
void initAvailableWidgetsView()
Initializes the available widgets tree view, repopulating the underlying model.
Proxy model to filter items in the tree views of the drag and drop designer.
void updateItemIndicator(QgsAttributesFormItem *item)
Updates the state of a the indicator for the given item.
Contains configuration settings for an editor form.
Qgis::AttributeFormPythonInitCodeSource initCodeSource() const
Returns Python code source for edit form initialization (if it shall be loaded from a file,...
QString initCode() const
Gets Python code for edit form initialization.
void setInitFunction(const QString &function)
Set Python function for edit form initialization.
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.
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.
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...
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.
QString initFunction() const
Gets Python function for edit form initialization.
void setUiForm(const QString &ui)
Set path to the .ui form.
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.
void setReuseLastValuePolicy(int index, Qgis::AttributeFormReuseLastValuePolicy policy)
Sets the reuse of last value policy for an attribute index.
bool supportsField(const QgsVectorLayer *vl, int fieldIdx) const
Check if this editor widget type supports a certain field.
QgsEditorWidgetFactory * factory(const QString &widgetId)
Gets a factory for the given widget type id.
QString type() const
Returns the widget type to use.
QVariantMap config() const
Returns the widget configuration.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
Provides field constraint indicators for attribute form views.
ConstraintStrength
Strength of constraints.
@ ConstraintStrengthSoft
User is warned if constraint is violated but feature can still be accepted.
@ ConstraintStrengthHard
Constraint must be honored before feature can be accepted.
void setConstraintStrength(Constraint constraint, ConstraintStrength strength)
Sets the strength of a constraint.
void setConstraintExpression(const QString &expression, const QString &description=QString())
Set the constraint expression for the field.
@ ConstraintOriginProvider
Constraint was set at data provider.
@ ConstraintOriginLayer
Constraint was set by layer.
ConstraintStrength constraintStrength(Constraint constraint) const
Returns the strength of a field constraint, or ConstraintStrengthNotSet if the constraint is not pres...
ConstraintOrigin constraintOrigin(Constraint constraint) const
Returns the origin of a field constraint, or ConstraintOriginNotSet if the constraint is not present ...
QString constraintExpression() const
Returns the constraint expression for the field, if set.
@ ConstraintNotNull
Field may not be null.
@ ConstraintUnique
Field must have a unique value.
@ ConstraintExpression
Field has an expression constraint set. See constraintExpression().
void removeConstraint(Constraint constraint)
Removes a constraint from the field.
QString constraintDescription() const
Returns the descriptive name for the constraint expression.
void setConstraint(Constraint constraint, ConstraintOrigin origin=ConstraintOriginLayer)
Sets a constraint on the field.
QFlags< Constraint > Constraints
Provides default value indicators for attribute form views.
QString name
Definition qgsfield.h:65
Qgis::FieldDomainSplitPolicy splitPolicy() const
Returns the field's split policy, which indicates how field values should be handled during a split o...
Definition qgsfield.cpp:754
Qgis::FieldDuplicatePolicy duplicatePolicy() const
Returns the field's duplicate policy, which indicates how field values should be handled during a dup...
Definition qgsfield.cpp:764
QgsDefaultValue defaultValueDefinition
Definition qgsfield.h:67
Qgis::FieldDomainMergePolicy mergePolicy() const
Returns the field's merge policy, which indicates how field values should be handled during a merge o...
Definition qgsfield.cpp:774
QgsFieldConstraints constraints
Definition qgsfield.h:68
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Definition qgsfield.cpp:739
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
Definition qgsfields.cpp:75
Q_INVOKABLE int indexOf(const QString &fieldName) const
Gets the field index from the field name.
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories.
Definition qgsgui.cpp:109
static QgsVectorLayer * createMemoryLayer(const QString &name, const QgsFields &fields, Qgis::WkbType geometryType=Qgis::WkbType::NoGeometry, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem(), bool loadDefaultStyle=true) SIP_FACTORY
Creates a new memory layer using the specified parameters.
A bar for displaying non-blocking messages to the user.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:113
static QgsProject * instance()
Returns the QgsProject singleton instance.
int count() const
Returns the number of properties contained within the collection.
A boolean settings entry.
static const QgsSettingsEntryBool * settingsDigitizingDisableEnterAttributeValuesDialog
Settings entry digitizing disable enter attribute values dialog.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
A widget which displays information about vector layer fields, and allows some configuration of them.
static QgsFeature createFeature(const QgsVectorLayer *layer, const QgsGeometry &geometry=QgsGeometry(), const QgsAttributeMap &attributes=QgsAttributeMap(), QgsExpressionContext *context=nullptr)
Creates a new feature ready for insertion into a layer.
Represents a vector layer which manages a vector based dataset.
void setFieldConstraint(int index, QgsFieldConstraints::Constraint constraint, QgsFieldConstraints::ConstraintStrength strength=QgsFieldConstraints::ConstraintStrengthHard)
Sets a constraint for a specified field index.
void removeFieldConstraint(int index, QgsFieldConstraints::Constraint constraint)
Removes a constraint for a specified field index.
void setFieldMergePolicy(int index, Qgis::FieldDomainMergePolicy policy)
Sets a merge policy for the field with the specified index.
void setDefaultValueDefinition(int index, const QgsDefaultValue &definition)
Sets the definition of the expression to use when calculating the default value for a field.
void setEditFormConfig(const QgsEditFormConfig &editFormConfig)
Sets the editFormConfig (configuration) of the form used to represent this vector layer.
void setEditorWidgetSetup(int index, const QgsEditorWidgetSetup &setup)
Sets the editor widget setup for the field at the specified index.
void setConstraintExpression(int index, const QString &expression, const QString &description=QString())
Sets the constraint expression for the specified field index.
void setFieldDuplicatePolicy(int index, Qgis::FieldDuplicatePolicy policy)
Sets a duplicate policy for the field with the specified index.
Q_INVOKABLE void setFieldAlias(int index, const QString &aliasString)
Sets an alias (a display name) for attributes to display in dialogs.
void updatedFields()
Emitted whenever the fields available from this layer have been changed.
QgsEditFormConfig editFormConfig
void setFieldSplitPolicy(int index, Qgis::FieldDomainSplitPolicy policy)
Sets a split policy for the field with the specified index.
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
void readXml(const QDomNode &node)
Reads configuration from node.
Holds the configuration for a field.
Qgis::FieldDuplicatePolicy mDuplicatePolicy
QMap< QString, QVariant > mEditorWidgetConfig
Qgis::FieldDomainSplitPolicy mSplitPolicy
Qgis::FieldDomainMergePolicy mMergePolicy
Qgis::AttributeFormReuseLastValuePolicy mReuseLastValuePolicy