Skip to content
Permalink
Browse files

Port reference map functionality from composer

  • Loading branch information
nyalldawson committed Dec 11, 2017
1 parent aa7986f commit 25d16380c0f3f0da92a3aa2bdbbd4585ed51cf42
@@ -19,6 +19,7 @@
#include "qgslayoutsnapper.h"
#include "qgslayoutpagecollection.h"
#include "qgslayoutundostack.h"
#include "qgslayoutitemmap.h"

QgsLayoutPropertiesWidget::QgsLayoutPropertiesWidget( QWidget *parent, QgsLayout *layout )
: QgsPanelWidget( parent )
@@ -69,6 +70,11 @@ QgsLayoutPropertiesWidget::QgsLayoutPropertiesWidget( QWidget *parent, QgsLayout
connect( mBottomMarginSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutPropertiesWidget::resizeMarginsChanged );
connect( mLeftMarginSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutPropertiesWidget::resizeMarginsChanged );
connect( mResizePageButton, &QPushButton::clicked, this, &QgsLayoutPropertiesWidget::resizeToContents );

connect( mReferenceMapComboBox, &QgsLayoutItemComboBox::itemChanged, this, &QgsLayoutPropertiesWidget::referenceMapChanged );

mReferenceMapComboBox->setCurrentLayout( mLayout );
mReferenceMapComboBox->setItem( mLayout->referenceMap() );
}

void QgsLayoutPropertiesWidget::updateSnappingElements()
@@ -150,6 +156,14 @@ void QgsLayoutPropertiesWidget::resizeToContents()
mLayout->undoStack()->endMacro();
}

void QgsLayoutPropertiesWidget::referenceMapChanged( QgsLayoutItem *item )
{
mLayout->undoStack()->beginCommand( mLayout, tr( "Set Reference Map" ) );
QgsLayoutItemMap *map = qobject_cast< QgsLayoutItemMap * >( item );
mLayout->setReferenceMap( map );
mLayout->undoStack()->endCommand();
}

void QgsLayoutPropertiesWidget::blockSignals( bool block )
{
mGridResolutionSpinBox->blockSignals( block );
@@ -38,7 +38,7 @@ class QgsLayoutPropertiesWidget: public QgsPanelWidget, private Ui::QgsLayoutWid
void snapToleranceChanged( int tolerance );
void resizeMarginsChanged();
void resizeToContents();

void referenceMapChanged( QgsLayoutItem *item );
private:

QgsLayout *mLayout = nullptr;
@@ -25,6 +25,7 @@
#include "qgslayoutitemgroup.h"
#include "qgslayoutitemgroupundocommand.h"
#include "qgslayoutmultiframe.h"
#include "qgslayoutitemmap.h"
#include "qgslayoutundostack.h"

QgsLayout::QgsLayout( QgsProject *project )
@@ -214,7 +215,7 @@ bool QgsLayout::moveItemToBottom( QgsLayoutItem *item, bool deferUpdate )
return result;
}

