QGIS API Documentation 3.99.0-Master (26c88405ac0)
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
33#include "moc_qgsattributesformmodel.cpp"
34
36{
37 if ( !layer || idx < 0 || idx >= layer->fields().count() )
38 return;
39
40 mAlias = layer->fields().at( idx ).alias();
42 mComment = layer->fields().at( idx ).comment();
43 mEditable = !layer->editFormConfig().readOnly( idx );
44 mLabelOnTop = layer->editFormConfig().labelOnTop( idx );
46 mFieldConstraints = layer->fields().at( idx ).constraints();
47 const QgsEditorWidgetSetup setup = QgsGui::editorWidgetRegistry()->findBest( layer, layer->fields().field( idx ).name() );
48 mEditorWidgetType = setup.type();
50 mSplitPolicy = layer->fields().at( idx ).splitPolicy();
51 mDuplicatePolicy = layer->fields().at( idx ).duplicatePolicy();
52 mMergePolicy = layer->fields().at( idx ).mergePolicy();
55}
56
57QgsAttributesFormData::FieldConfig::operator QVariant()
58{
59 return QVariant::fromValue<QgsAttributesFormData::FieldConfig>( *this );
60}
61
62QgsAttributesFormData::RelationEditorConfiguration::operator QVariant()
63{
64 return QVariant::fromValue<QgsAttributesFormData::RelationEditorConfiguration>( *this );
65}
66
71
76
81
86
88{
89 return mShowLabel;
90}
91
96
101
106
111
116
121
126
131
136
137
142
147
152
157
159{
160 return mBackgroundColor;
161}
162
167
172
177
178
180 : mName( name )
181 , mDisplayName( displayName )
182 , mType( itemType )
183 , mParent( parent )
184{}
185
187 : mName( name )
188 , mDisplayName( displayName )
189 , mType( itemType )
190 , mData( data )
191 , mParent( parent )
192{}
193
195{
196 if ( !mChildren.empty() && row >= 0 && row < childCount() )
197 return mChildren.at( row ).get();
198
199 return nullptr;
200}
201
203{
204 if ( !mChildren.empty() && itemId.trimmed().isEmpty() )
205 return nullptr;
206
207 // Search for first matching item by name
208 const auto it = std::find_if( mChildren.cbegin(), mChildren.cend(), [itemType, itemId]( const std::unique_ptr< QgsAttributesFormItem > &item ) {
209 return item->type() == itemType && item->id() == itemId;
210 } );
211
212 if ( it != mChildren.cend() )
213 return it->get();
214
215 return nullptr;
216}
217
219{
220 if ( !mChildren.empty() && itemId.trimmed().isEmpty() )
221 return nullptr;
222
223 for ( const auto &child : std::as_const( mChildren ) )
224 {
225 if ( child->type() == itemType && child->id() == itemId )
226 return child.get();
227
228 if ( child->childCount() > 0 )
229 {
230 QgsAttributesFormItem *item = child->firstChildRecursive( itemType, itemId );
231 if ( item )
232 return item;
233 }
234 }
235
236 return nullptr;
237}
238
240{
241 return static_cast< int >( mChildren.size() );
242}
243
245{
246 if ( !mParent )
247 return 0;
248
249 const auto it = std::find_if( mParent->mChildren.cbegin(), mParent->mChildren.cend(), [this]( const std::unique_ptr< QgsAttributesFormItem > &item ) {
250 return item.get() == this;
251 } );
252
253 if ( it != mParent->mChildren.cend() )
254 {
255 return static_cast< int >( std::distance( mParent->mChildren.cbegin(), it ) );
256 }
257
258 return -1;
259}
260
261void QgsAttributesFormItem::addChild( std::unique_ptr< QgsAttributesFormItem > &&item )
262{
263 if ( !item )
264 return;
265
266 if ( !item->mParent )
267 item->mParent = this;
268
269 // forward the signal towards the root
271
272 mChildren.push_back( std::move( item ) );
273
274 emit addedChildren( this, mChildren.size() - 1, mChildren.size() - 1 );
275}
276
277void QgsAttributesFormItem::insertChild( int position, std::unique_ptr< QgsAttributesFormItem > &&item )
278{
279 if ( position < 0 || position > static_cast< int >( mChildren.size() ) || !item )
280 return;
281
282 if ( !item->mParent )
283 item->mParent = this;
284
285 // forward the signal towards the root
287
288 mChildren.insert( mChildren.begin() + position, std::move( item ) );
289
290 emit addedChildren( this, position, position );
291}
292
294{
295 if ( index >= 0 && index < static_cast< int >( mChildren.size() ) )
296 mChildren.erase( mChildren.begin() + index );
297}
298
300{
301 mChildren.clear();
302}
303
308
309QVariant QgsAttributesFormItem::data( int role ) const
310{
311 switch ( role )
312 {
314 return mType;
316 return QVariant::fromValue( mData );
318 return mName;
320 return mId;
322 return mDisplayName;
324 return QVariant::fromValue( mFieldConfigData );
325 default:
326 return QVariant();
327 }
328}
329
330bool QgsAttributesFormItem::setData( int role, const QVariant &value )
331{
332 switch ( role )
333 {
335 {
336 mData = value.value< QgsAttributesFormData::AttributeFormItemData >();
337 return true;
338 }
340 {
341 mName = value.toString();
342 return true;
343 }
345 {
346 mDisplayName = value.toString();
347 return true;
348 }
350 {
351 mType = static_cast<QgsAttributesFormData::AttributesFormItemType>( value.toInt() );
352 return true;
353 }
355 {
356 mId = value.toString();
357 return true;
358 }
360 {
361 mFieldConfigData = value.value< QgsAttributesFormData::FieldConfig >();
362 return true;
363 }
364 default:
365 return false;
366 }
367}
368
369
371 : QAbstractItemModel( parent )
372 , mRootItem( std::make_unique< QgsAttributesFormItem >() )
373 , mLayer( layer )
374 , mProject( project )
375{
376}
377
379
381{
382 if ( index.isValid() )
383 {
384 if ( auto *item = static_cast<QgsAttributesFormItem *>( index.internalPointer() ) )
385 return item;
386 }
387 return mRootItem.get();
388}
389
394
395
396int QgsAttributesFormModel::rowCount( const QModelIndex &parent ) const
397{
398 if ( parent.isValid() && parent.column() > 0 )
399 return 0;
400
401 const QgsAttributesFormItem *parentItem = itemForIndex( parent );
402
403 return parentItem ? parentItem->childCount() : 0;
404}
405
406int QgsAttributesFormModel::columnCount( const QModelIndex & ) const
407{
408 return 1;
409}
410
411bool QgsAttributesFormModel::indexLessThan( const QModelIndex &a, const QModelIndex &b ) const
412{
413 const QVector<int> pathA = rootToLeafPath( itemForIndex( a ) );
414 const QVector<int> pathB = rootToLeafPath( itemForIndex( b ) );
415
416 for ( int i = 0; i < std::min( pathA.size(), pathB.size() ); i++ )
417 {
418 if ( pathA.at( i ) != pathB.at( i ) )
419 {
420 return pathA.at( i ) < pathB.at( i );
421 }
422 }
423
424 return pathA.size() < pathB.size();
425}
426
428{
429 QVector<int> path;
430 if ( item != mRootItem.get() )
431 {
432 path << rootToLeafPath( item->parent() ) << item->row();
433 }
434 return path;
435}
436
437QModelIndex QgsAttributesFormModel::index( int row, int column, const QModelIndex &parent ) const
438{
439 if ( !hasIndex( row, column, parent ) )
440 return QModelIndex();
441
443 if ( !parentItem )
444 return QModelIndex();
445
446 if ( QgsAttributesFormItem *childItem = parentItem->child( row ) )
447 return createIndex( row, column, childItem );
448
449 return QModelIndex();
450}
451
452QModelIndex QgsAttributesFormModel::parent( const QModelIndex &index ) const
453{
454 if ( !index.isValid() )
455 return QModelIndex();
456
458 QgsAttributesFormItem *parentItem = childItem ? childItem->parent() : nullptr;
459
460 return ( parentItem != mRootItem.get() && parentItem != nullptr )
461 ? createIndex( parentItem->row(), 0, parentItem )
462 : 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
528
529Qt::ItemFlags QgsAttributesAvailableWidgetsModel::flags( const QModelIndex &index ) const
530{
531 if ( !index.isValid() )
532 return Qt::NoItemFlags;
533
534 Qt::ItemFlags flags = Qt::ItemIsEnabled;
535
536 const auto indexType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
537 if ( indexType != QgsAttributesFormData::WidgetType )
538 {
539 flags = flags | Qt::ItemIsDragEnabled | Qt::ItemIsSelectable;
540 }
541
542 return flags;
543}
544
545QVariant QgsAttributesAvailableWidgetsModel::headerData( int section, Qt::Orientation orientation, int role ) const
546{
547 Q_UNUSED( section )
548 return orientation == Qt::Horizontal && role == Qt::DisplayRole ? tr( "Available Widgets" ) : QVariant {};
549}
550
552{
553 if ( !mLayer )
554 return;
555
556 beginResetModel();
557 mRootItem->deleteChildren();
558
559 // Load fields
560
561 auto itemFields = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::WidgetType, QStringLiteral( "Fields" ), tr( "Fields" ) );
562
563 const QgsFields fields = mLayer->fields();
564 for ( int i = 0; i < fields.size(); ++i )
565 {
566 const QgsField field = fields.at( i );
568 itemData.setShowLabel( true );
569
571
572 auto item = std::make_unique< QgsAttributesFormItem >();
573 item->setData( ItemFieldConfigRole, cfg );
574 item->setData( ItemNameRole, field.name() );
575 item->setData( ItemIdRole, field.name() ); // Field names act as ids
576 item->setData( ItemDisplayRole, field.alias() );
578 item->setData( ItemDataRole, itemData );
579 item->setIcon( fields.iconForField( i, true ) );
580
581 itemFields->addChild( std::move( item ) );
582 }
583
584 mRootItem->addChild( std::move( itemFields ) );
585
586 // Load relations
587
588 auto itemRelations = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::WidgetType, QStringLiteral( "Relations" ), tr( "Relations" ) );
589
590 const QList<QgsRelation> relations = mProject->relationManager()->referencedRelations( mLayer );
591
592 for ( const QgsRelation &relation : relations )
593 {
594 QString name;
595 const QgsPolymorphicRelation polymorphicRelation = relation.polymorphicRelation();
596 if ( polymorphicRelation.isValid() )
597 {
598 name = QStringLiteral( "%1 (%2)" ).arg( relation.name(), polymorphicRelation.name() );
599 }
600 else
601 {
602 name = relation.name();
603 }
605 itemData.setShowLabel( true );
606
607 auto itemRelation = std::make_unique< QgsAttributesFormItem >();
608 itemRelation->setData( ItemTypeRole, QgsAttributesFormData::Relation );
609 itemRelation->setData( ItemNameRole, name );
610 itemRelation->setData( ItemIdRole, relation.id() );
611 itemRelation->setData( ItemDataRole, itemData );
612 itemRelation->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mEditorWidgetRelationEditor.svg" ) ) );
613 itemRelations->addChild( std::move( itemRelation ) );
614 }
615
616 mRootItem->addChild( std::move( itemRelations ) );
617
618 // Load form actions
619
620 auto itemActions = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::WidgetType, QStringLiteral( "Actions" ), tr( "Actions" ) );
621 mRootItem->addChild( std::move( itemActions ) );
622 populateActionItems( mLayer->actions()->actions() );
623
624 // Other widgets
625
626 auto itemOtherWidgets = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::WidgetType, QStringLiteral( "Other" ), tr( "Other Widgets" ) );
627
629 itemData.setShowLabel( true );
630 auto itemQml = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::QmlWidget, itemData, QStringLiteral( "QML Widget" ), tr( "QML Widget" ) );
631 itemQml->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mEditorWidgetQml.svg" ) ) );
632 itemOtherWidgets->addChild( std::move( itemQml ) );
633
635 itemHtmlData.setShowLabel( true );
636 auto itemHtml = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::HtmlWidget, itemHtmlData, QStringLiteral( "HTML Widget" ), tr( "HTML Widget" ) );
637 itemHtml->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mEditorWidgetHtml.svg" ) ) );
638 itemOtherWidgets->addChild( std::move( itemHtml ) );
639
641 itemTextData.setShowLabel( true );
642 auto itemText = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::TextWidget, itemTextData, QStringLiteral( "Text Widget" ), tr( "Text Widget" ) );
643 itemText->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mEditorWidgetText.svg" ) ) );
644 itemOtherWidgets->addChild( std::move( itemText ) );
645
647 itemTextData.setShowLabel( false );
648 auto itemSpacer = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::SpacerWidget, QStringLiteral( "Spacer Widget" ), tr( "Spacer Widget" ) );
649 itemSpacer->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mEditorWidgetSpacer.svg" ) ) );
650 itemOtherWidgets->addChild( std::move( itemSpacer ) );
651
652 mRootItem->addChild( std::move( itemOtherWidgets ) );
653
654 endResetModel();
655}
656
657void QgsAttributesAvailableWidgetsModel::populateLayerActions( const QList< QgsAction > actions )
658{
659 QModelIndex actionsIndex = actionContainer();
660 QgsAttributesFormItem *itemActions = itemForIndex( actionsIndex );
661
662 beginRemoveRows( actionsIndex, 0, itemActions->childCount() );
663 itemActions->deleteChildren();
664 endRemoveRows();
665
666 int count = 0;
667 for ( const auto &action : std::as_const( actions ) )
668 {
669 if ( action.isValid() && action.runable() && ( action.actionScopes().contains( QStringLiteral( "Feature" ) ) || action.actionScopes().contains( QStringLiteral( "Layer" ) ) ) )
670 {
671 count++;
672 }
673 }
674
675 if ( count > 0 )
676 {
677 beginInsertRows( actionsIndex, 0, count - 1 );
678 populateActionItems( actions );
679 endInsertRows();
680 }
681}
682
683void QgsAttributesAvailableWidgetsModel::populateActionItems( const QList<QgsAction> actions )
684{
685 QModelIndex actionsIndex = actionContainer();
686 QgsAttributesFormItem *itemActions = itemForIndex( actionsIndex );
687
688 for ( const auto &action : std::as_const( actions ) )
689 {
690 if ( action.isValid() && action.runable() && ( action.actionScopes().contains( QStringLiteral( "Feature" ) ) || action.actionScopes().contains( QStringLiteral( "Layer" ) ) ) )
691 {
692 const QString actionTitle { action.shortTitle().isEmpty() ? action.name() : action.shortTitle() };
693
694 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
695 itemData.setShowLabel( true );
696
697 auto itemAction = std::make_unique< QgsAttributesFormItem >();
698 itemAction->setData( ItemIdRole, action.id().toString() );
699 itemAction->setData( ItemTypeRole, QgsAttributesFormData::Action );
700 itemAction->setData( ItemNameRole, actionTitle );
701 itemAction->setData( ItemDataRole, itemData );
702 itemAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mEditorWidgetAction.svg" ) ) );
703
704 itemActions->addChild( std::move( itemAction ) );
705 }
706 }
707}
708
709QVariant QgsAttributesAvailableWidgetsModel::data( const QModelIndex &index, int role ) const
710{
711 if ( !index.isValid() )
712 return QVariant();
713
715 if ( !item )
716 return QVariant();
717
718 // Relations may be broken due to missing layers or references.
719 // Make those stand out from valid ones.
720 bool invalidRelation = false;
721 if ( ( role == Qt::ToolTipRole || role == Qt::ForegroundRole ) && item->type() == QgsAttributesFormData::Relation )
722 {
723 invalidRelation = !QgsProject::instance()->relationManager()->relation( item->id() ).isValid();
724 }
725
726 switch ( role )
727 {
728 case Qt::DisplayRole:
729 {
730 if ( !showAliases() && item->type() == QgsAttributesFormData::Field )
731 {
732 return item->name();
733 }
734
735 return item->displayName().isEmpty() ? item->name() : item->displayName();
736 }
737
738 case Qt::ToolTipRole:
739 {
741 {
742 const auto cfg = item->data( ItemFieldConfigRole ).value<QgsAttributesFormData::FieldConfig>();
743 if ( !cfg.mAlias.isEmpty() )
744 return tr( "%1 (%2)" ).arg( item->name(), cfg.mAlias );
745 else
746 return item->name();
747 }
748
749 if ( item->type() == QgsAttributesFormData::Relation && invalidRelation )
750 {
751 // Relation name will be displayed, inform users why it's red via tooltip
752 return tr( "Invalid relation" );
753 }
754
755 return QVariant();
756 }
757
758 case Qt::DecorationRole:
759 return item->icon();
760
761 case Qt::BackgroundRole:
762 {
764 return QBrush( QColor( 140, 140, 140, 50 ) );
765
766 return QVariant();
767 }
768
769 case Qt::ForegroundRole:
770 {
771 if ( item->type() == QgsAttributesFormData::Field )
772 {
773 if ( showAliases() && item->displayName().isEmpty() )
774 {
775 return QBrush( QColor( Qt::lightGray ) );
776 }
777 }
778
779 if ( item->type() == QgsAttributesFormData::Relation && invalidRelation )
780 {
781 return QBrush( QColor( 255, 0, 0 ) );
782 }
783
784 return QVariant();
785 }
786
787 case Qt::FontRole:
788 {
789 if ( item->type() == QgsAttributesFormData::Field )
790 {
791 if ( showAliases() && item->displayName().isEmpty() )
792 {
793 QFont font = QFont();
794 font.setItalic( true );
795 return font;
796 }
797 }
798 return QVariant();
799 }
800
801 case ItemDataRole:
803 case ItemNameRole:
804 case ItemTypeRole:
805 case ItemIdRole:
806 case ItemDisplayRole:
807 return item->data( role );
808
809 default:
810 return QVariant();
811 }
812}
813
815{
816 return Qt::CopyAction;
817}
818
820{
821 return QStringList() << QStringLiteral( "application/x-qgsattributesformavailablewidgetsrelement" );
822}
823
824QMimeData *QgsAttributesAvailableWidgetsModel::mimeData( const QModelIndexList &indexes ) const
825{
826 if ( indexes.count() == 0 )
827 return nullptr;
828
829 const QStringList types = mimeTypes();
830 if ( types.isEmpty() )
831 return nullptr;
832
833 QMimeData *data = new QMimeData();
834 const QString format = types.at( 0 );
835 QByteArray encoded;
836 QDataStream stream( &encoded, QIODevice::WriteOnly );
837
838 // Sort indexes since their order reflects selection order
839 QModelIndexList sortedIndexes = indexes;
840
841 std::sort( sortedIndexes.begin(), sortedIndexes.end(), [this]( const QModelIndex &a, const QModelIndex &b ) {
842 return indexLessThan( a, b );
843 } );
844
845 for ( const QModelIndex &index : std::as_const( sortedIndexes ) )
846 {
847 if ( index.isValid() )
848 {
849 const QString itemId = index.data( QgsAttributesFormModel::ItemIdRole ).toString();
850 const QString itemName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
851 int itemType = index.data( QgsAttributesFormModel::ItemTypeRole ).toInt();
852
853 stream << itemId << itemType << itemName;
854 }
855 }
856
857 data->setData( format, encoded );
858 return data;
859}
860
862{
863 if ( mRootItem->childCount() > 0 )
864 {
865 const int row = 0;
866 QgsAttributesFormItem *item = mRootItem->child( row );
867 if ( item && item->name() == QLatin1String( "Fields" ) && item->type() == QgsAttributesFormData::WidgetType )
868 return createIndex( row, 0, item );
869 }
870 return QModelIndex();
871}
872
874{
875 if ( mRootItem->childCount() > 1 )
876 {
877 const int row = 1;
878 QgsAttributesFormItem *item = mRootItem->child( row );
879 if ( item && item->name() == QLatin1String( "Relations" ) && item->type() == QgsAttributesFormData::WidgetType )
880 return createIndex( row, 0, item );
881 }
882 return QModelIndex();
883}
884
886{
887 if ( mRootItem->childCount() > 2 )
888 {
889 const int row = 2;
890 QgsAttributesFormItem *item = mRootItem->child( row );
891 if ( item && item->name() == QLatin1String( "Actions" ) && item->type() == QgsAttributesFormData::WidgetType )
892 return createIndex( row, 0, item );
893 }
894 return QModelIndex();
895}
896
897QModelIndex QgsAttributesAvailableWidgetsModel::fieldModelIndex( const QString &fieldName ) const
898{
899 if ( mRootItem->childCount() == 0 )
900 return QModelIndex();
901
902 QgsAttributesFormItem *fieldItems = mRootItem->child( 0 );
903 if ( !fieldItems || fieldItems->name() != QLatin1String( "Fields" ) || fieldItems->type() != QgsAttributesFormData::WidgetType )
904 return QModelIndex();
905
906 QgsAttributesFormItem *item = fieldItems->firstTopChild( QgsAttributesFormData::Field, fieldName );
907 return item ? createIndex( item->row(), 0, item ) : QModelIndex();
908}
909
910
915
916QVariant QgsAttributesFormLayoutModel::headerData( int section, Qt::Orientation orientation, int role ) const
917{
918 Q_UNUSED( section )
919 return orientation == Qt::Horizontal && role == Qt::DisplayRole ? tr( "Form Layout" ) : QVariant {};
920}
921
922Qt::ItemFlags QgsAttributesFormLayoutModel::flags( const QModelIndex &index ) const
923{
924 if ( !index.isValid() )
925 return Qt::ItemIsDropEnabled;
926
927 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
928
931 flags |= Qt::ItemIsDropEnabled;
932
933 return flags;
934}
935
937{
938 if ( !mLayer )
939 return;
940
941 beginResetModel();
942 mRootItem->deleteChildren();
943
944 const auto editorElements = mLayer->editFormConfig().tabs();
945 for ( QgsAttributeEditorElement *editorElement : editorElements )
946 {
947 loadAttributeEditorElementItem( editorElement, mRootItem.get() );
948 }
949
950 endResetModel();
951}
952
953void QgsAttributesFormLayoutModel::loadAttributeEditorElementItem( QgsAttributeEditorElement *const editorElement, QgsAttributesFormItem *parent, const int position )
954{
955 auto setCommonProperties = [editorElement]( QgsAttributesFormData::AttributeFormItemData &itemData ) {
956 itemData.setShowLabel( editorElement->showLabel() );
957 itemData.setLabelStyle( editorElement->labelStyle() );
958 itemData.setHorizontalStretch( editorElement->horizontalStretch() );
959 itemData.setVerticalStretch( editorElement->verticalStretch() );
960 };
961
962 auto editorItem = std::make_unique< QgsAttributesFormItem >();
963
964 switch ( editorElement->type() )
965 {
967 {
968 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
969 setCommonProperties( itemData );
970
971 editorItem->setData( ItemNameRole, editorElement->name() );
972 editorItem->setData( ItemIdRole, editorElement->name() ); // Field names act as ids
973 editorItem->setData( ItemTypeRole, QgsAttributesFormData::Field );
974 editorItem->setData( ItemDataRole, itemData );
975
976 const int fieldIndex = mLayer->fields().indexOf( editorElement->name() );
977 if ( fieldIndex != -1 )
978 {
979 editorItem->setData( ItemDisplayRole, mLayer->fields().field( fieldIndex ).alias() );
980
981 QgsAttributesFormData::FieldConfig config( mLayer, fieldIndex );
982 editorItem->setData( ItemFieldConfigRole, config );
983 editorItem->setIcon( QgsGui::instance()->editorWidgetRegistry()->icon( config.mEditorWidgetType ) );
984 }
985
986 break;
987 }
988
990 {
991 const QgsAttributeEditorAction *actionEditor = static_cast<const QgsAttributeEditorAction *>( editorElement );
992 const QgsAction action { actionEditor->action( mLayer ) };
993 if ( action.isValid() )
994 {
995 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
996 setCommonProperties( itemData );
997
998 editorItem->setData( ItemIdRole, action.id().toString() );
999 editorItem->setData( ItemNameRole, action.shortTitle().isEmpty() ? action.name() : action.shortTitle() );
1000 editorItem->setData( ItemTypeRole, QgsAttributesFormData::Action );
1001 editorItem->setData( ItemDataRole, itemData );
1002 editorItem->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mEditorWidgetAction.svg" ) ) );
1003 }
1004 else
1005 {
1006 QgsDebugError( QStringLiteral( "Invalid form action" ) );
1007 }
1008 break;
1009 }
1010
1012 {
1013 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1014 setCommonProperties( itemData );
1015
1016 const QgsAttributeEditorRelation *relationEditor = static_cast<const QgsAttributeEditorRelation *>( editorElement );
1017 QgsAttributesFormData::RelationEditorConfiguration relationEditorConfig;
1018 relationEditorConfig.mRelationWidgetType = relationEditor->relationWidgetTypeId();
1019 relationEditorConfig.mRelationWidgetConfig = relationEditor->relationEditorConfiguration();
1020 relationEditorConfig.nmRelationId = relationEditor->nmRelationId();
1021 relationEditorConfig.forceSuppressFormPopup = relationEditor->forceSuppressFormPopup();
1022 relationEditorConfig.label = relationEditor->label();
1023 itemData.setRelationEditorConfiguration( relationEditorConfig );
1024
1025 QgsRelation relation = relationEditor->relation();
1026 if ( relation.id().isEmpty() )
1027 {
1028 // If relation is coming from an internal move, we lose the id.
1029 // Go to relation manager and bring relation properties.
1030 relation = mProject->relationManager()->relation( editorElement->name() );
1031 }
1032
1033 editorItem->setData( ItemIdRole, relation.id() );
1034 editorItem->setData( ItemNameRole, relation.name() );
1035 editorItem->setData( ItemDisplayRole, relationEditorConfig.label );
1036 editorItem->setData( ItemTypeRole, QgsAttributesFormData::Relation );
1037 editorItem->setData( ItemDataRole, itemData );
1038 editorItem->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mEditorWidgetRelationEditor.svg" ) ) );
1039
1040 break;
1041 }
1042
1044 {
1045 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1046 setCommonProperties( itemData );
1047
1048 editorItem->setData( ItemNameRole, editorElement->name() );
1049 editorItem->setData( ItemIdRole, editorElement->name() ); // Containers don't have id, use name to make them searchable
1050 editorItem->setData( ItemTypeRole, QgsAttributesFormData::Container );
1051
1052 const QgsAttributeEditorContainer *container = static_cast<const QgsAttributeEditorContainer *>( editorElement );
1053 if ( !container )
1054 break;
1055
1056 itemData.setColumnCount( container->columnCount() );
1057 itemData.setContainerType( container->type() );
1058 itemData.setBackgroundColor( container->backgroundColor() );
1059 itemData.setVisibilityExpression( container->visibilityExpression() );
1060 itemData.setCollapsedExpression( container->collapsedExpression() );
1061 itemData.setCollapsed( container->collapsed() );
1062
1063 editorItem->setData( ItemDataRole, itemData );
1064
1065 const QList<QgsAttributeEditorElement *> children = container->children();
1066 for ( QgsAttributeEditorElement *childElement : children )
1067 {
1068 loadAttributeEditorElementItem( childElement, editorItem.get() );
1069 }
1070 break;
1071 }
1072
1074 {
1075 const QgsAttributeEditorQmlElement *qmlElementEditor = static_cast<const QgsAttributeEditorQmlElement *>( editorElement );
1076 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1077 setCommonProperties( itemData );
1078
1079 QgsAttributesFormData::QmlElementEditorConfiguration qmlEdConfig;
1080 qmlEdConfig.qmlCode = qmlElementEditor->qmlCode();
1081 itemData.setQmlElementEditorConfiguration( qmlEdConfig );
1082
1083 editorItem->setData( ItemNameRole, editorElement->name() );
1084 editorItem->setData( ItemTypeRole, QgsAttributesFormData::QmlWidget );
1085 editorItem->setData( ItemDataRole, itemData );
1086 editorItem->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mEditorWidgetQml.svg" ) ) );
1087 break;
1088 }
1089
1091 {
1092 const QgsAttributeEditorHtmlElement *htmlElementEditor = static_cast<const QgsAttributeEditorHtmlElement *>( editorElement );
1093 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1094 setCommonProperties( itemData );
1095
1096 QgsAttributesFormData::HtmlElementEditorConfiguration htmlEdConfig;
1097 htmlEdConfig.htmlCode = htmlElementEditor->htmlCode();
1098 itemData.setHtmlElementEditorConfiguration( htmlEdConfig );
1099
1100 editorItem->setData( ItemNameRole, editorElement->name() );
1101 editorItem->setData( ItemTypeRole, QgsAttributesFormData::HtmlWidget );
1102 editorItem->setData( ItemDataRole, itemData );
1103 editorItem->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mEditorWidgetHtml.svg" ) ) );
1104 break;
1105 }
1106
1108 {
1109 const QgsAttributeEditorTextElement *textElementEditor = static_cast<const QgsAttributeEditorTextElement *>( editorElement );
1110 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1111 setCommonProperties( itemData );
1112
1113 QgsAttributesFormData::TextElementEditorConfiguration textEdConfig;
1114 textEdConfig.text = textElementEditor->text();
1115 itemData.setTextElementEditorConfiguration( textEdConfig );
1116
1117 editorItem->setData( ItemNameRole, editorElement->name() );
1118 editorItem->setData( ItemTypeRole, QgsAttributesFormData::TextWidget );
1119 editorItem->setData( ItemDataRole, itemData );
1120 editorItem->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mEditorWidgetText.svg" ) ) );
1121 break;
1122 }
1123
1125 {
1126 const QgsAttributeEditorSpacerElement *spacerElementEditor = static_cast<const QgsAttributeEditorSpacerElement *>( editorElement );
1127 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1128 setCommonProperties( itemData );
1129 itemData.setShowLabel( false );
1130
1131 QgsAttributesFormData::SpacerElementEditorConfiguration spacerEdConfig;
1132 spacerEdConfig.drawLine = spacerElementEditor->drawLine();
1133 itemData.setSpacerElementEditorConfiguration( spacerEdConfig );
1134
1135 editorItem->setData( ItemNameRole, editorElement->name() );
1136 editorItem->setData( ItemTypeRole, QgsAttributesFormData::SpacerWidget );
1137 editorItem->setData( ItemDataRole, itemData );
1138 editorItem->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mEditorWidgetSpacer.svg" ) ) );
1139 break;
1140 }
1141
1143 {
1144 QgsDebugError( QStringLiteral( "Not loading invalid attribute editor type..." ) );
1145 break;
1146 }
1147 }
1148
1149 if ( position >= 0 && position < parent->childCount() )
1150 {
1151 parent->insertChild( position, std::move( editorItem ) );
1152 }
1153 else
1154 {
1155 parent->addChild( std::move( editorItem ) );
1156 }
1157}
1158
1159QVariant QgsAttributesFormLayoutModel::data( const QModelIndex &index, int role ) const
1160{
1161 if ( !index.isValid() )
1162 return QVariant();
1163
1164 if ( role == ItemFieldConfigRole ) // This model doesn't store data for that role
1165 return false;
1166
1168 if ( !item )
1169 return QVariant();
1170
1171 // Fields may be present in the form layout configuration
1172 // even if their corresponding layer fields were deleted.
1173 // Make those stand out from existent ones.
1174 const int fieldIndex = mLayer->fields().indexOf( item->name() );
1175 const bool invalidField = fieldIndex == -1;
1176
1177 // Relations may be broken due to missing layers or references.
1178 // Make those stand out from valid ones.
1179 bool invalidRelation = false;
1180 if ( ( role == Qt::DisplayRole || role == Qt::ToolTipRole || role == Qt::ForegroundRole ) && item->type() == QgsAttributesFormData::Relation )
1181 {
1182 invalidRelation = !QgsProject::instance()->relationManager()->relation( item->id() ).isValid();
1183 }
1184
1185 switch ( role )
1186 {
1187 case Qt::DisplayRole:
1188 {
1189 if ( item->type() == QgsAttributesFormData::Relation && invalidRelation )
1190 {
1191 // Invalid relations can have an id, if that's the case, we have a name.
1192 // Only set a new name if id is missing.
1193 if ( item->id().isEmpty() )
1194 {
1195 return tr( "Invalid relation" );
1196 }
1197 }
1198
1199 if ( !showAliases() && ( item->type() == QgsAttributesFormData::Field || item->type() == QgsAttributesFormData::Relation ) )
1200 {
1201 return item->name();
1202 }
1203
1204 return item->displayName().isEmpty() ? item->name() : item->displayName();
1205 }
1206
1207 case Qt::ToolTipRole:
1208 {
1209 if ( item->type() == QgsAttributesFormData::Field )
1210 {
1211 if ( invalidField )
1212 {
1213 return tr( "Invalid field" );
1214 }
1215 else
1216 {
1217 return item->name();
1218 }
1219 }
1220
1221 if ( item->type() == QgsAttributesFormData::Relation && invalidRelation )
1222 {
1223 if ( !item->id().isEmpty() )
1224 {
1225 // The relation name is shown, let's inform users via tooltip why it's red
1226 return tr( "Invalid relation" );
1227 }
1228 }
1229
1230 return QVariant();
1231 }
1232
1233 case Qt::DecorationRole:
1234 return item->icon();
1235
1236 case Qt::BackgroundRole:
1237 {
1238 if ( item->type() == QgsAttributesFormData::Container )
1239 return QBrush( QColor( 140, 140, 140, 50 ) );
1240
1241 return QVariant();
1242 }
1243
1244 case Qt::ForegroundRole:
1245 {
1246 if ( item->type() == QgsAttributesFormData::Field )
1247 {
1248 if ( invalidField )
1249 {
1250 return QBrush( QColor( 255, 0, 0 ) );
1251 }
1252 else if ( showAliases() && item->displayName().isEmpty() )
1253 {
1254 return QBrush( QColor( Qt::lightGray ) );
1255 }
1256 }
1257
1258 if ( item->type() == QgsAttributesFormData::Relation )
1259 {
1260 if ( invalidRelation )
1261 {
1262 return QBrush( QColor( 255, 0, 0 ) );
1263 }
1264 else if ( showAliases() && item->displayName().isEmpty() )
1265 {
1266 return QBrush( QColor( Qt::lightGray ) );
1267 }
1268 }
1269
1270 return QVariant();
1271 }
1272
1273 case Qt::FontRole:
1274 {
1275 if ( item->type() == QgsAttributesFormData::Field )
1276 {
1277 if ( !invalidField && showAliases() && item->displayName().isEmpty() )
1278 {
1279 QFont font = QFont();
1280 font.setItalic( true );
1281 return font;
1282 }
1283 }
1284
1285 if ( item->type() == QgsAttributesFormData::Relation )
1286 {
1287 if ( !invalidRelation && showAliases() && item->displayName().isEmpty() )
1288 {
1289 QFont font = QFont();
1290 font.setItalic( true );
1291 return font;
1292 }
1293 }
1294
1295 return QVariant();
1296 }
1297
1298 case ItemDataRole:
1299 case ItemNameRole:
1300 case ItemIdRole:
1301 case ItemTypeRole:
1302 case ItemDisplayRole:
1303 return item->data( role );
1304
1305 default:
1306 return QVariant();
1307 }
1308}
1309
1310bool QgsAttributesFormLayoutModel::removeRows( int row, int count, const QModelIndex &parent )
1311{
1312 if ( row < 0 )
1313 return false;
1314
1316
1317 if ( row > item->childCount() - count )
1318 return false;
1319
1320 beginRemoveRows( parent, row, row + count - 1 );
1321 for ( int r = 0; r < count; ++r )
1322 item->deleteChildAtIndex( row );
1323 endRemoveRows();
1324 return true;
1325}
1326
1327bool QgsAttributesFormLayoutModel::removeRow( int row, const QModelIndex &parent )
1328{
1329 beginRemoveRows( parent, row, row );
1331 item->deleteChildAtIndex( row );
1332 endRemoveRows();
1333 return true;
1334}
1335
1337{
1338 return Qt::MoveAction;
1339}
1340
1342{
1343 return Qt::DropAction::CopyAction | Qt::DropAction::MoveAction;
1344}
1345
1347{
1348 return QStringList() << QStringLiteral( "application/x-qgsattributesformlayoutelement" ) << QStringLiteral( "application/x-qgsattributesformavailablewidgetsrelement" );
1349}
1350
1351QModelIndexList QgsAttributesFormLayoutModel::curateIndexesForMimeData( const QModelIndexList &indexes ) const
1352{
1353 QModelIndexList containerList;
1354 for ( const auto index : indexes )
1355 {
1356 const auto indexType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
1357 if ( indexType == QgsAttributesFormData::Container )
1358 {
1359 containerList << index;
1360 }
1361 }
1362
1363 if ( containerList.size() == 0 )
1364 return indexes;
1365
1366 QModelIndexList curatedIndexes;
1367
1368 // Iterate searching if current index is child of any container in containerList (recursively)
1369 for ( const auto index : indexes )
1370 {
1371 QModelIndex parent = index.parent();
1372 bool redundantChild = false;
1373
1374 while ( parent.isValid() )
1375 {
1376 if ( containerList.contains( parent ) )
1377 {
1378 redundantChild = true;
1379 break;
1380 }
1381
1382 parent = parent.parent();
1383 }
1384
1385 if ( !redundantChild )
1386 curatedIndexes << index;
1387 }
1388
1389 return curatedIndexes;
1390}
1391
1392QMimeData *QgsAttributesFormLayoutModel::mimeData( const QModelIndexList &indexes ) const
1393{
1394 if ( indexes.count() == 0 )
1395 return nullptr;
1396
1397 // Discard redundant indexes
1398 QModelIndexList curatedIndexes;
1399 if ( indexes.count() > 1 )
1400 {
1401 curatedIndexes = curateIndexesForMimeData( indexes );
1402 }
1403 else
1404 {
1405 curatedIndexes = indexes;
1406 }
1407
1408 const QStringList types = mimeTypes();
1409 if ( types.isEmpty() )
1410 return nullptr;
1411
1412 QMimeData *data = new QMimeData();
1413 const QString format = types.at( 0 );
1414 QByteArray encoded;
1415 QDataStream stream( &encoded, QIODevice::WriteOnly );
1416
1417 // Sort indexes since their order reflects selection order
1418 std::sort( curatedIndexes.begin(), curatedIndexes.end(), [this]( const QModelIndex &a, const QModelIndex &b ) {
1419 return indexLessThan( a, b );
1420 } );
1421
1422 for ( const QModelIndex &index : std::as_const( curatedIndexes ) )
1423 {
1424 if ( index.isValid() )
1425 {
1426 QDomDocument doc;
1427
1428 QDomElement rootElem = doc.createElement( QStringLiteral( "form_layout_mime" ) );
1430 QDomElement editorElem = editor->toDomElement( doc );
1431 rootElem.appendChild( editorElem );
1432
1433 doc.appendChild( rootElem );
1434 stream << doc.toString( -1 );
1435 }
1436 }
1437
1438 data->setData( format, encoded );
1439 return data;
1440}
1441
1442bool QgsAttributesFormLayoutModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
1443{
1444 Q_UNUSED( column )
1445 bool isDropSuccessful = false;
1446 int rows = 0;
1447
1448 if ( row == -1 ) // Dropped at invalid index
1449 row = rowCount( parent ); // Let's append the item
1450
1451 if ( action == Qt::IgnoreAction )
1452 {
1453 isDropSuccessful = true;
1454 }
1455 else if ( data->hasFormat( QStringLiteral( "application/x-qgsattributesformavailablewidgetsrelement" ) ) )
1456 {
1457 Q_ASSERT( action == Qt::CopyAction ); // External drop
1458 QByteArray itemData = data->data( QStringLiteral( "application/x-qgsattributesformavailablewidgetsrelement" ) );
1459 QDataStream stream( &itemData, QIODevice::ReadOnly );
1460
1461 while ( !stream.atEnd() )
1462 {
1463 QString itemId;
1464 int itemTypeInt;
1465 QString itemName;
1466 stream >> itemId >> itemTypeInt >> itemName;
1467
1468 const auto itemType = static_cast< QgsAttributesFormData::AttributesFormItemType >( itemTypeInt );
1469 insertChild( parent, row + rows, itemId, itemType, itemName );
1470
1471 isDropSuccessful = true;
1472
1473 QModelIndex addedIndex = index( row + rows, 0, parent );
1474 emit externalItemDropped( addedIndex );
1475
1476 rows++;
1477 }
1478 }
1479 else if ( data->hasFormat( QStringLiteral( "application/x-qgsattributesformlayoutelement" ) ) )
1480 {
1481 Q_ASSERT( action == Qt::MoveAction ); // Internal move
1482 QByteArray itemData = data->data( QStringLiteral( "application/x-qgsattributesformlayoutelement" ) );
1483 QDataStream stream( &itemData, QIODevice::ReadOnly );
1484
1485 while ( !stream.atEnd() )
1486 {
1487 QString text;
1488 stream >> text;
1489
1490 QDomDocument doc;
1491 if ( !doc.setContent( text ) )
1492 continue;
1493 const QDomElement rootElem = doc.documentElement();
1494 if ( rootElem.tagName() != QLatin1String( "form_layout_mime" ) || !rootElem.hasChildNodes() )
1495 continue;
1496 const QDomElement childElem = rootElem.firstChild().toElement();
1497
1498 // Build editor element from XML and add/insert it to parent
1500 beginInsertRows( parent, row + rows, row + rows );
1501 loadAttributeEditorElementItem( editor, itemForIndex( parent ), row + rows );
1502 endInsertRows();
1503
1504 isDropSuccessful = true;
1505
1506 QModelIndex addedIndex = index( row + rows, 0, parent );
1507 emit internalItemDropped( addedIndex );
1508
1509 rows++;
1510 }
1511 }
1512
1513 return isDropSuccessful;
1514}
1515
1516void QgsAttributesFormLayoutModel::updateFieldConfigForFieldItemsRecursive( QgsAttributesFormItem *parent, const QString &fieldName, const QgsAttributesFormData::FieldConfig &config )
1517{
1518 for ( int i = 0; i < parent->childCount(); i++ )
1519 {
1520 QgsAttributesFormItem *child = parent->child( i );
1521 if ( child->name() == fieldName && child->type() == QgsAttributesFormData::Field )
1522 {
1523 child->setData( ItemFieldConfigRole, QVariant::fromValue( config ) );
1524 child->setIcon( QgsGui::instance()->editorWidgetRegistry()->icon( config.mEditorWidgetType ) );
1525 emit fieldConfigDataChanged( child ); // Item's field config has changed, let views know about it
1526 }
1527
1528 if ( child->childCount() > 0 )
1529 {
1530 updateFieldConfigForFieldItemsRecursive( child, fieldName, config );
1531 }
1532 }
1533}
1534
1536{
1537 updateFieldConfigForFieldItemsRecursive( mRootItem.get(), fieldName, config );
1538}
1539
1540void QgsAttributesFormLayoutModel::updateAliasForFieldItemsRecursive( QgsAttributesFormItem *parent, const QString &fieldName, const QString &fieldAlias )
1541{
1542 for ( int i = 0; i < parent->childCount(); i++ )
1543 {
1544 QgsAttributesFormItem *child = parent->child( i );
1545 if ( child->name() == fieldName && child->type() == QgsAttributesFormData::Field )
1546 {
1547 child->setData( ItemDisplayRole, fieldAlias );
1548 const QModelIndex index = createIndex( child->row(), 0, child );
1549 emit dataChanged( index, index ); // Item's alias has changed, let views know about it
1550 }
1551
1552 if ( child->childCount() > 0 )
1553 {
1554 updateAliasForFieldItemsRecursive( child, fieldName, fieldAlias );
1555 }
1556 }
1557}
1558
1559void QgsAttributesFormLayoutModel::updateAliasForFieldItems( const QString &fieldName, const QString &fieldAlias )
1560{
1561 updateAliasForFieldItemsRecursive( mRootItem.get(), fieldName, fieldAlias );
1562}
1563
1564QList< QgsAddAttributeFormContainerDialog::ContainerPair > QgsAttributesFormLayoutModel::recursiveListOfContainers( QgsAttributesFormItem *parent ) const
1565{
1566 QList< QgsAddAttributeFormContainerDialog::ContainerPair > containerList;
1567 for ( int i = 0; i < parent->childCount(); i++ )
1568 {
1569 QgsAttributesFormItem *child = parent->child( i );
1570 if ( child->type() == QgsAttributesFormData::Container )
1571 {
1572 containerList << QgsAddAttributeFormContainerDialog::ContainerPair( child->name(), createIndex( child->row(), 0, child ) );
1573 }
1574
1575 if ( child->childCount() > 0 )
1576 {
1577 containerList.append( recursiveListOfContainers( child ) );
1578 }
1579 }
1580
1581 return containerList;
1582}
1583
1585{
1586 QgsAttributeEditorElement *widgetDef = nullptr;
1587
1589 const int indexType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
1590 const QString indexName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
1591 const QString indexId = index.data( QgsAttributesFormModel::ItemIdRole ).toString();
1592
1593 switch ( indexType )
1594 {
1596 {
1597 const int fieldIndex = mLayer->fields().lookupField( indexName );
1598 widgetDef = new QgsAttributeEditorField( indexName, fieldIndex, parent );
1599 break;
1600 }
1601
1603 {
1604 const QgsAction action { mLayer->actions()->action( indexId ) };
1605 widgetDef = new QgsAttributeEditorAction( action, parent );
1606 break;
1607 }
1608
1610 {
1611 const QgsRelation relation = mProject->relationManager()->relation( indexId );
1612
1615 relDef->setRelationWidgetTypeId( relationEditorConfig.mRelationWidgetType );
1616 relDef->setRelationEditorConfiguration( relationEditorConfig.mRelationWidgetConfig );
1617 relDef->setNmRelationId( relationEditorConfig.nmRelationId );
1618 relDef->setForceSuppressFormPopup( relationEditorConfig.forceSuppressFormPopup );
1619 relDef->setLabel( relationEditorConfig.label );
1620 widgetDef = relDef;
1621 break;
1622 }
1623
1625 {
1626 QgsAttributeEditorContainer *container = new QgsAttributeEditorContainer( indexName, parent, itemData.backgroundColor() );
1627 container->setColumnCount( itemData.columnCount() );
1628 // only top-level containers can be tabs
1630 bool isTopLevel = !index.parent().isValid();
1631 if ( type == Qgis::AttributeEditorContainerType::Tab && !isTopLevel )
1632 {
1633 // a tab container found which isn't at the top level -- reset it to a group box instead
1635 }
1636 container->setType( type );
1637 container->setCollapsed( itemData.collapsed() );
1638 container->setCollapsedExpression( itemData.collapsedExpression() );
1639 container->setVisibilityExpression( itemData.visibilityExpression() );
1640 container->setBackgroundColor( itemData.backgroundColor() );
1641
1642 QModelIndex childIndex;
1643 for ( int t = 0; t < rowCount( index ); t++ )
1644 {
1645 childIndex = this->index( t, 0, index );
1646 QgsAttributeEditorElement *element { createAttributeEditorWidget( childIndex, container ) };
1647 if ( element )
1648 container->addChildElement( element );
1649 }
1650 widgetDef = container;
1651 break;
1652 }
1653
1655 {
1657 element->setQmlCode( itemData.qmlElementEditorConfiguration().qmlCode );
1658 widgetDef = element;
1659 break;
1660 }
1661
1663 {
1666 widgetDef = element;
1667 break;
1668 }
1669
1671 {
1673 element->setText( itemData.textElementEditorConfiguration().text );
1674 widgetDef = element;
1675 break;
1676 }
1677
1679 {
1682 widgetDef = element;
1683 break;
1684 }
1685
1687 default:
1688 break;
1689 }
1690
1691 if ( widgetDef )
1692 {
1693 widgetDef->setShowLabel( itemData.showLabel() );
1694 widgetDef->setLabelStyle( itemData.labelStyle() );
1695 widgetDef->setHorizontalStretch( itemData.horizontalStretch() );
1696 widgetDef->setVerticalStretch( itemData.verticalStretch() );
1697 }
1698
1699 return widgetDef;
1700}
1701
1702QList< QgsAddAttributeFormContainerDialog::ContainerPair > QgsAttributesFormLayoutModel::listOfContainers() const
1703{
1704 return recursiveListOfContainers( mRootItem.get() );
1705}
1706
1708{
1709 beginInsertRows( parent, rowCount( parent ), rowCount( parent ) );
1710
1711 QgsAttributesFormItem *parentItem = itemForIndex( parent );
1712
1713 auto containerItem = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::Container, name, QString(), parentItem );
1714
1716 itemData.setColumnCount( columnCount );
1718
1719 containerItem->setData( QgsAttributesFormModel::ItemDataRole, itemData );
1720 containerItem->setData( QgsAttributesFormModel::ItemIdRole, name ); // Make it searchable
1721 parentItem->addChild( std::move( containerItem ) );
1722
1723 endInsertRows();
1724}
1725
1726void QgsAttributesFormLayoutModel::insertChild( const QModelIndex &parent, int row, const QString &itemId, QgsAttributesFormData::AttributesFormItemType itemType, const QString &itemName )
1727{
1728 if ( row < 0 )
1729 return;
1730
1731 beginInsertRows( parent, row, row );
1732 auto item = std::make_unique< QgsAttributesFormItem >();
1733
1734 item->setData( QgsAttributesFormModel::ItemIdRole, itemId );
1735 item->setData( QgsAttributesFormModel::ItemTypeRole, itemType );
1736 item->setData( QgsAttributesFormModel::ItemNameRole, itemName );
1737
1738 itemForIndex( parent )->insertChild( row, std::move( item ) );
1739 endInsertRows();
1740}
1741
1742
1744 : QSortFilterProxyModel( parent )
1745{
1746}
1747
1749{
1750 mModel = model;
1751 QSortFilterProxyModel::setSourceModel( mModel );
1752}
1753
1758
1760{
1761 return mFilterText;
1762}
1763
1765{
1766 // Since we want to allow refreshing the filter when, e.g.,
1767 // users switch to aliases, then we allow this method to be
1768 // executed even if previous and new filters are equal
1769
1770 mFilterText = filterText.trimmed();
1771 invalidate();
1772}
1773
1774bool QgsAttributesFormProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
1775{
1776 if ( mFilterText.isEmpty() )
1777 return true;
1778
1779 QModelIndex sourceIndex = sourceModel()->index( sourceRow, 0, sourceParent );
1780 if ( !sourceIndex.isValid() )
1781 return false;
1782
1783 // If name or alias match, accept it before any other checks
1784 if ( sourceIndex.data( QgsAttributesFormModel::ItemNameRole ).toString().contains( mFilterText, Qt::CaseInsensitive ) || sourceIndex.data( QgsAttributesFormModel::ItemDisplayRole ).toString().contains( mFilterText, Qt::CaseInsensitive ) )
1785 return true;
1786
1787 // Child is accepted if any of its parents is accepted
1788 QModelIndex parent = sourceIndex.parent();
1789 while ( parent.isValid() )
1790 {
1791 if ( parent.data( QgsAttributesFormModel::ItemNameRole ).toString().contains( mFilterText, Qt::CaseInsensitive ) || parent.data( QgsAttributesFormModel::ItemDisplayRole ).toString().contains( mFilterText, Qt::CaseInsensitive ) )
1792 return true;
1793
1794 parent = parent.parent();
1795 }
1796
1797 return false;
1798}
AttributeEditorContainerType
Attribute editor container types.
Definition qgis.h:5470
@ Action
A layer action element.
Definition qgis.h:5457
@ Container
A container.
Definition qgis.h:5452
@ QmlElement
A QML element.
Definition qgis.h:5455
@ Relation
A relation.
Definition qgis.h:5454
@ HtmlElement
A HTML element.
Definition qgis.h:5456
@ TextElement
A text element.
Definition qgis.h:5458
@ SpacerElement
A spacer element.
Definition qgis.h:5459
Utility class that encapsulates an action based on vector attributes.
Definition qgsaction.h:37
QString name() const
The name of the action. This may be a longer description.
Definition qgsaction.h:115
bool isValid() const
Returns true if this action was a default constructed one.
Definition qgsaction.h:130
QString shortTitle() const
The short title is used to label user interface elements like buttons.
Definition qgsaction.h:118
QUuid id() const
Returns a unique id for this action.
Definition qgsaction.h:124
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:54
QString name
Definition qgsfield.h:63
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:762
QString alias
Definition qgsfield.h:64
Qgis::FieldDuplicatePolicy duplicatePolicy() const
Returns the field's duplicate policy, which indicates how field values should be handled during a dup...
Definition qgsfield.cpp:772
QgsDefaultValue defaultValueDefinition
Definition qgsfield.h:65
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:782
QString comment
Definition qgsfield.h:62
QgsFieldConstraints constraints
Definition qgsfield.h:66
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:106
static QgsGui * instance()
Returns a pointer to the singleton instance.
Definition qgsgui.cpp:90
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:109
QgsRelationManager * relationManager
Definition qgsproject.h:120
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:57
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