Skip to content

Commit

Permalink
[composer] Use weak layer reference matching when loading attribute t…
Browse files Browse the repository at this point in the history
…able from XML

Allows attribute tables in templates to reattach to matching layers
when loaded in a different project to the project the template was
created in.

On behalf of Faunalia, sponsored by ENEL

(cherry-picked from eb1e820)
  • Loading branch information
nyalldawson committed Apr 19, 2017
1 parent a09ea45 commit be3ddc6
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 25 deletions.
41 changes: 18 additions & 23 deletions src/core/composer/qgscomposerattributetablev2.cpp
Expand Up @@ -49,7 +49,6 @@ bool QgsComposerAttributeTableCompareV2::operator()( const QgsComposerTableRow&
QgsComposerAttributeTableV2::QgsComposerAttributeTableV2( QgsComposition* composition, bool createUndoCommands )
: QgsComposerTableV2( composition, createUndoCommands )
, mSource( LayerAttributes )
, mVectorLayer( nullptr )
, mCurrentAtlasLayer( nullptr )
, mComposerMap( nullptr )
, mMaximumNumberOfFeatures( 30 )
Expand All @@ -67,15 +66,15 @@ QgsComposerAttributeTableV2::QgsComposerAttributeTableV2( QgsComposition* compos
QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( mapIt.value() );
if ( vl )
{
mVectorLayer = vl;
mVectorLayer.setLayer( vl );
break;
}
}
if ( mVectorLayer )
{
resetColumns();
//listen for modifications to layer and refresh table when they occur
connect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( refreshAttributes() ) );
connect( mVectorLayer.get(), SIGNAL( layerModified() ), this, SLOT( refreshAttributes() ) );
}
connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( removeLayer( const QString& ) ) );

Expand Down Expand Up @@ -104,14 +103,14 @@ QString QgsComposerAttributeTableV2::displayName() const

void QgsComposerAttributeTableV2::setVectorLayer( QgsVectorLayer* layer )
{
if ( layer == mVectorLayer )
if ( layer == mVectorLayer.get() )
{
//no change
return;
}

QgsVectorLayer* prevLayer = sourceLayer();
mVectorLayer = layer;
mVectorLayer.setLayer( layer );

if ( mSource == QgsComposerAttributeTableV2::LayerAttributes && layer != prevLayer )
{
Expand All @@ -125,7 +124,7 @@ void QgsComposerAttributeTableV2::setVectorLayer( QgsVectorLayer* layer )
resetColumns();

//listen for modifications to layer and refresh table when they occur
connect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( refreshAttributes() ) );
connect( mVectorLayer.get(), SIGNAL( layerModified() ), this, SLOT( refreshAttributes() ) );
}

refreshAttributes();
Expand Down Expand Up @@ -591,7 +590,7 @@ QgsExpressionContext *QgsComposerAttributeTableV2::createExpressionContext() con

if ( mSource == LayerAttributes )
{
context->appendScope( QgsExpressionContextUtils::layerScope( mVectorLayer ) );
context->appendScope( QgsExpressionContextUtils::layerScope( mVectorLayer.get() ) );
}

