23#include <QApplication>
26#include "moc_qgspolymorphicrelation.cpp"
28using namespace Qt::StringLiterals;
31 : d( new QgsPolymorphicRelationPrivate() )
36 : d( new QgsPolymorphicRelationPrivate() )
44 , mContext( other.mContext )
48 : d( std::move( other.d ) )
49 , mContext( std::move( other.mContext ) )
58 mContext = other.mContext;
67 d = std::move( other.d );
68 mContext = std::move( other.mContext );
81 QDomElement elem = node.toElement();
83 if ( elem.tagName() !=
"relation"_L1 )
85 QgsLogger::warning( QApplication::translate(
"QgsPolymorphicRelation",
"Cannot create relation. Unexpected tag '%1'" ).arg( elem.tagName() ) );
93 QString
id = elem.attribute( u
"id"_s );
94 QString
name = elem.attribute( u
"name"_s );
95 QString relationStrength = elem.attribute( u
"relationStrength"_s );
96 QStringList
referencedLayerIds = elem.attribute( u
"referencedLayerIds"_s ).split(
"," );
98 QMap<QString, QgsMapLayer *> mapLayers = relationContext.
project()->
mapLayers();
101 relation.d->mReferencingLayer = qobject_cast<QgsVectorLayer *>( mapLayers[
referencingLayerId] );
105 relation.d->mRelationId =
id;
106 relation.d->mRelationName =
name;
109 QDomNodeList references = elem.elementsByTagName( u
"fieldRef"_s );
110 for (
int i = 0; i < references.size(); ++i )
112 QDomElement refEl = references.at( i ).toElement();
114 QString referencingField = refEl.attribute( u
"referencingField"_s );
115 QString referencedField = refEl.attribute( u
"referencedField"_s );
117 relation.
addFieldPair( referencingField, referencedField );
127 QDomElement elem = doc.createElement( u
"relation"_s );
128 elem.setAttribute( u
"id"_s, d->mRelationId );
129 elem.setAttribute( u
"name"_s, d->mRelationName );
130 elem.setAttribute( u
"referencingLayer"_s, d->mReferencingLayerId );
131 elem.setAttribute( u
"referencedLayerField"_s, d->mReferencedLayerField );
132 elem.setAttribute( u
"referencedLayerExpression"_s, d->mReferencedLayerExpression );
133 elem.setAttribute( u
"referencedLayerIds"_s, d->mReferencedLayerIds.join(
"," ) );
137 for (
const QString &layerId : std::as_const( d->mReferencedLayerIds ) )
138 Q_ASSERT( !layerId.contains(
"," ) );
142 QDomElement referenceElem = doc.createElement( u
"fieldRef"_s );
143 referenceElem.setAttribute( u
"referencingField"_s, pair.first );
144 referenceElem.setAttribute( u
"referencedField"_s, pair.second );
145 elem.appendChild( referenceElem );
148 node.appendChild( elem );
153 if ( d->mRelationId ==
id )
165 d->mReferencingLayerId =
id;
180 d->mFieldPairs << fieldPair;
186 return d->mRelationId;
197 return d->mReferencingLayerId;
202 return d->mReferencingLayer;
207 return d->mFieldPairs;
214 if ( d->mReferencedLayerIds.contains( layerId ) )
236 attrs << d->mReferencingLayer->fields().lookupField( pair.first );
243 return d->mValid && !d->mReferencingLayer.isNull() && !d->mReferencedLayerField.isNull() && d->mReferencingLayer.data()->isValid() && !d->mReferencedLayerExpression.isNull();
248 return d->mReferencedLayerField == other.d->mReferencedLayerField
249 && d->mReferencedLayerExpression == other.d->mReferencedLayerExpression
250 && d->mReferencingLayerId == other.d->mReferencingLayerId
251 && d->mFieldPairs == other.d->mFieldPairs;
256 const QMap<QString, QgsMapLayer *> &mapLayers = mContext.project()->mapLayers();
259 d->mReferencingLayer = mapLayers.contains( d->mReferencingLayerId ) ? qobject_cast<QgsVectorLayer *>( mapLayers[d->mReferencingLayerId] ) :
nullptr;
260 d->mReferencedLayersMap.clear();
262 if ( d->mRelationId.isEmpty() )
269 if ( !d->mReferencingLayer )
271 QgsDebugMsgLevel( u
"Invalid relation: referencing layer does not exist. ID: %1"_s.arg( d->mReferencingLayerId ), 4 );
276 if ( d->mReferencingLayer->fields().lookupField( d->mReferencedLayerField ) == -1 )
278 QgsDebugMsgLevel( u
"Invalid relation: referenced layer field \"%1\" does not exist in layer with ID: %2"_s.arg( d->mReferencedLayerField, d->mReferencingLayerId ), 4 );
283 if ( d->mReferencedLayerExpression.trimmed().isNull() )
285 QgsDebugMsgLevel( u
"Invalid relation: referenced layer expression \"%1\" is missing"_s.arg( d->mReferencedLayerExpression ), 4 );
293 d->mReferencedLayersMap.insert( referencedLayerId, qobject_cast<QgsVectorLayer *>( mapLayers[referencedLayerId] ) );
295 if ( !d->mReferencedLayersMap[referencedLayerId] || !d->mReferencedLayersMap[referencedLayerId]->isValid() )
297 QgsDebugMsgLevel( u
"Invalid relation: referenced layer does not exist. ID: %1"_s.arg( d->mReferencedLayersMap[referencedLayerId]->id() ), 4 );
303 if ( d->mFieldPairs.count() == 0 )
305 QgsDebugMsgLevel( u
"Invalid relation: no pair of field is specified."_s, 4 );
312 if ( d->mReferencingLayer->fields().lookupField( pair.first ) == -1 )
314 QgsDebugError( u
"Invalid relation: field %1 does not exist in referencing layer %2"_s.arg( pair.first, d->mReferencingLayer->name() ) );
321 if ( d->mReferencedLayersMap[referencedLayerId]->fields().lookupField( pair.second ) == -1 )
323 QgsDebugError( u
"Invalid relation: field %1 does not exist in referenced layer %2"_s.arg( pair.second, d->mReferencedLayersMap[referencedLayerId]->name() ) );
333 if ( d->mRelationName ==
name && !
name.isEmpty() )
337 d->mRelationName =
name;
343 if ( d->mRelationName.isEmpty() )
344 return QObject::tr(
"Polymorphic relations for \"%1\"" ).arg( d->mReferencingLayer ? d->mReferencingLayer->name() : u
"<NO LAYER>"_s );
346 return d->mRelationName;
358 return d->mReferencedLayerField;
370 return d->mReferencedLayerExpression;
382 return d->mReferencedLayerIds;
387 return d->mRelationStrength;
393 d->mRelationStrength = relationStrength;
399 QList<QgsRelation> relations;
409 const QString referencedLayerName = d->mReferencedLayersMap[referencedLayerId]->
name();
411 relation.
setId( u
"%1_%2"_s.arg( d->mRelationId, referencedLayerId ) );
414 relation.
setName( u
"Generated for \"%1\""_s.arg( referencedLayerName ) );
418 const QList<QgsRelation::FieldPair> constFieldPairs =
fieldPairs();
425 relations << relation;
431QString QgsPolymorphicRelation::upgradeGeneratedRelationId(
const QString &oldRelationId )
const
439 const QString referencedLayerName = d->mReferencedLayersMap[referencedLayerId]->name();
440 if ( oldRelationId == u
"%1_%2"_s.arg( d->mRelationId, referencedLayerName ) )
442 return u
"%1_%2"_s.arg( d->mRelationId, referencedLayerId );
451 if ( !layer || !layer->
isValid() )
457 return expr.
evaluate( &context ).toString();
RelationshipStrength
Relationship strength.
@ Association
Loose relation, related elements are not part of the parent and a parent copy will not copy any child...
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Handles parsing and evaluation of expressions (formerly called "search strings").
QVariant evaluate()
Evaluate the feature and return the result.
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
static void warning(const QString &msg)
Goes to qWarning.
QgsAttributeList referencedFields(const QString &layerId) const
Returns a list of attributes used to form the referenced fields (most likely primary key) on the refe...
QString layerRepresentation(const QgsVectorLayer *layer) const
Returns layer representation as evaluated string.
QList< QgsRelation > generateRelations() const
Returns a list of generated relations, based on the currently set referencedLayerIds().
void setReferencedLayerIds(const QStringList &childRelationIds)
Sets a list of layer ids to be used as potential referenced layers.
QString referencedLayerExpression
void setReferencedLayerExpression(const QString &expression)
Sets the expression to identify the parent layer.
void setReferencedLayerField(const QString &referencedLayerField)
Sets the field in the referencing layer where the referenced layer identifier is stored.
void generateId()
Generate a (project-wide) unique id for this relation.
void setReferencingLayer(const QString &id)
Set the referencing (child) layer id.
QList< QgsRelation::FieldPair > fieldPairs() const
Returns the field pairs which form this relation The first element of each pair are the field names o...
void writeXml(QDomNode &node, QDomDocument &doc) const
Writes a relation to an XML structure.
void addFieldPair(const QString &referencingField, const QString &referencedField)
Add a field pair which is part of this relation The first element of each pair are the field names of...
~QgsPolymorphicRelation()
void setRelationStrength(Qgis::RelationshipStrength relationStrength)
Sets the relation strength for all the generated normal relations.
bool hasEqualDefinition(const QgsPolymorphicRelation &other) const
Compares the two QgsRelation, ignoring the name and the ID.
static Q_DECL_DEPRECATED QgsPolymorphicRelation createFromXml(const QDomNode &node, QgsReadWriteContext &context)
Creates a relation from an XML structure.
QString referencingLayerId() const
Access the referencing (child) layer's id This is the layer which has the field(s) which point to ano...
void updateRelationStatus()
Updates the validity status of this relation.
Qgis::RelationshipStrength strength() const
Returns the relation strength for all the generated normal relations.
QgsVectorLayer * referencingLayer
QStringList referencedLayerIds() const
Returns a list of layer ids to be used as potential referenced layers.
QgsPolymorphicRelation()
Default constructor.
QgsAttributeList referencingFields() const
Returns a list of attributes used to form the referencing fields (foreign key) on the referencing (ch...
QString referencedLayerField
void setName(const QString &name)
Set a name for this relation.
void setId(const QString &id)
Set an id for this relation.
QgsPolymorphicRelation & operator=(const QgsPolymorphicRelation &other)
Copies a relation.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
QMap< QString, QgsMapLayer * > mapLayers(const bool validOnly=false) const
Returns a map of all registered layers by layer ID.
A container for the context for various read/write operations on objects.
const QgsProject * project() const
Gets the associated project.
Defines a relation between matching fields of the two involved tables of a relation.
Represents a relationship between two vector layers.
void setId(const QString &id)
Set an id for this relation.
void setReferencedLayer(const QString &id)
Set the referenced (parent) layer id.
void setPolymorphicRelationId(const QString &polymorphicRelationId)
Sets the parent polymorphic relation id.
void setStrength(Qgis::RelationshipStrength strength)
Set a strength for this relation.
Q_INVOKABLE void addFieldPair(const QString &referencingField, const QString &referencedField)
Add a field pair which is part of this relation The first element of each pair are the field names of...
void setReferencingLayer(const QString &id)
Set the referencing (child) layer id.
void setName(const QString &name)
Set a name for this relation.
Represents a vector layer which manages a vector based dataset.
QgsExpressionContext createExpressionContext() const final
This method needs to be reimplemented in all classes which implement this interface and return an exp...
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
QList< int > QgsAttributeList
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)