QGIS API Documentation 3.99.0-Master (d270888f95f)
Loading...
Searching...
No Matches
qgsattributesformmodel.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsattributesformmodel.cpp
3 ---------------------
4 begin : March 2025
5 copyright : (C) 2025 by Germán Carrillo
6 email : german at opengis dot ch
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
18#include "qgsactionmanager.h"
19#include "qgsapplication.h"
29#include "qgsgui.h"
30
31#include <QMimeData>
32#include <QString>
33
34#include "moc_qgsattributesformmodel.cpp"
35
36using namespace Qt::StringLiterals;
37
39{
40 if ( !layer || idx < 0 || idx >= layer->fields().count() )
41 return;
42
43 mAlias = layer->fields().at( idx ).alias();
45 mComment = layer->fields().at( idx ).comment();
46 mEditable = !layer->editFormConfig().readOnly( idx );
47 mLabelOnTop = layer->editFormConfig().labelOnTop( idx );
49 mFieldConstraints = layer->fields().at( idx ).constraints();
50 const QgsEditorWidgetSetup setup = QgsGui::editorWidgetRegistry()->findBest( layer, layer->fields().field( idx ).name() );
51 mEditorWidgetType = setup.type();
53 mSplitPolicy = layer->fields().at( idx ).splitPolicy();
54 mDuplicatePolicy = layer->fields().at( idx ).duplicatePolicy();
55 mMergePolicy = layer->fields().at( idx ).mergePolicy();
58}
59
60QgsAttributesFormData::FieldConfig::operator QVariant()
61{
62 return QVariant::fromValue<QgsAttributesFormData::FieldConfig>( *this );
63}
64
65QgsAttributesFormData::RelationEditorConfiguration::operator QVariant()
66{
67 return QVariant::fromValue<QgsAttributesFormData::RelationEditorConfiguration>( *this );
68}
69
74
79
84
89
91{
92 return mShowLabel;
93}
94
99
104
109
114
119
124
129
134
139
140
145
150
155
160
162{
163 return mBackgroundColor;
164}
165
170
175
180
181
183 : mName( name )
184 , mDisplayName( displayName )
185 , mType( itemType )
186 , mParent( parent )
187{}
188
190 : mName( name )
191 , mDisplayName( displayName )
192 , mType( itemType )
193 , mData( data )
194 , mParent( parent )
195{}
196
198{
199 if ( !mChildren.empty() && row >= 0 && row < childCount() )
200 return mChildren.at( row ).get();
201
202 return nullptr;
203}
204
206{
207 if ( !mChildren.empty() && itemId.trimmed().isEmpty() )
208 return nullptr;
209
210 // Search for first matching item by name
211 const auto it = std::find_if( mChildren.cbegin(), mChildren.cend(), [itemType, itemId]( const std::unique_ptr< QgsAttributesFormItem > &item ) {
212 return item->type() == itemType && item->id() == itemId;
213 } );
214
215 if ( it != mChildren.cend() )
216 return it->get();
217
218 return nullptr;
219}
220
222{
223 if ( !mChildren.empty() && itemId.trimmed().isEmpty() )
224 return nullptr;
225
226 for ( const auto &child : std::as_const( mChildren ) )
227 {
228 if ( child->type() == itemType && child->id() == itemId )
229 return child.get();
230
231 if ( child->childCount() > 0 )
232 {
233 QgsAttributesFormItem *item = child->firstChildRecursive( itemType, itemId );
234 if ( item )
235 return item;
236 }
237 }
238
239 return nullptr;
240}
241
243{
244 return static_cast< int >( mChildren.size() );
245}
246
248{
249 if ( !mParent )
250 return 0;
251
252 const auto it = std::find_if( mParent->mChildren.cbegin(), mParent->mChildren.cend(), [this]( const std::unique_ptr< QgsAttributesFormItem > &item ) {
253 return item.get() == this;
254 } );
255
256 if ( it != mParent->mChildren.cend() )
257 {
258 return static_cast< int >( std::distance( mParent->mChildren.cbegin(), it ) );
259 }
260
261 return -1;
262}
263
264void QgsAttributesFormItem::addChild( std::unique_ptr< QgsAttributesFormItem > &&item )
265{
266 if ( !item )
267 return;
268
269 if ( !item->mParent )
270 item->mParent = this;
271
272 // forward the signal towards the root
274
275 mChildren.push_back( std::move( item ) );
276
277 emit addedChildren( this, mChildren.size() - 1, mChildren.size() - 1 );
278}
279
280void QgsAttributesFormItem::insertChild( int position, std::unique_ptr< QgsAttributesFormItem > &&item )
281{
282 if ( position < 0 || position > static_cast< int >( mChildren.size() ) || !item )
283 return;
284
285 if ( !item->mParent )
286 item->mParent = this;
287
288 // forward the signal towards the root
290
291 mChildren.insert( mChildren.begin() + position, std::move( item ) );
292
293 emit addedChildren( this, position, position );
294}
295
297{
298 if ( index >= 0 && index < static_cast< int >( mChildren.size() ) )
299 mChildren.erase( mChildren.begin() + index );
300}
301
303{
304 mChildren.clear();
305}
306
311
312QVariant QgsAttributesFormItem::data( int role ) const
313{
314 switch ( role )
315 {
317 return mType;
319 return QVariant::fromValue( mData );
321 return mName;
323 return mId;
325 return mDisplayName;
327 return QVariant::fromValue( mFieldConfigData );
328 default:
329 return QVariant();
330 }
331}
332
333bool QgsAttributesFormItem::setData( int role, const QVariant &value )
334{
335 switch ( role )
336 {
338 {
339 mData = value.value< QgsAttributesFormData::AttributeFormItemData >();
340 return true;
341 }
343 {
344 mName = value.toString();
345 return true;
346 }
348 {
349 mDisplayName = value.toString();
350 return true;
351 }
353 {
354 mType = static_cast<QgsAttributesFormData::AttributesFormItemType>( value.toInt() );
355 return true;
356 }
358 {
359 mId = value.toString();
360 return true;
361 }
363 {
364 mFieldConfigData = value.value< QgsAttributesFormData::FieldConfig >();
365 return true;
366 }
367 default:
368 return false;
369 }
370}
371
372
374 : QAbstractItemModel( parent )
375 , mRootItem( std::make_unique< QgsAttributesFormItem >() )
376 , mLayer( layer )
377 , mProject( project )
378{
379}
380
382
384{
385 if ( index.isValid() )
386 {
387 if ( auto *item = static_cast<QgsAttributesFormItem *>( index.internalPointer() ) )
388 return item;
389 }
390 return mRootItem.get();
391}
392
397
398
399int QgsAttributesFormModel::rowCount( const QModelIndex &parent ) const
400{
401 if ( parent.isValid() && parent.column() > 0 )
402 return 0;
403
404 const QgsAttributesFormItem *parentItem = itemForIndex( parent );
405
406 return parentItem ? parentItem->childCount() : 0;
407}
408
409int QgsAttributesFormModel::columnCount( const QModelIndex & ) const
410{
411 return 1;
412}
413
414bool QgsAttributesFormModel::indexLessThan( const QModelIndex &a, const QModelIndex &b ) const
415{
416 const QVector<int> pathA = rootToLeafPath( itemForIndex( a ) );
417 const QVector<int> pathB = rootToLeafPath( itemForIndex( b ) );
418
419 for ( int i = 0; i < std::min( pathA.size(), pathB.size() ); i++ )
420 {
421 if ( pathA.at( i ) != pathB.at( i ) )
422 {
423 return pathA.at( i ) < pathB.at( i );
424 }
425 }
426
427 return pathA.size() < pathB.size();
428}
429
431{
432 QVector<int> path;
433 if ( item != mRootItem.get() )
434 {
435 path << rootToLeafPath( item->parent() ) << item->row();
436 }
437 return path;
438}
439
440QModelIndex QgsAttributesFormModel::index( int row, int column, const QModelIndex &parent ) const
441{
442 if ( !hasIndex( row, column, parent ) )
443 return QModelIndex();
444
446 if ( !parentItem )
447 return QModelIndex();
448
449 if ( QgsAttributesFormItem *childItem = parentItem->child( row ) )
450 return createIndex( row, column, childItem );
451
452 return QModelIndex();
453}
454
455QModelIndex QgsAttributesFormModel::parent( const QModelIndex &index ) const
456{
457 if ( !index.isValid() )
458 return QModelIndex();
459
461 QgsAttributesFormItem *parentItem = childItem ? childItem->parent() : nullptr;
462
463 return ( parentItem != mRootItem.get() && parentItem != nullptr )
464 ? createIndex( parentItem->row(), 0, parentItem )
465 : QModelIndex();
466}
467
469{
470 QgsAttributesFormItem *item = mRootItem->firstTopChild( itemType, itemId );
471 return item ? createIndex( item->row(), 0, item ) : QModelIndex();
472}
473
475{
476 QgsAttributesFormItem *item = mRootItem->firstChildRecursive( itemType, itemId );
477 return item ? createIndex( item->row(), 0, item ) : QModelIndex();
478}
479
480bool QgsAttributesFormModel::setData( const QModelIndex &index, const QVariant &value, int role )
481{
482 if ( !index.isValid() )
483 return false;
484
486 bool result = item->setData( role, value );
487
488 if ( result )
489 {
490 emit dataChanged( index, index, { role } );
491
493 {
494 emit fieldConfigDataChanged( item );
495 }
496 }
497
498 return result;
499}
500
502{
503 return mShowAliases;
504}
505
507{
508 mShowAliases = show;
509
510 emitDataChangedRecursively( QModelIndex(), QVector<int>() << Qt::DisplayRole << Qt::ForegroundRole << Qt::FontRole );
511}
512
513void QgsAttributesFormModel::emitDataChangedRecursively( const QModelIndex &parent, const QVector<int> &roles )
514{
515 emit dataChanged( index( 0, 0, parent ), index( rowCount( parent ) - 1, 0, parent ), roles );
516 for ( int i = 0; i < rowCount( parent ); i++ )
517 {
518 const QModelIndex childIndex = index( i, 0, parent );
519 if ( hasChildren( childIndex ) )
520 {
521 emitDataChangedRecursively( childIndex, roles );
522 }
523 }
524}
525
526
531
532Qt::ItemFlags QgsAttributesAvailableWidgetsModel::flags( const QModelIndex &index ) const
533{
534 if ( !index.isValid() )
535 return Qt::NoItemFlags;
536
537 Qt::ItemFlags flags = Qt::ItemIsEnabled;
538
539 const auto indexType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
540 if ( indexType != QgsAttributesFormData::WidgetType )
541 {
542 flags = flags | Qt::ItemIsDragEnabled | Qt::ItemIsSelectable;
543 }
544
545 return flags;
546}
547
548QVariant QgsAttributesAvailableWidgetsModel::headerData( int section, Qt::Orientation orientation, int role ) const
549{
550 Q_UNUSED( section )
551 return orientation == Qt::Horizontal && role == Qt::DisplayRole ? tr( "Available Widgets" ) : QVariant {};
552}
553
555{
556 if ( !mLayer )
557 return;
558
559 beginResetModel();
560 mRootItem->deleteChildren();
561
562 // Load fields
563
564 auto itemFields = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::WidgetType, u"Fields"_s, tr( "Fields" ) );
565
566 const QgsFields fields = mLayer->fields();
567 for ( int i = 0; i < fields.size(); ++i )
568 {
569 const QgsField field = fields.at( i );
571 itemData.setShowLabel( true );
572
574
575 auto item = std::make_unique< QgsAttributesFormItem >();
576 item->setData( ItemFieldConfigRole, cfg );
577 item->setData( ItemNameRole, field.name() );
578 item->setData( ItemIdRole, field.name() ); // Field names act as ids
579 item->setData( ItemDisplayRole, field.alias() );
581 item->setData( ItemDataRole, itemData );
582 item->setIcon( fields.iconForField( i, true ) );
583
584 itemFields->addChild( std::move( item ) );
585 }
586
587 mRootItem->addChild( std::move( itemFields ) );
588
589 // Load relations
590
591 auto itemRelations = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::WidgetType, u"Relations"_s, tr( "Relations" ) );
592
593 const QList<QgsRelation> relations = mProject->relationManager()->referencedRelations( mLayer );
594
595 for ( const QgsRelation &relation : relations )
596 {
597 QString name;
598 const QgsPolymorphicRelation polymorphicRelation = relation.polymorphicRelation();
599 if ( polymorphicRelation.isValid() )
600 {
601 name = u"%1 (%2)"_s.arg( relation.name(), polymorphicRelation.name() );
602 }
603 else
604 {
605 name = relation.name();
606 }
608 itemData.setShowLabel( true );
609
610 auto itemRelation = std::make_unique< QgsAttributesFormItem >();
611 itemRelation->setData( ItemTypeRole, QgsAttributesFormData::Relation );
612 itemRelation->setData( ItemNameRole, name );
613 itemRelation->setData( ItemIdRole, relation.id() );
614 itemRelation->setData( ItemDataRole, itemData );
615 itemRelation->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetRelationEditor.svg"_s ) );
616 itemRelations->addChild( std::move( itemRelation ) );
617 }
618
619 mRootItem->addChild( std::move( itemRelations ) );
620
621 // Load form actions
622
623 auto itemActions = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::WidgetType, u"Actions"_s, tr( "Actions" ) );
624 mRootItem->addChild( std::move( itemActions ) );
625 populateActionItems( mLayer->actions()->actions() );
626
627 // Other widgets
628
629 auto itemOtherWidgets = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::WidgetType, u"Other"_s, tr( "Other Widgets" ) );
630
632 itemData.setShowLabel( true );
633 auto itemQml = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::QmlWidget, itemData, u"QML Widget"_s, tr( "QML Widget" ) );
634 itemQml->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetQml.svg"_s ) );
635 itemOtherWidgets->addChild( std::move( itemQml ) );
636
638 itemHtmlData.setShowLabel( true );
639 auto itemHtml = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::HtmlWidget, itemHtmlData, u"HTML Widget"_s, tr( "HTML Widget" ) );
640 itemHtml->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetHtml.svg"_s ) );
641 itemOtherWidgets->addChild( std::move( itemHtml ) );
642
644 itemTextData.setShowLabel( true );
645 auto itemText = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::TextWidget, itemTextData, u"Text Widget"_s, tr( "Text Widget" ) );
646 itemText->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetText.svg"_s ) );
647 itemOtherWidgets->addChild( std::move( itemText ) );
648
650 itemTextData.setShowLabel( false );
651 auto itemSpacer = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::SpacerWidget, u"Spacer Widget"_s, tr( "Spacer Widget" ) );
652 itemSpacer->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetSpacer.svg"_s ) );
653 itemOtherWidgets->addChild( std::move( itemSpacer ) );
654
655 mRootItem->addChild( std::move( itemOtherWidgets ) );
656
657 endResetModel();
658}
659
660void QgsAttributesAvailableWidgetsModel::populateLayerActions( const QList< QgsAction > actions )
661{
662 QModelIndex actionsIndex = actionContainer();
663 QgsAttributesFormItem *itemActions = itemForIndex( actionsIndex );
664
665 beginRemoveRows( actionsIndex, 0, itemActions->childCount() );
666 itemActions->deleteChildren();
667 endRemoveRows();
668
669 int count = 0;
670 for ( const auto &action : std::as_const( actions ) )
671 {
672 if ( action.isValid() && action.runable() && ( action.actionScopes().contains( u"Feature"_s ) || action.actionScopes().contains( u"Layer"_s ) ) )
673 {
674 count++;
675 }
676 }
677
678 if ( count > 0 )
679 {
680 beginInsertRows( actionsIndex, 0, count - 1 );
681 populateActionItems( actions );
682 endInsertRows();
683 }
684}
685
686void QgsAttributesAvailableWidgetsModel::populateActionItems( const QList<QgsAction> actions )
687{
688 QModelIndex actionsIndex = actionContainer();
689 QgsAttributesFormItem *itemActions = itemForIndex( actionsIndex );
690
691 for ( const auto &action : std::as_const( actions ) )
692 {
693 if ( action.isValid() && action.runable() && ( action.actionScopes().contains( u"Feature"_s ) || action.actionScopes().contains( u"Layer"_s ) ) )
694 {
695 const QString actionTitle { action.shortTitle().isEmpty() ? action.name() : action.shortTitle() };
696
697 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
698 itemData.setShowLabel( true );
699
700 auto itemAction = std::make_unique< QgsAttributesFormItem >();
701 itemAction->setData( ItemIdRole, action.id().toString() );
702 itemAction->setData( ItemTypeRole, QgsAttributesFormData::Action );
703 itemAction->setData( ItemNameRole, actionTitle );
704 itemAction->setData( ItemDataRole, itemData );
705 itemAction->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetAction.svg"_s ) );
706
707 itemActions->addChild( std::move( itemAction ) );
708 }
709 }
710}
711
712QVariant QgsAttributesAvailableWidgetsModel::data( const QModelIndex &index, int role ) const
713{
714 if ( !index.isValid() )
715 return QVariant();
716
718 if ( !item )
719 return QVariant();
720
721 // Relations may be broken due to missing layers or references.
722 // Make those stand out from valid ones.
723 bool invalidRelation = false;
724 if ( ( role == Qt::ToolTipRole || role == Qt::ForegroundRole ) && item->type() == QgsAttributesFormData::Relation )
725 {
726 invalidRelation = !QgsProject::instance()->relationManager()->relation( item->id() ).isValid();
727 }
728
729 switch ( role )
730 {
731 case Qt::DisplayRole:
732 {
733 if ( !showAliases() && item->type() == QgsAttributesFormData::Field )
734 {
735 return item->name();
736 }
737
738 return item->displayName().isEmpty() ? item->name() : item->displayName();
739 }
740
741 case Qt::ToolTipRole:
742 {
744 {
745 const auto cfg = item->data( ItemFieldConfigRole ).value<QgsAttributesFormData::FieldConfig>();
746 if ( !cfg.mAlias.isEmpty() )
747 return tr( "%1 (%2)" ).arg( item->name(), cfg.mAlias );
748 else
749 return item->name();
750 }
751
752 if ( item->type() == QgsAttributesFormData::Relation && invalidRelation )
753 {
754 // Relation name will be displayed, inform users why it's red via tooltip
755 return tr( "Invalid relation" );
756 }
757
758 return QVariant();
759 }
760
761 case Qt::DecorationRole:
762 return item->icon();
763
764 case Qt::BackgroundRole:
765 {
767 return QBrush( QColor( 140, 140, 140, 50 ) );
768
769 return QVariant();
770 }
771
772 case Qt::ForegroundRole:
773 {
774 if ( item->type() == QgsAttributesFormData::Field )
775 {
776 if ( showAliases() && item->displayName().isEmpty() )
777 {
778 return QBrush( QColor( Qt::lightGray ) );
779 }
780 }
781
782 if ( item->type() == QgsAttributesFormData::Relation && invalidRelation )
783 {
784 return QBrush( QColor( 255, 0, 0 ) );
785 }
786
787 return QVariant();
788 }
789
790 case Qt::FontRole:
791 {
792 if ( item->type() == QgsAttributesFormData::Field )
793 {
794 if ( showAliases() && item->displayName().isEmpty() )
795 {
796 QFont font = QFont();
797 font.setItalic( true );
798 return font;
799 }
800 }
801 return QVariant();
802 }
803
804 case ItemDataRole:
806 case ItemNameRole:
807 case ItemTypeRole:
808 case ItemIdRole:
809 case ItemDisplayRole:
810 return item->data( role );
811
812 default:
813 return QVariant();
814 }
815}
816
818{
819 return Qt::CopyAction;
820}
821
823{
824 return QStringList() << u"application/x-qgsattributesformavailablewidgetsrelement"_s;
825}
826
827QMimeData *QgsAttributesAvailableWidgetsModel::mimeData( const QModelIndexList &indexes ) const
828{
829 if ( indexes.count() == 0 )
830 return nullptr;
831
832 const QStringList types = mimeTypes();
833 if ( types.isEmpty() )
834 return nullptr;
835
836 QMimeData *data = new QMimeData();
837 const QString format = types.at( 0 );
838 QByteArray encoded;
839 QDataStream stream( &encoded, QIODevice::WriteOnly );
840
841 // Sort indexes since their order reflects selection order
842 QModelIndexList sortedIndexes = indexes;
843
844 std::sort( sortedIndexes.begin(), sortedIndexes.end(), [this]( const QModelIndex &a, const QModelIndex &b ) {
845 return indexLessThan( a, b );
846 } );
847
848 for ( const QModelIndex &index : std::as_const( sortedIndexes ) )
849 {
850 if ( index.isValid() )
851 {
852 const QString itemId = index.data( QgsAttributesFormModel::ItemIdRole ).toString();
853 const QString itemName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
854 int itemType = index.data( QgsAttributesFormModel::ItemTypeRole ).toInt();
855
856 stream << itemId << itemType << itemName;
857 }
858 }
859
860 data->setData( format, encoded );
861 return data;
862}
863
865{
866 if ( mRootItem->childCount() > 0 )
867 {
868 const int row = 0;
869 QgsAttributesFormItem *item = mRootItem->child( row );
870 if ( item && item->name() == "Fields"_L1 && item->type() == QgsAttributesFormData::WidgetType )
871 return createIndex( row, 0, item );
872 }
873 return QModelIndex();
874}
875
877{
878 if ( mRootItem->childCount() > 1 )
879 {
880 const int row = 1;
881 QgsAttributesFormItem *item = mRootItem->child( row );
882 if ( item && item->name() == "Relations"_L1 && item->type() == QgsAttributesFormData::WidgetType )
883 return createIndex( row, 0, item );
884 }
885 return QModelIndex();
886}
887
889{
890 if ( mRootItem->childCount() > 2 )
891 {
892 const int row = 2;
893 QgsAttributesFormItem *item = mRootItem->child( row );
894 if ( item && item->name() == "Actions"_L1 && item->type() == QgsAttributesFormData::WidgetType )
895 return createIndex( row, 0, item );
896 }
897 return QModelIndex();
898}
899
900QModelIndex QgsAttributesAvailableWidgetsModel::fieldModelIndex( const QString &fieldName ) const
901{
902 if ( mRootItem->childCount() == 0 )
903 return QModelIndex();
904
905 QgsAttributesFormItem *fieldItems = mRootItem->child( 0 );
906 if ( !fieldItems || fieldItems->name() != "Fields"_L1 || fieldItems->type() != QgsAttributesFormData::WidgetType )
907 return QModelIndex();
908
909 QgsAttributesFormItem *item = fieldItems->firstTopChild( QgsAttributesFormData::Field, fieldName );
910 return item ? createIndex( item->row(), 0, item ) : QModelIndex();
911}
912
913
918
919QVariant QgsAttributesFormLayoutModel::headerData( int section, Qt::Orientation orientation, int role ) const
920{
921 Q_UNUSED( section )
922 return orientation == Qt::Horizontal && role == Qt::DisplayRole ? tr( "Form Layout" ) : QVariant {};
923}
924
925Qt::ItemFlags QgsAttributesFormLayoutModel::flags( const QModelIndex &index ) const
926{
927 if ( !index.isValid() )
928 return Qt::ItemIsDropEnabled;
929
930 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
931
934 flags |= Qt::ItemIsDropEnabled;
935
936 return flags;
937}
938
940{
941 if ( !mLayer )
942 return;
943
944 beginResetModel();
945 mRootItem->deleteChildren();
946
947 const auto editorElements = mLayer->editFormConfig().tabs();
948 for ( QgsAttributeEditorElement *editorElement : editorElements )
949 {
950 loadAttributeEditorElementItem( editorElement, mRootItem.get() );
951 }
952
953 endResetModel();
954}
955
956void QgsAttributesFormLayoutModel::loadAttributeEditorElementItem( QgsAttributeEditorElement *const editorElement, QgsAttributesFormItem *parent, const int position )
957{
958 auto setCommonProperties = [editorElement]( QgsAttributesFormData::AttributeFormItemData &itemData ) {
959 itemData.setShowLabel( editorElement->showLabel() );
960 itemData.setLabelStyle( editorElement->labelStyle() );
961 itemData.setHorizontalStretch( editorElement->horizontalStretch() );
962 itemData.setVerticalStretch( editorElement->verticalStretch() );
963 };
964
965 auto editorItem = std::make_unique< QgsAttributesFormItem >();
966
967 switch ( editorElement->type() )
968 {
970 {
971 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
972 setCommonProperties( itemData );
973
974 editorItem->setData( ItemNameRole, editorElement->name() );
975 editorItem->setData( ItemIdRole, editorElement->name() ); // Field names act as ids
976 editorItem->setData( ItemTypeRole, QgsAttributesFormData::Field );
977 editorItem->setData( ItemDataRole, itemData );
978
979 const int fieldIndex = mLayer->fields().indexOf( editorElement->name() );
980 if ( fieldIndex != -1 )
981 {
982 editorItem->setData( ItemDisplayRole, mLayer->fields().field( fieldIndex ).alias() );
983
984 QgsAttributesFormData::FieldConfig config( mLayer, fieldIndex );
985 editorItem->setData( ItemFieldConfigRole, config );
986 editorItem->setIcon( QgsGui::instance()->editorWidgetRegistry()->icon( config.mEditorWidgetType ) );
987 }
988
989 break;
990 }
991
993 {
994 const QgsAttributeEditorAction *actionEditor = static_cast<const QgsAttributeEditorAction *>( editorElement );
995 const QgsAction action { actionEditor->action( mLayer ) };
996 if ( action.isValid() )
997 {
998 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
999 setCommonProperties( itemData );
1000
1001 editorItem->setData( ItemIdRole, action.id().toString() );
1002 editorItem->setData( ItemNameRole, action.shortTitle().isEmpty() ? action.name() : action.shortTitle() );
1003 editorItem->setData( ItemTypeRole, QgsAttributesFormData::Action );
1004 editorItem->setData( ItemDataRole, itemData );
1005 editorItem->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetAction.svg"_s ) );
1006 }
1007 else
1008 {
1009 QgsDebugError( u"Invalid form action"_s );
1010 }
1011 break;
1012 }
1013
1015 {
1016 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1017 setCommonProperties( itemData );
1018
1019 const QgsAttributeEditorRelation *relationEditor = static_cast<const QgsAttributeEditorRelation *>( editorElement );
1020 QgsAttributesFormData::RelationEditorConfiguration relationEditorConfig;
1021 relationEditorConfig.mRelationWidgetType = relationEditor->relationWidgetTypeId();
1022 relationEditorConfig.mRelationWidgetConfig = relationEditor->relationEditorConfiguration();
1023 relationEditorConfig.nmRelationId = relationEditor->nmRelationId();
1024 relationEditorConfig.forceSuppressFormPopup = relationEditor->forceSuppressFormPopup();
1025 relationEditorConfig.label = relationEditor->label();
1026 itemData.setRelationEditorConfiguration( relationEditorConfig );
1027
1028 QgsRelation relation = relationEditor->relation();
1029 if ( relation.id().isEmpty() )
1030 {
1031 // If relation is coming from an internal move, we lose the id.
1032 // Go to relation manager and bring relation properties.
1033 relation = mProject->relationManager()->relation( editorElement->name() );
1034 }
1035
1036 editorItem->setData( ItemIdRole, relation.id() );
1037 editorItem->setData( ItemNameRole, relation.name() );
1038 editorItem->setData( ItemDisplayRole, relationEditorConfig.label );
1039 editorItem->setData( ItemTypeRole, QgsAttributesFormData::Relation );
1040 editorItem->setData( ItemDataRole, itemData );
1041 editorItem->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetRelationEditor.svg"_s ) );
1042
1043 break;
1044 }
1045
1047 {
1048 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1049 setCommonProperties( itemData );
1050
1051 editorItem->setData( ItemNameRole, editorElement->name() );
1052 editorItem->setData( ItemIdRole, editorElement->name() ); // Containers don't have id, use name to make them searchable
1053 editorItem->setData( ItemTypeRole, QgsAttributesFormData::Container );
1054
1055 const QgsAttributeEditorContainer *container = static_cast<const QgsAttributeEditorContainer *>( editorElement );
1056 if ( !container )
1057 break;
1058
1059 itemData.setColumnCount( container->columnCount() );
1060 itemData.setContainerType( container->type() );
1061 itemData.setBackgroundColor( container->backgroundColor() );
1062 itemData.setVisibilityExpression( container->visibilityExpression() );
1063 itemData.setCollapsedExpression( container->collapsedExpression() );
1064 itemData.setCollapsed( container->collapsed() );
1065
1066 editorItem->setData( ItemDataRole, itemData );
1067
1068 const QList<QgsAttributeEditorElement *> children = container->children();
1069 for ( QgsAttributeEditorElement *childElement : children )
1070 {
1071 loadAttributeEditorElementItem( childElement, editorItem.get() );
1072 }
1073 break;
1074 }
1075
1077 {
1078 const QgsAttributeEditorQmlElement *qmlElementEditor = static_cast<const QgsAttributeEditorQmlElement *>( editorElement );
1079 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1080 setCommonProperties( itemData );
1081
1082 QgsAttributesFormData::QmlElementEditorConfiguration qmlEdConfig;
1083 qmlEdConfig.qmlCode = qmlElementEditor->qmlCode();
1084 itemData.setQmlElementEditorConfiguration( qmlEdConfig );
1085
1086 editorItem->setData( ItemNameRole, editorElement->name() );
1087 editorItem->setData( ItemTypeRole, QgsAttributesFormData::QmlWidget );
1088 editorItem->setData( ItemDataRole, itemData );
1089 editorItem->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetQml.svg"_s ) );
1090 break;
1091 }
1092
1094 {
1095 const QgsAttributeEditorHtmlElement *htmlElementEditor = static_cast<const QgsAttributeEditorHtmlElement *>( editorElement );
1096 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1097 setCommonProperties( itemData );
1098
1099 QgsAttributesFormData::HtmlElementEditorConfiguration htmlEdConfig;
1100 htmlEdConfig.htmlCode = htmlElementEditor->htmlCode();
1101 itemData.setHtmlElementEditorConfiguration( htmlEdConfig );
1102
1103 editorItem->setData( ItemNameRole, editorElement->name() );
1104 editorItem->setData( ItemTypeRole, QgsAttributesFormData::HtmlWidget );
1105 editorItem->setData( ItemDataRole, itemData );
1106 editorItem->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetHtml.svg"_s ) );
1107 break;
1108 }
1109
1111 {
1112 const QgsAttributeEditorTextElement *textElementEditor = static_cast<const QgsAttributeEditorTextElement *>( editorElement );
1113 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1114 setCommonProperties( itemData );
1115
1116 QgsAttributesFormData::TextElementEditorConfiguration textEdConfig;
1117 textEdConfig.text = textElementEditor->text();
1118 itemData.setTextElementEditorConfiguration( textEdConfig );
1119
1120 editorItem->setData( ItemNameRole, editorElement->name() );
1121 editorItem->setData( ItemTypeRole, QgsAttributesFormData::TextWidget );
1122 editorItem->setData( ItemDataRole, itemData );
1123 editorItem->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetText.svg"_s ) );
1124 break;
1125 }
1126
1128 {
1129 const QgsAttributeEditorSpacerElement *spacerElementEditor = static_cast<const QgsAttributeEditorSpacerElement *>( editorElement );
1130 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1131 setCommonProperties( itemData );
1132 itemData.setShowLabel( false );
1133
1134 QgsAttributesFormData::SpacerElementEditorConfiguration spacerEdConfig;
1135 spacerEdConfig.drawLine = spacerElementEditor->drawLine();
1136 itemData.setSpacerElementEditorConfiguration( spacerEdConfig );
1137
1138 editorItem->setData( ItemNameRole, editorElement->name() );
1139 editorItem->setData( ItemTypeRole, QgsAttributesFormData::SpacerWidget );
1140 editorItem->setData( ItemDataRole, itemData );
1141 editorItem->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetSpacer.svg"_s ) );
1142 break;
1143 }
1144
1146 {
1147 QgsDebugError( u"Not loading invalid attribute editor type..."_s );
1148 break;
1149 }
1150 }
1151
1152 if ( position >= 0 && position < parent->childCount() )
1153 {
1154 parent->insertChild( position, std::move( editorItem ) );
1155 }
1156 else
1157 {
1158 parent->addChild( std::move( editorItem ) );
1159 }
1160}
1161
1162QVariant QgsAttributesFormLayoutModel::data( const QModelIndex &index, int role ) const
1163{
1164 if ( !index.isValid() )
1165 return QVariant();
1166
1167 if ( role == ItemFieldConfigRole ) // This model doesn't store data for that role
1168 return false;
1169
1171 if ( !item )
1172 return QVariant();
1173
1174 // Fields may be present in the form layout configuration
1175 // even if their corresponding layer fields were deleted.
1176 // Make those stand out from existent ones.
1177 const int fieldIndex = mLayer->fields().indexOf( item->name() );
1178 const bool invalidField = fieldIndex == -1;
1179
1180 // Relations may be broken due to missing layers or references.
1181 // Make those stand out from valid ones.
1182 bool invalidRelation = false;
1183 if ( ( role == Qt::DisplayRole || role == Qt::ToolTipRole || role == Qt::ForegroundRole ) && item->type() == QgsAttributesFormData::Relation )
1184 {
1185 invalidRelation = !QgsProject::instance()->relationManager()->relation( item->id() ).isValid();
1186 }
1187
1188 switch ( role )
1189 {
1190 case Qt::DisplayRole:
1191 {
1192 if ( item->type() == QgsAttributesFormData::Relation && invalidRelation )
1193 {
1194 // Invalid relations can have an id, if that's the case, we have a name.
1195 // Only set a new name if id is missing.
1196 if ( item->id().isEmpty() )
1197 {
1198 return tr( "Invalid relation" );
1199 }
1200 }
1201
1202 if ( !showAliases() && ( item->type() == QgsAttributesFormData::Field || item->type() == QgsAttributesFormData::Relation ) )
1203 {
1204 return item->name();
1205 }
1206
1207 return item->displayName().isEmpty() ? item->name() : item->displayName();
1208 }
1209
1210 case Qt::ToolTipRole:
1211 {
1212 if ( item->type() == QgsAttributesFormData::Field )
1213 {
1214 if ( invalidField )
1215 {
1216 return tr( "Invalid field" );
1217 }
1218 else
1219 {
1220 return item->name();
1221 }
1222 }
1223
1224 if ( item->type() == QgsAttributesFormData::Relation && invalidRelation )
1225 {
1226 if ( !item->id().isEmpty() )
1227 {
1228 // The relation name is shown, let's inform users via tooltip why it's red
1229 return tr( "Invalid relation" );
1230 }
1231 }
1232
1233 return QVariant();
1234 }
1235
1236 case Qt::DecorationRole:
1237 return item->icon();
1238
1239 case Qt::BackgroundRole:
1240 {
1241 if ( item->type() == QgsAttributesFormData::Container )
1242 return QBrush( QColor( 140, 140, 140, 50 ) );
1243
1244 return QVariant();
1245 }
1246
1247 case Qt::ForegroundRole:
1248 {
1249 if ( item->type() == QgsAttributesFormData::Field )
1250 {
1251 if ( invalidField )
1252 {
1253 return QBrush( QColor( 255, 0, 0 ) );
1254 }
1255 else if ( showAliases() && item->displayName().isEmpty() )
1256 {
1257 return QBrush( QColor( Qt::lightGray ) );
1258 }
1259 }
1260
1261 if ( item->type() == QgsAttributesFormData::Relation )
1262 {
1263 if ( invalidRelation )
1264 {
1265 return QBrush( QColor( 255, 0, 0 ) );
1266 }
1267 else if ( showAliases() && item->displayName().isEmpty() )
1268 {
1269 return QBrush( QColor( Qt::lightGray ) );
1270 }
1271 }
1272
1273 return QVariant();
1274 }
1275
1276 case Qt::FontRole:
1277 {
1278 if ( item->type() == QgsAttributesFormData::Field )
1279 {
1280 if ( !invalidField && showAliases() && item->displayName().isEmpty() )
1281 {
1282 QFont font = QFont();
1283 font.setItalic( true );
1284 return font;
1285 }
1286 }
1287
1288 if ( item->type() == QgsAttributesFormData::Relation )
1289 {
1290 if ( !invalidRelation && showAliases() && item->displayName().isEmpty() )
1291 {
1292 QFont font = QFont();
1293 font.setItalic( true );
1294 return font;
1295 }
1296 }
1297
1298 return QVariant();
1299 }
1300
1301 case ItemDataRole:
1302 case ItemNameRole:
1303 case ItemIdRole:
1304 case ItemTypeRole:
1305 case ItemDisplayRole:
1306 return item->data( role );
1307
1308 default:
1309 return QVariant();
1310 }
1311}
1312
1313bool QgsAttributesFormLayoutModel::removeRows( int row, int count, const QModelIndex &parent )
1314{
1315 if ( row < 0 )
1316 return false;
1317
1319
1320 if ( row > item->childCount() - count )
1321 return false;
1322
1323 beginRemoveRows( parent, row, row + count - 1 );
1324 for ( int r = 0; r < count; ++r )
1325 item->deleteChildAtIndex( row );
1326 endRemoveRows();
1327 return true;
1328}
1329
1330bool QgsAttributesFormLayoutModel::removeRow( int row, const QModelIndex &parent )
1331{
1332 beginRemoveRows( parent, row, row );
1334 item->deleteChildAtIndex( row );
1335 endRemoveRows();
1336 return true;
1337}
1338
1340{
1341 return Qt::MoveAction;
1342}
1343
1345{
1346 return Qt::DropAction::CopyAction | Qt::DropAction::MoveAction;
1347}
1348
1350{
1351 return QStringList() << u"application/x-qgsattributesformlayoutelement"_s << u"application/x-qgsattributesformavailablewidgetsrelement"_s;
1352}
1353
1354QModelIndexList QgsAttributesFormLayoutModel::curateIndexesForMimeData( const QModelIndexList &indexes ) const
1355{
1356 QModelIndexList containerList;
1357 for ( const auto index : indexes )
1358 {
1359 const auto indexType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
1360 if ( indexType == QgsAttributesFormData::Container )
1361 {
1362 containerList << index;
1363 }
1364 }
1365
1366 if ( containerList.size() == 0 )
1367 return indexes;
1368
1369 QModelIndexList curatedIndexes;
1370
1371 // Iterate searching if current index is child of any container in containerList (recursively)
1372 for ( const auto index : indexes )
1373 {
1374 QModelIndex parent = index.parent();
1375 bool redundantChild = false;
1376
1377 while ( parent.isValid() )
1378 {
1379 if ( containerList.contains( parent ) )
1380 {
1381 redundantChild = true;
1382 break;
1383 }
1384
1385 parent = parent.parent();
1386 }
1387
1388 if ( !redundantChild )
1389 curatedIndexes << index;
1390 }
1391
1392 return curatedIndexes;
1393}
1394
1395QMimeData *QgsAttributesFormLayoutModel::mimeData( const QModelIndexList &indexes ) const
1396{
1397 if ( indexes.count() == 0 )
1398 return nullptr;
1399
1400 // Discard redundant indexes
1401 QModelIndexList curatedIndexes;
1402 if ( indexes.count() > 1 )
1403 {
1404 curatedIndexes = curateIndexesForMimeData( indexes );
1405 }
1406 else
1407 {
1408 curatedIndexes = indexes;
1409 }
1410
1411 const QStringList types = mimeTypes();
1412 if ( types.isEmpty() )
1413 return nullptr;
1414
1415 QMimeData *data = new QMimeData();
1416 const QString format = types.at( 0 );
1417 QByteArray encoded;
1418 QDataStream stream( &encoded, QIODevice::WriteOnly );
1419
1420 // Sort indexes since their order reflects selection order
1421 std::sort( curatedIndexes.begin(), curatedIndexes.end(), [this]( const QModelIndex &a, const QModelIndex &b ) {
1422 return indexLessThan( a, b );
1423 } );
1424
1425 for ( const QModelIndex &index : std::as_const( curatedIndexes ) )
1426 {
1427 if ( index.isValid() )
1428 {
1429 QDomDocument doc;
1430
1431 QDomElement rootElem = doc.createElement( u"form_layout_mime"_s );
1433 QDomElement editorElem = editor->toDomElement( doc );
1434 rootElem.appendChild( editorElem );
1435
1436 doc.appendChild( rootElem );
1437 stream << doc.toString( -1 );
1438 }
1439 }
1440
1441 data->setData( format, encoded );
1442 return data;
1443}
1444
1445bool QgsAttributesFormLayoutModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
1446{
1447 Q_UNUSED( column )
1448 bool isDropSuccessful = false;
1449 int rows = 0;
1450
1451 if ( row == -1 ) // Dropped at invalid index
1452 row = rowCount( parent ); // Let's append the item
1453
1454 if ( action == Qt::IgnoreAction )
1455 {
1456 isDropSuccessful = true;
1457 }
1458 else if ( data->hasFormat( u"application/x-qgsattributesformavailablewidgetsrelement"_s ) )
1459 {
1460 Q_ASSERT( action == Qt::CopyAction ); // External drop
1461 QByteArray itemData = data->data( u"application/x-qgsattributesformavailablewidgetsrelement"_s );
1462 QDataStream stream( &itemData, QIODevice::ReadOnly );
1463
1464 while ( !stream.atEnd() )
1465 {
1466 QString itemId;
1467 int itemTypeInt;
1468 QString itemName;
1469 stream >> itemId >> itemTypeInt >> itemName;
1470
1471 const auto itemType = static_cast< QgsAttributesFormData::AttributesFormItemType >( itemTypeInt );
1472 insertChild( parent, row + rows, itemId, itemType, itemName );
1473
1474 isDropSuccessful = true;
1475
1476 QModelIndex addedIndex = index( row + rows, 0, parent );
1477 emit externalItemDropped( addedIndex );
1478
1479 rows++;
1480 }
1481 }
1482 else if ( data->hasFormat( u"application/x-qgsattributesformlayoutelement"_s ) )
1483 {
1484 Q_ASSERT( action == Qt::MoveAction ); // Internal move
1485 QByteArray itemData = data->data( u"application/x-qgsattributesformlayoutelement"_s );
1486 QDataStream stream( &itemData, QIODevice::ReadOnly );
1487
1488 while ( !stream.atEnd() )
1489 {
1490 QString text;
1491 stream >> text;
1492
1493 QDomDocument doc;
1494 if ( !doc.setContent( text ) )
1495 continue;
1496 const QDomElement rootElem = doc.documentElement();
1497 if ( rootElem.tagName() != "form_layout_mime"_L1 || !rootElem.hasChildNodes() )
1498 continue;
1499 const QDomElement childElem = rootElem.firstChild().toElement();
1500
1501 // Build editor element from XML and add/insert it to parent
1503 beginInsertRows( parent, row + rows, row + rows );
1504 loadAttributeEditorElementItem( editor, itemForIndex( parent ), row + rows );
1505 endInsertRows();
1506
1507 isDropSuccessful = true;
1508
1509 QModelIndex addedIndex = index( row + rows, 0, parent );
1510 emit internalItemDropped( addedIndex );
1511
1512 rows++;
1513 }
1514 }
1515
1516 return isDropSuccessful;
1517}
1518
1519void QgsAttributesFormLayoutModel::updateFieldConfigForFieldItemsRecursive( QgsAttributesFormItem *parent, const QString &fieldName, const QgsAttributesFormData::FieldConfig &config )
1520{
1521 for ( int i = 0; i < parent->childCount(); i++ )
1522 {
1523 QgsAttributesFormItem *child = parent->child( i );
1524 if ( child->name() == fieldName && child->type() == QgsAttributesFormData::Field )
1525 {
1526 child->setData( ItemFieldConfigRole, QVariant::fromValue( config ) );
1527 child->setIcon( QgsGui::instance()->editorWidgetRegistry()->icon( config.mEditorWidgetType ) );
1528 emit fieldConfigDataChanged( child ); // Item's field config has changed, let views know about it
1529 }
1530
1531 if ( child->childCount() > 0 )
1532 {
1533 updateFieldConfigForFieldItemsRecursive( child, fieldName, config );
1534 }
1535 }
1536}
1537
1539{
1540 updateFieldConfigForFieldItemsRecursive( mRootItem.get(), fieldName, config );
1541}
1542
1543void QgsAttributesFormLayoutModel::updateAliasForFieldItemsRecursive( QgsAttributesFormItem *parent, const QString &fieldName, const QString &fieldAlias )
1544{
1545 for ( int i = 0; i < parent->childCount(); i++ )
1546 {
1547 QgsAttributesFormItem *child = parent->child( i );
1548 if ( child->name() == fieldName && child->type() == QgsAttributesFormData::Field )
1549 {
1550 child->setData( ItemDisplayRole, fieldAlias );
1551 const QModelIndex index = createIndex( child->row(), 0, child );
1552 emit dataChanged( index, index ); // Item's alias has changed, let views know about it
1553 }
1554
1555 if ( child->childCount() > 0 )
1556 {
1557 updateAliasForFieldItemsRecursive( child, fieldName, fieldAlias );
1558 }
1559 }
1560}
1561
1562void QgsAttributesFormLayoutModel::updateAliasForFieldItems( const QString &fieldName, const QString &fieldAlias )
1563{
1564 updateAliasForFieldItemsRecursive( mRootItem.get(), fieldName, fieldAlias );
1565}
1566
1567QList< QgsAddAttributeFormContainerDialog::ContainerPair > QgsAttributesFormLayoutModel::recursiveListOfContainers( QgsAttributesFormItem *parent ) const
1568{
1569 QList< QgsAddAttributeFormContainerDialog::ContainerPair > containerList;
1570 for ( int i = 0; i < parent->childCount(); i++ )
1571 {
1572 QgsAttributesFormItem *child = parent->child( i );
1573 if ( child->type() == QgsAttributesFormData::Container )
1574 {
1575 containerList << QgsAddAttributeFormContainerDialog::ContainerPair( child->name(), createIndex( child->row(), 0, child ) );
1576 }
1577
1578 if ( child->childCount() > 0 )
1579 {
1580 containerList.append( recursiveListOfContainers( child ) );
1581 }
1582 }
1583
1584 return containerList;
1585}
1586
1588{
1589 QgsAttributeEditorElement *widgetDef = nullptr;
1590
1592 const int indexType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
1593 const QString indexName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
1594 const QString indexId = index.data( QgsAttributesFormModel::ItemIdRole ).toString();
1595
1596 switch ( indexType )
1597 {
1599 {
1600 const int fieldIndex = mLayer->fields().lookupField( indexName );
1601 widgetDef = new QgsAttributeEditorField( indexName, fieldIndex, parent );
1602 break;
1603 }
1604
1606 {
1607 const QgsAction action { mLayer->actions()->action( indexId ) };
1608 widgetDef = new QgsAttributeEditorAction( action, parent );
1609 break;
1610 }
1611
1613 {
1614 const QgsRelation relation = mProject->relationManager()->relation( indexId );
1615
1618 relDef->setRelationWidgetTypeId( relationEditorConfig.mRelationWidgetType );
1619 relDef->setRelationEditorConfiguration( relationEditorConfig.mRelationWidgetConfig );
1620 relDef->setNmRelationId( relationEditorConfig.nmRelationId );
1621 relDef->setForceSuppressFormPopup( relationEditorConfig.forceSuppressFormPopup );
1622 relDef->setLabel( relationEditorConfig.label );
1623 widgetDef = relDef;
1624 break;
1625 }
1626
1628 {
1629 QgsAttributeEditorContainer *container = new QgsAttributeEditorContainer( indexName, parent, itemData.backgroundColor() );
1630 container->setColumnCount( itemData.columnCount() );
1631 // only top-level containers can be tabs
1633 bool isTopLevel = !index.parent().isValid();
1634 if ( type == Qgis::AttributeEditorContainerType::Tab && !isTopLevel )
1635 {
1636 // a tab container found which isn't at the top level -- reset it to a group box instead
1638 }
1639 container->setType( type );
1640 container->setCollapsed( itemData.collapsed() );
1641 container->setCollapsedExpression( itemData.collapsedExpression() );
1642 container->setVisibilityExpression( itemData.visibilityExpression() );
1643 container->setBackgroundColor( itemData.backgroundColor() );
1644
1645 QModelIndex childIndex;
1646 for ( int t = 0; t < rowCount( index ); t++ )
1647 {
1648 childIndex = this->index( t, 0, index );
1649 QgsAttributeEditorElement *element { createAttributeEditorWidget( childIndex, container ) };
1650 if ( element )
1651 container->addChildElement( element );
1652 }
1653 widgetDef = container;
1654 break;
1655 }
1656
1658 {
1660 element->setQmlCode( itemData.qmlElementEditorConfiguration().qmlCode );
1661 widgetDef = element;
1662 break;
1663 }
1664
1666 {
1669 widgetDef = element;
1670 break;
1671 }
1672
1674 {
1676 element->setText( itemData.textElementEditorConfiguration().text );
1677 widgetDef = element;
1678 break;
1679 }
1680
1682 {
1685 widgetDef = element;
1686 break;
1687 }
1688
1690 default:
1691 break;
1692 }
1693
1694 if ( widgetDef )
1695 {
1696 widgetDef->setShowLabel( itemData.showLabel() );
1697 widgetDef->setLabelStyle( itemData.labelStyle() );
1698 widgetDef->setHorizontalStretch( itemData.horizontalStretch() );
1699 widgetDef->setVerticalStretch( itemData.verticalStretch() );
1700 }
1701
1702 return widgetDef;
1703}
1704
1705QList< QgsAddAttributeFormContainerDialog::ContainerPair > QgsAttributesFormLayoutModel::listOfContainers() const
1706{
1707 return recursiveListOfContainers( mRootItem.get() );
1708}
1709
1711{
1712 beginInsertRows( parent, rowCount( parent ), rowCount( parent ) );
1713
1714 QgsAttributesFormItem *parentItem = itemForIndex( parent );
1715
1716 auto containerItem = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::Container, name, QString(), parentItem );
1717
1719 itemData.setColumnCount( columnCount );
1721
1722 containerItem->setData( QgsAttributesFormModel::ItemDataRole, itemData );
1723 containerItem->setData( QgsAttributesFormModel::ItemIdRole, name ); // Make it searchable
1724 parentItem->addChild( std::move( containerItem ) );
1725
1726 endInsertRows();
1727}
1728
1729void QgsAttributesFormLayoutModel::insertChild( const QModelIndex &parent, int row, const QString &itemId, QgsAttributesFormData::AttributesFormItemType itemType, const QString &itemName )
1730{
1731 if ( row < 0 )
1732 return;
1733
1734 beginInsertRows( parent, row, row );
1735 auto item = std::make_unique< QgsAttributesFormItem >();
1736
1737 item->setData( QgsAttributesFormModel::ItemIdRole, itemId );
1738 item->setData( QgsAttributesFormModel::ItemTypeRole, itemType );
1739 item->setData( QgsAttributesFormModel::ItemNameRole, itemName );
1740
1741 itemForIndex( parent )->insertChild( row, std::move( item ) );
1742 endInsertRows();
1743}
1744
1745
1747 : QSortFilterProxyModel( parent )
1748{
1749}
1750
1752{
1753 mModel = model;
1754 QSortFilterProxyModel::setSourceModel( mModel );
1755}
1756
1761
1763{
1764 return mFilterText;
1765}
1766
1768{
1769 // Since we want to allow refreshing the filter when, e.g.,
1770 // users switch to aliases, then we allow this method to be
1771 // executed even if previous and new filters are equal
1772
1773 mFilterText = filterText.trimmed();
1774 invalidate();
1775}
1776
1777bool QgsAttributesFormProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
1778{
1779 if ( mFilterText.isEmpty() )
1780 return true;
1781
1782 QModelIndex sourceIndex = sourceModel()->index( sourceRow, 0, sourceParent );
1783 if ( !sourceIndex.isValid() )
1784 return false;
1785
1786 // If name or alias match, accept it before any other checks
1787 if ( sourceIndex.data( QgsAttributesFormModel::ItemNameRole ).toString().contains( mFilterText, Qt::CaseInsensitive ) || sourceIndex.data( QgsAttributesFormModel::ItemDisplayRole ).toString().contains( mFilterText, Qt::CaseInsensitive ) )
1788 return true;
1789
1790 // Child is accepted if any of its parents is accepted
1791 QModelIndex parent = sourceIndex.parent();
1792 while ( parent.isValid() )
1793 {
1794 if ( parent.data( QgsAttributesFormModel::ItemNameRole ).toString().contains( mFilterText, Qt::CaseInsensitive ) || parent.data( QgsAttributesFormModel::ItemDisplayRole ).toString().contains( mFilterText, Qt::CaseInsensitive ) )
1795 return true;
1796
1797 parent = parent.parent();
1798 }
1799
1800 return false;
1801}
AttributeEditorContainerType
Attribute editor container types.
Definition qgis.h:5736
@ Action
A layer action element.
Definition qgis.h:5723
@ Container
A container.
Definition qgis.h:5718
@ QmlElement
A QML element.
Definition qgis.h:5721
@ Relation
A relation.
Definition qgis.h:5720
@ HtmlElement
A HTML element.
Definition qgis.h:5722
@ TextElement
A text element.
Definition qgis.h:5724
@ SpacerElement
A spacer element.
Definition qgis.h:5725
Utility class that encapsulates an action based on vector attributes.
Definition qgsaction.h:38
QString name() const
The name of the action. This may be a longer description.
Definition qgsaction.h:116
bool isValid() const
Returns true if this action was a default constructed one.
Definition qgsaction.h:131
QString shortTitle() const
The short title is used to label user interface elements like buttons.
Definition qgsaction.h:119
QUuid id() const
Returns a unique id for this action.
Definition qgsaction.h:125
QPair< QString, QModelIndex > ContainerPair
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.
A container for attribute editors, used to group them visually in the attribute form if it is set to ...
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.
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 true if this group box is collapsed.
Qgis::AttributeEditorContainerType type() const
Returns the container type.
void setType(Qgis::AttributeEditorContainerType type)
Sets the container type.
void setCollapsedExpression(const QgsOptionalExpression &collapsedExpression)
The collapsed expression is used in the attribute form to set the collapsed status of the group box o...
QList< QgsAttributeEditorElement * > children() const
Gets a list of the children elements of this container.
QColor backgroundColor() const
Returns the background color of the container.
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.
An abstract base class for any elements of a drag and drop form.
void setHorizontalStretch(int stretch)
Sets the horizontal stretch factor for the element.
QDomElement toDomElement(QDomDocument &doc) const
Gets the XML Dom element to save this element.
LabelStyle labelStyle() const
Returns the label style.
void setLabelStyle(const LabelStyle &labelStyle)
Sets the labelStyle.
Qgis::AttributeEditorType type() const
The type of this element.
int verticalStretch() const
Returns the vertical stretch factor for the 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.
static QgsAttributeEditorElement * create(const QDomElement &element, const QString &layerId, const QgsFields &fields, const QgsReadWriteContext &context, QgsAttributeEditorElement *parent=nullptr)
Constructs the editor element from the given element.
void setVerticalStretch(int stretch)
Sets the vertical stretch factor for the element.
void setShowLabel(bool showLabel)
Controls if this element should be labeled with a title (field, relation or groupname).
int horizontalStretch() const
Returns the horizontal stretch factor for the element.
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.
An attribute editor widget that will represent a spacer.
void setDrawLine(bool drawLine)
Sets a flag to define if the spacer element will contain an horizontal line.
bool drawLine() const
Returns true if the spacer element will contain an horizontal line.
An attribute editor widget that will represent arbitrary text code.
void setText(const QString &text)
Sets the text that will be represented within this widget to text.
QString text() const
The Text that will be represented within this widget.
QgsAttributesAvailableWidgetsModel(QgsVectorLayer *layer, QgsProject *project, QObject *parent=nullptr)
Constructor for QgsAttributesAvailableWidgetsModel, with the given parent.
Qt::DropActions supportedDragActions() const override
Qt::ItemFlags flags(const QModelIndex &index) const override
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
QMimeData * mimeData(const QModelIndexList &indexes) const override
QModelIndex fieldModelIndex(const QString &fieldName) const
Returns the model index that corresponds to the field with the given fieldName.
QModelIndex actionContainer() const
Returns the action container in this model, expected to be placed at the third top-level row.
void populateLayerActions(const QList< QgsAction > actions)
Refresh layer actions in the model to keep an updated action list.
QModelIndex fieldContainer() const
Returns the field container in this model, expected to be placed at the first top-level row.
QModelIndex relationContainer() const
Returns the relation container in this model, expected to be placed at the second top-level row.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
Main class to store and transfer editor data contained in a QgsAttributesFormModel.
HtmlElementEditorConfiguration htmlElementEditorConfiguration() const
Returns the HTML editor configuration.
QgsOptionalExpression collapsedExpression() const
Returns the optional expression that dynamically controls the collapsed status of a group box contain...
TextElementEditorConfiguration textElementEditorConfiguration() const
Returns the editor configuration for text element.
bool collapsed() const
For group box containers returns if this group box is collapsed.
SpacerElementEditorConfiguration spacerElementEditorConfiguration() const
Returns the spacer element configuration.
const QgsAttributeEditorElement::LabelStyle labelStyle() const
Returns the label style.
void setColumnCount(int count)
Sets the number of columns for a container.
void setHtmlElementEditorConfiguration(const HtmlElementEditorConfiguration &htmlElementEditorConfiguration)
Sets the HTML editor configuration.
void setBackgroundColor(const QColor &backgroundColor)
Sets the background color of a container.
int columnCount() const
Returns the number of columns in a container.
bool showLabel() const
Returns whether the widget's label is to be shown.
void setCollapsedExpression(const QgsOptionalExpression &collapsedExpression)
Sets the optional collapsedExpression that dynamically controls the collapsed status of a group box c...
void setShowLabel(bool showLabel)
Sets whether the label for the widget should be shown.
void setQmlElementEditorConfiguration(const QmlElementEditorConfiguration &qmlElementEditorConfiguration)
Sets the QML editor configuration.
int horizontalStretch() const
Returns the horizontal stretch factor for the element.
void setHorizontalStretch(int stretch)
Sets the horizontal stretch factor for the element.
void setContainerType(Qgis::AttributeEditorContainerType type)
Sets the container type.
RelationEditorConfiguration relationEditorConfiguration() const
Returns the relation editor configuration.
void setRelationEditorConfiguration(const RelationEditorConfiguration &relationEditorConfiguration)
Sets the relation editor configuration.
void setVisibilityExpression(const QgsOptionalExpression &visibilityExpression)
Sets the optional visibilityExpression that dynamically controls the visibility status of a container...
Qgis::AttributeEditorContainerType containerType() const
Returns the container type.
void setLabelStyle(const QgsAttributeEditorElement::LabelStyle &labelStyle)
Sets the label style to labelStyle.
int verticalStretch() const
Returns the vertical stretch factor for the element.
void setVerticalStretch(int stretch)
Sets the vertical stretch factor for the element.
void setCollapsed(bool collapsed)
For group box containers sets if this group box is collapsed.
void setSpacerElementEditorConfiguration(SpacerElementEditorConfiguration spacerElementEditorConfiguration)
Sets the the spacer element configuration to spacerElementEditorConfiguration.
QmlElementEditorConfiguration qmlElementEditorConfiguration() const
Returns the QML editor configuration.
QColor backgroundColor() const
Returns the background color of a container.
void setTextElementEditorConfiguration(const TextElementEditorConfiguration &textElementEditorConfiguration)
Sets the editor configuration for text element to textElementEditorConfiguration.
QgsOptionalExpression visibilityExpression() const
Returns the expression to control the visibility status of a container.
AttributesFormItemType
Custom item types.
@ Container
Container for the form, which may be tab, group or row.
@ Relation
Relation between two vector layers.
@ Field
Vector layer field.
@ SpacerWidget
Spacer widget type,.
@ WidgetType
In the available widgets tree, the type of widget.
@ TextWidget
Text widget type,.
Holds parent-child relations as well as item data contained in a QgsAttributesFormModel.
void insertChild(int position, std::unique_ptr< QgsAttributesFormItem > &&item)
Inserts a child item to the item at a given position.
QIcon icon() const
Returns the icon of the item.
void setIcon(const QIcon &icon)
Sets an icon for the item.
QgsAttributesFormItem()=default
QString name() const
Returns the name of the item.
int childCount() const
Returns the number of children items for the given item.
QgsAttributesFormItem * child(int row)
Access the child item located at row position.
static bool isGroup(QgsAttributesFormItem *item)
Returns whether the item is a group.
bool setData(int role, const QVariant &value)
Stores a data value in a given role inside the item.
QgsAttributesFormItem * parent()
Returns the parent object of the item.
QgsAttributesFormItem * firstChildRecursive(const QgsAttributesFormData::AttributesFormItemType &itemType, const QString &itemId) const
Access the first child item that matches itemType and itemId, recursively.
int row() const
Returns the position of the item regarding its parent.
QgsAttributesFormData::AttributesFormItemType type() const
Returns the type of the item.
QString id() const
Returns the id of the item.
QVariant data(int role) const
Returns the data stored in the item, corresponding to the given role.
QString displayName() const
Returns the display name of the item.
void addedChildren(QgsAttributesFormItem *item, int indexFrom, int indexTo)
Notifies other objects when children have been added to the item, informing the indices where added c...
void addChild(std::unique_ptr< QgsAttributesFormItem > &&child)
Appends a child to this item.
QgsAttributesFormItem * firstTopChild(const QgsAttributesFormData::AttributesFormItemType itemType, const QString &itemId) const
Access the first top-level child item that matches itemType and itemId.
void deleteChildAtIndex(int index)
Deletes the child of the item placed at the given index.
void deleteChildren()
Deletes all child items from this item.
void externalItemDropped(QModelIndex &index)
Informs that items were inserted (via drop) in the model from another model.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
Qt::DropActions supportedDragActions() const override
void updateAliasForFieldItems(const QString &fieldName, const QString &fieldAlias)
Updates the aliases of all matching fields in the model.
QStringList mimeTypes() const override
QgsAttributesFormLayoutModel(QgsVectorLayer *layer, QgsProject *project, QObject *parent=nullptr)
Constructor for QgsAttributesFormLayoutModel, with the given parent.
QMimeData * mimeData(const QModelIndexList &indexes) const override
bool removeRow(int row, const QModelIndex &parent=QModelIndex())
Removes the index located at row within the given parent.
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override
Qt::DropActions supportedDropActions() const override
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
void updateFieldConfigForFieldItems(const QString &fieldName, const QgsAttributesFormData::FieldConfig &config)
Updates the field config of all matching fields in the model.
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
void addContainer(QModelIndex &parent, const QString &name, int columnCount, Qgis::AttributeEditorContainerType type)
Adds a new container to parent.
QList< QgsAddAttributeFormContainerDialog::ContainerPair > listOfContainers() const
Returns a list of containers stored in the model, structured as pairs (name, container model index).
QgsAttributeEditorElement * createAttributeEditorWidget(const QModelIndex &index, QgsAttributeEditorElement *parent) const
Creates a new attribute editor element based on the definition stored in a form layout model index.
Qt::ItemFlags flags(const QModelIndex &index) const override
void internalItemDropped(QModelIndex &index)
Informs that items were moved (via drop) in the model from the same model.
void insertChild(const QModelIndex &parent, int row, const QString &itemId, QgsAttributesFormData::AttributesFormItemType itemType, const QString &itemName)
Inserts a new child to parent model index at the given row position.
Abstract class for tree models allowing for configuration of attributes forms.
void emitDataChangedRecursively(const QModelIndex &parent=QModelIndex(), const QVector< int > &roles=QVector< int >())
Emits dataChanged signal for all parent items in a model.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
std::unique_ptr< QgsAttributesFormItem > mRootItem
bool showAliases() const
Returns whether field aliases are preferred over field names as item text.
@ ItemFieldConfigRole
Prior to QGIS 3.44, this was available as FieldConfigRole.
@ ItemDisplayRole
Display text for the item.
@ ItemNameRole
Prior to QGIS 3.44, this was available as FieldNameRole.
@ ItemDataRole
Prior to QGIS 3.44, this was available as DnDTreeRole.
@ ItemIdRole
Items may have ids to ease comparison. Used by Relations, fields, actions and containers.
void setShowAliases(bool show)
Sets whether field aliases should be preferred over field names as item text.
QModelIndex firstRecursiveMatchingModelIndex(const QgsAttributesFormData::AttributesFormItemType &itemType, const QString &itemId) const
Returns the first model index that matches the given itemType and itemId, recursively.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
QgsAttributesFormModel(QgsVectorLayer *layer, QgsProject *project, QObject *parent=nullptr)
Constructor for QgsAttributesFormModel, with the given parent.
QModelIndex parent(const QModelIndex &index) const override
~QgsAttributesFormModel() override
QModelIndex firstTopMatchingModelIndex(const QgsAttributesFormData::AttributesFormItemType &itemType, const QString &itemId) const
Returns the first top-level model index that matches the given itemType and itemId.
bool indexLessThan(const QModelIndex &a, const QModelIndex &b) const
Auxiliary function to sort indexes, returning true if index a is less than index b.
void fieldConfigDataChanged(QgsAttributesFormItem *item)
Notifies other objects that the field config data has changed in the item.
int columnCount(const QModelIndex &parent=QModelIndex()) const override
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
QgsAttributesFormItem * rootItem() const
Returns the root item in this model.
QVector< int > rootToLeafPath(QgsAttributesFormItem *item) const
Returns a QVector of iterative positions from root item to the given item.
QgsAttributesFormItem * itemForIndex(const QModelIndex &index) const
Returns the underlying item that corresponds to the given index.
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
QgsAttributesFormModel * sourceAttributesFormModel() const
Returns the source model.
void setFilterText(const QString &filterText=QString())
Sets the filter text.
const QString filterText() const
Returns the text used to filter source model items.
QgsAttributesFormProxyModel(QObject *parent=nullptr)
Constructor for QgsAttributesFormProxyModel, with the given parent.
void setAttributesFormSourceModel(QgsAttributesFormModel *model)
Sets the source model for the proxy model.
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 ...
QgsPropertyCollection dataDefinedFieldProperties(const QString &fieldName) const
Returns data defined properties for fieldName.
bool labelOnTop(int idx) const
If this returns true, the widget at the given index will receive its label on the previous line while...
Qgis::AttributeFormReuseLastValuePolicy reuseLastValuePolicy(int index) const
Returns the reuse of last value policy for an attribute index.
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.
QString type() const
Returns the widget type to use.
QVariantMap config() const
Returns the widget configuration.
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:56
QString name
Definition qgsfield.h:65
Qgis::FieldDomainSplitPolicy splitPolicy() const
Returns the field's split policy, which indicates how field values should be handled during a split o...
Definition qgsfield.cpp:766
QString alias
Definition qgsfield.h:66
Qgis::FieldDuplicatePolicy duplicatePolicy() const
Returns the field's duplicate policy, which indicates how field values should be handled during a dup...
Definition qgsfield.cpp:776
QgsDefaultValue defaultValueDefinition
Definition qgsfield.h:67
Qgis::FieldDomainMergePolicy mergePolicy() const
Returns the field's merge policy, which indicates how field values should be handled during a merge o...
Definition qgsfield.cpp:786
QString comment
Definition qgsfield.h:64
QgsFieldConstraints constraints
Definition qgsfield.h:68
Container of fields for a vector layer.
Definition qgsfields.h:46
int count
Definition qgsfields.h:50
QgsField field(int fieldIdx) const
Returns the field at particular index (must be in range 0..N-1).
int size() const
Returns number of items.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
QIcon iconForField(int fieldIdx, bool considerOrigin=false) const
Returns an icon corresponding to a field index, based on the field's type and source.
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories.
Definition qgsgui.cpp:109
static QgsGui * instance()
Returns a pointer to the singleton instance.
Definition qgsgui.cpp:93
An expression with an additional enabled flag.
A relation where the referenced (parent) layer is calculated based on fields from the referencing (ch...
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:112
QgsRelationManager * relationManager
Definition qgsproject.h:123
static QgsProject * instance()
Returns the QgsProject singleton instance.
A container for the context for various read/write operations on objects.
Q_INVOKABLE QgsRelation relation(const QString &id) const
Gets access to a relation by its id.
Represents a relationship between two vector layers.
Definition qgsrelation.h:42
QString name
Definition qgsrelation.h:52
QString id
Definition qgsrelation.h:45
Represents a vector layer which manages a vector based dataset.
QgsEditFormConfig editFormConfig
#define QgsDebugError(str)
Definition qgslogger.h:59
The TabStyle struct defines color and font overrides for form fields, tabs and groups labels.
Holds the configuration for a field.
Qgis::FieldDuplicatePolicy mDuplicatePolicy
QMap< QString, QVariant > mEditorWidgetConfig
Qgis::FieldDomainSplitPolicy mSplitPolicy
Qgis::FieldDomainMergePolicy mMergePolicy
Qgis::AttributeFormReuseLastValuePolicy mReuseLastValuePolicy