26#include <QApplication>
28#include "moc_qgsrelation.cpp"
31 : d( new QgsRelationPrivate() )
36 : d( new QgsRelationPrivate() )
45 , mContext( other.mContext )
50 : d( std::move( other.d ) )
51 , mContext( std::move( other.mContext ) )
60 mContext = other.mContext;
69 d = std::move( other.d );
70 mContext = std::move( other.mContext );
76 QDomElement elem = node.toElement();
78 if ( elem.tagName() != QLatin1String(
"relation" ) )
80 QgsLogger::warning( QApplication::translate(
"QgsRelation",
"Cannot create relation. Unexpected tag '%1'" ).arg( elem.tagName() ) );
86 QString
referencedLayerId = elem.attribute( QStringLiteral(
"referencedLayer" ) );
87 QString
id = elem.attribute( QStringLiteral(
"id" ) );
89 QString
strength = elem.attribute( QStringLiteral(
"strength" ) );
91 QMap<QString, QgsMapLayer *> mapLayers = relationContext.
project()->
mapLayers();
115 relation.d->mReferencingLayer = qobject_cast<QgsVectorLayer *>(
referencingLayer );
117 relation.d->mReferencedLayer = qobject_cast<QgsVectorLayer *>(
referencedLayer );
118 relation.d->mRelationId =
id;
119 relation.d->mRelationName =
name;
122 QDomNodeList references = elem.elementsByTagName( QStringLiteral(
"fieldRef" ) );
123 for (
int i = 0; i < references.size(); ++i )
125 QDomElement refEl = references.at( i ).toElement();
127 QString referencingField = refEl.attribute( QStringLiteral(
"referencingField" ) );
128 QString referencedField = refEl.attribute( QStringLiteral(
"referencedField" ) );
130 relation.
addFieldPair( referencingField, referencedField );
140 QDomElement elem = doc.createElement( QStringLiteral(
"relation" ) );
141 elem.setAttribute( QStringLiteral(
"id" ), d->mRelationId );
142 elem.setAttribute( QStringLiteral(
"name" ), d->mRelationName );
143 elem.setAttribute( QStringLiteral(
"referencingLayer" ), d->mReferencingLayerId );
144 elem.setAttribute( QStringLiteral(
"referencedLayer" ), d->mReferencedLayerId );
147 for (
const FieldPair &pair : std::as_const( d->mFieldPairs ) )
149 QDomElement referenceElem = doc.createElement( QStringLiteral(
"fieldRef" ) );
150 referenceElem.setAttribute( QStringLiteral(
"referencingField" ), pair.first );
151 referenceElem.setAttribute( QStringLiteral(
"referencedField" ), pair.second );
152 elem.appendChild( referenceElem );
155 node.appendChild( elem );
169 d->mRelationName =
name;
182 d->mReferencingLayerId =
id;
190 d->mReferencedLayerId =
id;
198 d->mFieldPairs <<
FieldPair( referencingField, referencedField );
205 d->mFieldPairs << fieldPair;
217 QgsDebugMsgLevel( QStringLiteral(
"Filter conditions: '%1'" ).arg( filter ), 2 );
226 QStringList conditions;
228 if ( ! d->mPolymorphicRelationId.isEmpty() )
238 conditions << QStringLiteral(
" FALSE " );
242 for (
const FieldPair &pair : std::as_const( d->mFieldPairs ) )
244 QVariant val( feature.
attribute( pair.referencedField() ) );
246 if ( referencingIdx >= 0 )
257 return conditions.join( QLatin1String(
" AND " ) );
262 QStringList conditions;
264 for (
const FieldPair &pair : std::as_const( d->mFieldPairs ) )
268 if ( referencedIdx >= 0 )
281 QgsDebugMsgLevel( QStringLiteral(
"Filter conditions: '%1'" ).arg( conditions.join(
" AND " ) ), 2 );
298 ( void )d->mReferencedLayer->getFeatures( request ).nextFeature( f );
304 return d->mRelationName;
309 return d->mRelationStrength;
314 return d->mRelationId;
319 if ( !d->mFieldPairs.isEmpty() )
322 d->mRelationId = QStringLiteral(
"%1_%2_%3_%4" )
333 return d->mReferencingLayerId;
338 return d->mReferencingLayer;
343 return d->mReferencedLayerId;
348 return d->mReferencedLayer;
353 return d->mFieldPairs;
359 attrs.reserve( d->mFieldPairs.size() );
360 for (
const FieldPair &pair : std::as_const( d->mFieldPairs ) )
362 attrs << d->mReferencedLayer->fields().lookupField( pair.second );
371 for (
const FieldPair &pair : std::as_const( d->mFieldPairs ) )
373 attrs << d->mReferencingLayer->fields().lookupField( pair.first );
388 return std::find_if( fields.constBegin(), fields.constEnd(), [&](
const auto & fieldIdx )
390 if ( !referencingLayer()->fields().exists( fieldIdx ) )
396 } ) == fields.constEnd();
401 return d->mValid && !d->mReferencingLayer.isNull() && !d->mReferencedLayer.isNull() && d->mReferencingLayer.data()->isValid() && d->mReferencedLayer.data()->isValid();
409 if ( d->mReferencingLayer.isNull() )
411 if ( d->mReferencingLayerId.isEmpty() )
412 return QObject::tr(
"Referencing layer not set" );
414 return QObject::tr(
"Referencing layer %1 does not exist" ).arg( d->mReferencingLayerId );
416 else if ( !d->mReferencingLayer.data()->isValid() )
417 return QObject::tr(
"Referencing layer %1 is not valid" ).arg( d->mReferencingLayerId );
418 else if ( d->mReferencedLayer.isNull() )
420 if ( d->mReferencedLayerId.isEmpty() )
421 return QObject::tr(
"Referenced layer not set" );
423 return QObject::tr(
"Referenced layer %1 does not exist" ).arg( d->mReferencedLayerId );
425 else if ( !d->mReferencedLayer.data()->isValid() )
426 return QObject::tr(
"Referenced layer %1 is not valid" ).arg( d->mReferencedLayerId );
428 return d->mValidationError;
433 return d->mReferencedLayerId == other.d->mReferencedLayerId && d->mReferencingLayerId == other.d->mReferencingLayerId && d->mFieldPairs == other.d->mFieldPairs;
438 for (
const FieldPair &pair : std::as_const( d->mFieldPairs ) )
440 if ( pair.first == referencingField )
448 for (
const FieldPair &pair : std::as_const( d->mFieldPairs ) )
450 if ( pair.second == referencedField )
458 const QMap<QString, QgsMapLayer *> &mapLayers = mContext.project()->mapLayers();
460 d->mReferencingLayer = qobject_cast<QgsVectorLayer *>( mapLayers[d->mReferencingLayerId] );
461 d->mReferencedLayer = qobject_cast<QgsVectorLayer *>( mapLayers[d->mReferencedLayerId] );
465 if ( d->mRelationId.isEmpty() )
467 QgsDebugError( QStringLiteral(
"Invalid relation: no ID" ) );
468 d->mValidationError = QObject::tr(
"Relationship has no ID" );
473 if ( !d->mReferencedLayer )
475 QgsDebugMsgLevel( QStringLiteral(
"Invalid relation: referenced layer does not exist. ID: %1" ).arg( d->mReferencedLayerId ), 4 );
476 d->mValidationError = QObject::tr(
"Referenced layer %1 does not exist" ).arg( d->mReferencedLayerId );
479 else if ( !d->mReferencingLayer )
481 QgsDebugMsgLevel( QStringLiteral(
"Invalid relation: referencing layer does not exist. ID: %2" ).arg( d->mReferencingLayerId ), 4 );
482 d->mValidationError = QObject::tr(
"Referencing layer %1 does not exist" ).arg( d->mReferencingLayerId );
487 if ( d->mFieldPairs.count() < 1 )
489 QgsDebugMsgLevel( QStringLiteral(
"Invalid relation: no pair of field is specified." ), 4 );
490 d->mValidationError = QObject::tr(
"No fields specified for relationship" );
494 for (
const FieldPair &pair : std::as_const( d->mFieldPairs ) )
496 if ( -1 == d->mReferencingLayer->fields().lookupField( pair.first ) )
498 QgsDebugError( QStringLiteral(
"Invalid relation: field %1 does not exist in referencing layer %2" ).arg( pair.first, d->mReferencingLayer->name() ) );
499 d->mValidationError = QObject::tr(
"Field %1 does not exist in referencing layer %2" ).arg( pair.first, d->mReferencingLayer->name() );
503 else if ( -1 == d->mReferencedLayer->fields().lookupField( pair.second ) )
505 QgsDebugError( QStringLiteral(
"Invalid relation: field %1 does not exist in referenced layer %2" ).arg( pair.second, d->mReferencedLayer->name() ) );
506 d->mValidationError = QObject::tr(
"Field %1 does not exist in referenced layer %2" ).arg( pair.second, d->mReferencedLayer->name() );
524 return d->mPolymorphicRelationId;
529 if ( ! mContext.project() || ! mContext.project()->relationManager() )
532 return mContext.project()->relationManager()->polymorphicRelation( d->mPolymorphicRelationId );
537 if ( d->mPolymorphicRelationId.isNull() )
545 switch ( cardinality )
548 return QObject::tr(
"One-to-one" );
550 return QObject::tr(
"One-to-many" );
552 return QObject::tr(
"Many-to-one" );
554 return QObject::tr(
"Many-to-many" );
564 return QObject::tr(
"Association" );
566 return QObject::tr(
"Composition" );
RelationshipStrength
Relationship strength.
@ Composition
Fix relation, related elements are part of the parent and a parent copy will copy any children or del...
@ Association
Loose relation, related elements are not part of the parent and a parent copy will not copy any child...
RelationshipType
Relationship types.
@ Generated
A generated relation is a child of a polymorphic relation.
@ Normal
A normal relation.
RelationshipCardinality
Relationship cardinality.
@ ManyToMany
Many to many relationship.
@ ManyToOne
Many to one relationship.
@ OneToOne
One to one relationship.
@ OneToMany
One to many relationship.
static QString createFieldEqualityExpression(const QString &fieldName, const QVariant &value, QMetaType::Type fieldType=QMetaType::Type::UnknownType)
Create an expression allowing to evaluate if a field is equal to a value.
Wrapper for iterator of features from vector data provider or vector layer.
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
@ ConstraintNotNull
Field may not be null.
Encapsulate a field in an attribute table or data source.
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.
static void warning(const QString &msg)
Goes to qWarning.
Base class for all map layer types.
A relation where the referenced (parent) layer is calculated based on fields from the referencing (ch...
QString layerRepresentation(const QgsVectorLayer *layer) const
Returns layer representation as evaluated string.
QString referencedLayerField
virtual QString translate(const QString &context, const QString &sourceText, const char *disambiguation=nullptr, int n=-1) const =0
Translates a string using the Qt QTranslator mechanism.
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 QgsProjectTranslator * projectTranslator() const
Returns the project translator.
const QgsProject * project() const
Gets the associated project.
Defines a relation between matching fields of the two involved tables of a relation.
QString referencingField() const
Gets the name of the referencing (child) field.
QString referencedField() const
Gets the name of the referenced (parent) field.
QgsFeatureRequest getReferencedFeatureRequest(const QgsAttributes &attributes) const
Creates a request to return the feature on the referenced (parent) layer which is referenced by the p...
QList< int > referencedFields
static QString cardinalityToDisplayString(Qgis::RelationshipCardinality cardinality)
Returns a user-friendly translated string representing a relationship cardinality.
Q_INVOKABLE QgsFeature getReferencedFeature(const QgsFeature &feature) const
Creates a request to return the feature on the referenced (parent) layer which is referenced by the p...
void setId(const QString &id)
Set an id for this relation.
QgsFeatureIterator getRelatedFeatures(const QgsFeature &feature) const
Creates an iterator which returns all the features on the referencing (child) layer which have a fore...
QgsRelation()
Default constructor.
void setReferencedLayer(const QString &id)
Set the referenced (parent) layer id.
void setPolymorphicRelationId(const QString &polymorphicRelationId)
Sets the parent polymorphic relation id.
QgsRelation & operator=(const QgsRelation &other)
Copies a relation.
void generateId()
Generate a (project-wide) unique id for this relation.
Q_INVOKABLE QString resolveReferencingField(const QString &referencedField) const
Gets the referencing field counterpart given a referenced field.
bool hasEqualDefinition(const QgsRelation &other) const
Compares the two QgsRelation, ignoring the name and the ID.
static QgsRelation createFromXml(const QDomNode &node, QgsReadWriteContext &context, const QgsRelationContext &relationContext=QgsRelationContext())
Creates a relation from an XML structure.
QString validationError() const
Returns a user-friendly explanation for why the relationship is invalid.
Q_INVOKABLE QString resolveReferencedField(const QString &referencingField) const
Gets the referenced field counterpart given a referencing field.
QString polymorphicRelationId
QgsVectorLayer * referencedLayer
Qgis::RelationshipType type() const
Returns the type of the relation.
void setStrength(Qgis::RelationshipStrength strength)
Set a strength for this relation.
static QString strengthToDisplayString(Qgis::RelationshipStrength strength)
Returns a user-friendly translated string representing a relationship strength.
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.
QList< QgsRelation::FieldPair > fieldPairs() const
Returns the field pairs which form this relation The first element of each pair are the field names o...
QString referencedLayerId
QgsPolymorphicRelation polymorphicRelation
Qgis::RelationshipStrength strength
QgsVectorLayer * referencingLayer
QString referencingLayerId
bool referencingFieldsAllowNull() const
Returns true if none of the referencing fields has a NOT NULL constraint.
void setName(const QString &name)
Set a name for this relation.
void writeXml(QDomNode &node, QDomDocument &doc) const
Writes a relation to an XML structure.
Q_INVOKABLE QString getRelatedFeaturesFilter(const QgsFeature &feature) const
Returns a filter expression which returns all the features on the referencing (child) layer which hav...
void updateRelationStatus()
Updates the validity status of this relation.
QList< int > referencingFields
QgsFeatureRequest getRelatedFeaturesRequest(const QgsFeature &feature) const
Creates a request to return all the features on the referencing (child) layer which have a foreign ke...
Represents a vector layer which manages a vector based dataset.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const final
Queries the layer for features specified in request.
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.
#define BUILTIN_UNREACHABLE
QList< int > QgsAttributeList
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)