1 /*************************************************************************** 2 qgsvectorlayerjoinbuffer.h 3 --------------------------- 4 begin : Feb 09, 2011 5 copyright : (C) 2011 by Marco Hugentobler 6 email : marco dot hugentobler at sourcepole dot ch 7 ***************************************************************************/ 8 9 /*************************************************************************** 10 * * 11 * This program is free software; you can redistribute it and/or modify * 12 * it under the terms of the GNU General Public License as published by * 13 * the Free Software Foundation; either version 2 of the License, or * 14 * (at your option) any later version. * 15 * * 16 ***************************************************************************/ 17 18 #ifndef QGSVECTORLAYERJOINBUFFER_H 19 #define QGSVECTORLAYERJOINBUFFER_H 20 21 #include "qgis_core.h" 22 #include "qgis_sip.h" 23 #include "qgsvectorlayerjoininfo.h" 24 #include "qgsfeaturesink.h" 25 26 #include <QHash> 27 #include <QString> 28 29 30 typedef QList< QgsVectorLayerJoinInfo > QgsVectorJoinList; 31 32 33 /** 34 * \ingroup core 35 * \brief Manages joined fields for a vector layer. 36 */ 37 class CORE_EXPORT QgsVectorLayerJoinBuffer : public QObject, public QgsFeatureSink 38 { 39 Q_OBJECT 40 public: 41 QgsVectorLayerJoinBuffer( QgsVectorLayer *layer = nullptr ); 42 43 /** 44 * Joins another vector layer to this layer 45 * \param joinInfo join object containing join layer id, target and source field 46 * \returns (since 2.6) whether the join was successfully added 47 */ 48 bool addJoin( const QgsVectorLayerJoinInfo &joinInfo ); 49 50 /** 51 * Removes a vector layer join 52 * \returns TRUE if join was found and successfully removed 53 */ 54 bool removeJoin( const QString &joinLayerId ); 55 56 /** 57 * Updates field map with joined attributes 58 * \param fields map to append joined attributes 59 */ 60 void updateFields( QgsFields &fields ); 61 62 //! Calls cacheJoinLayer() for all vector joins 63 void createJoinCaches(); 64 65 //! Saves mVectorJoins to xml under the layer node 66 void writeXml( QDomNode &layer_node, QDomDocument &document ) const; 67 68 /** 69 * Reads joins from project file. 70 * Does not resolve layer IDs to layers - call resolveReferences() afterwards 71 */ 72 void readXml( const QDomNode &layer_node ); 73 74 /** 75 * Resolves layer IDs of joined layers using given project's available layers 76 * \since QGIS 3.0 77 */ 78 void resolveReferences( QgsProject *project ); 79 80 //! Quick way to test if there is any join at all containsJoins()81 bool containsJoins() const { return !mVectorJoins.isEmpty(); } 82 vectorJoins()83 const QgsVectorJoinList &vectorJoins() const { return mVectorJoins; } 84 85 /** 86 * Finds the vector join for a layer field index. 87 * \param index this layers attribute index 88 * \param fields fields of the vector layer (including joined fields) 89 * \param sourceFieldIndex Output: field's index in source layer 90 * \returns the vector layer join info 91 */ 92 const QgsVectorLayerJoinInfo *joinForFieldIndex( int index, const QgsFields &fields, int &sourceFieldIndex SIP_OUT ) const; 93 94 /** 95 * Find out what is the first index of the join within fields. Returns -1 if join is not present 96 * \since QGIS 2.6 97 */ 98 int joinedFieldsOffset( const QgsVectorLayerJoinInfo *info, const QgsFields &fields ); 99 100 /** 101 * Returns a vector of indices for use in join based on field names from the layer 102 * \since QGIS 2.6 103 */ 104 static QVector<int> joinSubsetIndices( QgsVectorLayer *joinLayer, const QStringList &joinFieldsSubset ); 105 106 /** 107 * Returns a vector of indices for use in join based on field names from the join layer's fields. 108 * \since QGIS 3.20 109 */ 110 static QVector<int> joinSubsetIndices( const QgsFields &joinLayerFields, const QStringList &joinFieldsSubset ); 111 112 /** 113 * Returns joins where the field of a target layer is considered as an id. 114 * \param field the field of a target layer 115 * \returns a list of vector joins 116 * \since QGIS 3.0 117 */ 118 QList<const QgsVectorLayerJoinInfo *> joinsWhereFieldIsId( const QgsField &field ) const; 119 120 /** 121 * Returns the joined feature corresponding to the feature. 122 * \param info the vector join information 123 * \param feature the feature of the target layer 124 * \since QGIS 3.0 125 */ 126 QgsFeature joinedFeatureOf( const QgsVectorLayerJoinInfo *info, const QgsFeature &feature ) const; 127 128 /** 129 * Returns the targeted feature corresponding to the joined feature. 130 * \param info the vector join information 131 * \param feature the feature of the joined layer 132 * \since QGIS 3.0 133 */ 134 QgsFeature targetedFeatureOf( const QgsVectorLayerJoinInfo *info, const QgsFeature &feature ) const; 135 136 /** 137 * Returns TRUE if the join information is about auxiliary layer, FALSE otherwise 138 * 139 * \param info The join information 140 * 141 * \returns TRUE if the join information is about auxiliary layer, FALSE otherwise 142 * 143 * \since QGIS 3.0 144 */ 145 bool isAuxiliaryJoin( const QgsVectorLayerJoinInfo &info ) const; 146 147 /** 148 * Create a copy of the join buffer 149 * \since QGIS 2.6 150 */ 151 QgsVectorLayerJoinBuffer *clone() const SIP_FACTORY; 152 153 /** 154 * Adds a list of features in joined layers. Features given in parameter 155 * are those added in target layer. If a corresponding joined feature yet 156 * exists in a joined layer, then this feature is just updated. Note that 157 * if a corresponding joined feature has only empty fields, then it's not 158 * created nor added. 159 * 160 * \param features The list of features added in the target layer 161 * \param flags Unused parameter 162 * 163 * \returns FALSE if an error happened, TRUE otherwise 164 * 165 * \since QGIS 3.0 166 */ 167 bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = QgsFeatureSink::Flags() ) override; 168 169 /** 170 * Changes attribute value in joined layers. The feature id given in 171 * parameter is the one added in target layer. If the corresponding joined 172 * feature does not exist in a joined layer, then it's automatically 173 * created if its fields are not empty. 174 * 175 * \param fid The feature id 176 * \param field The field to update 177 * \param newValue The new value of the attribute 178 * \param oldValue The old value of the attribute 179 * 180 * \returns FALSE if an error happened, TRUE otherwise 181 * 182 * \since QGIS 3.0 183 */ 184 bool changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue = QVariant() ); 185 186 /** 187 * Changes attributes' values in joined layers. The feature id given in 188 * parameter is the one added in target layer. If the corresponding joined 189 * feature does not exist in a joined layer, then it's automatically 190 * created if its fields are not empty. 191 * 192 * \param fid The feature id 193 * \param newValues The new values for attributes 194 * \param oldValues The old values for attributes 195 * 196 * \returns FALSE if an error happened, TRUE otherwise 197 * 198 * \since QGIS 3.0 199 */ 200 bool changeAttributeValues( QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues = QgsAttributeMap() ); 201 202 /** 203 * Deletes a feature from joined layers. The feature id given in 204 * parameter is the one coming from the target layer. 205 * 206 * \param fid The feature id from the target layer to delete 207 * \param context The chain of features which will be deleted for feedback and to avoid infinite recursions. Can be NULLPTR. 208 * 209 * \returns FALSE if an error happened, TRUE otherwise 210 * 211 * \since QGIS 3.0 212 */ 213 bool deleteFeature( QgsFeatureId fid, QgsVectorLayer::DeleteContext *context = nullptr ) const; 214 215 /** 216 * Deletes a list of features from joined layers. Feature ids given 217 * in a parameter are those coming from the target layer. 218 * 219 * \param fids Feature ids from the target layer to delete 220 * \param context The chain of features who will be deleted for feedback and to avoid infinite recursions. Can be NULLPTR. 221 * 222 * \returns FALSE if an error happened, TRUE otherwise 223 * 224 * \since QGIS 3.0 225 */ 226 bool deleteFeatures( const QgsFeatureIds &fids, QgsVectorLayer::DeleteContext *context = nullptr ) const; 227 228 signals: 229 230 /** 231 * Emitted whenever the list of joined fields changes (e.g. added join or joined layer's fields change) 232 * \since QGIS 2.6 233 */ 234 void joinedFieldsChanged(); 235 236 private slots: 237 void joinedLayerUpdatedFields(); 238 239 void joinedLayerModified(); 240 241 void joinedLayerWillBeDeleted(); 242 243 private: 244 void connectJoinedLayer( QgsVectorLayer *vl ); 245 246 private: 247 248 QgsVectorLayer *mLayer = nullptr; 249 250 //! Joined vector layers 251 QgsVectorJoinList mVectorJoins; 252 253 //! Caches attributes of join layer in memory if QgsVectorJoinInfo.memoryCache is TRUE (and the cache is not already there) 254 void cacheJoinLayer( QgsVectorLayerJoinInfo &joinInfo ); 255 256 //! Main mutex to protect most data members that can be modified concurrently 257 QMutex mMutex; 258 }; 259 260 #endif // QGSVECTORLAYERJOINBUFFER_H 261