return context;
Expand All @@ -615,7 +614,7 @@ QgsVectorLayer *QgsComposerAttributeTableV2::sourceLayer()
case QgsComposerAttributeTableV2::AtlasFeature:
return mComposition->atlasComposition().coverageLayer();
case QgsComposerAttributeTableV2::LayerAttributes:
return mVectorLayer;
return mVectorLayer.get();
case QgsComposerAttributeTableV2::RelationChildren:
{
QgsRelation relation = QgsProject::instance()->relationManager()->relation( mRelationId );
Expand All @@ -631,7 +630,7 @@ void QgsComposerAttributeTableV2::removeLayer( const QString& layerId )
{
if ( layerId == mVectorLayer->id() )
{
mVectorLayer = nullptr;
mVectorLayer.setLayer( nullptr );
//remove existing columns
qDeleteAll( mColumns );
mColumns.clear();
Expand Down Expand Up @@ -709,7 +708,10 @@ bool QgsComposerAttributeTableV2::writeXML( QDomElement& elem, QDomDocument & do
}
if ( mVectorLayer )
{
composerTableElem.setAttribute( "vectorLayer", mVectorLayer->id() );
composerTableElem.setAttribute( "vectorLayer", mVectorLayer.layerId );
composerTableElem.setAttribute( "vectorLayerName", mVectorLayer.name );
composerTableElem.setAttribute( "vectorLayerSource", mVectorLayer.source );
composerTableElem.setAttribute( "vectorLayerProvider", mVectorLayer.provider );
}

bool ok = QgsComposerTableV2::writeXML( composerTableElem, doc, ignoreFrames );
Expand Down Expand Up @@ -778,19 +780,12 @@ bool QgsComposerAttributeTableV2::readXML( const QDomElement& itemElem, const QD
}

//vector layer
QString layerId = itemElem.attribute( "vectorLayer", "not_existing" );
if ( layerId == "not_existing" )
{
mVectorLayer = nullptr;
}
else
{
QgsMapLayer* ml = QgsMapLayerRegistry::instance()->mapLayer( layerId );
if ( ml )
{
mVectorLayer = dynamic_cast<QgsVectorLayer*>( ml );
}
}
QString layerId = itemElem.attribute( "vectorLayer" );
QString layerName = itemElem.attribute( "vectorLayerName" );
QString layerSource = itemElem.attribute( "vectorLayerSource" );
QString layerProvider = itemElem.attribute( "vectorLayerProvider" );
mVectorLayer = QgsVectorLayerRef( layerId, layerName, layerSource, layerProvider );
mVectorLayer.resolveWeakly();

//connect to new layer
connect( sourceLayer(), SIGNAL( layerModified() ), this, SLOT( refreshAttributes() ) );
Expand Down
5 changes: 3 additions & 2 deletions src/core/composer/qgscomposerattributetablev2.h
Expand Up @@ -20,6 +20,7 @@

#include "qgscomposertablev2.h"
#include "qgscomposerattributetable.h"
#include "qgsvectorlayerref.h"

class QgsComposerMap;
class QgsVectorLayer;
Expand Down Expand Up @@ -120,7 +121,7 @@ class CORE_EXPORT QgsComposerAttributeTableV2: public QgsComposerTableV2
* @returns attribute table's current vector layer
* @see setVectorLayer
*/
QgsVectorLayer* vectorLayer() const { return mVectorLayer; }
QgsVectorLayer* vectorLayer() const { return mVectorLayer.get(); }

/** Sets the relation id from which to display child features
* @param relationId id for relation to display child features from
Expand Down Expand Up @@ -314,7 +315,7 @@ class CORE_EXPORT QgsComposerAttributeTableV2: public QgsComposerTableV2
/** Attribute source*/
ContentSource mSource;
/** Associated vector layer*/
QgsVectorLayer* mVectorLayer;
QgsVectorLayerRef mVectorLayer;
/** Relation id, if in relation children mode*/
QString mRelationId;

Expand Down
52 changes: 52 additions & 0 deletions tests/src/core/testqgscomposition.cpp
Expand Up @@ -17,6 +17,7 @@

#include "qgsapplication.h"
#include "qgscomposition.h"
#include "qgscomposerattributetablev2.h"
#include "qgscomposerlabel.h"
#include "qgscomposershape.h"
#include "qgscomposerarrow.h"
Expand Down Expand Up @@ -60,6 +61,7 @@ class TestQgsComposition : public QObject
void georeference();
void variablesEdited();
void legendRestoredFromTemplate();
void attributeTableRestoredFromTemplate();

private:
QgsComposition *mComposition;
Expand Down Expand Up @@ -688,5 +690,55 @@ void TestQgsComposition::legendRestoredFromTemplate()
QCOMPARE( model3->data( model->node2index( layerNode3 ), Qt::DisplayRole ).toString(), QString( "new title!" ) );
}

void TestQgsComposition::attributeTableRestoredFromTemplate()
{
// load some layers
QFileInfo vectorFileInfo( QString( TEST_DATA_DIR ) + "/points.shp" );
QgsVectorLayer *layer = new QgsVectorLayer( vectorFileInfo.filePath(),
vectorFileInfo.completeBaseName(),
"ogr" );
QgsVectorLayer *layer2 = new QgsVectorLayer( "Point", "memory", "memory" );
QgsMapLayerRegistry::instance()->addMapLayer( layer2 );
QgsMapLayerRegistry::instance()->addMapLayer( layer );

// create composition
QgsMapSettings ms;
QgsComposition c( ms );
// add an attribute table
QgsComposerAttributeTableV2 *table = new QgsComposerAttributeTableV2( &c, false );
c.addMultiFrame( table );
table->setVectorLayer( layer );
QgsComposerFrame *frame = new QgsComposerFrame( &c, table, 1, 1, 10, 10 );
c.addComposerTableFrame( table, frame );
table->addFrame( frame );

// save composition to template
QDomDocument doc;
QDomElement composerElem = doc.createElement( "Composer" );
doc.appendChild( composerElem );
c.writeXML( composerElem, doc );
c.atlasComposition().writeXML( composerElem, doc );

// new project
QgsMapLayerRegistry::instance()->removeAllMapLayers();
QgsVectorLayer *layer3 = new QgsVectorLayer( vectorFileInfo.filePath(),
vectorFileInfo.completeBaseName(),
"ogr" );
QgsVectorLayer *layer4 = new QgsVectorLayer( "Point", "memory", "memory" );
QgsMapLayerRegistry::instance()->addMapLayer( layer4 );
QgsMapLayerRegistry::instance()->addMapLayer( layer3 );

// make a new composition from template
QgsComposition c2( ms );
QVERIFY( c2.loadFromTemplate( doc ) );
// get table from new composition
QList< QgsComposerFrame * > frames2;
c2.composerItems( frames2 );
QgsComposerAttributeTableV2 *table2 = static_cast< QgsComposerAttributeTableV2 *>( frames2.at( 0 )->multiFrame() );
QVERIFY( table2 );

QCOMPARE( table2->vectorLayer(), layer3 );
}

QTEST_MAIN( TestQgsComposition )
#include "testqgscomposition.moc"

0 comments on commit be3ddc6

Please sign in to comment.