18#include "moc_qgsattributesformmodel.cpp"
35 if ( !layer || idx < 0 || idx >= layer->
fields().
count() )
53QgsAttributesFormData::FieldConfig::operator QVariant()
55 return QVariant::fromValue<QgsAttributesFormData::FieldConfig>( *
this );
53QgsAttributesFormData::FieldConfig::operator QVariant() {
…}
58QgsAttributesFormData::RelationEditorConfiguration::operator QVariant()
60 return QVariant::fromValue<QgsAttributesFormData::RelationEditorConfiguration>( *
this );
58QgsAttributesFormData::RelationEditorConfiguration::operator QVariant() {
…}
65 return mContainerType;
70 mContainerType = type;
80 mLabelStyle = labelStyle;
90 mShowLabel = showLabel;
95 return mVisibilityExpression;
100 mVisibilityExpression = visibilityExpression;
105 return mCollapsedExpression;
110 mCollapsedExpression = collapsedExpression;
115 return mRelationEditorConfiguration;
120 mRelationEditorConfiguration = relationEditorConfiguration;
125 return mQmlElementEditorConfiguration;
130 mQmlElementEditorConfiguration = qmlElementEditorConfiguration;
136 return mHtmlElementEditorConfiguration;
141 mHtmlElementEditorConfiguration = htmlElementEditorConfiguration;
146 return mSpacerElementEditorConfiguration;
151 mSpacerElementEditorConfiguration = spacerElementEditorConfiguration;
156 return mBackgroundColor;
161 mBackgroundColor = backgroundColor;
166 return mTextElementEditorConfiguration;
171 mTextElementEditorConfiguration = textElementEditorConfiguration;
177 , mDisplayName( displayName )
184 , mDisplayName( displayName )
193 return mChildren.at(
row ).get();
200 if ( !mChildren.empty() && itemId.trimmed().isEmpty() )
204 const auto it = std::find_if( mChildren.cbegin(), mChildren.cend(), [itemType, itemId](
const std::unique_ptr< QgsAttributesFormItem > &item ) {
205 return item->type() == itemType && item->id() == itemId;
208 if ( it != mChildren.cend() )
216 if ( !mChildren.empty() && itemId.trimmed().isEmpty() )
219 for (
const auto &
child : std::as_const( mChildren ) )
237 return static_cast< int >( mChildren.size() );
245 const auto it = std::find_if( mParent->mChildren.cbegin(), mParent->mChildren.cend(), [
this](
const std::unique_ptr< QgsAttributesFormItem > &item ) {
246 return item.get() == this;
249 if ( it != mParent->mChildren.cend() )
251 return static_cast< int >( std::distance( mParent->mChildren.cbegin(), it ) );
262 if ( !item->mParent )
263 item->mParent =
this;
265 mChildren.push_back( std::move( item ) );
270 if ( position < 0 || position >
static_cast< int >( mChildren.size() ) || !item )
273 if ( !item->mParent )
274 item->mParent =
this;
276 mChildren.insert( mChildren.begin() + position, std::move( item ) );
281 if ( index >= 0 && index <
static_cast< int >( mChildren.size() ) )
282 mChildren.erase( mChildren.begin() + index );
297 return QVariant::fromValue( mData );
305 return QVariant::fromValue( mFieldConfigData );
322 mName = value.toString();
327 mDisplayName = value.toString();
337 mId = value.toString();
352 : QAbstractItemModel( parent )
355 , mProject( project )
363 if (
index.isValid() )
378 return parentItem ? parentItem->
childCount() : 0;
391 for (
int i = 0; i < std::min( pathA.size(), pathB.size() ); i++ )
393 if ( pathA.at( i ) != pathB.at( i ) )
395 return pathA.at( i ) < pathB.at( i );
399 return pathA.size() < pathB.size();
414 if ( !hasIndex( row, column,
parent ) )
415 return QModelIndex();
419 return QModelIndex();
422 return createIndex( row, column, childItem );
424 return QModelIndex();
429 if ( !
index.isValid() )
430 return QModelIndex();
435 return ( parentItem !=
mRootItem.get() && parentItem !=
nullptr )
436 ? createIndex( parentItem->
row(), 0, parentItem )
443 return item ? createIndex( item->
row(), 0, item ) : QModelIndex();
449 return item ? createIndex( item->
row(), 0, item ) : QModelIndex();
460 emit dataChanged( QModelIndex(), QModelIndex(), QVector<int>() << Qt::DisplayRole << Qt::ForegroundRole << Qt::FontRole );
471 if ( !
index.isValid() )
472 return Qt::NoItemFlags;
474 Qt::ItemFlags
flags = Qt::ItemIsEnabled;
479 flags =
flags | Qt::ItemIsDragEnabled | Qt::ItemIsSelectable;
488 return orientation == Qt::Horizontal && role == Qt::DisplayRole ? tr(
"Available Widgets" ) : QVariant {};
504 for (
int i = 0; i < fields.
size(); ++i )
508 itemData.setShowLabel(
true );
512 auto item = std::make_unique< QgsAttributesFormItem >();
521 itemFields->addChild( std::move( item ) );
524 mRootItem->addChild( std::move( itemFields ) );
536 if ( polymorphicRelation.
isValid() )
538 name = QStringLiteral(
"%1 (%2)" ).arg( relation.name(), polymorphicRelation.
name() );
542 name = relation.
name();
547 auto itemRelation = std::make_unique< QgsAttributesFormItem >();
550 itemRelation->setData(
ItemIdRole, relation.id() );
552 itemRelations->addChild( std::move( itemRelation ) );
555 mRootItem->addChild( std::move( itemRelations ) );
560 mRootItem->addChild( std::move( itemActions ) );
570 itemOtherWidgets->addChild( std::move( itemQml ) );
574 auto itemHtml = std::make_unique< QgsAttributesFormItem >(
QgsAttributesFormData::HtmlWidget, itemHtmlData, QStringLiteral(
"HTML Widget" ), tr(
"HTML Widget" ) );
575 itemOtherWidgets->addChild( std::move( itemHtml ) );
579 auto itemText = std::make_unique< QgsAttributesFormItem >(
QgsAttributesFormData::TextWidget, itemTextData, QStringLiteral(
"Text Widget" ), tr(
"Text Widget" ) );
580 itemOtherWidgets->addChild( std::move( itemText ) );
585 itemOtherWidgets->addChild( std::move( itemSpacer ) );
587 mRootItem->addChild( std::move( itemOtherWidgets ) );
597 beginRemoveRows( actionsIndex, 0, itemActions->
childCount() );
602 for (
const auto &action : std::as_const( actions ) )
604 if ( action.isValid() && action.runable() && ( action.actionScopes().contains( QStringLiteral(
"Feature" ) ) || action.actionScopes().contains( QStringLiteral(
"Layer" ) ) ) )
610 beginInsertRows( actionsIndex, 0, count );
611 populateActionItems( actions );
615void QgsAttributesAvailableWidgetsModel::populateActionItems(
const QList<QgsAction> actions )
620 for (
const auto &action : std::as_const( actions ) )
622 if ( action.isValid() && action.runable() && ( action.actionScopes().contains( QStringLiteral(
"Feature" ) ) || action.actionScopes().contains( QStringLiteral(
"Layer" ) ) ) )
624 const QString actionTitle { action.shortTitle().isEmpty() ? action.name() : action.shortTitle() };
629 auto itemAction = std::make_unique< QgsAttributesFormItem >();
630 itemAction->setData(
ItemIdRole, action.id().toString() );
635 itemActions->
addChild( std::move( itemAction ) );
642 if ( !
index.isValid() )
651 bool invalidRelation =
false;
659 case Qt::DisplayRole:
669 case Qt::ToolTipRole:
674 if ( !cfg.mAlias.isEmpty() )
675 return tr(
"%1 (%2)" ).arg( item->
name(), cfg.mAlias );
683 return tr(
"Invalid relation" );
689 case Qt::DecorationRole:
692 case Qt::BackgroundRole:
695 return QBrush( Qt::lightGray );
700 case Qt::ForegroundRole:
706 return QBrush( QColor( Qt::lightGray ) );
712 return QBrush( QColor( 255, 0, 0 ) );
724 QFont font = QFont();
725 font.setItalic(
true );
738 return item->
data( role );
747 if ( !
index.isValid() )
751 bool result = item->
setData( role, value );
761 return Qt::CopyAction;
766 return QStringList() << QStringLiteral(
"application/x-qgsattributesformavailablewidgetsrelement" );
771 if ( indexes.count() == 0 )
775 if ( types.isEmpty() )
778 QMimeData *
data =
new QMimeData();
779 const QString format = types.at( 0 );
781 QDataStream stream( &encoded, QIODevice::WriteOnly );
784 QModelIndexList sortedIndexes = indexes;
786 std::sort( sortedIndexes.begin(), sortedIndexes.end(), [
this](
const QModelIndex &a,
const QModelIndex &b ) {
787 return indexLessThan( a, b );
790 for (
const QModelIndex &
index : std::as_const( sortedIndexes ) )
792 if (
index.isValid() )
798 stream << itemId << itemType << itemName;
802 data->setData( format, encoded );
813 return createIndex( row, 0, item );
815 return QModelIndex();
825 return createIndex( row, 0, item );
827 return QModelIndex();
837 return createIndex( row, 0, item );
839 return QModelIndex();
845 return QModelIndex();
849 return QModelIndex();
852 return item ? createIndex( item->
row(), 0, item ) : QModelIndex();
864 return orientation == Qt::Horizontal && role == Qt::DisplayRole ? tr(
"Form Layout" ) : QVariant {};
869 if ( !
index.isValid() )
870 return Qt::ItemIsDropEnabled;
872 Qt::ItemFlags
flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
876 flags |= Qt::ItemIsDropEnabled;
892 loadAttributeEditorElementItem( editorElement,
mRootItem.get() );
907 auto editorItem = std::make_unique< QgsAttributesFormItem >();
909 switch ( editorElement->
type() )
914 setCommonProperties( itemData );
922 if ( fieldIndex != -1 )
934 if ( action.isValid() )
937 setCommonProperties( itemData );
939 editorItem->setData(
ItemIdRole, action.id().toString() );
940 editorItem->setData(
ItemNameRole, action.shortTitle().isEmpty() ? action.name() : action.shortTitle() );
954 setCommonProperties( itemData );
962 relationEditorConfig.
label = relationEditor->
label();
966 if ( relation.
id().isEmpty() )
985 setCommonProperties( itemData );
1004 const QList<QgsAttributeEditorElement *> children = container->
children();
1007 loadAttributeEditorElementItem( childElement, editorItem.get() );
1016 setCommonProperties( itemData );
1032 setCommonProperties( itemData );
1048 setCommonProperties( itemData );
1051 textEdConfig.
text = textElementEditor->
text();
1064 setCommonProperties( itemData );
1079 QgsDebugError( QStringLiteral(
"Not loading invalid attribute editor type..." ) );
1084 if ( position >= 0 && position < parent->childCount() )
1086 parent->insertChild( position, std::move( editorItem ) );
1090 parent->addChild( std::move( editorItem ) );
1096 if ( !
index.isValid() )
1110 const bool invalidField = fieldIndex == -1;
1114 bool invalidRelation =
false;
1122 case Qt::DisplayRole:
1128 if ( item->
id().isEmpty() )
1130 return tr(
"Invalid relation" );
1136 return item->
name();
1142 case Qt::ToolTipRole:
1148 return tr(
"Invalid field" );
1152 return item->
name();
1158 if ( !item->
id().isEmpty() )
1161 return tr(
"Invalid relation" );
1168 case Qt::DecorationRole:
1169 return item->
icon();
1171 case Qt::BackgroundRole:
1174 return QBrush( Qt::lightGray );
1179 case Qt::ForegroundRole:
1185 return QBrush( QColor( 255, 0, 0 ) );
1189 return QBrush( QColor( Qt::lightGray ) );
1195 if ( invalidRelation )
1197 return QBrush( QColor( 255, 0, 0 ) );
1201 return QBrush( QColor( Qt::lightGray ) );
1214 QFont font = QFont();
1215 font.setItalic(
true );
1224 QFont font = QFont();
1225 font.setItalic(
true );
1238 return item->
data( role );
1247 if ( !
index.isValid() )
1254 bool result = item->
setData( role, value );
1272 beginRemoveRows(
parent, row, row + count - 1 );
1273 for (
int r = 0; r < count; ++r )
1281 beginRemoveRows(
parent, row, row );
1290 return Qt::MoveAction;
1295 return Qt::DropAction::CopyAction | Qt::DropAction::MoveAction;
1300 return QStringList() << QStringLiteral(
"application/x-qgsattributesformlayoutelement" ) << QStringLiteral(
"application/x-qgsattributesformavailablewidgetsrelement" );
1303QModelIndexList QgsAttributesFormLayoutModel::curateIndexesForMimeData(
const QModelIndexList &indexes )
const
1305 QModelIndexList containerList;
1306 for (
const auto index : indexes )
1311 containerList <<
index;
1315 if ( containerList.size() == 0 )
1318 QModelIndexList curatedIndexes;
1321 for (
const auto index : indexes )
1324 bool redundantChild =
false;
1326 while (
parent.isValid() )
1328 if ( containerList.contains(
parent ) )
1330 redundantChild =
true;
1337 if ( !redundantChild )
1338 curatedIndexes <<
index;
1341 return curatedIndexes;
1346 if ( indexes.count() == 0 )
1350 QModelIndexList curatedIndexes;
1351 if ( indexes.count() > 1 )
1353 curatedIndexes = curateIndexesForMimeData( indexes );
1357 curatedIndexes = indexes;
1361 if ( types.isEmpty() )
1364 QMimeData *
data =
new QMimeData();
1365 const QString format = types.at( 0 );
1367 QDataStream stream( &encoded, QIODevice::WriteOnly );
1370 std::sort( curatedIndexes.begin(), curatedIndexes.end(), [
this](
const QModelIndex &a,
const QModelIndex &b ) {
1371 return indexLessThan( a, b );
1374 for (
const QModelIndex &
index : std::as_const( curatedIndexes ) )
1376 if (
index.isValid() )
1380 QDomElement rootElem = doc.createElement( QStringLiteral(
"form_layout_mime" ) );
1383 rootElem.appendChild( editorElem );
1385 doc.appendChild( rootElem );
1386 stream << doc.toString( -1 );
1390 data->setData( format, encoded );
1397 bool isDropSuccessful =
false;
1403 if ( action == Qt::IgnoreAction )
1405 isDropSuccessful =
true;
1407 else if (
data->hasFormat( QStringLiteral(
"application/x-qgsattributesformavailablewidgetsrelement" ) ) )
1409 Q_ASSERT( action == Qt::CopyAction );
1410 QByteArray itemData =
data->data( QStringLiteral(
"application/x-qgsattributesformavailablewidgetsrelement" ) );
1411 QDataStream stream( &itemData, QIODevice::ReadOnly );
1413 while ( !stream.atEnd() )
1418 stream >> itemId >> itemTypeInt >> itemName;
1423 isDropSuccessful =
true;
1425 QModelIndex addedIndex =
index( row + rows, 0,
parent );
1431 else if (
data->hasFormat( QStringLiteral(
"application/x-qgsattributesformlayoutelement" ) ) )
1433 Q_ASSERT( action == Qt::MoveAction );
1434 QByteArray itemData =
data->data( QStringLiteral(
"application/x-qgsattributesformlayoutelement" ) );
1435 QDataStream stream( &itemData, QIODevice::ReadOnly );
1437 while ( !stream.atEnd() )
1443 if ( !doc.setContent( text ) )
1445 const QDomElement rootElem = doc.documentElement();
1446 if ( rootElem.tagName() != QLatin1String(
"form_layout_mime" ) || !rootElem.hasChildNodes() )
1448 const QDomElement childElem = rootElem.firstChild().toElement();
1452 beginInsertRows(
parent, row + rows, row + rows );
1456 isDropSuccessful =
true;
1458 QModelIndex addedIndex =
index( row + rows, 0,
parent );
1465 return isDropSuccessful;
1468void QgsAttributesFormLayoutModel::updateAliasForFieldItemsRecursive(
QgsAttributesFormItem *parent,
const QString &fieldName,
const QString &fieldAlias )
1470 for (
int i = 0; i <
parent->childCount(); i++ )
1476 const QModelIndex
index = createIndex( child->
row(), 0, child );
1482 updateAliasForFieldItemsRecursive( child, fieldName, fieldAlias );
1489 updateAliasForFieldItemsRecursive(
mRootItem.get(), fieldName, fieldAlias );
1492QList< QgsAddAttributeFormContainerDialog::ContainerPair > QgsAttributesFormLayoutModel::recursiveListOfContainers(
QgsAttributesFormItem *parent )
const
1494 QList< QgsAddAttributeFormContainerDialog::ContainerPair > containerList;
1495 for (
int i = 0; i <
parent->childCount(); i++ )
1505 containerList.append( recursiveListOfContainers( child ) );
1509 return containerList;
1521 switch ( indexType )
1558 bool isTopLevel = !
index.parent().isValid();
1570 QModelIndex childIndex;
1578 widgetDef = container;
1586 widgetDef = element;
1594 widgetDef = element;
1602 widgetDef = element;
1610 widgetDef = element;
1632 return recursiveListOfContainers(
mRootItem.get() );
1641 std::unique_ptr< QgsAttributesFormItem > containerItem = std::make_unique< QgsAttributesFormItem >(
QgsAttributesFormData::Container, name, QString(), parentItem );
1649 parentItem->
addChild( std::move( containerItem ) );
1659 beginInsertRows(
parent, row, row );
1660 std::unique_ptr< QgsAttributesFormItem > item = std::make_unique< QgsAttributesFormItem >();
AttributeEditorContainerType
Attribute editor container types.
@ Action
A layer action element.
@ QmlElement
A QML element.
@ HtmlElement
A HTML element.
@ TextElement
A text element.
@ SpacerElement
A spacer element.
QList< QgsAction > actions(const QString &actionScope=QString()) const
Returns a list of actions that are available in the given action scope.
QgsAction action(QUuid id) const
Gets an action by its id.
Utility class that encapsulates an action based on vector attributes.
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.
Encapsulate a field in an attribute table or data source.
Qgis::FieldDomainSplitPolicy splitPolicy() const
Returns the field's split policy, which indicates how field values should be handled during a split o...
Qgis::FieldDuplicatePolicy duplicatePolicy() const
Returns the field's duplicate policy, which indicates how field values should be handled during a dup...
Qgis::FieldDomainMergePolicy mergePolicy() const
Returns the field's merge policy, which indicates how field values should be handled during a merge o...
QgsFieldConstraints constraints
Container of fields for a vector layer.
Q_INVOKABLE int indexOf(const QString &fieldName) const
Gets the field index from the field name.
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).
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
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.
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,...
QgsRelationManager * relationManager
static QgsProject * instance()
Returns the QgsProject singleton instance.
A container for the context for various read/write operations on objects.
QList< QgsRelation > referencedRelations(const QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
Q_INVOKABLE QgsRelation relation(const QString &id) const
Gets access to a relation by its id.
Represents a relationship between two vector layers.
Represents a vector layer which manages a vector based dataset.
QgsActionManager * actions()
Returns all layer actions defined on this layer.
QgsEditFormConfig editFormConfig
#define QgsDebugError(str)
The TabStyle struct defines color and font overrides for form fields, tabs and groups labels.