mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-28 00:17:30 -05:00
[composer] Use weak layer reference matching when loading attribute table 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
This commit is contained in:
parent
85a7327aae
commit
eb1e8205e1
@ -51,7 +51,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 )
|
||||
@ -69,7 +68,7 @@ QgsComposerAttributeTableV2::QgsComposerAttributeTableV2( QgsComposition *compos
|
||||
QgsVectorLayer *vl = dynamic_cast<QgsVectorLayer *>( mapIt.value() );
|
||||
if ( vl )
|
||||
{
|
||||
mVectorLayer = vl;
|
||||
mVectorLayer.setLayer( vl );
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -77,7 +76,7 @@ QgsComposerAttributeTableV2::QgsComposerAttributeTableV2( QgsComposition *compos
|
||||
{
|
||||
resetColumns();
|
||||
//listen for modifications to layer and refresh table when they occur
|
||||
connect( mVectorLayer, &QgsVectorLayer::layerModified, this, &QgsComposerTableV2::refreshAttributes );
|
||||
connect( &mVectorLayer, &QgsVectorLayer::layerModified, this, &QgsComposerTableV2::refreshAttributes );
|
||||
}
|
||||
|
||||
if ( mComposition )
|
||||
@ -103,14 +102,14 @@ QString QgsComposerAttributeTableV2::displayName() const
|
||||
|
||||
void QgsComposerAttributeTableV2::setVectorLayer( QgsVectorLayer *layer )
|
||||
{
|
||||
if ( layer == mVectorLayer )
|
||||
if ( layer == &mVectorLayer )
|
||||
{
|
||||
//no change
|
||||
return;
|
||||
}
|
||||
|
||||
QgsVectorLayer *prevLayer = sourceLayer();
|
||||
mVectorLayer = layer;
|
||||
mVectorLayer.setLayer( layer );
|
||||
|
||||
if ( mSource == QgsComposerAttributeTableV2::LayerAttributes && layer != prevLayer )
|
||||
{
|
||||
@ -124,7 +123,7 @@ void QgsComposerAttributeTableV2::setVectorLayer( QgsVectorLayer *layer )
|
||||
resetColumns();
|
||||
|
||||
//listen for modifications to layer and refresh table when they occur
|
||||
connect( mVectorLayer, &QgsVectorLayer::layerModified, this, &QgsComposerTableV2::refreshAttributes );
|
||||
connect( &mVectorLayer, &QgsVectorLayer::layerModified, this, &QgsComposerTableV2::refreshAttributes );
|
||||
}
|
||||
|
||||
refreshAttributes();
|
||||
@ -539,7 +538,7 @@ QgsExpressionContext QgsComposerAttributeTableV2::createExpressionContext() cons
|
||||
|
||||
if ( mSource == LayerAttributes )
|
||||
{
|
||||
context.appendScope( QgsExpressionContextUtils::layerScope( mVectorLayer ) );
|
||||
context.appendScope( QgsExpressionContextUtils::layerScope( &mVectorLayer ) );
|
||||
}
|
||||
|
||||
return context;
|
||||
@ -563,7 +562,7 @@ QgsVectorLayer *QgsComposerAttributeTableV2::sourceLayer()
|
||||
case QgsComposerAttributeTableV2::AtlasFeature:
|
||||
return mComposition->atlasComposition().coverageLayer();
|
||||
case QgsComposerAttributeTableV2::LayerAttributes:
|
||||
return mVectorLayer;
|
||||
return &mVectorLayer;
|
||||
case QgsComposerAttributeTableV2::RelationChildren:
|
||||
{
|
||||
QgsRelation relation = mComposition->project()->relationManager()->relation( mRelationId );
|
||||
@ -579,7 +578,7 @@ void QgsComposerAttributeTableV2::removeLayer( const QString &layerId )
|
||||
{
|
||||
if ( layerId == mVectorLayer->id() )
|
||||
{
|
||||
mVectorLayer = nullptr;
|
||||
mVectorLayer.setLayer( nullptr );
|
||||
//remove existing columns
|
||||
qDeleteAll( mColumns );
|
||||
mColumns.clear();
|
||||
@ -657,7 +656,10 @@ bool QgsComposerAttributeTableV2::writeXml( QDomElement &elem, QDomDocument &doc
|
||||
}
|
||||
if ( mVectorLayer )
|
||||
{
|
||||
composerTableElem.setAttribute( QStringLiteral( "vectorLayer" ), mVectorLayer->id() );
|
||||
composerTableElem.setAttribute( QStringLiteral( "vectorLayer" ), mVectorLayer.layerId );
|
||||
composerTableElem.setAttribute( QStringLiteral( "vectorLayerName" ), mVectorLayer.name );
|
||||
composerTableElem.setAttribute( QStringLiteral( "vectorLayerSource" ), mVectorLayer.source );
|
||||
composerTableElem.setAttribute( QStringLiteral( "vectorLayerProvider" ), mVectorLayer.provider );
|
||||
}
|
||||
|
||||
bool ok = QgsComposerTableV2::writeXml( composerTableElem, doc, ignoreFrames );
|
||||
@ -726,19 +728,12 @@ bool QgsComposerAttributeTableV2::readXml( const QDomElement &itemElem, const QD
|
||||
}
|
||||
|
||||
//vector layer
|
||||
QString layerId = itemElem.attribute( QStringLiteral( "vectorLayer" ), QStringLiteral( "not_existing" ) );
|
||||
if ( layerId == QLatin1String( "not_existing" ) )
|
||||
{
|
||||
mVectorLayer = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsMapLayer *ml = mComposition->project()->mapLayer( layerId );
|
||||
if ( ml )
|
||||
{
|
||||
mVectorLayer = dynamic_cast<QgsVectorLayer *>( ml );
|
||||
}
|
||||
}
|
||||
QString layerId = itemElem.attribute( QStringLiteral( "vectorLayer" ) );
|
||||
QString layerName = itemElem.attribute( QStringLiteral( "vectorLayerName" ) );
|
||||
QString layerSource = itemElem.attribute( QStringLiteral( "vectorLayerSource" ) );
|
||||
QString layerProvider = itemElem.attribute( QStringLiteral( "vectorLayerProvider" ) );
|
||||
mVectorLayer = QgsVectorLayerRef( layerId, layerName, layerSource, layerProvider );
|
||||
mVectorLayer.resolveWeakly( mComposition->project() );
|
||||
|
||||
//connect to new layer
|
||||
connect( sourceLayer(), &QgsVectorLayer::layerModified, this, &QgsComposerTableV2::refreshAttributes );
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "qgis_core.h"
|
||||
#include "qgscomposertablev2.h"
|
||||
#include "qgsvectorlayerref.h"
|
||||
|
||||
class QgsComposerMap;
|
||||
class QgsVectorLayer;
|
||||
@ -119,7 +120,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; }
|
||||
|
||||
/** Sets the relation id from which to display child features
|
||||
* \param relationId id for relation to display child features from
|
||||
@ -303,7 +304,7 @@ class CORE_EXPORT QgsComposerAttributeTableV2: public QgsComposerTableV2
|
||||
//! Attribute source
|
||||
ContentSource mSource;
|
||||
//! Associated vector layer
|
||||
QgsVectorLayer *mVectorLayer = nullptr;
|
||||
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"
|
||||
@ -65,6 +66,7 @@ class TestQgsComposition : public QObject
|
||||
void referenceMap();
|
||||
void legendRestoredFromTemplate();
|
||||
void legendRestoredFromTemplateAutoUpdate();
|
||||
void attributeTableRestoredFromTemplate();
|
||||
|
||||
private:
|
||||
QgsComposition *mComposition = nullptr;
|
||||
@ -783,9 +785,15 @@ void TestQgsComposition::legendRestoredFromTemplateAutoUpdate()
|
||||
c.writeXml( composerElem, doc );
|
||||
c.atlasComposition().writeXml( composerElem, doc );
|
||||
|
||||
//new project
|
||||
QgsVectorLayer *layer2 = new QgsVectorLayer( vectorFileInfo.filePath(),
|
||||
vectorFileInfo.completeBaseName(),
|
||||
"ogr" );
|
||||
QgsProject p2;
|
||||
p2.addMapLayer( layer2 );
|
||||
|
||||
// make a new composition from template
|
||||
QgsComposition c2( &p );
|
||||
QgsComposition c2( &p2 );
|
||||
QVERIFY( c2.loadFromTemplate( doc ) );
|
||||
// get legend from new composition
|
||||
QList< QgsComposerLegend * > legends2;
|
||||
@ -797,9 +805,59 @@ void TestQgsComposition::legendRestoredFromTemplateAutoUpdate()
|
||||
QgsLayerTreeNode *node2 = model2->rootGroup()->children().at( 0 );
|
||||
QgsLayerTreeLayer *layerNode2 = dynamic_cast< QgsLayerTreeLayer * >( node2 );
|
||||
QVERIFY( layerNode2 );
|
||||
QCOMPARE( layerNode2->layer(), layer );
|
||||
QCOMPARE( layerNode2->layer(), layer2 );
|
||||
QCOMPARE( model2->data( model->node2index( layerNode2 ), Qt::DisplayRole ).toString(), QString( "points" ) );
|
||||
}
|
||||
|
||||
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" );
|
||||
QgsProject p;
|
||||
p.addMapLayer( layer2 );
|
||||
p.addMapLayer( layer );
|
||||
|
||||
// create composition
|
||||
QgsComposition c( &p );
|
||||
// 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
|
||||
QgsProject p2;
|
||||
QgsVectorLayer *layer3 = new QgsVectorLayer( vectorFileInfo.filePath(),
|
||||
vectorFileInfo.completeBaseName(),
|
||||
"ogr" );
|
||||
QgsVectorLayer *layer4 = new QgsVectorLayer( "Point", "memory", "memory" );
|
||||
p2.addMapLayer( layer4 );
|
||||
p2.addMapLayer( layer3 );
|
||||
|
||||
// make a new composition from template
|
||||
QgsComposition c2( &p2 );
|
||||
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 );
|
||||
}
|
||||
|
||||
QGSTEST_MAIN( TestQgsComposition )
|
||||
#include "testqgscomposition.moc"
|
||||
|
Loading…
x
Reference in New Issue
Block a user