QGIS API Documentation 4.1.0-Master (009143bf4b4)
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 mCustomComment = layer->fields().at( idx ).customComment();
47 mEditable = !layer->editFormConfig().readOnly( idx );
48 mLabelOnTop = layer->editFormConfig().labelOnTop( idx );
50 mFieldConstraints = layer->fields().at( idx ).constraints();
51 const QgsEditorWidgetSetup setup = QgsGui::editorWidgetRegistry()->findBest( layer, layer->fields().field( idx ).name() );
52 mEditorWidgetType = setup.type();
54 mSplitPolicy = layer->fields().at( idx ).splitPolicy();
55 mDuplicatePolicy = layer->fields().at( idx ).duplicatePolicy();
56 mMergePolicy = layer->fields().at( idx ).mergePolicy();
59}
60
61QgsAttributesFormData::FieldConfig::operator QVariant()
62{
63 return QVariant::fromValue<QgsAttributesFormData::FieldConfig>( *this );
64}
65
66QgsAttributesFormData::RelationEditorConfiguration::operator QVariant()
67{
68 return QVariant::fromValue<QgsAttributesFormData::RelationEditorConfiguration>( *this );
69}
70
75
80
85
90
92{
93 return mShowLabel;
94}
95
100
105
110
115
120
125
130
135
140
141
146
151
156
161
163{
164 return mBackgroundColor;
165}
166
171
176
181
182
184 : mName( name )
185 , mDisplayName( displayName )
186 , mType( itemType )
187 , mParent( parent )
188{}
189
192)
193 : mName( name )
194 , mDisplayName( displayName )
195 , mType( itemType )
196 , mData( data )
197 , mParent( parent )
198{}
199
201{
202 if ( !mChildren.empty() && row >= 0 && row < childCount() )
203 return mChildren.at( row ).get();
204
205 return nullptr;
206}
207
209{
210 if ( !mChildren.empty() && itemId.trimmed().isEmpty() )
211 return nullptr;
212
213 // Search for first matching item by name
214 const auto it = std::find_if( mChildren.cbegin(), mChildren.cend(), [itemType, itemId]( const std::unique_ptr< QgsAttributesFormItem > &item ) {
215 return item->type() == itemType && item->id() == itemId;
216 } );
217
218 if ( it != mChildren.cend() )
219 return it->get();
220
221 return nullptr;
222}
223
225{
226 if ( !mChildren.empty() && itemId.trimmed().isEmpty() )
227 return nullptr;
228
229 for ( const auto &child : std::as_const( mChildren ) )
230 {
231 if ( child->type() == itemType && child->id() == itemId )
232 return child.get();
233
234 if ( child->childCount() > 0 )
235 {
236 QgsAttributesFormItem *item = child->firstChildRecursive( itemType, itemId );
237 if ( item )
238 return item;
239 }
240 }
241
242 return nullptr;
243}
244
246{
247 return static_cast< int >( mChildren.size() );
248}
249
251{
252 if ( !mParent )
253 return 0;
254
255 const auto it = std::find_if( mParent->mChildren.cbegin(), mParent->mChildren.cend(), [this]( const std::unique_ptr< QgsAttributesFormItem > &item ) { return item.get() == this; } );
256
257 if ( it != mParent->mChildren.cend() )
258 {
259 return static_cast< int >( std::distance( mParent->mChildren.cbegin(), it ) );
260 }
261
262 return -1;
263}
264
265void QgsAttributesFormItem::addChild( std::unique_ptr< QgsAttributesFormItem > &&item )
266{
267 if ( !item )
268 return;
269
270 if ( !item->mParent )
271 item->mParent = this;
272
273 // forward the signal towards the root
275
276 mChildren.push_back( std::move( item ) );
277
278 emit addedChildren( this, mChildren.size() - 1, mChildren.size() - 1 );
279}
280
281void QgsAttributesFormItem::insertChild( int position, std::unique_ptr< QgsAttributesFormItem > &&item )
282{
283 if ( position < 0 || position > static_cast< int >( mChildren.size() ) || !item )
284 return;
285
286 if ( !item->mParent )
287 item->mParent = this;
288
289 // forward the signal towards the root
291
292 mChildren.insert( mChildren.begin() + position, std::move( item ) );
293
294 emit addedChildren( this, position, position );
295}
296
298{
299 if ( index >= 0 && index < static_cast< int >( mChildren.size() ) )
300 mChildren.erase( mChildren.begin() + index );
301}
302
304{
305 mChildren.clear();
306}
307
312
313QVariant QgsAttributesFormItem::data( int role ) const
314{
315 switch ( role )
316 {
318 return mType;
320 return QVariant::fromValue( mData );
322 return mName;
324 return mId;
326 return mDisplayName;
328 return QVariant::fromValue( mFieldConfigData );
329 default:
330 return QVariant();
331 }
332}
333
334bool QgsAttributesFormItem::setData( int role, const QVariant &value )
335{
336 switch ( role )
337 {
339 {
340 mData = value.value< QgsAttributesFormData::AttributeFormItemData >();
341 return true;
342 }
344 {
345 mName = value.toString();
346 return true;
347 }
349 {
350 mDisplayName = value.toString();
351 return true;
352 }
354 {
355 mType = static_cast<QgsAttributesFormData::AttributesFormItemType>( value.toInt() );
356 return true;
357 }
359 {
360 mId = value.toString();
361 return true;
362 }
364 {
365 mFieldConfigData = value.value< QgsAttributesFormData::FieldConfig >();
366 return true;
367 }
368 default:
369 return false;
370 }
371}
372
373
375 : QAbstractItemModel( parent )
376 , mRootItem( std::make_unique< QgsAttributesFormItem >() )
377 , mLayer( layer )
378 , mProject( project )
379{}
380
382
384{
385 if ( index.isValid() )
386 {
387 if ( auto *item = static_cast<QgsAttributesFormItem *>( index.internalPointer() ) )
388 return item;
389 }
390 return mRootItem.get();
391}
392
397
398
399int QgsAttributesFormModel::rowCount( const QModelIndex &parent ) const
400{
401 if ( parent.isValid() && parent.column() > 0 )
402 return 0;
403
404 const QgsAttributesFormItem *parentItem = itemForIndex( parent );
405
406 return parentItem ? parentItem->childCount() : 0;
407}
408
409int QgsAttributesFormModel::columnCount( const QModelIndex & ) const
410{
411 return 1;
412}
413
414bool QgsAttributesFormModel::indexLessThan( const QModelIndex &a, const QModelIndex &b ) const
415{
416 const QVector<int> pathA = rootToLeafPath( itemForIndex( a ) );
417 const QVector<int> pathB = rootToLeafPath( itemForIndex( b ) );
418
419 for ( int i = 0; i < std::min( pathA.size(), pathB.size() ); i++ )
420 {
421 if ( pathA.at( i ) != pathB.at( i ) )
422 {
423 return pathA.at( i ) < pathB.at( i );
424 }
425 }
426
427 return pathA.size() < pathB.size();
428}
429
431{
432 QVector<int> path;
433 if ( item != mRootItem.get() )
434 {
435 path << rootToLeafPath( item->parent() ) << item->row();
436 }
437 return path;
438}
439
440QModelIndex QgsAttributesFormModel::index( int row, int column, const QModelIndex &parent ) const
441{
442 if ( !hasIndex( row, column, parent ) )
443 return QModelIndex();
444
446 if ( !parentItem )
447 return QModelIndex();
448
449 if ( QgsAttributesFormItem *childItem = parentItem->child( row ) )
450 return createIndex( row, column, childItem );
451
452 return QModelIndex();
453}
454
455QModelIndex QgsAttributesFormModel::parent( const QModelIndex &index ) const
456{
457 if ( !index.isValid() )
458 return QModelIndex();
459
461 QgsAttributesFormItem *parentItem = childItem ? childItem->parent() : nullptr;
462
463 return ( parentItem != mRootItem.get() && parentItem != nullptr ) ? createIndex( parentItem->row(), 0, parentItem ) : QModelIndex();
464}
465
467{
468 QgsAttributesFormItem *item = mRootItem->firstTopChild( itemType, itemId );
469 return item ? createIndex( item->row(), 0, item ) : QModelIndex();
470}
471
473{
474 QgsAttributesFormItem *item = mRootItem->firstChildRecursive( itemType, itemId );
475 return item ? createIndex( item->row(), 0, item ) : QModelIndex();
476}
477
478bool QgsAttributesFormModel::setData( const QModelIndex &index, const QVariant &value, int role )
479{
480 if ( !index.isValid() )
481 return false;
482
484 bool result = item->setData( role, value );
485
486 if ( result )
487 {
488 emit dataChanged( index, index, { role } );
489
491 {
492 emit fieldConfigDataChanged( item );
493 }
494 }
495
496 return result;
497}
498
500{
501 return mShowAliases;
502}
503
505{
506 mShowAliases = show;
507
508 emitDataChangedRecursively( QModelIndex(), QVector<int>() << Qt::DisplayRole << Qt::ForegroundRole << Qt::FontRole );
509}
510
511void QgsAttributesFormModel::emitDataChangedRecursively( const QModelIndex &parent, const QVector<int> &roles )
512{
513 emit dataChanged( index( 0, 0, parent ), index( rowCount( parent ) - 1, 0, parent ), roles );
514 for ( int i = 0; i < rowCount( parent ); i++ )
515 {
516 const QModelIndex childIndex = index( i, 0, parent );
517 if ( hasChildren( childIndex ) )
518 {
519 emitDataChangedRecursively( childIndex, roles );
520 }
521 }
522}
523
524
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, u"Fields"_s, 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, u"Relations"_s, 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 = u"%1 (%2)"_s.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( u"/mEditorWidgetRelationEditor.svg"_s ) );
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, u"Actions"_s, 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, u"Other"_s, tr( "Other Widgets" ) );
627
629 itemData.setShowLabel( true );
630 auto itemQml = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::QmlWidget, itemData, u"QML Widget"_s, tr( "QML Widget" ) );
631 itemQml->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetQml.svg"_s ) );
632 itemOtherWidgets->addChild( std::move( itemQml ) );
633
635 itemHtmlData.setShowLabel( true );
636 auto itemHtml = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::HtmlWidget, itemHtmlData, u"HTML Widget"_s, tr( "HTML Widget" ) );
637 itemHtml->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetHtml.svg"_s ) );
638 itemOtherWidgets->addChild( std::move( itemHtml ) );
639
641 itemTextData.setShowLabel( true );
642 auto itemText = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::TextWidget, itemTextData, u"Text Widget"_s, tr( "Text Widget" ) );
643 itemText->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetText.svg"_s ) );
644 itemOtherWidgets->addChild( std::move( itemText ) );
645
647 itemTextData.setShowLabel( false );
648 auto itemSpacer = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::SpacerWidget, u"Spacer Widget"_s, tr( "Spacer Widget" ) );
649 itemSpacer->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetSpacer.svg"_s ) );
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( u"Feature"_s ) || action.actionScopes().contains( u"Layer"_s ) ) )
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( u"Feature"_s ) || action.actionScopes().contains( u"Layer"_s ) ) )
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( u"/mEditorWidgetAction.svg"_s ) );
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() << u"application/x-qgsattributesformavailablewidgetsrelement"_s;
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 ) { return indexLessThan( a, b ); } );
842
843 for ( const QModelIndex &index : std::as_const( sortedIndexes ) )
844 {
845 if ( index.isValid() )
846 {
847 const QString itemId = index.data( QgsAttributesFormModel::ItemIdRole ).toString();
848 const QString itemName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
849 int itemType = index.data( QgsAttributesFormModel::ItemTypeRole ).toInt();
850
851 stream << itemId << itemType << itemName;
852 }
853 }
854
855 data->setData( format, encoded );
856 return data;
857}
858
860{
861 if ( mRootItem->childCount() > 0 )
862 {
863 const int row = 0;
864 QgsAttributesFormItem *item = mRootItem->child( row );
865 if ( item && item->name() == "Fields"_L1 && item->type() == QgsAttributesFormData::WidgetType )
866 return createIndex( row, 0, item );
867 }
868 return QModelIndex();
869}
870
872{
873 if ( mRootItem->childCount() > 1 )
874 {
875 const int row = 1;
876 QgsAttributesFormItem *item = mRootItem->child( row );
877 if ( item && item->name() == "Relations"_L1 && item->type() == QgsAttributesFormData::WidgetType )
878 return createIndex( row, 0, item );
879 }
880 return QModelIndex();
881}
882
884{
885 if ( mRootItem->childCount() > 2 )
886 {
887 const int row = 2;
888 QgsAttributesFormItem *item = mRootItem->child( row );
889 if ( item && item->name() == "Actions"_L1 && item->type() == QgsAttributesFormData::WidgetType )
890 return createIndex( row, 0, item );
891 }
892 return QModelIndex();
893}
894
895QModelIndex QgsAttributesAvailableWidgetsModel::fieldModelIndex( const QString &fieldName ) const
896{
897 if ( mRootItem->childCount() == 0 )
898 return QModelIndex();
899
900 QgsAttributesFormItem *fieldItems = mRootItem->child( 0 );
901 if ( !fieldItems || fieldItems->name() != "Fields"_L1 || fieldItems->type() != QgsAttributesFormData::WidgetType )
902 return QModelIndex();
903
904 QgsAttributesFormItem *item = fieldItems->firstTopChild( QgsAttributesFormData::Field, fieldName );
905 return item ? createIndex( item->row(), 0, item ) : QModelIndex();
906}
907
908
912
913QVariant QgsAttributesFormLayoutModel::headerData( int section, Qt::Orientation orientation, int role ) const
914{
915 Q_UNUSED( section )
916 return orientation == Qt::Horizontal && role == Qt::DisplayRole ? tr( "Form Layout" ) : QVariant {};
917}
918
919Qt::ItemFlags QgsAttributesFormLayoutModel::flags( const QModelIndex &index ) const
920{
921 if ( !index.isValid() )
922 return Qt::ItemIsDropEnabled;
923
924 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
925
928 flags |= Qt::ItemIsDropEnabled;
929
930 return flags;
931}
932
934{
935 if ( !mLayer )
936 return;
937
938 beginResetModel();
939 mRootItem->deleteChildren();
940
941 const auto editorElements = mLayer->editFormConfig().tabs();
942 for ( QgsAttributeEditorElement *editorElement : editorElements )
943 {
944 loadAttributeEditorElementItem( editorElement, mRootItem.get() );
945 }
946
947 endResetModel();
948}
949
950void QgsAttributesFormLayoutModel::loadAttributeEditorElementItem( QgsAttributeEditorElement *const editorElement, QgsAttributesFormItem *parent, const int position )
951{
952 auto setCommonProperties = [editorElement]( QgsAttributesFormData::AttributeFormItemData &itemData ) {
953 itemData.setShowLabel( editorElement->showLabel() );
954 itemData.setLabelStyle( editorElement->labelStyle() );
955 itemData.setHorizontalStretch( editorElement->horizontalStretch() );
956 itemData.setVerticalStretch( editorElement->verticalStretch() );
957 };
958
959 auto editorItem = std::make_unique< QgsAttributesFormItem >();
960
961 switch ( editorElement->type() )
962 {
964 {
965 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
966 setCommonProperties( itemData );
967
968 editorItem->setData( ItemNameRole, editorElement->name() );
969 editorItem->setData( ItemIdRole, editorElement->name() ); // Field names act as ids
970 editorItem->setData( ItemTypeRole, QgsAttributesFormData::Field );
971 editorItem->setData( ItemDataRole, itemData );
972
973 const int fieldIndex = mLayer->fields().indexOf( editorElement->name() );
974 if ( fieldIndex != -1 )
975 {
976 editorItem->setData( ItemDisplayRole, mLayer->fields().field( fieldIndex ).alias() );
977
978 QgsAttributesFormData::FieldConfig config( mLayer, fieldIndex );
979 editorItem->setData( ItemFieldConfigRole, config );
980 editorItem->setIcon( QgsGui::instance()->editorWidgetRegistry()->icon( config.mEditorWidgetType ) );
981 }
982
983 break;
984 }
985
987 {
988 const QgsAttributeEditorAction *actionEditor = static_cast<const QgsAttributeEditorAction *>( editorElement );
989 const QgsAction action { actionEditor->action( mLayer ) };
990 if ( action.isValid() )
991 {
992 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
993 setCommonProperties( itemData );
994
995 editorItem->setData( ItemIdRole, action.id().toString() );
996 editorItem->setData( ItemNameRole, action.shortTitle().isEmpty() ? action.name() : action.shortTitle() );
997 editorItem->setData( ItemTypeRole, QgsAttributesFormData::Action );
998 editorItem->setData( ItemDataRole, itemData );
999 editorItem->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetAction.svg"_s ) );
1000 }
1001 else
1002 {
1003 QgsDebugError( u"Invalid form action"_s );
1004 }
1005 break;
1006 }
1007
1009 {
1010 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1011 setCommonProperties( itemData );
1012
1013 const QgsAttributeEditorRelation *relationEditor = static_cast<const QgsAttributeEditorRelation *>( editorElement );
1014 QgsAttributesFormData::RelationEditorConfiguration relationEditorConfig;
1015 relationEditorConfig.mRelationWidgetType = relationEditor->relationWidgetTypeId();
1016 relationEditorConfig.mRelationWidgetConfig = relationEditor->relationEditorConfiguration();
1017 relationEditorConfig.nmRelationId = relationEditor->nmRelationId();
1018 relationEditorConfig.forceSuppressFormPopup = relationEditor->forceSuppressFormPopup();
1019 relationEditorConfig.label = relationEditor->label();
1020 itemData.setRelationEditorConfiguration( relationEditorConfig );
1021
1022 QgsRelation relation = relationEditor->relation();
1023 if ( relation.id().isEmpty() )
1024 {
1025 // If relation is coming from an internal move, we lose the id.
1026 // Go to relation manager and bring relation properties.
1027 relation = mProject->relationManager()->relation( editorElement->name() );
1028 }
1029
1030 editorItem->setData( ItemIdRole, relation.id() );
1031 editorItem->setData( ItemNameRole, relation.name() );
1032 editorItem->setData( ItemDisplayRole, relationEditorConfig.label );
1033 editorItem->setData( ItemTypeRole, QgsAttributesFormData::Relation );
1034 editorItem->setData( ItemDataRole, itemData );
1035 editorItem->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetRelationEditor.svg"_s ) );
1036
1037 break;
1038 }
1039
1041 {
1042 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1043 setCommonProperties( itemData );
1044
1045 editorItem->setData( ItemNameRole, editorElement->name() );
1046 editorItem->setData( ItemIdRole, editorElement->name() ); // Containers don't have id, use name to make them searchable
1047 editorItem->setData( ItemTypeRole, QgsAttributesFormData::Container );
1048
1049 const QgsAttributeEditorContainer *container = static_cast<const QgsAttributeEditorContainer *>( editorElement );
1050 if ( !container )
1051 break;
1052
1053 itemData.setColumnCount( container->columnCount() );
1054 itemData.setContainerType( container->type() );
1055 itemData.setBackgroundColor( container->backgroundColor() );
1056 itemData.setVisibilityExpression( container->visibilityExpression() );
1057 itemData.setCollapsedExpression( container->collapsedExpression() );
1058 itemData.setCollapsed( container->collapsed() );
1059
1060 editorItem->setData( ItemDataRole, itemData );
1061
1062 const QList<QgsAttributeEditorElement *> children = container->children();
1063 for ( QgsAttributeEditorElement *childElement : children )
1064 {
1065 loadAttributeEditorElementItem( childElement, editorItem.get() );
1066 }
1067 break;
1068 }
1069
1071 {
1072 const QgsAttributeEditorQmlElement *qmlElementEditor = static_cast<const QgsAttributeEditorQmlElement *>( editorElement );
1073 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1074 setCommonProperties( itemData );
1075
1076 QgsAttributesFormData::QmlElementEditorConfiguration qmlEdConfig;
1077 qmlEdConfig.qmlCode = qmlElementEditor->qmlCode();
1078 itemData.setQmlElementEditorConfiguration( qmlEdConfig );
1079
1080 editorItem->setData( ItemNameRole, editorElement->name() );
1081 editorItem->setData( ItemTypeRole, QgsAttributesFormData::QmlWidget );
1082 editorItem->setData( ItemDataRole, itemData );
1083 editorItem->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetQml.svg"_s ) );
1084 break;
1085 }
1086
1088 {
1089 const QgsAttributeEditorHtmlElement *htmlElementEditor = static_cast<const QgsAttributeEditorHtmlElement *>( editorElement );
1090 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1091 setCommonProperties( itemData );
1092
1093 QgsAttributesFormData::HtmlElementEditorConfiguration htmlEdConfig;
1094 htmlEdConfig.htmlCode = htmlElementEditor->htmlCode();
1095 itemData.setHtmlElementEditorConfiguration( htmlEdConfig );
1096
1097 editorItem->setData( ItemNameRole, editorElement->name() );
1098 editorItem->setData( ItemTypeRole, QgsAttributesFormData::HtmlWidget );
1099 editorItem->setData( ItemDataRole, itemData );
1100 editorItem->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetHtml.svg"_s ) );
1101 break;
1102 }
1103
1105 {
1106 const QgsAttributeEditorTextElement *textElementEditor = static_cast<const QgsAttributeEditorTextElement *>( editorElement );
1107 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1108 setCommonProperties( itemData );
1109
1110 QgsAttributesFormData::TextElementEditorConfiguration textEdConfig;
1111 textEdConfig.text = textElementEditor->text();
1112 itemData.setTextElementEditorConfiguration( textEdConfig );
1113
1114 editorItem->setData( ItemNameRole, editorElement->name() );
1115 editorItem->setData( ItemTypeRole, QgsAttributesFormData::TextWidget );
1116 editorItem->setData( ItemDataRole, itemData );
1117 editorItem->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetText.svg"_s ) );
1118 break;
1119 }
1120
1122 {
1123 const QgsAttributeEditorSpacerElement *spacerElementEditor = static_cast<const QgsAttributeEditorSpacerElement *>( editorElement );
1124 QgsAttributesFormData::AttributeFormItemData itemData = QgsAttributesFormData::AttributeFormItemData();
1125 setCommonProperties( itemData );
1126 itemData.setShowLabel( false );
1127
1128 QgsAttributesFormData::SpacerElementEditorConfiguration spacerEdConfig;
1129 spacerEdConfig.drawLine = spacerElementEditor->drawLine();
1130 itemData.setSpacerElementEditorConfiguration( spacerEdConfig );
1131
1132 editorItem->setData( ItemNameRole, editorElement->name() );
1133 editorItem->setData( ItemTypeRole, QgsAttributesFormData::SpacerWidget );
1134 editorItem->setData( ItemDataRole, itemData );
1135 editorItem->setIcon( QgsApplication::getThemeIcon( u"/mEditorWidgetSpacer.svg"_s ) );
1136 break;
1137 }
1138
1140 {
1141 QgsDebugError( u"Not loading invalid attribute editor type..."_s );
1142 break;
1143 }
1144 }
1145
1146 if ( position >= 0 && position < parent->childCount() )
1147 {
1148 parent->insertChild( position, std::move( editorItem ) );
1149 }
1150 else
1151 {
1152 parent->addChild( std::move( editorItem ) );
1153 }
1154}
1155
1156QVariant QgsAttributesFormLayoutModel::data( const QModelIndex &index, int role ) const
1157{
1158 if ( !index.isValid() )
1159 return QVariant();
1160
1161 if ( role == ItemFieldConfigRole ) // This model doesn't store data for that role
1162 return false;
1163
1165 if ( !item )
1166 return QVariant();
1167
1168 // Fields may be present in the form layout configuration
1169 // even if their corresponding layer fields were deleted.
1170 // Make those stand out from existent ones.
1171 const int fieldIndex = mLayer->fields().indexOf( item->name() );
1172 const bool invalidField = fieldIndex == -1;
1173
1174 // Relations may be broken due to missing layers or references.
1175 // Make those stand out from valid ones.
1176 bool invalidRelation = false;
1177 if ( ( role == Qt::DisplayRole || role == Qt::ToolTipRole || role == Qt::ForegroundRole ) && item->type() == QgsAttributesFormData::Relation )
1178 {
1179 invalidRelation = !QgsProject::instance()->relationManager()->relation( item->id() ).isValid();
1180 }
1181
1182 switch ( role )
1183 {
1184 case Qt::DisplayRole:
1185 {
1186 if ( item->type() == QgsAttributesFormData::Relation && invalidRelation )
1187 {
1188 // Invalid relations can have an id, if that's the case, we have a name.
1189 // Only set a new name if id is missing.
1190 if ( item->id().isEmpty() )
1191 {
1192 return tr( "Invalid relation" );
1193 }
1194 }
1195
1196 if ( !showAliases() && ( item->type() == QgsAttributesFormData::Field || item->type() == QgsAttributesFormData::Relation ) )
1197 {
1198 return item->name();
1199 }
1200
1201 return item->displayName().isEmpty() ? item->name() : item->displayName();
1202 }
1203
1204 case Qt::ToolTipRole:
1205 {
1206 if ( item->type() == QgsAttributesFormData::Field )
1207 {
1208 if ( invalidField )
1209 {
1210 return tr( "Invalid field" );
1211 }
1212 else
1213 {
1214 return item->name();
1215 }
1216 }
1217
1218 if ( item->type() == QgsAttributesFormData::Relation && invalidRelation )
1219 {
1220 if ( !item->id().isEmpty() )
1221 {
1222 // The relation name is shown, let's inform users via tooltip why it's red
1223 return tr( "Invalid relation" );
1224 }
1225 }
1226
1227 return QVariant();
1228 }
1229
1230 case Qt::DecorationRole:
1231 return item->icon();
1232
1233 case Qt::BackgroundRole:
1234 {
1235 if ( item->type() == QgsAttributesFormData::Container )
1236 return QBrush( QColor( 140, 140, 140, 50 ) );
1237
1238 return QVariant();
1239 }
1240
1241 case Qt::ForegroundRole:
1242 {
1243 if ( item->type() == QgsAttributesFormData::Field )
1244 {
1245 if ( invalidField )
1246 {
1247 return QBrush( QColor( 255, 0, 0 ) );
1248 }
1249 else if ( showAliases() && item->displayName().isEmpty() )
1250 {
1251 return QBrush( QColor( Qt::lightGray ) );
1252 }
1253 }
1254
1255 if ( item->type() == QgsAttributesFormData::Relation )
1256 {
1257 if ( invalidRelation )
1258 {
1259 return QBrush( QColor( 255, 0, 0 ) );
1260 }
1261 else if ( showAliases() && item->displayName().isEmpty() )
1262 {
1263 return QBrush( QColor( Qt::lightGray ) );
1264 }
1265 }
1266
1267 return QVariant();
1268 }
1269
1270 case Qt::FontRole:
1271 {
1272 if ( item->type() == QgsAttributesFormData::Field )
1273 {
1274 if ( !invalidField && showAliases() && item->displayName().isEmpty() )
1275 {
1276 QFont font = QFont();
1277 font.setItalic( true );
1278 return font;
1279 }
1280 }
1281
1282 if ( item->type() == QgsAttributesFormData::Relation )
1283 {
1284 if ( !invalidRelation && showAliases() && item->displayName().isEmpty() )
1285 {
1286 QFont font = QFont();
1287 font.setItalic( true );
1288 return font;
1289 }
1290 }
1291
1292 return QVariant();
1293 }
1294
1295 case ItemDataRole:
1296 case ItemNameRole:
1297 case ItemIdRole:
1298 case ItemTypeRole:
1299 case ItemDisplayRole:
1300 return item->data( role );
1301
1302 default:
1303 return QVariant();
1304 }
1305}
1306
1307bool QgsAttributesFormLayoutModel::removeRows( int row, int count, const QModelIndex &parent )
1308{
1309 if ( row < 0 )
1310 return false;
1311
1313
1314 if ( row > item->childCount() - count )
1315 return false;
1316
1317 beginRemoveRows( parent, row, row + count - 1 );
1318 for ( int r = 0; r < count; ++r )
1319 item->deleteChildAtIndex( row );
1320 endRemoveRows();
1321 return true;
1322}
1323
1324bool QgsAttributesFormLayoutModel::removeRow( int row, const QModelIndex &parent )
1325{
1326 beginRemoveRows( parent, row, row );
1328 item->deleteChildAtIndex( row );
1329 endRemoveRows();
1330 return true;
1331}
1332
1334{
1335 return Qt::MoveAction;
1336}
1337
1339{
1340 return Qt::DropAction::CopyAction | Qt::DropAction::MoveAction;
1341}
1342
1344{
1345 return QStringList() << u"application/x-qgsattributesformlayoutelement"_s << u"application/x-qgsattributesformavailablewidgetsrelement"_s;
1346}
1347
1348QModelIndexList QgsAttributesFormLayoutModel::curateIndexesForMimeData( const QModelIndexList &indexes ) const
1349{
1350 QModelIndexList containerList;
1351 for ( const auto index : indexes )
1352 {
1353 const auto indexType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
1354 if ( indexType == QgsAttributesFormData::Container )
1355 {
1356 containerList << index;
1357 }
1358 }
1359
1360 if ( containerList.size() == 0 )
1361 return indexes;
1362
1363 QModelIndexList curatedIndexes;
1364
1365 // Iterate searching if current index is child of any container in containerList (recursively)
1366 for ( const auto index : indexes )
1367 {
1368 QModelIndex parent = index.parent();
1369 bool redundantChild = false;
1370
1371 while ( parent.isValid() )
1372 {
1373 if ( containerList.contains( parent ) )
1374 {
1375 redundantChild = true;
1376 break;
1377 }
1378
1379 parent = parent.parent();
1380 }
1381
1382 if ( !redundantChild )
1383 curatedIndexes << index;
1384 }
1385
1386 return curatedIndexes;
1387}
1388
1389QMimeData *QgsAttributesFormLayoutModel::mimeData( const QModelIndexList &indexes ) const
1390{
1391 if ( indexes.count() == 0 )
1392 return nullptr;
1393
1394 // Discard redundant indexes
1395 QModelIndexList curatedIndexes;
1396 if ( indexes.count() > 1 )
1397 {
1398 curatedIndexes = curateIndexesForMimeData( indexes );
1399 }
1400 else
1401 {
1402 curatedIndexes = indexes;
1403 }
1404
1405 const QStringList types = mimeTypes();
1406 if ( types.isEmpty() )
1407 return nullptr;
1408
1409 QMimeData *data = new QMimeData();
1410 const QString format = types.at( 0 );
1411 QByteArray encoded;
1412 QDataStream stream( &encoded, QIODevice::WriteOnly );
1413
1414 // Sort indexes since their order reflects selection order
1415 std::sort( curatedIndexes.begin(), curatedIndexes.end(), [this]( const QModelIndex &a, const QModelIndex &b ) { return indexLessThan( a, b ); } );
1416
1417 for ( const QModelIndex &index : std::as_const( curatedIndexes ) )
1418 {
1419 if ( index.isValid() )
1420 {
1421 QDomDocument doc;
1422
1423 QDomElement rootElem = doc.createElement( u"form_layout_mime"_s );
1425 QDomElement editorElem = editor->toDomElement( doc );
1426 rootElem.appendChild( editorElem );
1427
1428 doc.appendChild( rootElem );
1429 stream << doc.toString( -1 );
1430 }
1431 }
1432
1433 data->setData( format, encoded );
1434 return data;
1435}
1436
1437bool QgsAttributesFormLayoutModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
1438{
1439 Q_UNUSED( column )
1440 bool isDropSuccessful = false;
1441 int rows = 0;
1442
1443 if ( row == -1 ) // Dropped at invalid index
1444 row = rowCount( parent ); // Let's append the item
1445
1446 if ( action == Qt::IgnoreAction )
1447 {
1448 isDropSuccessful = true;
1449 }
1450 else if ( data->hasFormat( u"application/x-qgsattributesformavailablewidgetsrelement"_s ) )
1451 {
1452 Q_ASSERT( action == Qt::CopyAction ); // External drop
1453 QByteArray itemData = data->data( u"application/x-qgsattributesformavailablewidgetsrelement"_s );
1454 QDataStream stream( &itemData, QIODevice::ReadOnly );
1455
1456 while ( !stream.atEnd() )
1457 {
1458 QString itemId;
1459 int itemTypeInt;
1460 QString itemName;
1461 stream >> itemId >> itemTypeInt >> itemName;
1462
1463 const auto itemType = static_cast< QgsAttributesFormData::AttributesFormItemType >( itemTypeInt );
1464 insertChild( parent, row + rows, itemId, itemType, itemName );
1465
1466 isDropSuccessful = true;
1467
1468 QModelIndex addedIndex = index( row + rows, 0, parent );
1469 emit externalItemDropped( addedIndex );
1470
1471 rows++;
1472 }
1473 }
1474 else if ( data->hasFormat( u"application/x-qgsattributesformlayoutelement"_s ) )
1475 {
1476 Q_ASSERT( action == Qt::MoveAction ); // Internal move
1477 QByteArray itemData = data->data( u"application/x-qgsattributesformlayoutelement"_s );
1478 QDataStream stream( &itemData, QIODevice::ReadOnly );
1479
1480 while ( !stream.atEnd() )
1481 {
1482 QString text;
1483 stream >> text;
1484
1485 QDomDocument doc;
1486 if ( !doc.setContent( text ) )
1487 continue;
1488 const QDomElement rootElem = doc.documentElement();
1489 if ( rootElem.tagName() != "form_layout_mime"_L1 || !rootElem.hasChildNodes() )
1490 continue;
1491 const QDomElement childElem = rootElem.firstChild().toElement();
1492
1493 // Build editor element from XML and add/insert it to parent
1495 beginInsertRows( parent, row + rows, row + rows );
1496 loadAttributeEditorElementItem( editor, itemForIndex( parent ), row + rows );
1497 endInsertRows();
1498
1499 isDropSuccessful = true;
1500
1501 QModelIndex addedIndex = index( row + rows, 0, parent );
1502 emit internalItemDropped( addedIndex );
1503
1504 rows++;
1505 }
1506 }
1507
1508 return isDropSuccessful;
1509}
1510
1511void QgsAttributesFormLayoutModel::updateFieldConfigForFieldItemsRecursive( QgsAttributesFormItem *parent, const QString &fieldName, const QgsAttributesFormData::FieldConfig &config )
1512{
1513 for ( int i = 0; i < parent->childCount(); i++ )
1514 {
1515 QgsAttributesFormItem *child = parent->child( i );
1516 if ( child->name() == fieldName && child->type() == QgsAttributesFormData::Field )
1517 {
1518 child->setData( ItemFieldConfigRole, QVariant::fromValue( config ) );
1519 child->setIcon( QgsGui::instance()->editorWidgetRegistry()->icon( config.mEditorWidgetType ) );
1520 emit fieldConfigDataChanged( child ); // Item's field config has changed, let views know about it
1521 }
1522
1523 if ( child->childCount() > 0 )
1524 {
1525 updateFieldConfigForFieldItemsRecursive( child, fieldName, config );
1526 }
1527 }
1528}
1529
1531{
1532 updateFieldConfigForFieldItemsRecursive( mRootItem.get(), fieldName, config );
1533}
1534
1535void QgsAttributesFormLayoutModel::updateAliasForFieldItemsRecursive( QgsAttributesFormItem *parent, const QString &fieldName, const QString &fieldAlias )
1536{
1537 for ( int i = 0; i < parent->childCount(); i++ )
1538 {
1539 QgsAttributesFormItem *child = parent->child( i );
1540 if ( child->name() == fieldName && child->type() == QgsAttributesFormData::Field )
1541 {
1542 child->setData( ItemDisplayRole, fieldAlias );
1543 const QModelIndex index = createIndex( child->row(), 0, child );
1544 emit dataChanged( index, index ); // Item's alias has changed, let views know about it
1545 }
1546
1547 if ( child->childCount() > 0 )
1548 {
1549 updateAliasForFieldItemsRecursive( child, fieldName, fieldAlias );
1550 }
1551 }
1552}
1553
1554void QgsAttributesFormLayoutModel::updateAliasForFieldItems( const QString &fieldName, const QString &fieldAlias )
1555{
1556 updateAliasForFieldItemsRecursive( mRootItem.get(), fieldName, fieldAlias );
1557}
1558
1559QList< QgsAddAttributeFormContainerDialog::ContainerPair > QgsAttributesFormLayoutModel::recursiveListOfContainers( QgsAttributesFormItem *parent ) const
1560{
1561 QList< QgsAddAttributeFormContainerDialog::ContainerPair > containerList;
1562 for ( int i = 0; i < parent->childCount(); i++ )
1563 {
1564 QgsAttributesFormItem *child = parent->child( i );
1565 if ( child->type() == QgsAttributesFormData::Container )
1566 {
1567 containerList << QgsAddAttributeFormContainerDialog::ContainerPair( child->name(), createIndex( child->row(), 0, child ) );
1568 }
1569
1570 if ( child->childCount() > 0 )
1571 {
1572 containerList.append( recursiveListOfContainers( child ) );
1573 }
1574 }
1575
1576 return containerList;
1577}
1578
1580{
1581 QgsAttributeEditorElement *widgetDef = nullptr;
1582
1584 const int indexType = static_cast< QgsAttributesFormData::AttributesFormItemType >( index.data( QgsAttributesFormModel::ItemTypeRole ).toInt() );
1585 const QString indexName = index.data( QgsAttributesFormModel::ItemNameRole ).toString();
1586 const QString indexId = index.data( QgsAttributesFormModel::ItemIdRole ).toString();
1587
1588 switch ( indexType )
1589 {
1591 {
1592 const int fieldIndex = mLayer->fields().lookupField( indexName );
1593 widgetDef = new QgsAttributeEditorField( indexName, fieldIndex, parent );
1594 break;
1595 }
1596
1598 {
1599 const QgsAction action { mLayer->actions()->action( indexId ) };
1600 widgetDef = new QgsAttributeEditorAction( action, parent );
1601 break;
1602 }
1603
1605 {
1606 const QgsRelation relation = mProject->relationManager()->relation( indexId );
1607
1610 relDef->setRelationWidgetTypeId( relationEditorConfig.mRelationWidgetType );
1611 relDef->setRelationEditorConfiguration( relationEditorConfig.mRelationWidgetConfig );
1612 relDef->setNmRelationId( relationEditorConfig.nmRelationId );
1613 relDef->setForceSuppressFormPopup( relationEditorConfig.forceSuppressFormPopup );
1614 relDef->setLabel( relationEditorConfig.label );
1615 widgetDef = relDef;
1616 break;
1617 }
1618
1620 {
1621 QgsAttributeEditorContainer *container = new QgsAttributeEditorContainer( indexName, parent, itemData.backgroundColor() );
1622 container->setColumnCount( itemData.columnCount() );
1623 // only top-level containers can be tabs
1625 bool isTopLevel = !index.parent().isValid();
1626 if ( type == Qgis::AttributeEditorContainerType::Tab && !isTopLevel )
1627 {
1628 // a tab container found which isn't at the top level -- reset it to a group box instead
1630 }
1631 container->setType( type );
1632 container->setCollapsed( itemData.collapsed() );
1633 container->setCollapsedExpression( itemData.collapsedExpression() );
1634 container->setVisibilityExpression( itemData.visibilityExpression() );
1635 container->setBackgroundColor( itemData.backgroundColor() );
1636
1637 QModelIndex childIndex;
1638 for ( int t = 0; t < rowCount( index ); t++ )
1639 {
1640 childIndex = this->index( t, 0, index );
1641 QgsAttributeEditorElement *element { createAttributeEditorWidget( childIndex, container ) };
1642 if ( element )
1643 container->addChildElement( element );
1644 }
1645 widgetDef = container;
1646 break;
1647 }
1648
1650 {
1652 element->setQmlCode( itemData.qmlElementEditorConfiguration().qmlCode );
1653 widgetDef = element;
1654 break;
1655 }
1656
1658 {
1661 widgetDef = element;
1662 break;
1663 }
1664
1666 {
1668 element->setText( itemData.textElementEditorConfiguration().text );
1669 widgetDef = element;
1670 break;
1671 }
1672
1674 {
1677 widgetDef = element;
1678 break;
1679 }
1680
1682 default:
1683 break;
1684 }
1685
1686 if ( widgetDef )
1687 {
1688 widgetDef->setShowLabel( itemData.showLabel() );
1689 widgetDef->setLabelStyle( itemData.labelStyle() );
1690 widgetDef->setHorizontalStretch( itemData.horizontalStretch() );
1691 widgetDef->setVerticalStretch( itemData.verticalStretch() );
1692 }
1693
1694 return widgetDef;
1695}
1696
1697QList< QgsAddAttributeFormContainerDialog::ContainerPair > QgsAttributesFormLayoutModel::listOfContainers() const
1698{
1699 return recursiveListOfContainers( mRootItem.get() );
1700}
1701
1703{
1704 beginInsertRows( parent, rowCount( parent ), rowCount( parent ) );
1705
1706 QgsAttributesFormItem *parentItem = itemForIndex( parent );
1707
1708 auto containerItem = std::make_unique< QgsAttributesFormItem >( QgsAttributesFormData::Container, name, QString(), parentItem );
1709
1711 itemData.setColumnCount( columnCount );
1713
1714 containerItem->setData( QgsAttributesFormModel::ItemDataRole, itemData );
1715 containerItem->setData( QgsAttributesFormModel::ItemIdRole, name ); // Make it searchable
1716 parentItem->addChild( std::move( containerItem ) );
1717
1718 endInsertRows();
1719}
1720
1721void QgsAttributesFormLayoutModel::insertChild( const QModelIndex &parent, int row, const QString &itemId, QgsAttributesFormData::AttributesFormItemType itemType, const QString &itemName )
1722{
1723 if ( row < 0 )
1724 return;
1725
1726 beginInsertRows( parent, row, row );
1727 auto item = std::make_unique< QgsAttributesFormItem >();
1728
1729 item->setData( QgsAttributesFormModel::ItemIdRole, itemId );
1730 item->setData( QgsAttributesFormModel::ItemTypeRole, itemType );
1731 item->setData( QgsAttributesFormModel::ItemNameRole, itemName );
1732
1733 itemForIndex( parent )->insertChild( row, std::move( item ) );
1734 endInsertRows();
1735}
1736
1737
1739 : QSortFilterProxyModel( parent )
1740{}
1741
1743{
1744 mModel = model;
1745 QSortFilterProxyModel::setSourceModel( mModel );
1746}
1747
1752
1754{
1755 return mFilterText;
1756}
1757
1759{
1760 // Since we want to allow refreshing the filter when, e.g.,
1761 // users switch to aliases, then we allow this method to be
1762 // executed even if previous and new filters are equal
1763
1764 mFilterText = filterText.trimmed();
1765 invalidate();
1766}
1767
1768bool QgsAttributesFormProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
1769{
1770 if ( mFilterText.isEmpty() )
1771 return true;
1772
1773 QModelIndex sourceIndex = sourceModel()->index( sourceRow, 0, sourceParent );
1774 if ( !sourceIndex.isValid() )
1775 return false;
1776
1777 // If name or alias match, accept it before any other checks
1778 if ( sourceIndex.data( QgsAttributesFormModel::ItemNameRole ).toString().contains( mFilterText, Qt::CaseInsensitive )
1779 || sourceIndex.data( QgsAttributesFormModel::ItemDisplayRole ).toString().contains( mFilterText, Qt::CaseInsensitive ) )
1780 return true;
1781
1782 // Child is accepted if any of its parents is accepted
1783 QModelIndex parent = sourceIndex.parent();
1784 while ( parent.isValid() )
1785 {
1786 if ( parent.data( QgsAttributesFormModel::ItemNameRole ).toString().contains( mFilterText, Qt::CaseInsensitive )
1787 || parent.data( QgsAttributesFormModel::ItemDisplayRole ).toString().contains( mFilterText, Qt::CaseInsensitive ) )
1788 return true;
1789
1790 parent = parent.parent();
1791 }
1792
1793 return false;
1794}
AttributeEditorContainerType
Attribute editor container types.
Definition qgis.h:5956
@ Action
A layer action element.
Definition qgis.h:5943
@ Container
A container.
Definition qgis.h:5938
@ QmlElement
A QML element.
Definition qgis.h:5941
@ Relation
A relation.
Definition qgis.h:5940
@ HtmlElement
A HTML element.
Definition qgis.h:5942
@ TextElement
A text element.
Definition qgis.h:5944
@ SpacerElement
A spacer element.
Definition qgis.h:5945
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:764
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:774
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:784
QString customComment
Definition qgsfield.h:71
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