Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsrelationmanager.cpp 3 : : -------------------------------------- 4 : : Date : 1.3.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 "qgsrelationmanager.h" 17 : : 18 : : #include "qgsapplication.h" 19 : : #include "qgslogger.h" 20 : : #include "qgsproject.h" 21 : : #include "qgsvectordataprovider.h" 22 : : #include "qgsvectorlayer.h" 23 : : 24 : 5 : QgsRelationManager::QgsRelationManager( QgsProject *project ) 25 : 5 : : QObject( project ) 26 : 5 : , mProject( project ) 27 : 10 : { 28 : 5 : if ( project ) 29 : : { 30 : : // TODO: QGIS 4 remove: relations are now stored with the layer style 31 : 5 : connect( project, &QgsProject::readProjectWithContext, this, &QgsRelationManager::readProject ); 32 : : // TODO: QGIS 4 remove: relations are now stored with the layer style 33 : 5 : connect( project, &QgsProject::writeProject, this, &QgsRelationManager::writeProject ); 34 : : 35 : 5 : connect( project, &QgsProject::layersRemoved, this, &QgsRelationManager::layersRemoved ); 36 : 5 : } 37 : 5 : } 38 : : 39 : 0 : QgsRelationContext QgsRelationManager::context() const 40 : : { 41 : 0 : return QgsRelationContext( mProject ); 42 : : } 43 : : 44 : 0 : void QgsRelationManager::setRelations( const QList<QgsRelation> &relations ) 45 : : { 46 : 0 : mRelations.clear(); 47 : 0 : for ( const QgsRelation &rel : std::as_const( relations ) ) 48 : : { 49 : 0 : addRelation( rel ); 50 : : } 51 : 0 : emit changed(); 52 : 0 : } 53 : : 54 : 0 : QMap<QString, QgsRelation> QgsRelationManager::relations() const 55 : : { 56 : 0 : return mRelations; 57 : : } 58 : : 59 : 0 : void QgsRelationManager::addRelation( const QgsRelation &relation ) 60 : : { 61 : : // Do not add relations to layers that do not exist 62 : 0 : if ( !( relation.referencingLayer() && relation.referencedLayer() ) ) 63 : 0 : return; 64 : : 65 : 0 : mRelations.insert( relation.id(), relation ); 66 : 0 : if ( mProject ) 67 : : { 68 : 0 : mProject->setDirty( true ); 69 : 0 : } 70 : 0 : emit changed(); 71 : 0 : } 72 : : 73 : : 74 : 0 : void QgsRelationManager::updateRelationsStatus() 75 : : { 76 : 0 : for ( auto relation : mRelations ) 77 : : { 78 : 0 : relation.updateRelationStatus(); 79 : 0 : } 80 : 0 : } 81 : : 82 : : 83 : 0 : void QgsRelationManager::removeRelation( const QString &id ) 84 : : { 85 : 0 : mRelations.remove( id ); 86 : 0 : emit changed(); 87 : 0 : } 88 : : 89 : 0 : void QgsRelationManager::removeRelation( const QgsRelation &relation ) 90 : : { 91 : 0 : mRelations.remove( relation.id() ); 92 : 0 : emit changed(); 93 : 0 : } 94 : : 95 : 0 : QgsRelation QgsRelationManager::relation( const QString &id ) const 96 : : { 97 : 0 : return mRelations.value( id ); 98 : 0 : } 99 : : 100 : 0 : QList<QgsRelation> QgsRelationManager::relationsByName( const QString &name ) const 101 : : { 102 : 0 : QList<QgsRelation> relations; 103 : : 104 : 0 : for ( const QgsRelation &rel : std::as_const( mRelations ) ) 105 : : { 106 : 0 : if ( QString::compare( rel.name(), name, Qt::CaseInsensitive ) == 0 ) 107 : 0 : relations << rel; 108 : : } 109 : : 110 : 0 : return relations; 111 : 0 : } 112 : : 113 : 8 : void QgsRelationManager::clear() 114 : : { 115 : 8 : mRelations.clear(); 116 : 8 : emit changed(); 117 : 8 : } 118 : : 119 : 0 : QList<QgsRelation> QgsRelationManager::referencingRelations( const QgsVectorLayer *layer, int fieldIdx ) const 120 : : { 121 : 0 : if ( !layer ) 122 : : { 123 : 0 : return mRelations.values(); 124 : : } 125 : : 126 : 0 : QList<QgsRelation> relations; 127 : : 128 : 0 : for ( const QgsRelation &rel : std::as_const( mRelations ) ) 129 : : { 130 : 0 : if ( rel.referencingLayer() == layer ) 131 : : { 132 : 0 : if ( fieldIdx != -2 ) 133 : : { 134 : 0 : bool containsField = false; 135 : 0 : const auto constFieldPairs = rel.fieldPairs(); 136 : 0 : for ( const QgsRelation::FieldPair &fp : constFieldPairs ) 137 : : { 138 : 0 : if ( fieldIdx == layer->fields().lookupField( fp.referencingField() ) ) 139 : : { 140 : 0 : containsField = true; 141 : 0 : break; 142 : : } 143 : : } 144 : : 145 : 0 : if ( !containsField ) 146 : : { 147 : 0 : continue; 148 : : } 149 : 0 : } 150 : 0 : relations.append( rel ); 151 : 0 : } 152 : : } 153 : : 154 : 0 : return relations; 155 : 0 : } 156 : : 157 : 0 : QList<QgsRelation> QgsRelationManager::referencedRelations( const QgsVectorLayer *layer ) const 158 : : { 159 : 0 : if ( !layer ) 160 : : { 161 : 0 : return mRelations.values(); 162 : : } 163 : : 164 : 0 : QList<QgsRelation> relations; 165 : : 166 : 0 : for ( const QgsRelation &rel : std::as_const( mRelations ) ) 167 : : { 168 : 0 : if ( rel.referencedLayer() == layer ) 169 : : { 170 : 0 : relations.append( rel ); 171 : 0 : } 172 : : } 173 : : 174 : 0 : return relations; 175 : 0 : } 176 : : 177 : 0 : void QgsRelationManager::readProject( const QDomDocument &doc, QgsReadWriteContext &context ) 178 : : { 179 : 0 : mRelations.clear(); 180 : 0 : mPolymorphicRelations.clear(); 181 : : 182 : 0 : QDomNodeList relationNodes = doc.elementsByTagName( QStringLiteral( "relations" ) ); 183 : 0 : if ( relationNodes.count() ) 184 : : { 185 : 0 : QgsRelationContext relcontext( mProject ); 186 : : 187 : 0 : QDomNode node = relationNodes.item( 0 ); 188 : 0 : QDomNodeList relationNodes = node.childNodes(); 189 : 0 : int relCount = relationNodes.count(); 190 : 0 : for ( int i = 0; i < relCount; ++i ) 191 : : { 192 : 0 : addRelation( QgsRelation::createFromXml( relationNodes.at( i ), context, relcontext ) ); 193 : 0 : } 194 : 0 : } 195 : : else 196 : : { 197 : 0 : QgsDebugMsg( QStringLiteral( "No relations data present in this document" ) ); 198 : : } 199 : : 200 : 0 : QDomNodeList polymorphicRelationNodes = doc.elementsByTagName( QStringLiteral( "polymorphicRelations" ) ); 201 : 0 : if ( polymorphicRelationNodes.count() ) 202 : : { 203 : 0 : QgsRelationContext relcontext( mProject ); 204 : : 205 : 0 : QDomNode node = polymorphicRelationNodes.item( 0 ); 206 : 0 : QDomNodeList relationNodes = node.childNodes(); 207 : 0 : int relCount = relationNodes.count(); 208 : 0 : for ( int i = 0; i < relCount; ++i ) 209 : : { 210 : 0 : addPolymorphicRelation( QgsPolymorphicRelation::createFromXml( relationNodes.at( i ), context, relcontext ) ); 211 : 0 : } 212 : 0 : } 213 : : else 214 : : { 215 : 0 : QgsDebugMsgLevel( QStringLiteral( "No polymorphic relations data present in this document" ), 3 ); 216 : : } 217 : : 218 : 0 : emit relationsLoaded(); 219 : 0 : emit changed(); 220 : 0 : } 221 : : 222 : 0 : void QgsRelationManager::writeProject( QDomDocument &doc ) 223 : : { 224 : 0 : QDomNodeList nl = doc.elementsByTagName( QStringLiteral( "qgis" ) ); 225 : 0 : if ( !nl.count() ) 226 : : { 227 : 0 : QgsDebugMsg( QStringLiteral( "Unable to find qgis element in project file" ) ); 228 : 0 : return; 229 : : } 230 : 0 : QDomNode qgisNode = nl.item( 0 ); // there should only be one 231 : : 232 : 0 : QDomElement relationsNode = doc.createElement( QStringLiteral( "relations" ) ); 233 : 0 : qgisNode.appendChild( relationsNode ); 234 : : 235 : 0 : for ( const QgsRelation &relation : std::as_const( mRelations ) ) 236 : : { 237 : : // the generated relations for polymorphic relations should be ignored, 238 : : // they are generated every time when a polymorphic relation is added 239 : 0 : if ( relation.type() == QgsRelation::Generated ) 240 : 0 : continue; 241 : : 242 : 0 : relation.writeXml( relationsNode, doc ); 243 : : } 244 : : 245 : 0 : QDomElement polymorphicRelationsNode = doc.createElement( QStringLiteral( "polymorphicRelations" ) ); 246 : 0 : qgisNode.appendChild( polymorphicRelationsNode ); 247 : : 248 : 0 : for ( const QgsPolymorphicRelation &relation : std::as_const( mPolymorphicRelations ) ) 249 : : { 250 : 0 : relation.writeXml( polymorphicRelationsNode, doc ); 251 : : } 252 : 0 : } 253 : : 254 : 0 : void QgsRelationManager::layersRemoved( const QStringList &layers ) 255 : : { 256 : 0 : bool relationsChanged = false; 257 : 0 : for ( const QString &layer : std::as_const( layers ) ) 258 : : { 259 : 0 : QMapIterator<QString, QgsRelation> it( mRelations ); 260 : : 261 : 0 : while ( it.hasNext() ) 262 : : { 263 : 0 : it.next(); 264 : : 265 : 0 : if ( it.value().referencedLayerId() == layer 266 : 0 : || it.value().referencingLayerId() == layer ) 267 : : { 268 : 0 : mRelations.remove( it.key() ); 269 : 0 : relationsChanged = true; 270 : 0 : } 271 : : } 272 : 0 : } 273 : 0 : if ( relationsChanged ) 274 : : { 275 : 0 : emit changed(); 276 : 0 : } 277 : 0 : } 278 : : 279 : 0 : static bool hasRelationWithEqualDefinition( const QList<QgsRelation> &existingRelations, const QgsRelation &relation ) 280 : : { 281 : 0 : for ( const QgsRelation &cur : std::as_const( existingRelations ) ) 282 : : { 283 : 0 : if ( cur.hasEqualDefinition( relation ) ) return true; 284 : : } 285 : 0 : return false; 286 : 0 : } 287 : : 288 : 0 : QList<QgsRelation> QgsRelationManager::discoverRelations( const QList<QgsRelation> &existingRelations, const QList<QgsVectorLayer *> &layers ) 289 : : { 290 : 0 : QList<QgsRelation> result; 291 : 0 : for ( const QgsVectorLayer *layer : std::as_const( layers ) ) 292 : : { 293 : 0 : const auto constDiscoverRelations = layer->dataProvider()->discoverRelations( layer, layers ); 294 : 0 : for ( const QgsRelation &relation : constDiscoverRelations ) 295 : : { 296 : 0 : if ( !hasRelationWithEqualDefinition( existingRelations, relation ) ) 297 : : { 298 : 0 : result.append( relation ); 299 : 0 : } 300 : : } 301 : 0 : } 302 : 0 : return result; 303 : 0 : } 304 : : 305 : 0 : QMap<QString, QgsPolymorphicRelation> QgsRelationManager::polymorphicRelations() const 306 : : { 307 : 0 : return mPolymorphicRelations; 308 : : } 309 : : 310 : 0 : QgsPolymorphicRelation QgsRelationManager::polymorphicRelation( const QString &polymorphicRelationId ) const 311 : : { 312 : 0 : return mPolymorphicRelations.value( polymorphicRelationId ); 313 : 0 : } 314 : : 315 : 0 : void QgsRelationManager::addPolymorphicRelation( const QgsPolymorphicRelation &polymorphicRelation ) 316 : : { 317 : 0 : if ( !polymorphicRelation.referencingLayer() || polymorphicRelation.id().isNull() ) 318 : 0 : return; 319 : : 320 : 0 : mPolymorphicRelations.insert( polymorphicRelation.id(), polymorphicRelation ); 321 : : 322 : 0 : const QList<QgsRelation> generatedRelations = polymorphicRelation.generateRelations(); 323 : 0 : for ( const QgsRelation &generatedRelation : generatedRelations ) 324 : 0 : addRelation( generatedRelation ); 325 : 0 : } 326 : : 327 : 0 : void QgsRelationManager::removePolymorphicRelation( const QString &polymorphicRelationId ) 328 : : { 329 : 0 : QgsPolymorphicRelation relation = mPolymorphicRelations.take( polymorphicRelationId ); 330 : : 331 : 0 : const QList<QgsRelation> generatedRelations = relation.generateRelations(); 332 : 0 : for ( const QgsRelation &generatedRelation : generatedRelations ) 333 : 0 : removeRelation( generatedRelation.id() ); 334 : 0 : } 335 : : 336 : 0 : void QgsRelationManager::setPolymorphicRelations( const QList<QgsPolymorphicRelation> &relations ) 337 : : { 338 : 0 : const QList<QgsPolymorphicRelation> oldRelations = polymorphicRelations().values(); 339 : 0 : for ( const QgsPolymorphicRelation &oldRelation : oldRelations ) 340 : 0 : removePolymorphicRelation( oldRelation.id() ); 341 : : 342 : 0 : for ( const QgsPolymorphicRelation &newRelation : relations ) 343 : 0 : addPolymorphicRelation( newRelation ); 344 : 0 : } 345 : :