[layouts] Add setters/getters for map item stacking positions

This commit is contained in:
Nyall Dawson 2018-12-28 16:39:50 +10:00
parent 6eb49feddc
commit 1b309c6810
5 changed files with 221 additions and 4 deletions

View File

@ -22,6 +22,15 @@ An item which is drawn inside a QgsLayoutItemMap, e.g., a grid or map overview.
%End
public:
enum StackingPosition
{
StackBelowMap,
StackBelowMapLayer,
StackAboveMapLayer,
StackBelowMapLabels,
StackAboveMapLabels,
};
QgsLayoutItemMapItem( const QString &name, QgsLayoutItemMap *map );
%Docstring
Constructor for QgsLayoutItemMapItem, attached to the specified ``map``.
@ -111,6 +120,60 @@ Returns whether the item will be drawn.
virtual bool usesAdvancedEffects() const;
%Docstring
Returns true if the item is drawn using advanced effects, such as blend modes.
%End
StackingPosition stackingPosition() const;
%Docstring
Returns the item's stacking position, which specifies where the in the map's
stack the item should be rendered.
.. seealso:: :py:func:`setStackingPosition`
.. seealso:: :py:func:`stackingLayer`
.. versionadded:: 3.6
%End
void setStackingPosition( StackingPosition position );
%Docstring
Sets the item's stacking ``position``, which specifies where the in the map's
stack the item should be rendered.
.. seealso:: :py:func:`stackingPosition`
.. seealso:: :py:func:`setStackingLayer`
.. versionadded:: 3.6
%End
QgsMapLayer *stackingLayer() const;
%Docstring
Returns the item's stacking layer, which specifies where the in the map's
stack the item should be rendered.
This setting is only used when stackingPosition() is StackBelowMapLayer or
StackAboveMapLayer.
.. seealso:: :py:func:`setStackingLayer`
.. seealso:: :py:func:`stackingPosition`
.. versionadded:: 3.6
%End
void setStackingLayer( QgsMapLayer *layer );
%Docstring
Sets the item's stacking ``layer``, which specifies where the in the map's
stack the item should be rendered.
This setting is only used when stackingPosition() is StackBelowMapLayer or
StackAboveMapLayer.
.. seealso:: :py:func:`stackingLayer`
.. seealso:: :py:func:`setStackingPosition`
.. versionadded:: 3.6
%End
protected:
@ -119,10 +182,10 @@ Returns true if the item is drawn using advanced effects, such as blend modes.
};
class QgsLayoutItemMapItemStack
{
%Docstring

View File

@ -17,6 +17,7 @@
#include "qgslayoutitemmapitem.h"
#include "qgslayoutitemmap.h"
#include "qgslayout.h"
#include <QUuid>
QgsLayoutItemMapItem::QgsLayoutItemMapItem( const QString &name, QgsLayoutItemMap *map )
@ -35,6 +36,16 @@ bool QgsLayoutItemMapItem::writeXml( QDomElement &element, QDomDocument &documen
element.setAttribute( QStringLiteral( "uuid" ), mUuid );
element.setAttribute( QStringLiteral( "name" ), mName );
element.setAttribute( QStringLiteral( "show" ), mEnabled );
element.setAttribute( QStringLiteral( "position" ), static_cast< int >( mStackingPosition ) );
if ( mStackingLayer )
{
element.setAttribute( QStringLiteral( "stackingLayer" ), mStackingLayer.layerId );
element.setAttribute( QStringLiteral( "stackingLayerName" ), mStackingLayer.name );
element.setAttribute( QStringLiteral( "stackingLayerSource" ), mStackingLayer.source );
element.setAttribute( QStringLiteral( "stackingLayerProvider" ), mStackingLayer.provider );
}
return true;
}
@ -44,6 +55,16 @@ bool QgsLayoutItemMapItem::readXml( const QDomElement &itemElem, const QDomDocum
mUuid = itemElem.attribute( QStringLiteral( "uuid" ) );
mName = itemElem.attribute( QStringLiteral( "name" ) );
mEnabled = ( itemElem.attribute( QStringLiteral( "show" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
mStackingPosition = static_cast< StackingPosition >( itemElem.attribute( QStringLiteral( "position" ), QString::number( QgsLayoutItemMapItem::StackBelowMapLabels ) ).toInt() );
const QString layerId = itemElem.attribute( QStringLiteral( "stackingLayer" ) );
const QString layerName = itemElem.attribute( QStringLiteral( "stackingLayerName" ) );
const QString layerSource = itemElem.attribute( QStringLiteral( "stackingLayerSource" ) );
const QString layerProvider = itemElem.attribute( QStringLiteral( "stackingLayerProvider" ) );
mStackingLayer = QgsMapLayerRef( layerId, layerName, layerSource, layerProvider );
if ( mMap && mMap->layout() )
mStackingLayer.resolveWeakly( mMap->layout()->project() );
return true;
}
@ -86,6 +107,16 @@ bool QgsLayoutItemMapItem::usesAdvancedEffects() const
return false;
}
QgsMapLayer *QgsLayoutItemMapItem::stackingLayer() const
{
return mStackingLayer.get();
}
void QgsLayoutItemMapItem::setStackingLayer( QgsMapLayer *layer )
{
mStackingLayer.setLayer( layer );
}
//
// QgsLayoutItemMapItemStack
//

View File

@ -20,6 +20,7 @@
#include "qgis_core.h"
#include "qgis_sip.h"
#include "qgslayoutobject.h"
#include "qgsmaplayerref.h"
class QgsLayoutItemMap;
@ -35,6 +36,16 @@ class CORE_EXPORT QgsLayoutItemMapItem : public QgsLayoutObject
public:
//! Item stacking position, specifies where the in the map's stack the item should be rendered
enum StackingPosition
{
StackBelowMap, //!< Render below all map layers
StackBelowMapLayer, //!< Render below a specific map layer (see stackingLayer())
StackAboveMapLayer, //!< Render above a specific map layer (see stackingLayer())
StackBelowMapLabels, //!< Render above all map layers, but below map labels
StackAboveMapLabels, //!< Render above all map layers and labels
};
/**
* Constructor for QgsLayoutItemMapItem, attached to the specified \a map.
*
@ -117,6 +128,56 @@ class CORE_EXPORT QgsLayoutItemMapItem : public QgsLayoutObject
*/
virtual bool usesAdvancedEffects() const;
/**
* Returns the item's stacking position, which specifies where the in the map's
* stack the item should be rendered.
*
* \see setStackingPosition()
* \see stackingLayer()
*
* \since QGIS 3.6
*/
StackingPosition stackingPosition() const { return mStackingPosition; }
/**
* Sets the item's stacking \a position, which specifies where the in the map's
* stack the item should be rendered.
*
* \see stackingPosition()
* \see setStackingLayer()
*
* \since QGIS 3.6
*/
void setStackingPosition( StackingPosition position ) { mStackingPosition = position; }
/**
* Returns the item's stacking layer, which specifies where the in the map's
* stack the item should be rendered.
*
* This setting is only used when stackingPosition() is StackBelowMapLayer or
* StackAboveMapLayer.
*
* \see setStackingLayer()
* \see stackingPosition()
*
* \since QGIS 3.6
*/
QgsMapLayer *stackingLayer() const;
/**
* Sets the item's stacking \a layer, which specifies where the in the map's
* stack the item should be rendered.
*
* This setting is only used when stackingPosition() is StackBelowMapLayer or
* StackAboveMapLayer.
*
* \see stackingLayer()
* \see setStackingPosition
*
* \since QGIS 3.6
*/
void setStackingLayer( QgsMapLayer *layer );
protected:
//! Friendly display name
@ -131,10 +192,12 @@ class CORE_EXPORT QgsLayoutItemMapItem : public QgsLayoutObject
//! True if item is to be displayed on map
bool mEnabled;
StackingPosition mStackingPosition = StackBelowMapLabels;
QgsMapLayerRef mStackingLayer;
};
/**
* \ingroup core
* \class QgsLayoutItemMapItemStack

View File

@ -69,6 +69,7 @@ class TestQgsLayout: public QObject
void mapLayersRestoredFromTemplate();
void mapLayersStyleOverrideRestoredFromTemplate();
void atlasLayerRestoredFromTemplate();
void overviewStackingLayerRestoredFromTemplate();
private:
QString mReport;
@ -1264,6 +1265,45 @@ void TestQgsLayout::atlasLayerRestoredFromTemplate()
QCOMPARE( c2.atlas()->coverageLayer(), layer2 );
}
void TestQgsLayout::overviewStackingLayerRestoredFromTemplate()
{
// load some layers
QFileInfo vectorFileInfo( QStringLiteral( TEST_DATA_DIR ) + "/points.shp" );
QgsVectorLayer *layer = new QgsVectorLayer( vectorFileInfo.filePath(),
vectorFileInfo.completeBaseName(),
QStringLiteral( "ogr" ) );
QgsProject p;
p.addMapLayer( layer );
QgsPrintLayout c( &p );
QgsLayoutItemMap *map = new QgsLayoutItemMap( &c );
map->attemptSetSceneRect( QRectF( 1, 1, 10, 10 ) );
c.addLayoutItem( map );
map->overview()->setStackingLayer( layer );
// save composition to template
QDomDocument doc;
doc.appendChild( c.writeXml( doc, QgsReadWriteContext() ) );
// new project
QgsProject p2;
QgsVectorLayer *layer2 = new QgsVectorLayer( vectorFileInfo.filePath(),
vectorFileInfo.completeBaseName(),
QStringLiteral( "ogr" ) );
p2.addMapLayer( layer2 );
// make a new layout from template
QgsPrintLayout c2( &p2 );
c2.loadFromTemplate( doc, QgsReadWriteContext() );
// get legend from new composition
QList< QgsLayoutItemMap * > maps2;
c2.layoutItems( maps2 );
QgsLayoutItemMap *map2 = maps2.at( 0 );
QVERIFY( map2 );
QCOMPARE( map2->overview()->stackingLayer(), layer2 );
}
QGSTEST_MAIN( TestQgsLayout )
#include "testqgslayout.moc"

View File

@ -20,6 +20,7 @@ from qgis.PyQt.QtCore import QFileInfo, QRectF, QDir
from qgis.PyQt.QtGui import QPainter
from qgis.core import (QgsLayoutItemMap,
QgsLayoutItemMapItem,
QgsRectangle,
QgsRasterLayer,
QgsVectorLayer,
@ -217,6 +218,25 @@ class TestQgsLayoutMap(unittest.TestCase, LayoutItemTestCase):
layer = overviewMap.overview().asMapLayer()
self.assertEqual([f.geometry().asWkt(0) for f in layer.getFeatures()], ['Polygon ((-53 -128, 128 53, 309 -128, 128 -309, -53 -128),(93 -129, 101 -160, 163 -143, 155 -112, 93 -129))'])
def test_StackingPosition(self):
l = QgsLayout(QgsProject.instance())
l.initializeDefaults()
overviewMap = QgsLayoutItemMap(l)
overviewMap.attemptSetSceneRect(QRectF(20, 130, 70, 70))
l.addLayoutItem(overviewMap)
overviewMap.overview().setStackingPosition(QgsLayoutItemMapItem.StackBelowMap)
self.assertEqual(overviewMap.overview().stackingPosition(), QgsLayoutItemMapItem.StackBelowMap)
overviewMap.overview().setStackingPosition(QgsLayoutItemMapItem.StackBelowMapLayer)
self.assertEqual(overviewMap.overview().stackingPosition(), QgsLayoutItemMapItem.StackBelowMapLayer)
overviewMap.overview().setStackingLayer(self.raster_layer)
self.assertEqual(overviewMap.overview().stackingLayer(), self.raster_layer)
overviewMap.overview().setStackingLayer(self.vector_layer)
self.assertEqual(overviewMap.overview().stackingLayer(), self.vector_layer)
overviewMap.overview().setStackingLayer(None)
self.assertIsNone(overviewMap.overview().stackingLayer())
if __name__ == '__main__':
unittest.main()