Skip to content
Permalink
Browse files
[composer] Use weak layer reference matching when loading attribute t…
…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 be3ddc64a650b2baaa810517135f24f2b31d7504
Showing with 73 additions and 25 deletions.
  1. +18 −23 src/core/composer/qgscomposerattributetablev2.cpp
  2. +3 −2 src/core/composer/qgscomposerattributetablev2.h
  3. +52 −0 tests/src/core/testqgscomposition.cpp
@@ -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 )
@@ -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& ) ) );

@@ -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 )
{
@@ -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();
@@ -591,7 +590,7 @@ QgsExpressionContext *QgsComposerAttributeTableV2::createExpressionContext() con

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

return context;
@@ -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 );
@@ -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();
@@ -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 );
@@ -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() ) );
@@ -20,6 +20,7 @@

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

class QgsComposerMap;
class QgsVectorLayer;
@@ -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
@@ -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;

@@ -17,6 +17,7 @@

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

private:
QgsComposition *mComposition;
@@ -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.