LCOV - code coverage report
Current view: top level - core - qgsrelation.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 255 0.0 %
Date: 2021-04-10 08:29:14 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :     qgsrelation.cpp
       3                 :            :      --------------------------------------
       4                 :            :     Date                 : 29.4.2013
       5                 :            :     Copyright            : (C) 2013 Matthias Kuhn
       6                 :            :     Email                : matthias 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                 :            : 
      16                 :            : #include "qgsrelation.h"
      17                 :            : 
      18                 :            : #include "qgsapplication.h"
      19                 :            : #include "qgsfeatureiterator.h"
      20                 :            : #include "qgslogger.h"
      21                 :            : #include "qgsproject.h"
      22                 :            : #include "qgsvectorlayer.h"
      23                 :            : #include "qgsrelation_p.h"
      24                 :            : #include "qgspolymorphicrelation.h"
      25                 :            : #include "qgsrelationmanager.h"
      26                 :            : 
      27                 :          0 : QgsRelation::QgsRelation()
      28                 :          0 :   : d( new QgsRelationPrivate() )
      29                 :            : {
      30                 :          0 : }
      31                 :            : 
      32                 :          0 : QgsRelation::QgsRelation( const QgsRelationContext &context )
      33                 :          0 :   : d( new QgsRelationPrivate() )
      34                 :          0 :   , mContext( context )
      35                 :            : {
      36                 :          0 : }
      37                 :            : 
      38                 :          0 : QgsRelation::~QgsRelation() = default;
      39                 :            : 
      40                 :          0 : QgsRelation::QgsRelation( const QgsRelation &other )
      41                 :          0 :   : d( other.d )
      42                 :          0 :   , mContext( other.mContext )
      43                 :            : {
      44                 :          0 : }
      45                 :            : 
      46                 :          0 : QgsRelation &QgsRelation::operator=( const QgsRelation &other )
      47                 :            : {
      48                 :          0 :   d = other.d;
      49                 :          0 :   mContext = other.mContext;
      50                 :          0 :   return *this;
      51                 :            : }
      52                 :            : 
      53                 :          0 : QgsRelation QgsRelation::createFromXml( const QDomNode &node, QgsReadWriteContext &context,  const QgsRelationContext &relationContext )
      54                 :            : {
      55                 :          0 :   QDomElement elem = node.toElement();
      56                 :            : 
      57                 :          0 :   if ( elem.tagName() != QLatin1String( "relation" ) )
      58                 :            :   {
      59                 :          0 :     QgsLogger::warning( QApplication::translate( "QgsRelation", "Cannot create relation. Unexpected tag '%1'" ).arg( elem.tagName() ) );
      60                 :          0 :   }
      61                 :            : 
      62                 :          0 :   QgsRelation relation( relationContext );
      63                 :            : 
      64                 :          0 :   QString referencingLayerId = elem.attribute( QStringLiteral( "referencingLayer" ) );
      65                 :          0 :   QString referencedLayerId = elem.attribute( QStringLiteral( "referencedLayer" ) );
      66                 :          0 :   QString id = elem.attribute( QStringLiteral( "id" ) );
      67                 :          0 :   QString name = context.projectTranslator()->translate( QStringLiteral( "project:relations" ), elem.attribute( QStringLiteral( "name" ) ) );
      68                 :          0 :   QString strength = elem.attribute( QStringLiteral( "strength" ) );
      69                 :            : 
      70                 :          0 :   QMap<QString, QgsMapLayer *> mapLayers = relationContext.project()->mapLayers();
      71                 :            : 
      72                 :          0 :   QgsMapLayer *referencingLayer = mapLayers[referencingLayerId];
      73                 :          0 :   QgsMapLayer *referencedLayer = mapLayers[referencedLayerId];
      74                 :            : 
      75                 :          0 :   if ( !referencingLayer )
      76                 :            :   {
      77                 :          0 :     QgsLogger::warning( QApplication::translate( "QgsRelation", "Relation defined for layer '%1' which does not exist." ).arg( referencingLayerId ) );
      78                 :          0 :   }
      79                 :          0 :   else if ( QgsMapLayerType::VectorLayer  != referencingLayer->type() )
      80                 :            :   {
      81                 :          0 :     QgsLogger::warning( QApplication::translate( "QgsRelation", "Relation defined for layer '%1' which is not of type VectorLayer." ).arg( referencingLayerId ) );
      82                 :          0 :   }
      83                 :            : 
      84                 :          0 :   if ( !referencedLayer )
      85                 :            :   {
      86                 :          0 :     QgsLogger::warning( QApplication::translate( "QgsRelation", "Relation defined for layer '%1' which does not exist." ).arg( referencedLayerId ) );
      87                 :          0 :   }
      88                 :          0 :   else if ( QgsMapLayerType::VectorLayer  != referencedLayer->type() )
      89                 :            :   {
      90                 :          0 :     QgsLogger::warning( QApplication::translate( "QgsRelation", "Relation defined for layer '%1' which is not of type VectorLayer." ).arg( referencedLayerId ) );
      91                 :          0 :   }
      92                 :            : 
      93                 :          0 :   relation.d->mReferencingLayerId = referencingLayerId;
      94                 :          0 :   relation.d->mReferencingLayer = qobject_cast<QgsVectorLayer *>( referencingLayer );
      95                 :          0 :   relation.d->mReferencedLayerId = referencedLayerId;
      96                 :          0 :   relation.d->mReferencedLayer = qobject_cast<QgsVectorLayer *>( referencedLayer );
      97                 :          0 :   relation.d->mRelationId = id;
      98                 :          0 :   relation.d->mRelationName = name;
      99                 :          0 :   relation.d->mRelationStrength = qgsEnumKeyToValue<QgsRelation::RelationStrength>( strength, RelationStrength::Association );
     100                 :            : 
     101                 :          0 :   QDomNodeList references = elem.elementsByTagName( QStringLiteral( "fieldRef" ) );
     102                 :          0 :   for ( int i = 0; i < references.size(); ++i )
     103                 :            :   {
     104                 :          0 :     QDomElement refEl = references.at( i ).toElement();
     105                 :            : 
     106                 :          0 :     QString referencingField = refEl.attribute( QStringLiteral( "referencingField" ) );
     107                 :          0 :     QString referencedField = refEl.attribute( QStringLiteral( "referencedField" ) );
     108                 :            : 
     109                 :          0 :     relation.addFieldPair( referencingField, referencedField );
     110                 :          0 :   }
     111                 :            : 
     112                 :          0 :   relation.updateRelationStatus();
     113                 :            : 
     114                 :          0 :   return relation;
     115                 :          0 : }
     116                 :            : 
     117                 :          0 : void QgsRelation::writeXml( QDomNode &node, QDomDocument &doc ) const
     118                 :            : {
     119                 :          0 :   QDomElement elem = doc.createElement( QStringLiteral( "relation" ) );
     120                 :          0 :   elem.setAttribute( QStringLiteral( "id" ), d->mRelationId );
     121                 :          0 :   elem.setAttribute( QStringLiteral( "name" ), d->mRelationName );
     122                 :          0 :   elem.setAttribute( QStringLiteral( "referencingLayer" ), d->mReferencingLayerId );
     123                 :          0 :   elem.setAttribute( QStringLiteral( "referencedLayer" ), d->mReferencedLayerId );
     124                 :          0 :   elem.setAttribute( QStringLiteral( "strength" ), qgsEnumValueToKey<RelationStrength>( d->mRelationStrength ) );
     125                 :            : 
     126                 :          0 :   for ( const FieldPair &pair : std::as_const( d->mFieldPairs ) )
     127                 :            :   {
     128                 :          0 :     QDomElement referenceElem = doc.createElement( QStringLiteral( "fieldRef" ) );
     129                 :          0 :     referenceElem.setAttribute( QStringLiteral( "referencingField" ), pair.first );
     130                 :          0 :     referenceElem.setAttribute( QStringLiteral( "referencedField" ), pair.second );
     131                 :          0 :     elem.appendChild( referenceElem );
     132                 :          0 :   }
     133                 :            : 
     134                 :          0 :   node.appendChild( elem );
     135                 :          0 : }
     136                 :            : 
     137                 :          0 : void QgsRelation::setId( const QString &id )
     138                 :            : {
     139                 :          0 :   d.detach();
     140                 :          0 :   d->mRelationId = id;
     141                 :            : 
     142                 :          0 :   updateRelationStatus();
     143                 :          0 : }
     144                 :            : 
     145                 :          0 : void QgsRelation::setName( const QString &name )
     146                 :            : {
     147                 :          0 :   d.detach();
     148                 :          0 :   d->mRelationName = name;
     149                 :          0 : }
     150                 :            : 
     151                 :            : 
     152                 :          0 : void QgsRelation::setStrength( RelationStrength strength )
     153                 :            : {
     154                 :          0 :   d.detach();
     155                 :          0 :   d->mRelationStrength = strength;
     156                 :          0 : }
     157                 :            : 
     158                 :          0 : void QgsRelation::setReferencingLayer( const QString &id )
     159                 :            : {
     160                 :          0 :   d.detach();
     161                 :          0 :   d->mReferencingLayerId = id;
     162                 :            : 
     163                 :          0 :   updateRelationStatus();
     164                 :          0 : }
     165                 :            : 
     166                 :          0 : void QgsRelation::setReferencedLayer( const QString &id )
     167                 :            : {
     168                 :          0 :   d.detach();
     169                 :          0 :   d->mReferencedLayerId = id;
     170                 :            : 
     171                 :          0 :   updateRelationStatus();
     172                 :          0 : }
     173                 :            : 
     174                 :          0 : void QgsRelation::addFieldPair( const QString &referencingField, const QString &referencedField )
     175                 :            : {
     176                 :          0 :   d.detach();
     177                 :          0 :   d->mFieldPairs << FieldPair( referencingField, referencedField );
     178                 :          0 :   updateRelationStatus();
     179                 :          0 : }
     180                 :            : 
     181                 :          0 : void QgsRelation::addFieldPair( const FieldPair &fieldPair )
     182                 :            : {
     183                 :          0 :   d.detach();
     184                 :          0 :   d->mFieldPairs << fieldPair;
     185                 :          0 :   updateRelationStatus();
     186                 :          0 : }
     187                 :            : 
     188                 :          0 : QgsFeatureIterator QgsRelation::getRelatedFeatures( const QgsFeature &feature ) const
     189                 :            : {
     190                 :          0 :   return referencingLayer()->getFeatures( getRelatedFeaturesRequest( feature ) );
     191                 :          0 : }
     192                 :            : 
     193                 :          0 : QgsFeatureRequest QgsRelation::getRelatedFeaturesRequest( const QgsFeature &feature ) const
     194                 :            : {
     195                 :          0 :   QString filter = getRelatedFeaturesFilter( feature );
     196                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "Filter conditions: '%1'" ).arg( filter ), 2 );
     197                 :            : 
     198                 :          0 :   QgsFeatureRequest myRequest;
     199                 :          0 :   myRequest.setFilterExpression( filter );
     200                 :          0 :   return myRequest;
     201                 :          0 : }
     202                 :            : 
     203                 :          0 : QString QgsRelation::getRelatedFeaturesFilter( const QgsFeature &feature ) const
     204                 :            : {
     205                 :          0 :   QStringList conditions;
     206                 :            : 
     207                 :          0 :   if ( ! d->mPolymorphicRelationId.isEmpty() )
     208                 :            :   {
     209                 :          0 :     QgsPolymorphicRelation polyRel = polymorphicRelation();
     210                 :          0 :     if ( polyRel.isValid() )
     211                 :            :     {
     212                 :          0 :       conditions << QgsExpression::createFieldEqualityExpression( polyRel.referencedLayerField(), polyRel.layerRepresentation( referencedLayer() ) );
     213                 :          0 :     }
     214                 :            :     else
     215                 :            :     {
     216                 :          0 :       QgsDebugMsg( "The polymorphic relation is invalid" );
     217                 :          0 :       conditions << QStringLiteral( " FALSE " );
     218                 :            :     }
     219                 :          0 :   }
     220                 :            : 
     221                 :          0 :   for ( const FieldPair &pair : std::as_const( d->mFieldPairs ) )
     222                 :            :   {
     223                 :          0 :     QVariant val( feature.attribute( pair.referencedField() ) );
     224                 :          0 :     conditions << QgsExpression::createFieldEqualityExpression( pair.referencingField(), val );
     225                 :          0 :   }
     226                 :            : 
     227                 :          0 :   return conditions.join( QLatin1String( " AND " ) );
     228                 :          0 : }
     229                 :            : 
     230                 :          0 : QgsFeatureRequest QgsRelation::getReferencedFeatureRequest( const QgsAttributes &attributes ) const
     231                 :            : {
     232                 :          0 :   QStringList conditions;
     233                 :            : 
     234                 :          0 :   for ( const FieldPair &pair : std::as_const( d->mFieldPairs ) )
     235                 :            :   {
     236                 :          0 :     int referencingIdx = referencingLayer()->fields().lookupField( pair.referencingField() );
     237                 :          0 :     conditions << QgsExpression::createFieldEqualityExpression( pair.referencedField(), attributes.at( referencingIdx ) );
     238                 :            :   }
     239                 :            : 
     240                 :          0 :   QgsFeatureRequest myRequest;
     241                 :            : 
     242                 :          0 :   QgsDebugMsgLevel( QStringLiteral( "Filter conditions: '%1'" ).arg( conditions.join( " AND " ) ), 2 );
     243                 :            : 
     244                 :          0 :   myRequest.setFilterExpression( conditions.join( QLatin1String( " AND " ) ) );
     245                 :            : 
     246                 :          0 :   return myRequest;
     247                 :          0 : }
     248                 :            : 
     249                 :          0 : QgsFeatureRequest QgsRelation::getReferencedFeatureRequest( const QgsFeature &feature ) const
     250                 :            : {
     251                 :          0 :   return getReferencedFeatureRequest( feature.attributes() );
     252                 :          0 : }
     253                 :            : 
     254                 :          0 : QgsFeature QgsRelation::getReferencedFeature( const QgsFeature &feature ) const
     255                 :            : {
     256                 :          0 :   QgsFeatureRequest request = getReferencedFeatureRequest( feature );
     257                 :            : 
     258                 :          0 :   QgsFeature f;
     259                 :          0 :   d->mReferencedLayer->getFeatures( request ).nextFeature( f );
     260                 :          0 :   return f;
     261                 :          0 : }
     262                 :            : 
     263                 :          0 : QString QgsRelation::name() const
     264                 :            : {
     265                 :          0 :   return d->mRelationName;
     266                 :            : }
     267                 :            : 
     268                 :          0 : QgsRelation::RelationStrength QgsRelation::strength() const
     269                 :            : {
     270                 :          0 :   return d->mRelationStrength;
     271                 :            : }
     272                 :            : 
     273                 :          0 : QString QgsRelation::id() const
     274                 :            : {
     275                 :          0 :   return d->mRelationId;
     276                 :            : }
     277                 :            : 
     278                 :          0 : void QgsRelation::generateId()
     279                 :            : {
     280                 :          0 :   if ( !d->mFieldPairs.isEmpty() )
     281                 :            :   {
     282                 :          0 :     const QgsRelation::FieldPair fieldPair = d->mFieldPairs.at( 0 );
     283                 :          0 :     d->mRelationId = QStringLiteral( "%1_%2_%3_%4" )
     284                 :          0 :                      .arg( referencingLayerId(),
     285                 :          0 :                            fieldPair.referencingField(),
     286                 :          0 :                            referencedLayerId(),
     287                 :          0 :                            fieldPair.referencedField() );
     288                 :          0 :   }
     289                 :          0 :   updateRelationStatus();
     290                 :          0 : }
     291                 :            : 
     292                 :          0 : QString QgsRelation::referencingLayerId() const
     293                 :            : {
     294                 :          0 :   return d->mReferencingLayerId;
     295                 :            : }
     296                 :            : 
     297                 :          0 : QgsVectorLayer *QgsRelation::referencingLayer() const
     298                 :            : {
     299                 :          0 :   return d->mReferencingLayer;
     300                 :            : }
     301                 :            : 
     302                 :          0 : QString QgsRelation::referencedLayerId() const
     303                 :            : {
     304                 :          0 :   return d->mReferencedLayerId;
     305                 :            : }
     306                 :            : 
     307                 :          0 : QgsVectorLayer *QgsRelation::referencedLayer() const
     308                 :            : {
     309                 :          0 :   return d->mReferencedLayer;
     310                 :            : }
     311                 :            : 
     312                 :          0 : QList<QgsRelation::FieldPair> QgsRelation::fieldPairs() const
     313                 :            : {
     314                 :          0 :   return d->mFieldPairs;
     315                 :            : }
     316                 :            : 
     317                 :          0 : QgsAttributeList QgsRelation::referencedFields() const
     318                 :            : {
     319                 :          0 :   QgsAttributeList attrs;
     320                 :          0 :   attrs.reserve( d->mFieldPairs.size() );
     321                 :          0 :   for ( const FieldPair &pair : std::as_const( d->mFieldPairs ) )
     322                 :            :   {
     323                 :          0 :     attrs << d->mReferencedLayer->fields().lookupField( pair.second );
     324                 :            :   }
     325                 :          0 :   return attrs;
     326                 :          0 : }
     327                 :            : 
     328                 :          0 : QgsAttributeList QgsRelation::referencingFields() const
     329                 :            : {
     330                 :          0 :   QgsAttributeList attrs;
     331                 :            : 
     332                 :          0 :   for ( const FieldPair &pair : std::as_const( d->mFieldPairs ) )
     333                 :            :   {
     334                 :          0 :     attrs << d->mReferencingLayer->fields().lookupField( pair.first );
     335                 :            :   }
     336                 :          0 :   return attrs;
     337                 :            : 
     338                 :          0 : }
     339                 :            : 
     340                 :          0 : bool QgsRelation::isValid() const
     341                 :            : {
     342                 :          0 :   return d->mValid && !d->mReferencingLayer.isNull() && !d->mReferencedLayer.isNull() && d->mReferencingLayer.data()->isValid() && d->mReferencedLayer.data()->isValid();
     343                 :            : }
     344                 :            : 
     345                 :          0 : bool QgsRelation::hasEqualDefinition( const QgsRelation &other ) const
     346                 :            : {
     347                 :          0 :   return d->mReferencedLayerId == other.d->mReferencedLayerId && d->mReferencingLayerId == other.d->mReferencingLayerId && d->mFieldPairs == other.d->mFieldPairs;
     348                 :            : }
     349                 :            : 
     350                 :          0 : QString QgsRelation::resolveReferencedField( const QString &referencingField ) const
     351                 :            : {
     352                 :          0 :   for ( const FieldPair &pair : std::as_const( d->mFieldPairs ) )
     353                 :            :   {
     354                 :          0 :     if ( pair.first == referencingField )
     355                 :          0 :       return pair.second;
     356                 :            :   }
     357                 :          0 :   return QString();
     358                 :          0 : }
     359                 :            : 
     360                 :          0 : QString QgsRelation::resolveReferencingField( const QString &referencedField ) const
     361                 :            : {
     362                 :          0 :   for ( const FieldPair &pair : std::as_const( d->mFieldPairs ) )
     363                 :            :   {
     364                 :          0 :     if ( pair.second == referencedField )
     365                 :          0 :       return pair.first;
     366                 :            :   }
     367                 :          0 :   return QString();
     368                 :          0 : }
     369                 :            : 
     370                 :          0 : void QgsRelation::updateRelationStatus()
     371                 :            : {
     372                 :          0 :   const QMap<QString, QgsMapLayer *> &mapLayers = mContext.project()->mapLayers();
     373                 :            : 
     374                 :          0 :   d->mReferencingLayer = qobject_cast<QgsVectorLayer *>( mapLayers[d->mReferencingLayerId] );
     375                 :          0 :   d->mReferencedLayer = qobject_cast<QgsVectorLayer *>( mapLayers[d->mReferencedLayerId] );
     376                 :            : 
     377                 :          0 :   d->mValid = true;
     378                 :            : 
     379                 :          0 :   if ( d->mRelationId.isEmpty() )
     380                 :            :   {
     381                 :          0 :     QgsDebugMsg( QStringLiteral( "Invalid relation: no ID" ) );
     382                 :          0 :     d->mValid = false;
     383                 :          0 :   }
     384                 :            :   else
     385                 :            :   {
     386                 :          0 :     if ( !d->mReferencedLayer )
     387                 :            :     {
     388                 :          0 :       QgsDebugMsgLevel( QStringLiteral( "Invalid relation: referenced layer does not exist. ID: %1" ).arg( d->mReferencedLayerId ), 4 );
     389                 :          0 :       d->mValid = false;
     390                 :          0 :     }
     391                 :          0 :     else if ( !d->mReferencingLayer )
     392                 :            :     {
     393                 :          0 :       QgsDebugMsgLevel( QStringLiteral( "Invalid relation: referencing layer does not exist. ID: %2" ).arg( d->mReferencingLayerId ), 4 );
     394                 :          0 :       d->mValid = false;
     395                 :          0 :     }
     396                 :            :     else
     397                 :            :     {
     398                 :          0 :       if ( d->mFieldPairs.count() < 1 )
     399                 :            :       {
     400                 :          0 :         QgsDebugMsgLevel( QStringLiteral( "Invalid relation: no pair of field is specified." ), 4 );
     401                 :          0 :         d->mValid = false;
     402                 :          0 :       }
     403                 :            : 
     404                 :          0 :       for ( const FieldPair &pair : std::as_const( d->mFieldPairs ) )
     405                 :            :       {
     406                 :          0 :         if ( -1 == d->mReferencingLayer->fields().lookupField( pair.first ) )
     407                 :            :         {
     408                 :          0 :           QgsDebugMsg( QStringLiteral( "Invalid relation: field %1 does not exist in referencing layer %2" ).arg( pair.first, d->mReferencingLayer->name() ) );
     409                 :          0 :           d->mValid = false;
     410                 :          0 :           break;
     411                 :            :         }
     412                 :          0 :         else if ( -1 == d->mReferencedLayer->fields().lookupField( pair.second ) )
     413                 :            :         {
     414                 :          0 :           QgsDebugMsg( QStringLiteral( "Invalid relation: field %1 does not exist in referenced layer %2" ).arg( pair.second, d->mReferencedLayer->name() ) );
     415                 :          0 :           d->mValid = false;
     416                 :          0 :           break;
     417                 :            :         }
     418                 :            :       }
     419                 :            :     }
     420                 :            : 
     421                 :            :   }
     422                 :          0 : }
     423                 :            : 
     424                 :          0 : void QgsRelation::setPolymorphicRelationId( const QString &polymorphicRelationId )
     425                 :            : {
     426                 :          0 :   d.detach();
     427                 :          0 :   d->mPolymorphicRelationId = polymorphicRelationId;
     428                 :          0 : }
     429                 :            : 
     430                 :          0 : QString QgsRelation::polymorphicRelationId() const
     431                 :            : {
     432                 :          0 :   return d->mPolymorphicRelationId;
     433                 :            : }
     434                 :            : 
     435                 :          0 : QgsPolymorphicRelation QgsRelation::polymorphicRelation() const
     436                 :            : {
     437                 :          0 :   if ( ! mContext.project() || ! mContext.project()->relationManager() )
     438                 :          0 :     return QgsPolymorphicRelation();
     439                 :            : 
     440                 :          0 :   return mContext.project()->relationManager()->polymorphicRelation( d->mPolymorphicRelationId );
     441                 :          0 : }
     442                 :            : 
     443                 :          0 : QgsRelation::RelationType QgsRelation::type() const
     444                 :            : {
     445                 :          0 :   if ( d->mPolymorphicRelationId.isNull() )
     446                 :          0 :     return QgsRelation::Normal;
     447                 :            :   else
     448                 :          0 :     return QgsRelation::Generated;
     449                 :          0 : }

Generated by: LCOV version 1.14