QgsLayoutItem *QgsLayout::itemByUuid( const QString &uuid, bool includeTemplateUuids )
QgsLayoutItem *QgsLayout::itemByUuid( const QString &uuid, bool includeTemplateUuids ) const
{
QList<QgsLayoutItem *> itemList;
layoutItems( itemList );
@@ -358,12 +359,31 @@ QStringList QgsLayout::customProperties() const

QgsLayoutItemMap *QgsLayout::referenceMap() const
{
return nullptr;
// prefer explicitly set reference map
if ( QgsLayoutItemMap *map = qobject_cast< QgsLayoutItemMap * >( itemByUuid( mWorldFileMapId ) ) )
return map;

// else try to find largest map
QList< QgsLayoutItemMap * > maps;
layoutItems( maps );
QgsLayoutItemMap *largestMap = nullptr;
double largestMapArea = 0;
for ( QgsLayoutItemMap *map : qgis::as_const( maps ) )
{
double area = map->rect().width() * map->rect().height();
if ( area > largestMapArea )
{
largestMapArea = area;
largestMap = map;
}
}
return largestMap;
}

void QgsLayout::setReferenceMap( QgsLayoutItemMap *map )
{
Q_UNUSED( map );
mWorldFileMapId = map ? map->uuid() : QString();
mProject->setDirty( true );
}

QgsLayoutPageCollection *QgsLayout::pageCollection()
@@ -689,6 +709,7 @@ void QgsLayout::writeXmlLayoutSettings( QDomElement &element, QDomDocument &docu
mCustomProperties.writeXml( element, document );
element.setAttribute( QStringLiteral( "name" ), mName );
element.setAttribute( QStringLiteral( "units" ), QgsUnitTypes::encodeUnit( mUnits ) );
element.setAttribute( QStringLiteral( "worldFileMap" ), mWorldFileMapId );
}

QDomElement QgsLayout::writeXml( QDomDocument &document, const QgsReadWriteContext &context ) const
@@ -731,6 +752,8 @@ bool QgsLayout::readXmlLayoutSettings( const QDomElement &layoutElement, const Q
mCustomProperties.readXml( layoutElement );
setName( layoutElement.attribute( QStringLiteral( "name" ) ) );
setUnits( QgsUnitTypes::decodeLayoutUnit( layoutElement.attribute( QStringLiteral( "units" ) ) ) );
mWorldFileMapId = layoutElement.attribute( QStringLiteral( "worldFileMap" ) );

return true;
}

@@ -116,7 +116,7 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
* Returns a list of layout items of a specific type.
* \note not available in Python bindings
*/
template<class T> void layoutItems( QList<T *> &itemList ) SIP_SKIP
template<class T> void layoutItems( QList<T *> &itemList ) const SIP_SKIP
{
itemList.clear();
QList<QGraphicsItem *> graphicsItemList = items();
@@ -223,7 +223,7 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
*
* \see multiFrameByUuid()
*/
QgsLayoutItem *itemByUuid( const QString &uuid, bool includeTemplateUuids = false );
QgsLayoutItem *itemByUuid( const QString &uuid, bool includeTemplateUuids = false ) const;

/**
* Returns the layout multiframe with matching \a uuid unique identifier, or a nullptr
@@ -404,7 +404,6 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
* \see setReferenceMap()
* \see generateWorldFile()
*/
//TODO
QgsLayoutItemMap *referenceMap() const;

/**
@@ -413,7 +412,6 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
* \see referenceMap()
* \see setGenerateWorldFile()
*/
//TODO
void setReferenceMap( QgsLayoutItemMap *map );

/**
@@ -627,6 +625,9 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
//! List of multiframe objects
QList<QgsLayoutMultiFrame *> mMultiFrames;

//! Item ID for composer map to use for the world file generation
QString mWorldFileMapId;

//! Writes only the layout settings (not member settings like grid settings, etc) to XML
void writeXmlLayoutSettings( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const;
//! Reads only the layout settings (not member settings like grid settings, etc) from XML
@@ -148,12 +148,13 @@ class LayoutDpiRestorer
double mPreviousSetting = 0;
};
///@endcond PRIVATE

QgsLayoutExporter::ExportResult QgsLayoutExporter::exportToImage( const QString &filePath, const QgsLayoutExporter::ImageExportSettings &settings )
{
int worldFilePageNo = -1;
if ( mLayout->referenceMap() )
if ( QgsLayoutItemMap *referenceMap = mLayout->referenceMap() )
{
worldFilePageNo = mLayout->referenceMap()->page();
worldFilePageNo = referenceMap->page();
}

QFileInfo fi( filePath );
@@ -117,15 +117,14 @@ QgsRenderContext QgsLayoutUtils::createRenderContextForMap( QgsLayoutItemMap *ma
{
dpi = ( painter && painter->device() ) ? painter->device()->logicalDpiX() : 88;
}
#if 0
double dotsPerMM = dpi / 25.4;
// TODO

// get map settings from reference map
QgsRectangle extent = *( map->currentMapExtent() );
QSizeF mapSizeMM = map->rect().size();
QgsRectangle extent = map->extent();
QSizeF mapSizeLayoutUnits = map->rect().size();
QSizeF mapSizeMM = map->layout()->convertFromLayoutUnits( mapSizeLayoutUnits, QgsUnitTypes::LayoutMillimeters ).toQSizeF();
QgsMapSettings ms = map->mapSettings( extent, mapSizeMM * dotsPerMM, dpi );
#endif
QgsRenderContext context; // = QgsRenderContext::fromMapSettings( ms );
QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
if ( painter )
context.setPainter( painter );

@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>234</width>
<height>327</height>
<width>311</width>
<height>515</height>
</rect>
</property>
<property name="windowTitle">
@@ -54,11 +54,40 @@
<rect>
<x>0</x>
<y>0</y>
<width>234</width>
<height>327</height>
<width>297</width>
<height>632</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QgsCollapsibleGroupBoxBasic" name="groupBox">
<property name="title">
<string>GroupBox</string>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Reference map</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QgsLayoutItemComboBox" name="mReferenceMapComboBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>Specifies the master map for this composition, which is used to georeference composer exports and for scale calculation for item styles.</string>
</property>
<property name="editable">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QgsCollapsibleGroupBoxBasic" name="mSnapToGridGroupCheckBox">
<property name="focusPolicy">
@@ -343,9 +372,15 @@
<extends>QSpinBox</extends>
<header>qgsspinbox.h</header>
</customwidget>
<customwidget>
<class>QgsLayoutItemComboBox</class>
<extends>QComboBox</extends>
<header>qgslayoutitemcombobox.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>scrollArea</tabstop>
<tabstop>mReferenceMapComboBox</tabstop>
<tabstop>mSnapToGridGroupCheckBox</tabstop>
<tabstop>mGridResolutionSpinBox</tabstop>
<tabstop>mGridSpacingUnitsCombo</tabstop>
@@ -239,27 +239,23 @@ void TestQgsLayout::referenceMap()

// no maps
QVERIFY( !l.referenceMap() );
#if 0

QgsLayoutItemMap *map = new QgsLayoutItemMap( &l );
map->setNewExtent( extent );
map->setSceneRect( QRectF( 30, 60, 200, 100 ) );
l.addComposerMap( map );
map->attemptSetSceneRect( QRectF( 30, 60, 200, 100 ) );
map->setExtent( extent );
l.addLayoutItem( map );
QCOMPARE( l.referenceMap(), map );
#endif
#if 0 // TODO

// add a larger map
QgsLayoutItemMap *map2 = new QgsLayoutItemMap( &l );
map2->setNewExtent( extent );
map2->setSceneRect( QRectF( 30, 60, 250, 150 ) );
l.addComposerMap( map2 );
map2->attemptSetSceneRect( QRectF( 30, 60, 250, 150 ) );
map2->setExtent( extent );
l.addLayoutItem( map2 );

QCOMPARE( l.referenceMap(), map2 );
// explicitly set reference map
l.setReferenceMap( map );
QCOMPARE( l.referenceMap(), map );
#endif

}

void TestQgsLayout::bounds()
@@ -244,10 +244,8 @@ void TestQgsLayoutUtils::createRenderContextFromLayout()

// add a reference map
QgsLayoutItemMap *map = new QgsLayoutItemMap( &l );
#if 0 // TODO
map->setNewExtent( extent );
map->setSceneRect( QRectF( 30, 60, 200, 100 ) );
#endif
map->attemptSetSceneRect( QRectF( 30, 60, 200, 100 ) );
map->setExtent( extent );
l.addLayoutItem( map );
l.setReferenceMap( map );

@@ -306,16 +304,12 @@ void TestQgsLayoutUtils::createRenderContextFromMap()
QgsProject project;
QgsLayout l( &project );

#if 0 // TODO
// add a map
QgsLayoutItemMap *map = new QgsLayoutItemMap( &l );
map->attemptSetSceneRect( QRectF( 30, 60, 200, 100 ) );
map->setExtent( extent );
l.addLayoutItem( map );

map->setNewExtent( extent );
map->setSceneRect( QRectF( 30, 60, 200, 100 ) );
l.addComposerMap( map );
#endif

#if 0 //TODO
rc = QgsLayoutUtils::createRenderContextForMap( map, &p );
QGSCOMPARENEAR( rc.scaleFactor(), 150 / 25.4, 0.001 );
QGSCOMPARENEAR( rc.rendererScale(), map->scale(), 1000000 );
@@ -329,10 +323,9 @@ void TestQgsLayoutUtils::createRenderContextFromMap()

// secondary map
QgsLayoutItemMap *map2 = new QgsLayoutItemMap( &l );

map2->setNewExtent( extent );
map2->setSceneRect( QRectF( 30, 60, 100, 50 ) );
composition->addComposerMap( map2 );
map2->attemptSetSceneRect( QRectF( 30, 60, 100, 50 ) );
map2->setExtent( extent );
l.addLayoutItem( map2 );

rc = QgsLayoutUtils::createRenderContextForMap( map2, &p );
QGSCOMPARENEAR( rc.scaleFactor(), 150 / 25.4, 0.001 );
@@ -357,7 +350,7 @@ void TestQgsLayoutUtils::createRenderContextFromMap()
QVERIFY( ( rc.flags() & QgsRenderContext::Antialiasing ) );
QVERIFY( ( rc.flags() & QgsRenderContext::UseAdvancedEffects ) );
QVERIFY( ( rc.flags() & QgsRenderContext::ForceVectorOutput ) );
#endif

p.end();
}

@@ -86,6 +86,8 @@ def testReadWriteXml(self):
item2.setId('zzyyzz')
l.addItem(item2)

l.setReferenceMap(item2)

doc = QDomDocument("testdoc")
elem = l.writeXml(doc, QgsReadWriteContext())

@@ -112,6 +114,7 @@ def testReadWriteXml(self):
new_item2 = l2.itemByUuid(item2.uuid())
self.assertTrue(new_item2)
self.assertEqual(new_item2.id(), 'zzyyzz')
self.assertEqual(l2.referenceMap().id(), 'zzyyzz')

def testAddItemsFromXml(self):
p = QgsProject()

0 comments on commit 25d1638

Please sign in to comment.
You can’t perform that action at this time.