QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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 "qgsattributetypedialog.h"
20#include "qgsattributeformcontaineredit.h"
21#include "qgsattributewidgetedit.h"
23#include "qgsfieldcombobox.h"
24#include "qgsqmlwidgetwrapper.h"
26#include "qgsapplication.h"
27#include "qgscolorbutton.h"
28#include "qgscodeeditorhtml.h"
36
37
39 : QWidget( parent )
40 , mLayer( layer )
41{
42 if ( !layer )
43 return;
44
45 setupUi( this );
46
47 mEditorLayoutComboBox->addItem( tr( "Autogenerate" ), QgsEditFormConfig::EditorLayout::GeneratedLayout );
48 mEditorLayoutComboBox->addItem( tr( "Drag and Drop Designer" ), QgsEditFormConfig::EditorLayout::TabLayout );
49 mEditorLayoutComboBox->addItem( tr( "Provide ui-file" ), QgsEditFormConfig::EditorLayout::UiFileLayout );
50
51 // available widgets tree
52 QGridLayout *availableWidgetsWidgetLayout = new QGridLayout;
54 availableWidgetsWidgetLayout->addWidget( mAvailableWidgetsTree );
55 availableWidgetsWidgetLayout->setContentsMargins( 0, 0, 0, 0 );
56 mAvailableWidgetsWidget->setLayout( availableWidgetsWidgetLayout );
57 mAvailableWidgetsTree->setSelectionMode( QAbstractItemView::SelectionMode::ExtendedSelection );
58 mAvailableWidgetsTree->setHeaderLabels( QStringList() << tr( "Available Widgets" ) );
59 mAvailableWidgetsTree->setType( QgsAttributesDnDTree::Type::Drag );
60
61 // form layout tree
62 QGridLayout *formLayoutWidgetLayout = new QGridLayout;
64 mFormLayoutWidget->setLayout( formLayoutWidgetLayout );
65 formLayoutWidgetLayout->addWidget( mFormLayoutTree );
66 formLayoutWidgetLayout->setContentsMargins( 0, 0, 0, 0 );
67 mFormLayoutTree->setHeaderLabels( QStringList() << tr( "Form Layout" ) );
68 mFormLayoutTree->setType( QgsAttributesDnDTree::Type::Drop );
69
70 connect( mAvailableWidgetsTree, &QTreeWidget::itemSelectionChanged, this, &QgsAttributesFormProperties::onAttributeSelectionChanged );
71 connect( mFormLayoutTree, &QTreeWidget::itemSelectionChanged, this, &QgsAttributesFormProperties::onFormLayoutSelectionChanged );
72 connect( mAddTabOrGroupButton, &QAbstractButton::clicked, this, &QgsAttributesFormProperties::addTabOrGroupButton );
73 connect( mRemoveTabOrGroupButton, &QAbstractButton::clicked, this, &QgsAttributesFormProperties::removeTabOrGroupButton );
74 connect( mInvertSelectionButton, &QAbstractButton::clicked, this, &QgsAttributesFormProperties::onInvertSelectionButtonClicked );
75 connect( mEditorLayoutComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsAttributesFormProperties::mEditorLayoutComboBox_currentIndexChanged );
76 connect( pbnSelectEditForm, &QToolButton::clicked, this, &QgsAttributesFormProperties::pbnSelectEditForm_clicked );
77 connect( mTbInitCode, &QPushButton::clicked, this, &QgsAttributesFormProperties::mTbInitCode_clicked );
78}
79
81{
84
88}
89
91{
92 mAvailableWidgetsTree->clear();
93 mAvailableWidgetsTree->setSortingEnabled( false );
94 mAvailableWidgetsTree->setSelectionBehavior( QAbstractItemView::SelectRows );
95 mAvailableWidgetsTree->setAcceptDrops( false );
96 mAvailableWidgetsTree->setDragDropMode( QAbstractItemView::DragOnly );
97
98 //load Fields
99
100 DnDTreeItemData catItemData = DnDTreeItemData( DnDTreeItemData::WidgetType, QStringLiteral( "Fields" ), QStringLiteral( "Fields" ) );
101 QTreeWidgetItem *catitem = mAvailableWidgetsTree->addItem( mAvailableWidgetsTree->invisibleRootItem(), catItemData );
102
103 const QgsFields fields = mLayer->fields();
104 for ( int i = 0; i < fields.size(); ++i )
105 {
106 const QgsField field = fields.at( i );
108 itemData.setShowLabel( true );
109
110 FieldConfig cfg( mLayer, i );
111
112 QTreeWidgetItem *item = mAvailableWidgetsTree->addItem( catitem, itemData, -1, fields.iconForField( i, true ) );
113
114 item->setData( 0, FieldConfigRole, cfg );
115 item->setData( 0, FieldNameRole, field.name() );
116
117 QString tooltip;
118 if ( !field.alias().isEmpty() )
119 tooltip = tr( "%1 (%2)" ).arg( field.name(), field.alias() );
120 else
121 tooltip = field.name();
122 item->setToolTip( 0, tooltip );
123 }
124 catitem->setExpanded( true );
125
126 //load Relations
127 catItemData = DnDTreeItemData( DnDTreeItemData::WidgetType, QStringLiteral( "Relations" ), tr( "Relations" ) );
128 catitem = mAvailableWidgetsTree->addItem( mAvailableWidgetsTree->invisibleRootItem(), catItemData );
129
130 const QList<QgsRelation> relations = QgsProject::instance()->relationManager()->referencedRelations( mLayer );
131
132 for ( const QgsRelation &relation : relations )
133 {
134 DnDTreeItemData itemData = DnDTreeItemData( DnDTreeItemData::Relation, relation.id(), relation.name() );
135 itemData.setShowLabel( true );
136 QTreeWidgetItem *item = mAvailableWidgetsTree->addItem( catitem, itemData );
137 item->setData( 0, FieldNameRole, relation.id() );
138 }
139 catitem->setExpanded( true );
140
141 // Form actions
142 catItemData = DnDTreeItemData( DnDTreeItemData::WidgetType, QStringLiteral( "Actions" ), tr( "Actions" ) );
143 catitem = mAvailableWidgetsTree->addItem( mAvailableWidgetsTree->invisibleRootItem(), catItemData );
144
145 const QList<QgsAction> actions { mLayer->actions()->actions( ) };
146
147 for ( const auto &action : std::as_const( actions ) )
148 {
149 if ( action.isValid() && action.runable() &&
150 ( action.actionScopes().contains( QStringLiteral( "Feature" ) ) ||
151 action.actionScopes().contains( QStringLiteral( "Layer" ) ) ) )
152 {
153 const QString actionTitle { action.shortTitle().isEmpty() ? action.name() : action.shortTitle() };
154 DnDTreeItemData itemData = DnDTreeItemData( DnDTreeItemData::Action, action.id().toString(), actionTitle );
155 itemData.setShowLabel( true );
156 mAvailableWidgetsTree->addItem( catitem, itemData );
157 }
158 }
159
160 // QML/HTML widget
161 catItemData = DnDTreeItemData( DnDTreeItemData::WidgetType, QStringLiteral( "Other" ), tr( "Other Widgets" ) );
162 catitem = mAvailableWidgetsTree->addItem( mAvailableWidgetsTree->invisibleRootItem(), catItemData );
163
164 DnDTreeItemData itemData = DnDTreeItemData( DnDTreeItemData::QmlWidget, QStringLiteral( "QmlWidget" ), tr( "QML Widget" ) );
165 itemData.setShowLabel( true );
166 mAvailableWidgetsTree->addItem( catitem, itemData );
167
168 auto itemDataHtml { DnDTreeItemData( DnDTreeItemData::HtmlWidget, QStringLiteral( "HtmlWidget" ), tr( "HTML Widget" ) ) };
169 itemDataHtml.setShowLabel( true );
170 mAvailableWidgetsTree->addItem( catitem, itemDataHtml );
171 catitem ->setExpanded( true );
172}
173
175{
176 // tabs and groups info
177 mFormLayoutTree->clear();
178 mFormLayoutTree->setSortingEnabled( false );
179 mFormLayoutTree->setSelectionBehavior( QAbstractItemView::SelectRows );
180 mFormLayoutTree->setSelectionMode( QAbstractItemView::SelectionMode::ExtendedSelection );
181 mFormLayoutTree->setAcceptDrops( true );
182 mFormLayoutTree->setDragDropMode( QAbstractItemView::DragDrop );
183
184 const auto constTabs = mLayer->editFormConfig().tabs();
185 for ( QgsAttributeEditorElement *wdg : constTabs )
186 {
187 loadAttributeEditorTreeItem( wdg, mFormLayoutTree->invisibleRootItem(), mFormLayoutTree );
188 }
189}
190
191
193{
195 {
196 mFormSuppressCmbBx->addItem( tr( "Hide Form on Add Feature (global settings)" ) );
197 }
198 else
199 {
200 mFormSuppressCmbBx->addItem( tr( "Show Form on Add Feature (global settings)" ) );
201 }
202 mFormSuppressCmbBx->addItem( tr( "Hide Form on Add Feature" ) );
203 mFormSuppressCmbBx->addItem( tr( "Show Form on Add Feature" ) );
204
205 mFormSuppressCmbBx->setCurrentIndex( mLayer->editFormConfig().suppress() );
206}
207
209{
210 QgsExpressionContext context;
212 return context;
213}
214
216{
217 mEditorLayoutComboBox->setCurrentIndex( mEditorLayoutComboBox->findData( mLayer->editFormConfig().layout() ) );
218
219 mEditorLayoutComboBox_currentIndexChanged( mEditorLayoutComboBox->currentIndex() );
220
222 mEditFormLineEdit->setText( cfg.uiForm() );
223}
224
226{
228
229 mInitCodeSource = cfg.initCodeSource();
230 mInitFunction = cfg.initFunction();
231 mInitFilePath = cfg.initFilePath();
232 mInitCode = cfg.initCode();
233
234 if ( mInitCode.isEmpty() )
235 {
236 mInitCode.append( tr( "# -*- coding: utf-8 -*-\n\"\"\"\n"
237 "QGIS forms can have a Python function that is called when the form is\n"
238 "opened.\n"
239 "\n"
240 "Use this function to add extra logic to your forms.\n"
241 "\n"
242 "Enter the name of the function in the \"Python Init function\"\n"
243 "field.\n"
244 "An example follows:\n"
245 "\"\"\"\n"
246 "from qgis.PyQt.QtWidgets import QWidget\n\n"
247 "def my_form_open(dialog, layer, feature):\n"
248 " geom = feature.geometry()\n"
249 " control = dialog.findChild(QWidget, \"MyLineEdit\")\n" ) );
250 }
251}
252
253void QgsAttributesFormProperties::loadAttributeTypeDialog()
254{
255 if ( mAvailableWidgetsTree->selectedItems().count() != 1 )
256 return;
257
258 QTreeWidgetItem *item = mAvailableWidgetsTree->selectedItems().at( 0 );
259
260 const FieldConfig cfg = item->data( 0, FieldConfigRole ).value<FieldConfig>();
261 const QString fieldName = item->data( 0, FieldNameRole ).toString();
262 const int index = mLayer->fields().indexOf( fieldName );
263
264 if ( index < 0 )
265 return;
266
267 mAttributeTypeDialog = new QgsAttributeTypeDialog( mLayer, index, mAttributeTypeFrame );
268
269 const QgsFieldConstraints constraints = cfg.mFieldConstraints;
270
271 mAttributeTypeDialog->setAlias( cfg.mAlias );
272 mAttributeTypeDialog->setDataDefinedProperties( cfg.mDataDefinedProperties );
273 mAttributeTypeDialog->setComment( cfg.mComment );
274 mAttributeTypeDialog->setFieldEditable( cfg.mEditable );
275 mAttributeTypeDialog->setLabelOnTop( cfg.mLabelOnTop );
276 mAttributeTypeDialog->setReuseLastValues( cfg.mReuseLastValues );
281
282 QgsFieldConstraints::Constraints providerConstraints = QgsFieldConstraints::Constraints();
284 providerConstraints |= QgsFieldConstraints::ConstraintNotNull;
286 providerConstraints |= QgsFieldConstraints::ConstraintUnique;
288 providerConstraints |= QgsFieldConstraints::ConstraintExpression;
289 mAttributeTypeDialog->setProviderConstraints( providerConstraints );
290
291 mAttributeTypeDialog->setConstraintExpression( constraints.constraintExpression() );
292 mAttributeTypeDialog->setConstraintExpressionDescription( constraints.constraintDescription() );
294 mAttributeTypeDialog->setDefaultValueExpression( mLayer->defaultValueDefinition( index ).expression() );
295 mAttributeTypeDialog->setApplyDefaultValueOnUpdate( mLayer->defaultValueDefinition( index ).applyOnUpdate() );
296
297 mAttributeTypeDialog->setEditorWidgetConfig( cfg.mEditorWidgetConfig );
298 mAttributeTypeDialog->setEditorWidgetType( cfg.mEditorWidgetType );
299
300 mAttributeTypeDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
301 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
302
303 mAttributeTypeFrame->layout()->addWidget( mAttributeTypeDialog );
304}
305
306
307void QgsAttributesFormProperties::storeAttributeTypeDialog()
308{
310 return;
311
312 if ( mAttributeTypeDialog->fieldIdx() < 0 || mAttributeTypeDialog->fieldIdx() >= mLayer->fields().count() )
313 return;
314
315 FieldConfig cfg;
316
317 cfg.mComment = mLayer->fields().at( mAttributeTypeDialog->fieldIdx() ).comment();
318 cfg.mEditable = mAttributeTypeDialog->fieldEditable();
319 cfg.mLabelOnTop = mAttributeTypeDialog->labelOnTop();
320 cfg.mReuseLastValues = mAttributeTypeDialog->reuseLastValues();
321 cfg.mAlias = mAttributeTypeDialog->alias();
322 cfg.mDataDefinedProperties = mAttributeTypeDialog->dataDefinedProperties();
323
324 QgsFieldConstraints constraints;
325 if ( mAttributeTypeDialog->notNull() )
326 {
328 }
329 else if ( mAttributeTypeDialog->notNullFromProvider() )
330 {
332 }
333
334 if ( mAttributeTypeDialog->unique() )
335 {
337 }
338 else if ( mAttributeTypeDialog->uniqueFromProvider() )
339 {
341 }
342
343 if ( !mAttributeTypeDialog->constraintExpression().isEmpty() )
344 {
346 }
347
348 constraints.setConstraintExpression( mAttributeTypeDialog->constraintExpression(), mAttributeTypeDialog->constraintExpressionDescription() );
349
354 constraints.setConstraintStrength( QgsFieldConstraints::ConstraintExpression, mAttributeTypeDialog->constraintExpressionEnforced() ?
356
357 cfg.mFieldConstraints = constraints;
358
359 mLayer->setDefaultValueDefinition( mAttributeTypeDialog->fieldIdx(), QgsDefaultValue( mAttributeTypeDialog->defaultValueExpression(), mAttributeTypeDialog->applyDefaultValueOnUpdate() ) );
360
361 cfg.mEditorWidgetType = mAttributeTypeDialog->editorWidgetType();
362 cfg.mEditorWidgetConfig = mAttributeTypeDialog->editorWidgetConfig();
363
364 const QString fieldName = mLayer->fields().at( mAttributeTypeDialog->fieldIdx() ).name();
365
366 for ( auto itemIt = QTreeWidgetItemIterator( mAvailableWidgetsTree ); *itemIt; ++itemIt )
367 {
368 QTreeWidgetItem *item = *itemIt;
369 if ( item->data( 0, FieldNameRole ).toString() == fieldName )
370 item->setData( 0, FieldConfigRole, QVariant::fromValue<FieldConfig>( cfg ) );
371 }
372}
373
374void QgsAttributesFormProperties::storeAttributeWidgetEdit()
375{
377 return;
378
379 mAttributeWidgetEdit->updateItemData();
380}
381
382void QgsAttributesFormProperties::loadAttributeWidgetEdit()
383{
384 if ( mFormLayoutTree->selectedItems().count() != 1 )
385 return;
386
387 QTreeWidgetItem *currentItem = mFormLayoutTree->selectedItems().at( 0 );
388 mAttributeWidgetEdit = new QgsAttributeWidgetEdit( currentItem, this );
389 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
390 mAttributeTypeFrame->layout()->addWidget( mAttributeWidgetEdit );
391}
392
393void QgsAttributesFormProperties::loadInfoWidget( const QString &infoText )
394{
395 mInfoTextWidget = new QLabel( infoText );
396 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
397 mAttributeTypeFrame->layout()->addWidget( mInfoTextWidget );
398}
399
400void QgsAttributesFormProperties::storeAttributeContainerEdit()
401{
403 return;
404
405 mAttributeContainerEdit->updateItemData();
406}
407
408void QgsAttributesFormProperties::loadAttributeContainerEdit()
409{
410 if ( mFormLayoutTree->selectedItems().count() != 1 )
411 return;
412
413 QTreeWidgetItem *currentItem = mFormLayoutTree->selectedItems().at( 0 );
414 mAttributeContainerEdit = new QgsAttributeFormContainerEdit( currentItem, mLayer, this );
415 mAttributeContainerEdit->registerExpressionContextGenerator( this );
416 mAttributeContainerEdit->layout()->setContentsMargins( 0, 0, 0, 0 );
417 mAttributeTypeFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
418 mAttributeTypeFrame->layout()->addWidget( mAttributeContainerEdit );
419
420}
421
422QTreeWidgetItem *QgsAttributesFormProperties::loadAttributeEditorTreeItem( QgsAttributeEditorElement *const widgetDef, QTreeWidgetItem *parent, QgsAttributesDnDTree *tree )
423{
424 QTreeWidgetItem *newWidget = nullptr;
425 switch ( widgetDef->type() )
426 {
428 {
429 DnDTreeItemData itemData = DnDTreeItemData( DnDTreeItemData::Field, widgetDef->name(), widgetDef->name() );
430 itemData.setShowLabel( widgetDef->showLabel() );
431 itemData.setLabelStyle( widgetDef->labelStyle() );
432 newWidget = tree->addItem( parent, itemData );
433 break;
434 }
435
437 {
438 const QgsAttributeEditorAction *actionEditor = static_cast<const QgsAttributeEditorAction *>( widgetDef );
439 const QgsAction action { actionEditor->action( mLayer ) };
440 if ( action.isValid() )
441 {
442 DnDTreeItemData itemData = DnDTreeItemData( DnDTreeItemData::Action, action.id().toString(), action.shortTitle().isEmpty() ? action.name() : action.shortTitle() );
443 itemData.setShowLabel( widgetDef->showLabel() );
444 itemData.setLabelStyle( widgetDef->labelStyle() );
445 newWidget = tree->addItem( parent, itemData );
446 }
447 else
448 {
449 QgsDebugMsg( QStringLiteral( "Invalid form action" ) );
450 }
451 break;
452 }
453
455 {
456 const QgsAttributeEditorRelation *relationEditor = static_cast<const QgsAttributeEditorRelation *>( widgetDef );
457 DnDTreeItemData itemData = DnDTreeItemData( DnDTreeItemData::Relation, relationEditor->relation().id(), relationEditor->relation().name() );
458 itemData.setShowLabel( widgetDef->showLabel() );
459 itemData.setLabelStyle( widgetDef->labelStyle() );
460
461 RelationEditorConfiguration relEdConfig;
462// relEdConfig.buttons = relationEditor->visibleButtons();
463 relEdConfig.mRelationWidgetType = relationEditor->relationWidgetTypeId();
464 relEdConfig.mRelationWidgetConfig = relationEditor->relationEditorConfiguration();
465 relEdConfig.nmRelationId = relationEditor->nmRelationId();
466 relEdConfig.forceSuppressFormPopup = relationEditor->forceSuppressFormPopup();
467 relEdConfig.label = relationEditor->label();
468 itemData.setRelationEditorConfiguration( relEdConfig );
469 newWidget = tree->addItem( parent, itemData );
470 break;
471 }
472
474 {
475 DnDTreeItemData itemData( DnDTreeItemData::Container, widgetDef->name(), widgetDef->name() );
476 itemData.setShowLabel( widgetDef->showLabel() );
477
478 const QgsAttributeEditorContainer *container = static_cast<const QgsAttributeEditorContainer *>( widgetDef );
479 if ( !container )
480 break;
481
482 itemData.setColumnCount( container->columnCount() );
483 itemData.setShowAsGroupBox( container->isGroupBox() );
484 itemData.setBackgroundColor( container->backgroundColor() );
485 itemData.setVisibilityExpression( container->visibilityExpression() );
486 itemData.setCollapsedExpression( container->collapsedExpression() );
487 itemData.setCollapsed( container->collapsed() );
488 itemData.setLabelStyle( widgetDef->labelStyle() );
489 newWidget = tree->addItem( parent, itemData );
490
491 const QList<QgsAttributeEditorElement *> children = container->children();
492 for ( QgsAttributeEditorElement *wdg : children )
493 {
494 loadAttributeEditorTreeItem( wdg, newWidget, tree );
495 }
496 break;
497 }
498
500 {
501 const QgsAttributeEditorQmlElement *qmlElementEditor = static_cast<const QgsAttributeEditorQmlElement *>( widgetDef );
502 DnDTreeItemData itemData = DnDTreeItemData( DnDTreeItemData::QmlWidget, widgetDef->name(), widgetDef->name() );
503 itemData.setShowLabel( widgetDef->showLabel() );
504 QmlElementEditorConfiguration qmlEdConfig;
505 qmlEdConfig.qmlCode = qmlElementEditor->qmlCode();
506 itemData.setQmlElementEditorConfiguration( qmlEdConfig );
507 itemData.setLabelStyle( widgetDef->labelStyle() );
508 newWidget = tree->addItem( parent, itemData );
509 break;
510 }
511
513 {
514 const QgsAttributeEditorHtmlElement *htmlElementEditor = static_cast<const QgsAttributeEditorHtmlElement *>( widgetDef );
515 DnDTreeItemData itemData = DnDTreeItemData( DnDTreeItemData::HtmlWidget, widgetDef->name(), widgetDef->name() );
516 itemData.setShowLabel( widgetDef->showLabel() );
517 HtmlElementEditorConfiguration htmlEdConfig;
518 htmlEdConfig.htmlCode = htmlElementEditor->htmlCode();
519 itemData.setHtmlElementEditorConfiguration( htmlEdConfig );
520 itemData.setLabelStyle( widgetDef->labelStyle() );
521 newWidget = tree->addItem( parent, itemData );
522 break;
523 }
524
526 {
527 QgsDebugMsg( QStringLiteral( "Not loading invalid attribute editor type..." ) );
528 break;
529 }
530 }
531
532 return newWidget;
533}
534
535
536void QgsAttributesFormProperties::onAttributeSelectionChanged()
537{
538 disconnect( mFormLayoutTree, &QTreeWidget::itemSelectionChanged, this, &QgsAttributesFormProperties::onFormLayoutSelectionChanged );
539 loadAttributeSpecificEditor( mAvailableWidgetsTree, mFormLayoutTree );
540 connect( mFormLayoutTree, &QTreeWidget::itemSelectionChanged, this, &QgsAttributesFormProperties::onFormLayoutSelectionChanged );
541}
542
543void QgsAttributesFormProperties::onFormLayoutSelectionChanged()
544{
545 // when the selection changes in the DnD layout, sync the main tree
546 disconnect( mAvailableWidgetsTree, &QTreeWidget::itemSelectionChanged, this, &QgsAttributesFormProperties::onAttributeSelectionChanged );
547 loadAttributeSpecificEditor( mFormLayoutTree, mAvailableWidgetsTree );
548 connect( mAvailableWidgetsTree, &QTreeWidget::itemSelectionChanged, this, &QgsAttributesFormProperties::onAttributeSelectionChanged );
549}
550
551void QgsAttributesFormProperties::loadAttributeSpecificEditor( QgsAttributesDnDTree *emitter, QgsAttributesDnDTree *receiver )
552{
553 const QgsEditFormConfig::EditorLayout layout = mEditorLayoutComboBox->currentData().value<QgsEditFormConfig::EditorLayout>();
554
555 if ( layout == QgsEditFormConfig::EditorLayout::TabLayout )
556 storeAttributeWidgetEdit();
557 storeAttributeTypeDialog();
558 storeAttributeContainerEdit();
559
560 clearAttributeTypeFrame();
561
562 if ( emitter->selectedItems().count() != 1 )
563 {
564 receiver->clearSelection();
565 }
566 else
567 {
568 const DnDTreeItemData itemData = emitter->selectedItems().at( 0 )->data( 0, DnDTreeRole ).value<DnDTreeItemData>();
569 switch ( itemData.type() )
570 {
572 {
573 receiver->selectFirstMatchingItem( itemData );
574 if ( layout == QgsEditFormConfig::EditorLayout::TabLayout )
575 {
576 loadAttributeWidgetEdit();
577 }
578 else
579 {
580 loadInfoWidget( tr( "This configuration is available in the Drag and Drop Designer" ) );
581 }
582 break;
583 }
585 {
586 receiver->selectFirstMatchingItem( itemData );
587 if ( layout == QgsEditFormConfig::EditorLayout::TabLayout )
588 loadAttributeWidgetEdit();
589 loadAttributeTypeDialog();
590 break;
591 }
593 {
594 receiver->clearSelection();
595 loadAttributeContainerEdit();
596 break;
597 }
599 {
600 receiver->selectFirstMatchingItem( itemData );
601 const QgsAction action {mLayer->actions()->action( itemData.name() )};
602 loadInfoWidget( action.html() );
603 break;
604 }
607 {
608 if ( layout != QgsEditFormConfig::EditorLayout::TabLayout )
609 {
610 loadInfoWidget( tr( "This configuration is available with double-click in the Drag and Drop Designer" ) );
611 }
612 else
613 {
614 loadInfoWidget( tr( "This configuration is available with double-click" ) );
615 }
616 receiver->clearSelection();
617 break;
618 }
620 {
621 receiver->clearSelection();
622 break;
623 }
624 }
625 }
626}
627
628void QgsAttributesFormProperties::clearAttributeTypeFrame()
629{
631 {
632 mAttributeTypeFrame->layout()->removeWidget( mAttributeWidgetEdit );
633 mAttributeWidgetEdit->deleteLater();
634 mAttributeWidgetEdit = nullptr;
635 }
637 {
638 mAttributeTypeFrame->layout()->removeWidget( mAttributeTypeDialog );
639 mAttributeTypeDialog->deleteLater();
640 mAttributeTypeDialog = nullptr;
641 }
643 {
644 mAttributeTypeFrame->layout()->removeWidget( mAttributeContainerEdit );
645 mAttributeContainerEdit->deleteLater();
646 mAttributeContainerEdit = nullptr;
647 }
648 if ( mInfoTextWidget )
649 {
650 mAttributeTypeFrame->layout()->removeWidget( mInfoTextWidget );
651 mInfoTextWidget->deleteLater();
652 mInfoTextWidget = nullptr;
653 }
654}
655
656void QgsAttributesFormProperties::onInvertSelectionButtonClicked( bool checked )
657{
658 Q_UNUSED( checked )
659 const auto selectedItemList { mFormLayoutTree->selectedItems() };
660 const auto rootItem { mFormLayoutTree->invisibleRootItem() };
661 for ( int i = 0; i < rootItem->childCount(); ++i )
662 {
663 rootItem->child( i )->setSelected( ! selectedItemList.contains( rootItem->child( i ) ) );
664 }
665}
666
667void QgsAttributesFormProperties::addTabOrGroupButton()
668{
669 QList<QgsAddTabOrGroup::TabPair> tabList;
670
671 for ( QTreeWidgetItemIterator it( mFormLayoutTree ); *it; ++it )
672 {
673 const DnDTreeItemData itemData = ( *it )->data( 0, DnDTreeRole ).value<DnDTreeItemData>();
674 if ( itemData.type() == DnDTreeItemData::Container )
675 {
676 tabList.append( QgsAddTabOrGroup::TabPair( itemData.name(), *it ) );
677 }
678 }
679 QTreeWidgetItem *currentItem = mFormLayoutTree->selectedItems().value( 0 );
680 QgsAddTabOrGroup addTabOrGroup( mLayer, tabList, currentItem, this );
681
682 if ( !addTabOrGroup.exec() )
683 return;
684
685 const QString name = addTabOrGroup.name();
686 if ( addTabOrGroup.tabButtonIsChecked() )
687 {
688 mFormLayoutTree->addContainer( mFormLayoutTree->invisibleRootItem(), name, addTabOrGroup.columnCount() );
689 }
690 else
691 {
692 QTreeWidgetItem *tabItem = addTabOrGroup.tab();
693 mFormLayoutTree->addContainer( tabItem, name, addTabOrGroup.columnCount() );
694 }
695}
696
697void QgsAttributesFormProperties::removeTabOrGroupButton()
698{
699 qDeleteAll( mFormLayoutTree->selectedItems() );
700}
701
702
704{
705 QgsAttributeEditorElement *widgetDef = nullptr;
706
707 const DnDTreeItemData itemData = item->data( 0, DnDTreeRole ).value<DnDTreeItemData>();
708
709 switch ( itemData.type() )
710 {
711 //indexed here?
713 {
714 const int idx = mLayer->fields().lookupField( itemData.name() );
715 widgetDef = new QgsAttributeEditorField( itemData.name(), idx, parent );
716 break;
717 }
718
720 {
721 const QgsAction action { mLayer->actions()->action( itemData.name() )};
722 widgetDef = new QgsAttributeEditorAction( action, parent );
723 break;
724 }
725
727 {
728 const QgsRelation relation = QgsProject::instance()->relationManager()->relation( itemData.name() );
729 QgsAttributeEditorRelation *relDef = new QgsAttributeEditorRelation( relation, parent );
731 relDef->setRelationWidgetTypeId( relationEditorConfig.mRelationWidgetType );
732 relDef->setRelationEditorConfiguration( relationEditorConfig.mRelationWidgetConfig );
733 relDef->setNmRelationId( relationEditorConfig.nmRelationId );
734 relDef->setForceSuppressFormPopup( relationEditorConfig.forceSuppressFormPopup );
735 relDef->setLabel( relationEditorConfig.label );
736 widgetDef = relDef;
737 break;
738 }
739
741 {
742 QgsAttributeEditorContainer *container = new QgsAttributeEditorContainer( item->text( 0 ), parent, itemData.backgroundColor() );
743 container->setColumnCount( itemData.columnCount() );
744 container->setIsGroupBox( forceGroup ? true : itemData.showAsGroupBox() );
745 container->setCollapsed( itemData.collapsed() );
746 container->setCollapsedExpression( itemData.collapsedExpression() );
747 container->setVisibilityExpression( itemData.visibilityExpression() );
748 container->setBackgroundColor( itemData.backgroundColor( ) );
749
750 for ( int t = 0; t < item->childCount(); t++ )
751 {
752 QgsAttributeEditorElement *element { createAttributeEditorWidget( item->child( t ), container ) };
753 if ( element )
754 container->addChildElement( element );
755 }
756
757 widgetDef = container;
758 break;
759 }
760
762 {
763 QgsAttributeEditorQmlElement *element = new QgsAttributeEditorQmlElement( item->text( 0 ), parent );
764 element->setQmlCode( itemData.qmlElementEditorConfiguration().qmlCode );
765 widgetDef = element;
766 break;
767 }
768
770 {
771 QgsAttributeEditorHtmlElement *element = new QgsAttributeEditorHtmlElement( item->text( 0 ), parent );
773 widgetDef = element;
774 break;
775 }
776
778 break;
779
780 }
781
782 if ( widgetDef )
783 {
784 widgetDef->setShowLabel( itemData.showLabel() );
785 widgetDef->setLabelStyle( itemData.labelStyle() );
786 }
787
788 return widgetDef;
789}
790
791void QgsAttributesFormProperties::mEditorLayoutComboBox_currentIndexChanged( int index )
792{
793 Q_UNUSED( index )
794
795 const QgsEditFormConfig::EditorLayout layout = mEditorLayoutComboBox->currentData().value<QgsEditFormConfig::EditorLayout>();
796 switch ( layout )
797 {
798 case QgsEditFormConfig::EditorLayout::GeneratedLayout:
799 mFormLayoutWidget->setVisible( false );
800 mUiFileFrame->setVisible( false );
801 mAddTabOrGroupButton->setVisible( false );
802 mRemoveTabOrGroupButton->setVisible( false );
803 mInvertSelectionButton->setVisible( false );
804 break;
805
806 case QgsEditFormConfig::EditorLayout::TabLayout:
807 mFormLayoutWidget->setVisible( true );
808 mUiFileFrame->setVisible( false );
809 mAddTabOrGroupButton->setVisible( true );
810 mRemoveTabOrGroupButton->setVisible( true );
811 mInvertSelectionButton->setVisible( true );
812 break;
813
814 case QgsEditFormConfig::EditorLayout::UiFileLayout:
815 // ui file
816 mFormLayoutWidget->setVisible( false );
817 mUiFileFrame->setVisible( true );
818 mAddTabOrGroupButton->setVisible( false );
819 mRemoveTabOrGroupButton->setVisible( false );
820 mInvertSelectionButton->setVisible( false );
821 break;
822 }
823}
824
825void QgsAttributesFormProperties::mTbInitCode_clicked()
826{
827 QgsAttributesFormInitCode attributesFormInitCode;
828
829 attributesFormInitCode.setCodeSource( mInitCodeSource );
830 attributesFormInitCode.setInitCode( mInitCode );
831 attributesFormInitCode.setInitFilePath( mInitFilePath );
832 attributesFormInitCode.setInitFunction( mInitFunction );
833
834 if ( !attributesFormInitCode.exec() )
835 return;
836
837 mInitCodeSource = attributesFormInitCode.codeSource();
838 mInitCode = attributesFormInitCode.initCode();
839 mInitFilePath = attributesFormInitCode.initFilePath();
840 mInitFunction = attributesFormInitCode.initFunction();
841
842}
843
844void QgsAttributesFormProperties::pbnSelectEditForm_clicked()
845{
846 QgsSettings myQSettings;
847 const QString lastUsedDir = myQSettings.value( QStringLiteral( "style/lastUIDir" ), QDir::homePath() ).toString();
848 const QString uifilename = QFileDialog::getOpenFileName( this, tr( "Select edit form" ), lastUsedDir, tr( "UI file" ) + " (*.ui)" );
849
850 if ( uifilename.isNull() )
851 return;
852
853 const QFileInfo fi( uifilename );
854 myQSettings.setValue( QStringLiteral( "style/lastUIDir" ), fi.path() );
855 mEditFormLineEdit->setText( uifilename );
856}
857
859{
860 storeAttributeWidgetEdit();
861 storeAttributeContainerEdit();
862 storeAttributeTypeDialog();
863
864 QgsEditFormConfig editFormConfig = mLayer->editFormConfig();
865
866 QTreeWidgetItem *fieldContainer = mAvailableWidgetsTree->invisibleRootItem()->child( 0 );
867
868 for ( int i = 0; i < fieldContainer->childCount(); i++ )
869 {
870 QTreeWidgetItem *fieldItem = fieldContainer->child( i );
871 const FieldConfig cfg = fieldItem->data( 0, FieldConfigRole ).value<FieldConfig>();
872
873 const QString fieldName { fieldItem->data( 0, FieldNameRole ).toString() };
874 const int idx = mLayer->fields().indexOf( fieldName );
875
876 //continue in case field does not exist anymore
877 if ( idx < 0 )
878 continue;
879
880 editFormConfig.setReadOnly( idx, !cfg.mEditable );
881 editFormConfig.setLabelOnTop( idx, cfg.mLabelOnTop );
882 editFormConfig.setReuseLastValue( idx, cfg.mReuseLastValues );
883
884 if ( cfg.mDataDefinedProperties.count() > 0 )
885 {
886 editFormConfig.setDataDefinedFieldProperties( fieldName, cfg.mDataDefinedProperties );
887 }
888
890
891 const QgsFieldConstraints constraints = cfg.mFieldConstraints;
892 mLayer->setConstraintExpression( idx, constraints.constraintExpression(), constraints.constraintDescription() );
894 {
896 }
897 else
898 {
900 }
902 {
904 }
905 else
906 {
908 }
910 {
912 }
913 else
914 {
916 }
917
918 mLayer->setFieldAlias( idx, cfg.mAlias );
919 }
920
921 // tabs and groups
922 editFormConfig.clearTabs();
923 for ( int t = 0; t < mFormLayoutTree->invisibleRootItem()->childCount(); t++ )
924 {
925 QTreeWidgetItem *tabItem = mFormLayoutTree->invisibleRootItem()->child( t );
926 QgsAttributeEditorElement *editorElement { createAttributeEditorWidget( tabItem, nullptr, false ) };
927 if ( editorElement )
928 editFormConfig.addTab( editorElement );
929 }
930
931 editFormConfig.setUiForm( mEditFormLineEdit->text() );
932
933 editFormConfig.setLayout( static_cast<QgsEditFormConfig::EditorLayout>( mEditorLayoutComboBox->currentIndex() ) );
934
935 editFormConfig.setInitCodeSource( mInitCodeSource );
936 editFormConfig.setInitFunction( mInitFunction );
937 editFormConfig.setInitFilePath( mInitFilePath );
938 editFormConfig.setInitCode( mInitCode );
939
940 editFormConfig.setSuppress( static_cast<QgsEditFormConfig::FeatureFormSuppress>( mFormSuppressCmbBx->currentIndex() ) );
941
942 // write the legacy config of relation widgets to support settings read by the API
943 QTreeWidgetItem *relationContainer = mAvailableWidgetsTree->invisibleRootItem()->child( 1 );
944
945 for ( int i = 0; i < relationContainer->childCount(); i++ )
946 {
947 QTreeWidgetItem *relationItem = relationContainer->child( i );
948 const DnDTreeItemData itemData = relationItem->data( 0, DnDTreeRole ).value<DnDTreeItemData>();
949
950 for ( int t = 0; t < mFormLayoutTree->invisibleRootItem()->childCount(); t++ )
951 {
952 QTreeWidgetItem *tabItem = mFormLayoutTree->invisibleRootItem()->child( t );
953 const DnDTreeItemData tabItemData = tabItem->data( 0, DnDTreeRole ).value<DnDTreeItemData>();
954
955 if ( tabItemData.type() == itemData.type() && tabItemData.name() == itemData.name() )
956 {
957 QVariantMap cfg;
958
959 cfg[QStringLiteral( "nm-rel" )] = tabItemData.relationEditorConfiguration().nmRelationId;
960 cfg[QStringLiteral( "force-suppress-popup" )] = tabItemData.relationEditorConfiguration().forceSuppressFormPopup;
961
962 editFormConfig.setWidgetConfig( tabItemData.name(), cfg );
963 break;
964 }
965 }
966 }
967
968 mLayer->setEditFormConfig( editFormConfig );
969}
970
971
972/*
973 * FieldConfig implementation
974 */
976{
977 mAlias = layer->fields().at( idx ).alias();
979 mComment = layer->fields().at( idx ).comment();
980 mEditable = !layer->editFormConfig().readOnly( idx );
982 && layer->fields().fieldOrigin( idx ) != QgsFields::OriginExpression;
983 mLabelOnTop = layer->editFormConfig().labelOnTop( idx );
985 mFieldConstraints = layer->fields().at( idx ).constraints();
986 const QgsEditorWidgetSetup setup = QgsGui::editorWidgetRegistry()->findBest( layer, layer->fields().field( idx ).name() );
987 mEditorWidgetType = setup.type();
988 mEditorWidgetConfig = setup.config();
989}
990
991QgsAttributesFormProperties::FieldConfig::operator QVariant()
992{
993 return QVariant::fromValue<QgsAttributesFormProperties::FieldConfig>( *this );
994}
995
996/*
997 * RelationEditorConfiguration implementation
998 */
999
1000QgsAttributesFormProperties::RelationEditorConfiguration::operator QVariant()
1001{
1002 return QVariant::fromValue<QgsAttributesFormProperties::RelationEditorConfiguration>( *this );
1003}
1004
1005/*
1006 * DnDTree implementation
1007 */
1008
1009QTreeWidgetItem *QgsAttributesDnDTree::addContainer( QTreeWidgetItem *parent, const QString &title, int columnCount )
1010{
1011 QTreeWidgetItem *newItem = new QTreeWidgetItem( QStringList() << title );
1012 newItem->setBackground( 0, QBrush( Qt::lightGray ) );
1013 newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled );
1015 itemData.setColumnCount( columnCount );
1016 newItem->setData( 0, QgsAttributesFormProperties::DnDTreeRole, itemData );
1017 parent->addChild( newItem );
1018 newItem->setExpanded( true );
1019 return newItem;
1020}
1021
1023 : QTreeWidget( parent )
1024 , mLayer( layer )
1025{
1026 connect( this, &QTreeWidget::itemDoubleClicked, this, &QgsAttributesDnDTree::onItemDoubleClicked );
1027}
1028
1029QTreeWidgetItem *QgsAttributesDnDTree::addItem( QTreeWidgetItem *parent, QgsAttributesFormProperties::DnDTreeItemData data, int index, const QIcon &icon )
1030{
1031 QTreeWidgetItem *newItem = new QTreeWidgetItem( QStringList() << data.name() );
1032
1033 switch ( data.type() )
1034 {
1040 newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled );
1041 break;
1042
1045 {
1046 newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled );
1047 newItem->setBackground( 0, QBrush( Qt::lightGray ) );
1048 }
1049 break;
1050 }
1051
1052 newItem->setData( 0, QgsAttributesFormProperties::DnDTreeRole, data );
1053 newItem->setText( 0, data.displayName() );
1054 newItem->setIcon( 0, icon );
1055
1056 if ( index < 0 )
1057 parent->addChild( newItem );
1058 else
1059 parent->insertChild( index, newItem );
1060
1061 return newItem;
1062}
1063
1069void QgsAttributesDnDTree::dragMoveEvent( QDragMoveEvent *event )
1070{
1071 const QMimeData *data = event->mimeData();
1072
1073 if ( data->hasFormat( QStringLiteral( "application/x-qgsattributetabledesignerelement" ) ) )
1074 {
1076
1077 QByteArray itemData = data->data( QStringLiteral( "application/x-qgsattributetabledesignerelement" ) );
1078 QDataStream stream( &itemData, QIODevice::ReadOnly );
1079 stream >> itemElement;
1080
1081 // Inner drag and drop actions are always MoveAction
1082 if ( event->source() == this )
1083 {
1084 event->setDropAction( Qt::MoveAction );
1085 }
1086 }
1087 else
1088 {
1089 event->ignore();
1090 }
1091
1092 QTreeWidget::dragMoveEvent( event );
1093}
1094
1095
1096bool QgsAttributesDnDTree::dropMimeData( QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action )
1097{
1098 bool bDropSuccessful = false;
1099
1100 if ( action == Qt::IgnoreAction )
1101 {
1102 bDropSuccessful = true;
1103 }
1104 else if ( data->hasFormat( QStringLiteral( "application/x-qgsattributetabledesignerelement" ) ) )
1105 {
1106 QByteArray itemData = data->data( QStringLiteral( "application/x-qgsattributetabledesignerelement" ) );
1107 QDataStream stream( &itemData, QIODevice::ReadOnly );
1109
1110 while ( !stream.atEnd() )
1111 {
1112 stream >> itemElement;
1113
1114 QTreeWidgetItem *newItem;
1115
1116 if ( parent )
1117 {
1118 newItem = addItem( parent, itemElement, index++ );
1119 bDropSuccessful = true;
1120 }
1121 else
1122 {
1123 newItem = addItem( invisibleRootItem(), itemElement, index++ );
1124 bDropSuccessful = true;
1125 }
1126
1128 {
1129 onItemDoubleClicked( newItem, 0 );
1130 }
1131
1133 {
1134 onItemDoubleClicked( newItem, 0 );
1135 }
1136 clearSelection();
1137 newItem->setSelected( true );
1138 }
1139 }
1140
1141 return bDropSuccessful;
1142}
1143
1144void QgsAttributesDnDTree::dropEvent( QDropEvent *event )
1145{
1146 if ( !event->mimeData()->hasFormat( QStringLiteral( "application/x-qgsattributetabledesignerelement" ) ) )
1147 return;
1148
1149 if ( event->source() == this )
1150 {
1151 event->setDropAction( Qt::MoveAction );
1152 }
1153
1154 QTreeWidget::dropEvent( event );
1155}
1156
1158{
1159 return QStringList() << QStringLiteral( "application/x-qgsattributetabledesignerelement" );
1160}
1161
1162#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1163QMimeData *QgsAttributesDnDTree::mimeData( const QList<QTreeWidgetItem *> items ) const
1164#else
1165QMimeData *QgsAttributesDnDTree::mimeData( const QList<QTreeWidgetItem *> &items ) const
1166#endif
1167{
1168 if ( items.count() <= 0 )
1169 return nullptr;
1170
1171 const QStringList types = mimeTypes();
1172
1173 if ( types.isEmpty() )
1174 return nullptr;
1175
1176 QMimeData *data = new QMimeData();
1177 const QString format = types.at( 0 );
1178 QByteArray encoded;
1179 QDataStream stream( &encoded, QIODevice::WriteOnly );
1180
1181 const auto constItems = items;
1182 for ( const QTreeWidgetItem *item : constItems )
1183 {
1184 if ( item )
1185 {
1186 // Relevant information is always in the DnDTreeRole of the first column
1188 stream << itemData;
1189 }
1190 }
1191
1192 data->setData( format, encoded );
1193
1194 return data;
1195}
1196
1197void QgsAttributesDnDTree::onItemDoubleClicked( QTreeWidgetItem *item, int column )
1198{
1199 Q_UNUSED( column )
1200
1202
1203 QGroupBox *baseData = new QGroupBox( tr( "Base configuration" ) );
1204
1205 QFormLayout *baseLayout = new QFormLayout();
1206 baseData->setLayout( baseLayout );
1207 QCheckBox *showLabelCheckbox = new QCheckBox( QStringLiteral( "Show label" ) );
1208 showLabelCheckbox->setChecked( itemData.showLabel() );
1209 baseLayout->addRow( showLabelCheckbox );
1210 QWidget *baseWidget = new QWidget();
1211 baseWidget->setLayout( baseLayout );
1212
1213 switch ( itemData.type() )
1214 {
1220 break;
1221
1223 {
1224 if ( mType == QgsAttributesDnDTree::Type::Drag )
1225 return;
1226
1227 QDialog dlg;
1228 dlg.setWindowTitle( tr( "Configure QML Widget" ) );
1229
1230 QVBoxLayout *mainLayout = new QVBoxLayout();
1231 QHBoxLayout *qmlLayout = new QHBoxLayout();
1232 QVBoxLayout *layout = new QVBoxLayout();
1233 mainLayout->addLayout( qmlLayout );
1234 qmlLayout->addLayout( layout );
1235 dlg.setLayout( mainLayout );
1236 layout->addWidget( baseWidget );
1237
1238 QLineEdit *title = new QLineEdit( itemData.name() );
1239
1240 //qmlCode
1241 QPlainTextEdit *qmlCode = new QPlainTextEdit( itemData.qmlElementEditorConfiguration().qmlCode );
1242 qmlCode->setPlaceholderText( tr( "Insert QML code here…" ) );
1243
1244 QgsQmlWidgetWrapper *qmlWrapper = new QgsQmlWidgetWrapper( mLayer, nullptr, this );
1245 QgsFeature previewFeature;
1246 mLayer->getFeatures().nextFeature( previewFeature );
1247
1248 //update preview on text change
1249 connect( qmlCode, &QPlainTextEdit::textChanged, this, [ = ]
1250 {
1251 qmlWrapper->setQmlCode( qmlCode->toPlainText() );
1252 qmlWrapper->reinitWidget();
1253 qmlWrapper->setFeature( previewFeature );
1254 } );
1255
1256 //templates
1257 QComboBox *qmlObjectTemplate = new QComboBox();
1258 qmlObjectTemplate->addItem( tr( "Free Text…" ) );
1259 qmlObjectTemplate->addItem( tr( "Rectangle" ) );
1260 qmlObjectTemplate->addItem( tr( "Pie Chart" ) );
1261 qmlObjectTemplate->addItem( tr( "Bar Chart" ) );
1262 connect( qmlObjectTemplate, qOverload<int>( &QComboBox::activated ), qmlCode, [ = ]( int index )
1263 {
1264 qmlCode->clear();
1265 switch ( index )
1266 {
1267 case 0:
1268 {
1269 qmlCode->setPlaceholderText( tr( "Insert QML code here…" ) );
1270 break;
1271 }
1272 case 1:
1273 {
1274 qmlCode->insertPlainText( QStringLiteral( "import QtQuick 2.0\n"
1275 "\n"
1276 "Rectangle {\n"
1277 " width: 100\n"
1278 " height: 100\n"
1279 " color: \"steelblue\"\n"
1280 " Text{ text: \"A rectangle\" }\n"
1281 "}\n" ) );
1282 break;
1283 }
1284 case 2:
1285 {
1286 qmlCode->insertPlainText( QStringLiteral( "import QtQuick 2.0\n"
1287 "import QtCharts 2.0\n"
1288 "\n"
1289 "ChartView {\n"
1290 " width: 400\n"
1291 " height: 400\n"
1292 "\n"
1293 " PieSeries {\n"
1294 " id: pieSeries\n"
1295 " PieSlice { label: \"First slice\"; value: 25 }\n"
1296 " PieSlice { label: \"Second slice\"; value: 45 }\n"
1297 " PieSlice { label: \"Third slice\"; value: 30 }\n"
1298 " }\n"
1299 "}\n" ) );
1300 break;
1301 }
1302 case 3:
1303 {
1304 qmlCode->insertPlainText( QStringLiteral( "import QtQuick 2.0\n"
1305 "import QtCharts 2.0\n"
1306 "\n"
1307 "ChartView {\n"
1308 " title: \"Bar series\"\n"
1309 " width: 600\n"
1310 " height:400\n"
1311 " legend.alignment: Qt.AlignBottom\n"
1312 " antialiasing: true\n"
1313 " ValueAxis{\n"
1314 " id: valueAxisY\n"
1315 " min: 0\n"
1316 " max: 15\n"
1317 " }\n"
1318 "\n"
1319 " BarSeries {\n"
1320 " id: mySeries\n"
1321 " axisY: valueAxisY\n"
1322 " axisX: BarCategoryAxis { categories: [\"2007\", \"2008\", \"2009\", \"2010\", \"2011\", \"2012\" ] }\n"
1323 " BarSet { label: \"Bob\"; values: [2, 2, 3, 4, 5, 6] }\n"
1324 " BarSet { label: \"Susan\"; values: [5, 1, 2, 4, 1, 7] }\n"
1325 " BarSet { label: \"James\"; values: [3, 5, 8, 13, 5, 8] }\n"
1326 " }\n"
1327 "}\n" ) );
1328 break;
1329 }
1330 default:
1331 break;
1332 }
1333 } );
1334
1335 QgsFieldExpressionWidget *expressionWidget = new QgsFieldExpressionWidget;
1336 expressionWidget->setLayer( mLayer );
1337 QToolButton *addExpressionButton = new QToolButton();
1338 addExpressionButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/symbologyAdd.svg" ) ) );
1339
1340 connect( addExpressionButton, &QAbstractButton::clicked, this, [ = ]
1341 {
1342 qmlCode->insertPlainText( QStringLiteral( "expression.evaluate(\"%1\")" ).arg( expressionWidget->expression().replace( '"', QLatin1String( "\\\"" ) ) ) );
1343 } );
1344
1345 layout->addWidget( new QLabel( tr( "Title" ) ) );
1346 layout->addWidget( title );
1347 QGroupBox *qmlCodeBox = new QGroupBox( tr( "QML Code" ) );
1348 qmlCodeBox->setLayout( new QGridLayout );
1349 qmlCodeBox->layout()->addWidget( qmlObjectTemplate );
1350 QGroupBox *expressionWidgetBox = new QGroupBox();
1351 qmlCodeBox->layout()->addWidget( expressionWidgetBox );
1352 expressionWidgetBox->setLayout( new QHBoxLayout );
1353 expressionWidgetBox->layout()->addWidget( expressionWidget );
1354 expressionWidgetBox->layout()->addWidget( addExpressionButton );
1355 qmlCodeBox->layout()->addWidget( qmlCode );
1356 layout->addWidget( qmlCodeBox );
1357 QScrollArea *qmlPreviewBox = new QgsScrollArea();
1358 qmlPreviewBox->setLayout( new QGridLayout );
1359 qmlPreviewBox->setMinimumWidth( 400 );
1360 qmlPreviewBox->layout()->addWidget( qmlWrapper->widget() );
1361 //emit to load preview for the first time
1362 emit qmlCode->textChanged();
1363 qmlLayout->addWidget( qmlPreviewBox );
1364
1365 QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1366
1367 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1368 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1369
1370 mainLayout->addWidget( buttonBox );
1371
1372 if ( dlg.exec() )
1373 {
1375 qmlEdCfg.qmlCode = qmlCode->toPlainText();
1376 itemData.setName( title->text() );
1377 itemData.setQmlElementEditorConfiguration( qmlEdCfg );
1378 itemData.setShowLabel( showLabelCheckbox->isChecked() );
1379
1380 item->setData( 0, QgsAttributesFormProperties::DnDTreeRole, itemData );
1381 item->setText( 0, title->text() );
1382 }
1383 }
1384 break;
1385
1387 {
1388 if ( mType == QgsAttributesDnDTree::Type::Drag )
1389 return;
1390 QDialog dlg;
1391 dlg.setWindowTitle( tr( "Configure HTML Widget" ) );
1392
1393 QVBoxLayout *mainLayout = new QVBoxLayout();
1394 QHBoxLayout *htmlLayout = new QHBoxLayout();
1395 QVBoxLayout *layout = new QVBoxLayout();
1396 mainLayout->addLayout( htmlLayout );
1397 htmlLayout->addLayout( layout );
1398 dlg.setLayout( mainLayout );
1399 layout->addWidget( baseWidget );
1400
1401 QLineEdit *title = new QLineEdit( itemData.name() );
1402
1403 //htmlCode
1404 QgsCodeEditorHTML *htmlCode = new QgsCodeEditorHTML( );
1405 htmlCode->setSizePolicy( QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding );
1406 htmlCode->setText( itemData.htmlElementEditorConfiguration().htmlCode );
1407
1408 QgsHtmlWidgetWrapper *htmlWrapper = new QgsHtmlWidgetWrapper( mLayer, nullptr, this );
1409 QgsFeature previewFeature;
1410 mLayer->getFeatures().nextFeature( previewFeature );
1411
1412 //update preview on text change
1413 connect( htmlCode, &QgsCodeEditorHTML::textChanged, this, [ = ]
1414 {
1415 htmlWrapper->setHtmlCode( htmlCode->text( ) );
1416 htmlWrapper->reinitWidget();
1417 htmlWrapper->setFeature( previewFeature );
1418 } );
1419
1420 QgsFieldExpressionWidget *expressionWidget = new QgsFieldExpressionWidget;
1421 expressionWidget->setLayer( mLayer );
1422 QToolButton *addExpressionButton = new QToolButton();
1423 addExpressionButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/symbologyAdd.svg" ) ) );
1424
1425 connect( addExpressionButton, &QAbstractButton::clicked, this, [ = ]
1426 {
1427 htmlCode->insertText( QStringLiteral( "<script>document.write(expression.evaluate(\"%1\"));</script>" ).arg( expressionWidget->expression().replace( '"', QLatin1String( "\\\"" ) ) ) );
1428 } );
1429
1430 layout->addWidget( new QLabel( tr( "Title" ) ) );
1431 layout->addWidget( title );
1432 QGroupBox *expressionWidgetBox = new QGroupBox( tr( "HTML Code" ) );
1433 layout->addWidget( expressionWidgetBox );
1434 expressionWidgetBox->setLayout( new QHBoxLayout );
1435 expressionWidgetBox->layout()->addWidget( expressionWidget );
1436 expressionWidgetBox->layout()->addWidget( addExpressionButton );
1437 layout->addWidget( htmlCode );
1438 QScrollArea *htmlPreviewBox = new QgsScrollArea();
1439 htmlPreviewBox->setLayout( new QGridLayout );
1440 htmlPreviewBox->setMinimumWidth( 400 );
1441 htmlPreviewBox->layout()->addWidget( htmlWrapper->widget() );
1442 //emit to load preview for the first time
1443 emit htmlCode->textChanged();
1444 htmlLayout->addWidget( htmlPreviewBox );
1445
1446 QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1447
1448 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1449 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1450
1451 mainLayout->addWidget( buttonBox );
1452
1453 if ( dlg.exec() )
1454 {
1456 htmlEdCfg.htmlCode = htmlCode->text();
1457 itemData.setName( title->text() );
1458 itemData.setHtmlElementEditorConfiguration( htmlEdCfg );
1459 itemData.setShowLabel( showLabelCheckbox->isChecked() );
1460
1461 item->setData( 0, QgsAttributesFormProperties::DnDTreeRole, itemData );
1462 item->setText( 0, title->text() );
1463 }
1464 }
1465 break;
1466 }
1467}
1468
1470{
1471 return mType;
1472}
1473
1475{
1476 mType = value;
1477}
1478
1480{
1481 QTreeWidgetItemIterator it( this );
1482 while ( *it )
1483 {
1485 if ( data.type() == rowData.type() && data.name() == rowData.name() )
1486 {
1487 if ( selectedItems().count() == 1 && ( *it )->isSelected() == true )
1488 {
1489 // the selection is already good
1490 }
1491 else
1492 {
1493 clearSelection();
1494 ( *it )->setSelected( true );
1495 }
1496 return;
1497 }
1498 ++it;
1499 }
1500 clearSelection();
1501}
1502
1503
1504/*
1505 * Serialization helpers for DesigerTreeItemData so we can stuff this easily into QMimeData
1506 */
1507
1508QDataStream &operator<<( QDataStream &stream, const QgsAttributesFormProperties::DnDTreeItemData &data )
1509{
1510 stream << static_cast<quint32>( data.type() ) << data.name() << data.displayName();
1511 return stream;
1512}
1513
1514QDataStream &operator>>( QDataStream &stream, QgsAttributesFormProperties::DnDTreeItemData &data )
1515{
1516 QString name;
1517 QString displayName;
1518 quint32 type;
1519
1520 stream >> type >> name >> displayName;
1521
1523 data.setName( name );
1524 data.setDisplayName( displayName );
1525
1526 return stream;
1527}
1528
1530{
1531 return mShowAsGroupBox;
1532}
1533
1535{
1536 mShowAsGroupBox = showAsGroupBox;
1537}
1538
1540{
1541 return mLabelStyle;
1542}
1543
1545{
1546 mLabelStyle = labelStyle;
1547}
1548
1550{
1551 return mShowLabel;
1552}
1553
1555{
1556 mShowLabel = showLabel;
1557}
1558
1560{
1561 return mVisibilityExpression;
1562}
1563
1565{
1566 mVisibilityExpression = visibilityExpression;
1567}
1568
1570{
1571 return mCollapsedExpression;
1572}
1573
1575{
1576 mCollapsedExpression = collapsedExpression;
1577}
1578
1580{
1581 return mRelationEditorConfiguration;
1582}
1583
1585{
1586 mRelationEditorConfiguration = relationEditorConfiguration;
1587}
1588
1590{
1591 return mQmlElementEditorConfiguration;
1592}
1593
1595{
1596 mQmlElementEditorConfiguration = qmlElementEditorConfiguration;
1597}
1598
1599
1601{
1602 return mHtmlElementEditorConfiguration;
1603}
1604
1606{
1607 mHtmlElementEditorConfiguration = htmlElementEditorConfiguration;
1608}
1609
1611{
1612 return mBackgroundColor;
1613}
1614
1616{
1617 mBackgroundColor = backgroundColor;
1618}
QList< QgsAction > actions(const QString &actionScope=QString()) const
Returns a list of actions that are available in the given action scope.
QgsAction action(QUuid id) const
Gets an action by its id.
Utility class that encapsulates an action based on vector attributes.
Definition: qgsaction.h:35
Dialog to add a tab or group of attributes.
QPair< QString, QTreeWidgetItem * > TabPair
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
This element will load a layer action onto the form.
const QgsAction & action(const QgsVectorLayer *layer) const
Returns the (possibly lazy loaded) action for the given layer.
This is a container for attribute editors, used to group them visually in the attribute form if it is...
virtual void addChildElement(QgsAttributeEditorElement *element)
Add a child element to this container.
QgsOptionalExpression visibilityExpression() const
The visibility expression is used in the attribute form to show or hide this container based on an ex...
void setColumnCount(int columnCount)
Set the number of columns in this group.
virtual bool isGroupBox() const
Returns if this container is going to be a group box.
void setVisibilityExpression(const QgsOptionalExpression &visibilityExpression)
The visibility expression is used in the attribute form to show or hide this container based on an ex...
QgsOptionalExpression collapsedExpression() const
The collapsed expression is used in the attribute form to set the collapsed status of the group box c...
bool collapsed() const
For group box containers returns if this group box is collapsed.
void setCollapsedExpression(const QgsOptionalExpression &collapsedExpression)
The collapsed expression is used in the attribute form to set the collapsed status of the group box o...
virtual void setIsGroupBox(bool isGroupBox)
Determines if this container is rendered as collapsible group box or tab in a tabwidget.
QList< QgsAttributeEditorElement * > children() const
Gets a list of the children elements of this container.
QColor backgroundColor() const
backgroundColor
void setCollapsed(bool collapsed)
For group box containers sets if this group box is collapsed.
int columnCount() const
Gets the number of columns in this group.
void setBackgroundColor(const QColor &backgroundColor)
Sets the background color to backgroundColor.
This is an abstract base class for any elements of a drag and drop form.
LabelStyle labelStyle() const
Returns the label style.
void setLabelStyle(const LabelStyle &labelStyle)
Sets the labelStyle.
AttributeEditorType type() const
The type of this element.
bool showLabel() const
Controls if this element should be labeled with a title (field, relation or groupname).
QString name() const
Returns the name of this element.
void setShowLabel(bool showLabel)
Controls if this element should be labeled with a title (field, relation or groupname).
@ AeTypeAction
A layer action element (since QGIS 3.22)
This element will load a field's widget onto the form.
An attribute editor widget that will represent arbitrary HTML code.
QString htmlCode() const
The Html code that will be represented within this widget.
void setHtmlCode(const QString &htmlCode)
Sets the HTML code that will be represented within this widget to htmlCode.
An attribute editor widget that will represent arbitrary QML code.
QString qmlCode() const
The QML code that will be represented within this widget.
void setQmlCode(const QString &qmlCode)
Sets the QML code that will be represented within this widget to qmlCode.
This element will load a relation editor onto the form.
void setNmRelationId(const QVariant &nmRelationId=QVariant())
Sets nmRelationId for the relation id of the second relation involved in an N:M relation.
void setRelationWidgetTypeId(const QString &relationWidgetTypeId)
Sets the relation widget type.
const QgsRelation & relation() const
Gets the id of the relation which shall be embedded.
QVariantMap relationEditorConfiguration() const
Returns the relation editor widget configuration.
void setForceSuppressFormPopup(bool forceSuppressFormPopup)
Sets force suppress form popup status to forceSuppressFormPopup.
QVariant nmRelationId() const
Determines the relation id of the second relation involved in an N:M relation.
bool forceSuppressFormPopup() const
Determines the force suppress form popup status.
QString relationWidgetTypeId() const
Returns the current relation widget type id.
void setRelationEditorConfiguration(const QVariantMap &config)
Sets the relation editor configuration.
void setLabel(const QString &label=QString())
Sets label for this element If it's empty it takes the relation id as label.
QString label() const
Determines the label of this element.
This class overrides mime type handling to be able to work with the drag and drop attribute editor.
void setType(QgsAttributesDnDTree::Type value)
QTreeWidgetItem * addContainer(QTreeWidgetItem *parent, const QString &title, int columnCount)
QTreeWidgetItem * addItem(QTreeWidgetItem *parent, QgsAttributesFormProperties::DnDTreeItemData data, int index=-1, const QIcon &icon=QIcon())
Adds a new item to a parent.
void dropEvent(QDropEvent *event) override
QStringList mimeTypes() const override
QgsAttributesDnDTree(QgsVectorLayer *layer, QWidget *parent=nullptr)
QMimeData * mimeData(const QList< QTreeWidgetItem * > &items) const override
bool dropMimeData(QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action) override
void dragMoveEvent(QDragMoveEvent *event) override
Is called when mouse is moved over attributes tree before a drop event.
void selectFirstMatchingItem(const QgsAttributesFormProperties::DnDTreeItemData &data)
void setCodeSource(QgsEditFormConfig::PythonInitCodeSource initCodeSourceComboBoxIndex)
void setInitFilePath(const QString &initFilePath)
void setInitFunction(const QString &initFunction)
QgsEditFormConfig::PythonInitCodeSource codeSource() const
void setInitCode(const QString &initCode)
void setRelationEditorConfiguration(RelationEditorConfiguration relationEditorConfiguration)
void setLabelStyle(const QgsAttributeEditorElement::LabelStyle &labelStyle)
Sets the label style to labelStyle.
QmlElementEditorConfiguration qmlElementEditorConfiguration() const
void setQmlElementEditorConfiguration(QmlElementEditorConfiguration qmlElementEditorConfiguration)
const QgsAttributeEditorElement::LabelStyle labelStyle() const
Returns the label style.
void setVisibilityExpression(const QgsOptionalExpression &visibilityExpression)
Sets the optional visibilityExpression that dynamically controls the visibility status of a container...
QgsOptionalExpression collapsedExpression() const
Returns the optional expression that dynamically controls the collapsed status of a group box contain...
@ WidgetType
In the widget tree, the type of widget.
void setCollapsedExpression(const QgsOptionalExpression &collapsedExpression)
Sets the optional collapsedExpression that dynamically controls the collapsed status of a group box c...
HtmlElementEditorConfiguration htmlElementEditorConfiguration() const
void setHtmlElementEditorConfiguration(HtmlElementEditorConfiguration htmlElementEditorConfiguration)
bool collapsed() const
For group box containers returns if this group box is collapsed.
RelationEditorConfiguration relationEditorConfiguration() const
QgsAttributesDnDTree * mAvailableWidgetsTree
QgsAttributeFormContainerEdit * mAttributeContainerEdit
QgsAttributesFormProperties(QgsVectorLayer *layer, QWidget *parent=nullptr)
QgsAttributeTypeDialog * mAttributeTypeDialog
QgsAttributeEditorElement * createAttributeEditorWidget(QTreeWidgetItem *item, QgsAttributeEditorElement *parent, bool forceGroup=true)
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QgsAttributeWidgetEdit * mAttributeWidgetEdit
A HTML editor based on QScintilla2.
void insertText(const QString &text)
Insert text at cursor position, or replace any selected text if user has made a selection.
The QgsDefaultValue class provides a container for managing client side default values for fields.
Q_GADGET QString expression
Contains configuration settings for an editor form.
bool reuseLastValue(int index) const
If this returns true, the widget at the given index will remember the previously entered value from t...
bool readOnly(int idx) const
This returns true if the field is manually set to read only or if the field does not support editing ...
QString initCode() const
Gets Python code for edit form initialization.
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.
QgsPropertyCollection dataDefinedFieldProperties(const QString &fieldName) const
Returns data defined properties for fieldName.
EditorLayout
The different types to layout the attribute editor.
FeatureFormSuppress
Types of feature form suppression after feature creation.
FeatureFormSuppress suppress() const
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(EditorLayout editorLayout)
Sets the active layout style for the attribute editor for this layer.
void clearTabs()
Clears all the tabs for the attribute editor form with EditorLayout::TabLayout.
bool labelOnTop(int idx) const
If this returns true, the widget at the given index will receive its label on the previous line while...
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...
PythonInitCodeSource initCodeSource() const
Returns Python code source for edit form initialization (if it shall be loaded from a file,...
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 setSuppress(FeatureFormSuppress s)
Sets type of feature form pop-up suppression after feature creation (overrides app setting)
QList< QgsAttributeEditorElement * > tabs() const
Returns a list of tabs for EditorLayout::TabLayout obtained from the invisible root container.
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.
EditorLayout layout() const
Gets the active layout style for the attribute editor for this layer.
void setInitCodeSource(PythonInitCodeSource initCodeSource)
Sets if Python code shall be used for edit form initialization and its origin.
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.
QgsEditorWidgetSetup findBest(const QgsVectorLayer *vl, const QString &fieldName) const
Find the best editor widget and its configuration for a given field.
Holder for the widget type and its configuration for a field.
QVariantMap config() const
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
bool nextFeature(QgsFeature &f)
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
Stores information about constraints which may be present on a field.
@ ConstraintStrengthSoft
User is warned if constraint is violated but feature can still be accepted.
@ ConstraintStrengthHard
Constraint must be honored before feature can be accepted.
void setConstraintStrength(Constraint constraint, ConstraintStrength strength)
Sets the strength of a constraint.
void setConstraintExpression(const QString &expression, const QString &description=QString())
Set the constraint expression for the field.
@ ConstraintOriginProvider
Constraint was set at data provider.
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().
QString constraintDescription() const
Returns the descriptive name for the constraint expression.
Q_GADGET Constraints constraints
void setConstraint(Constraint constraint, ConstraintOrigin origin=ConstraintOriginLayer)
Sets a constraint on the field.
The QgsFieldExpressionWidget class reates a widget to choose fields and edit expressions It contains ...
void setLayer(QgsMapLayer *layer)
Sets the layer used to display the fields and expression.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
QString name
Definition: qgsfield.h:60
QString alias
Definition: qgsfield.h:61
QString comment
Definition: qgsfield.h:59
QgsFieldConstraints constraints
Definition: qgsfield.h:63
Container of fields for a vector layer.
Definition: qgsfields.h:45
int indexOf(const QString &fieldName) const
Gets the field index from the field name.
Definition: qgsfields.cpp:207
@ OriginExpression
Field is calculated from an expression.
Definition: qgsfields.h:54
@ OriginJoin
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
Definition: qgsfields.h:52
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
FieldOrigin fieldOrigin(int fieldIdx) const
Returns the field's origin (value from an enumeration).
Definition: qgsfields.cpp:189
QgsField field(int fieldIdx) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:168
int size() const
Returns number of items.
Definition: qgsfields.cpp:138
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:163
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:349
QIcon iconForField(int fieldIdx, bool considerOrigin=false) const
Returns an icon corresponding to a field index, based on the field's type and source.
Definition: qgsfields.cpp:275
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories.
Definition: qgsgui.cpp:83
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
An expression with an additional enabled flag.
QgsRelationManager * relationManager
Definition: qgsproject.h:114
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:477
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
QList< QgsRelation > referencedRelations(const QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
Q_INVOKABLE QgsRelation relation(const QString &id) const
Gets access to a relation by its id.
QString name
Definition: qgsrelation.h:48
Q_GADGET QString id
Definition: qgsrelation.h:45
A QScrollArea subclass with improved scrolling behavior.
Definition: qgsscrollarea.h:42
static const QgsSettingsEntryBool settingsDigitizingDisableEnterAttributeValuesDialog
Settings entry digitizing disable enter attribute values dialog.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Represents a vector layer which manages a vector based data sets.
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.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
void removeFieldConstraint(int index, QgsFieldConstraints::Constraint constraint)
Removes a constraint for a specified field 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)
The editor widget setup defines which QgsFieldFormatter and editor widget will be used for the field ...
void setConstraintExpression(int index, const QString &expression, const QString &description=QString())
Sets the constraint expression for the specified field 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.
QgsEditFormConfig editFormConfig
QWidget * widget()
Access the widget managed by this wrapper.
QDataStream & operator>>(QDataStream &stream, QgsAttributesFormProperties::DnDTreeItemData &data)
QDataStream & operator<<(QDataStream &stream, const QgsAttributesFormProperties::DnDTreeItemData &data)
const QgsField & field
Definition: qgsfield.h:463
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
The TabStyle struct defines color and font overrides for form fields, tabs and groups labels.