Skip to content

Commit

Permalink
Rework vector joins so they do not use QgsProject::instance()
Browse files Browse the repository at this point in the history
The basic idea is to split reading of XML definition and resolution of layer IDs into layers.

Also includes some cleanups in QgsProject and improvements in QgsVectorLayerJoinInfo.
  • Loading branch information
wonder-sk committed Jan 31, 2017
1 parent 2a518fd commit 7683cfa
Show file tree
Hide file tree
Showing 32 changed files with 557 additions and 523 deletions.
18 changes: 18 additions & 0 deletions doc/api_break.dox
Expand Up @@ -179,6 +179,7 @@ Renamed Classes {#qgis_api_break_3_0_renamed_classes}
<tr><td>QgsVectorGradientColorRampV2Dialog<td>QgsGradientColorRampDialog <tr><td>QgsVectorGradientColorRampV2Dialog<td>QgsGradientColorRampDialog
<tr><td>QgsVectorGradientColorRampV2DialogBase<td>QgsGradientColorRampDialogBase <tr><td>QgsVectorGradientColorRampV2DialogBase<td>QgsGradientColorRampDialogBase
<tr><td>QgsVectorGradientRampV2<td>QgsVectorGradientRamp <tr><td>QgsVectorGradientRampV2<td>QgsVectorGradientRamp
<tr><td>QgsVectorJoinInfo<td>QgsVectorLayerJoinInfo
<tr><td>QgsVectorLayersetRendererV2<td>QgsVectorLayersetRenderer <tr><td>QgsVectorLayersetRendererV2<td>QgsVectorLayersetRenderer
<tr><td>QgsVectorRandomColorRampV2<td>QgsLimitedRandomColorRamp <tr><td>QgsVectorRandomColorRampV2<td>QgsLimitedRandomColorRamp
<tr><td>QgsVectorRandomColorRampV2Dialog<td>QgsLimitedRandomColorRampDialog <tr><td>QgsVectorRandomColorRampV2Dialog<td>QgsLimitedRandomColorRampDialog
Expand Down Expand Up @@ -1531,6 +1532,7 @@ QgsProject {#qgis_api_break_3_0_QgsProject}
- read( QDomNode& layerNode ) was renamed to readLayer( const QDomNode& layerNode ). - read( QDomNode& layerNode ) was renamed to readLayer( const QDomNode& layerNode ).
- read( const QFileInfo& file ) was replaced by read( const QString& filename ). - read( const QFileInfo& file ) was replaced by read( const QString& filename ).
- write( const QFileInfo& file ) was replaced by write( const QString& filename ). - write( const QFileInfo& file ) was replaced by write( const QString& filename ).
- createEmbeddedLayer() does not take vectorLayerList as the third parameter anymore.




QgsProjectPropertyValue {#qgis_api_break_3_0_QgsProjectPropertyValue} QgsProjectPropertyValue {#qgis_api_break_3_0_QgsProjectPropertyValue}
Expand Down Expand Up @@ -1887,6 +1889,13 @@ QGIS 3.0 defaultValue() only returns literal, constant defaultValues. A new meth
has been added which returns the SQL clause fragments which must be evaluated by the provider itself. has been added which returns the SQL clause fragments which must be evaluated by the provider itself.




QgsVectorJoinInfo {#qgis_api_break_3_0_QgsVectorJoinInfo}
-----------------

- class has been renamed to QgsVectorLayerJoinInfo
- member variables are now accessible through pairs of getters and setters rather than using direct read/write


QgsVectorLayer {#qgis_api_break_3_0_QgsVectorLayer} QgsVectorLayer {#qgis_api_break_3_0_QgsVectorLayer}
-------------- --------------


Expand Down Expand Up @@ -1926,6 +1935,9 @@ displayExpression instead. For the map tip use mapTipTemplate() instead.
- loadNamedStyle(): theResultFlag argument is correctly declared as output argument - loadNamedStyle(): theResultFlag argument is correctly declared as output argument
- The duplicate selectionChanged() signal was removed. Use selectionChanged( const QgsFeatureIds&, const QgsFeatureIds&, const bool ) instead. - The duplicate selectionChanged() signal was removed. Use selectionChanged( const QgsFeatureIds&, const QgsFeatureIds&, const bool ) instead.
- featureCount() now requires a legend key string instead of a QgsSymbol pointer argument. - featureCount() now requires a legend key string instead of a QgsSymbol pointer argument.
- createJoinCaches() has been removed. Caches are created/updated when needed internally.
- checkJoinLayerRemove() has been removed. Joins are removed internally when joined layer is deleted.
- readXml() does not resolve references to joined layers. Call resolveReferences() when joined layers are available.


QgsVectorLayerEditBuffer {#qgis_api_break_3_0_QgsVectorLayerEditBuffer} QgsVectorLayerEditBuffer {#qgis_api_break_3_0_QgsVectorLayerEditBuffer}
------------------------ ------------------------
Expand Down Expand Up @@ -1953,6 +1965,12 @@ in code which previously passed a null pointer to QgsVectorLayerImport.
- ErrUserCancelled (ImportError enum value) has been renamed to ErrUserCanceled <!--#spellok--> - ErrUserCancelled (ImportError enum value) has been renamed to ErrUserCanceled <!--#spellok-->




QgsVectorLayerJoinBuffer {#qgis_api_break_3_0_QgsVectorLayerJoinBuffer}
------------------------

- readXml() does not resolve layer IDs to layers anymore. You need to call resolveReferences() afterwards.


QgsVectorLayerUndoCommand {#qgis_api_break_3_0_QgsVectorLayerUndoCommand} QgsVectorLayerUndoCommand {#qgis_api_break_3_0_QgsVectorLayerUndoCommand}
------------------------- -------------------------


Expand Down
1 change: 1 addition & 0 deletions python/core/core.sip
Expand Up @@ -155,6 +155,7 @@
%Include qgsvectorlayereditpassthrough.sip %Include qgsvectorlayereditpassthrough.sip
%Include qgsvectorlayerimport.sip %Include qgsvectorlayerimport.sip
%Include qgsvectorlayerjoinbuffer.sip %Include qgsvectorlayerjoinbuffer.sip
%Include qgsvectorlayerjoininfo.sip
%Include qgsvectorlayertools.sip %Include qgsvectorlayertools.sip
%Include qgsvectorlayerundocommand.sip %Include qgsvectorlayerundocommand.sip
%Include qgsvectorlayerutils.sip %Include qgsvectorlayerutils.sip
Expand Down
56 changes: 7 additions & 49 deletions python/core/qgsvectorlayer.sip
Expand Up @@ -3,46 +3,6 @@ typedef QList<int> QgsAttributeList;
typedef QSet<int> QgsAttributeIds; typedef QSet<int> QgsAttributeIds;




struct QgsVectorJoinInfo
{
%TypeHeaderCode
#include "qgsvectorlayer.h"
%End
QgsVectorJoinInfo();

/** Join field in the target layer*/
QString targetFieldName;
/** Source layer*/
QString joinLayerId;
/** Join field in the source layer*/
QString joinFieldName;
/** True if the join is cached in virtual memory*/
bool memoryCache;
/** True if the cached join attributes need to be updated*/
bool cacheDirty;

/** Cache for joined attributes to provide fast lookup (size is 0 if no memory caching)
* @note not available in python bindings
*/
// QHash< QString, QgsAttributeMap> cachedAttributes;

/** An optional prefix. If it is a Null string "{layername}_" will be used
* @note Added in 2.8
*/
QString prefix;

bool operator==( const QgsVectorJoinInfo& other ) const;

/** Set subset of fields to be used from joined layer. Takes ownership of the passed pointer. Null pointer tells to use all fields.
@note added in 2.6 */
void setJoinFieldNamesSubset( QStringList* fieldNamesSubset /Transfer/ );
/** Get subset of fields to be used from joined layer. All fields will be used if null is returned.
@note added in 2.6 */
QStringList* joinFieldNamesSubset() const;
};



/** \ingroup core /** \ingroup core
* Represents a vector layer which manages a vector based data sets. * Represents a vector layer which manages a vector based data sets.
* *
Expand Down Expand Up @@ -413,7 +373,7 @@ class QgsVectorLayer : QgsMapLayer, QgsExpressionContextGenerator
/** Joins another vector layer to this layer /** Joins another vector layer to this layer
@param joinInfo join object containing join layer id, target and source field @param joinInfo join object containing join layer id, target and source field
@note since 2.6 returns bool indicating whether the join can be added */ @note since 2.6 returns bool indicating whether the join can be added */
bool addJoin( const QgsVectorJoinInfo& joinInfo ); bool addJoin( const QgsVectorLayerJoinInfo& joinInfo );


/** Removes a vector layer join /** Removes a vector layer join
@returns true if join was found and successfully removed */ @returns true if join was found and successfully removed */
Expand All @@ -424,7 +384,7 @@ class QgsVectorLayer : QgsMapLayer, QgsExpressionContextGenerator
* @note added 2.14.7 * @note added 2.14.7
*/ */
QgsVectorLayerJoinBuffer* joinBuffer(); QgsVectorLayerJoinBuffer* joinBuffer();
const QList<QgsVectorJoinInfo> vectorJoins() const; const QList<QgsVectorLayerJoinInfo> vectorJoins() const;


/** /**
* Sets the list of dependencies. * Sets the list of dependencies.
Expand Down Expand Up @@ -656,6 +616,11 @@ class QgsVectorLayer : QgsMapLayer, QgsExpressionContextGenerator
*/ */
virtual bool writeXml( QDomNode & layer_node, QDomDocument & doc ) const; virtual bool writeXml( QDomNode & layer_node, QDomDocument & doc ) const;


/** Resolve references to other layers (kept as layer IDs after reading XML) into layer objects.
* @note added in 3.0
*/
void resolveReferences( QgsProject* project );

/** /**
* Save named and sld style of the layer to the style table in the db. * Save named and sld style of the layer to the style table in the db.
* @param name * @param name
Expand Down Expand Up @@ -1216,10 +1181,6 @@ class QgsVectorLayer : QgsMapLayer, QgsExpressionContextGenerator
/** Assembles mUpdatedFields considering provider fields, joined fields and added fields */ /** Assembles mUpdatedFields considering provider fields, joined fields and added fields */
void updateFields(); void updateFields();


/** Caches joined attributes if required (and not already done) */
// marked as const as these are just caches, and need to be created from const accessors
void createJoinCaches() const;

/** Returns the calculated default value for the specified field index. The default /** Returns the calculated default value for the specified field index. The default
* value may be taken from a client side default value expression (see setDefaultValueExpression()) * value may be taken from a client side default value expression (see setDefaultValueExpression())
* or taken from the underlying data provider. * or taken from the underlying data provider.
Expand Down Expand Up @@ -1539,9 +1500,6 @@ class QgsVectorLayer : QgsMapLayer, QgsExpressionContextGenerator
*/ */
virtual void updateExtents(); virtual void updateExtents();


/** Check if there is a join with a layer that will be removed */
void checkJoinLayerRemove( const QString& theLayerId );

/** /**
* Make layer editable. * Make layer editable.
* This starts an edit session on this layer. Changes made in this edit session will not * This starts an edit session on this layer. Changes made in this edit session will not
Expand Down
12 changes: 8 additions & 4 deletions python/core/qgsvectorlayerjoinbuffer.sip
Expand Up @@ -10,7 +10,7 @@ class QgsVectorLayerJoinBuffer : QObject
/** Joins another vector layer to this layer /** Joins another vector layer to this layer
@param joinInfo join object containing join layer id, target and source field @param joinInfo join object containing join layer id, target and source field
@return (since 2.6) whether the join was successfully added */ @return (since 2.6) whether the join was successfully added */
bool addJoin( const QgsVectorJoinInfo& joinInfo ); bool addJoin( const QgsVectorLayerJoinInfo& joinInfo );


/** Removes a vector layer join /** Removes a vector layer join
@returns true if join was found and successfully removed */ @returns true if join was found and successfully removed */
Expand All @@ -30,20 +30,24 @@ class QgsVectorLayerJoinBuffer : QObject
/** Reads joins from project file*/ /** Reads joins from project file*/
void readXml( const QDomNode& layer_node ); void readXml( const QDomNode& layer_node );


//! Resolves layer IDs of joined layers using given project's available layers
//! @note added in 3.0
void resolveReferences( QgsProject* project );

/** Quick way to test if there is any join at all*/ /** Quick way to test if there is any join at all*/
bool containsJoins() const; bool containsJoins() const;


const QList< QgsVectorJoinInfo >& vectorJoins() const; const QList< QgsVectorLayerJoinInfo >& vectorJoins() const;


/** Finds the vector join for a layer field index. /** Finds the vector join for a layer field index.
@param index this layers attribute index @param index this layers attribute index
@param fields fields of the vector layer (including joined fields) @param fields fields of the vector layer (including joined fields)
@param sourceFieldIndex Output: field's index in source layer */ @param sourceFieldIndex Output: field's index in source layer */
const QgsVectorJoinInfo* joinForFieldIndex( int index, const QgsFields& fields, int& sourceFieldIndex /Out/ ) const; const QgsVectorLayerJoinInfo* joinForFieldIndex( int index, const QgsFields& fields, int& sourceFieldIndex /Out/ ) const;


//! Find out what is the first index of the join within fields. Returns -1 if join is not present //! Find out what is the first index of the join within fields. Returns -1 if join is not present
//! @note added in 2.6 //! @note added in 2.6
int joinedFieldsOffset( const QgsVectorJoinInfo* info, const QgsFields& fields ); int joinedFieldsOffset( const QgsVectorLayerJoinInfo* info, const QgsFields& fields );


//! Return a vector of indices for use in join based on field names from the layer //! Return a vector of indices for use in join based on field names from the layer
//! @note added in 2.6 //! @note added in 2.6
Expand Down
49 changes: 49 additions & 0 deletions python/core/qgsvectorlayerjoininfo.sip
@@ -0,0 +1,49 @@

class QgsVectorLayerJoinInfo
{
%TypeHeaderCode
#include "qgsvectorlayerjoininfo.h"
%End

public:
QgsVectorLayerJoinInfo();

//! Sets weak reference to the joined layer
void setJoinLayer( QgsVectorLayer* layer );
//! Returns joined layer (may be null if the reference was set by layer ID and not resolved yet)
QgsVectorLayer* joinLayer() const;

//! Sets ID of the joined layer. It will need to be overwritten by setJoinLayer() to a reference to real layer
void setJoinLayerId( const QString& layerId );
//! ID of the joined layer - may be used to resolve reference to the joined layer
QString joinLayerId() const;

//! Sets name of the field of our layer that will be used for join
void setTargetFieldName( const QString& fieldName );
//! Returns name of the field of our layer that will be used for join
QString targetFieldName() const;

//! Sets name of the field of joined layer that will be used for join
void setJoinFieldName( const QString& fieldName );
//! Returns name of the field of joined layer that will be used for join
QString joinFieldName() const;

//! Sets prefix of fields from the joined layer. If null, joined layer's name will be used.
void setPrefix( const QString& prefix );
//! Returns prefix of fields from the joined layer. If null, joined layer's name will be used.
QString prefix() const;

//! Sets whether values from the joined layer should be cached in memory to speed up lookups
void setUsingMemoryCache( bool enabled );
//! Returns whether values from the joined layer should be cached in memory to speed up lookups
bool isUsingMemoryCache() const;

bool operator==( const QgsVectorLayerJoinInfo& other ) const;

/** Set subset of fields to be used from joined layer. Takes ownership of the passed pointer. Null pointer tells to use all fields.
@note added in 2.6 */
void setJoinFieldNamesSubset( QStringList* fieldNamesSubset /Transfer/ );
/** Get subset of fields to be used from joined layer. All fields will be used if null is returned.
@note added in 2.6 */
QStringList* joinFieldNamesSubset() const;
};
6 changes: 3 additions & 3 deletions src/app/qgisapp.cpp
Expand Up @@ -247,6 +247,7 @@
#include "qgsvirtuallayerdefinitionutils.h" #include "qgsvirtuallayerdefinitionutils.h"
#include "qgstransaction.h" #include "qgstransaction.h"
#include "qgstransactiongroup.h" #include "qgstransactiongroup.h"
#include "qgsvectorlayerjoininfo.h"
#include "qgsvectorlayerutils.h" #include "qgsvectorlayerutils.h"
#include "qgshelp.h" #include "qgshelp.h"


Expand Down Expand Up @@ -8543,7 +8544,7 @@ void QgisApp::duplicateLayers( const QList<QgsMapLayer *>& lyrList )
QgsExpressionContextUtils::setLayerVariable( dupVLayer, variableName, varValue ); QgsExpressionContextUtils::setLayerVariable( dupVLayer, variableName, varValue );
} }


Q_FOREACH ( const QgsVectorJoinInfo& join, vlayer->vectorJoins() ) Q_FOREACH ( const QgsVectorLayerJoinInfo& join, vlayer->vectorJoins() )
dupVLayer->addJoin( join ); dupVLayer->addJoin( join );


for ( int fld = 0; fld < vlayer->fields().count(); fld++ ) for ( int fld = 0; fld < vlayer->fields().count(); fld++ )
Expand Down Expand Up @@ -9509,7 +9510,6 @@ void QgisApp::embedLayers()


//layer ids //layer ids
QList<QDomNode> brokenNodes; QList<QDomNode> brokenNodes;
QList< QPair< QgsVectorLayer*, QDomElement > > vectorLayerList;


// resolve dependencies // resolve dependencies
QgsLayerDefinition::DependencySorter depSorter( projectFile ); QgsLayerDefinition::DependencySorter depSorter( projectFile );
Expand All @@ -9520,7 +9520,7 @@ void QgisApp::embedLayers()
Q_FOREACH ( const QString& selId, layerIds ) Q_FOREACH ( const QString& selId, layerIds )
{ {
if ( selId == id ) if ( selId == id )
QgsProject::instance()->createEmbeddedLayer( selId, projectFile, brokenNodes, vectorLayerList ); QgsProject::instance()->createEmbeddedLayer( selId, projectFile, brokenNodes );
} }
} }


Expand Down
34 changes: 16 additions & 18 deletions src/app/qgsjoindialog.cpp
Expand Up @@ -20,6 +20,7 @@
#include "qgsproject.h" #include "qgsproject.h"
#include "qgsvectordataprovider.h" #include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h" #include "qgsvectorlayer.h"
#include "qgsvectorlayerjoininfo.h"
#include "qgsmaplayercombobox.h" #include "qgsmaplayercombobox.h"
#include "qgsfieldcombobox.h" #include "qgsfieldcombobox.h"


Expand Down Expand Up @@ -66,20 +67,20 @@ QgsJoinDialog::~QgsJoinDialog()
{ {
} }


void QgsJoinDialog::setJoinInfo( const QgsVectorJoinInfo& joinInfo ) void QgsJoinDialog::setJoinInfo( const QgsVectorLayerJoinInfo& joinInfo )
{ {
mJoinLayerComboBox->setLayer( QgsProject::instance()->mapLayer( joinInfo.joinLayerId ) ); mJoinLayerComboBox->setLayer( joinInfo.joinLayer() );
mJoinFieldComboBox->setField( joinInfo.joinFieldName ); mJoinFieldComboBox->setField( joinInfo.joinFieldName() );
mTargetFieldComboBox->setField( joinInfo.targetFieldName ); mTargetFieldComboBox->setField( joinInfo.targetFieldName() );
mCacheInMemoryCheckBox->setChecked( joinInfo.memoryCache ); mCacheInMemoryCheckBox->setChecked( joinInfo.isUsingMemoryCache() );
if ( joinInfo.prefix.isNull() ) if ( joinInfo.prefix().isNull() )
{ {
mUseCustomPrefix->setChecked( false ); mUseCustomPrefix->setChecked( false );
} }
else else
{ {
mUseCustomPrefix->setChecked( true ); mUseCustomPrefix->setChecked( true );
mCustomPrefix->setText( joinInfo.prefix ); mCustomPrefix->setText( joinInfo.prefix() );
} }


QStringList* lst = joinInfo.joinFieldNamesSubset(); QStringList* lst = joinInfo.joinFieldNamesSubset();
Expand All @@ -102,21 +103,18 @@ void QgsJoinDialog::setJoinInfo( const QgsVectorJoinInfo& joinInfo )
} }
} }


QgsVectorJoinInfo QgsJoinDialog::joinInfo() const QgsVectorLayerJoinInfo QgsJoinDialog::joinInfo() const
{ {
QgsVectorJoinInfo info; QgsVectorLayerJoinInfo info;
if ( mJoinLayerComboBox->currentLayer() ) info.setJoinLayer( qobject_cast<QgsVectorLayer*>( mJoinLayerComboBox->currentLayer() ) );
info.joinLayerId = mJoinLayerComboBox->currentLayer()->id(); info.setJoinFieldName( mJoinFieldComboBox->currentField() );
info.joinFieldName = mJoinFieldComboBox->currentField(); info.setTargetFieldName( mTargetFieldComboBox->currentField() );
info.targetFieldName = mTargetFieldComboBox->currentField(); info.setUsingMemoryCache( mCacheInMemoryCheckBox->isChecked() );
info.memoryCache = mCacheInMemoryCheckBox->isChecked();
info.targetFieldIndex = -1;
info.joinFieldIndex = -1;


if ( mUseCustomPrefix->isChecked() ) if ( mUseCustomPrefix->isChecked() )
info.prefix = mCustomPrefix->text(); info.setPrefix( mCustomPrefix->text() );
else else
info.prefix = QString::null; info.setPrefix( QString::null );


if ( mUseJoinFieldsSubset->isChecked() ) if ( mUseJoinFieldsSubset->isChecked() )
{ {
Expand Down
6 changes: 3 additions & 3 deletions src/app/qgsjoindialog.h
Expand Up @@ -22,7 +22,7 @@
#include "qgis_app.h" #include "qgis_app.h"


class QgsVectorLayer; class QgsVectorLayer;
struct QgsVectorJoinInfo; class QgsVectorLayerJoinInfo;


class APP_EXPORT QgsJoinDialog: public QDialog, private Ui::QgsJoinDialogBase class APP_EXPORT QgsJoinDialog: public QDialog, private Ui::QgsJoinDialogBase
{ {
Expand All @@ -32,10 +32,10 @@ class APP_EXPORT QgsJoinDialog: public QDialog, private Ui::QgsJoinDialogBase
~QgsJoinDialog(); ~QgsJoinDialog();


//! Configure the dialog for an existing join //! Configure the dialog for an existing join
void setJoinInfo( const QgsVectorJoinInfo& joinInfo ); void setJoinInfo( const QgsVectorLayerJoinInfo& joinInfo );


//! Returns the join info //! Returns the join info
QgsVectorJoinInfo joinInfo() const; QgsVectorLayerJoinInfo joinInfo() const;


//! Returns true if user wants to create an attribute index on the join field //! Returns true if user wants to create an attribute index on the join field
bool createAttributeIndex() const; bool createAttributeIndex() const;
Expand Down

0 comments on commit 7683cfa

Please sign in to comment.