QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
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"
25 #include "qgshtmlwidgetwrapper.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 
221  const QgsEditFormConfig cfg = mLayer->editFormConfig();
222  mEditFormLineEdit->setText( cfg.uiForm() );
223 }
224 
226 {
227  const QgsEditFormConfig cfg = mLayer->editFormConfig();
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  "\tgeom = feature.geometry()\n"
249  "\tcontrol = dialog.findChild(QWidget, \"MyLineEdit\")\n" ) );
250  }
251 }
252 
253 void 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 
307 void QgsAttributesFormProperties::storeAttributeTypeDialog()
308 {
309  if ( !mAttributeTypeDialog )
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 
374 void QgsAttributesFormProperties::storeAttributeWidgetEdit()
375 {
376  if ( !mAttributeWidgetEdit )
377  return;
378 
379  mAttributeWidgetEdit->updateItemData();
380 }
381 
382 void 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 
393 void 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 
400 void QgsAttributesFormProperties::storeAttributeContainerEdit()
401 {
403  return;
404 
405  mAttributeContainerEdit->updateItemData();
406 }
407 
408 void 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 QTreeWidgetItem *QgsAttributesFormProperties::loadAttributeEditorTreeItem( QgsAttributeEditorElement *const widgetDef, QTreeWidgetItem *parent, QgsAttributesDnDTree *tree )
422 {
423  QTreeWidgetItem *newWidget = nullptr;
424  switch ( widgetDef->type() )
425  {
427  {
428  DnDTreeItemData itemData = DnDTreeItemData( DnDTreeItemData::Field, widgetDef->name(), widgetDef->name() );
429  itemData.setShowLabel( widgetDef->showLabel() );
430  newWidget = tree->addItem( parent, itemData );
431  break;
432  }
433 
435  {
436  const QgsAttributeEditorAction *actionEditor = static_cast<const QgsAttributeEditorAction *>( widgetDef );
437  const QgsAction action { actionEditor->action( mLayer ) };
438  if ( action.isValid() )
439  {
440  DnDTreeItemData itemData = DnDTreeItemData( DnDTreeItemData::Action, action.id().toString(), action.shortTitle().isEmpty() ? action.name() : action.shortTitle() );
441  itemData.setShowLabel( widgetDef->showLabel() );
442  newWidget = tree->addItem( parent, itemData );
443  }
444  else
445  {
446  QgsDebugMsg( QStringLiteral( "Invalid form action" ) );
447  }
448  break;
449  }
450 
452  {
453  const QgsAttributeEditorRelation *relationEditor = static_cast<const QgsAttributeEditorRelation *>( widgetDef );
454  DnDTreeItemData itemData = DnDTreeItemData( DnDTreeItemData::Relation, relationEditor->relation().id(), relationEditor->relation().name() );
455  itemData.setShowLabel( widgetDef->showLabel() );
456 
457  RelationEditorConfiguration relEdConfig;
458 // relEdConfig.buttons = relationEditor->visibleButtons();
459  relEdConfig.mRelationWidgetType = relationEditor->relationWidgetTypeId();
460  relEdConfig.mRelationWidgetConfig = relationEditor->relationEditorConfiguration();
461  relEdConfig.nmRelationId = relationEditor->nmRelationId();
462  relEdConfig.forceSuppressFormPopup = relationEditor->forceSuppressFormPopup();
463  relEdConfig.label = relationEditor->label();
464  itemData.setRelationEditorConfiguration( relEdConfig );
465  newWidget = tree->addItem( parent, itemData );
466  break;
467  }
468 
470  {
471  DnDTreeItemData itemData( DnDTreeItemData::Container, widgetDef->name(), widgetDef->name() );
472  itemData.setShowLabel( widgetDef->showLabel() );
473 
474  const QgsAttributeEditorContainer *container = static_cast<const QgsAttributeEditorContainer *>( widgetDef );
475  if ( !container )
476  break;
477 
478  itemData.setColumnCount( container->columnCount() );
479  itemData.setShowAsGroupBox( container->isGroupBox() );
480  itemData.setBackgroundColor( container->backgroundColor() );
481  itemData.setVisibilityExpression( container->visibilityExpression() );
482  newWidget = tree->addItem( parent, itemData );
483 
484  const QList<QgsAttributeEditorElement *> children = container->children();
485  for ( QgsAttributeEditorElement *wdg : children )
486  {
487  loadAttributeEditorTreeItem( wdg, newWidget, tree );
488  }
489  break;
490  }
491 
493  {
494  const QgsAttributeEditorQmlElement *qmlElementEditor = static_cast<const QgsAttributeEditorQmlElement *>( widgetDef );
495  DnDTreeItemData itemData = DnDTreeItemData( DnDTreeItemData::QmlWidget, widgetDef->name(), widgetDef->name() );
496  itemData.setShowLabel( widgetDef->showLabel() );
497  QmlElementEditorConfiguration qmlEdConfig;
498  qmlEdConfig.qmlCode = qmlElementEditor->qmlCode();
499  itemData.setQmlElementEditorConfiguration( qmlEdConfig );
500  newWidget = tree->addItem( parent, itemData );
501  break;
502  }
503 
505  {
506  const QgsAttributeEditorHtmlElement *htmlElementEditor = static_cast<const QgsAttributeEditorHtmlElement *>( widgetDef );
507  DnDTreeItemData itemData = DnDTreeItemData( DnDTreeItemData::HtmlWidget, widgetDef->name(), widgetDef->name() );
508  itemData.setShowLabel( widgetDef->showLabel() );
509  HtmlElementEditorConfiguration htmlEdConfig;
510  htmlEdConfig.htmlCode = htmlElementEditor->htmlCode();
511  itemData.setHtmlElementEditorConfiguration( htmlEdConfig );
512  newWidget = tree->addItem( parent, itemData );
513  break;
514  }
515 
517  {
518  QgsDebugMsg( QStringLiteral( "Not loading invalid attribute editor type..." ) );
519  break;
520  }
521  }
522 
523  return newWidget;
524 }
525 
526 
527 void QgsAttributesFormProperties::onAttributeSelectionChanged()
528 {
529  disconnect( mFormLayoutTree, &QTreeWidget::itemSelectionChanged, this, &QgsAttributesFormProperties::onFormLayoutSelectionChanged );
530  loadAttributeSpecificEditor( mAvailableWidgetsTree, mFormLayoutTree );
531  connect( mFormLayoutTree, &QTreeWidget::itemSelectionChanged, this, &QgsAttributesFormProperties::onFormLayoutSelectionChanged );
532 }
533 
534 void QgsAttributesFormProperties::onFormLayoutSelectionChanged()
535 {
536  // when the selection changes in the DnD layout, sync the main tree
537  disconnect( mAvailableWidgetsTree, &QTreeWidget::itemSelectionChanged, this, &QgsAttributesFormProperties::onAttributeSelectionChanged );
538  loadAttributeSpecificEditor( mFormLayoutTree, mAvailableWidgetsTree );
539  connect( mAvailableWidgetsTree, &QTreeWidget::itemSelectionChanged, this, &QgsAttributesFormProperties::onAttributeSelectionChanged );
540 }
541 
542 void QgsAttributesFormProperties::loadAttributeSpecificEditor( QgsAttributesDnDTree *emitter, QgsAttributesDnDTree *receiver )
543 {
544  const QgsEditFormConfig::EditorLayout layout = mEditorLayoutComboBox->currentData().value<QgsEditFormConfig::EditorLayout>();
545 
546  if ( layout == QgsEditFormConfig::EditorLayout::TabLayout )
547  storeAttributeWidgetEdit();
548  storeAttributeTypeDialog();
549  storeAttributeContainerEdit();
550 
551  clearAttributeTypeFrame();
552 
553  if ( emitter->selectedItems().count() != 1 )
554  {
555  receiver->clearSelection();
556  }
557  else
558  {
559  const DnDTreeItemData itemData = emitter->selectedItems().at( 0 )->data( 0, DnDTreeRole ).value<DnDTreeItemData>();
560  switch ( itemData.type() )
561  {
563  {
564  receiver->selectFirstMatchingItem( itemData );
565  if ( layout == QgsEditFormConfig::EditorLayout::TabLayout )
566  {
567  loadAttributeWidgetEdit();
568  }
569  else
570  {
571  loadInfoWidget( tr( "This configuration is available in the Drag and Drop Designer" ) );
572  }
573  break;
574  }
576  {
577  receiver->selectFirstMatchingItem( itemData );
578  if ( layout == QgsEditFormConfig::EditorLayout::TabLayout )
579  loadAttributeWidgetEdit();
580  loadAttributeTypeDialog();
581  break;
582  }
584  {
585  receiver->clearSelection();
586  loadAttributeContainerEdit();
587  break;
588  }
590  {
591  receiver->selectFirstMatchingItem( itemData );
592  const QgsAction action {mLayer->actions()->action( itemData.name() )};
593  loadInfoWidget( action.html() );
594  break;
595  }
598  {
599  if ( layout != QgsEditFormConfig::EditorLayout::TabLayout )
600  {
601  loadInfoWidget( tr( "This configuration is available with double-click in the Drag and Drop Designer" ) );
602  }
603  else
604  {
605  loadInfoWidget( tr( "This configuration is available with double-click" ) );
606  }
607  receiver->clearSelection();
608  break;
609  }
611  {
612  receiver->clearSelection();
613  break;
614  }
615  }
616  }
617 }
618 
619 void QgsAttributesFormProperties::clearAttributeTypeFrame()
620 {
621  if ( mAttributeWidgetEdit )
622  {
623  mAttributeTypeFrame->layout()->removeWidget( mAttributeWidgetEdit );
624  mAttributeWidgetEdit->deleteLater();
625  mAttributeWidgetEdit = nullptr;
626  }
627  if ( mAttributeTypeDialog )
628  {
629  mAttributeTypeFrame->layout()->removeWidget( mAttributeTypeDialog );
630  mAttributeTypeDialog->deleteLater();
631  mAttributeTypeDialog = nullptr;
632  }
634  {
635  mAttributeTypeFrame->layout()->removeWidget( mAttributeContainerEdit );
636  mAttributeContainerEdit->deleteLater();
637  mAttributeContainerEdit = nullptr;
638  }
639  if ( mInfoTextWidget )
640  {
641  mAttributeTypeFrame->layout()->removeWidget( mInfoTextWidget );
642  mInfoTextWidget->deleteLater();
643  mInfoTextWidget = nullptr;
644  }
645 }
646 
647 void QgsAttributesFormProperties::onInvertSelectionButtonClicked( bool checked )
648 {
649  Q_UNUSED( checked )
650  const auto selectedItemList { mFormLayoutTree->selectedItems() };
651  const auto rootItem { mFormLayoutTree->invisibleRootItem() };
652  for ( int i = 0; i < rootItem->childCount(); ++i )
653  {
654  rootItem->child( i )->setSelected( ! selectedItemList.contains( rootItem->child( i ) ) );
655  }
656 }
657 
658 void QgsAttributesFormProperties::addTabOrGroupButton()
659 {
660  QList<QgsAddTabOrGroup::TabPair> tabList;
661 
662  for ( QTreeWidgetItemIterator it( mFormLayoutTree ); *it; ++it )
663  {
664  const DnDTreeItemData itemData = ( *it )->data( 0, DnDTreeRole ).value<DnDTreeItemData>();
665  if ( itemData.type() == DnDTreeItemData::Container )
666  {
667  tabList.append( QgsAddTabOrGroup::TabPair( itemData.name(), *it ) );
668  }
669  }
670  QTreeWidgetItem *currentItem = mFormLayoutTree->selectedItems().value( 0 );
671  QgsAddTabOrGroup addTabOrGroup( mLayer, tabList, currentItem, this );
672 
673  if ( !addTabOrGroup.exec() )
674  return;
675 
676  const QString name = addTabOrGroup.name();
677  if ( addTabOrGroup.tabButtonIsChecked() )
678  {
679  mFormLayoutTree->addContainer( mFormLayoutTree->invisibleRootItem(), name, addTabOrGroup.columnCount() );
680  }
681  else
682  {
683  QTreeWidgetItem *tabItem = addTabOrGroup.tab();
684  mFormLayoutTree->addContainer( tabItem, name, addTabOrGroup.columnCount() );
685  }
686 }
687 
688 void QgsAttributesFormProperties::removeTabOrGroupButton()
689 {
690  qDeleteAll( mFormLayoutTree->selectedItems() );
691 }
692 
693 
695 {
696  QgsAttributeEditorElement *widgetDef = nullptr;
697 
698  const DnDTreeItemData itemData = item->data( 0, DnDTreeRole ).value<DnDTreeItemData>();
699 
700  switch ( itemData.type() )
701  {
702  //indexed here?
704  {
705  const int idx = mLayer->fields().lookupField( itemData.name() );
706  widgetDef = new QgsAttributeEditorField( itemData.name(), idx, parent );
707  break;
708  }
709 
711  {
712  const QgsAction action { mLayer->actions()->action( itemData.name() )};
713  widgetDef = new QgsAttributeEditorAction( action, parent );
714  break;
715  }
716 
718  {
719  const QgsRelation relation = QgsProject::instance()->relationManager()->relation( itemData.name() );
720  QgsAttributeEditorRelation *relDef = new QgsAttributeEditorRelation( relation, parent );
722  relDef->setRelationWidgetTypeId( relationEditorConfig.mRelationWidgetType );
723  relDef->setRelationEditorConfiguration( relationEditorConfig.mRelationWidgetConfig );
724  relDef->setNmRelationId( relationEditorConfig.nmRelationId );
725  relDef->setForceSuppressFormPopup( relationEditorConfig.forceSuppressFormPopup );
726  relDef->setLabel( relationEditorConfig.label );
727  widgetDef = relDef;
728  break;
729  }
730 
732  {
733  QgsAttributeEditorContainer *container = new QgsAttributeEditorContainer( item->text( 0 ), parent, itemData.backgroundColor() );
734  container->setColumnCount( itemData.columnCount() );
735  container->setIsGroupBox( forceGroup ? true : itemData.showAsGroupBox() );
736  container->setVisibilityExpression( itemData.visibilityExpression() );
737  container->setBackgroundColor( itemData.backgroundColor( ) );
738 
739  for ( int t = 0; t < item->childCount(); t++ )
740  {
741  QgsAttributeEditorElement *element { createAttributeEditorWidget( item->child( t ), container ) };
742  if ( element )
743  container->addChildElement( element );
744  }
745 
746  widgetDef = container;
747  break;
748  }
749 
751  {
752  QgsAttributeEditorQmlElement *element = new QgsAttributeEditorQmlElement( item->text( 0 ), parent );
753  element->setQmlCode( itemData.qmlElementEditorConfiguration().qmlCode );
754  widgetDef = element;
755  break;
756  }
757 
759  {
760  QgsAttributeEditorHtmlElement *element = new QgsAttributeEditorHtmlElement( item->text( 0 ), parent );
761  element->setHtmlCode( itemData.htmlElementEditorConfiguration().htmlCode );
762  widgetDef = element;
763  break;
764  }
765 
767  break;
768 
769  }
770 
771  if ( widgetDef )
772  widgetDef->setShowLabel( itemData.showLabel() );
773 
774  return widgetDef;
775 }
776 
777 void QgsAttributesFormProperties::mEditorLayoutComboBox_currentIndexChanged( int index )
778 {
779  Q_UNUSED( index )
780 
781  const QgsEditFormConfig::EditorLayout layout = mEditorLayoutComboBox->currentData().value<QgsEditFormConfig::EditorLayout>();
782  switch ( layout )
783  {
784  case QgsEditFormConfig::EditorLayout::GeneratedLayout:
785  mFormLayoutWidget->setVisible( false );
786  mUiFileFrame->setVisible( false );
787  mAddTabOrGroupButton->setVisible( false );
788  mRemoveTabOrGroupButton->setVisible( false );
789  mInvertSelectionButton->setVisible( false );
790  break;
791 
792  case QgsEditFormConfig::EditorLayout::TabLayout:
793  mFormLayoutWidget->setVisible( true );
794  mUiFileFrame->setVisible( false );
795  mAddTabOrGroupButton->setVisible( true );
796  mRemoveTabOrGroupButton->setVisible( true );
797  mInvertSelectionButton->setVisible( true );
798  break;
799 
800  case QgsEditFormConfig::EditorLayout::UiFileLayout:
801  // ui file
802  mFormLayoutWidget->setVisible( false );
803  mUiFileFrame->setVisible( true );
804  mAddTabOrGroupButton->setVisible( false );
805  mRemoveTabOrGroupButton->setVisible( false );
806  mInvertSelectionButton->setVisible( false );
807  break;
808  }
809 }
810 
811 void QgsAttributesFormProperties::mTbInitCode_clicked()
812 {
813  QgsAttributesFormInitCode attributesFormInitCode;
814 
815  attributesFormInitCode.setCodeSource( mInitCodeSource );
816  attributesFormInitCode.setInitCode( mInitCode );
817  attributesFormInitCode.setInitFilePath( mInitFilePath );
818  attributesFormInitCode.setInitFunction( mInitFunction );
819 
820  if ( !attributesFormInitCode.exec() )
821  return;
822 
823  mInitCodeSource = attributesFormInitCode.codeSource();
824  mInitCode = attributesFormInitCode.initCode();
825  mInitFilePath = attributesFormInitCode.initFilePath();
826  mInitFunction = attributesFormInitCode.initFunction();
827 
828 }
829 
830 void QgsAttributesFormProperties::pbnSelectEditForm_clicked()
831 {
832  QgsSettings myQSettings;
833  const QString lastUsedDir = myQSettings.value( QStringLiteral( "style/lastUIDir" ), QDir::homePath() ).toString();
834  const QString uifilename = QFileDialog::getOpenFileName( this, tr( "Select edit form" ), lastUsedDir, tr( "UI file" ) + " (*.ui)" );
835 
836  if ( uifilename.isNull() )
837  return;
838 
839  const QFileInfo fi( uifilename );
840  myQSettings.setValue( QStringLiteral( "style/lastUIDir" ), fi.path() );
841  mEditFormLineEdit->setText( uifilename );
842 }
843 
845 {
846  storeAttributeWidgetEdit();
847  storeAttributeContainerEdit();
848  storeAttributeTypeDialog();
849 
850  QgsEditFormConfig editFormConfig = mLayer->editFormConfig();
851 
852  QTreeWidgetItem *fieldContainer = mAvailableWidgetsTree->invisibleRootItem()->child( 0 );
853 
854  for ( int i = 0; i < fieldContainer->childCount(); i++ )
855  {
856  QTreeWidgetItem *fieldItem = fieldContainer->child( i );
857  const FieldConfig cfg = fieldItem->data( 0, FieldConfigRole ).value<FieldConfig>();
858 
859  const QString fieldName { fieldItem->data( 0, FieldNameRole ).toString() };
860  const int idx = mLayer->fields().indexOf( fieldName );
861 
862  //continue in case field does not exist anymore
863  if ( idx < 0 )
864  continue;
865 
866  editFormConfig.setReadOnly( idx, !cfg.mEditable );
867  editFormConfig.setLabelOnTop( idx, cfg.mLabelOnTop );
868  editFormConfig.setReuseLastValue( idx, cfg.mReuseLastValues );
869 
870  if ( cfg.mDataDefinedProperties.count() > 0 )
871  {
872  editFormConfig.setDataDefinedFieldProperties( fieldName, cfg.mDataDefinedProperties );
873  }
874 
876 
877  const QgsFieldConstraints constraints = cfg.mFieldConstraints;
878  mLayer->setConstraintExpression( idx, constraints.constraintExpression(), constraints.constraintDescription() );
880  {
882  }
883  else
884  {
886  }
888  {
890  }
891  else
892  {
894  }
896  {
898  }
899  else
900  {
902  }
903 
904  mLayer->setFieldAlias( idx, cfg.mAlias );
905  }
906 
907  // tabs and groups
908  editFormConfig.clearTabs();
909  for ( int t = 0; t < mFormLayoutTree->invisibleRootItem()->childCount(); t++ )
910  {
911  QTreeWidgetItem *tabItem = mFormLayoutTree->invisibleRootItem()->child( t );
912  QgsAttributeEditorElement *editorElement { createAttributeEditorWidget( tabItem, nullptr, false ) };
913  if ( editorElement )
914  editFormConfig.addTab( editorElement );
915  }
916 
917  editFormConfig.setUiForm( mEditFormLineEdit->text() );
918 
919  editFormConfig.setLayout( static_cast<QgsEditFormConfig::EditorLayout>( mEditorLayoutComboBox->currentIndex() ) );
920 
921  editFormConfig.setInitCodeSource( mInitCodeSource );
922  editFormConfig.setInitFunction( mInitFunction );
923  editFormConfig.setInitFilePath( mInitFilePath );
924  editFormConfig.setInitCode( mInitCode );
925 
926  editFormConfig.setSuppress( static_cast<QgsEditFormConfig::FeatureFormSuppress>( mFormSuppressCmbBx->currentIndex() ) );
927 
928  // write the legacy config of relation widgets to support settings read by the API
929  QTreeWidgetItem *relationContainer = mAvailableWidgetsTree->invisibleRootItem()->child( 1 );
930 
931  for ( int i = 0; i < relationContainer->childCount(); i++ )
932  {
933  QTreeWidgetItem *relationItem = relationContainer->child( i );
934  const DnDTreeItemData itemData = relationItem->data( 0, DnDTreeRole ).value<DnDTreeItemData>();
935 
936  for ( int t = 0; t < mFormLayoutTree->invisibleRootItem()->childCount(); t++ )
937  {
938  QTreeWidgetItem *tabItem = mFormLayoutTree->invisibleRootItem()->child( t );
939  const DnDTreeItemData tabItemData = tabItem->data( 0, DnDTreeRole ).value<DnDTreeItemData>();
940 
941  if ( tabItemData.type() == itemData.type() && tabItemData.name() == itemData.name() )
942  {
943  QVariantMap cfg;
944 
945  cfg[QStringLiteral( "nm-rel" )] = tabItemData.relationEditorConfiguration().nmRelationId;
946  cfg[QStringLiteral( "force-suppress-popup" )] = tabItemData.relationEditorConfiguration().forceSuppressFormPopup;
947 
948  editFormConfig.setWidgetConfig( tabItemData.name(), cfg );
949  break;
950  }
951  }
952  }
953 
954  mLayer->setEditFormConfig( editFormConfig );
955 }
956 
957 
958 /*
959  * FieldConfig implementation
960  */
962 {
963  mAlias = layer->fields().at( idx ).alias();
965  mComment = layer->fields().at( idx ).comment();
966  mEditable = !layer->editFormConfig().readOnly( idx );
968  && layer->fields().fieldOrigin( idx ) != QgsFields::OriginExpression;
969  mLabelOnTop = layer->editFormConfig().labelOnTop( idx );
971  mFieldConstraints = layer->fields().at( idx ).constraints();
972  const QgsEditorWidgetSetup setup = QgsGui::editorWidgetRegistry()->findBest( layer, layer->fields().field( idx ).name() );
973  mEditorWidgetType = setup.type();
974  mEditorWidgetConfig = setup.config();
975 }
976 
977 QgsAttributesFormProperties::FieldConfig::operator QVariant()
978 {
979  return QVariant::fromValue<QgsAttributesFormProperties::FieldConfig>( *this );
980 }
981 
982 /*
983  * RelationEditorConfiguration implementation
984  */
985 
986 QgsAttributesFormProperties::RelationEditorConfiguration::operator QVariant()
987 {
988  return QVariant::fromValue<QgsAttributesFormProperties::RelationEditorConfiguration>( *this );
989 }
990 
991 /*
992  * DnDTree implementation
993  */
994 
995 QTreeWidgetItem *QgsAttributesDnDTree::addContainer( QTreeWidgetItem *parent, const QString &title, int columnCount )
996 {
997  QTreeWidgetItem *newItem = new QTreeWidgetItem( QStringList() << title );
998  newItem->setBackground( 0, QBrush( Qt::lightGray ) );
999  newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled );
1001  itemData.setColumnCount( columnCount );
1002  newItem->setData( 0, QgsAttributesFormProperties::DnDTreeRole, itemData );
1003  parent->addChild( newItem );
1004  newItem->setExpanded( true );
1005  return newItem;
1006 }
1007 
1009  : QTreeWidget( parent )
1010  , mLayer( layer )
1011 {
1012  connect( this, &QTreeWidget::itemDoubleClicked, this, &QgsAttributesDnDTree::onItemDoubleClicked );
1013 }
1014 
1015 QTreeWidgetItem *QgsAttributesDnDTree::addItem( QTreeWidgetItem *parent, QgsAttributesFormProperties::DnDTreeItemData data, int index, const QIcon &icon )
1016 {
1017  QTreeWidgetItem *newItem = new QTreeWidgetItem( QStringList() << data.name() );
1018 
1019  switch ( data.type() )
1020  {
1026  newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled );
1027  break;
1028 
1031  {
1032  newItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled );
1033  newItem->setBackground( 0, QBrush( Qt::lightGray ) );
1034  }
1035  break;
1036  }
1037 
1038  newItem->setData( 0, QgsAttributesFormProperties::DnDTreeRole, data );
1039  newItem->setText( 0, data.displayName() );
1040  newItem->setIcon( 0, icon );
1041 
1042  if ( index < 0 )
1043  parent->addChild( newItem );
1044  else
1045  parent->insertChild( index, newItem );
1046 
1047  return newItem;
1048 }
1049 
1055 void QgsAttributesDnDTree::dragMoveEvent( QDragMoveEvent *event )
1056 {
1057  const QMimeData *data = event->mimeData();
1058 
1059  if ( data->hasFormat( QStringLiteral( "application/x-qgsattributetabledesignerelement" ) ) )
1060  {
1062 
1063  QByteArray itemData = data->data( QStringLiteral( "application/x-qgsattributetabledesignerelement" ) );
1064  QDataStream stream( &itemData, QIODevice::ReadOnly );
1065  stream >> itemElement;
1066 
1067  // Inner drag and drop actions are always MoveAction
1068  if ( event->source() == this )
1069  {
1070  event->setDropAction( Qt::MoveAction );
1071  }
1072  }
1073  else
1074  {
1075  event->ignore();
1076  }
1077 
1078  QTreeWidget::dragMoveEvent( event );
1079 }
1080 
1081 
1082 bool QgsAttributesDnDTree::dropMimeData( QTreeWidgetItem *parent, int index, const QMimeData *data, Qt::DropAction action )
1083 {
1084  bool bDropSuccessful = false;
1085 
1086  if ( action == Qt::IgnoreAction )
1087  {
1088  bDropSuccessful = true;
1089  }
1090  else if ( data->hasFormat( QStringLiteral( "application/x-qgsattributetabledesignerelement" ) ) )
1091  {
1092  QByteArray itemData = data->data( QStringLiteral( "application/x-qgsattributetabledesignerelement" ) );
1093  QDataStream stream( &itemData, QIODevice::ReadOnly );
1095 
1096  while ( !stream.atEnd() )
1097  {
1098  stream >> itemElement;
1099 
1100  QTreeWidgetItem *newItem;
1101 
1102  if ( parent )
1103  {
1104  newItem = addItem( parent, itemElement, index++ );
1105  bDropSuccessful = true;
1106  }
1107  else
1108  {
1109  newItem = addItem( invisibleRootItem(), itemElement, index++ );
1110  bDropSuccessful = true;
1111  }
1112 
1113  if ( itemElement.type() == QgsAttributesFormProperties::DnDTreeItemData::QmlWidget )
1114  {
1115  onItemDoubleClicked( newItem, 0 );
1116  }
1117 
1119  {
1120  onItemDoubleClicked( newItem, 0 );
1121  }
1122  clearSelection();
1123  newItem->setSelected( true );
1124  }
1125  }
1126 
1127  return bDropSuccessful;
1128 }
1129 
1130 void QgsAttributesDnDTree::dropEvent( QDropEvent *event )
1131 {
1132  if ( !event->mimeData()->hasFormat( QStringLiteral( "application/x-qgsattributetabledesignerelement" ) ) )
1133  return;
1134 
1135  if ( event->source() == this )
1136  {
1137  event->setDropAction( Qt::MoveAction );
1138  }
1139 
1140  QTreeWidget::dropEvent( event );
1141 }
1142 
1144 {
1145  return QStringList() << QStringLiteral( "application/x-qgsattributetabledesignerelement" );
1146 }
1147 
1148 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1149 QMimeData *QgsAttributesDnDTree::mimeData( const QList<QTreeWidgetItem *> items ) const
1150 #else
1151 QMimeData *QgsAttributesDnDTree::mimeData( const QList<QTreeWidgetItem *> &items ) const
1152 #endif
1153 {
1154  if ( items.count() <= 0 )
1155  return nullptr;
1156 
1157  const QStringList types = mimeTypes();
1158 
1159  if ( types.isEmpty() )
1160  return nullptr;
1161 
1162  QMimeData *data = new QMimeData();
1163  const QString format = types.at( 0 );
1164  QByteArray encoded;
1165  QDataStream stream( &encoded, QIODevice::WriteOnly );
1166 
1167  const auto constItems = items;
1168  for ( const QTreeWidgetItem *item : constItems )
1169  {
1170  if ( item )
1171  {
1172  // Relevant information is always in the DnDTreeRole of the first column
1174  stream << itemData;
1175  }
1176  }
1177 
1178  data->setData( format, encoded );
1179 
1180  return data;
1181 }
1182 
1183 void QgsAttributesDnDTree::onItemDoubleClicked( QTreeWidgetItem *item, int column )
1184 {
1185  Q_UNUSED( column )
1186 
1188 
1189  QGroupBox *baseData = new QGroupBox( tr( "Base configuration" ) );
1190 
1191  QFormLayout *baseLayout = new QFormLayout();
1192  baseData->setLayout( baseLayout );
1193  QCheckBox *showLabelCheckbox = new QCheckBox( QStringLiteral( "Show label" ) );
1194  showLabelCheckbox->setChecked( itemData.showLabel() );
1195  baseLayout->addRow( showLabelCheckbox );
1196  QWidget *baseWidget = new QWidget();
1197  baseWidget->setLayout( baseLayout );
1198 
1199  switch ( itemData.type() )
1200  {
1206  break;
1207 
1209  {
1210  if ( mType == QgsAttributesDnDTree::Type::Drag )
1211  return;
1212 
1213  QDialog dlg;
1214  dlg.setWindowTitle( tr( "Configure QML Widget" ) );
1215 
1216  QVBoxLayout *mainLayout = new QVBoxLayout();
1217  QHBoxLayout *qmlLayout = new QHBoxLayout();
1218  QVBoxLayout *layout = new QVBoxLayout();
1219  mainLayout->addLayout( qmlLayout );
1220  qmlLayout->addLayout( layout );
1221  dlg.setLayout( mainLayout );
1222  layout->addWidget( baseWidget );
1223 
1224  QLineEdit *title = new QLineEdit( itemData.name() );
1225 
1226  //qmlCode
1227  QPlainTextEdit *qmlCode = new QPlainTextEdit( itemData.qmlElementEditorConfiguration().qmlCode );
1228  qmlCode->setPlaceholderText( tr( "Insert QML code here…" ) );
1229 
1230  QgsQmlWidgetWrapper *qmlWrapper = new QgsQmlWidgetWrapper( mLayer, nullptr, this );
1231  QgsFeature previewFeature;
1232  mLayer->getFeatures().nextFeature( previewFeature );
1233 
1234  //update preview on text change
1235  connect( qmlCode, &QPlainTextEdit::textChanged, this, [ = ]
1236  {
1237  qmlWrapper->setQmlCode( qmlCode->toPlainText() );
1238  qmlWrapper->reinitWidget();
1239  qmlWrapper->setFeature( previewFeature );
1240  } );
1241 
1242  //templates
1243  QComboBox *qmlObjectTemplate = new QComboBox();
1244  qmlObjectTemplate->addItem( tr( "Free Text…" ) );
1245  qmlObjectTemplate->addItem( tr( "Rectangle" ) );
1246  qmlObjectTemplate->addItem( tr( "Pie Chart" ) );
1247  qmlObjectTemplate->addItem( tr( "Bar Chart" ) );
1248  connect( qmlObjectTemplate, qOverload<int>( &QComboBox::activated ), qmlCode, [ = ]( int index )
1249  {
1250  qmlCode->clear();
1251  switch ( index )
1252  {
1253  case 0:
1254  {
1255  qmlCode->setPlaceholderText( tr( "Insert QML code here…" ) );
1256  break;
1257  }
1258  case 1:
1259  {
1260  qmlCode->insertPlainText( QStringLiteral( "import QtQuick 2.0\n"
1261  "\n"
1262  "Rectangle {\n"
1263  " width: 100\n"
1264  " height: 100\n"
1265  " color: \"steelblue\"\n"
1266  " Text{ text: \"A rectangle\" }\n"
1267  "}\n" ) );
1268  break;
1269  }
1270  case 2:
1271  {
1272  qmlCode->insertPlainText( QStringLiteral( "import QtQuick 2.0\n"
1273  "import QtCharts 2.0\n"
1274  "\n"
1275  "ChartView {\n"
1276  " width: 400\n"
1277  " height: 400\n"
1278  "\n"
1279  " PieSeries {\n"
1280  " id: pieSeries\n"
1281  " PieSlice { label: \"First slice\"; value: 25 }\n"
1282  " PieSlice { label: \"Second slice\"; value: 45 }\n"
1283  " PieSlice { label: \"Third slice\"; value: 30 }\n"
1284  " }\n"
1285  "}\n" ) );
1286  break;
1287  }
1288  case 3:
1289  {
1290  qmlCode->insertPlainText( QStringLiteral( "import QtQuick 2.0\n"
1291  "import QtCharts 2.0\n"
1292  "\n"
1293  "ChartView {\n"
1294  " title: \"Bar series\"\n"
1295  " width: 600\n"
1296  " height:400\n"
1297  " legend.alignment: Qt.AlignBottom\n"
1298  " antialiasing: true\n"
1299  " ValueAxis{\n"
1300  " id: valueAxisY\n"
1301  " min: 0\n"
1302  " max: 15\n"
1303  " }\n"
1304  "\n"
1305  " BarSeries {\n"
1306  " id: mySeries\n"
1307  " axisY: valueAxisY\n"
1308  " axisX: BarCategoryAxis { categories: [\"2007\", \"2008\", \"2009\", \"2010\", \"2011\", \"2012\" ] }\n"
1309  " BarSet { label: \"Bob\"; values: [2, 2, 3, 4, 5, 6] }\n"
1310  " BarSet { label: \"Susan\"; values: [5, 1, 2, 4, 1, 7] }\n"
1311  " BarSet { label: \"James\"; values: [3, 5, 8, 13, 5, 8] }\n"
1312  " }\n"
1313  "}\n" ) );
1314  break;
1315  }
1316  default:
1317  break;
1318  }
1319  } );
1320 
1321  QgsFieldExpressionWidget *expressionWidget = new QgsFieldExpressionWidget;
1322  expressionWidget->setLayer( mLayer );
1323  QToolButton *addExpressionButton = new QToolButton();
1324  addExpressionButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/symbologyAdd.svg" ) ) );
1325 
1326  connect( addExpressionButton, &QAbstractButton::clicked, this, [ = ]
1327  {
1328  qmlCode->insertPlainText( QStringLiteral( "expression.evaluate(\"%1\")" ).arg( expressionWidget->expression().replace( '"', QLatin1String( "\\\"" ) ) ) );
1329  } );
1330 
1331  layout->addWidget( new QLabel( tr( "Title" ) ) );
1332  layout->addWidget( title );
1333  QGroupBox *qmlCodeBox = new QGroupBox( tr( "QML Code" ) );
1334  qmlCodeBox->setLayout( new QGridLayout );
1335  qmlCodeBox->layout()->addWidget( qmlObjectTemplate );
1336  QGroupBox *expressionWidgetBox = new QGroupBox();
1337  qmlCodeBox->layout()->addWidget( expressionWidgetBox );
1338  expressionWidgetBox->setLayout( new QHBoxLayout );
1339  expressionWidgetBox->layout()->addWidget( expressionWidget );
1340  expressionWidgetBox->layout()->addWidget( addExpressionButton );
1341  qmlCodeBox->layout()->addWidget( qmlCode );
1342  layout->addWidget( qmlCodeBox );
1343  QScrollArea *qmlPreviewBox = new QScrollArea();
1344  qmlPreviewBox->setLayout( new QGridLayout );
1345  qmlPreviewBox->setMinimumWidth( 400 );
1346  qmlPreviewBox->layout()->addWidget( qmlWrapper->widget() );
1347  //emit to load preview for the first time
1348  emit qmlCode->textChanged();
1349  qmlLayout->addWidget( qmlPreviewBox );
1350 
1351  QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1352 
1353  connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1354  connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1355 
1356  mainLayout->addWidget( buttonBox );
1357 
1358  if ( dlg.exec() )
1359  {
1361  qmlEdCfg.qmlCode = qmlCode->toPlainText();
1362  itemData.setName( title->text() );
1363  itemData.setQmlElementEditorConfiguration( qmlEdCfg );
1364  itemData.setShowLabel( showLabelCheckbox->isChecked() );
1365 
1366  item->setData( 0, QgsAttributesFormProperties::DnDTreeRole, itemData );
1367  item->setText( 0, title->text() );
1368  }
1369  }
1370  break;
1371 
1373  {
1374  if ( mType == QgsAttributesDnDTree::Type::Drag )
1375  return;
1376  QDialog dlg;
1377  dlg.setWindowTitle( tr( "Configure HTML Widget" ) );
1378 
1379  QVBoxLayout *mainLayout = new QVBoxLayout();
1380  QHBoxLayout *htmlLayout = new QHBoxLayout();
1381  QVBoxLayout *layout = new QVBoxLayout();
1382  mainLayout->addLayout( htmlLayout );
1383  htmlLayout->addLayout( layout );
1384  dlg.setLayout( mainLayout );
1385  layout->addWidget( baseWidget );
1386 
1387  QLineEdit *title = new QLineEdit( itemData.name() );
1388 
1389  //htmlCode
1390  QgsCodeEditorHTML *htmlCode = new QgsCodeEditorHTML( );
1391  htmlCode->setSizePolicy( QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding );
1392  htmlCode->setText( itemData.htmlElementEditorConfiguration().htmlCode );
1393 
1394  QgsHtmlWidgetWrapper *htmlWrapper = new QgsHtmlWidgetWrapper( mLayer, nullptr, this );
1395  QgsFeature previewFeature;
1396  mLayer->getFeatures().nextFeature( previewFeature );
1397 
1398  //update preview on text change
1399  connect( htmlCode, &QgsCodeEditorHTML::textChanged, this, [ = ]
1400  {
1401  htmlWrapper->setHtmlCode( htmlCode->text( ) );
1402  htmlWrapper->reinitWidget();
1403  htmlWrapper->setFeature( previewFeature );
1404  } );
1405 
1406  QgsFieldExpressionWidget *expressionWidget = new QgsFieldExpressionWidget;
1407  expressionWidget->setLayer( mLayer );
1408  QToolButton *addExpressionButton = new QToolButton();
1409  addExpressionButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/symbologyAdd.svg" ) ) );
1410 
1411  connect( addExpressionButton, &QAbstractButton::clicked, this, [ = ]
1412  {
1413  htmlCode->insertText( QStringLiteral( "<script>document.write(expression.evaluate(\"%1\"));</script>" ).arg( expressionWidget->expression().replace( '"', QLatin1String( "\\\"" ) ) ) );
1414  } );
1415 
1416  layout->addWidget( new QLabel( tr( "Title" ) ) );
1417  layout->addWidget( title );
1418  QGroupBox *expressionWidgetBox = new QGroupBox( tr( "HTML Code" ) );
1419  layout->addWidget( expressionWidgetBox );
1420  expressionWidgetBox->setLayout( new QHBoxLayout );
1421  expressionWidgetBox->layout()->addWidget( expressionWidget );
1422  expressionWidgetBox->layout()->addWidget( addExpressionButton );
1423  layout->addWidget( htmlCode );
1424  QScrollArea *htmlPreviewBox = new QScrollArea();
1425  htmlPreviewBox->setLayout( new QGridLayout );
1426  htmlPreviewBox->setMinimumWidth( 400 );
1427  htmlPreviewBox->layout()->addWidget( htmlWrapper->widget() );
1428  //emit to load preview for the first time
1429  emit htmlCode->textChanged();
1430  htmlLayout->addWidget( htmlPreviewBox );
1431 
1432  QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
1433 
1434  connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1435  connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1436 
1437  mainLayout->addWidget( buttonBox );
1438 
1439  if ( dlg.exec() )
1440  {
1442  htmlEdCfg.htmlCode = htmlCode->text();
1443  itemData.setName( title->text() );
1444  itemData.setHtmlElementEditorConfiguration( htmlEdCfg );
1445  itemData.setShowLabel( showLabelCheckbox->isChecked() );
1446 
1447  item->setData( 0, QgsAttributesFormProperties::DnDTreeRole, itemData );
1448  item->setText( 0, title->text() );
1449  }
1450  }
1451  break;
1452  }
1453 }
1454 
1456 {
1457  return mType;
1458 }
1459 
1461 {
1462  mType = value;
1463 }
1464 
1466 {
1467  QTreeWidgetItemIterator it( this );
1468  while ( *it )
1469  {
1471  if ( data.type() == rowData.type() && data.name() == rowData.name() )
1472  {
1473  if ( selectedItems().count() == 1 && ( *it )->isSelected() == true )
1474  {
1475  // the selection is already good
1476  }
1477  else
1478  {
1479  clearSelection();
1480  ( *it )->setSelected( true );
1481  }
1482  return;
1483  }
1484  ++it;
1485  }
1486  clearSelection();
1487 }
1488 
1489 
1490 /*
1491  * Serialization helpers for DesigerTreeItemData so we can stuff this easily into QMimeData
1492  */
1493 
1494 QDataStream &operator<<( QDataStream &stream, const QgsAttributesFormProperties::DnDTreeItemData &data )
1495 {
1496  stream << static_cast<quint32>( data.type() ) << data.name() << data.displayName();
1497  return stream;
1498 }
1499 
1500 QDataStream &operator>>( QDataStream &stream, QgsAttributesFormProperties::DnDTreeItemData &data )
1501 {
1502  QString name;
1503  QString displayName;
1504  quint32 type;
1505 
1506  stream >> type >> name >> displayName;
1507 
1508  data.setType( static_cast<QgsAttributesFormProperties::DnDTreeItemData::Type>( type ) );
1509  data.setName( name );
1510  data.setDisplayName( displayName );
1511 
1512  return stream;
1513 }
1514 
1516 {
1517  return mShowAsGroupBox;
1518 }
1519 
1521 {
1522  mShowAsGroupBox = showAsGroupBox;
1523 }
1524 
1526 {
1527  return mShowLabel;
1528 }
1529 
1531 {
1532  mShowLabel = showLabel;
1533 }
1534 
1536 {
1537  return mVisibilityExpression;
1538 }
1539 
1541 {
1542  mVisibilityExpression = visibilityExpression;
1543 }
1544 
1546 {
1547  return mRelationEditorConfiguration;
1548 }
1549 
1551 {
1552  mRelationEditorConfiguration = relationEditorConfiguration;
1553 }
1554 
1556 {
1557  return mQmlElementEditorConfiguration;
1558 }
1559 
1561 {
1562  mQmlElementEditorConfiguration = qmlElementEditorConfiguration;
1563 }
1564 
1565 
1567 {
1568  return mHtmlElementEditorConfiguration;
1569 }
1570 
1572 {
1573  mHtmlElementEditorConfiguration = htmlElementEditorConfiguration;
1574 }
1575 
1577 {
1578  return mBackgroundColor;
1579 }
1580 
1582 {
1583  mBackgroundColor = backgroundColor;
1584 }
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 rendered as 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...
virtual void setIsGroupBox(bool isGroupBox)
Determines if this container is rendered as collapsible group box or tab in a tabwidget.
QColor backgroundColor() const
backgroundColor
int columnCount() const
Gets the number of columns in this group.
QList< QgsAttributeEditorElement * > children() const
Gets a list of the children elements of this container.
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.
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)
QmlElementEditorConfiguration qmlElementEditorConfiguration() const
void setQmlElementEditorConfiguration(QmlElementEditorConfiguration qmlElementEditorConfiguration)
void setVisibilityExpression(const QgsOptionalExpression &visibilityExpression)
@ WidgetType
In the widget tree, the type of widget.
HtmlElementEditorConfiguration htmlElementEditorConfiguration() const
void setHtmlElementEditorConfiguration(HtmlElementEditorConfiguration htmlElementEditorConfiguration)
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:344
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:111
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:467
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:49
Q_GADGET QString id
Definition: qgsrelation.h:46
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.
QgsActionManager * actions()
Returns all layer actions defined on this layer.
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.
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, const QgsAttributesFormProperties::DnDTreeItemData &data)
QDataStream & operator>>(QDataStream &stream, QgsAttributesFormProperties::DnDTreeItemData &data)
const QgsField & field
Definition: qgsfield.h:463
#define QgsDebugMsg(str)
Definition: qgslogger.h:38