QGIS API Documentation 3.99.0-Master (26c88405ac0)
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 "qgsattributeformcontaineredit.h"
25#include "qgsattributetypedialog.h"
26#include "qgsattributewidgetedit.h"
27#include "qgscodeeditor.h"
30#include "qgsfieldcombobox.h"
31#include "qgsgui.h"
33#include "qgsxmlutils.h"
34
35#include "moc_qgsattributesformproperties.cpp"
36
37#ifdef ENABLE_MODELTEST
38#include "modeltest.h"
39#endif
40
41const QgsSettingsEntryBool *QgsAttributesFormProperties::settingShowAliases = new QgsSettingsEntryBool( QStringLiteral( "show-aliases" ), sTreeAttributesForm, false, QStringLiteral( "Whether to show aliases (true) or names (false) in both the Available Widgets and the Form Layout panels." ) );
42
44 : QWidget( parent )
45 , mLayer( layer )
46{
47 if ( !layer )
48 return;
49
50 setupUi( this );
51
52 mEditorLayoutComboBox->addItem( tr( "Autogenerate" ), QVariant::fromValue( Qgis::AttributeFormLayout::AutoGenerated ) );
53 mEditorLayoutComboBox->addItem( tr( "Drag and Drop Designer" ), QVariant::fromValue( Qgis::AttributeFormLayout::DragAndDrop ) );
54 mEditorLayoutComboBox->addItem( tr( "Provide ui-file" ), QVariant::fromValue( Qgis::AttributeFormLayout::UiFile ) );
55 mShowAliasesButton->setChecked( settingShowAliases->value() );
56
57 // available widgets tree
58 QGridLayout *availableWidgetsWidgetLayout = new QGridLayout;
60 availableWidgetsWidgetLayout->addWidget( mAvailableWidgetsView );
61 availableWidgetsWidgetLayout->setContentsMargins( 0, 0, 0, 0 );
62 mAvailableWidgetsWidget->setLayout( availableWidgetsWidgetLayout );
63 mAvailableWidgetsView->setContextMenuPolicy( Qt::CustomContextMenu );
64
65 // we need a custom item delegate in order to draw indicators
66 mAvailableWidgetsView->setItemDelegate( new QgsAttributesFormTreeViewItemDelegate( mAvailableWidgetsView ) );
67 mAvailableWidgetsView->setStyle( new QgsAttributesFormTreeViewProxyStyle( mAvailableWidgetsView ) );
68
69 mAvailableWidgetsModel = new QgsAttributesAvailableWidgetsModel( mLayer, QgsProject().instance(), this );
70 mAvailableWidgetsProxyModel = new QgsAttributesFormProxyModel( this );
71 mAvailableWidgetsProxyModel->setAttributesFormSourceModel( mAvailableWidgetsModel );
72 mAvailableWidgetsProxyModel->setRecursiveFilteringEnabled( true );
73 mAvailableWidgetsView->setModel( mAvailableWidgetsProxyModel );
74
75 mConstraintIndicatorProviderAvailableWidgets = new QgsFieldConstraintIndicatorProvider( mAvailableWidgetsView ); // gets parented to the available widgets view
76 mDefaultValueIndicatorProviderAvailableWidgets = new QgsFieldDefaultValueIndicatorProvider( mAvailableWidgetsView ); // gets parented to the available widgets view
77
78#ifdef ENABLE_MODELTEST
79 new ModelTest( mAvailableWidgetsProxyModel, this );
80#endif
81
82 // form layout tree
83 QGridLayout *formLayoutWidgetLayout = new QGridLayout;
85 formLayoutWidgetLayout->addWidget( mFormLayoutView );
86 formLayoutWidgetLayout->setContentsMargins( 0, 0, 0, 0 );
87 mFormLayoutWidget->setLayout( formLayoutWidgetLayout );
88
89 // we need a custom item delegate in order to draw indicators
90 mFormLayoutView->setItemDelegate( new QgsAttributesFormTreeViewItemDelegate( mFormLayoutView ) );
91 mFormLayoutView->setStyle( new QgsAttributesFormTreeViewProxyStyle( mFormLayoutView ) );
92
93 mFormLayoutModel = new QgsAttributesFormLayoutModel( mLayer, QgsProject().instance(), this );
94 mFormLayoutProxyModel = new QgsAttributesFormProxyModel( this );
95 mFormLayoutProxyModel->setAttributesFormSourceModel( mFormLayoutModel );
96 mFormLayoutProxyModel->setRecursiveFilteringEnabled( true );
97 mFormLayoutView->setModel( mFormLayoutProxyModel );
98
99 mConstraintIndicatorProviderFormLayout = new QgsFieldConstraintIndicatorProvider( mFormLayoutView ); // gets parented to the form layout view
100 mDefaultValueIndicatorProviderFormLayout = new QgsFieldDefaultValueIndicatorProvider( mFormLayoutView ); // gets parented to the form layout view
101
102#ifdef ENABLE_MODELTEST
103 new ModelTest( mFormLayoutProxyModel, this );
104#endif
105
106 connect( mAvailableWidgetsView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsAttributesFormProperties::onAttributeSelectionChanged );
107 connect( mFormLayoutView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsAttributesFormProperties::onFormLayoutSelectionChanged );
108
109 connect( mAvailableWidgetsView, &QWidget::customContextMenuRequested, this, &QgsAttributesFormProperties::onContextMenuRequested );
110
111 connect( mAddContainerButton, &QAbstractButton::clicked, this, &QgsAttributesFormProperties::addContainer );
112 connect( mRemoveLayoutItemButton, &QAbstractButton::clicked, this, &QgsAttributesFormProperties::removeTabOrGroupButton );
113 connect( mInvertSelectionButton, &QAbstractButton::clicked, this, &QgsAttributesFormProperties::onInvertSelectionButtonClicked );
114 connect( mShowAliasesButton, &QAbstractButton::toggled, this, &QgsAttributesFormProperties::toggleShowAliases );
115 connect( mEditorLayoutComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsAttributesFormProperties::mEditorLayoutComboBox_currentIndexChanged );
116 connect( pbnSelectEditForm, &QToolButton::clicked, this, &QgsAttributesFormProperties::pbnSelectEditForm_clicked );
117 connect( mTbInitCode, &QPushButton::clicked, this, &QgsAttributesFormProperties::mTbInitCode_clicked );
118
119 connect( mSearchLineEdit, &QgsFilterLineEdit::textChanged, this, &QgsAttributesFormProperties::updateFilteredItems );
120
121 connect( mLayer, &QgsVectorLayer::updatedFields, this, [this] {
122 if ( !mBlockUpdates )
123 updatedFields();
124 } );
125
126 // Context menu and children actions
127 mAvailableWidgetsContextMenu = new QMenu( this );
128 mActionCopyWidgetConfiguration = new QAction( tr( "Copy widget configuration" ), this );
129 mActionPasteWidgetConfiguration = new QAction( tr( "Paste widget configuration" ), this );
130
131 connect( mActionCopyWidgetConfiguration, &QAction::triggered, this, &QgsAttributesFormProperties::copyWidgetConfiguration );
132 connect( mActionPasteWidgetConfiguration, &QAction::triggered, this, &QgsAttributesFormProperties::pasteWidgetConfiguration );
133
134 mAvailableWidgetsContextMenu->addAction( mActionCopyWidgetConfiguration );
135 mAvailableWidgetsContextMenu->addAction( mActionPasteWidgetConfiguration );
136
137 mMessageBar = new QgsMessageBar();
138 mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
139 gridLayout->addWidget( mMessageBar, 0, 0 );
140
141 // Assign initial size to splitter widgets. By doing so, we can
142 // show an eventual horizontal scrollbar in the right-hand side panel
143 splitter->setSizes( { widget->minimumSizeHint().width(), 600 } );
144}
145
155
157{
158 mAvailableWidgetsView->setSortingEnabled( false );
159 mAvailableWidgetsView->setSelectionBehavior( QAbstractItemView::SelectRows );
160 mAvailableWidgetsView->setSelectionMode( QAbstractItemView::SelectionMode::ExtendedSelection );
161 mAvailableWidgetsView->setAcceptDrops( false );
162 mAvailableWidgetsView->setDragDropMode( QAbstractItemView::DragDropMode::DragOnly );
163
164 mAvailableWidgetsModel->populate();
165 mAvailableWidgetsModel->setShowAliases( settingShowAliases->value() );
166 mAvailableWidgetsView->expandAll();
167}
168
170{
171 // tabs and groups info
172 mFormLayoutView->setSortingEnabled( false );
173 mFormLayoutView->setSelectionBehavior( QAbstractItemView::SelectRows );
174 mFormLayoutView->setSelectionMode( QAbstractItemView::SelectionMode::ExtendedSelection );
175 mFormLayoutView->setAcceptDrops( true );
176 mFormLayoutView->setDragDropMode( QAbstractItemView::DragDropMode::DragDrop );
177 mFormLayoutView->setDefaultDropAction( Qt::MoveAction );
178
179 mFormLayoutView->selectionModel()->clear();
180 mFormLayoutModel->populate();
181 mFormLayoutModel->setShowAliases( settingShowAliases->value() );
182 mFormLayoutView->expandAll();
183}
184
185
187{
189 {
190 mFormSuppressCmbBx->addItem( tr( "Hide Form on Add Feature (global settings)" ), QVariant::fromValue( Qgis::AttributeFormSuppression::Default ) );
191 }
192 else
193 {
194 mFormSuppressCmbBx->addItem( tr( "Show Form on Add Feature (global settings)" ), QVariant::fromValue( Qgis::AttributeFormSuppression::Default ) );
195 }
196 mFormSuppressCmbBx->addItem( tr( "Hide Form on Add Feature" ), QVariant::fromValue( Qgis::AttributeFormSuppression::On ) );
197 mFormSuppressCmbBx->addItem( tr( "Show Form on Add Feature" ), QVariant::fromValue( Qgis::AttributeFormSuppression::Off ) );
198
199 mFormSuppressCmbBx->setCurrentIndex( mFormSuppressCmbBx->findData( QVariant::fromValue( mLayer->editFormConfig().suppress() ) ) );
200}
201
202void QgsAttributesFormProperties::initAvailableWidgetsActions( const QList< QgsAction > actions )
203{
204 mAvailableWidgetsModel->populateLayerActions( actions );
205}
206
213
215{
216 mEditorLayoutComboBox->setCurrentIndex( mEditorLayoutComboBox->findData( QVariant::fromValue( mLayer->editFormConfig().layout() ) ) );
217
218 mEditorLayoutComboBox_currentIndexChanged( mEditorLayoutComboBox->currentIndex() );
219
220 const QgsEditFormConfig cfg = mLayer->editFormConfig();
221 mEditFormLineEdit->setText( cfg.uiForm() );
222}
223
225{
226 const QgsEditFormConfig cfg = mLayer->editFormConfig();
227
228 mInitCodeSource = cfg.initCodeSource();
229 mInitFunction = cfg.initFunction();
230 mInitFilePath = cfg.initFilePath();
231 mInitCode = cfg.initCode();
232
233 if ( mInitCode.isEmpty() )
234 {
235 mInitCode.append( tr( "# -*- coding: utf-8 -*-\n\"\"\"\n"
236 "QGIS forms can have a Python function that is called when the form is\n"
237 "opened.\n"
238 "\n"
239 "Use this function to add extra logic to your forms.\n"
240 "\n"
241 "Enter the name of the function in the \"Python Init function\"\n"
242 "field.\n"
243 "An example follows:\n"
244 "\"\"\"\n"
245 "from qgis.PyQt.QtWidgets import QWidget\n\n"
246 "def my_form_open(dialog, layer, feature):\n"
247 " geom = feature.geometry()\n"
248 " control = dialog.findChild(QWidget, \"MyLineEdit\")\n" ) );
249 }
250}
251
252void QgsAttributesFormProperties::loadAttributeTypeDialog()
253{
254 if ( mAvailableWidgetsView->selectionModel()->selectedRows( 0 ).count() != 1 )
255 return;
256
257 const QModelIndex index = mAvailableWidgetsView->firstSelectedIndex();
258
260 const QString fieldName = mAvailableWidgetsModel->data( index, QgsAttributesFormModel::ItemNameRole ).toString();
261 const int fieldIndex = mLayer->fields().indexOf( fieldName );
262
263 if ( fieldIndex < 0 )
264 return;
265
266 mAttributeTypeDialog = new QgsAttributeTypeDialog( mLayer, fieldIndex, mAttributeTypeFrame );
267
268 loadAttributeTypeDialogFromConfiguration( cfg );
269
270 mAttributeTypeDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
271 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
272
273 mAttributeTypeFrame->layout()->addWidget( mAttributeTypeDialog );
274}
275
276void QgsAttributesFormProperties::loadAttributeTypeDialogFromConfiguration( const QgsAttributesFormData::FieldConfig &config )
277{
278 const QgsFieldConstraints constraints = config.mFieldConstraints;
279
280 mAttributeTypeDialog->setAlias( config.mAlias );
281 mAttributeTypeDialog->setDataDefinedProperties( config.mDataDefinedProperties );
282 mAttributeTypeDialog->setComment( config.mComment );
283 mAttributeTypeDialog->setFieldEditable( config.mEditable );
284 mAttributeTypeDialog->setLabelOnTop( config.mLabelOnTop );
285 mAttributeTypeDialog->setReuseLastValuePolicy( config.mReuseLastValuePolicy );
290 mAttributeTypeDialog->setSplitPolicy( config.mSplitPolicy );
291 mAttributeTypeDialog->setDuplicatePolicy( config.mDuplicatePolicy );
292 mAttributeTypeDialog->setMergePolicy( config.mMergePolicy );
293 mAttributeTypeDialog->setDefaultValueExpression( config.mDefaultValueExpression );
294 mAttributeTypeDialog->setApplyDefaultValueOnUpdate( config.mApplyDefaultValueOnUpdate );
295
298 providerConstraints |= QgsFieldConstraints::ConstraintNotNull;
300 providerConstraints |= QgsFieldConstraints::ConstraintUnique;
302 providerConstraints |= QgsFieldConstraints::ConstraintExpression;
303 mAttributeTypeDialog->setProviderConstraints( providerConstraints );
304
305 mAttributeTypeDialog->setConstraintExpression( constraints.constraintExpression() );
306 mAttributeTypeDialog->setConstraintExpressionDescription( constraints.constraintDescription() );
308
309 // Make sure the widget is refreshed, even if
310 // the new widget type matches the current one
311 mAttributeTypeDialog->setEditorWidgetConfig( config.mEditorWidgetConfig );
312 mAttributeTypeDialog->setEditorWidgetType( config.mEditorWidgetType, true );
313}
314
315void QgsAttributesFormProperties::storeAttributeTypeDialog()
316{
318 return;
319
320 if ( mAttributeTypeDialog->fieldIdx() < 0 || mAttributeTypeDialog->fieldIdx() >= mLayer->fields().count() )
321 return;
322
323 QgsAttributesFormData::FieldConfig cfg;
324
325 cfg.mComment = mLayer->fields().at( mAttributeTypeDialog->fieldIdx() ).comment();
326 cfg.mEditable = mAttributeTypeDialog->fieldEditable();
327 cfg.mLabelOnTop = mAttributeTypeDialog->labelOnTop();
328 cfg.mReuseLastValuePolicy = mAttributeTypeDialog->reuseLastValuePolicy();
329 cfg.mAlias = mAttributeTypeDialog->alias();
330 cfg.mDataDefinedProperties = mAttributeTypeDialog->dataDefinedProperties();
331
332 QgsFieldConstraints constraints;
333 if ( mAttributeTypeDialog->notNull() )
334 {
336 }
337 else if ( mAttributeTypeDialog->notNullFromProvider() )
338 {
340 }
341
342 if ( mAttributeTypeDialog->unique() )
343 {
345 }
346 else if ( mAttributeTypeDialog->uniqueFromProvider() )
347 {
349 }
350
351 if ( !mAttributeTypeDialog->constraintExpression().isEmpty() )
352 {
354 }
355
356 constraints.setConstraintExpression( mAttributeTypeDialog->constraintExpression(), mAttributeTypeDialog->constraintExpressionDescription() );
357
361
362 // The call to mLayer->setDefaultValueDefinition will possibly emit updatedFields
363 // which will set mAttributeTypeDialog to nullptr so we need to store any value before calling it
364 cfg.mFieldConstraints = constraints;
365 cfg.mEditorWidgetType = mAttributeTypeDialog->editorWidgetType();
366 cfg.mEditorWidgetConfig = mAttributeTypeDialog->editorWidgetConfig();
367 cfg.mSplitPolicy = mAttributeTypeDialog->splitPolicy();
368 cfg.mDuplicatePolicy = mAttributeTypeDialog->duplicatePolicy();
369 cfg.mMergePolicy = mAttributeTypeDialog->mergePolicy();
370
371 cfg.mApplyDefaultValueOnUpdate = mAttributeTypeDialog->applyDefaultValueOnUpdate();
372 cfg.mDefaultValueExpression = mAttributeTypeDialog->defaultValueExpression();
373
374 const int fieldIndex = mAttributeTypeDialog->fieldIdx();
375 const QString fieldName = mLayer->fields().at( fieldIndex ).name();
376
377 QModelIndex index = mAvailableWidgetsModel->fieldModelIndex( fieldName );
378 if ( index.isValid() )
379 {
380 mAvailableWidgetsModel->setData( index, QVariant::fromValue<QgsAttributesFormData::FieldConfig>( cfg ), QgsAttributesFormModel::ItemFieldConfigRole );
381 mAvailableWidgetsModel->setData( index, mAttributeTypeDialog->alias(), QgsAttributesFormModel::ItemDisplayRole );
382 }
383
384 // Save field config to each matching field item in Form Layout model
385 mFormLayoutModel->updateFieldConfigForFieldItems( fieldName, cfg );
386
387 // Save alias to each matching field item in Form Layout model
388 mFormLayoutModel->updateAliasForFieldItems( fieldName, mAttributeTypeDialog->alias() );
389}
390
391void QgsAttributesFormProperties::storeAttributeWidgetEdit()
392{
394 return;
395
396 if ( mFormLayoutView->selectionModel()->selectedRows().count() != 1 )
397 return;
398
399 QModelIndex index = mFormLayoutView->firstSelectedIndex();
400 storeAttributeWidgetEdit( index );
401}
402
403void QgsAttributesFormProperties::storeAttributeWidgetEdit( const QModelIndex &index )
404{
406 return;
407
408 if ( !index.isValid() )
409 return;
410
411 auto itemData = index.data( QgsAttributesFormLayoutModel::ItemDataRole ).value< QgsAttributesFormData::AttributeFormItemData >();
412 mAttributeWidgetEdit->updateItemData( itemData );
413
415 {
416 QgsAttributesFormData::RelationEditorConfiguration config = mAttributeWidgetEdit->updatedRelationConfiguration();
417 itemData.setRelationEditorConfiguration( config );
418 mFormLayoutModel->setData( index, config.label, QgsAttributesFormLayoutModel::ItemDisplayRole );
419 }
420 mFormLayoutModel->setData( index, itemData, QgsAttributesFormLayoutModel::ItemDataRole );
421}
422
423void QgsAttributesFormProperties::loadAttributeWidgetEdit()
424{
425 if ( mFormLayoutView->selectionModel()->selectedRows().count() != 1 )
426 return;
427
428 const QModelIndex currentIndex = mFormLayoutView->firstSelectedIndex();
429 const QgsAttributesFormData::AttributeFormItemData itemData = currentIndex.data( QgsAttributesFormModel::ItemDataRole ).value< QgsAttributesFormData::AttributeFormItemData >();
430 mAttributeWidgetEdit = new QgsAttributeWidgetEdit( itemData, this );
432 {
433 mAttributeWidgetEdit->setRelationSpecificWidget( itemData.relationEditorConfiguration(), currentIndex.data( QgsAttributesFormModel::ItemIdRole ).toString() );
434 }
435 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
436 mAttributeTypeFrame->layout()->addWidget( mAttributeWidgetEdit );
437}
438
439void QgsAttributesFormProperties::loadInfoWidget( const QString &infoText )
440{
441 mInfoTextWidget = new QLabel( infoText );
442 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
443 mAttributeTypeFrame->layout()->addWidget( mInfoTextWidget );
444}
445
446void QgsAttributesFormProperties::storeAttributeContainerEdit()
447{
449 return;
450
451 if ( mFormLayoutView->selectionModel()->selectedRows().count() != 1 )
452 return;
453
454 const QModelIndex currentIndex = mFormLayoutView->firstSelectedIndex();
455 storeAttributeContainerEdit( currentIndex );
456}
457
458void QgsAttributesFormProperties::storeAttributeContainerEdit( const QModelIndex &index )
459{
461 return;
462
463 if ( !index.isValid() )
464 return;
465
466 auto itemData = index.data( QgsAttributesFormModel::ItemDataRole ).value< QgsAttributesFormData::AttributeFormItemData >();
467 QString containerName;
468
469 mAttributeContainerEdit->updateItemData( itemData, containerName );
470 mFormLayoutModel->setData( index, itemData, QgsAttributesFormLayoutModel::ItemDataRole );
471 mFormLayoutModel->setData( index, containerName, QgsAttributesFormLayoutModel::ItemNameRole );
472}
473
474void QgsAttributesFormProperties::loadAttributeContainerEdit()
475{
476 if ( mFormLayoutView->selectionModel()->selectedRows().count() != 1 )
477 return;
478
479 const QModelIndex currentIndex = mFormLayoutView->firstSelectedIndex();
480 const QgsAttributesFormData::AttributeFormItemData itemData = currentIndex.data( QgsAttributesFormModel::ItemDataRole ).value< QgsAttributesFormData::AttributeFormItemData >();
481 mAttributeContainerEdit = new QgsAttributeFormContainerEdit( itemData, mLayer, this );
482 mAttributeContainerEdit->setTitle( currentIndex.data( QgsAttributesFormModel::ItemNameRole ).toString() );
483 mAttributeContainerEdit->setUpContainerTypeComboBox( !currentIndex.parent().isValid(), itemData.containerType() );
484
485 mAttributeContainerEdit->registerExpressionContextGenerator( this );
486 mAttributeContainerEdit->layout()->setContentsMargins( 0, 0, 0, 0 );
487 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
488 mAttributeTypeFrame->layout()->addWidget( mAttributeContainerEdit );
489}
490
491void QgsAttributesFormProperties::onAttributeSelectionChanged( const QItemSelection &, const QItemSelection & )
492{
493 disconnect( mFormLayoutView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsAttributesFormProperties::onFormLayoutSelectionChanged );
494
495 QModelIndex index;
496 if ( mFormLayoutView->selectionModel()->selectedRows( 0 ).count() == 1 )
497 {
498 // Go to the form layout view and store the single-selected index, as
499 // it will be used to store its current settings before being deselected
500 index = mFormLayoutView->firstSelectedIndex();
501 }
502
503 loadAttributeSpecificEditor( mAvailableWidgetsView, mFormLayoutView, index );
504 connect( mFormLayoutView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsAttributesFormProperties::onFormLayoutSelectionChanged );
505}
506
507void QgsAttributesFormProperties::onFormLayoutSelectionChanged( const QItemSelection &, const QItemSelection &deselected )
508{
509 // when the selection changes in the DnD layout, sync the main tree
510 disconnect( mAvailableWidgetsView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsAttributesFormProperties::onAttributeSelectionChanged );
511 QModelIndex index;
512 if ( deselected.indexes().count() == 1 )
513 {
514 index = mFormLayoutProxyModel->mapToSource( deselected.indexes().at( 0 ) );
515 }
516 else if ( deselected.indexes().count() == 0 && mFormLayoutView->selectionModel()->selectedIndexes().count() == 2 )
517 {
518 // There was 1 selected, it was not deselected, but instead a new item was added to selection
519 index = mFormLayoutView->firstSelectedIndex();
520 }
521
522 loadAttributeSpecificEditor( mFormLayoutView, mAvailableWidgetsView, index );
523 connect( mAvailableWidgetsView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsAttributesFormProperties::onAttributeSelectionChanged );
524}
525
526void QgsAttributesFormProperties::loadAttributeSpecificEditor( QgsAttributesFormBaseView *emitter, QgsAttributesFormBaseView *receiver, QModelIndex &deselectedFormLayoutIndex )
527{
528 const Qgis::AttributeFormLayout layout = mEditorLayoutComboBox->currentData().value<Qgis::AttributeFormLayout>();
529
531 {
532 storeAttributeWidgetEdit( deselectedFormLayoutIndex );
533 storeAttributeContainerEdit( deselectedFormLayoutIndex );
534 }
536 {
537 storeAttributeTypeDialog();
538 }
539
540 clearAttributeTypeFrame();
541
542 if ( emitter->selectionModel()->selectedRows( 0 ).count() != 1 )
543 {
544 receiver->clearSelection();
545 }
546 else
547 {
548 const QModelIndex index = emitter->firstSelectedIndex();
549 const auto indexType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
550 switch ( indexType )
551 {
553 {
556 {
557 loadAttributeWidgetEdit();
558 }
559 else
560 {
561 loadInfoWidget( tr( "This configuration is available in the Drag and Drop Designer" ) );
562 }
563 break;
564 }
566 {
569 {
570 loadAttributeWidgetEdit();
571 }
572 loadAttributeTypeDialog();
573 break;
574 }
576 {
577 receiver->clearSelection();
578 loadAttributeContainerEdit();
579 break;
580 }
582 {
584 const QgsAction action { mLayer->actions()->action( index.data( QgsAttributesFormModel::ItemIdRole ).toString() ) };
585 loadInfoWidget( action.html() );
586 break;
587 }
592 {
594 {
595 loadInfoWidget( tr( "This configuration is available with double-click in the Drag and Drop Designer" ) );
596 }
597 else
598 {
599 loadInfoWidget( tr( "This configuration is available with double-click in the Form Layout panel" ) );
600 }
601 receiver->clearSelection();
602 break;
603 }
605 {
606 receiver->clearSelection();
607 break;
608 }
609 }
610 }
611}
612
613void QgsAttributesFormProperties::clearAttributeTypeFrame()
614{
616 {
617 mAttributeTypeFrame->layout()->removeWidget( mAttributeWidgetEdit );
618 mAttributeWidgetEdit->deleteLater();
619 mAttributeWidgetEdit = nullptr;
620 }
622 {
623 mAttributeTypeFrame->layout()->removeWidget( mAttributeTypeDialog );
624 mAttributeTypeDialog->deleteLater();
625 mAttributeTypeDialog = nullptr;
626 }
628 {
629 mAttributeTypeFrame->layout()->removeWidget( mAttributeContainerEdit );
630 mAttributeContainerEdit->deleteLater();
631 mAttributeContainerEdit = nullptr;
632 }
633 if ( mInfoTextWidget )
634 {
635 mAttributeTypeFrame->layout()->removeWidget( mInfoTextWidget );
636 mInfoTextWidget->deleteLater();
637 mInfoTextWidget = nullptr;
638 }
639}
640
641void QgsAttributesFormProperties::onInvertSelectionButtonClicked( bool checked )
642{
643 Q_UNUSED( checked )
644 for ( int i = 0; i < mFormLayoutProxyModel->rowCount(); ++i )
645 {
646 QModelIndex index = mFormLayoutProxyModel->index( i, 0 );
647 mFormLayoutView->selectionModel()->select( index, QItemSelectionModel::Toggle );
648 }
649}
650
651void QgsAttributesFormProperties::toggleShowAliases( bool checked )
652{
653 settingShowAliases->setValue( checked );
654 mAvailableWidgetsModel->setShowAliases( checked );
655 mFormLayoutModel->setShowAliases( checked );
656}
657
658void QgsAttributesFormProperties::addContainer()
659{
660 QList<QgsAddAttributeFormContainerDialog::ContainerPair> existingContainerList = mFormLayoutModel->listOfContainers();
661
662 QModelIndex currentItem;
663 if ( mFormLayoutView->selectionModel()->selectedRows().count() > 0 )
664 currentItem = mFormLayoutView->firstSelectedIndex();
665
666 QgsAddAttributeFormContainerDialog dialog( mLayer, existingContainerList, currentItem, this );
667
668 if ( !dialog.exec() )
669 return;
670
671 const QString name = dialog.name();
672 QModelIndex parentContainerItem = dialog.parentContainerItem();
673
674 mFormLayoutModel->addContainer( parentContainerItem, name, dialog.columnCount(), dialog.containerType() );
675 if ( parentContainerItem.isValid() )
676 mFormLayoutView->setExpanded( parentContainerItem, true );
677}
678
679void QgsAttributesFormProperties::removeTabOrGroupButton()
680{
681 // deleting an item may delete any number of nested child items -- so we delete
682 // them one at a time and then see if there's any selection left
683 while ( true )
684 {
685 const QModelIndexList items = mFormLayoutView->selectionModel()->selectedRows();
686 if ( items.empty() )
687 break;
688
689 const QModelIndex item = mFormLayoutProxyModel->mapToSource( items.at( 0 ) );
690 mFormLayoutModel->removeRow( item.row(), item.parent() );
691 }
692}
693
694void QgsAttributesFormProperties::mEditorLayoutComboBox_currentIndexChanged( int )
695{
696 // Refresh the right-hand side panel: first, save selection to recover it later
697 const QItemSelection selection = mAvailableWidgetsView->selectionModel()->selection();
698 if ( selection.count() > 0 )
699 {
700 mAvailableWidgetsView->selectionModel()->clear();
701 }
702
703 if ( mFormLayoutView->selectionModel()->selectedRows().count() > 0 )
704 {
705 mFormLayoutView->selectionModel()->clear(); // Get rid of e.g., container selection
706 }
707
708 const Qgis::AttributeFormLayout layout = mEditorLayoutComboBox->currentData().value<Qgis::AttributeFormLayout>();
709 switch ( layout )
710 {
712 mFormLayoutWidget->setVisible( false );
713 mTreeViewHorizontalSpacer->changeSize( 0, 20, QSizePolicy::Fixed, QSizePolicy::Fixed );
714 mUiFileFrame->setVisible( false );
715 mAddContainerButton->setVisible( false );
716 mRemoveLayoutItemButton->setVisible( false );
717 mInvertSelectionButton->setVisible( false );
718
719 setAvailableWidgetsIndicatorProvidersEnabled( true );
720 setFormLayoutIndicatorProvidersEnabled( false );
721 break;
722
724 mFormLayoutWidget->setVisible( true );
725 mTreeViewHorizontalSpacer->changeSize( 6, 20, QSizePolicy::Fixed, QSizePolicy::Fixed );
726 mUiFileFrame->setVisible( false );
727 mAddContainerButton->setVisible( true );
728 mRemoveLayoutItemButton->setVisible( true );
729 mInvertSelectionButton->setVisible( true );
730
731 setAvailableWidgetsIndicatorProvidersEnabled( false );
732 setFormLayoutIndicatorProvidersEnabled( true );
733 break;
734
736 // ui file
737 mFormLayoutWidget->setVisible( false );
738 mTreeViewHorizontalSpacer->changeSize( 0, 20, QSizePolicy::Fixed, QSizePolicy::Fixed );
739 mUiFileFrame->setVisible( true );
740 mAddContainerButton->setVisible( false );
741 mRemoveLayoutItemButton->setVisible( false );
742 mInvertSelectionButton->setVisible( false );
743
744 setAvailableWidgetsIndicatorProvidersEnabled( true );
745 setFormLayoutIndicatorProvidersEnabled( false );
746 break;
747 }
748
749 // Get the selection back so that we refresh the right-hand side panel
750 if ( selection.count() > 0 )
751 {
752 mAvailableWidgetsView->selectionModel()->select( selection, QItemSelectionModel::Select );
753 }
754}
755
756void QgsAttributesFormProperties::mTbInitCode_clicked()
757{
758 QgsAttributesFormInitCode attributesFormInitCode;
759
760 attributesFormInitCode.setCodeSource( mInitCodeSource );
761 attributesFormInitCode.setInitCode( mInitCode );
762 attributesFormInitCode.setInitFilePath( mInitFilePath );
763 attributesFormInitCode.setInitFunction( mInitFunction );
764
765 if ( !attributesFormInitCode.exec() )
766 return;
767
768 mInitCodeSource = attributesFormInitCode.codeSource();
769 mInitCode = attributesFormInitCode.initCode();
770 mInitFilePath = attributesFormInitCode.initFilePath();
771 mInitFunction = attributesFormInitCode.initFunction();
772}
773
774void QgsAttributesFormProperties::pbnSelectEditForm_clicked()
775{
776 QgsSettings myQSettings;
777 const QString lastUsedDir = myQSettings.value( QStringLiteral( "style/lastUIDir" ), QDir::homePath() ).toString();
778 const QString uifilename = QFileDialog::getOpenFileName( this, tr( "Select edit form" ), lastUsedDir, tr( "UI file" ) + " (*.ui)" );
779
780 if ( uifilename.isNull() )
781 return;
782
783 const QFileInfo fi( uifilename );
784 myQSettings.setValue( QStringLiteral( "style/lastUIDir" ), fi.path() );
785 mEditFormLineEdit->setText( uifilename );
786}
787
789{
790 storeAttributeWidgetEdit();
791 storeAttributeContainerEdit();
792 storeAttributeTypeDialog();
793}
794
796{
797 mBlockUpdates++;
798 store();
799
800 QgsEditFormConfig editFormConfig = mLayer->editFormConfig();
801
802 const QModelIndex fieldContainer = mAvailableWidgetsModel->fieldContainer();
803 QModelIndex index;
804
805 for ( int i = 0; i < mAvailableWidgetsModel->rowCount( fieldContainer ); i++ )
806 {
807 index = mAvailableWidgetsModel->index( i, 0, fieldContainer );
809
810 const QString fieldName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
811 const int idx = mLayer->fields().indexOf( fieldName );
812
813 //continue in case field does not exist anymore
814 if ( idx < 0 )
815 continue;
816
817 editFormConfig.setReadOnly( idx, !cfg.mEditable );
818 editFormConfig.setLabelOnTop( idx, cfg.mLabelOnTop );
819 editFormConfig.setReuseLastValuePolicy( idx, cfg.mReuseLastValuePolicy );
820
821 if ( cfg.mDataDefinedProperties.count() > 0 )
822 {
823 editFormConfig.setDataDefinedFieldProperties( fieldName, cfg.mDataDefinedProperties );
824 }
825
826 mLayer->setEditorWidgetSetup( idx, QgsEditorWidgetSetup( cfg.mEditorWidgetType, cfg.mEditorWidgetConfig ) );
827
828 const QgsFieldConstraints constraints = cfg.mFieldConstraints;
829 mLayer->setConstraintExpression( idx, constraints.constraintExpression(), constraints.constraintDescription() );
831 {
833 }
834 else
835 {
836 mLayer->removeFieldConstraint( idx, QgsFieldConstraints::ConstraintNotNull );
837 }
839 {
841 }
842 else
843 {
844 mLayer->removeFieldConstraint( idx, QgsFieldConstraints::ConstraintUnique );
845 }
847 {
849 }
850 else
851 {
852 mLayer->removeFieldConstraint( idx, QgsFieldConstraints::ConstraintExpression );
853 }
854
855 mLayer->setFieldAlias( idx, cfg.mAlias );
856 mLayer->setFieldSplitPolicy( idx, cfg.mSplitPolicy );
857 mLayer->setFieldDuplicatePolicy( idx, cfg.mDuplicatePolicy );
858 mLayer->setFieldMergePolicy( idx, cfg.mMergePolicy );
859
860 mLayer->setDefaultValueDefinition( idx, QgsDefaultValue( cfg.mDefaultValueExpression, cfg.mApplyDefaultValueOnUpdate ) );
861 }
862
863 // // tabs and groups
864 editFormConfig.clearTabs();
865
866 for ( int t = 0; t < mFormLayoutModel->rowCount(); t++ )
867 {
868 QModelIndex index = mFormLayoutModel->index( t, 0 );
869 QgsAttributeEditorElement *editorElement { mFormLayoutModel->createAttributeEditorWidget( index, nullptr ) };
870 if ( editorElement )
871 editFormConfig.addTab( editorElement );
872 }
873
874 editFormConfig.setUiForm( mEditFormLineEdit->text() );
875
876 editFormConfig.setLayout( mEditorLayoutComboBox->currentData().value<Qgis::AttributeFormLayout>() );
877
878 editFormConfig.setInitCodeSource( mInitCodeSource );
879 editFormConfig.setInitFunction( mInitFunction );
880 editFormConfig.setInitFilePath( mInitFilePath );
881 editFormConfig.setInitCode( mInitCode );
882
883 editFormConfig.setSuppress( mFormSuppressCmbBx->currentData().value<Qgis::AttributeFormSuppression>() );
884
885 // write the legacy config of relation widgets to support settings read by the API
886 const QModelIndex relationContainer = mAvailableWidgetsModel->relationContainer();
887
888 for ( int i = 0; i < mAvailableWidgetsModel->rowCount( relationContainer ); i++ )
889 {
890 const QModelIndex relationIndex = mAvailableWidgetsModel->index( i, 0, relationContainer );
891
893 const auto indexType = static_cast< QgsAttributesFormData::AttributesFormItemType >( relationIndex.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
894 const QString indexId = relationIndex.data( QgsAttributesFormModel::ItemIdRole ).toString();
895
896 const QModelIndex layoutIndex = mFormLayoutModel->firstRecursiveMatchingModelIndex( indexType, indexId );
897 if ( layoutIndex.isValid() )
898 {
899 QVariantMap config;
900
902 config[QStringLiteral( "nm-rel" )] = tabIndexData.relationEditorConfiguration().nmRelationId;
903 config[QStringLiteral( "force-suppress-popup" )] = tabIndexData.relationEditorConfiguration().forceSuppressFormPopup;
904
905 editFormConfig.setWidgetConfig( indexId, config );
906 break;
907 }
908 }
909
910 mLayer->setEditFormConfig( editFormConfig );
911 mBlockUpdates--;
912}
913
914
915void QgsAttributesFormProperties::updatedFields()
916{
917 // Store configuration to insure changes made are kept after refreshing the list
918 QMap<QString, QgsAttributesFormData::FieldConfig> fieldConfigs;
919
920 const QModelIndex fieldContainerBefore = mAvailableWidgetsModel->fieldContainer();
921 QModelIndex index;
922
923 for ( int i = 0; i < mAvailableWidgetsModel->rowCount( fieldContainerBefore ); i++ )
924 {
925 index = mAvailableWidgetsModel->index( i, 0, fieldContainerBefore );
926 const QString fieldName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
928 fieldConfigs[fieldName] = config;
929 }
930
932
933 const QModelIndex fieldContainerAfter = mAvailableWidgetsModel->fieldContainer();
934
935 for ( int i = 0; i < mAvailableWidgetsModel->rowCount( fieldContainerAfter ); i++ )
936 {
937 index = mAvailableWidgetsModel->index( i, 0, fieldContainerAfter );
938 const QString fieldName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
939
940 if ( fieldConfigs.contains( fieldName ) )
941 {
942 mAvailableWidgetsModel->setData( index, fieldConfigs[fieldName], QgsAttributesFormModel::ItemFieldConfigRole );
943 mAvailableWidgetsModel->setData( index, fieldConfigs[fieldName].mAlias, QgsAttributesFormModel::ItemDisplayRole );
944 }
945 }
946}
947
948void QgsAttributesFormProperties::updateFilteredItems( const QString &filterText )
949{
950 const int availableWidgetsPreviousSelectionCount = mAvailableWidgetsView->selectionModel()->selectedRows().count();
951 const int formLayoutPreviousSelectionCount = mFormLayoutView->selectionModel()->selectedRows().count();
952
953 static_cast< QgsAttributesAvailableWidgetsView *>( mAvailableWidgetsView )->setFilterText( filterText );
954 mAvailableWidgetsView->expandAll();
955
956 static_cast< QgsAttributesFormLayoutView *>( mFormLayoutView )->setFilterText( filterText );
957 mFormLayoutView->expandAll();
958
959 // If there was no previous selection leave as is, since
960 // after a filter change no new selection may be added (only lost).
961 if ( !( availableWidgetsPreviousSelectionCount == 0 && formLayoutPreviousSelectionCount == 0 ) )
962 {
963 const int selectedAvailableWidgetItemCount = mAvailableWidgetsView->selectionModel()->selectedRows().count();
964 const int selectedFormLayoutItemCount = mFormLayoutView->selectionModel()->selectedRows().count();
965
966 if ( selectedAvailableWidgetItemCount == 0 && selectedFormLayoutItemCount == 0 )
967 {
968 // Clear right-hand side panel since all selected items have been filtered out
969 clearAttributeTypeFrame();
970 }
971 }
972}
973
974void QgsAttributesFormProperties::onContextMenuRequested( QPoint point )
975{
976 if ( mAvailableWidgetsView->selectionModel()->selectedRows().count() != 1 )
977 return;
978
979 QPoint globalPos = mAvailableWidgetsView->viewport()->mapToGlobal( point );
980
981 const QModelIndex index = mAvailableWidgetsView->indexAt( point );
982 const auto itemType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
983 if ( itemType == QgsAttributesFormData::Field )
984 {
985 const QClipboard *clipboard = QApplication::clipboard();
986 const QMimeData *mimeData = clipboard->mimeData();
987 if ( !mimeData )
988 return;
989
990 const bool pasteEnabled = mimeData->hasFormat( QStringLiteral( "application/x-qgsattributetabledesignerelementclipboard" ) );
991 mActionPasteWidgetConfiguration->setEnabled( pasteEnabled );
992 mAvailableWidgetsContextMenu->popup( globalPos );
993 }
994}
995
996void QgsAttributesFormProperties::copyWidgetConfiguration()
997{
998 if ( mAvailableWidgetsView->selectionModel()->selectedRows().count() != 1 )
999 return;
1000
1001 const QModelIndex index = mAvailableWidgetsView->firstSelectedIndex();
1002 const auto itemType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
1003
1004 if ( itemType != QgsAttributesFormData::Field )
1005 return;
1006
1007 const QString fieldName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
1008 const int fieldIndex = mLayer->fields().indexOf( fieldName );
1009
1010 if ( fieldIndex < 0 )
1011 return;
1012
1013 const QgsField field = mLayer->fields().field( fieldIndex );
1014
1015 // We'll copy everything but field aliases or comments
1016 QDomDocument doc;
1017 QDomElement documentElement = doc.createElement( QStringLiteral( "FormWidgetClipboard" ) );
1018 documentElement.setAttribute( QStringLiteral( "name" ), field.name() );
1019
1020 // Editor widget setup
1021 QgsEditorWidgetSetup widgetSetup = field.editorWidgetSetup();
1022
1023 QDomElement editWidgetElement = doc.createElement( QStringLiteral( "editWidget" ) );
1024 documentElement.appendChild( editWidgetElement );
1025 editWidgetElement.setAttribute( QStringLiteral( "type" ), widgetSetup.type() );
1026 QDomElement editWidgetConfigElement = doc.createElement( QStringLiteral( "config" ) );
1027
1028 editWidgetConfigElement.appendChild( QgsXmlUtils::writeVariant( widgetSetup.config(), doc ) );
1029 editWidgetElement.appendChild( editWidgetConfigElement );
1030
1031 // Split policy
1032 QDomElement splitPolicyElement = doc.createElement( QStringLiteral( "splitPolicy" ) );
1033 splitPolicyElement.setAttribute( QStringLiteral( "policy" ), qgsEnumValueToKey( field.splitPolicy() ) );
1034 documentElement.appendChild( splitPolicyElement );
1035
1036 // Duplicate policy
1037 QDomElement duplicatePolicyElement = doc.createElement( QStringLiteral( "duplicatePolicy" ) );
1038 duplicatePolicyElement.setAttribute( QStringLiteral( "policy" ), qgsEnumValueToKey( field.duplicatePolicy() ) );
1039 documentElement.appendChild( duplicatePolicyElement );
1040
1041 // Merge policy
1042 QDomElement mergePolicyElement = doc.createElement( QStringLiteral( "mergePolicy" ) );
1043 mergePolicyElement.setAttribute( QStringLiteral( "policy" ), qgsEnumValueToKey( field.mergePolicy() ) );
1044 documentElement.appendChild( mergePolicyElement );
1045
1046 // Default expressions
1047 QDomElement defaultElem = doc.createElement( QStringLiteral( "default" ) );
1048 defaultElem.setAttribute( QStringLiteral( "expression" ), field.defaultValueDefinition().expression() );
1049 defaultElem.setAttribute( QStringLiteral( "applyOnUpdate" ), field.defaultValueDefinition().applyOnUpdate() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
1050 documentElement.appendChild( defaultElem );
1051
1052 // Constraints
1053 QDomElement constraintElem = doc.createElement( QStringLiteral( "constraint" ) );
1054 constraintElem.setAttribute( QStringLiteral( "constraints" ), field.constraints().constraints() );
1055 constraintElem.setAttribute( QStringLiteral( "unique_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintUnique ) );
1056 constraintElem.setAttribute( QStringLiteral( "notnull_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintNotNull ) );
1057 constraintElem.setAttribute( QStringLiteral( "exp_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintExpression ) );
1058 documentElement.appendChild( constraintElem );
1059
1060 // Constraint expressions
1061 QDomElement constraintExpressionElem = doc.createElement( QStringLiteral( "constraintExpression" ) );
1062 constraintExpressionElem.setAttribute( QStringLiteral( "exp" ), field.constraints().constraintExpression() );
1063 constraintExpressionElem.setAttribute( QStringLiteral( "desc" ), field.constraints().constraintDescription() );
1064 documentElement.appendChild( constraintExpressionElem );
1065
1066 // Widget general settings
1068 {
1069 QDomElement widgetGeneralSettingsElem = doc.createElement( QStringLiteral( "widgetGeneralSettings" ) );
1070 widgetGeneralSettingsElem.setAttribute( QStringLiteral( "editable" ), mAttributeTypeDialog->fieldEditable() );
1071 widgetGeneralSettingsElem.setAttribute( QStringLiteral( "label_on_top" ), mAttributeTypeDialog->labelOnTop() );
1072 widgetGeneralSettingsElem.setAttribute( QStringLiteral( "reuse_last_value_policy" ), qgsEnumValueToKey( mAttributeTypeDialog->reuseLastValuePolicy() ) );
1073 documentElement.appendChild( widgetGeneralSettingsElem );
1074 }
1075
1076 // Widget display section
1078 {
1079 // Go for the corresponding form layout item and extract its display settings
1080 if ( mFormLayoutView->selectionModel()->selectedRows().count() != 1 )
1081 return;
1082
1083 const QModelIndex indexLayout = mFormLayoutView->firstSelectedIndex();
1084 const auto layoutData = indexLayout.data( QgsAttributesFormModel::ItemDataRole ).value< QgsAttributesFormData::AttributeFormItemData >();
1085
1086 QDomElement displayElement = doc.createElement( QStringLiteral( "widgetDisplay" ) );
1087 displayElement.setAttribute( QStringLiteral( "showLabel" ), layoutData.showLabel() );
1088 displayElement.setAttribute( QStringLiteral( "horizontalStretch" ), layoutData.horizontalStretch() );
1089 displayElement.setAttribute( QStringLiteral( "verticalStretch" ), layoutData.verticalStretch() );
1090 displayElement.appendChild( layoutData.labelStyle().writeXml( doc ) );
1091 documentElement.appendChild( displayElement );
1092 }
1093
1094 doc.appendChild( documentElement );
1095
1096 QMimeData *mimeData = new QMimeData;
1097 mimeData->setData( QStringLiteral( "application/x-qgsattributetabledesignerelementclipboard" ), doc.toByteArray() );
1098 QClipboard *clipboard = QApplication::clipboard();
1099 clipboard->setMimeData( mimeData );
1100}
1101
1102void QgsAttributesFormProperties::pasteWidgetConfiguration()
1103{
1104 if ( mAvailableWidgetsView->selectionModel()->selectedRows().count() != 1 )
1105 return;
1106
1107 QModelIndex index = mAvailableWidgetsView->firstSelectedIndex();
1108
1109 const QString fieldName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
1110 const int fieldIndex = mLayer->fields().indexOf( fieldName );
1111
1112 if ( fieldIndex < 0 )
1113 return;
1114
1115 // Get base config from target item and ovewrite settings when possible
1116 auto config = index.data( QgsAttributesFormModel::ItemFieldConfigRole ).value< QgsAttributesFormData::FieldConfig >();
1117
1118 QDomDocument doc;
1119 QClipboard *clipboard = QApplication::clipboard();
1120 const QMimeData *mimeData = clipboard->mimeData();
1121 if ( !mimeData )
1122 return;
1123
1124 if ( doc.setContent( mimeData->data( QStringLiteral( "application/x-qgsattributetabledesignerelementclipboard" ) ) ) )
1125 {
1126 QDomElement docElem = doc.documentElement();
1127 if ( docElem.tagName() != QLatin1String( "FormWidgetClipboard" ) )
1128 return;
1129
1130 // When pasting, the target item has already been selected and
1131 // has triggered attribute type dialog loading. Therefore, we'll
1132 // only overwrite GUI settings instead of destroying and recreating
1133 // the whole dialog.
1134
1135 // Editor widget configuration
1136 const QDomElement fieldWidgetElement = docElem.firstChildElement( QStringLiteral( "editWidget" ) );
1137 if ( !fieldWidgetElement.isNull() )
1138 {
1139 const QString widgetType = fieldWidgetElement.attribute( QStringLiteral( "type" ) );
1140
1141 // Only paste if source editor widget type is supported by target field
1142 const QgsEditorWidgetFactory *factory = QgsGui::editorWidgetRegistry()->factory( widgetType );
1143 if ( factory->supportsField( mLayer, fieldIndex ) )
1144 {
1145 const QDomElement configElement = fieldWidgetElement.firstChildElement( QStringLiteral( "config" ) );
1146 if ( !configElement.isNull() )
1147 {
1148 const QDomElement optionsElem = configElement.childNodes().at( 0 ).toElement();
1149 QVariantMap optionsMap = QgsXmlUtils::readVariant( optionsElem ).toMap();
1150 QgsReadWriteContext context;
1151 // translate widget configuration strings
1152 if ( widgetType == QLatin1String( "ValueRelation" ) )
1153 {
1154 optionsMap[QStringLiteral( "Value" )] = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fields:%2:valuerelationvalue" ).arg( mLayer->id(), fieldName ), optionsMap[QStringLiteral( "Value" )].toString() );
1155 }
1156 if ( widgetType == QLatin1String( "ValueMap" ) )
1157 {
1158 if ( optionsMap[QStringLiteral( "map" )].canConvert<QList<QVariant>>() )
1159 {
1160 QList<QVariant> translatedValueList;
1161 const QList<QVariant> valueList = optionsMap[QStringLiteral( "map" )].toList();
1162 for ( int i = 0, row = 0; i < valueList.count(); i++, row++ )
1163 {
1164 QMap<QString, QVariant> translatedValueMap;
1165 QString translatedKey = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fields:%2:valuemapdescriptions" ).arg( mLayer->id(), fieldName ), valueList[i].toMap().constBegin().key() );
1166 translatedValueMap.insert( translatedKey, valueList[i].toMap().constBegin().value() );
1167 translatedValueList.append( translatedValueMap );
1168 }
1169 optionsMap.insert( QStringLiteral( "map" ), translatedValueList );
1170 }
1171 }
1172 config.mEditorWidgetType = widgetType;
1173 config.mEditorWidgetConfig = optionsMap;
1174 }
1175 }
1176 else
1177 {
1178 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 );
1179 }
1180 }
1181
1182 // Split policy
1183 const QDomElement splitPolicyElement = docElem.firstChildElement( QStringLiteral( "splitPolicy" ) );
1184 if ( !splitPolicyElement.isNull() )
1185 {
1186 const Qgis::FieldDomainSplitPolicy policy = qgsEnumKeyToValue( splitPolicyElement.attribute( QStringLiteral( "policy" ) ), Qgis::FieldDomainSplitPolicy::Duplicate );
1187 config.mSplitPolicy = policy;
1188 }
1189
1190 // Duplicate policy
1191 const QDomElement duplicatePolicyElement = docElem.firstChildElement( QStringLiteral( "duplicatePolicy" ) );
1192 if ( !duplicatePolicyElement.isNull() )
1193 {
1194 const Qgis::FieldDuplicatePolicy policy = qgsEnumKeyToValue( duplicatePolicyElement.attribute( QStringLiteral( "policy" ) ), Qgis::FieldDuplicatePolicy::Duplicate );
1195 config.mDuplicatePolicy = policy;
1196 }
1197
1198 // Merge policy
1199 const QDomElement mergePolicyElement = docElem.firstChildElement( QStringLiteral( "mergePolicy" ) );
1200 if ( !mergePolicyElement.isNull() )
1201 {
1202 const Qgis::FieldDomainMergePolicy policy = qgsEnumKeyToValue( mergePolicyElement.attribute( QStringLiteral( "policy" ) ), Qgis::FieldDomainMergePolicy::DefaultValue );
1203 config.mMergePolicy = policy;
1204 }
1205
1206 // Default expressions
1207 const QDomElement defaultElement = docElem.firstChildElement( QStringLiteral( "default" ) );
1208 if ( !defaultElement.isNull() )
1209 {
1210 config.mDefaultValueExpression = defaultElement.attribute( QStringLiteral( "expression" ) );
1211 config.mApplyDefaultValueOnUpdate = defaultElement.attribute( QStringLiteral( "applyOnUpdate" ) ).toInt();
1212 }
1213
1214 // Constraints
1215 // take target field constraints as a basis
1216 QgsFieldConstraints fieldConstraints = config.mFieldConstraints;
1217 const QDomElement constraintElement = docElem.firstChildElement( QStringLiteral( "constraint" ) );
1218 if ( !constraintElement.isNull() )
1219 {
1220 const int intConstraints = constraintElement.attribute( QStringLiteral( "constraints" ), QStringLiteral( "0" ) ).toInt();
1221 QgsFieldConstraints::Constraints constraints = static_cast< QgsFieldConstraints::Constraints >( intConstraints );
1222
1223 // always keep provider constraints intact
1225 {
1226 if ( constraints & QgsFieldConstraints::ConstraintNotNull )
1228 else
1230 }
1232 {
1233 if ( constraints & QgsFieldConstraints::ConstraintUnique )
1235 else
1237 }
1239 {
1242 else
1244 }
1245
1246 const int uniqueStrength = constraintElement.attribute( QStringLiteral( "unique_strength" ), QStringLiteral( "1" ) ).toInt();
1247 const int notNullStrength = constraintElement.attribute( QStringLiteral( "notnull_strength" ), QStringLiteral( "1" ) ).toInt();
1248 const int expStrength = constraintElement.attribute( QStringLiteral( "exp_strength" ), QStringLiteral( "1" ) ).toInt();
1249
1253 }
1254
1255 // Constraint expressions
1256 // always keep provider constraints intact
1258 {
1259 const QDomElement constraintExpressionElement = docElem.firstChildElement( QStringLiteral( "constraintExpression" ) );
1260 if ( !constraintExpressionElement.isNull() )
1261 {
1262 QString expression = constraintExpressionElement.attribute( QStringLiteral( "exp" ), QString() );
1263 QString description = constraintExpressionElement.attribute( QStringLiteral( "desc" ), QString() );
1264 fieldConstraints.setConstraintExpression( expression, description );
1265 }
1266 }
1267 config.mFieldConstraints = fieldConstraints;
1268
1269 const QDomElement widgetGeneralSettingsElement = docElem.firstChildElement( QStringLiteral( "widgetGeneralSettings" ) );
1270 if ( !widgetGeneralSettingsElement.isNull() )
1271 {
1272 const int editable = widgetGeneralSettingsElement.attribute( QStringLiteral( "editable" ), QStringLiteral( "0" ) ).toInt();
1274 if ( widgetGeneralSettingsElement.hasAttribute( QStringLiteral( "reuse_last_values" ) ) )
1275 {
1276 reusePolicy = widgetGeneralSettingsElement.attribute( QStringLiteral( "reuse_last_values" ), QStringLiteral( "0" ) ).toInt() == 1 ? Qgis::AttributeFormReuseLastValuePolicy::AllowedDefaultOn : Qgis::AttributeFormReuseLastValuePolicy::NotAllowed;
1277 }
1278 else
1279 {
1280 reusePolicy = qgsEnumKeyToValue( widgetGeneralSettingsElement.attribute( QStringLiteral( "reuse_last_values" ) ), Qgis::AttributeFormReuseLastValuePolicy::NotAllowed );
1281 }
1282 const int labelOnTop = widgetGeneralSettingsElement.attribute( QStringLiteral( "label_on_top" ), QStringLiteral( "0" ) ).toInt();
1283
1284 config.mEditable = editable;
1285 config.mReuseLastValuePolicy = reusePolicy;
1286 config.mLabelOnTop = labelOnTop;
1287 }
1288
1289 loadAttributeTypeDialogFromConfiguration( config );
1290
1291 // Widget display section
1293 {
1294 const QDomElement displayElement = docElem.firstChildElement( QStringLiteral( "widgetDisplay" ) );
1295 if ( !displayElement.isNull() )
1296 {
1297 const int showLabel = displayElement.attribute( QStringLiteral( "showLabel" ), QStringLiteral( "0" ) ).toInt();
1298 const int horizontalStretch = displayElement.attribute( QStringLiteral( "horizontalStretch" ), QStringLiteral( "0" ) ).toInt();
1299 const int verticalStretch = displayElement.attribute( QStringLiteral( "verticalStretch" ), QStringLiteral( "0" ) ).toInt();
1300 QgsAttributeEditorElement::LabelStyle style;
1301 style.readXml( displayElement );
1302
1303 // Update current GUI controls
1304 mAttributeWidgetEdit->setShowLabel( showLabel );
1305 mAttributeWidgetEdit->setHorizontalStretch( horizontalStretch );
1306 mAttributeWidgetEdit->setVerticalStretch( verticalStretch );
1307 mAttributeWidgetEdit->setLabelStyle( style );
1308 }
1309 }
1310 }
1311}
1312
1313void QgsAttributesFormProperties::setAvailableWidgetsIndicatorProvidersEnabled( bool enabled )
1314{
1315 // Only enable if the provider is disabled and only disable if it's enabled
1316 if ( enabled && !mDefaultValueIndicatorProviderAvailableWidgets->isEnabled() )
1317 {
1318 connect( mAvailableWidgetsModel, &QgsAttributesFormModel::fieldConfigDataChanged, mDefaultValueIndicatorProviderAvailableWidgets, &QgsFieldDefaultValueIndicatorProvider::updateItemIndicator );
1319 mDefaultValueIndicatorProviderAvailableWidgets->setEnabled( enabled );
1320 }
1321 else if ( !enabled && mDefaultValueIndicatorProviderAvailableWidgets->isEnabled() )
1322 {
1323 disconnect( mAvailableWidgetsModel, &QgsAttributesFormModel::fieldConfigDataChanged, mDefaultValueIndicatorProviderAvailableWidgets, &QgsFieldDefaultValueIndicatorProvider::updateItemIndicator );
1324 mDefaultValueIndicatorProviderAvailableWidgets->setEnabled( enabled );
1325 }
1326
1327 if ( enabled && !mConstraintIndicatorProviderAvailableWidgets->isEnabled() )
1328 {
1329 connect( mAvailableWidgetsModel, &QgsAttributesFormModel::fieldConfigDataChanged, mConstraintIndicatorProviderAvailableWidgets, &QgsFieldConstraintIndicatorProvider::updateItemIndicator );
1330 mConstraintIndicatorProviderAvailableWidgets->setEnabled( enabled );
1331 }
1332 else if ( !enabled && mConstraintIndicatorProviderAvailableWidgets->isEnabled() )
1333 {
1334 disconnect( mAvailableWidgetsModel, &QgsAttributesFormModel::fieldConfigDataChanged, mConstraintIndicatorProviderAvailableWidgets, &QgsFieldConstraintIndicatorProvider::updateItemIndicator );
1335 mConstraintIndicatorProviderAvailableWidgets->setEnabled( enabled );
1336 }
1337}
1338
1339void QgsAttributesFormProperties::setFormLayoutIndicatorProvidersEnabled( bool enabled )
1340{
1341 // Only enable if the provider is disabled and only disable if it's enabled
1342 if ( enabled && !mDefaultValueIndicatorProviderFormLayout->isEnabled() )
1343 {
1344 connect( mFormLayoutModel, &QgsAttributesFormModel::fieldConfigDataChanged, mDefaultValueIndicatorProviderFormLayout, &QgsFieldDefaultValueIndicatorProvider::updateItemIndicator );
1345 mDefaultValueIndicatorProviderFormLayout->setEnabled( enabled );
1346 }
1347 else if ( !enabled && mDefaultValueIndicatorProviderFormLayout->isEnabled() )
1348 {
1349 disconnect( mFormLayoutModel, &QgsAttributesFormModel::fieldConfigDataChanged, mDefaultValueIndicatorProviderFormLayout, &QgsFieldDefaultValueIndicatorProvider::updateItemIndicator );
1350 mDefaultValueIndicatorProviderFormLayout->setEnabled( enabled );
1351 }
1352
1353 if ( enabled && !mConstraintIndicatorProviderFormLayout->isEnabled() )
1354 {
1355 connect( mFormLayoutModel, &QgsAttributesFormModel::fieldConfigDataChanged, mConstraintIndicatorProviderFormLayout, &QgsFieldConstraintIndicatorProvider::updateItemIndicator );
1356 mConstraintIndicatorProviderFormLayout->setEnabled( enabled );
1357 }
1358 else if ( !enabled && mConstraintIndicatorProviderFormLayout->isEnabled() )
1359 {
1360 disconnect( mFormLayoutModel, &QgsAttributesFormModel::fieldConfigDataChanged, mConstraintIndicatorProviderFormLayout, &QgsFieldConstraintIndicatorProvider::updateItemIndicator );
1361 mConstraintIndicatorProviderFormLayout->setEnabled( enabled );
1362 }
1363}
AttributeFormReuseLastValuePolicy
Attribute form policy for reusing last entered values.
Definition qgis.h:5529
@ AllowedDefaultOn
Reuse of last values allowed and enabled by default.
Definition qgis.h:5531
@ NotAllowed
Reuse of last values not allowed.
Definition qgis.h:5530
AttributeFormSuppression
Available form types for layout of the attribute form editor.
Definition qgis.h:5500
@ On
Always suppress feature form.
Definition qgis.h:5502
@ Default
Use the application-wide setting.
Definition qgis.h:5501
@ Off
Never suppress feature form.
Definition qgis.h:5503
AttributeFormLayout
Available form types for layout of the attribute form editor.
Definition qgis.h:5485
@ DragAndDrop
"Drag and drop" layout. Needs to be configured.
Definition qgis.h:5487
@ AutoGenerated
Autogenerate a simple tabular layout for the form.
Definition qgis.h:5486
@ UiFile
Load a .ui file for the layout. Needs to be configured.
Definition qgis.h:5488
FieldDomainMergePolicy
Merge policy for field domains.
Definition qgis.h:3923
@ DefaultValue
Use default field value.
Definition qgis.h:3924
@ Warning
Warning message.
Definition qgis.h:158
FieldDomainSplitPolicy
Split policy for field domains.
Definition qgis.h:3906
@ Duplicate
Duplicate original value.
Definition qgis.h:3908
FieldDuplicatePolicy
Duplicate policy for fields.
Definition qgis.h:3943
@ Duplicate
Duplicate original value.
Definition qgis.h:3945
QString html() const
Returns an HTML table with the basic information about this action.
An abstract base class for any elements of a drag and drop form.
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.
Main class to store and transfer editor data contained in a QgsAttributesFormModel.
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
QgsAttributesFormProperties(QgsVectorLayer *layer, QWidget *parent=nullptr)
QgsAttributesFormBaseView * mAvailableWidgetsView
QgsAttributeTypeDialog * mAttributeTypeDialog
void store()
Stores currently opened widget configuration.
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.
Provides a container for managing client side default values for fields.
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.
Holder for the widget type and its configuration for a field.
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.
Stores information about constraints which may be present on a field.
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:63
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:762
Qgis::FieldDuplicatePolicy duplicatePolicy() const
Returns the field's duplicate policy, which indicates how field values should be handled during a dup...
Definition qgsfield.cpp:772
QgsDefaultValue defaultValueDefinition
Definition qgsfield.h:65
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:782
QgsFieldConstraints constraints
Definition qgsfield.h:66
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Definition qgsfield.cpp:747
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:106
A bar for displaying non-blocking messages to the user.
virtual QString translate(const QString &context, const QString &sourceText, const char *disambiguation=nullptr, int n=-1) const =0
Translates a string using the Qt QTranslator mechanism.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:109
int count() const
Returns the number of properties contained within the collection.
const QgsProjectTranslator * projectTranslator() const
Returns the project translator.
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.
Represents a vector layer which manages a vector based dataset.
void updatedFields()
Emitted whenever the fields available from this layer have been changed.
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:6817
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:6798
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