QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
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
191)
192 : mName( name )
193 , mDisplayName( displayName )
194 , mType( itemType )
195 , mData( data )
196 , mParent( parent )
197{}
198
200{
201 if ( !mChildren.empty() && row >= 0 && row < childCount() )
202 return mChildren.at( row ).get();
203
204 return nullptr;
205}
206
208{
209 if ( !mChildren.empty() && itemId.trimmed().isEmpty() )
210 return nullptr;
211
212 // Search for first matching item by name
213 const auto it = std::find_if( mChildren.cbegin(), mChildren.cend(), [itemType, itemId]( const std::unique_ptr< QgsAttributesFormItem > &item ) {
214 return item->type() == itemType && item->id() == itemId;
215 } );
216
217 if ( it != mChildren.cend() )
218 return it->get();
219
220 return nullptr;
221}
222
224{
225 if ( !mChildren.empty() && itemId.trimmed().isEmpty() )
226 return nullptr;
227
228 for ( const auto &child : std::as_const( mChildren ) )
229 {
230 if ( child->type() == itemType && child->id() == itemId )
231 return child.get();
232
233 if ( child->childCount() > 0 )
234 {
235 QgsAttributesFormItem *item = child->firstChildRecursive( itemType, itemId );
236 if ( item )
237 return item;
238 }
239 }
240
241 return nullptr;
242}
243
245{
246 return static_cast< int >( mChildren.size() );
247}
248
250{
251 if ( !mParent )
252 return 0;
253
254 const auto it = std::find_if( mParent->mChildren.cbegin(), mParent->mChildren.cend(), [this]( const std::unique_ptr< QgsAttributesFormItem > &item ) { return item.get() == this; } );
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
381
383{
384 if ( index.isValid() )
385 {
386 if ( auto *item = static_cast<QgsAttributesFormItem *>( index.internalPointer() ) )
387 return item;
388 }
389 return mRootItem.get();
390}
391
396
397
398int QgsAttributesFormModel::rowCount( const QModelIndex &parent ) const
399{
400 if ( parent.isValid() && parent.column() > 0 )
401 return 0;
402
403 const QgsAttributesFormItem *parentItem = itemForIndex( parent );
404
405 return parentItem ? parentItem->childCount() : 0;
406}
407
408int QgsAttributesFormModel::columnCount( const QModelIndex & ) const
409{
410 return 1;
411}
412
413bool QgsAttributesFormModel::indexLessThan( const QModelIndex &a, const QModelIndex &b ) const
414{
415 const QVector<int> pathA = rootToLeafPath( itemForIndex( a ) );
416 const QVector<int> pathB = rootToLeafPath( itemForIndex( b ) );
417
418 for ( int i = 0; i < std::min( pathA.size(), pathB.size() ); i++ )
419 {
420 if ( pathA.at( i ) != pathB.at( i ) )
421 {
422 return pathA.at( i ) < pathB.at( i );
423 }
424 }
425
426 return pathA.size() < pathB.size();
427}
428
430{
431 QVector<int> path;
432 if ( item != mRootItem.get() )
433 {
434 path << rootToLeafPath( item->parent() ) << item->row();
435 }
436 return path;
437}
438
439QModelIndex QgsAttributesFormModel::index( int row, int column, const QModelIndex &parent ) const
440{
441 if ( !hasIndex( row, column, parent ) )
442 return QModelIndex();
443
445 if ( !parentItem )
446 return QModelIndex();
447
448 if ( QgsAttributesFormItem *childItem = parentItem->child( row ) )
449 return createIndex( row, column, childItem );
450
451 return QModelIndex();
452}
453
454QModelIndex QgsAttributesFormModel::parent( const QModelIndex &index ) const
455{
456 if ( !index.isValid() )
457 return QModelIndex();
458
460 QgsAttributesFormItem *parentItem = childItem ? childItem->parent() : nullptr;
461
462 return ( parentItem != mRootItem.get() && parentItem != nullptr ) ? createIndex( parentItem->row(), 0, parentItem ) : QModelIndex();
463}
464
466{
467 QgsAttributesFormItem *item = mRootItem->firstTopChild( itemType, itemId );
468 return item ? createIndex( item->row(), 0, item ) : QModelIndex();
469}
470
472{
473 QgsAttributesFormItem *item = mRootItem->firstChildRecursive( itemType, itemId );
474 return item ? createIndex( item->row(), 0, item ) : QModelIndex();
475}
476
477bool QgsAttributesFormModel::setData( const QModelIndex &index, const QVariant &value, int role )
478{
479 if ( !index.isValid() )
480 return false;
481
483 bool result = item->setData( role, value );
484
485 if ( result )
486 {
487 emit dataChanged( index, index, { role } );
488
490 {
491 emit fieldConfigDataChanged( item );
492 }
493 }
494
495 return result;
496}
497
499{
500 return mShowAliases;
501}
502
504{
505 mShowAliases = show;
506
507 emitDataChangedRecursively( QModelIndex(), QVector<int>() << Qt::DisplayRole << Qt::ForegroundRole << Qt::FontRole );
508}
509
510void QgsAttributesFormModel::emitDataChangedRecursively( const QModelIndex &parent, const QVector<int> &roles )
511{
512 emit dataChanged( index( 0, 0, parent ), index( rowCount( parent ) - 1, 0, parent ), roles );
513 for ( int i = 0; i < rowCount( parent ); i++ )
514 {
515 const QModelIndex childIndex = index( i, 0, parent );
516 if ( hasChildren( childIndex ) )
517 {
518 emitDataChangedRecursively( childIndex, roles );
519 }
520 }
521}
522
523
527
528Qt::ItemFlags QgsAttributesAvailableWidgetsModel::flags( const QModelIndex &index ) const
529{
530 if ( !index.isValid() )
531 return Qt::NoItemFlags;
532
533 Qt::ItemFlags flags = Qt::ItemIsEnabled;
534
535 const auto indexType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
536 if ( indexType != QgsAttributesFormData::WidgetType )
537 {
538 flags = flags | Qt::ItemIsDragEnabled | Qt::ItemIsSelectable;
539 }
540
541 return flags;
542}
543
544QVariant QgsAttributesAvailableWidgetsModel::headerData( int section, Qt::Orientation orientation, int role ) const
545{
546 Q_UNUSED( section )
547 return orientation == Qt::Horizontal && role == Qt::DisplayRole ? tr( "Available Widgets" ) : QVariant {};
548}
549
551{
552 if ( !mLayer )
553 return;
554
555 beginResetModel();
556 mRootItem->deleteChildren();
557
558 // Load fields
559
560 auto itemFields = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::WidgetType, u"Fields"_s, tr( "Fields" ) );
561
562 const QgsFields fields = mLayer->fields();
563 for ( int i = 0; i < fields.size(); ++i )
564 {
565 const QgsField field = fields.at( i );
567 itemData.setShowLabel( true );
568
570
571 auto item = std::make_unique< QgsAttributesFormItem >();
572 item->setData( ItemFieldConfigRole, cfg );
573 item->setData( ItemNameRole, field.name() );
574 item->setData( ItemIdRole, field.name() ); // Field names act as ids
575 item->setData( ItemDisplayRole, field.alias() );
577 item->setData( ItemDataRole, itemData );
578 item->setIcon( fields.iconForField( i, true ) );
579
580 itemFields->addChild( std::move( item ) );
581 }
582
583 mRootItem->addChild( std::move( itemFields ) );
584
585 // Load relations
586
587 auto itemRelations = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::WidgetType, u"Relations"_s, tr( "Relations" ) );
588
589 const QList<QgsRelation> relations = mProject->relationManager()->referencedRelations( mLayer );
590
591 for ( const QgsRelation &relation : relations )
592 {
593 QString name;
594 const QgsPolymorphicRelation polymorphicRelation = relation.polymorphicRelation();
595 if ( polymorphicRelation.isValid() )
596 {
597 name = u"%1 (%2)"_s.arg( relation.name(), polymorphicRelation.name() );
598 }
599 else
600 {
601 name = relation.name();
602 }
604 itemData.setShowLabel( true );
605
606 auto itemRelation = std::make_unique< QgsAttributesFormItem >();
607 itemRelation->setData( ItemTypeRole, QgsAttributesFormData::Relation );
608 itemRelation->setData( ItemNameRole, name );
609 itemRelation->setData( ItemIdRole, relation.id() );
610 itemRelation->setData( ItemDataRole, itemData );
611 itemRelation->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetRelationEditor.svg"_s ) );
612 itemRelations->addChild( std::move( itemRelation ) );
613 }
614
615 mRootItem->addChild( std::move( itemRelations ) );
616
617 // Load form actions
618
619 auto itemActions = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::WidgetType, u"Actions"_s, tr( "Actions" ) );
620 mRootItem->addChild( std::move( itemActions ) );
621 populateActionItems( mLayer->actions()->actions() );
622
623 // Other widgets
624
625 auto itemOtherWidgets = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::WidgetType, u"Other"_s, tr( "Other Widgets" ) );
626
628 itemData.setShowLabel( true );
629 auto itemQml = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::QmlWidget, itemData, u"QML Widget"_s, tr( "QML Widget" ) );
630 itemQml->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetQml.svg"_s ) );
631 itemOtherWidgets->addChild( std::move( itemQml ) );
632
634 itemHtmlData.setShowLabel( true );
635 auto itemHtml = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::HtmlWidget, itemHtmlData, u"HTML Widget"_s, tr( "HTML Widget" ) );
636 itemHtml->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetHtml.svg"_s ) );
637 itemOtherWidgets->addChild( std::move( itemHtml ) );
638
640 itemTextData.setShowLabel( true );
641 auto itemText = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::TextWidget, itemTextData, u"Text Widget"_s, tr( "Text Widget" ) );
642 itemText->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetText.svg"_s ) );
643 itemOtherWidgets->addChild( std::move( itemText ) );
644
646 itemTextData.setShowLabel( false );
647 auto itemSpacer = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::SpacerWidget, u"Spacer Widget"_s, tr( "Spacer Widget" ) );
648 itemSpacer->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetSpacer.svg"_s ) );
649 itemOtherWidgets->addChild( std::move( itemSpacer ) );
650
651 mRootItem->addChild( std::move( itemOtherWidgets ) );
652
653 endResetModel();
654}
655
656void QgsAttributesAvailableWidgetsModel::populateLayerActions( const QList< QgsAction > actions )
657{
658 QModelIndex actionsIndex = actionContainer();
659 QgsAttributesFormItem *itemActions = itemForIndex( actionsIndex );
660
661 beginRemoveRows( actionsIndex, 0, itemActions->childCount() );
662 itemActions->deleteChildren();
663 endRemoveRows();
664
665 int count = 0;
666 for ( const auto &action : std::as_const( actions ) )
667 {
668 if ( action.isValid() && action.runable() && ( action.actionScopes().contains( u"Feature"_s ) || action.actionScopes().contains( u"Layer"_s ) ) )
669 {
670 count++;
671 }
672 }
673
674 if ( count > 0 )
675 {
676 beginInsertRows( actionsIndex, 0, count - 1 );
677 populateActionItems( actions );
678 endInsertRows();
679 }
680}
681
682void QgsAttributesAvailableWidgetsModel::populateActionItems( const QList<QgsAction> actions )
683{
684 QModelIndex actionsIndex = actionContainer();
685 QgsAttributesFormItem *itemActions = itemForIndex( actionsIndex );
686
687 for ( const auto &action : std::as_const( actions ) )
688 {
689 if ( action.isValid() && action.runable() && ( action.actionScopes().contains( u"Feature"_s ) || action.actionScopes().contains( u"Layer"_s ) ) )
690 {
691 const QString actionTitle { action.shortTitle().isEmpty() ? action.name() : action.shortTitle() };
692
693 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
694 itemData.setShowLabel( true );
695
696 auto itemAction = std::make_unique< QgsAttributesFormItem >();
697 itemAction->setData( ItemIdRole, action.id().toString() );
698 itemAction->setData( ItemTypeRole, QgsAttributesFormData::Action );
699 itemAction->setData( ItemNameRole, actionTitle );
700 itemAction->setData( ItemDataRole, itemData );
701 itemAction->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetAction.svg"_s ) );
702
703 itemActions->addChild( std::move( itemAction ) );
704 }
705 }
706}
707
708QVariant QgsAttributesAvailableWidgetsModel::data( const QModelIndex &index, int role ) const
709{
710 if ( !index.isValid() )
711 return QVariant();
712
714 if ( !item )
715 return QVariant();
716
717 // Relations may be broken due to missing layers or references.
718 // Make those stand out from valid ones.
719 bool invalidRelation = false;
720 if ( ( role == Qt::ToolTipRole || role == Qt::ForegroundRole ) && item->type() == QgsAttributesFormData::Relation )
721 {
722 invalidRelation = !QgsProject::instance()->relationManager()->relation( item->id() ).isValid();
723 }
724
725 switch ( role )
726 {
727 case Qt::DisplayRole:
728 {
729 if ( !showAliases() && item->type() == QgsAttributesFormData::Field )
730 {
731 return item->name();
732 }
733
734 return item->displayName().isEmpty() ? item->name() : item->displayName();
735 }
736
737 case Qt::ToolTipRole:
738 {
740 {
741 const auto cfg = item->data( ItemFieldConfigRole ).value<QgsAttributesFormData::FieldConfig>();
742 if ( !cfg.mAlias.isEmpty() )
743 return tr( "%1 (%2)" ).arg( item->name(), cfg.mAlias );
744 else
745 return item->name();
746 }
747
748 if ( item->type() == QgsAttributesFormData::Relation && invalidRelation )
749 {
750 // Relation name will be displayed, inform users why it's red via tooltip
751 return tr( "Invalid relation" );
752 }
753
754 return QVariant();
755 }
756
757 case Qt::DecorationRole:
758 return item->icon();
759
760 case Qt::BackgroundRole:
761 {
763 return QBrush( QColor( 140, 140, 140, 50 ) );
764
765 return QVariant();
766 }
767
768 case Qt::ForegroundRole:
769 {
770 if ( item->type() == QgsAttributesFormData::Field )
771 {
772 if ( showAliases() && item->displayName().isEmpty() )
773 {
774 return QBrush( QColor( Qt::lightGray ) );
775 }
776 }
777
778 if ( item->type() == QgsAttributesFormData::Relation && invalidRelation )
779 {
780 return QBrush( QColor( 255, 0, 0 ) );
781 }
782
783 return QVariant();
784 }
785
786 case Qt::FontRole:
787 {
788 if ( item->type() == QgsAttributesFormData::Field )
789 {
790 if ( showAliases() && item->displayName().isEmpty() )
791 {
792 QFont font = QFont();
793 font.setItalic( true );
794 return font;
795 }
796 }
797 return QVariant();
798 }
799
800 case ItemDataRole:
802 case ItemNameRole:
803 case ItemTypeRole:
804 case ItemIdRole:
805 case ItemDisplayRole:
806 return item->data( role );
807
808 default:
809 return QVariant();
810 }
811}
812
814{
815 return Qt::CopyAction;
816}
817
819{
820 return QStringList() << u"application/x-qgsattributesformavailablewidgetsrelement"_s;
821}
822
823QMimeData *QgsAttributesAvailableWidgetsModel::mimeData( const QModelIndexList &indexes ) const
824{
825 if ( indexes.count() == 0 )
826 return nullptr;
827
828 const QStringList types = mimeTypes();
829 if ( types.isEmpty() )
830 return nullptr;
831
832 QMimeData *data = new QMimeData();
833 const QString format = types.at( 0 );
834 QByteArray encoded;
835 QDataStream stream( &encoded, QIODevice::WriteOnly );
836
837 // Sort indexes since their order reflects selection order
838 QModelIndexList sortedIndexes = indexes;
839
840 std::sort( sortedIndexes.begin(), sortedIndexes.end(), [this]( const QModelIndex &a, const QModelIndex &b ) { return indexLessThan( a, b ); } );
841
842 for ( const QModelIndex &index : std::as_const( sortedIndexes ) )
843 {
844 if ( index.isValid() )
845 {
846 const QString itemId = index.data( QgsAttributesFormModel::ItemIdRole ).toString();
847 const QString itemName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
848 int itemType = index.data( QgsAttributesFormModel::ItemTypeRole ).toInt();
849
850 stream << itemId << itemType << itemName;
851 }
852 }
853
854 data->setData( format, encoded );
855 return data;
856}
857
859{
860 if ( mRootItem->childCount() > 0 )
861 {
862 const int row = 0;
863 QgsAttributesFormItem *item = mRootItem->child( row );
864 if ( item && item->name() == "Fields"_L1 && item->type() == QgsAttributesFormData::WidgetType )
865 return createIndex( row, 0, item );
866 }
867 return QModelIndex();
868}
869
871{
872 if ( mRootItem->childCount() > 1 )
873 {
874 const int row = 1;
875 QgsAttributesFormItem *item = mRootItem->child( row );
876 if ( item && item->name() == "Relations"_L1 && item->type() == QgsAttributesFormData::WidgetType )
877 return createIndex( row, 0, item );
878 }
879 return QModelIndex();
880}
881
883{
884 if ( mRootItem->childCount() > 2 )
885 {
886 const int row = 2;
887 QgsAttributesFormItem *item = mRootItem->child( row );
888 if ( item && item->name() == "Actions"_L1 && item->type() == QgsAttributesFormData::WidgetType )
889 return createIndex( row, 0, item );
890 }
891 return QModelIndex();
892}
893
894QModelIndex QgsAttributesAvailableWidgetsModel::fieldModelIndex( const QString &fieldName ) const
895{
896 if ( mRootItem->childCount() == 0 )
897 return QModelIndex();
898
899 QgsAttributesFormItem *fieldItems = mRootItem->child( 0 );
900 if ( !fieldItems || fieldItems->name() != "Fields"_L1 || fieldItems->type() != QgsAttributesFormData::WidgetType )
901 return QModelIndex();
902
903 QgsAttributesFormItem *item = fieldItems->firstTopChild( QgsAttributesFormData::Field, fieldName );
904 return item ? createIndex( item->row(), 0, item ) : QModelIndex();
905}
906
907
911
912QVariant QgsAttributesFormLayoutModel::headerData( int section, Qt::Orientation orientation, int role ) const
913{
914 Q_UNUSED( section )
915 return orientation == Qt::Horizontal && role == Qt::DisplayRole ? tr( "Form Layout" ) : QVariant {};
916}
917
918Qt::ItemFlags QgsAttributesFormLayoutModel::flags( const QModelIndex &index ) const
919{
920 if ( !index.isValid() )
921 return Qt::ItemIsDropEnabled;
922
923 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
924
927 flags |= Qt::ItemIsDropEnabled;
928
929 return flags;
930}
931
933{
934 if ( !mLayer )
935 return;
936
937 beginResetModel();
938 mRootItem->deleteChildren();
939
940 const auto editorElements = mLayer->editFormConfig().tabs();
941 for ( QgsAttributeEditorElement *editorElement : editorElements )
942 {
943 loadAttributeEditorElementItem( editorElement, mRootItem.get() );
944 }
945
946 endResetModel();
947}
948
949void QgsAttributesFormLayoutModel::loadAttributeEditorElementItem( QgsAttributeEditorElement *const editorElement, QgsAttributesFormItem *parent, const int position )
950{
951 auto setCommonProperties = [editorElement]( QgsAttributesFormData::AttributeFormItemData &itemData ) {
952 itemData.setShowLabel( editorElement->showLabel() );
953 itemData.setLabelStyle( editorElement->labelStyle() );
954 itemData.setHorizontalStretch( editorElement->horizontalStretch() );
955 itemData.setVerticalStretch( editorElement->verticalStretch() );
956 };
957
958 auto editorItem = std::make_unique< QgsAttributesFormItem >();
959
960 switch ( editorElement->type() )
961 {
963 {
964 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
965 setCommonProperties( itemData );
966
967 editorItem->setData( ItemNameRole, editorElement->name() );
968 editorItem->setData( ItemIdRole, editorElement->name() ); // Field names act as ids
969 editorItem->setData( ItemTypeRole, QgsAttributesFormData::Field );
970 editorItem->setData( ItemDataRole, itemData );
971
972 const int fieldIndex = mLayer->fields().indexOf( editorElement->name() );
973 if ( fieldIndex != -1 )
974 {
975 editorItem->setData( ItemDisplayRole, mLayer->fields().field( fieldIndex ).alias() );
976
977 QgsAttributesFormData::FieldConfig config( mLayer, fieldIndex );
978 editorItem->setData( ItemFieldConfigRole, config );
979 editorItem->setIcon( QgsGui::instance()->editorWidgetRegistry()->icon( config.mEditorWidgetType ) );
980 }
981
982 break;
983 }
984
986 {
987 const QgsAttributeEditorAction *actionEditor = static_cast<const QgsAttributeEditorAction *>( editorElement );
988 const QgsAction action { actionEditor->action( mLayer ) };
989 if ( action.isValid() )
990 {
991 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
992 setCommonProperties( itemData );
993
994 editorItem->setData( ItemIdRole, action.id().toString() );
995 editorItem->setData( ItemNameRole, action.shortTitle().isEmpty() ? action.name() : action.shortTitle() );
996 editorItem->setData( ItemTypeRole, QgsAttributesFormData::Action );
997 editorItem->setData( ItemDataRole, itemData );
998 editorItem->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetAction.svg"_s ) );
999 }
1000 else
1001 {
1002 QgsDebugError( u"Invalid form action"_s );
1003 }
1004 break;
1005 }
1006
1008 {
1009 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1010 setCommonProperties( itemData );
1011
1012 const QgsAttributeEditorRelation *relationEditor = static_cast<const QgsAttributeEditorRelation *>( editorElement );
1013 QgsAttributesFormData::RelationEditorConfiguration relationEditorConfig;
1014 relationEditorConfig.mRelationWidgetType = relationEditor->relationWidgetTypeId();
1015 relationEditorConfig.mRelationWidgetConfig = relationEditor->relationEditorConfiguration();
1016 relationEditorConfig.nmRelationId = relationEditor->nmRelationId();
1017 relationEditorConfig.forceSuppressFormPopup = relationEditor->forceSuppressFormPopup();
1018 relationEditorConfig.label = relationEditor->label();
1019 itemData.setRelationEditorConfiguration( relationEditorConfig );
1020
1021 QgsRelation relation = relationEditor->relation();
1022 if ( relation.id().isEmpty() )
1023 {
1024 // If relation is coming from an internal move, we lose the id.
1025 // Go to relation manager and bring relation properties.
1026 relation = mProject->relationManager()->relation( editorElement->name() );
1027 }
1028
1029 editorItem->setData( ItemIdRole, relation.id() );
1030 editorItem->setData( ItemNameRole, relation.name() );
1031 editorItem->setData( ItemDisplayRole, relationEditorConfig.label );
1032 editorItem->setData( ItemTypeRole, QgsAttributesFormData::Relation );
1033 editorItem->setData( ItemDataRole, itemData );
1034 editorItem->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetRelationEditor.svg"_s ) );
1035
1036 break;
1037 }
1038
1040 {
1041 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1042 setCommonProperties( itemData );
1043
1044 editorItem->setData( ItemNameRole, editorElement->name() );
1045 editorItem->setData( ItemIdRole, editorElement->name() ); // Containers don't have id, use name to make them searchable
1046 editorItem->setData( ItemTypeRole, QgsAttributesFormData::Container );
1047
1048 const QgsAttributeEditorContainer *container = static_cast<const QgsAttributeEditorContainer *>( editorElement );
1049 if ( !container )
1050 break;
1051
1052 itemData.setColumnCount( container->columnCount() );
1053 itemData.setContainerType( container->type() );
1054 itemData.setBackgroundColor( container->backgroundColor() );
1055 itemData.setVisibilityExpression( container->visibilityExpression() );
1056 itemData.setCollapsedExpression( container->collapsedExpression() );
1057 itemData.setCollapsed( container->collapsed() );
1058
1059 editorItem->setData( ItemDataRole, itemData );
1060
1061 const QList<QgsAttributeEditorElement *> children = container->children();
1062 for ( QgsAttributeEditorElement *childElement : children )
1063 {
1064 loadAttributeEditorElementItem( childElement, editorItem.get() );
1065 }
1066 break;
1067 }
1068
1070 {
1071 const QgsAttributeEditorQmlElement *qmlElementEditor = static_cast<const QgsAttributeEditorQmlElement *>( editorElement );
1072 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1073 setCommonProperties( itemData );
1074
1075 QgsAttributesFormData::QmlElementEditorConfiguration qmlEdConfig;
1076 qmlEdConfig.qmlCode = qmlElementEditor->qmlCode();
1077 itemData.setQmlElementEditorConfiguration( qmlEdConfig );
1078
1079 editorItem->setData( ItemNameRole, editorElement->name() );
1080 editorItem->setData( ItemTypeRole, QgsAttributesFormData::QmlWidget );
1081 editorItem->setData( ItemDataRole, itemData );
1082 editorItem->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetQml.svg"_s ) );
1083 break;
1084 }
1085
1087 {
1088 const QgsAttributeEditorHtmlElement *htmlElementEditor = static_cast<const QgsAttributeEditorHtmlElement *>( editorElement );
1089 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1090 setCommonProperties( itemData );
1091
1092 QgsAttributesFormData::HtmlElementEditorConfiguration htmlEdConfig;
1093 htmlEdConfig.htmlCode = htmlElementEditor->htmlCode();
1094 itemData.setHtmlElementEditorConfiguration( htmlEdConfig );
1095
1096 editorItem->setData( ItemNameRole, editorElement->name() );
1097 editorItem->setData( ItemTypeRole, QgsAttributesFormData::HtmlWidget );
1098 editorItem->setData( ItemDataRole, itemData );
1099 editorItem->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetHtml.svg"_s ) );
1100 break;
1101 }
1102
1104 {
1105 const QgsAttributeEditorTextElement *textElementEditor = static_cast<const QgsAttributeEditorTextElement *>( editorElement );
1106 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1107 setCommonProperties( itemData );
1108
1109 QgsAttributesFormData::TextElementEditorConfiguration textEdConfig;
1110 textEdConfig.text = textElementEditor->text();
1111 itemData.setTextElementEditorConfiguration( textEdConfig );
1112
1113 editorItem->setData( ItemNameRole, editorElement->name() );
1114 editorItem->setData( ItemTypeRole, QgsAttributesFormData::TextWidget );
1115 editorItem->setData( ItemDataRole, itemData );
1116 editorItem->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetText.svg"_s ) );
1117 break;
1118 }
1119
1121 {
1122 const QgsAttributeEditorSpacerElement *spacerElementEditor = static_cast<const QgsAttributeEditorSpacerElement *>( editorElement );
1123 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1124 setCommonProperties( itemData );
1125 itemData.setShowLabel( false );
1126
1127 QgsAttributesFormData::SpacerElementEditorConfiguration spacerEdConfig;
1128 spacerEdConfig.drawLine = spacerElementEditor->drawLine();
1129 itemData.setSpacerElementEditorConfiguration( spacerEdConfig );
1130
1131 editorItem->setData( ItemNameRole, editorElement->name() );
1132 editorItem->setData( ItemTypeRole, QgsAttributesFormData::SpacerWidget );
1133 editorItem->setData( ItemDataRole, itemData );
1134 editorItem->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetSpacer.svg"_s ) );
1135 break;
1136 }
1137
1139 {
1140 QgsDebugError( u"Not loading invalid attribute editor type..."_s );
1141 break;
1142 }
1143 }
1144
1145 if ( position >= 0 && position < parent->childCount() )
1146 {
1147 parent->insertChild( position, std::move( editorItem ) );
1148 }
1149 else
1150 {
1151 parent->addChild( std::move( editorItem ) );
1152 }
1153}
1154
1155QVariant QgsAttributesFormLayoutModel::data( const QModelIndex &index, int role ) const
1156{
1157 if ( !index.isValid() )
1158 return QVariant();
1159
1160 if ( role == ItemFieldConfigRole ) // This model doesn't store data for that role
1161 return false;
1162
1164 if ( !item )
1165 return QVariant();
1166
1167 // Fields may be present in the form layout configuration
1168 // even if their corresponding layer fields were deleted.
1169 // Make those stand out from existent ones.
1170 const int fieldIndex = mLayer->fields().indexOf( item->name() );
1171 const bool invalidField = fieldIndex == -1;
1172
1173 // Relations may be broken due to missing layers or references.
1174 // Make those stand out from valid ones.
1175 bool invalidRelation = false;
1176 if ( ( role == Qt::DisplayRole || role == Qt::ToolTipRole || role == Qt::ForegroundRole ) && item->type() == QgsAttributesFormData::Relation )
1177 {
1178 invalidRelation = !QgsProject::instance()->relationManager()->relation( item->id() ).isValid();
1179 }
1180
1181 switch ( role )
1182 {
1183 case Qt::DisplayRole:
1184 {
1185 if ( item->type() == QgsAttributesFormData::Relation && invalidRelation )
1186 {
1187 // Invalid relations can have an id, if that's the case, we have a name.
1188 // Only set a new name if id is missing.
1189 if ( item->id().isEmpty() )
1190 {
1191 return tr( "Invalid relation" );
1192 }
1193 }
1194
1195 if ( !showAliases() && ( item->type() == QgsAttributesFormData::Field || item->type() == QgsAttributesFormData::Relation ) )
1196 {
1197 return item->name();
1198 }
1199
1200 return item->displayName().isEmpty() ? item->name() : item->displayName();
1201 }
1202
1203 case Qt::ToolTipRole:
1204 {
1205 if ( item->type() == QgsAttributesFormData::Field )
1206 {
1207 if ( invalidField )
1208 {
1209 return tr( "Invalid field" );
1210 }
1211 else
1212 {
1213 return item->name();
1214 }
1215 }
1216
1217 if ( item->type() == QgsAttributesFormData::Relation && invalidRelation )
1218 {
1219 if ( !item->id().isEmpty() )
1220 {
1221 // The relation name is shown, let's inform users via tooltip why it's red
1222 return tr( "Invalid relation" );
1223 }
1224 }
1225
1226 return QVariant();
1227 }
1228
1229 case Qt::DecorationRole:
1230 return item->icon();
1231
1232 case Qt::BackgroundRole:
1233 {
1234 if ( item->type() == QgsAttributesFormData::Container )
1235 return QBrush( QColor( 140, 140, 140, 50 ) );
1236
1237 return QVariant();
1238 }
1239
1240 case Qt::ForegroundRole:
1241 {
1242 if ( item->type() == QgsAttributesFormData::Field )
1243 {
1244 if ( invalidField )
1245 {
1246 return QBrush( QColor( 255, 0, 0 ) );
1247 }
1248 else if ( showAliases() && item->displayName().isEmpty() )
1249 {
1250 return QBrush( QColor( Qt::lightGray ) );
1251 }
1252 }
1253
1254 if ( item->type() == QgsAttributesFormData::Relation )
1255 {
1256 if ( invalidRelation )
1257 {
1258 return QBrush( QColor( 255, 0, 0 ) );
1259 }
1260 else if ( showAliases() && item->displayName().isEmpty() )
1261 {
1262 return QBrush( QColor( Qt::lightGray ) );
1263 }
1264 }
1265
1266 return QVariant();
1267 }
1268
1269 case Qt::FontRole:
1270 {
1271 if ( item->type() == QgsAttributesFormData::Field )
1272 {
1273 if ( !invalidField && showAliases() && item->displayName().isEmpty() )
1274 {
1275 QFont font = QFont();
1276 font.setItalic( true );
1277 return font;
1278 }
1279 }
1280
1281 if ( item->type() == QgsAttributesFormData::Relation )
1282 {
1283 if ( !invalidRelation && showAliases() && item->displayName().isEmpty() )
1284 {
1285 QFont font = QFont();
1286 font.setItalic( true );
1287 return font;
1288 }
1289 }
1290
1291 return QVariant();
1292 }
1293
1294 case ItemDataRole:
1295 case ItemNameRole:
1296 case ItemIdRole:
1297 case ItemTypeRole:
1298 case ItemDisplayRole:
1299 return item->data( role );
1300
1301 default:
1302 return QVariant();
1303 }
1304}
1305
1306bool QgsAttributesFormLayoutModel::removeRows( int row, int count, const QModelIndex &parent )
1307{
1308 if ( row < 0 )
1309 return false;
1310
1312
1313 if ( row > item->childCount() - count )
1314 return false;
1315
1316 beginRemoveRows( parent, row, row + count - 1 );
1317 for ( int r = 0; r < count; ++r )
1318 item->deleteChildAtIndex( row );
1319 endRemoveRows();
1320 return true;
1321}
1322
1323bool QgsAttributesFormLayoutModel::removeRow( int row, const QModelIndex &parent )
1324{
1325 beginRemoveRows( parent, row, row );
1327 item->deleteChildAtIndex( row );
1328 endRemoveRows();
1329 return true;
1330}
1331
1333{
1334 return Qt::MoveAction;
1335}
1336
1338{
1339 return Qt::DropAction::CopyAction | Qt::DropAction::MoveAction;
1340}
1341
1343{
1344 return QStringList() << u"application/x-qgsattributesformlayoutelement"_s << u"application/x-qgsattributesformavailablewidgetsrelement"_s;
1345}
1346
1347QModelIndexList QgsAttributesFormLayoutModel::curateIndexesForMimeData( const QModelIndexList &indexes ) const
1348{
1349 QModelIndexList containerList;
1350 for ( const auto index : indexes )
1351 {
1352 const auto indexType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
1353 if ( indexType == QgsAttributesFormData::Container )
1354 {
1355 containerList << index;
1356 }
1357 }
1358
1359 if ( containerList.size() == 0 )
1360 return indexes;
1361
1362 QModelIndexList curatedIndexes;
1363
1364 // Iterate searching if current index is child of any container in containerList (recursively)
1365 for ( const auto index : indexes )
1366 {
1367 QModelIndex parent = index.parent();
1368 bool redundantChild = false;
1369
1370 while ( parent.isValid() )
1371 {
1372 if ( containerList.contains( parent ) )
1373 {
1374 redundantChild = true;
1375 break;
1376 }
1377
1378 parent = parent.parent();
1379 }
1380
1381 if ( !redundantChild )
1382 curatedIndexes << index;
1383 }
1384
1385 return curatedIndexes;
1386}
1387
1388QMimeData *QgsAttributesFormLayoutModel::mimeData( const QModelIndexList &indexes ) const
1389{
1390 if ( indexes.count() == 0 )
1391 return nullptr;
1392
1393 // Discard redundant indexes
1394 QModelIndexList curatedIndexes;
1395 if ( indexes.count() > 1 )
1396 {
1397 curatedIndexes = curateIndexesForMimeData( indexes );
1398 }
1399 else
1400 {
1401 curatedIndexes = indexes;
1402 }
1403
1404 const QStringList types = mimeTypes();
1405 if ( types.isEmpty() )
1406 return nullptr;
1407
1408 QMimeData *data = new QMimeData();
1409 const QString format = types.at( 0 );
1410 QByteArray encoded;
1411 QDataStream stream( &encoded, QIODevice::WriteOnly );
1412
1413 // Sort indexes since their order reflects selection order
1414 std::sort( curatedIndexes.begin(), curatedIndexes.end(), [this]( const QModelIndex &a, const QModelIndex &b ) { return indexLessThan( a, b ); } );
1415
1416 for ( const QModelIndex &index : std::as_const( curatedIndexes ) )
1417 {
1418 if ( index.isValid() )
1419 {
1420 QDomDocument doc;
1421
1422 QDomElement rootElem = doc.createElement( u"form_layout_mime"_s );
1424 QDomElement editorElem = editor->toDomElement( doc );
1425 rootElem.appendChild( editorElem );
1426
1427 doc.appendChild( rootElem );
1428 stream << doc.toString( -1 );
1429 }
1430 }
1431
1432 data->setData( format, encoded );
1433 return data;
1434}
1435
1436bool QgsAttributesFormLayoutModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
1437{
1438 Q_UNUSED( column )
1439 bool isDropSuccessful = false;
1440 int rows = 0;
1441
1442 if ( row == -1 ) // Dropped at invalid index
1443 row = rowCount( parent ); // Let's append the item
1444
1445 if ( action == Qt::IgnoreAction )
1446 {
1447 isDropSuccessful = true;
1448 }
1449 else if ( data->hasFormat( u"application/x-qgsattributesformavailablewidgetsrelement"_s ) )
1450 {
1451 Q_ASSERT( action == Qt::CopyAction ); // External drop
1452 QByteArray itemData = data->data( u"application/x-qgsattributesformavailablewidgetsrelement"_s );
1453 QDataStream stream( &itemData, QIODevice::ReadOnly );
1454
1455 while ( !stream.atEnd() )
1456 {
1457 QString itemId;
1458 int itemTypeInt;
1459 QString itemName;
1460 stream >> itemId >> itemTypeInt >> itemName;
1461
1462 const auto itemType = static_cast< QgsAttributesFormData::AttributesFormItemType >( itemTypeInt );
1463 insertChild( parent, row + rows, itemId, itemType, itemName );
1464
1465 isDropSuccessful = true;
1466
1467 QModelIndex addedIndex = index( row + rows, 0, parent );
1468 emit externalItemDropped( addedIndex );
1469
1470 rows++;
1471 }
1472 }
1473 else if ( data->hasFormat( u"application/x-qgsattributesformlayoutelement"_s ) )
1474 {
1475 Q_ASSERT( action == Qt::MoveAction ); // Internal move
1476 QByteArray itemData = data->data( u"application/x-qgsattributesformlayoutelement"_s );
1477 QDataStream stream( &itemData, QIODevice::ReadOnly );
1478
1479 while ( !stream.atEnd() )
1480 {
1481 QString text;
1482 stream >> text;
1483
1484 QDomDocument doc;
1485 if ( !doc.setContent( text ) )
1486 continue;
1487 const QDomElement rootElem = doc.documentElement();
1488 if ( rootElem.tagName() != "form_layout_mime"_L1 || !rootElem.hasChildNodes() )
1489 continue;
1490 const QDomElement childElem = rootElem.firstChild().toElement();
1491
1492 // Build editor element from XML and add/insert it to parent
1494 beginInsertRows( parent, row + rows, row + rows );
1495 loadAttributeEditorElementItem( editor, itemForIndex( parent ), row + rows );
1496 endInsertRows();
1497
1498 isDropSuccessful = true;
1499
1500 QModelIndex addedIndex = index( row + rows, 0, parent );
1501 emit internalItemDropped( addedIndex );
1502
1503 rows++;
1504 }
1505 }
1506
1507 return isDropSuccessful;
1508}
1509
1510void QgsAttributesFormLayoutModel::updateFieldConfigForFieldItemsRecursive( QgsAttributesFormItem *parent, const QString &fieldName, const QgsAttributesFormData::FieldConfig &config )
1511{
1512 for ( int i = 0; i < parent->childCount(); i++ )
1513 {
1514 QgsAttributesFormItem *child = parent->child( i );
1515 if ( child->name() == fieldName && child->type() == QgsAttributesFormData::Field )
1516 {
1517 child->setData( ItemFieldConfigRole, QVariant::fromValue( config ) );
1518 child->setIcon( QgsGui::instance()->editorWidgetRegistry()->icon( config.mEditorWidgetType ) );
1519 emit fieldConfigDataChanged( child ); // Item's field config has changed, let views know about it
1520 }
1521
1522 if ( child->childCount() > 0 )
1523 {
1524 updateFieldConfigForFieldItemsRecursive( child, fieldName, config );
1525 }
1526 }
1527}
1528
1530{
1531 updateFieldConfigForFieldItemsRecursive( mRootItem.get(), fieldName, config );
1532}
1533
1534void QgsAttributesFormLayoutModel::updateAliasForFieldItemsRecursive( QgsAttributesFormItem *parent, const QString &fieldName, const QString &fieldAlias )
1535{
1536 for ( int i = 0; i < parent->childCount(); i++ )
1537 {
1538 QgsAttributesFormItem *child = parent->child( i );
1539 if ( child->name() == fieldName && child->type() == QgsAttributesFormData::Field )
1540 {
1541 child->setData( ItemDisplayRole, fieldAlias );
1542 const QModelIndex index = createIndex( child->row(), 0, child );
1543 emit dataChanged( index, index ); // Item's alias has changed, let views know about it
1544 }
1545
1546 if ( child->childCount() > 0 )
1547 {
1548 updateAliasForFieldItemsRecursive( child, fieldName, fieldAlias );
1549 }
1550 }
1551}
1552
1553void QgsAttributesFormLayoutModel::updateAliasForFieldItems( const QString &fieldName, const QString &fieldAlias )
1554{
1555 updateAliasForFieldItemsRecursive( mRootItem.get(), fieldName, fieldAlias );
1556}
1557
1558QList< QgsAddAttributeFormContainerDialog::ContainerPair > QgsAttributesFormLayoutModel::recursiveListOfContainers( QgsAttributesFormItem *parent ) const
1559{
1560 QList< QgsAddAttributeFormContainerDialog::ContainerPair > containerList;
1561 for ( int i = 0; i < parent->childCount(); i++ )
1562 {
1563 QgsAttributesFormItem *child = parent->child( i );
1564 if ( child->type() == QgsAttributesFormData::Container )
1565 {
1566 containerList << QgsAddAttributeFormContainerDialog::ContainerPair( child->name(), createIndex( child->row(), 0, child ) );
1567 }
1568
1569 if ( child->childCount() > 0 )
1570 {
1571 containerList.append( recursiveListOfContainers( child ) );
1572 }
1573 }
1574
1575 return containerList;
1576}
1577
1579{
1580 QgsAttributeEditorElement *widgetDef = nullptr;
1581
1583 const int indexType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
1584 const QString indexName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
1585 const QString indexId = index.data( QgsAttributesFormModel::ItemIdRole ).toString();
1586
1587 switch ( indexType )
1588 {
1590 {
1591 const int fieldIndex = mLayer->fields().lookupField( indexName );
1592 widgetDef = new QgsAttributeEditorField( indexName, fieldIndex, parent );
1593 break;
1594 }
1595
1597 {
1598 const QgsAction action { mLayer->actions()->action( indexId ) };
1599 widgetDef = new QgsAttributeEditorAction( action, parent );
1600 break;
1601 }
1602
1604 {
1605 const QgsRelation relation = mProject->relationManager()->relation( indexId );
1606
1609 relDef->setRelationWidgetTypeId( relationEditorConfig.mRelationWidgetType );
1610 relDef->setRelationEditorConfiguration( relationEditorConfig.mRelationWidgetConfig );
1611 relDef->setNmRelationId( relationEditorConfig.nmRelationId );
1612 relDef->setForceSuppressFormPopup( relationEditorConfig.forceSuppressFormPopup );
1613 relDef->setLabel( relationEditorConfig.label );
1614 widgetDef = relDef;
1615 break;
1616 }
1617
1619 {
1620 QgsAttributeEditorContainer *container = new QgsAttributeEditorContainer( indexName, parent, itemData.backgroundColor() );
1621 container->setColumnCount( itemData.columnCount() );
1622 // only top-level containers can be tabs
1624 bool isTopLevel = !index.parent().isValid();
1625 if ( type == Qgis::AttributeEditorContainerType::Tab && !isTopLevel )
1626 {
1627 // a tab container found which isn't at the top level -- reset it to a group box instead
1629 }
1630 container->setType( type );
1631 container->setCollapsed( itemData.collapsed() );
1632 container->setCollapsedExpression( itemData.collapsedExpression() );
1633 container->setVisibilityExpression( itemData.visibilityExpression() );
1634 container->setBackgroundColor( itemData.backgroundColor() );
1635
1636 QModelIndex childIndex;
1637 for ( int t = 0; t < rowCount( index ); t++ )
1638 {
1639 childIndex = this->index( t, 0, index );
1640 QgsAttributeEditorElement *element { createAttributeEditorWidget( childIndex, container ) };
1641 if ( element )
1642 container->addChildElement( element );
1643 }
1644 widgetDef = container;
1645 break;
1646 }
1647
1649 {
1651 element->setQmlCode( itemData.qmlElementEditorConfiguration().qmlCode );
1652 widgetDef = element;
1653 break;
1654 }
1655
1657 {
1660 widgetDef = element;
1661 break;
1662 }
1663
1665 {
1667 element->setText( itemData.textElementEditorConfiguration().text );
1668 widgetDef = element;
1669 break;
1670 }
1671
1673 {
1676 widgetDef = element;
1677 break;
1678 }
1679
1681 default:
1682 break;
1683 }
1684
1685 if ( widgetDef )
1686 {
1687 widgetDef->setShowLabel( itemData.showLabel() );
1688 widgetDef->setLabelStyle( itemData.labelStyle() );
1689 widgetDef->setHorizontalStretch( itemData.horizontalStretch() );
1690 widgetDef->setVerticalStretch( itemData.verticalStretch() );
1691 }
1692
1693 return widgetDef;
1694}
1695
1696QList< QgsAddAttributeFormContainerDialog::ContainerPair > QgsAttributesFormLayoutModel::listOfContainers() const
1697{
1698 return recursiveListOfContainers( mRootItem.get() );
1699}
1700
1702{
1703 beginInsertRows( parent, rowCount( parent ), rowCount( parent ) );
1704
1705 QgsAttributesFormItem *parentItem = itemForIndex( parent );
1706
1707 auto containerItem = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::Container, name, QString(), parentItem );
1708
1710 itemData.setColumnCount( columnCount );
1712
1713 containerItem->setData( QgsAttributesFormModel::ItemDataRole, itemData );
1714 containerItem->setData( QgsAttributesFormModel::ItemIdRole, name ); // Make it searchable
1715 parentItem->addChild( std::move( containerItem ) );
1716
1717 endInsertRows();
1718}
1719
1720void QgsAttributesFormLayoutModel::insertChild( const QModelIndex &parent, int row, const QString &itemId, QgsAttributesFormData::AttributesFormItemType itemType, const QString &itemName )
1721{
1722 if ( row < 0 )
1723 return;
1724
1725 beginInsertRows( parent, row, row );
1726 auto item = std::make_unique< QgsAttributesFormItem >();
1727
1728 item->setData( QgsAttributesFormModel::ItemIdRole, itemId );
1729 item->setData( QgsAttributesFormModel::ItemTypeRole, itemType );
1730 item->setData( QgsAttributesFormModel::ItemNameRole, itemName );
1731
1732 itemForIndex( parent )->insertChild( row, std::move( item ) );
1733 endInsertRows();
1734}
1735
1736
1738 : QSortFilterProxyModel( parent )
1739{}
1740
1742{
1743 mModel = model;
1744 QSortFilterProxyModel::setSourceModel( mModel );
1745}
1746
1751
1753{
1754 return mFilterText;
1755}
1756
1758{
1759 // Since we want to allow refreshing the filter when, e.g.,
1760 // users switch to aliases, then we allow this method to be
1761 // executed even if previous and new filters are equal
1762
1763 mFilterText = filterText.trimmed();
1764 invalidate();
1765}
1766
1767bool QgsAttributesFormProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
1768{
1769 if ( mFilterText.isEmpty() )
1770 return true;
1771
1772 QModelIndex sourceIndex = sourceModel()->index( sourceRow, 0, sourceParent );
1773 if ( !sourceIndex.isValid() )
1774 return false;
1775
1776 // If name or alias match, accept it before any other checks
1777 if ( sourceIndex.data( QgsAttributesFormModel::ItemNameRole ).toString().contains( mFilterText, Qt::CaseInsensitive )
1778 || sourceIndex.data( QgsAttributesFormModel::ItemDisplayRole ).toString().contains( mFilterText, Qt::CaseInsensitive ) )
1779 return true;
1780
1781 // Child is accepted if any of its parents is accepted
1782 QModelIndex parent = sourceIndex.parent();
1783 while ( parent.isValid() )
1784 {
1785 if ( parent.data( QgsAttributesFormModel::ItemNameRole ).toString().contains( mFilterText, Qt::CaseInsensitive )
1786 || parent.data( QgsAttributesFormModel::ItemDisplayRole ).toString().contains( mFilterText, Qt::CaseInsensitive ) )
1787 return true;
1788
1789 parent = parent.parent();
1790 }
1791
1792 return false;
1793}
AttributeEditorContainerType
Attribute editor container types.
Definition qgis.h:5826
@ Action
A layer action element.
Definition qgis.h:5813
@ Container
A container.
Definition qgis.h:5808
@ QmlElement
A QML element.
Definition qgis.h:5811
@ Relation
A relation.
Definition qgis.h:5810
@ HtmlElement
A HTML element.
Definition qgis.h:5812
@ TextElement
A text element.
Definition qgis.h:5814
@ SpacerElement
A spacer element.
Definition qgis.h:5815
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:136
bool isValid() const
Returns true if this action was a default constructed one.
Definition qgsaction.h:151
QString shortTitle() const
The short title is used to label user interface elements like buttons.
Definition qgsaction.h:139
QUuid id() const
Returns a unique id for this action.
Definition qgsaction.h:145
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:754
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:764
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:774
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:113
QgsRelationManager * relationManager
Definition qgsproject.h:124
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