QGIS API Documentation 3.43.0-Master (69d1901085b)
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
16#include "qgsactionmanager.h"
17#include "qgsaddtaborgroup.h"
19#include "moc_qgsattributesformproperties.cpp"
20#include "qgsattributetypedialog.h"
21#include "qgsattributeformcontaineredit.h"
22#include "qgsattributewidgetedit.h"
24#include "qgsqmlwidgetwrapper.h"
26#include "qgsapplication.h"
27#include "qgscodeeditor.h"
28#include "qgscodeeditorhtml.h"
32#include "qgsgui.h"
35#include "qgsfieldcombobox.h"
36#include "qgsexpressionfinder.h"
38#include "qgshelp.h"
39#include "qgsxmlutils.h"
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 mAvailableWidgetsModel = new QgsAttributesAvailableWidgetsModel( mLayer, QgsProject().instance(), this );
66 mAvailableWidgetsView->setModel( mAvailableWidgetsModel );
67
68 // form layout tree
69 QGridLayout *formLayoutWidgetLayout = new QGridLayout;
71 mFormLayoutWidget->setLayout( formLayoutWidgetLayout );
72 formLayoutWidgetLayout->addWidget( mFormLayoutView );
73 formLayoutWidgetLayout->setContentsMargins( 0, 0, 0, 0 );
74
75 mFormLayoutModel = new QgsAttributesFormLayoutModel( mLayer, QgsProject().instance(), this );
76 mFormLayoutView->setModel( mFormLayoutModel );
77
78 connect( mAvailableWidgetsView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsAttributesFormProperties::onAttributeSelectionChanged );
79 connect( mFormLayoutView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsAttributesFormProperties::onFormLayoutSelectionChanged );
80
81 connect( mAvailableWidgetsView, &QWidget::customContextMenuRequested, this, &QgsAttributesFormProperties::onContextMenuRequested );
82
83 connect( mAddContainerButton, &QAbstractButton::clicked, this, &QgsAttributesFormProperties::addContainer );
84 connect( mRemoveLayoutItemButton, &QAbstractButton::clicked, this, &QgsAttributesFormProperties::removeTabOrGroupButton );
85 connect( mInvertSelectionButton, &QAbstractButton::clicked, this, &QgsAttributesFormProperties::onInvertSelectionButtonClicked );
86 connect( mShowAliasesButton, &QAbstractButton::toggled, this, &QgsAttributesFormProperties::toggleShowAliases );
87 connect( mEditorLayoutComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsAttributesFormProperties::mEditorLayoutComboBox_currentIndexChanged );
88 connect( pbnSelectEditForm, &QToolButton::clicked, this, &QgsAttributesFormProperties::pbnSelectEditForm_clicked );
89 connect( mTbInitCode, &QPushButton::clicked, this, &QgsAttributesFormProperties::mTbInitCode_clicked );
90
91
92 connect( mLayer, &QgsVectorLayer::updatedFields, this, [this] {
93 if ( !mBlockUpdates )
94 updatedFields();
95 } );
96
97 // Context menu and children actions
98 mAvailableWidgetsContextMenu = new QMenu( this );
99 mActionCopyWidgetConfiguration = new QAction( tr( "Copy widget configuration" ), this );
100 mActionPasteWidgetConfiguration = new QAction( tr( "Paste widget configuration" ), this );
101
102 connect( mActionCopyWidgetConfiguration, &QAction::triggered, this, &QgsAttributesFormProperties::copyWidgetConfiguration );
103 connect( mActionPasteWidgetConfiguration, &QAction::triggered, this, &QgsAttributesFormProperties::pasteWidgetConfiguration );
104
105 mAvailableWidgetsContextMenu->addAction( mActionCopyWidgetConfiguration );
106 mAvailableWidgetsContextMenu->addAction( mActionPasteWidgetConfiguration );
107
108 mMessageBar = new QgsMessageBar();
109 mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
110 gridLayout->addWidget( mMessageBar, 0, 0 );
111}
112
122
124{
125 mAvailableWidgetsView->setSortingEnabled( false );
126 mAvailableWidgetsView->setSelectionBehavior( QAbstractItemView::SelectRows );
127 mAvailableWidgetsView->setSelectionMode( QAbstractItemView::SelectionMode::ExtendedSelection );
128 mAvailableWidgetsView->setAcceptDrops( false );
129 mAvailableWidgetsView->setDragDropMode( QAbstractItemView::DragDropMode::DragOnly );
130
131 mAvailableWidgetsModel->populate();
132 mAvailableWidgetsModel->setShowAliases( settingShowAliases->value() );
133 mAvailableWidgetsView->expandAll();
134}
135
137{
138 // tabs and groups info
139 mFormLayoutView->setSortingEnabled( false );
140 mFormLayoutView->setSelectionBehavior( QAbstractItemView::SelectRows );
141 mFormLayoutView->setSelectionMode( QAbstractItemView::SelectionMode::ExtendedSelection );
142 mFormLayoutView->setAcceptDrops( true );
143 mFormLayoutView->setDragDropMode( QAbstractItemView::DragDropMode::DragDrop );
144 mFormLayoutView->setDefaultDropAction( Qt::MoveAction );
145
146 mFormLayoutView->selectionModel()->clear();
147 mFormLayoutModel->populate();
148 mFormLayoutModel->setShowAliases( settingShowAliases->value() );
149 mFormLayoutView->expandAll();
150}
151
152
154{
156 {
157 mFormSuppressCmbBx->addItem( tr( "Hide Form on Add Feature (global settings)" ), QVariant::fromValue( Qgis::AttributeFormSuppression::Default ) );
158 }
159 else
160 {
161 mFormSuppressCmbBx->addItem( tr( "Show Form on Add Feature (global settings)" ), QVariant::fromValue( Qgis::AttributeFormSuppression::Default ) );
162 }
163 mFormSuppressCmbBx->addItem( tr( "Hide Form on Add Feature" ), QVariant::fromValue( Qgis::AttributeFormSuppression::On ) );
164 mFormSuppressCmbBx->addItem( tr( "Show Form on Add Feature" ), QVariant::fromValue( Qgis::AttributeFormSuppression::Off ) );
165
166 mFormSuppressCmbBx->setCurrentIndex( mFormSuppressCmbBx->findData( QVariant::fromValue( mLayer->editFormConfig().suppress() ) ) );
167}
168
169void QgsAttributesFormProperties::initAvailableWidgetsActions( const QList< QgsAction > actions )
170{
171 mAvailableWidgetsModel->populateLayerActions( actions );
172}
173
180
182{
183 mEditorLayoutComboBox->setCurrentIndex( mEditorLayoutComboBox->findData( QVariant::fromValue( mLayer->editFormConfig().layout() ) ) );
184
185 mEditorLayoutComboBox_currentIndexChanged( mEditorLayoutComboBox->currentIndex() );
186
188 mEditFormLineEdit->setText( cfg.uiForm() );
189}
190
192{
194
195 mInitCodeSource = cfg.initCodeSource();
196 mInitFunction = cfg.initFunction();
197 mInitFilePath = cfg.initFilePath();
198 mInitCode = cfg.initCode();
199
200 if ( mInitCode.isEmpty() )
201 {
202 mInitCode.append( tr( "# -*- coding: utf-8 -*-\n\"\"\"\n"
203 "QGIS forms can have a Python function that is called when the form is\n"
204 "opened.\n"
205 "\n"
206 "Use this function to add extra logic to your forms.\n"
207 "\n"
208 "Enter the name of the function in the \"Python Init function\"\n"
209 "field.\n"
210 "An example follows:\n"
211 "\"\"\"\n"
212 "from qgis.PyQt.QtWidgets import QWidget\n\n"
213 "def my_form_open(dialog, layer, feature):\n"
214 " geom = feature.geometry()\n"
215 " control = dialog.findChild(QWidget, \"MyLineEdit\")\n" ) );
216 }
217}
218
219void QgsAttributesFormProperties::loadAttributeTypeDialog()
220{
221 if ( mAvailableWidgetsView->selectionModel()->selectedRows( 0 ).count() != 1 )
222 return;
223
224 const QModelIndex index = mAvailableWidgetsView->selectionModel()->selectedRows().at( 0 );
225
227 const QString fieldName = mAvailableWidgetsModel->data( index, QgsAttributesFormModel::ItemNameRole ).toString();
228 const int fieldIndex = mLayer->fields().indexOf( fieldName );
229
230 if ( fieldIndex < 0 )
231 return;
232
233 mAttributeTypeDialog = new QgsAttributeTypeDialog( mLayer, fieldIndex, mAttributeTypeFrame );
234
235 loadAttributeTypeDialogFromConfiguration( cfg );
236
237 mAttributeTypeDialog->setDefaultValueExpression( mLayer->defaultValueDefinition( fieldIndex ).expression() );
238 mAttributeTypeDialog->setApplyDefaultValueOnUpdate( mLayer->defaultValueDefinition( fieldIndex ).applyOnUpdate() );
239
240 mAttributeTypeDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
241 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
242
243 mAttributeTypeFrame->layout()->addWidget( mAttributeTypeDialog );
244}
245
246void QgsAttributesFormProperties::loadAttributeTypeDialogFromConfiguration( const QgsAttributesFormData::FieldConfig &config )
247{
248 const QgsFieldConstraints constraints = config.mFieldConstraints;
249
250 mAttributeTypeDialog->setAlias( config.mAlias );
251 mAttributeTypeDialog->setDataDefinedProperties( config.mDataDefinedProperties );
252 mAttributeTypeDialog->setComment( config.mComment );
253 mAttributeTypeDialog->setFieldEditable( config.mEditable );
254 mAttributeTypeDialog->setLabelOnTop( config.mLabelOnTop );
255 mAttributeTypeDialog->setReuseLastValues( config.mReuseLastValues );
260 mAttributeTypeDialog->setSplitPolicy( config.mSplitPolicy );
261 mAttributeTypeDialog->setDuplicatePolicy( config.mDuplicatePolicy );
262 mAttributeTypeDialog->setMergePolicy( config.mMergePolicy );
263
266 providerConstraints |= QgsFieldConstraints::ConstraintNotNull;
268 providerConstraints |= QgsFieldConstraints::ConstraintUnique;
270 providerConstraints |= QgsFieldConstraints::ConstraintExpression;
271 mAttributeTypeDialog->setProviderConstraints( providerConstraints );
272
273 mAttributeTypeDialog->setConstraintExpression( constraints.constraintExpression() );
274 mAttributeTypeDialog->setConstraintExpressionDescription( constraints.constraintDescription() );
276
277 // Make sure the widget is refreshed, even if
278 // the new widget type matches the current one
279 mAttributeTypeDialog->setEditorWidgetConfig( config.mEditorWidgetConfig );
280 mAttributeTypeDialog->setEditorWidgetType( config.mEditorWidgetType, true );
281}
282
283void QgsAttributesFormProperties::storeAttributeTypeDialog()
284{
286 return;
287
288 if ( mAttributeTypeDialog->fieldIdx() < 0 || mAttributeTypeDialog->fieldIdx() >= mLayer->fields().count() )
289 return;
290
292
293 cfg.mComment = mLayer->fields().at( mAttributeTypeDialog->fieldIdx() ).comment();
294 cfg.mEditable = mAttributeTypeDialog->fieldEditable();
295 cfg.mLabelOnTop = mAttributeTypeDialog->labelOnTop();
296 cfg.mReuseLastValues = mAttributeTypeDialog->reuseLastValues();
297 cfg.mAlias = mAttributeTypeDialog->alias();
298 cfg.mDataDefinedProperties = mAttributeTypeDialog->dataDefinedProperties();
299
300 QgsFieldConstraints constraints;
301 if ( mAttributeTypeDialog->notNull() )
302 {
304 }
305 else if ( mAttributeTypeDialog->notNullFromProvider() )
306 {
308 }
309
310 if ( mAttributeTypeDialog->unique() )
311 {
313 }
314 else if ( mAttributeTypeDialog->uniqueFromProvider() )
315 {
317 }
318
319 if ( !mAttributeTypeDialog->constraintExpression().isEmpty() )
320 {
322 }
323
324 constraints.setConstraintExpression( mAttributeTypeDialog->constraintExpression(), mAttributeTypeDialog->constraintExpressionDescription() );
325
329
330 // The call to mLayer->setDefaultValueDefinition will possibly emit updatedFields
331 // which will set mAttributeTypeDialog to nullptr so we need to store any value before calling it
332 cfg.mFieldConstraints = constraints;
333 cfg.mEditorWidgetType = mAttributeTypeDialog->editorWidgetType();
334 cfg.mEditorWidgetConfig = mAttributeTypeDialog->editorWidgetConfig();
335 cfg.mSplitPolicy = mAttributeTypeDialog->splitPolicy();
336 cfg.mDuplicatePolicy = mAttributeTypeDialog->duplicatePolicy();
337 cfg.mMergePolicy = mAttributeTypeDialog->mergePolicy();
338
339 const int fieldIndex = mAttributeTypeDialog->fieldIdx();
340 mLayer->setDefaultValueDefinition( fieldIndex, QgsDefaultValue( mAttributeTypeDialog->defaultValueExpression(), mAttributeTypeDialog->applyDefaultValueOnUpdate() ) );
341
342 const QString fieldName = mLayer->fields().at( fieldIndex ).name();
343
344 QModelIndex index = mAvailableWidgetsModel->fieldModelIndex( fieldName );
345 if ( index.isValid() )
346 {
347 mAvailableWidgetsModel->setData( index, QVariant::fromValue<QgsAttributesFormData::FieldConfig>( cfg ), QgsAttributesFormModel::ItemFieldConfigRole );
348 mAvailableWidgetsModel->setData( index, mAttributeTypeDialog->alias(), QgsAttributesFormModel::ItemDisplayRole );
349 }
350
351 // Save alias to each matching field item in Form Layout model
352 mFormLayoutModel->updateAliasForFieldItems( fieldName, mAttributeTypeDialog->alias() );
353}
354
355void QgsAttributesFormProperties::storeAttributeWidgetEdit()
356{
358 return;
359
360 if ( mFormLayoutView->selectionModel()->selectedRows().count() != 1 )
361 return;
362
363 QModelIndex index = mFormLayoutView->selectionModel()->selectedRows().at( 0 );
364 storeAttributeWidgetEdit( index );
365}
366
367void QgsAttributesFormProperties::storeAttributeWidgetEdit( const QModelIndex &index )
368{
370 return;
371
372 if ( !index.isValid() )
373 return;
374
376 mAttributeWidgetEdit->updateItemData( itemData );
377
379 {
380 QgsAttributesFormData::RelationEditorConfiguration config = mAttributeWidgetEdit->updatedRelationConfiguration();
381 itemData.setRelationEditorConfiguration( config );
382 mFormLayoutModel->setData( index, config.label, QgsAttributesFormLayoutModel::ItemDisplayRole );
383 }
384 mFormLayoutModel->setData( index, itemData, QgsAttributesFormLayoutModel::ItemDataRole );
385}
386
387void QgsAttributesFormProperties::loadAttributeWidgetEdit()
388{
389 if ( mFormLayoutView->selectionModel()->selectedRows().count() != 1 )
390 return;
391
392 const QModelIndex currentIndex = mFormLayoutView->selectionModel()->selectedRows().at( 0 );
394 mAttributeWidgetEdit = new QgsAttributeWidgetEdit( itemData, this );
396 {
397 mAttributeWidgetEdit->setRelationSpecificWidget( itemData.relationEditorConfiguration(), currentIndex.data( QgsAttributesFormModel::ItemIdRole ).toString() );
398 }
399 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
400 mAttributeTypeFrame->layout()->addWidget( mAttributeWidgetEdit );
401}
402
403void QgsAttributesFormProperties::loadInfoWidget( const QString &infoText )
404{
405 mInfoTextWidget = new QLabel( infoText );
406 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
407 mAttributeTypeFrame->layout()->addWidget( mInfoTextWidget );
408}
409
410void QgsAttributesFormProperties::storeAttributeContainerEdit()
411{
413 return;
414
415 if ( mFormLayoutView->selectionModel()->selectedRows().count() != 1 )
416 return;
417
418 const QModelIndex currentIndex = mFormLayoutView->selectionModel()->selectedRows().at( 0 );
419 storeAttributeContainerEdit( currentIndex );
420}
421
422void QgsAttributesFormProperties::storeAttributeContainerEdit( const QModelIndex &index )
423{
425 return;
426
427 if ( !index.isValid() )
428 return;
429
431 QString containerName;
432
433 mAttributeContainerEdit->updateItemData( itemData, containerName );
434 mFormLayoutModel->setData( index, itemData, QgsAttributesFormLayoutModel::ItemDataRole );
435 mFormLayoutModel->setData( index, containerName, QgsAttributesFormLayoutModel::ItemNameRole );
436}
437
438void QgsAttributesFormProperties::loadAttributeContainerEdit()
439{
440 if ( mFormLayoutView->selectionModel()->selectedRows().count() != 1 )
441 return;
442
443 const QModelIndex currentIndex = mFormLayoutView->selectionModel()->selectedRows().at( 0 );
445 mAttributeContainerEdit = new QgsAttributeFormContainerEdit( itemData, mLayer, this );
446 mAttributeContainerEdit->setTitle( currentIndex.data( QgsAttributesFormModel::ItemNameRole ).toString() );
447 mAttributeContainerEdit->setUpContainerTypeComboBox( !currentIndex.parent().isValid(), itemData.containerType() );
448
449 mAttributeContainerEdit->registerExpressionContextGenerator( this );
450 mAttributeContainerEdit->layout()->setContentsMargins( 0, 0, 0, 0 );
451 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
452 mAttributeTypeFrame->layout()->addWidget( mAttributeContainerEdit );
453}
454
455void QgsAttributesFormProperties::onAttributeSelectionChanged( const QItemSelection &, const QItemSelection & )
456{
457 disconnect( mFormLayoutView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsAttributesFormProperties::onFormLayoutSelectionChanged );
458
459 QModelIndex index;
460 if ( mFormLayoutView->selectionModel()->selectedRows( 0 ).count() == 1 )
461 {
462 // Go to the form layout view and store the single-selected index, as
463 // it will be used to store its current settings before being deselected
464 index = mFormLayoutView->selectionModel()->selectedIndexes().at( 0 );
465 }
466
467 loadAttributeSpecificEditor( mAvailableWidgetsView, mFormLayoutView, index );
468 connect( mFormLayoutView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsAttributesFormProperties::onFormLayoutSelectionChanged );
469}
470
471void QgsAttributesFormProperties::onFormLayoutSelectionChanged( const QItemSelection &, const QItemSelection &deselected )
472{
473 // when the selection changes in the DnD layout, sync the main tree
474 disconnect( mAvailableWidgetsView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsAttributesFormProperties::onAttributeSelectionChanged );
475 QModelIndex index;
476 if ( deselected.indexes().count() == 1 )
477 {
478 index = deselected.indexes().at( 0 );
479 }
480 else if ( deselected.indexes().count() == 0 && mFormLayoutView->selectionModel()->selectedIndexes().count() == 2 )
481 {
482 // There was 1 selected, it was not deselected, but instead a new item was added to selection
483 index = mFormLayoutView->selectionModel()->selectedIndexes().at( 0 );
484 }
485
486 loadAttributeSpecificEditor( mFormLayoutView, mAvailableWidgetsView, index );
487 connect( mAvailableWidgetsView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsAttributesFormProperties::onAttributeSelectionChanged );
488}
489
490void QgsAttributesFormProperties::loadAttributeSpecificEditor( QgsAttributesFormBaseView *emitter, QgsAttributesFormBaseView *receiver, QModelIndex &deselectedFormLayoutIndex )
491{
492 const Qgis::AttributeFormLayout layout = mEditorLayoutComboBox->currentData().value<Qgis::AttributeFormLayout>();
493
495 {
496 storeAttributeWidgetEdit( deselectedFormLayoutIndex );
497 storeAttributeContainerEdit( deselectedFormLayoutIndex );
498 }
500 {
501 storeAttributeTypeDialog();
502 }
503
504 clearAttributeTypeFrame();
505
506 if ( emitter->selectionModel()->selectedRows( 0 ).count() != 1 )
507 {
508 receiver->clearSelection();
509 }
510 else
511 {
512 const QModelIndex index = emitter->selectionModel()->selectedRows().at( 0 );
513 const auto indexType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
514 switch ( indexType )
515 {
517 {
520 {
521 loadAttributeWidgetEdit();
522 }
523 else
524 {
525 loadInfoWidget( tr( "This configuration is available in the Drag and Drop Designer" ) );
526 }
527 break;
528 }
530 {
533 {
534 loadAttributeWidgetEdit();
535 }
536 loadAttributeTypeDialog();
537 break;
538 }
540 {
541 receiver->clearSelection();
542 loadAttributeContainerEdit();
543 break;
544 }
546 {
548 const QgsAction action { mLayer->actions()->action( index.data( QgsAttributesFormModel::ItemIdRole ).toString() ) };
549 loadInfoWidget( action.html() );
550 break;
551 }
556 {
558 {
559 loadInfoWidget( tr( "This configuration is available with double-click in the Drag and Drop Designer" ) );
560 }
561 else
562 {
563 loadInfoWidget( tr( "This configuration is available with double-click in the Form Layout panel" ) );
564 }
565 receiver->clearSelection();
566 break;
567 }
569 {
570 receiver->clearSelection();
571 break;
572 }
573 }
574 }
575}
576
577void QgsAttributesFormProperties::clearAttributeTypeFrame()
578{
580 {
581 mAttributeTypeFrame->layout()->removeWidget( mAttributeWidgetEdit );
582 mAttributeWidgetEdit->deleteLater();
583 mAttributeWidgetEdit = nullptr;
584 }
586 {
587 mAttributeTypeFrame->layout()->removeWidget( mAttributeTypeDialog );
588 mAttributeTypeDialog->deleteLater();
589 mAttributeTypeDialog = nullptr;
590 }
592 {
593 mAttributeTypeFrame->layout()->removeWidget( mAttributeContainerEdit );
594 mAttributeContainerEdit->deleteLater();
595 mAttributeContainerEdit = nullptr;
596 }
597 if ( mInfoTextWidget )
598 {
599 mAttributeTypeFrame->layout()->removeWidget( mInfoTextWidget );
600 mInfoTextWidget->deleteLater();
601 mInfoTextWidget = nullptr;
602 }
603}
604
605void QgsAttributesFormProperties::onInvertSelectionButtonClicked( bool checked )
606{
607 Q_UNUSED( checked )
608 for ( int i = 0; i < mFormLayoutModel->rowCount(); ++i )
609 {
610 QModelIndex index = mFormLayoutModel->index( i, 0 );
611 mFormLayoutView->selectionModel()->select( index, QItemSelectionModel::Toggle );
612 }
613}
614
615void QgsAttributesFormProperties::toggleShowAliases( bool checked )
616{
617 settingShowAliases->setValue( checked );
618 mAvailableWidgetsModel->setShowAliases( checked );
619 mFormLayoutModel->setShowAliases( checked );
620}
621
622void QgsAttributesFormProperties::addContainer()
623{
624 QList<QgsAddAttributeFormContainerDialog::ContainerPair> existingContainerList = mFormLayoutModel->listOfContainers();
625
626 QModelIndex currentItem;
627 if ( mFormLayoutView->selectionModel()->selectedRows().count() > 0 )
628 currentItem = mFormLayoutView->selectionModel()->selectedRows().at( 0 );
629
630 QgsAddAttributeFormContainerDialog dialog( mLayer, existingContainerList, currentItem, this );
631
632 if ( !dialog.exec() )
633 return;
634
635 const QString name = dialog.name();
636 QModelIndex parentContainerItem = dialog.parentContainerItem();
637
638 mFormLayoutModel->addContainer( parentContainerItem, name, dialog.columnCount(), dialog.containerType() );
639 if ( parentContainerItem.isValid() )
640 mFormLayoutView->setExpanded( parentContainerItem, true );
641}
642
643void QgsAttributesFormProperties::removeTabOrGroupButton()
644{
645 // deleting a item may delete any number of nested child items -- so we delete
646 // them one at a time and then see if there's any selection left
647 while ( true )
648 {
649 const QModelIndexList items = mFormLayoutView->selectionModel()->selectedRows();
650 if ( items.empty() )
651 break;
652
653 const QModelIndex item = items.at( 0 );
654 mFormLayoutModel->removeRow( item.row(), item.parent() );
655 }
656}
657
658void QgsAttributesFormProperties::mEditorLayoutComboBox_currentIndexChanged( int )
659{
660 // Refresh the right panel. Save selection to recover it later.
661 const QItemSelection selection = mAvailableWidgetsView->selectionModel()->selection();
662 if ( selection.count() > 0 )
663 {
664 mAvailableWidgetsView->selectionModel()->clear();
665 }
666
667 if ( mFormLayoutView->selectionModel()->selectedRows().count() > 0 )
668 {
669 mFormLayoutView->selectionModel()->clear(); // Get rid of e.g., container selection
670 }
671
672 const Qgis::AttributeFormLayout layout = mEditorLayoutComboBox->currentData().value<Qgis::AttributeFormLayout>();
673 switch ( layout )
674 {
676 mFormLayoutWidget->setVisible( false );
677 mUiFileFrame->setVisible( false );
678 mAddContainerButton->setVisible( false );
679 mRemoveLayoutItemButton->setVisible( false );
680 mInvertSelectionButton->setVisible( false );
681 break;
682
684 mFormLayoutWidget->setVisible( true );
685 mUiFileFrame->setVisible( false );
686 mAddContainerButton->setVisible( true );
687 mRemoveLayoutItemButton->setVisible( true );
688 mInvertSelectionButton->setVisible( true );
689 break;
690
692 // ui file
693 mFormLayoutWidget->setVisible( false );
694 mUiFileFrame->setVisible( true );
695 mAddContainerButton->setVisible( false );
696 mRemoveLayoutItemButton->setVisible( false );
697 mInvertSelectionButton->setVisible( false );
698 break;
699 }
700
701 // Get the selection back so that we refresh the right panel
702 if ( selection.count() > 0 )
703 {
704 mAvailableWidgetsView->selectionModel()->select( selection, QItemSelectionModel::Select );
705 }
706}
707
708void QgsAttributesFormProperties::mTbInitCode_clicked()
709{
710 QgsAttributesFormInitCode attributesFormInitCode;
711
712 attributesFormInitCode.setCodeSource( mInitCodeSource );
713 attributesFormInitCode.setInitCode( mInitCode );
714 attributesFormInitCode.setInitFilePath( mInitFilePath );
715 attributesFormInitCode.setInitFunction( mInitFunction );
716
717 if ( !attributesFormInitCode.exec() )
718 return;
719
720 mInitCodeSource = attributesFormInitCode.codeSource();
721 mInitCode = attributesFormInitCode.initCode();
722 mInitFilePath = attributesFormInitCode.initFilePath();
723 mInitFunction = attributesFormInitCode.initFunction();
724}
725
726void QgsAttributesFormProperties::pbnSelectEditForm_clicked()
727{
728 QgsSettings myQSettings;
729 const QString lastUsedDir = myQSettings.value( QStringLiteral( "style/lastUIDir" ), QDir::homePath() ).toString();
730 const QString uifilename = QFileDialog::getOpenFileName( this, tr( "Select edit form" ), lastUsedDir, tr( "UI file" ) + " (*.ui)" );
731
732 if ( uifilename.isNull() )
733 return;
734
735 const QFileInfo fi( uifilename );
736 myQSettings.setValue( QStringLiteral( "style/lastUIDir" ), fi.path() );
737 mEditFormLineEdit->setText( uifilename );
738}
739
741{
742 storeAttributeWidgetEdit();
743 storeAttributeContainerEdit();
744 storeAttributeTypeDialog();
745}
746
748{
749 mBlockUpdates++;
750 store();
751
752 QgsEditFormConfig editFormConfig = mLayer->editFormConfig();
753
754 const QModelIndex fieldContainer = mAvailableWidgetsModel->fieldContainer();
755 QModelIndex index;
756
757 for ( int i = 0; i < mAvailableWidgetsModel->rowCount( fieldContainer ); i++ )
758 {
759 index = mAvailableWidgetsModel->index( i, 0, fieldContainer );
761
762 const QString fieldName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
763 const int idx = mLayer->fields().indexOf( fieldName );
764
765 //continue in case field does not exist anymore
766 if ( idx < 0 )
767 continue;
768
769 editFormConfig.setReadOnly( idx, !cfg.mEditable );
770 editFormConfig.setLabelOnTop( idx, cfg.mLabelOnTop );
771 editFormConfig.setReuseLastValue( idx, cfg.mReuseLastValues );
772
773 if ( cfg.mDataDefinedProperties.count() > 0 )
774 {
775 editFormConfig.setDataDefinedFieldProperties( fieldName, cfg.mDataDefinedProperties );
776 }
777
779
780 const QgsFieldConstraints constraints = cfg.mFieldConstraints;
781 mLayer->setConstraintExpression( idx, constraints.constraintExpression(), constraints.constraintDescription() );
783 {
785 }
786 else
787 {
789 }
791 {
793 }
794 else
795 {
797 }
799 {
801 }
802 else
803 {
805 }
806
807 mLayer->setFieldAlias( idx, cfg.mAlias );
811 }
812
813 // // tabs and groups
814 editFormConfig.clearTabs();
815
816 for ( int t = 0; t < mFormLayoutModel->rowCount(); t++ )
817 {
818 QModelIndex index = mFormLayoutModel->index( t, 0 );
819 QgsAttributeEditorElement *editorElement { mFormLayoutModel->createAttributeEditorWidget( index, nullptr ) };
820 if ( editorElement )
821 editFormConfig.addTab( editorElement );
822 }
823
824 editFormConfig.setUiForm( mEditFormLineEdit->text() );
825
826 editFormConfig.setLayout( mEditorLayoutComboBox->currentData().value<Qgis::AttributeFormLayout>() );
827
828 editFormConfig.setInitCodeSource( mInitCodeSource );
829 editFormConfig.setInitFunction( mInitFunction );
830 editFormConfig.setInitFilePath( mInitFilePath );
831 editFormConfig.setInitCode( mInitCode );
832
833 editFormConfig.setSuppress( mFormSuppressCmbBx->currentData().value<Qgis::AttributeFormSuppression>() );
834
835 // write the legacy config of relation widgets to support settings read by the API
836 const QModelIndex relationContainer = mAvailableWidgetsModel->relationContainer();
837
838 for ( int i = 0; i < mAvailableWidgetsModel->rowCount( relationContainer ); i++ )
839 {
840 const QModelIndex relationIndex = mAvailableWidgetsModel->index( i, 0, relationContainer );
841
843 const auto indexType = static_cast< QgsAttributesFormData::AttributesFormItemType >( relationIndex.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
844 const QString indexId = relationIndex.data( QgsAttributesFormModel::ItemIdRole ).toString();
845
846 const QModelIndex layoutIndex = mFormLayoutModel->firstRecursiveMatchingModelIndex( indexType, indexId );
847 if ( layoutIndex.isValid() )
848 {
849 QVariantMap config;
850
852 config[QStringLiteral( "nm-rel" )] = tabIndexData.relationEditorConfiguration().nmRelationId;
853 config[QStringLiteral( "force-suppress-popup" )] = tabIndexData.relationEditorConfiguration().forceSuppressFormPopup;
854
855 editFormConfig.setWidgetConfig( indexId, config );
856 break;
857 }
858 }
859
860 mLayer->setEditFormConfig( editFormConfig );
861 mBlockUpdates--;
862}
863
864
866 : QTreeView( parent )
867 , mLayer( layer )
868{
869}
870
872{
873 // To be used with Relations, fields and actions
874 const auto *model = static_cast< QgsAttributesFormModel * >( this->model() );
875 QModelIndex index = model->firstRecursiveMatchingModelIndex( itemType, itemId );
876
877 if ( index.isValid() )
878 {
879 // TODO: compare with eventual single selected index, if they match, avoid calling next line
880 selectionModel()->setCurrentIndex( index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
881 }
882 else
883 {
884 selectionModel()->clearSelection();
885 }
886}
887
900
901
906
907void QgsAttributesAvailableWidgetsView::setModel( QAbstractItemModel *model )
908{
909 mModel = qobject_cast<QgsAttributesAvailableWidgetsModel *>( model );
910 if ( !mModel )
911 return;
912
913 QTreeView::setModel( mModel );
914}
915
920
921
923 : QgsAttributesFormBaseView( layer, parent )
924{
925 connect( this, &QTreeView::doubleClicked, this, &QgsAttributesFormLayoutView::onItemDoubleClicked );
926}
927
928void QgsAttributesFormLayoutView::setModel( QAbstractItemModel *model )
929{
930 mModel = qobject_cast<QgsAttributesFormLayoutModel *>( model );
931 if ( !mModel )
932 return;
933
934 QTreeView::setModel( mModel );
935
936 connect( mModel, &QgsAttributesFormLayoutModel::externalItemDropped, this, &QgsAttributesFormLayoutView::handleExternalDroppedItem );
937 connect( mModel, &QgsAttributesFormLayoutModel::internalItemDropped, this, &QgsAttributesFormLayoutView::handleInternalDroppedItem );
938}
939
944
945void QgsAttributesFormLayoutView::handleExternalDroppedItem( QModelIndex &index )
946{
947 selectionModel()->setCurrentIndex( index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
948
949 const auto itemType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
950
951 if ( itemType == QgsAttributesFormData::QmlWidget
955 {
956 onItemDoubleClicked( index );
957 }
958}
959
960void QgsAttributesFormLayoutView::handleInternalDroppedItem( QModelIndex &index )
961{
962 selectionModel()->clearCurrentIndex();
963 const auto itemType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
964 if ( itemType == QgsAttributesFormData::Container )
965 {
966 expandRecursively( index );
967 }
968}
969
971{
972 const QMimeData *data = event->mimeData();
973
974 if ( data->hasFormat( QStringLiteral( "application/x-qgsattributesformavailablewidgetsrelement" ) )
975 || data->hasFormat( QStringLiteral( "application/x-qgsattributesformlayoutelement" ) ) )
976 {
977 // Inner drag and drop actions are always MoveAction
978 if ( event->source() == this )
979 {
980 event->setDropAction( Qt::MoveAction );
981 }
982 }
983 else
984 {
985 event->ignore();
986 }
987
988 QTreeView::dragEnterEvent( event );
989}
990
996{
997 const QMimeData *data = event->mimeData();
998
999 if ( data->hasFormat( QStringLiteral( "application/x-qgsattributesformavailablewidgetsrelement" ) )
1000 || data->hasFormat( QStringLiteral( "application/x-qgsattributesformlayoutelement" ) ) )
1001 {
1002 // Inner drag and drop actions are always MoveAction
1003 if ( event->source() == this )
1004 {
1005 event->setDropAction( Qt::MoveAction );
1006 }
1007 }
1008 else
1009 {
1010 event->ignore();
1011 }
1012
1013 QTreeView::dragMoveEvent( event );
1014}
1015
1017{
1018 if ( !( event->mimeData()->hasFormat( QStringLiteral( "application/x-qgsattributesformavailablewidgetsrelement" ) )
1019 || event->mimeData()->hasFormat( QStringLiteral( "application/x-qgsattributesformlayoutelement" ) ) ) )
1020 return;
1021
1022 if ( event->source() == this )
1023 {
1024 event->setDropAction( Qt::MoveAction );
1025 }
1026
1027 QTreeView::dropEvent( event );
1028}
1029
1030void QgsAttributesFormLayoutView::onItemDoubleClicked( const QModelIndex &index )
1031{
1033 const auto itemType = static_cast<QgsAttributesFormData::AttributesFormItemType>( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
1034 const QString itemName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
1035
1036 QGroupBox *baseData = new QGroupBox( tr( "Base configuration" ) );
1037
1038 QFormLayout *baseLayout = new QFormLayout();
1039 baseData->setLayout( baseLayout );
1040 QCheckBox *showLabelCheckbox = new QCheckBox( QStringLiteral( "Show label" ) );
1041 showLabelCheckbox->setChecked( itemData.showLabel() );
1042 baseLayout->addRow( showLabelCheckbox );
1043 QWidget *baseWidget = new QWidget();
1044 baseWidget->setLayout( baseLayout );
1045
1046 switch ( itemType )
1047 {
1053 break;
1054
1056 {
1057 QDialog dlg;
1058 dlg.setObjectName( "QML Form Configuration Widget" );
1060 dlg.setWindowTitle( tr( "Configure QML Widget" ) );
1061
1062 QVBoxLayout *mainLayout = new QVBoxLayout( &dlg );
1063 QSplitter *qmlSplitter = new QSplitter();
1064 QWidget *qmlConfigWiget = new QWidget();
1065 QVBoxLayout *layout = new QVBoxLayout( qmlConfigWiget );
1066 layout->setContentsMargins( 0, 0, 0, 0 );
1067 mainLayout->addWidget( qmlSplitter );
1068 qmlSplitter->addWidget( qmlConfigWiget );
1069 layout->addWidget( baseWidget );
1070
1071 QLineEdit *title = new QLineEdit( itemName );
1072
1073 //qmlCode
1074 QgsCodeEditor *qmlCode = new QgsCodeEditor( this );
1075 qmlCode->setEditingTimeoutInterval( 250 );
1076 qmlCode->setText( itemData.qmlElementEditorConfiguration().qmlCode );
1077
1078 QgsQmlWidgetWrapper *qmlWrapper = new QgsQmlWidgetWrapper( mLayer, nullptr, this );
1079 QgsFeature previewFeature;
1080 mLayer->getFeatures().nextFeature( previewFeature );
1081
1082 //update preview on text change
1083 connect( qmlCode, &QgsCodeEditor::editingTimeout, this, [=] {
1084 qmlWrapper->setQmlCode( qmlCode->text() );
1085 qmlWrapper->reinitWidget();
1086 qmlWrapper->setFeature( previewFeature );
1087 } );
1088
1089 //templates
1090 QComboBox *qmlObjectTemplate = new QComboBox();
1091 qmlObjectTemplate->addItem( tr( "Free Text…" ) );
1092 qmlObjectTemplate->addItem( tr( "Rectangle" ) );
1093 qmlObjectTemplate->addItem( tr( "Pie Chart" ) );
1094 qmlObjectTemplate->addItem( tr( "Bar Chart" ) );
1095 connect( qmlObjectTemplate, qOverload<int>( &QComboBox::activated ), qmlCode, [=]( int index ) {
1096 qmlCode->clear();
1097 switch ( index )
1098 {
1099 case 0:
1100 {
1101 qmlCode->setText( QString() );
1102 break;
1103 }
1104 case 1:
1105 {
1106 qmlCode->setText( QStringLiteral( "import QtQuick 2.0\n"
1107 "\n"
1108 "Rectangle {\n"
1109 " width: 100\n"
1110 " height: 100\n"
1111 " color: \"steelblue\"\n"
1112 " Text{ text: \"A rectangle\" }\n"
1113 "}\n" ) );
1114 break;
1115 }
1116 case 2:
1117 {
1118 qmlCode->setText( QStringLiteral( "import QtQuick 2.0\n"
1119 "import QtCharts 2.0\n"
1120 "\n"
1121 "ChartView {\n"
1122 " width: 400\n"
1123 " height: 400\n"
1124 "\n"
1125 " PieSeries {\n"
1126 " id: pieSeries\n"
1127 " PieSlice { label: \"First slice\"; value: 25 }\n"
1128 " PieSlice { label: \"Second slice\"; value: 45 }\n"
1129 " PieSlice { label: \"Third slice\"; value: 30 }\n"
1130 " }\n"
1131 "}\n" ) );
1132 break;
1133 }
1134 case 3:
1135 {
1136 qmlCode->setText( QStringLiteral( "import QtQuick 2.0\n"
1137 "import QtCharts 2.0\n"
1138 "\n"
1139 "ChartView {\n"
1140 " title: \"Bar series\"\n"
1141 " width: 600\n"
1142 " height:400\n"
1143 " legend.alignment: Qt.AlignBottom\n"
1144 " antialiasing: true\n"
1145 " ValueAxis{\n"
1146 " id: valueAxisY\n"
1147 " min: 0\n"
1148 " max: 15\n"
1149 " }\n"
1150 "\n"
1151 " BarSeries {\n"
1152 " id: mySeries\n"
1153 " axisY: valueAxisY\n"
1154 " axisX: BarCategoryAxis { categories: [\"2007\", \"2008\", \"2009\", \"2010\", \"2011\", \"2012\" ] }\n"
1155 " BarSet { label: \"Bob\"; values: [2, 2, 3, 4, 5, 6] }\n"
1156 " BarSet { label: \"Susan\"; values: [5, 1, 2, 4, 1, 7] }\n"
1157 " BarSet { label: \"James\"; values: [3, 5, 8, 13, 5, 8] }\n"
1158 " }\n"
1159 "}\n" ) );
1160 break;
1161 }
1162 default:
1163 break;
1164 }
1165 } );
1166
1167 QgsFieldExpressionWidget *expressionWidget = new QgsFieldExpressionWidget;
1168 expressionWidget->setButtonVisible( false );
1169 expressionWidget->registerExpressionContextGenerator( this );
1170 expressionWidget->setLayer( mLayer );
1171 QToolButton *addFieldButton = new QToolButton();
1172 addFieldButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/symbologyAdd.svg" ) ) );
1173
1174 QToolButton *editExpressionButton = new QToolButton();
1175 editExpressionButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mIconExpression.svg" ) ) );
1176 editExpressionButton->setToolTip( tr( "Insert/Edit Expression" ) );
1177
1178 connect( addFieldButton, &QAbstractButton::clicked, this, [=] {
1179 QString expression = expressionWidget->expression().trimmed().replace( '"', QLatin1String( "\\\"" ) );
1180 if ( !expression.isEmpty() )
1181 qmlCode->insertText( QStringLiteral( "expression.evaluate(\"%1\")" ).arg( expression ) );
1182 } );
1183
1184 connect( editExpressionButton, &QAbstractButton::clicked, this, [=] {
1185 QString expression = QgsExpressionFinder::findAndSelectActiveExpression( qmlCode, QStringLiteral( "expression\\.evaluate\\(\\s*\"(.*?)\\s*\"\\s*\\)" ) );
1186 expression.replace( QLatin1String( "\\\"" ), QLatin1String( "\"" ) );
1188 QgsExpressionBuilderDialog exprDlg( mLayer, expression, this, QStringLiteral( "generic" ), context );
1189
1190 exprDlg.setWindowTitle( tr( "Insert Expression" ) );
1191 if ( exprDlg.exec() == QDialog::Accepted && !exprDlg.expressionText().trimmed().isEmpty() )
1192 {
1193 QString expression = exprDlg.expressionText().trimmed().replace( '"', QLatin1String( "\\\"" ) );
1194 if ( !expression.isEmpty() )
1195 qmlCode->insertText( QStringLiteral( "expression.evaluate(\"%1\")" ).arg( expression ) );
1196 }
1197 } );
1198
1199 layout->addWidget( new QLabel( tr( "Title" ) ) );
1200 layout->addWidget( title );
1201 QGroupBox *qmlCodeBox = new QGroupBox( tr( "QML Code" ) );
1202 qmlCodeBox->setLayout( new QVBoxLayout );
1203 qmlCodeBox->layout()->addWidget( qmlObjectTemplate );
1204 QWidget *expressionWidgetBox = new QWidget();
1205 qmlCodeBox->layout()->addWidget( expressionWidgetBox );
1206 expressionWidgetBox->setLayout( new QHBoxLayout );
1207 expressionWidgetBox->layout()->setContentsMargins( 0, 0, 0, 0 );
1208 expressionWidgetBox->layout()->addWidget( expressionWidget );
1209 expressionWidgetBox->layout()->addWidget( addFieldButton );
1210 expressionWidgetBox->layout()->addWidget( editExpressionButton );
1211 expressionWidgetBox->layout()->addWidget( editExpressionButton );
1212 layout->addWidget( qmlCodeBox );
1213 layout->addWidget( qmlCode );
1214 QScrollArea *qmlPreviewBox = new QgsScrollArea();
1215 qmlPreviewBox->setMinimumWidth( 200 );
1216 qmlPreviewBox->setWidget( qmlWrapper->widget() );
1217 //emit to load preview for the first time
1218 emit qmlCode->editingTimeout();
1219 qmlSplitter->addWidget( qmlPreviewBox );
1220 qmlSplitter->setChildrenCollapsible( false );
1221 qmlSplitter->setHandleWidth( 6 );
1222 qmlSplitter->setSizes( QList<int>() << 1 << 1 );
1223
1224 QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help );
1225
1226 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1227 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1228 connect( buttonBox, &QDialogButtonBox::helpRequested, &dlg, [=] {
1229 QgsHelp::openHelp( QStringLiteral( "working_with_vector/vector_properties.html#other-widgets" ) );
1230 } );
1231
1232 mainLayout->addWidget( buttonBox );
1233
1234 if ( dlg.exec() )
1235 {
1237 qmlEdCfg.qmlCode = qmlCode->text();
1238 itemData.setQmlElementEditorConfiguration( qmlEdCfg );
1239 itemData.setShowLabel( showLabelCheckbox->isChecked() );
1240
1241 model()->setData( index, itemData, QgsAttributesFormModel::ItemDataRole );
1242 model()->setData( index, title->text(), QgsAttributesFormModel::ItemNameRole );
1243 }
1244 }
1245 break;
1246
1248 {
1249 QDialog dlg;
1250 dlg.setObjectName( "HTML Form Configuration Widget" );
1252 dlg.setWindowTitle( tr( "Configure HTML Widget" ) );
1253
1254 QVBoxLayout *mainLayout = new QVBoxLayout( &dlg );
1255 QSplitter *htmlSplitter = new QSplitter();
1256 QWidget *htmlConfigWiget = new QWidget();
1257 QVBoxLayout *layout = new QVBoxLayout( htmlConfigWiget );
1258 layout->setContentsMargins( 0, 0, 0, 0 );
1259 mainLayout->addWidget( htmlSplitter );
1260 htmlSplitter->addWidget( htmlConfigWiget );
1261 htmlSplitter->setChildrenCollapsible( false );
1262 htmlSplitter->setHandleWidth( 6 );
1263 htmlSplitter->setSizes( QList<int>() << 1 << 1 );
1264 layout->addWidget( baseWidget );
1265
1266 QLineEdit *title = new QLineEdit( itemName );
1267
1268 //htmlCode
1269 QgsCodeEditorHTML *htmlCode = new QgsCodeEditorHTML();
1270 htmlCode->setSizePolicy( QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding );
1271 htmlCode->setText( itemData.htmlElementEditorConfiguration().htmlCode );
1272
1273 QgsHtmlWidgetWrapper *htmlWrapper = new QgsHtmlWidgetWrapper( mLayer, nullptr, this );
1274 QgsFeature previewFeature;
1275 mLayer->getFeatures().nextFeature( previewFeature );
1276
1277 //update preview on text change
1278 connect( htmlCode, &QgsCodeEditorHTML::textChanged, this, [=] {
1279 htmlWrapper->setHtmlCode( htmlCode->text() );
1280 htmlWrapper->reinitWidget();
1281 htmlWrapper->setFeature( previewFeature );
1282 } );
1283
1284 QgsFieldExpressionWidget *expressionWidget = new QgsFieldExpressionWidget;
1285 expressionWidget->setButtonVisible( false );
1286 expressionWidget->registerExpressionContextGenerator( this );
1287 expressionWidget->setLayer( mLayer );
1288 QToolButton *addFieldButton = new QToolButton();
1289 addFieldButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/symbologyAdd.svg" ) ) );
1290
1291 QToolButton *editExpressionButton = new QToolButton();
1292 editExpressionButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mIconExpression.svg" ) ) );
1293 editExpressionButton->setToolTip( tr( "Insert/Edit Expression" ) );
1294
1295 connect( addFieldButton, &QAbstractButton::clicked, this, [=] {
1296 QString expression = expressionWidget->expression().trimmed().replace( '"', QLatin1String( "\\\"" ) );
1297 if ( !expression.isEmpty() )
1298 htmlCode->insertText( QStringLiteral( "<script>document.write(expression.evaluate(\"%1\"));</script>" ).arg( expression ) );
1299 } );
1300
1301 connect( editExpressionButton, &QAbstractButton::clicked, this, [=] {
1302 QString expression = QgsExpressionFinder::findAndSelectActiveExpression( htmlCode, QStringLiteral( "<script>\\s*document\\.write\\(\\s*expression\\.evaluate\\(\\s*\"(.*?)\\s*\"\\s*\\)\\s*\\)\\s*;?\\s*</script>" ) );
1303 expression.replace( QLatin1String( "\\\"" ), QLatin1String( "\"" ) );
1305 QgsExpressionBuilderDialog exprDlg( mLayer, expression, this, QStringLiteral( "generic" ), context );
1306
1307 exprDlg.setWindowTitle( tr( "Insert Expression" ) );
1308 if ( exprDlg.exec() == QDialog::Accepted && !exprDlg.expressionText().trimmed().isEmpty() )
1309 {
1310 QString expression = exprDlg.expressionText().trimmed().replace( '"', QLatin1String( "\\\"" ) );
1311 if ( !expression.isEmpty() )
1312 htmlCode->insertText( QStringLiteral( "<script>document.write(expression.evaluate(\"%1\"));</script>" ).arg( expression ) );
1313 }
1314 } );
1315
1316 layout->addWidget( new QLabel( tr( "Title" ) ) );
1317 layout->addWidget( title );
1318 QGroupBox *expressionWidgetBox = new QGroupBox( tr( "HTML Code" ) );
1319 layout->addWidget( expressionWidgetBox );
1320 expressionWidgetBox->setLayout( new QHBoxLayout );
1321 expressionWidgetBox->layout()->addWidget( expressionWidget );
1322 expressionWidgetBox->layout()->addWidget( addFieldButton );
1323 expressionWidgetBox->layout()->addWidget( editExpressionButton );
1324 layout->addWidget( htmlCode );
1325 QScrollArea *htmlPreviewBox = new QgsScrollArea();
1326 htmlPreviewBox->setLayout( new QGridLayout );
1327 htmlPreviewBox->setMinimumWidth( 200 );
1328 htmlPreviewBox->layout()->addWidget( htmlWrapper->widget() );
1329 //emit to load preview for the first time
1330 emit htmlCode->textChanged();
1331 htmlSplitter->addWidget( htmlPreviewBox );
1332 htmlSplitter->setChildrenCollapsible( false );
1333 htmlSplitter->setHandleWidth( 6 );
1334 htmlSplitter->setSizes( QList<int>() << 1 << 1 );
1335
1336 QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help );
1337
1338 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1339 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1340 connect( buttonBox, &QDialogButtonBox::helpRequested, &dlg, [=] {
1341 QgsHelp::openHelp( QStringLiteral( "working_with_vector/vector_properties.html#other-widgets" ) );
1342 } );
1343
1344 mainLayout->addWidget( buttonBox );
1345
1346 if ( dlg.exec() )
1347 {
1349 htmlEdCfg.htmlCode = htmlCode->text();
1350 itemData.setHtmlElementEditorConfiguration( htmlEdCfg );
1351 itemData.setShowLabel( showLabelCheckbox->isChecked() );
1352
1353 model()->setData( index, itemData, QgsAttributesFormModel::ItemDataRole );
1354 model()->setData( index, title->text(), QgsAttributesFormModel::ItemNameRole );
1355 }
1356 break;
1357 }
1358
1360 {
1361 QDialog dlg;
1362 dlg.setObjectName( "Text Form Configuration Widget" );
1364 dlg.setWindowTitle( tr( "Configure Text Widget" ) );
1365
1366 QVBoxLayout *mainLayout = new QVBoxLayout( &dlg );
1367 QSplitter *textSplitter = new QSplitter();
1368 QWidget *textConfigWiget = new QWidget();
1369 QVBoxLayout *layout = new QVBoxLayout( textConfigWiget );
1370 layout->setContentsMargins( 0, 0, 0, 0 );
1371 mainLayout->addWidget( textSplitter );
1372 textSplitter->addWidget( textConfigWiget );
1373 layout->addWidget( baseWidget );
1374
1375 QLineEdit *title = new QLineEdit( itemName );
1376
1378 text->setSizePolicy( QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding );
1379 text->setText( itemData.textElementEditorConfiguration().text );
1380
1381 QgsTextWidgetWrapper *textWrapper = new QgsTextWidgetWrapper( mLayer, nullptr, this );
1382 QgsFeature previewFeature;
1383 mLayer->getFeatures().nextFeature( previewFeature );
1384
1385 //update preview on text change
1386 connect( text, &QgsCodeEditorExpression::textChanged, this, [=] {
1387 textWrapper->setText( text->text() );
1388 textWrapper->reinitWidget();
1389 textWrapper->setFeature( previewFeature );
1390 } );
1391
1392 QgsFieldExpressionWidget *expressionWidget = new QgsFieldExpressionWidget;
1393 expressionWidget->setButtonVisible( false );
1394 expressionWidget->registerExpressionContextGenerator( this );
1395 expressionWidget->setLayer( mLayer );
1396 QToolButton *addFieldButton = new QToolButton();
1397 addFieldButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/symbologyAdd.svg" ) ) );
1398
1399 QToolButton *editExpressionButton = new QToolButton();
1400 editExpressionButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mIconExpression.svg" ) ) );
1401 editExpressionButton->setToolTip( tr( "Insert/Edit Expression" ) );
1402
1403 connect( addFieldButton, &QAbstractButton::clicked, this, [=] {
1404 QString expression = expressionWidget->expression().trimmed();
1405 if ( !expression.isEmpty() )
1406 text->insertText( QStringLiteral( "[%%1%]" ).arg( expression ) );
1407 } );
1408 connect( editExpressionButton, &QAbstractButton::clicked, this, [=] {
1409 QString expression = QgsExpressionFinder::findAndSelectActiveExpression( text );
1410
1412 QgsExpressionBuilderDialog exprDlg( mLayer, expression, this, QStringLiteral( "generic" ), context );
1413
1414 exprDlg.setWindowTitle( tr( "Insert Expression" ) );
1415 if ( exprDlg.exec() == QDialog::Accepted && !exprDlg.expressionText().trimmed().isEmpty() )
1416 {
1417 QString expression = exprDlg.expressionText().trimmed();
1418 if ( !expression.isEmpty() )
1419 text->insertText( QStringLiteral( "[%%1%]" ).arg( expression ) );
1420 }
1421 } );
1422
1423 layout->addWidget( new QLabel( tr( "Title" ) ) );
1424 layout->addWidget( title );
1425 QGroupBox *expressionWidgetBox = new QGroupBox( tr( "Text" ) );
1426 layout->addWidget( expressionWidgetBox );
1427 expressionWidgetBox->setLayout( new QHBoxLayout );
1428 expressionWidgetBox->layout()->addWidget( expressionWidget );
1429 expressionWidgetBox->layout()->addWidget( addFieldButton );
1430 expressionWidgetBox->layout()->addWidget( editExpressionButton );
1431 layout->addWidget( text );
1432 QScrollArea *textPreviewBox = new QgsScrollArea();
1433 textPreviewBox->setLayout( new QGridLayout );
1434 textPreviewBox->setMinimumWidth( 200 );
1435 textPreviewBox->layout()->addWidget( textWrapper->widget() );
1436 //emit to load preview for the first time
1437 emit text->textChanged();
1438 textSplitter->addWidget( textPreviewBox );
1439 textSplitter->setChildrenCollapsible( false );
1440 textSplitter->setHandleWidth( 6 );
1441 textSplitter->setSizes( QList<int>() << 1 << 1 );
1442
1443 QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help );
1444
1445 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1446 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1447 connect( buttonBox, &QDialogButtonBox::helpRequested, &dlg, [=] {
1448 QgsHelp::openHelp( QStringLiteral( "working_with_vector/vector_properties.html#other-widgets" ) );
1449 } );
1450
1451 mainLayout->addWidget( buttonBox );
1452
1453 if ( dlg.exec() )
1454 {
1456 textEdCfg.text = text->text();
1457 itemData.setTextElementEditorConfiguration( textEdCfg );
1458 itemData.setShowLabel( showLabelCheckbox->isChecked() );
1459
1460 model()->setData( index, itemData, QgsAttributesFormModel::ItemDataRole );
1461 model()->setData( index, title->text(), QgsAttributesFormModel::ItemNameRole );
1462 }
1463 break;
1464 }
1465
1467 {
1468 QDialog dlg;
1469 dlg.setObjectName( "Spacer Form Configuration Widget" );
1471 dlg.setWindowTitle( tr( "Configure Spacer Widget" ) );
1472
1473 QVBoxLayout *mainLayout = new QVBoxLayout();
1474 mainLayout->addWidget( new QLabel( tr( "Title" ) ) );
1475 QLineEdit *title = new QLineEdit( itemName );
1476 mainLayout->addWidget( title );
1477
1478 QHBoxLayout *cbLayout = new QHBoxLayout();
1479 mainLayout->addLayout( cbLayout );
1480 dlg.setLayout( mainLayout );
1481 QCheckBox *cb = new QCheckBox { &dlg };
1482 cb->setChecked( itemData.spacerElementEditorConfiguration().drawLine );
1483 cbLayout->addWidget( new QLabel( tr( "Draw horizontal line" ), &dlg ) );
1484 cbLayout->addWidget( cb );
1485
1486 QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Help );
1487
1488 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1489 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1490 connect( buttonBox, &QDialogButtonBox::helpRequested, &dlg, [=] {
1491 QgsHelp::openHelp( QStringLiteral( "working_with_vector/vector_properties.html#other-widgets" ) );
1492 } );
1493
1494 mainLayout->addWidget( buttonBox );
1495
1496 if ( dlg.exec() )
1497 {
1499 spacerEdCfg.drawLine = cb->isChecked();
1500 itemData.setSpacerElementEditorConfiguration( spacerEdCfg );
1501 itemData.setShowLabel( false );
1502
1503 model()->setData( index, itemData, QgsAttributesFormModel::ItemDataRole );
1504 model()->setData( index, title->text(), QgsAttributesFormModel::ItemNameRole );
1505 }
1506
1507 break;
1508 }
1509 }
1510}
1511
1512
1513void QgsAttributesFormProperties::updatedFields()
1514{
1515 // Store configuration to insure changes made are kept after refreshing the list
1516 QMap<QString, QgsAttributesFormData::FieldConfig> fieldConfigs;
1517
1518 const QModelIndex fieldContainerBefore = mAvailableWidgetsModel->fieldContainer();
1519 QModelIndex index;
1520
1521 for ( int i = 0; i < mAvailableWidgetsModel->rowCount( fieldContainerBefore ); i++ )
1522 {
1523 index = mAvailableWidgetsModel->index( i, 0, fieldContainerBefore );
1524 const QString fieldName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
1526 fieldConfigs[fieldName] = config;
1527 }
1528
1530
1531 const QModelIndex fieldContainerAfter = mAvailableWidgetsModel->fieldContainer();
1532
1533 for ( int i = 0; i < mAvailableWidgetsModel->rowCount( fieldContainerAfter ); i++ )
1534 {
1535 index = mAvailableWidgetsModel->index( i, 0, fieldContainerAfter );
1536 const QString fieldName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
1537
1538 if ( fieldConfigs.contains( fieldName ) )
1539 {
1540 mAvailableWidgetsModel->setData( index, fieldConfigs[fieldName], QgsAttributesFormModel::ItemFieldConfigRole );
1541 mAvailableWidgetsModel->setData( index, fieldConfigs[fieldName].mAlias, QgsAttributesFormModel::ItemDisplayRole );
1542 }
1543 }
1544}
1545
1546void QgsAttributesFormProperties::onContextMenuRequested( QPoint point )
1547{
1548 if ( mAvailableWidgetsView->selectionModel()->selectedRows().count() != 1 )
1549 return;
1550
1551 QPoint globalPos = mAvailableWidgetsView->viewport()->mapToGlobal( point );
1552
1553 const QModelIndex index = mAvailableWidgetsView->indexAt( point );
1554 const auto itemType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
1555 if ( itemType == QgsAttributesFormData::Field )
1556 {
1557 const QClipboard *clipboard = QApplication::clipboard();
1558 const QMimeData *mimeData = clipboard->mimeData();
1559 if ( !mimeData )
1560 return;
1561
1562 const bool pasteEnabled = mimeData->hasFormat( QStringLiteral( "application/x-qgsattributetabledesignerelementclipboard" ) );
1563 mActionPasteWidgetConfiguration->setEnabled( pasteEnabled );
1564 mAvailableWidgetsContextMenu->popup( globalPos );
1565 }
1566}
1567
1568void QgsAttributesFormProperties::copyWidgetConfiguration()
1569{
1570 if ( mAvailableWidgetsView->selectionModel()->selectedRows().count() != 1 )
1571 return;
1572
1573 const QModelIndex index = mAvailableWidgetsView->selectionModel()->selectedRows().at( 0 );
1574 const auto itemType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
1575
1576 if ( itemType != QgsAttributesFormData::Field )
1577 return;
1578
1579 const QString fieldName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
1580 const int fieldIndex = mLayer->fields().indexOf( fieldName );
1581
1582 if ( fieldIndex < 0 )
1583 return;
1584
1585 const QgsField field = mLayer->fields().field( fieldIndex );
1586
1587 // We'll copy everything but field aliases or comments
1588 QDomDocument doc;
1589 QDomElement documentElement = doc.createElement( QStringLiteral( "FormWidgetClipboard" ) );
1590 documentElement.setAttribute( QStringLiteral( "name" ), field.name() );
1591
1592 // Editor widget setup
1593 QgsEditorWidgetSetup widgetSetup = field.editorWidgetSetup();
1594
1595 QDomElement editWidgetElement = doc.createElement( QStringLiteral( "editWidget" ) );
1596 documentElement.appendChild( editWidgetElement );
1597 editWidgetElement.setAttribute( QStringLiteral( "type" ), widgetSetup.type() );
1598 QDomElement editWidgetConfigElement = doc.createElement( QStringLiteral( "config" ) );
1599
1600 editWidgetConfigElement.appendChild( QgsXmlUtils::writeVariant( widgetSetup.config(), doc ) );
1601 editWidgetElement.appendChild( editWidgetConfigElement );
1602
1603 // Split policy
1604 QDomElement splitPolicyElement = doc.createElement( QStringLiteral( "splitPolicy" ) );
1605 splitPolicyElement.setAttribute( QStringLiteral( "policy" ), qgsEnumValueToKey( field.splitPolicy() ) );
1606 documentElement.appendChild( splitPolicyElement );
1607
1608 // Duplicate policy
1609 QDomElement duplicatePolicyElement = doc.createElement( QStringLiteral( "duplicatePolicy" ) );
1610 duplicatePolicyElement.setAttribute( QStringLiteral( "policy" ), qgsEnumValueToKey( field.duplicatePolicy() ) );
1611 documentElement.appendChild( duplicatePolicyElement );
1612
1613 // Merge policy
1614 QDomElement mergePolicyElement = doc.createElement( QStringLiteral( "mergePolicy" ) );
1615 mergePolicyElement.setAttribute( QStringLiteral( "policy" ), qgsEnumValueToKey( field.mergePolicy() ) );
1616 documentElement.appendChild( mergePolicyElement );
1617
1618 // Default expressions
1619 QDomElement defaultElem = doc.createElement( QStringLiteral( "default" ) );
1620 defaultElem.setAttribute( QStringLiteral( "expression" ), field.defaultValueDefinition().expression() );
1621 defaultElem.setAttribute( QStringLiteral( "applyOnUpdate" ), field.defaultValueDefinition().applyOnUpdate() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
1622 documentElement.appendChild( defaultElem );
1623
1624 // Constraints
1625 QDomElement constraintElem = doc.createElement( QStringLiteral( "constraint" ) );
1626 constraintElem.setAttribute( QStringLiteral( "constraints" ), field.constraints().constraints() );
1627 constraintElem.setAttribute( QStringLiteral( "unique_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintUnique ) );
1628 constraintElem.setAttribute( QStringLiteral( "notnull_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintNotNull ) );
1629 constraintElem.setAttribute( QStringLiteral( "exp_strength" ), field.constraints().constraintStrength( QgsFieldConstraints::ConstraintExpression ) );
1630 documentElement.appendChild( constraintElem );
1631
1632 // Constraint expressions
1633 QDomElement constraintExpressionElem = doc.createElement( QStringLiteral( "constraintExpression" ) );
1634 constraintExpressionElem.setAttribute( QStringLiteral( "exp" ), field.constraints().constraintExpression() );
1635 constraintExpressionElem.setAttribute( QStringLiteral( "desc" ), field.constraints().constraintDescription() );
1636 documentElement.appendChild( constraintExpressionElem );
1637
1638 // Widget general settings
1640 {
1641 QDomElement widgetGeneralSettingsElem = doc.createElement( QStringLiteral( "widgetGeneralSettings" ) );
1642 widgetGeneralSettingsElem.setAttribute( QStringLiteral( "editable" ), mAttributeTypeDialog->fieldEditable() );
1643 widgetGeneralSettingsElem.setAttribute( QStringLiteral( "reuse_last_values" ), mAttributeTypeDialog->labelOnTop() );
1644 widgetGeneralSettingsElem.setAttribute( QStringLiteral( "label_on_top" ), mAttributeTypeDialog->reuseLastValues() );
1645 documentElement.appendChild( widgetGeneralSettingsElem );
1646 }
1647
1648 // Widget display section
1650 {
1651 // Go for the corresponding form layout item and extract its display settings
1652 if ( mFormLayoutView->selectionModel()->selectedRows().count() != 1 )
1653 return;
1654
1655 const QModelIndex indexLayout = mFormLayoutView->selectionModel()->selectedRows().at( 0 );
1656 const auto layoutData = indexLayout.data( QgsAttributesFormModel::ItemDataRole ).value< QgsAttributesFormData::AttributeFormItemData >();
1657
1658 QDomElement displayElement = doc.createElement( QStringLiteral( "widgetDisplay" ) );
1659 displayElement.setAttribute( QStringLiteral( "showLabel" ), layoutData.showLabel() );
1660 displayElement.setAttribute( QStringLiteral( "horizontalStretch" ), layoutData.horizontalStretch() );
1661 displayElement.setAttribute( QStringLiteral( "verticalStretch" ), layoutData.verticalStretch() );
1662 displayElement.appendChild( layoutData.labelStyle().writeXml( doc ) );
1663 documentElement.appendChild( displayElement );
1664 }
1665
1666 doc.appendChild( documentElement );
1667
1668 QMimeData *mimeData = new QMimeData;
1669 mimeData->setData( QStringLiteral( "application/x-qgsattributetabledesignerelementclipboard" ), doc.toByteArray() );
1670 QClipboard *clipboard = QApplication::clipboard();
1671 clipboard->setMimeData( mimeData );
1672}
1673
1674void QgsAttributesFormProperties::pasteWidgetConfiguration()
1675{
1676 if ( mAvailableWidgetsView->selectionModel()->selectedRows().count() != 1 )
1677 return;
1678
1679 QModelIndex index = mAvailableWidgetsView->selectionModel()->selectedRows().at( 0 );
1680
1681 const QString fieldName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
1682 const int fieldIndex = mLayer->fields().indexOf( fieldName );
1683
1684 if ( fieldIndex < 0 )
1685 return;
1686
1687 // Get base config from target item and ovewrite settings when possible
1689
1690 QDomDocument doc;
1691 QClipboard *clipboard = QApplication::clipboard();
1692 const QMimeData *mimeData = clipboard->mimeData();
1693 if ( !mimeData )
1694 return;
1695
1696 if ( doc.setContent( mimeData->data( QStringLiteral( "application/x-qgsattributetabledesignerelementclipboard" ) ) ) )
1697 {
1698 QDomElement docElem = doc.documentElement();
1699 if ( docElem.tagName() != QLatin1String( "FormWidgetClipboard" ) )
1700 return;
1701
1702 // When pasting, the target item has already been selected and
1703 // has triggered attribute type dialog loading. Therefore, we'll
1704 // only overwrite GUI settings instead of destroying and recreating
1705 // the whole dialog.
1706
1707 // Editor widget configuration
1708 const QDomElement fieldWidgetElement = docElem.firstChildElement( QStringLiteral( "editWidget" ) );
1709 if ( !fieldWidgetElement.isNull() )
1710 {
1711 const QString widgetType = fieldWidgetElement.attribute( QStringLiteral( "type" ) );
1712
1713 // Only paste if source editor widget type is supported by target field
1714 const QgsEditorWidgetFactory *factory = QgsGui::editorWidgetRegistry()->factory( widgetType );
1715 if ( factory->supportsField( mLayer, fieldIndex ) )
1716 {
1717 const QDomElement configElement = fieldWidgetElement.firstChildElement( QStringLiteral( "config" ) );
1718 if ( !configElement.isNull() )
1719 {
1720 const QDomElement optionsElem = configElement.childNodes().at( 0 ).toElement();
1721 QVariantMap optionsMap = QgsXmlUtils::readVariant( optionsElem ).toMap();
1722 QgsReadWriteContext context;
1723 // translate widget configuration strings
1724 if ( widgetType == QStringLiteral( "ValueRelation" ) )
1725 {
1726 optionsMap[QStringLiteral( "Value" )] = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fields:%2:valuerelationvalue" ).arg( mLayer->id(), fieldName ), optionsMap[QStringLiteral( "Value" )].toString() );
1727 }
1728 if ( widgetType == QStringLiteral( "ValueMap" ) )
1729 {
1730 if ( optionsMap[QStringLiteral( "map" )].canConvert<QList<QVariant>>() )
1731 {
1732 QList<QVariant> translatedValueList;
1733 const QList<QVariant> valueList = optionsMap[QStringLiteral( "map" )].toList();
1734 for ( int i = 0, row = 0; i < valueList.count(); i++, row++ )
1735 {
1736 QMap<QString, QVariant> translatedValueMap;
1737 QString translatedKey = context.projectTranslator()->translate( QStringLiteral( "project:layers:%1:fields:%2:valuemapdescriptions" ).arg( mLayer->id(), fieldName ), valueList[i].toMap().constBegin().key() );
1738 translatedValueMap.insert( translatedKey, valueList[i].toMap().constBegin().value() );
1739 translatedValueList.append( translatedValueMap );
1740 }
1741 optionsMap.insert( QStringLiteral( "map" ), translatedValueList );
1742 }
1743 }
1744 config.mEditorWidgetType = widgetType;
1745 config.mEditorWidgetConfig = optionsMap;
1746 }
1747 }
1748 else
1749 {
1750 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 );
1751 }
1752 }
1753
1754 // Split policy
1755 const QDomElement splitPolicyElement = docElem.firstChildElement( QStringLiteral( "splitPolicy" ) );
1756 if ( !splitPolicyElement.isNull() )
1757 {
1758 const Qgis::FieldDomainSplitPolicy policy = qgsEnumKeyToValue( splitPolicyElement.attribute( QStringLiteral( "policy" ) ), Qgis::FieldDomainSplitPolicy::Duplicate );
1759 config.mSplitPolicy = policy;
1760 }
1761
1762 // Duplicate policy
1763 const QDomElement duplicatePolicyElement = docElem.firstChildElement( QStringLiteral( "duplicatePolicy" ) );
1764 if ( !duplicatePolicyElement.isNull() )
1765 {
1766 const Qgis::FieldDuplicatePolicy policy = qgsEnumKeyToValue( duplicatePolicyElement.attribute( QStringLiteral( "policy" ) ), Qgis::FieldDuplicatePolicy::Duplicate );
1767 config.mDuplicatePolicy = policy;
1768 }
1769
1770 // Merge policy
1771 const QDomElement mergePolicyElement = docElem.firstChildElement( QStringLiteral( "mergePolicy" ) );
1772 if ( !mergePolicyElement.isNull() )
1773 {
1774 const Qgis::FieldDomainMergePolicy policy = qgsEnumKeyToValue( mergePolicyElement.attribute( QStringLiteral( "policy" ) ), Qgis::FieldDomainMergePolicy::DefaultValue );
1775 config.mMergePolicy = policy;
1776 }
1777
1778 // Default expressions
1779 const QDomElement defaultElement = docElem.firstChildElement( QStringLiteral( "default" ) );
1780 if ( !defaultElement.isNull() )
1781 {
1782 mAttributeTypeDialog->setDefaultValueExpression( defaultElement.attribute( QStringLiteral( "expression" ) ) );
1783 mAttributeTypeDialog->setApplyDefaultValueOnUpdate( defaultElement.attribute( QStringLiteral( "applyOnUpdate" ) ).toInt() );
1784 }
1785
1786 // Constraints
1787 // take target field constraints as a basis
1788 QgsFieldConstraints fieldConstraints = config.mFieldConstraints;
1789 const QDomElement constraintElement = docElem.firstChildElement( QStringLiteral( "constraint" ) );
1790 if ( !constraintElement.isNull() )
1791 {
1792 const int intConstraints = constraintElement.attribute( QStringLiteral( "constraints" ), QStringLiteral( "0" ) ).toInt();
1793 QgsFieldConstraints::Constraints constraints = static_cast< QgsFieldConstraints::Constraints >( intConstraints );
1794
1795 // always keep provider constraints intact
1797 {
1798 if ( constraints & QgsFieldConstraints::ConstraintNotNull )
1800 else
1802 }
1804 {
1805 if ( constraints & QgsFieldConstraints::ConstraintUnique )
1807 else
1809 }
1811 {
1814 else
1816 }
1817
1818 const int uniqueStrength = constraintElement.attribute( QStringLiteral( "unique_strength" ), QStringLiteral( "1" ) ).toInt();
1819 const int notNullStrength = constraintElement.attribute( QStringLiteral( "notnull_strength" ), QStringLiteral( "1" ) ).toInt();
1820 const int expStrength = constraintElement.attribute( QStringLiteral( "exp_strength" ), QStringLiteral( "1" ) ).toInt();
1821
1825 }
1826
1827 // Constraint expressions
1828 // always keep provider constraints intact
1830 {
1831 const QDomElement constraintExpressionElement = docElem.firstChildElement( QStringLiteral( "constraintExpression" ) );
1832 if ( !constraintExpressionElement.isNull() )
1833 {
1834 QString expression = constraintExpressionElement.attribute( QStringLiteral( "exp" ), QString() );
1835 QString description = constraintExpressionElement.attribute( QStringLiteral( "desc" ), QString() );
1836 fieldConstraints.setConstraintExpression( expression, description );
1837 }
1838 }
1839 config.mFieldConstraints = fieldConstraints;
1840
1841 const QDomElement widgetGeneralSettingsElement = docElem.firstChildElement( QStringLiteral( "widgetGeneralSettings" ) );
1842 if ( !widgetGeneralSettingsElement.isNull() )
1843 {
1844 const int editable = widgetGeneralSettingsElement.attribute( QStringLiteral( "editable" ), QStringLiteral( "0" ) ).toInt();
1845 const int reuse = widgetGeneralSettingsElement.attribute( QStringLiteral( "reuse_last_values" ), QStringLiteral( "0" ) ).toInt();
1846 const int labelOnTop = widgetGeneralSettingsElement.attribute( QStringLiteral( "label_on_top" ), QStringLiteral( "0" ) ).toInt();
1847
1848 config.mEditable = editable;
1849 config.mReuseLastValues = reuse;
1850 config.mLabelOnTop = labelOnTop;
1851 }
1852
1853 loadAttributeTypeDialogFromConfiguration( config );
1854
1855 // Widget display section
1857 {
1858 const QDomElement displayElement = docElem.firstChildElement( QStringLiteral( "widgetDisplay" ) );
1859 if ( !displayElement.isNull() )
1860 {
1861 const int showLabel = displayElement.attribute( QStringLiteral( "showLabel" ), QStringLiteral( "0" ) ).toInt();
1862 const int horizontalStretch = displayElement.attribute( QStringLiteral( "horizontalStretch" ), QStringLiteral( "0" ) ).toInt();
1863 const int verticalStretch = displayElement.attribute( QStringLiteral( "verticalStretch" ), QStringLiteral( "0" ) ).toInt();
1865 style.readXml( displayElement );
1866
1867 // Update current GUI controls
1868 mAttributeWidgetEdit->setShowLabel( showLabel );
1869 mAttributeWidgetEdit->setHorizontalStretch( horizontalStretch );
1870 mAttributeWidgetEdit->setVerticalStretch( verticalStretch );
1871 mAttributeWidgetEdit->setLabelStyle( style );
1872 }
1873 }
1874 }
1875}
AttributeFormSuppression
Available form types for layout of the attribute form editor.
Definition qgis.h:5309
@ On
Always suppress feature form.
@ Default
Use the application-wide setting.
@ Off
Never suppress feature form.
AttributeFormLayout
Available form types for layout of the attribute form editor.
Definition qgis.h:5294
@ DragAndDrop
"Drag and drop" layout. Needs to be configured.
@ AutoGenerated
Autogenerate a simple tabular layout for the form.
@ UiFile
Load a .ui file for the layout. Needs to be configured.
FieldDomainMergePolicy
Merge policy for field domains.
Definition qgis.h:3789
@ DefaultValue
Use default field value.
@ Warning
Warning message.
Definition qgis.h:156
FieldDomainSplitPolicy
Split policy for field domains.
Definition qgis.h:3772
@ Duplicate
Duplicate original value.
FieldDuplicatePolicy
Duplicate policy for fields.
Definition qgis.h:3809
@ Duplicate
Duplicate original value.
QgsAction action(QUuid id) const
Gets an action by its id.
Utility class that encapsulates an action based on vector attributes.
Definition qgsaction.h:37
Dialog to add a container for attribute widgets.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
An abstract base class for any elements of a drag and drop form.
Manages available widgets when configuring attributes forms.
QModelIndex fieldModelIndex(const QString &fieldName) const
Returns the model index that corresponds to the field with the given fieldName.
void populateLayerActions(const QList< QgsAction > actions)
Refresh layer actions in the model to keep an updated action list.
QModelIndex fieldContainer() const
Returns the field container in this model, expected to be placed at the first top-level row.
QModelIndex relationContainer() const
Returns the relation container in this model, expected to be placed at the second top-level row.
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
Graphical representation for the available widgets while configuring attributes forms.
void setModel(QAbstractItemModel *model) override
Overridden setModel() from base class. Only QgsAttributesAvailableWidgetsModel is an acceptable model...
QgsAttributesAvailableWidgetsView(QgsVectorLayer *layer, QWidget *parent=nullptr)
Constructor for QgsAttributesAvailableWidgetsView, with the given parent.
QgsAttributesAvailableWidgetsModel * availableWidgetsModel() const
Access the underlying QgsAttributesAvailableWidgetsModel model.
Graphical representation for the attribute drag and drop editor.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QgsAttributesFormBaseView(QgsVectorLayer *layer, QWidget *parent=nullptr)
Constructor for QgsAttributesFormBaseView, with the given parent.
void selectFirstMatchingItem(const QgsAttributesFormData::AttributesFormItemType &itemType, const QString &itemId)
Selects the first item that matches a itemType and a itemId.
Main class to store and transfer editor data contained in a QgsAttributesFormModel.
HtmlElementEditorConfiguration htmlElementEditorConfiguration() const
Returns the HTML editor configuration.
TextElementEditorConfiguration textElementEditorConfiguration() const
Returns the editor configuration for text element.
SpacerElementEditorConfiguration spacerElementEditorConfiguration() const
Returns the spacer element configuration.
void setHtmlElementEditorConfiguration(const HtmlElementEditorConfiguration &htmlElementEditorConfiguration)
Sets the HTML editor configuration.
bool showLabel() const
Returns whether the widget's label is to be shown.
void setShowLabel(bool showLabel)
Sets whether the label for the widget should be shown.
void setQmlElementEditorConfiguration(const QmlElementEditorConfiguration &qmlElementEditorConfiguration)
Sets the QML editor configuration.
RelationEditorConfiguration relationEditorConfiguration() const
Returns the relation editor configuration.
Qgis::AttributeEditorContainerType containerType() const
Returns the container type.
void setSpacerElementEditorConfiguration(SpacerElementEditorConfiguration spacerElementEditorConfiguration)
Sets the the spacer element configuration to spacerElementEditorConfiguration.
QmlElementEditorConfiguration qmlElementEditorConfiguration() const
Returns the QML editor configuration.
void setTextElementEditorConfiguration(const TextElementEditorConfiguration &textElementEditorConfiguration)
Sets the editor configuration for text element to textElementEditorConfiguration.
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,.
A dialog for configuring the Python init code handling for attribute forms.
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.
void externalItemDropped(QModelIndex &index)
Informs that items were inserted (via drop) in the model from another model.
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
void updateAliasForFieldItems(const QString &fieldName, const QString &fieldAlias)
Updates the aliases of all matching fields in the model.
bool removeRow(int row, const QModelIndex &parent=QModelIndex())
Removes the index located at row within the given parent.
void addContainer(QModelIndex &parent, const QString &name, int columnCount, Qgis::AttributeEditorContainerType type)
Adds a new container to parent.
QList< QgsAddAttributeFormContainerDialog::ContainerPair > listOfContainers() const
Returns a list of containers stored in the model, structured as pairs (name, container model index).
QgsAttributeEditorElement * createAttributeEditorWidget(const QModelIndex &index, QgsAttributeEditorElement *parent) const
Creates a new attribute editor element based on the definition stored in a form layout model index.
void internalItemDropped(QModelIndex &index)
Informs that items were moved (via drop) in the model from the same model.
Graphical representation for the form layout while configuring attributes forms.
void dropEvent(QDropEvent *event) override
void dragEnterEvent(QDragEnterEvent *event) override
QgsAttributesFormLayoutView(QgsVectorLayer *layer, QWidget *parent=nullptr)
Constructor for QgsAttributesFormLayoutView, with the given parent.
void setModel(QAbstractItemModel *model) override
Overridden setModel() from base class. Only QgsAttributesFormLayoutModel is an acceptable model.
QgsAttributesFormLayoutModel * formLayoutModel() const
Access the underlying QgsAttributesFormLayoutModel model.
void dragMoveEvent(QDragMoveEvent *event) override
Is called when mouse is moved over attributes tree before a drop event.
Abstract class for tree models allowing for configuration of 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.
void setShowAliases(bool show)
Sets whether field aliases should be preferred over field names as item text.
QModelIndex firstRecursiveMatchingModelIndex(const QgsAttributesFormData::AttributesFormItemType &itemType, const QString &itemId) const
Returns the first model index that matches the given itemType and itemId, recursively.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
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.
A HTML editor based on QScintilla2.
A text editor based on QScintilla2.
void setText(const QString &text) override
void setEditingTimeoutInterval(int timeout)
Sets the timeout (in milliseconds) threshold for the editingTimeout() signal to be emitted after an e...
void insertText(const QString &text)
Insert text at cursor position, or replace any selected text if user has made a selection.
void editingTimeout()
Emitted when either:
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.
Qgis::AttributeFormSuppression suppress() const
Type of feature form pop-up suppression after feature creation (overrides app setting)
QString uiForm() const
Returns the path or URL to the .ui form.
void setLabelOnTop(int idx, bool onTop)
If this is set to true, the widget at the given index will receive its label on the previous line whi...
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 setReuseLastValue(int index, bool reuse)
Sets whether the widget at the given index will remember the previously entered value from this QGIS ...
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.
Qgis::AttributeFormLayout layout() const
Gets the active layout style for the attribute editor for this layer.
Every attribute editor widget needs a factory, which inherits this class.
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.
A generic dialog for building expression strings.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static QgsExpressionContextScope * formScope(const QgsFeature &formFeature=QgsFeature(), const QString &formMode=QString())
Creates a new scope which contains functions and variables from the current attribute form/table form...
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
static QString findAndSelectActiveExpression(QgsCodeEditor *editor, const QString &pattern=QString())
Find the expression under the cursor in the given editor and select it.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
Stores information about constraints which may be present on a field.
ConstraintStrength
Strength of constraints.
@ 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
A widget for selection of layer fields or expression creation.
void setButtonVisible(bool visible)
Set the visibility of the button.
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:53
QString name
Definition qgsfield.h:62
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:761
Qgis::FieldDuplicatePolicy duplicatePolicy() const
Returns the field's duplicate policy, which indicates how field values should be handled during a dup...
Definition qgsfield.cpp:771
QgsDefaultValue defaultValueDefinition
Definition qgsfield.h:64
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:781
QString comment
Definition qgsfield.h:61
QgsFieldConstraints constraints
Definition qgsfield.h:65
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
Definition qgsfield.cpp:746
int count
Definition qgsfields.h:50
Q_INVOKABLE int indexOf(const QString &fieldName) const
Gets the field index from the field name.
QgsField field(int fieldIdx) const
Returns the field at particular index (must be in range 0..N-1).
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories.
Definition qgsgui.cpp:95
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
Definition qgsgui.cpp:210
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition qgshelp.cpp:39
Wraps a QQuickWidget to display HTML code.
void reinitWidget()
Clears the content and makes new initialization.
void setHtmlCode(const QString &htmlCode)
Sets the HTML code to htmlCode.
void setFeature(const QgsFeature &feature) override
QString id
Definition qgsmaplayer.h:80
A bar for displaying non-blocking messages to the user.
void pushMessage(const QString &text, Qgis::MessageLevel level=Qgis::MessageLevel::Info, int duration=-1)
A convenience method for pushing a message with the specified text to the bar.
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:107
static QgsProject * instance()
Returns the QgsProject singleton instance.
int count() const
Returns the number of properties contained within the collection.
Wraps a QQuickWidget to display QML code.
void setFeature(const QgsFeature &feature) override
void reinitWidget()
Clears the content and makes new initialization.
void setQmlCode(const QString &qmlCode)
writes the qmlCode into a temporary file
A container for the context for various read/write operations on objects.
const QgsProjectTranslator * projectTranslator() const
Returns the project translator.
A QScrollArea subclass with improved scrolling behavior.
T value(const QString &dynamicKeyPart=QString()) const
Returns settings value.
bool setValue(const T &value, const QString &dynamicKeyPart=QString()) const
Set settings value.
A boolean settings entry.
static const QgsSettingsEntryBool * settingsDigitizingDisableEnterAttributeValuesDialog
Settings entry digitizing disable enter attribute values dialog.
Stores settings for use within QGIS.
Definition qgssettings.h:65
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.
Wraps a label widget to display text.
void setText(const QString &text)
Sets the text code to htmlCode.
void reinitWidget()
Clears the content and makes new initialization.
void setFeature(const QgsFeature &feature) override
Represents a vector layer which manages a vector based dataset.
QgsDefaultValue defaultValueDefinition(int index) const
Returns the definition of the expression used when calculating the default value for a field.
void setFieldConstraint(int index, QgsFieldConstraints::Constraint constraint, QgsFieldConstraints::ConstraintStrength strength=QgsFieldConstraints::ConstraintStrengthHard)
Sets a constraint for a specified field index.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
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.
QgsActionManager * actions()
Returns all layer actions defined on this layer.
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.
QWidget * widget()
Access the widget managed by this wrapper.
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:6512
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition qgis.h:6493
The TabStyle struct defines color and font overrides for form fields, tabs and groups labels.
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