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