mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -04:00
This adds a new option in composer map properties: "Follow visibility preset" with a combo box to choose the active preset. This is an alternative to "lock layers" (and "lock layer styles") functionality which would just copy preset's configuration, while the new option links to preset. The difference is that when a preset is updated, composer map will automatically pick the new configuration when following the preset, while there is no update if "lock layers" (and "lock layer styles") option is used.
2551 lines
78 KiB
C++
2551 lines
78 KiB
C++
/***************************************************************************
|
|
qgscomposermap.cpp
|
|
-------------------
|
|
begin : January 2005
|
|
copyright : (C) 2005 by Radim Blazek
|
|
email : blazek@itc.it
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include "qgscomposermap.h"
|
|
#include "qgscomposermapgrid.h"
|
|
#include "qgscomposermapoverview.h"
|
|
#include "qgscomposition.h"
|
|
#include "qgscomposerutils.h"
|
|
#include "qgslogger.h"
|
|
#include "qgsmaprenderer.h"
|
|
#include "qgsmaprenderercustompainterjob.h"
|
|
#include "qgsmaplayerregistry.h"
|
|
#include "qgsmaplayerstylemanager.h"
|
|
#include "qgsmaptopixel.h"
|
|
#include "qgsproject.h"
|
|
#include "qgsrasterlayer.h"
|
|
#include "qgsrendercontext.h"
|
|
#include "qgsscalecalculator.h"
|
|
#include "qgsvectorlayer.h"
|
|
#include "qgspallabeling.h"
|
|
#include "qgsexpression.h"
|
|
#include "qgsvisibilitypresetcollection.h"
|
|
|
|
#include "qgslabel.h"
|
|
#include "qgslabelattributes.h"
|
|
#include "qgssymbollayerv2utils.h" //for pointOnLineWithDistance
|
|
|
|
#include <QGraphicsScene>
|
|
#include <QGraphicsView>
|
|
#include <QPainter>
|
|
#include <QSettings>
|
|
#include <cmath>
|
|
|
|
QgsComposerMap::QgsComposerMap( QgsComposition *composition, int x, int y, int width, int height )
|
|
: QgsComposerItem( x, y, width, height, composition )
|
|
, mGridStack( nullptr )
|
|
, mOverviewStack( nullptr )
|
|
, mMapRotation( 0 )
|
|
, mEvaluatedMapRotation( 0 )
|
|
, mKeepLayerSet( false )
|
|
, mKeepLayerStyles( false )
|
|
, mFollowVisibilityPreset( false )
|
|
, mUpdatesEnabled( true )
|
|
, mMapCanvas( nullptr )
|
|
, mDrawCanvasItems( true )
|
|
, mAtlasDriven( false )
|
|
, mAtlasScalingMode( Auto )
|
|
, mAtlasMargin( 0.10 )
|
|
{
|
|
mComposition = composition;
|
|
|
|
mId = 0;
|
|
assignFreeId();
|
|
|
|
mPreviewMode = QgsComposerMap::Rectangle;
|
|
mCurrentRectangle = rect();
|
|
|
|
// Cache
|
|
mCacheUpdated = false;
|
|
mDrawing = false;
|
|
|
|
//Offset
|
|
mXOffset = 0.0;
|
|
mYOffset = 0.0;
|
|
|
|
//get the color for map canvas background and set map background color accordingly
|
|
int bgRedInt = QgsProject::instance()->readNumEntry( "Gui", "/CanvasColorRedPart", 255 );
|
|
int bgGreenInt = QgsProject::instance()->readNumEntry( "Gui", "/CanvasColorGreenPart", 255 );
|
|
int bgBlueInt = QgsProject::instance()->readNumEntry( "Gui", "/CanvasColorBluePart", 255 );
|
|
setBackgroundColor( QColor( bgRedInt, bgGreenInt, bgBlueInt ) );
|
|
|
|
//calculate mExtent based on width/height ratio and map canvas extent
|
|
mExtent = mComposition->mapSettings().visibleExtent();
|
|
|
|
init();
|
|
|
|
setSceneRect( QRectF( x, y, width, height ) );
|
|
}
|
|
|
|
QgsComposerMap::QgsComposerMap( QgsComposition *composition )
|
|
: QgsComposerItem( 0, 0, 10, 10, composition )
|
|
, mGridStack( nullptr )
|
|
, mOverviewStack( nullptr )
|
|
, mMapRotation( 0 )
|
|
, mEvaluatedMapRotation( 0 )
|
|
, mKeepLayerSet( false )
|
|
, mKeepLayerStyles( false )
|
|
, mFollowVisibilityPreset( false )
|
|
, mUpdatesEnabled( true )
|
|
, mMapCanvas( nullptr )
|
|
, mDrawCanvasItems( true )
|
|
, mAtlasDriven( false )
|
|
, mAtlasScalingMode( Auto )
|
|
, mAtlasMargin( 0.10 )
|
|
{
|
|
//Offset
|
|
mXOffset = 0.0;
|
|
mYOffset = 0.0;
|
|
|
|
mComposition = composition;
|
|
mId = mComposition->composerMapItems().size();
|
|
mPreviewMode = QgsComposerMap::Rectangle;
|
|
mCurrentRectangle = rect();
|
|
|
|
init();
|
|
updateToolTip();
|
|
}
|
|
|
|
void QgsComposerMap::init()
|
|
{
|
|
mGridStack = new QgsComposerMapGridStack( this );
|
|
mOverviewStack = new QgsComposerMapOverviewStack( this );
|
|
connectUpdateSlot();
|
|
|
|
// data defined strings
|
|
mDataDefinedNames.insert( QgsComposerObject::MapRotation, QString( "dataDefinedMapRotation" ) );
|
|
mDataDefinedNames.insert( QgsComposerObject::MapScale, QString( "dataDefinedMapScale" ) );
|
|
mDataDefinedNames.insert( QgsComposerObject::MapXMin, QString( "dataDefinedMapXMin" ) );
|
|
mDataDefinedNames.insert( QgsComposerObject::MapYMin, QString( "dataDefinedMapYMin" ) );
|
|
mDataDefinedNames.insert( QgsComposerObject::MapXMax, QString( "dataDefinedMapXMax" ) );
|
|
mDataDefinedNames.insert( QgsComposerObject::MapYMax, QString( "dataDefinedMapYMax" ) );
|
|
mDataDefinedNames.insert( QgsComposerObject::MapAtlasMargin, QString( "dataDefinedMapAtlasMargin" ) );
|
|
mDataDefinedNames.insert( QgsComposerObject::MapLayers, QString( "dataDefinedMapLayers" ) );
|
|
mDataDefinedNames.insert( QgsComposerObject::MapStylePreset, QString( "dataDefinedMapStylePreset" ) );
|
|
}
|
|
|
|
void QgsComposerMap::updateToolTip()
|
|
{
|
|
setToolTip( tr( "Map %1" ).arg( mId ) );
|
|
}
|
|
|
|
void QgsComposerMap::adjustExtentToItemShape( double itemWidth, double itemHeight, QgsRectangle& extent ) const
|
|
{
|
|
double itemWidthHeightRatio = itemWidth / itemHeight;
|
|
double newWidthHeightRatio = extent.width() / extent.height();
|
|
|
|
if ( itemWidthHeightRatio <= newWidthHeightRatio )
|
|
{
|
|
//enlarge height of new extent, ensuring the map center stays the same
|
|
double newHeight = extent.width() / itemWidthHeightRatio;
|
|
double deltaHeight = newHeight - extent.height();
|
|
extent.setYMinimum( extent.yMinimum() - deltaHeight / 2 );
|
|
extent.setYMaximum( extent.yMaximum() + deltaHeight / 2 );
|
|
}
|
|
else
|
|
{
|
|
//enlarge width of new extent, ensuring the map center stays the same
|
|
double newWidth = itemWidthHeightRatio * extent.height();
|
|
double deltaWidth = newWidth - extent.width();
|
|
extent.setXMinimum( extent.xMinimum() - deltaWidth / 2 );
|
|
extent.setXMaximum( extent.xMaximum() + deltaWidth / 2 );
|
|
}
|
|
}
|
|
|
|
QgsComposerMap::~QgsComposerMap()
|
|
{
|
|
delete mOverviewStack;
|
|
delete mGridStack;
|
|
}
|
|
|
|
/* This function is called by paint() and cache() to render the map. It does not override any functions
|
|
from QGraphicsItem. */
|
|
void QgsComposerMap::draw( QPainter *painter, const QgsRectangle& extent, QSizeF size, double dpi, double* forceWidthScale )
|
|
{
|
|
Q_UNUSED( forceWidthScale );
|
|
|
|
if ( !painter )
|
|
{
|
|
return;
|
|
}
|
|
if ( qgsDoubleNear( size.width(), 0.0 ) || qgsDoubleNear( size.height(), 0.0 ) )
|
|
{
|
|
//don't attempt to draw if size is invalid
|
|
return;
|
|
}
|
|
|
|
// render
|
|
QgsMapRendererCustomPainterJob job( mapSettings( extent, size, dpi ), painter );
|
|
// Render the map in this thread. This is done because of problems
|
|
// with printing to printer on Windows (printing to PDF is fine though).
|
|
// Raster images were not displayed - see #10599
|
|
job.renderSynchronously();
|
|
}
|
|
|
|
QgsMapSettings QgsComposerMap::mapSettings( const QgsRectangle& extent, QSizeF size, int dpi ) const
|
|
{
|
|
const QgsMapSettings &ms = mComposition->mapSettings();
|
|
|
|
QScopedPointer< QgsExpressionContext > expressionContext( createExpressionContext() );
|
|
|
|
QgsMapSettings jobMapSettings;
|
|
jobMapSettings.setExtent( extent );
|
|
jobMapSettings.setOutputSize( size.toSize() );
|
|
jobMapSettings.setOutputDpi( dpi );
|
|
jobMapSettings.setMapUnits( ms.mapUnits() );
|
|
jobMapSettings.setBackgroundColor( Qt::transparent );
|
|
jobMapSettings.setOutputImageFormat( ms.outputImageFormat() );
|
|
jobMapSettings.setRotation( mEvaluatedMapRotation );
|
|
|
|
//set layers to render
|
|
QStringList theLayerSet = layersToRender( expressionContext.data() );
|
|
if ( -1 != mCurrentExportLayer )
|
|
{
|
|
//exporting with separate layers (eg, to svg layers), so we only want to render a single map layer
|
|
const int layerIdx = mCurrentExportLayer - ( hasBackground() ? 1 : 0 );
|
|
theLayerSet =
|
|
( layerIdx >= 0 && layerIdx < theLayerSet.length() )
|
|
? QStringList( theLayerSet[ theLayerSet.length() - layerIdx - 1 ] )
|
|
: QStringList(); //exporting decorations such as map frame/grid/overview, so no map layers required
|
|
}
|
|
jobMapSettings.setLayers( theLayerSet );
|
|
jobMapSettings.setLayerStyleOverrides( layerStyleOverridesToRender( *expressionContext ) );
|
|
jobMapSettings.setDestinationCrs( ms.destinationCrs() );
|
|
jobMapSettings.setCrsTransformEnabled( ms.hasCrsTransformEnabled() );
|
|
jobMapSettings.setFlags( ms.flags() );
|
|
jobMapSettings.setFlag( QgsMapSettings::DrawSelection, false );
|
|
|
|
if ( mComposition->plotStyle() == QgsComposition::Print ||
|
|
mComposition->plotStyle() == QgsComposition::Postscript )
|
|
{
|
|
//if outputing composer, disable optimisations like layer simplification
|
|
jobMapSettings.setFlag( QgsMapSettings::UseRenderingOptimization, false );
|
|
}
|
|
|
|
QgsExpressionContext* context = createExpressionContext();
|
|
jobMapSettings.setExpressionContext( *context );
|
|
delete context;
|
|
|
|
// composer-specific overrides of flags
|
|
jobMapSettings.setFlag( QgsMapSettings::ForceVectorOutput ); // force vector output (no caching of marker images etc.)
|
|
jobMapSettings.setFlag( QgsMapSettings::DrawEditingInfo, false );
|
|
jobMapSettings.setFlag( QgsMapSettings::UseAdvancedEffects, mComposition->useAdvancedEffects() ); // respect the composition's useAdvancedEffects flag
|
|
|
|
jobMapSettings.datumTransformStore() = ms.datumTransformStore();
|
|
|
|
return jobMapSettings;
|
|
}
|
|
|
|
void QgsComposerMap::cache()
|
|
{
|
|
if ( mPreviewMode == Rectangle )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( mDrawing )
|
|
{
|
|
return;
|
|
}
|
|
|
|
mDrawing = true;
|
|
|
|
double horizontalVScaleFactor = horizontalViewScaleFactor();
|
|
if ( horizontalVScaleFactor < 0 )
|
|
{
|
|
//make sure scale factor is positive
|
|
horizontalVScaleFactor = mLastValidViewScaleFactor > 0 ? mLastValidViewScaleFactor : 1;
|
|
}
|
|
|
|
const QgsRectangle &ext = *currentMapExtent();
|
|
double widthMM = ext.width() * mapUnitsToMM();
|
|
double heightMM = ext.height() * mapUnitsToMM();
|
|
|
|
int w = widthMM * horizontalVScaleFactor;
|
|
int h = heightMM * horizontalVScaleFactor;
|
|
|
|
// limit size of image for better performance
|
|
if ( w > 5000 || h > 5000 )
|
|
{
|
|
if ( w > h )
|
|
{
|
|
w = 5000;
|
|
h = w * heightMM / widthMM;
|
|
}
|
|
else
|
|
{
|
|
h = 5000;
|
|
w = h * widthMM / heightMM;
|
|
}
|
|
}
|
|
|
|
mCacheImage = QImage( w, h, QImage::Format_ARGB32 );
|
|
|
|
// set DPI of the image
|
|
mCacheImage.setDotsPerMeterX( 1000 * w / widthMM );
|
|
mCacheImage.setDotsPerMeterY( 1000 * h / heightMM );
|
|
|
|
if ( hasBackground() )
|
|
{
|
|
//Initially fill image with specified background color. This ensures that layers with blend modes will
|
|
//preview correctly
|
|
mCacheImage.fill( backgroundColor().rgba() );
|
|
}
|
|
else
|
|
{
|
|
//no background, but start with empty fill to avoid artifacts
|
|
mCacheImage.fill( QColor( 255, 255, 255, 0 ).rgba() );
|
|
}
|
|
|
|
QPainter p( &mCacheImage );
|
|
|
|
draw( &p, ext, QSizeF( w, h ), mCacheImage.logicalDpiX() );
|
|
p.end();
|
|
mCacheUpdated = true;
|
|
|
|
mDrawing = false;
|
|
}
|
|
|
|
void QgsComposerMap::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
|
|
{
|
|
Q_UNUSED( pWidget );
|
|
|
|
if ( !mComposition || !painter )
|
|
{
|
|
return;
|
|
}
|
|
if ( !shouldDrawItem() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
QRectF thisPaintRect = QRectF( 0, 0, QGraphicsRectItem::rect().width(), QGraphicsRectItem::rect().height() );
|
|
painter->save();
|
|
painter->setClipRect( thisPaintRect );
|
|
|
|
if ( mComposition->plotStyle() == QgsComposition::Preview && mPreviewMode == Rectangle )
|
|
{
|
|
// Fill with background color
|
|
drawBackground( painter );
|
|
QFont messageFont( "", 12 );
|
|
painter->setFont( messageFont );
|
|
painter->setPen( QColor( 0, 0, 0, 125 ) );
|
|
painter->drawText( thisPaintRect, tr( "Map will be printed here" ) );
|
|
}
|
|
else if ( mComposition->plotStyle() == QgsComposition::Preview )
|
|
{
|
|
//draw cached pixmap. This function does not call cache() any more because
|
|
//Qt 4.4.0 and 4.4.1 have problems with recursive paintings
|
|
//QgsComposerMap::cache() and QgsComposerMap::update() need to be called by
|
|
//client functions
|
|
|
|
//Background color is already included in cached image, so no need to draw
|
|
|
|
double imagePixelWidth = mCacheImage.width(); //how many pixels of the image are for the map extent?
|
|
double scale = rect().width() / imagePixelWidth;
|
|
|
|
painter->save();
|
|
|
|
painter->translate( mXOffset, mYOffset );
|
|
painter->scale( scale, scale );
|
|
painter->drawImage( 0, 0, mCacheImage );
|
|
|
|
//restore rotation
|
|
painter->restore();
|
|
|
|
//draw canvas items
|
|
drawCanvasItems( painter, itemStyle );
|
|
}
|
|
else if ( mComposition->plotStyle() == QgsComposition::Print ||
|
|
mComposition->plotStyle() == QgsComposition::Postscript )
|
|
{
|
|
if ( mDrawing )
|
|
{
|
|
return;
|
|
}
|
|
|
|
mDrawing = true;
|
|
QPaintDevice* thePaintDevice = painter->device();
|
|
if ( !thePaintDevice )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Fill with background color
|
|
if ( shouldDrawPart( Background ) )
|
|
{
|
|
drawBackground( painter );
|
|
}
|
|
|
|
QgsRectangle cExtent = *currentMapExtent();
|
|
|
|
QSizeF theSize( cExtent.width() * mapUnitsToMM(), cExtent.height() * mapUnitsToMM() );
|
|
|
|
painter->save();
|
|
painter->translate( mXOffset, mYOffset );
|
|
|
|
double dotsPerMM = thePaintDevice->logicalDpiX() / 25.4;
|
|
theSize *= dotsPerMM; // output size will be in dots (pixels)
|
|
painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
|
|
draw( painter, cExtent, theSize, thePaintDevice->logicalDpiX() );
|
|
|
|
//restore rotation
|
|
painter->restore();
|
|
|
|
//draw canvas items
|
|
drawCanvasItems( painter, itemStyle );
|
|
|
|
mDrawing = false;
|
|
}
|
|
|
|
painter->setClipRect( thisPaintRect, Qt::NoClip );
|
|
if ( shouldDrawPart( OverviewMapExtent ) &&
|
|
( mComposition->plotStyle() != QgsComposition::Preview || mPreviewMode != Rectangle ) )
|
|
{
|
|
mOverviewStack->drawItems( painter );
|
|
}
|
|
if ( shouldDrawPart( Grid ) &&
|
|
( mComposition->plotStyle() != QgsComposition::Preview || mPreviewMode != Rectangle ) )
|
|
{
|
|
mGridStack->drawItems( painter );
|
|
}
|
|
if ( shouldDrawPart( Frame ) )
|
|
{
|
|
drawFrame( painter );
|
|
}
|
|
if ( isSelected() && shouldDrawPart( SelectionBoxes ) )
|
|
{
|
|
drawSelectionBoxes( painter );
|
|
}
|
|
|
|
painter->restore();
|
|
}
|
|
|
|
int QgsComposerMap::numberExportLayers() const
|
|
{
|
|
return
|
|
( hasBackground() ? 1 : 0 )
|
|
+ layersToRender().length()
|
|
+ 1 // for grids, if they exist
|
|
+ 1 // for overviews, if they exist
|
|
+ ( hasFrame() ? 1 : 0 )
|
|
+ ( isSelected() ? 1 : 0 )
|
|
;
|
|
}
|
|
|
|
bool QgsComposerMap::shouldDrawPart( PartType part ) const
|
|
{
|
|
if ( -1 == mCurrentExportLayer )
|
|
{
|
|
//all parts of the composer map are visible
|
|
return true;
|
|
}
|
|
|
|
int idx = numberExportLayers();
|
|
if ( isSelected() )
|
|
{
|
|
--idx;
|
|
if ( SelectionBoxes == part )
|
|
{
|
|
return mCurrentExportLayer == idx;
|
|
}
|
|
}
|
|
|
|
if ( hasFrame() )
|
|
{
|
|
--idx;
|
|
if ( Frame == part )
|
|
{
|
|
return mCurrentExportLayer == idx;
|
|
}
|
|
}
|
|
--idx;
|
|
if ( OverviewMapExtent == part )
|
|
{
|
|
return mCurrentExportLayer == idx;
|
|
}
|
|
--idx;
|
|
if ( Grid == part )
|
|
{
|
|
return mCurrentExportLayer == idx;
|
|
}
|
|
if ( hasBackground() )
|
|
{
|
|
if ( Background == part )
|
|
{
|
|
return mCurrentExportLayer == 0;
|
|
}
|
|
}
|
|
|
|
return true; // for Layer
|
|
}
|
|
|
|
void QgsComposerMap::updateCachedImage()
|
|
{
|
|
mCacheUpdated = false;
|
|
cache();
|
|
QGraphicsRectItem::update();
|
|
}
|
|
|
|
void QgsComposerMap::renderModeUpdateCachedImage()
|
|
{
|
|
if ( mPreviewMode == Render )
|
|
{
|
|
updateCachedImage();
|
|
}
|
|
}
|
|
|
|
void QgsComposerMap::layersChanged()
|
|
{
|
|
syncLayerSet();
|
|
renderModeUpdateCachedImage();
|
|
}
|
|
|
|
void QgsComposerMap::setCacheUpdated( bool u )
|
|
{
|
|
mCacheUpdated = u;
|
|
}
|
|
|
|
const QgsMapRenderer *QgsComposerMap::mapRenderer() const
|
|
{
|
|
Q_NOWARN_DEPRECATED_PUSH
|
|
return mComposition->mapRenderer();
|
|
Q_NOWARN_DEPRECATED_POP
|
|
}
|
|
|
|
QStringList QgsComposerMap::layersToRender( const QgsExpressionContext* context ) const
|
|
{
|
|
const QgsExpressionContext* evalContext = context;
|
|
QScopedPointer< QgsExpressionContext > scopedContext;
|
|
if ( !evalContext )
|
|
{
|
|
scopedContext.reset( createExpressionContext() );
|
|
evalContext = scopedContext.data();
|
|
}
|
|
|
|
QStringList renderLayerSet;
|
|
|
|
if ( mFollowVisibilityPreset )
|
|
{
|
|
QString presetName = mFollowVisibilityPresetName;
|
|
|
|
// preset name can be overridden by data-defined one
|
|
QVariant exprVal;
|
|
if ( dataDefinedEvaluate( QgsComposerObject::MapStylePreset, exprVal, *evalContext ) )
|
|
{
|
|
presetName = exprVal.toString();
|
|
}
|
|
|
|
if ( QgsProject::instance()->visibilityPresetCollection()->hasPreset( presetName ) )
|
|
renderLayerSet = QgsProject::instance()->visibilityPresetCollection()->presetVisibleLayers( presetName );
|
|
else // fallback to using map canvas layers
|
|
renderLayerSet = mComposition->mapSettings().layers();
|
|
}
|
|
else if ( mKeepLayerSet )
|
|
{
|
|
renderLayerSet = mLayerSet;
|
|
}
|
|
else
|
|
{
|
|
renderLayerSet = mComposition->mapSettings().layers();
|
|
}
|
|
|
|
QVariant exprVal;
|
|
if ( dataDefinedEvaluate( QgsComposerObject::MapLayers, exprVal, *evalContext ) )
|
|
{
|
|
renderLayerSet.clear();
|
|
|
|
QStringList layerNames = exprVal.toString().split( '|' );
|
|
//need to convert layer names to layer ids
|
|
Q_FOREACH ( const QString& name, layerNames )
|
|
{
|
|
QList< QgsMapLayer* > matchingLayers = QgsMapLayerRegistry::instance()->mapLayersByName( name );
|
|
Q_FOREACH ( QgsMapLayer* layer, matchingLayers )
|
|
{
|
|
renderLayerSet << layer->id();
|
|
}
|
|
}
|
|
}
|
|
|
|
//remove atlas coverage layer if required
|
|
//TODO - move setting for hiding coverage layer to map item properties
|
|
if ( mComposition->atlasMode() != QgsComposition::AtlasOff )
|
|
{
|
|
if ( mComposition->atlasComposition().hideCoverage() )
|
|
{
|
|
//hiding coverage layer
|
|
int removeAt = renderLayerSet.indexOf( mComposition->atlasComposition().coverageLayer()->id() );
|
|
if ( removeAt != -1 )
|
|
{
|
|
renderLayerSet.removeAt( removeAt );
|
|
}
|
|
}
|
|
}
|
|
|
|
return renderLayerSet;
|
|
}
|
|
|
|
QMap<QString, QString> QgsComposerMap::layerStyleOverridesToRender( const QgsExpressionContext& context ) const
|
|
{
|
|
if ( mFollowVisibilityPreset )
|
|
{
|
|
QString presetName = mFollowVisibilityPresetName;
|
|
|
|
QVariant exprVal;
|
|
if ( dataDefinedEvaluate( QgsComposerObject::MapStylePreset, exprVal, context ) )
|
|
{
|
|
presetName = exprVal.toString();
|
|
}
|
|
|
|
if ( QgsProject::instance()->visibilityPresetCollection()->hasPreset( presetName ) )
|
|
return QgsProject::instance()->visibilityPresetCollection()->presetStyleOverrides( presetName );
|
|
else
|
|
return QMap<QString, QString>();
|
|
}
|
|
else if ( mKeepLayerStyles )
|
|
{
|
|
return mLayerStyleOverrides;
|
|
}
|
|
else
|
|
{
|
|
return QMap<QString, QString>();
|
|
}
|
|
}
|
|
|
|
double QgsComposerMap::scale() const
|
|
{
|
|
QgsScaleCalculator calculator;
|
|
calculator.setMapUnits( mComposition->mapSettings().mapUnits() );
|
|
calculator.setDpi( 25.4 ); //QGraphicsView units are mm
|
|
return calculator.calculate( *currentMapExtent(), rect().width() );
|
|
}
|
|
|
|
void QgsComposerMap::resize( double dx, double dy )
|
|
{
|
|
//setRect
|
|
QRectF currentRect = rect();
|
|
QRectF newSceneRect = QRectF( pos().x(), pos().y(), currentRect.width() + dx, currentRect.height() + dy );
|
|
setSceneRect( newSceneRect );
|
|
updateItem();
|
|
}
|
|
|
|
void QgsComposerMap::moveContent( double dx, double dy )
|
|
{
|
|
if ( !mDrawing )
|
|
{
|
|
transformShift( dx, dy );
|
|
currentMapExtent()->setXMinimum( currentMapExtent()->xMinimum() + dx );
|
|
currentMapExtent()->setXMaximum( currentMapExtent()->xMaximum() + dx );
|
|
currentMapExtent()->setYMinimum( currentMapExtent()->yMinimum() + dy );
|
|
currentMapExtent()->setYMaximum( currentMapExtent()->yMaximum() + dy );
|
|
|
|
//in case data defined extents are set, these override the calculated values
|
|
refreshMapExtents();
|
|
|
|
cache();
|
|
update();
|
|
emit itemChanged();
|
|
emit extentChanged();
|
|
}
|
|
}
|
|
|
|
void QgsComposerMap::zoomContent( int delta, double x, double y )
|
|
{
|
|
QSettings settings;
|
|
|
|
//read zoom mode
|
|
QgsComposerItem::ZoomMode zoomMode = static_cast< QgsComposerItem::ZoomMode >( settings.value( "/qgis/wheel_action", 2 ).toInt() );
|
|
if ( zoomMode == QgsComposerItem::NoZoom )
|
|
{
|
|
//do nothing
|
|
return;
|
|
}
|
|
|
|
double zoomFactor = settings.value( "/qgis/zoom_factor", 2.0 ).toDouble();
|
|
zoomFactor = delta > 0 ? zoomFactor : 1 / zoomFactor;
|
|
|
|
zoomContent( zoomFactor, QPointF( x, y ), zoomMode );
|
|
}
|
|
|
|
void QgsComposerMap::zoomContent( const double factor, const QPointF point, const ZoomMode mode )
|
|
{
|
|
if ( mDrawing )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( mode == QgsComposerItem::NoZoom )
|
|
{
|
|
//do nothing
|
|
return;
|
|
}
|
|
|
|
//find out map coordinates of position
|
|
double mapX = currentMapExtent()->xMinimum() + ( point.x() / rect().width() ) * ( currentMapExtent()->xMaximum() - currentMapExtent()->xMinimum() );
|
|
double mapY = currentMapExtent()->yMinimum() + ( 1 - ( point.y() / rect().height() ) ) * ( currentMapExtent()->yMaximum() - currentMapExtent()->yMinimum() );
|
|
|
|
//find out new center point
|
|
double centerX = ( currentMapExtent()->xMaximum() + currentMapExtent()->xMinimum() ) / 2;
|
|
double centerY = ( currentMapExtent()->yMaximum() + currentMapExtent()->yMinimum() ) / 2;
|
|
|
|
if ( mode != QgsComposerItem::Zoom )
|
|
{
|
|
if ( mode == QgsComposerItem::ZoomRecenter )
|
|
{
|
|
centerX = mapX;
|
|
centerY = mapY;
|
|
}
|
|
else if ( mode == QgsComposerItem::ZoomToPoint )
|
|
{
|
|
centerX = mapX + ( centerX - mapX ) * ( 1.0 / factor );
|
|
centerY = mapY + ( centerY - mapY ) * ( 1.0 / factor );
|
|
}
|
|
}
|
|
|
|
double newIntervalX, newIntervalY;
|
|
|
|
if ( factor > 0 )
|
|
{
|
|
newIntervalX = ( currentMapExtent()->xMaximum() - currentMapExtent()->xMinimum() ) / factor;
|
|
newIntervalY = ( currentMapExtent()->yMaximum() - currentMapExtent()->yMinimum() ) / factor;
|
|
}
|
|
else //no need to zoom
|
|
{
|
|
return;
|
|
}
|
|
|
|
currentMapExtent()->setXMaximum( centerX + newIntervalX / 2 );
|
|
currentMapExtent()->setXMinimum( centerX - newIntervalX / 2 );
|
|
currentMapExtent()->setYMaximum( centerY + newIntervalY / 2 );
|
|
currentMapExtent()->setYMinimum( centerY - newIntervalY / 2 );
|
|
|
|
if ( mAtlasDriven && mAtlasScalingMode == Fixed && mComposition->atlasMode() != QgsComposition::AtlasOff )
|
|
{
|
|
//if map is atlas controlled and set to fixed scaling mode, then scale changes should be treated as permanant
|
|
//and also apply to the map's original extent (see #9602)
|
|
//we can't use the scaleRatio calculated earlier, as the scale can vary depending on extent for geographic coordinate systems
|
|
QgsScaleCalculator calculator;
|
|
calculator.setMapUnits( mComposition->mapSettings().mapUnits() );
|
|
calculator.setDpi( 25.4 ); //QGraphicsView units are mm
|
|
double scaleRatio = scale() / calculator.calculate( mExtent, rect().width() );
|
|
mExtent.scale( scaleRatio );
|
|
}
|
|
|
|
//recalculate data defined scale and extents, since that may override zoom
|
|
refreshMapExtents();
|
|
|
|
cache();
|
|
update();
|
|
emit itemChanged();
|
|
emit extentChanged();
|
|
}
|
|
|
|
void QgsComposerMap::setSceneRect( const QRectF& rectangle )
|
|
{
|
|
double w = rectangle.width();
|
|
double h = rectangle.height();
|
|
//prepareGeometryChange();
|
|
|
|
QgsComposerItem::setSceneRect( rectangle );
|
|
|
|
//QGraphicsRectItem::update();
|
|
double newHeight = mExtent.width() * h / w;
|
|
mExtent = QgsRectangle( mExtent.xMinimum(), mExtent.yMinimum(), mExtent.xMaximum(), mExtent.yMinimum() + newHeight );
|
|
|
|
//recalculate data defined scale and extents
|
|
refreshMapExtents();
|
|
mCacheUpdated = false;
|
|
|
|
updateBoundingRect();
|
|
update();
|
|
emit itemChanged();
|
|
emit extentChanged();
|
|
}
|
|
|
|
void QgsComposerMap::setNewExtent( const QgsRectangle& extent )
|
|
{
|
|
if ( *currentMapExtent() == extent )
|
|
{
|
|
return;
|
|
}
|
|
*currentMapExtent() = extent;
|
|
|
|
//recalculate data defined scale and extents, since that may override extent
|
|
refreshMapExtents();
|
|
|
|
//adjust height
|
|
QRectF currentRect = rect();
|
|
|
|
double newHeight = currentRect.width() * currentMapExtent()->height() / currentMapExtent()->width();
|
|
|
|
setSceneRect( QRectF( pos().x(), pos().y(), currentRect.width(), newHeight ) );
|
|
updateItem();
|
|
}
|
|
|
|
void QgsComposerMap::zoomToExtent( const QgsRectangle &extent )
|
|
{
|
|
QgsRectangle newExtent = extent;
|
|
//Make sure the width/height ratio is the same as the current composer map extent.
|
|
//This is to keep the map item frame size fixed
|
|
double currentWidthHeightRatio = currentMapExtent()->width() / currentMapExtent()->height();
|
|
double newWidthHeightRatio = newExtent.width() / newExtent.height();
|
|
|
|
if ( currentWidthHeightRatio < newWidthHeightRatio )
|
|
{
|
|
//enlarge height of new extent, ensuring the map center stays the same
|
|
double newHeight = newExtent.width() / currentWidthHeightRatio;
|
|
double deltaHeight = newHeight - newExtent.height();
|
|
newExtent.setYMinimum( newExtent.yMinimum() - deltaHeight / 2 );
|
|
newExtent.setYMaximum( newExtent.yMaximum() + deltaHeight / 2 );
|
|
}
|
|
else
|
|
{
|
|
//enlarge width of new extent, ensuring the map center stays the same
|
|
double newWidth = currentWidthHeightRatio * newExtent.height();
|
|
double deltaWidth = newWidth - newExtent.width();
|
|
newExtent.setXMinimum( newExtent.xMinimum() - deltaWidth / 2 );
|
|
newExtent.setXMaximum( newExtent.xMaximum() + deltaWidth / 2 );
|
|
}
|
|
|
|
if ( *currentMapExtent() == newExtent )
|
|
{
|
|
return;
|
|
}
|
|
*currentMapExtent() = newExtent;
|
|
|
|
//recalculate data defined scale and extents, since that may override extent
|
|
refreshMapExtents();
|
|
|
|
mCacheUpdated = false;
|
|
updateItem();
|
|
emit itemChanged();
|
|
emit extentChanged();
|
|
}
|
|
|
|
void QgsComposerMap::setNewAtlasFeatureExtent( const QgsRectangle& extent )
|
|
{
|
|
if ( mAtlasFeatureExtent != extent )
|
|
{
|
|
//don't adjust size of item, instead adjust size of bounds to fit
|
|
QgsRectangle newExtent = extent;
|
|
|
|
//Make sure the width/height ratio is the same as the map item size
|
|
double currentWidthHeightRatio = rect().width() / rect().height();
|
|
double newWidthHeightRatio = newExtent.width() / newExtent.height();
|
|
|
|
if ( currentWidthHeightRatio < newWidthHeightRatio )
|
|
{
|
|
//enlarge height of new extent, ensuring the map center stays the same
|
|
double newHeight = newExtent.width() / currentWidthHeightRatio;
|
|
double deltaHeight = newHeight - newExtent.height();
|
|
newExtent.setYMinimum( extent.yMinimum() - deltaHeight / 2 );
|
|
newExtent.setYMaximum( extent.yMaximum() + deltaHeight / 2 );
|
|
}
|
|
else
|
|
{
|
|
//enlarge width of new extent, ensuring the map center stays the same
|
|
double newWidth = currentWidthHeightRatio * newExtent.height();
|
|
double deltaWidth = newWidth - newExtent.width();
|
|
newExtent.setXMinimum( extent.xMinimum() - deltaWidth / 2 );
|
|
newExtent.setXMaximum( extent.xMaximum() + deltaWidth / 2 );
|
|
}
|
|
|
|
mAtlasFeatureExtent = newExtent;
|
|
}
|
|
|
|
//recalculate data defined scale and extents, since that may override extents
|
|
refreshMapExtents();
|
|
|
|
mCacheUpdated = false;
|
|
emit preparedForAtlas();
|
|
updateItem();
|
|
emit itemChanged();
|
|
emit extentChanged();
|
|
}
|
|
|
|
QgsRectangle* QgsComposerMap::currentMapExtent()
|
|
{
|
|
//non-const version
|
|
if ( mAtlasDriven && mComposition->atlasMode() != QgsComposition::AtlasOff )
|
|
{
|
|
//if atlas is enabled, and we are either exporting the composition or previewing the atlas, then
|
|
//return the current temporary atlas feature extent
|
|
return &mAtlasFeatureExtent;
|
|
}
|
|
else
|
|
{
|
|
//otherwise return permenant user set extent
|
|
return &mExtent;
|
|
}
|
|
}
|
|
|
|
const QgsRectangle* QgsComposerMap::currentMapExtent() const
|
|
{
|
|
//const version
|
|
if ( mAtlasDriven && mComposition->atlasMode() != QgsComposition::AtlasOff )
|
|
{
|
|
//if atlas is enabled, and we are either exporting the composition or previewing the atlas, then
|
|
//return the current temporary atlas feature extent
|
|
return &mAtlasFeatureExtent;
|
|
}
|
|
else
|
|
{
|
|
//otherwise return permenant user set extent
|
|
return &mExtent;
|
|
}
|
|
}
|
|
|
|
void QgsComposerMap::setNewScale( double scaleDenominator, bool forceUpdate )
|
|
{
|
|
double currentScaleDenominator = scale();
|
|
|
|
if ( qgsDoubleNear( scaleDenominator, currentScaleDenominator ) || qgsDoubleNear( scaleDenominator, 0.0 ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
double scaleRatio = scaleDenominator / currentScaleDenominator;
|
|
currentMapExtent()->scale( scaleRatio );
|
|
|
|
if ( mAtlasDriven && mAtlasScalingMode == Fixed && mComposition->atlasMode() != QgsComposition::AtlasOff )
|
|
{
|
|
//if map is atlas controlled and set to fixed scaling mode, then scale changes should be treated as permanant
|
|
//and also apply to the map's original extent (see #9602)
|
|
//we can't use the scaleRatio calculated earlier, as the scale can vary depending on extent for geographic coordinate systems
|
|
QgsScaleCalculator calculator;
|
|
calculator.setMapUnits( mComposition->mapSettings().mapUnits() );
|
|
calculator.setDpi( 25.4 ); //QGraphicsView units are mm
|
|
scaleRatio = scaleDenominator / calculator.calculate( mExtent, rect().width() );
|
|
mExtent.scale( scaleRatio );
|
|
}
|
|
|
|
mCacheUpdated = false;
|
|
if ( forceUpdate )
|
|
{
|
|
cache();
|
|
update();
|
|
emit itemChanged();
|
|
}
|
|
emit extentChanged();
|
|
}
|
|
|
|
void QgsComposerMap::setPreviewMode( PreviewMode m )
|
|
{
|
|
mPreviewMode = m;
|
|
emit itemChanged();
|
|
}
|
|
|
|
void QgsComposerMap::setOffset( double xOffset, double yOffset )
|
|
{
|
|
mXOffset = xOffset;
|
|
mYOffset = yOffset;
|
|
}
|
|
|
|
void QgsComposerMap::setRotation( double r )
|
|
{
|
|
//kept for api compatibility with QGIS 2.0
|
|
setMapRotation( r );
|
|
}
|
|
|
|
void QgsComposerMap::setMapRotation( double r )
|
|
{
|
|
mMapRotation = r;
|
|
mEvaluatedMapRotation = mMapRotation;
|
|
emit mapRotationChanged( r );
|
|
emit itemChanged();
|
|
update();
|
|
}
|
|
|
|
double QgsComposerMap::mapRotation( QgsComposerObject::PropertyValueType valueType ) const
|
|
{
|
|
return valueType == QgsComposerObject::EvaluatedValue ? mEvaluatedMapRotation : mMapRotation;
|
|
}
|
|
|
|
void QgsComposerMap::refreshMapExtents( const QgsExpressionContext* context )
|
|
{
|
|
const QgsExpressionContext* evalContext = context;
|
|
QScopedPointer< QgsExpressionContext > scopedContext;
|
|
if ( !evalContext )
|
|
{
|
|
scopedContext.reset( createExpressionContext() );
|
|
evalContext = scopedContext.data();
|
|
}
|
|
|
|
//data defined map extents set?
|
|
QVariant exprVal;
|
|
|
|
QgsRectangle newExtent = *currentMapExtent();
|
|
bool useDdXMin = false;
|
|
bool useDdXMax = false;
|
|
bool useDdYMin = false;
|
|
bool useDdYMax = false;
|
|
double minXD = 0;
|
|
double minYD = 0;
|
|
double maxXD = 0;
|
|
double maxYD = 0;
|
|
|
|
if ( dataDefinedEvaluate( QgsComposerObject::MapXMin, exprVal, *evalContext ) )
|
|
{
|
|
bool ok;
|
|
minXD = exprVal.toDouble( &ok );
|
|
QgsDebugMsg( QString( "exprVal Map XMin:%1" ).arg( minXD ) );
|
|
if ( ok && !exprVal.isNull() )
|
|
{
|
|
useDdXMin = true;
|
|
newExtent.setXMinimum( minXD );
|
|
}
|
|
}
|
|
if ( dataDefinedEvaluate( QgsComposerObject::MapYMin, exprVal, *evalContext ) )
|
|
{
|
|
bool ok;
|
|
minYD = exprVal.toDouble( &ok );
|
|
QgsDebugMsg( QString( "exprVal Map YMin:%1" ).arg( minYD ) );
|
|
if ( ok && !exprVal.isNull() )
|
|
{
|
|
useDdYMin = true;
|
|
newExtent.setYMinimum( minYD );
|
|
}
|
|
}
|
|
if ( dataDefinedEvaluate( QgsComposerObject::MapXMax, exprVal, *evalContext ) )
|
|
{
|
|
bool ok;
|
|
maxXD = exprVal.toDouble( &ok );
|
|
QgsDebugMsg( QString( "exprVal Map XMax:%1" ).arg( maxXD ) );
|
|
if ( ok && !exprVal.isNull() )
|
|
{
|
|
useDdXMax = true;
|
|
newExtent.setXMaximum( maxXD );
|
|
}
|
|
}
|
|
if ( dataDefinedEvaluate( QgsComposerObject::MapYMax, exprVal, *evalContext ) )
|
|
{
|
|
bool ok;
|
|
maxYD = exprVal.toDouble( &ok );
|
|
QgsDebugMsg( QString( "exprVal Map YMax:%1" ).arg( maxYD ) );
|
|
if ( ok && !exprVal.isNull() )
|
|
{
|
|
useDdYMax = true;
|
|
newExtent.setYMaximum( maxYD );
|
|
}
|
|
}
|
|
|
|
if ( newExtent != *currentMapExtent() )
|
|
{
|
|
//calculate new extents to fit data defined extents
|
|
|
|
//Make sure the width/height ratio is the same as in current map extent.
|
|
//This is to keep the map item frame and the page layout fixed
|
|
double currentWidthHeightRatio = currentMapExtent()->width() / currentMapExtent()->height();
|
|
double newWidthHeightRatio = newExtent.width() / newExtent.height();
|
|
|
|
if ( currentWidthHeightRatio < newWidthHeightRatio )
|
|
{
|
|
//enlarge height of new extent, ensuring the map center stays the same
|
|
double newHeight = newExtent.width() / currentWidthHeightRatio;
|
|
double deltaHeight = newHeight - newExtent.height();
|
|
newExtent.setYMinimum( newExtent.yMinimum() - deltaHeight / 2 );
|
|
newExtent.setYMaximum( newExtent.yMaximum() + deltaHeight / 2 );
|
|
}
|
|
else
|
|
{
|
|
//enlarge width of new extent, ensuring the map center stays the same
|
|
double newWidth = currentWidthHeightRatio * newExtent.height();
|
|
double deltaWidth = newWidth - newExtent.width();
|
|
newExtent.setXMinimum( newExtent.xMinimum() - deltaWidth / 2 );
|
|
newExtent.setXMaximum( newExtent.xMaximum() + deltaWidth / 2 );
|
|
}
|
|
|
|
*currentMapExtent() = newExtent;
|
|
}
|
|
|
|
//now refresh scale, as this potentially overrides extents
|
|
|
|
//data defined map scale set?
|
|
if ( dataDefinedEvaluate( QgsComposerObject::MapScale, exprVal, *evalContext ) )
|
|
{
|
|
bool ok;
|
|
double scaleD = exprVal.toDouble( &ok );
|
|
QgsDebugMsg( QString( "exprVal Map Scale:%1" ).arg( scaleD ) );
|
|
if ( ok && !exprVal.isNull() )
|
|
{
|
|
setNewScale( scaleD, false );
|
|
newExtent = *currentMapExtent();
|
|
}
|
|
}
|
|
|
|
if ( useDdXMax || useDdXMin || useDdYMax || useDdYMin )
|
|
{
|
|
//if only one of min/max was set for either x or y, then make sure our extent is locked on that value
|
|
//as we can do this without altering the scale
|
|
if ( useDdXMin && !useDdXMax )
|
|
{
|
|
double xMax = currentMapExtent()->xMaximum() - ( currentMapExtent()->xMinimum() - minXD );
|
|
newExtent.setXMinimum( minXD );
|
|
newExtent.setXMaximum( xMax );
|
|
}
|
|
else if ( !useDdXMin && useDdXMax )
|
|
{
|
|
double xMin = currentMapExtent()->xMinimum() - ( currentMapExtent()->xMaximum() - maxXD );
|
|
newExtent.setXMinimum( xMin );
|
|
newExtent.setXMaximum( maxXD );
|
|
}
|
|
if ( useDdYMin && !useDdYMax )
|
|
{
|
|
double yMax = currentMapExtent()->yMaximum() - ( currentMapExtent()->yMinimum() - minYD );
|
|
newExtent.setYMinimum( minYD );
|
|
newExtent.setYMaximum( yMax );
|
|
}
|
|
else if ( !useDdYMin && useDdYMax )
|
|
{
|
|
double yMin = currentMapExtent()->yMinimum() - ( currentMapExtent()->yMaximum() - maxYD );
|
|
newExtent.setYMinimum( yMin );
|
|
newExtent.setYMaximum( maxYD );
|
|
}
|
|
|
|
if ( newExtent != *currentMapExtent() )
|
|
{
|
|
*currentMapExtent() = newExtent;
|
|
}
|
|
}
|
|
|
|
//lastly, map rotation overrides all
|
|
double mapRotation = mMapRotation;
|
|
|
|
//data defined map rotation set?
|
|
if ( dataDefinedEvaluate( QgsComposerObject::MapRotation, exprVal, *evalContext ) )
|
|
{
|
|
bool ok;
|
|
double rotationD = exprVal.toDouble( &ok );
|
|
QgsDebugMsg( QString( "exprVal Map Rotation:%1" ).arg( rotationD ) );
|
|
if ( ok && !exprVal.isNull() )
|
|
{
|
|
mapRotation = rotationD;
|
|
}
|
|
}
|
|
|
|
if ( !qgsDoubleNear( mEvaluatedMapRotation, mapRotation ) )
|
|
{
|
|
mEvaluatedMapRotation = mapRotation;
|
|
emit mapRotationChanged( mapRotation );
|
|
}
|
|
|
|
}
|
|
|
|
void QgsComposerMap::updateItem()
|
|
{
|
|
if ( !mUpdatesEnabled )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( mPreviewMode != QgsComposerMap::Rectangle && !mCacheUpdated )
|
|
{
|
|
cache();
|
|
}
|
|
QgsComposerItem::updateItem();
|
|
}
|
|
|
|
bool QgsComposerMap::containsWMSLayer() const
|
|
{
|
|
QStringList layers = mComposition->mapSettings().layers();
|
|
|
|
QStringList::const_iterator layer_it = layers.constBegin();
|
|
QgsMapLayer* currentLayer = nullptr;
|
|
|
|
for ( ; layer_it != layers.constEnd(); ++layer_it )
|
|
{
|
|
currentLayer = QgsMapLayerRegistry::instance()->mapLayer( *layer_it );
|
|
if ( currentLayer )
|
|
{
|
|
QgsRasterLayer* currentRasterLayer = qobject_cast<QgsRasterLayer *>( currentLayer );
|
|
if ( currentRasterLayer )
|
|
{
|
|
const QgsRasterDataProvider* rasterProvider = nullptr;
|
|
if (( rasterProvider = currentRasterLayer->dataProvider() ) )
|
|
{
|
|
if ( rasterProvider->name() == "wms" )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool QgsComposerMap::containsAdvancedEffects() const
|
|
{
|
|
//check easy things first
|
|
|
|
//overviews
|
|
if ( mOverviewStack->containsAdvancedEffects() )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
//grids
|
|
if ( mGridStack->containsAdvancedEffects() )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// check if map contains advanced effects like blend modes, or flattened layers for transparency
|
|
|
|
QStringList layers = mComposition->mapSettings().layers();
|
|
|
|
QStringList::const_iterator layer_it = layers.constBegin();
|
|
QgsMapLayer* currentLayer = nullptr;
|
|
|
|
for ( ; layer_it != layers.constEnd(); ++layer_it )
|
|
{
|
|
currentLayer = QgsMapLayerRegistry::instance()->mapLayer( *layer_it );
|
|
if ( currentLayer )
|
|
{
|
|
if ( currentLayer->blendMode() != QPainter::CompositionMode_SourceOver )
|
|
{
|
|
return true;
|
|
}
|
|
// if vector layer, check labels and feature blend mode
|
|
QgsVectorLayer* currentVectorLayer = qobject_cast<QgsVectorLayer *>( currentLayer );
|
|
if ( currentVectorLayer )
|
|
{
|
|
if ( currentVectorLayer->layerTransparency() != 0 )
|
|
{
|
|
return true;
|
|
}
|
|
if ( currentVectorLayer->featureBlendMode() != QPainter::CompositionMode_SourceOver )
|
|
{
|
|
return true;
|
|
}
|
|
// check label blend modes
|
|
if ( QgsPalLabeling::staticWillUseLayer( currentVectorLayer ) )
|
|
{
|
|
// Check all label blending properties
|
|
QgsPalLayerSettings layerSettings = QgsPalLayerSettings::fromLayer( currentVectorLayer );
|
|
if (( layerSettings.blendMode != QPainter::CompositionMode_SourceOver ) ||
|
|
( layerSettings.bufferDraw && layerSettings.bufferBlendMode != QPainter::CompositionMode_SourceOver ) ||
|
|
( layerSettings.shadowDraw && layerSettings.shadowBlendMode != QPainter::CompositionMode_SourceOver ) ||
|
|
( layerSettings.shapeDraw && layerSettings.shapeBlendMode != QPainter::CompositionMode_SourceOver ) )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void QgsComposerMap::connectUpdateSlot()
|
|
{
|
|
//connect signal from layer registry to update in case of new or deleted layers
|
|
QgsMapLayerRegistry* layerRegistry = QgsMapLayerRegistry::instance();
|
|
if ( layerRegistry )
|
|
{
|
|
connect( layerRegistry, SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( layersChanged() ) );
|
|
connect( layerRegistry, SIGNAL( layerWasAdded( QgsMapLayer* ) ), this, SLOT( layersChanged() ) );
|
|
}
|
|
}
|
|
|
|
bool QgsComposerMap::writeXML( QDomElement& elem, QDomDocument & doc ) const
|
|
{
|
|
if ( elem.isNull() )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
QDomElement composerMapElem = doc.createElement( "ComposerMap" );
|
|
composerMapElem.setAttribute( "id", mId );
|
|
|
|
//previewMode
|
|
if ( mPreviewMode == Cache )
|
|
{
|
|
composerMapElem.setAttribute( "previewMode", "Cache" );
|
|
}
|
|
else if ( mPreviewMode == Render )
|
|
{
|
|
composerMapElem.setAttribute( "previewMode", "Render" );
|
|
}
|
|
else //rectangle
|
|
{
|
|
composerMapElem.setAttribute( "previewMode", "Rectangle" );
|
|
}
|
|
|
|
if ( mKeepLayerSet )
|
|
{
|
|
composerMapElem.setAttribute( "keepLayerSet", "true" );
|
|
}
|
|
else
|
|
{
|
|
composerMapElem.setAttribute( "keepLayerSet", "false" );
|
|
}
|
|
|
|
if ( mDrawCanvasItems )
|
|
{
|
|
composerMapElem.setAttribute( "drawCanvasItems", "true" );
|
|
}
|
|
else
|
|
{
|
|
composerMapElem.setAttribute( "drawCanvasItems", "false" );
|
|
}
|
|
|
|
//extent
|
|
QDomElement extentElem = doc.createElement( "Extent" );
|
|
extentElem.setAttribute( "xmin", qgsDoubleToString( mExtent.xMinimum() ) );
|
|
extentElem.setAttribute( "xmax", qgsDoubleToString( mExtent.xMaximum() ) );
|
|
extentElem.setAttribute( "ymin", qgsDoubleToString( mExtent.yMinimum() ) );
|
|
extentElem.setAttribute( "ymax", qgsDoubleToString( mExtent.yMaximum() ) );
|
|
composerMapElem.appendChild( extentElem );
|
|
|
|
// follow visibility preset
|
|
composerMapElem.setAttribute( "followPreset", mFollowVisibilityPreset ? "true" : "false" );
|
|
composerMapElem.setAttribute( "followPresetName", mFollowVisibilityPresetName );
|
|
|
|
//map rotation
|
|
composerMapElem.setAttribute( "mapRotation", QString::number( mMapRotation ) );
|
|
|
|
//layer set
|
|
QDomElement layerSetElem = doc.createElement( "LayerSet" );
|
|
QStringList::const_iterator layerIt = mLayerSet.constBegin();
|
|
for ( ; layerIt != mLayerSet.constEnd(); ++layerIt )
|
|
{
|
|
QDomElement layerElem = doc.createElement( "Layer" );
|
|
QDomText layerIdText = doc.createTextNode( *layerIt );
|
|
layerElem.appendChild( layerIdText );
|
|
layerSetElem.appendChild( layerElem );
|
|
}
|
|
composerMapElem.appendChild( layerSetElem );
|
|
|
|
// override styles
|
|
if ( mKeepLayerStyles )
|
|
{
|
|
QDomElement stylesElem = doc.createElement( "LayerStyles" );
|
|
QMap<QString, QString>::const_iterator styleIt = mLayerStyleOverrides.constBegin();
|
|
for ( ; styleIt != mLayerStyleOverrides.constEnd(); ++styleIt )
|
|
{
|
|
QDomElement styleElem = doc.createElement( "LayerStyle" );
|
|
styleElem.setAttribute( "layerid", styleIt.key() );
|
|
QgsMapLayerStyle style( styleIt.value() );
|
|
style.writeXml( styleElem );
|
|
stylesElem.appendChild( styleElem );
|
|
}
|
|
composerMapElem.appendChild( stylesElem );
|
|
}
|
|
|
|
//write a dummy "Grid" element to prevent crashes on pre 2.5 versions (refs #10905)
|
|
QDomElement gridElem = doc.createElement( "Grid" );
|
|
composerMapElem.appendChild( gridElem );
|
|
|
|
//grids
|
|
mGridStack->writeXML( composerMapElem, doc );
|
|
|
|
//overviews
|
|
mOverviewStack->writeXML( composerMapElem, doc );
|
|
|
|
//atlas
|
|
QDomElement atlasElem = doc.createElement( "AtlasMap" );
|
|
atlasElem.setAttribute( "atlasDriven", mAtlasDriven );
|
|
atlasElem.setAttribute( "scalingMode", mAtlasScalingMode );
|
|
atlasElem.setAttribute( "margin", qgsDoubleToString( mAtlasMargin ) );
|
|
composerMapElem.appendChild( atlasElem );
|
|
|
|
elem.appendChild( composerMapElem );
|
|
return _writeXML( composerMapElem, doc );
|
|
}
|
|
|
|
bool QgsComposerMap::readXML( const QDomElement& itemElem, const QDomDocument& doc )
|
|
{
|
|
if ( itemElem.isNull() )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
QString idRead = itemElem.attribute( "id", "not found" );
|
|
if ( idRead != "not found" )
|
|
{
|
|
mId = idRead.toInt();
|
|
updateToolTip();
|
|
}
|
|
mPreviewMode = Rectangle;
|
|
|
|
//previewMode
|
|
QString previewMode = itemElem.attribute( "previewMode" );
|
|
if ( previewMode == "Cache" )
|
|
{
|
|
mPreviewMode = Cache;
|
|
}
|
|
else if ( previewMode == "Render" )
|
|
{
|
|
mPreviewMode = Render;
|
|
}
|
|
else
|
|
{
|
|
mPreviewMode = Rectangle;
|
|
}
|
|
|
|
//extent
|
|
QDomNodeList extentNodeList = itemElem.elementsByTagName( "Extent" );
|
|
if ( !extentNodeList.isEmpty() )
|
|
{
|
|
QDomElement extentElem = extentNodeList.at( 0 ).toElement();
|
|
double xmin, xmax, ymin, ymax;
|
|
xmin = extentElem.attribute( "xmin" ).toDouble();
|
|
xmax = extentElem.attribute( "xmax" ).toDouble();
|
|
ymin = extentElem.attribute( "ymin" ).toDouble();
|
|
ymax = extentElem.attribute( "ymax" ).toDouble();
|
|
setNewExtent( QgsRectangle( xmin, ymin, xmax, ymax ) );
|
|
}
|
|
|
|
//map rotation
|
|
if ( !qgsDoubleNear( itemElem.attribute( "mapRotation", "0" ).toDouble(), 0.0 ) )
|
|
{
|
|
mMapRotation = itemElem.attribute( "mapRotation", "0" ).toDouble();
|
|
}
|
|
|
|
// follow visibility preset
|
|
mFollowVisibilityPreset = itemElem.attribute( "followPreset" ).compare( "true" ) == 0;
|
|
mFollowVisibilityPresetName = itemElem.attribute( "followPresetName" );
|
|
|
|
//mKeepLayerSet flag
|
|
QString keepLayerSetFlag = itemElem.attribute( "keepLayerSet" );
|
|
if ( keepLayerSetFlag.compare( "true", Qt::CaseInsensitive ) == 0 )
|
|
{
|
|
mKeepLayerSet = true;
|
|
}
|
|
else
|
|
{
|
|
mKeepLayerSet = false;
|
|
}
|
|
|
|
QString drawCanvasItemsFlag = itemElem.attribute( "drawCanvasItems", "true" );
|
|
if ( drawCanvasItemsFlag.compare( "true", Qt::CaseInsensitive ) == 0 )
|
|
{
|
|
mDrawCanvasItems = true;
|
|
}
|
|
else
|
|
{
|
|
mDrawCanvasItems = false;
|
|
}
|
|
|
|
mLayerStyleOverrides.clear();
|
|
|
|
//mLayerSet
|
|
QDomNodeList layerSetNodeList = itemElem.elementsByTagName( "LayerSet" );
|
|
QStringList layerSet;
|
|
if ( !layerSetNodeList.isEmpty() )
|
|
{
|
|
QDomElement layerSetElem = layerSetNodeList.at( 0 ).toElement();
|
|
QDomNodeList layerIdNodeList = layerSetElem.elementsByTagName( "Layer" );
|
|
layerSet.reserve( layerIdNodeList.size() );
|
|
for ( int i = 0; i < layerIdNodeList.size(); ++i )
|
|
{
|
|
const QDomElement& layerIdElement = layerIdNodeList.at( i ).toElement();
|
|
layerSet << layerIdElement.text();
|
|
}
|
|
}
|
|
mLayerSet = layerSet;
|
|
|
|
// override styles
|
|
QDomNodeList layerStylesNodeList = itemElem.elementsByTagName( "LayerStyles" );
|
|
mKeepLayerStyles = !layerStylesNodeList.isEmpty();
|
|
if ( mKeepLayerStyles )
|
|
{
|
|
QDomElement layerStylesElem = layerStylesNodeList.at( 0 ).toElement();
|
|
QDomNodeList layerStyleNodeList = layerStylesElem.elementsByTagName( "LayerStyle" );
|
|
for ( int i = 0; i < layerStyleNodeList.size(); ++i )
|
|
{
|
|
const QDomElement& layerStyleElement = layerStyleNodeList.at( i ).toElement();
|
|
QString layerId = layerStyleElement.attribute( "layerid" );
|
|
QgsMapLayerStyle style;
|
|
style.readXml( layerStyleElement );
|
|
mLayerStyleOverrides.insert( layerId, style.xmlData() );
|
|
}
|
|
}
|
|
|
|
mDrawing = false;
|
|
mNumCachedLayers = 0;
|
|
mCacheUpdated = false;
|
|
|
|
//overviews
|
|
mOverviewStack->readXML( itemElem, doc );
|
|
|
|
//grids
|
|
mGridStack->readXML( itemElem, doc );
|
|
|
|
//load grid / grid annotation in old xml format
|
|
//only do this if the grid stack didn't load any grids, otherwise this will
|
|
//be the dummy element created by QGIS >= 2.5 (refs #10905)
|
|
QDomNodeList gridNodeList = itemElem.elementsByTagName( "Grid" );
|
|
if ( mGridStack->size() == 0 && !gridNodeList.isEmpty() )
|
|
{
|
|
QDomElement gridElem = gridNodeList.at( 0 ).toElement();
|
|
QgsComposerMapGrid* mapGrid = new QgsComposerMapGrid( tr( "Grid %1" ).arg( 1 ), this );
|
|
mapGrid->setEnabled( gridElem.attribute( "show", "0" ) != "0" );
|
|
mapGrid->setStyle( QgsComposerMapGrid::GridStyle( gridElem.attribute( "gridStyle", "0" ).toInt() ) );
|
|
mapGrid->setIntervalX( gridElem.attribute( "intervalX", "0" ).toDouble() );
|
|
mapGrid->setIntervalY( gridElem.attribute( "intervalY", "0" ).toDouble() );
|
|
mapGrid->setOffsetX( gridElem.attribute( "offsetX", "0" ).toDouble() );
|
|
mapGrid->setOffsetY( gridElem.attribute( "offsetY", "0" ).toDouble() );
|
|
mapGrid->setCrossLength( gridElem.attribute( "crossLength", "3" ).toDouble() );
|
|
mapGrid->setFrameStyle( static_cast< QgsComposerMapGrid::FrameStyle >( gridElem.attribute( "gridFrameStyle", "0" ).toInt() ) );
|
|
mapGrid->setFrameWidth( gridElem.attribute( "gridFrameWidth", "2.0" ).toDouble() );
|
|
mapGrid->setFramePenSize( gridElem.attribute( "gridFramePenThickness", "0.5" ).toDouble() );
|
|
mapGrid->setFramePenColor( QgsSymbolLayerV2Utils::decodeColor( gridElem.attribute( "framePenColor", "0,0,0" ) ) );
|
|
mapGrid->setFrameFillColor1( QgsSymbolLayerV2Utils::decodeColor( gridElem.attribute( "frameFillColor1", "255,255,255,255" ) ) );
|
|
mapGrid->setFrameFillColor2( QgsSymbolLayerV2Utils::decodeColor( gridElem.attribute( "frameFillColor2", "0,0,0,255" ) ) );
|
|
mapGrid->setBlendMode( QgsMapRenderer::getCompositionMode( static_cast< QgsMapRenderer::BlendMode >( itemElem.attribute( "gridBlendMode", "0" ).toUInt() ) ) );
|
|
QDomElement gridSymbolElem = gridElem.firstChildElement( "symbol" );
|
|
QgsLineSymbolV2* lineSymbol = nullptr;
|
|
if ( gridSymbolElem.isNull() )
|
|
{
|
|
//old project file, read penWidth /penColorRed, penColorGreen, penColorBlue
|
|
lineSymbol = QgsLineSymbolV2::createSimple( QgsStringMap() );
|
|
lineSymbol->setWidth( gridElem.attribute( "penWidth", "0" ).toDouble() );
|
|
lineSymbol->setColor( QColor( gridElem.attribute( "penColorRed", "0" ).toInt(),
|
|
gridElem.attribute( "penColorGreen", "0" ).toInt(),
|
|
gridElem.attribute( "penColorBlue", "0" ).toInt() ) );
|
|
}
|
|
else
|
|
{
|
|
lineSymbol = QgsSymbolLayerV2Utils::loadSymbol<QgsLineSymbolV2>( gridSymbolElem );
|
|
}
|
|
mapGrid->setLineSymbol( lineSymbol );
|
|
|
|
//annotation
|
|
QDomNodeList annotationNodeList = gridElem.elementsByTagName( "Annotation" );
|
|
if ( !annotationNodeList.isEmpty() )
|
|
{
|
|
QDomElement annotationElem = annotationNodeList.at( 0 ).toElement();
|
|
mapGrid->setAnnotationEnabled( annotationElem.attribute( "show", "0" ) != "0" );
|
|
mapGrid->setAnnotationFormat( QgsComposerMapGrid::AnnotationFormat( annotationElem.attribute( "format", "0" ).toInt() ) );
|
|
mapGrid->setAnnotationPosition( QgsComposerMapGrid::AnnotationPosition( annotationElem.attribute( "leftPosition", "0" ).toInt() ), QgsComposerMapGrid::Left );
|
|
mapGrid->setAnnotationPosition( QgsComposerMapGrid::AnnotationPosition( annotationElem.attribute( "rightPosition", "0" ).toInt() ), QgsComposerMapGrid::Right );
|
|
mapGrid->setAnnotationPosition( QgsComposerMapGrid::AnnotationPosition( annotationElem.attribute( "topPosition", "0" ).toInt() ), QgsComposerMapGrid::Top );
|
|
mapGrid->setAnnotationPosition( QgsComposerMapGrid::AnnotationPosition( annotationElem.attribute( "bottomPosition", "0" ).toInt() ), QgsComposerMapGrid::Bottom );
|
|
mapGrid->setAnnotationDirection( QgsComposerMapGrid::AnnotationDirection( annotationElem.attribute( "leftDirection", "0" ).toInt() ), QgsComposerMapGrid::Left );
|
|
mapGrid->setAnnotationDirection( QgsComposerMapGrid::AnnotationDirection( annotationElem.attribute( "rightDirection", "0" ).toInt() ), QgsComposerMapGrid::Right );
|
|
mapGrid->setAnnotationDirection( QgsComposerMapGrid::AnnotationDirection( annotationElem.attribute( "topDirection", "0" ).toInt() ), QgsComposerMapGrid::Top );
|
|
mapGrid->setAnnotationDirection( QgsComposerMapGrid::AnnotationDirection( annotationElem.attribute( "bottomDirection", "0" ).toInt() ), QgsComposerMapGrid::Bottom );
|
|
mapGrid->setAnnotationFrameDistance( annotationElem.attribute( "frameDistance", "0" ).toDouble() );
|
|
QFont annotationFont;
|
|
annotationFont.fromString( annotationElem.attribute( "font", "" ) );
|
|
mapGrid->setAnnotationFont( annotationFont );
|
|
mapGrid->setAnnotationFontColor( QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "fontColor", "0,0,0,255" ) ) );
|
|
|
|
mapGrid->setAnnotationPrecision( annotationElem.attribute( "precision", "3" ).toInt() );
|
|
}
|
|
mGridStack->addGrid( mapGrid );
|
|
}
|
|
|
|
//load overview in old xml format
|
|
QDomElement overviewFrameElem = itemElem.firstChildElement( "overviewFrame" );
|
|
if ( !overviewFrameElem.isNull() )
|
|
{
|
|
QgsComposerMapOverview* mapOverview = new QgsComposerMapOverview( tr( "Overview %1" ).arg( mOverviewStack->size() + 1 ), this );
|
|
|
|
mapOverview->setFrameMap( overviewFrameElem.attribute( "overviewFrameMap", "-1" ).toInt() );
|
|
mapOverview->setBlendMode( QgsMapRenderer::getCompositionMode( static_cast< QgsMapRenderer::BlendMode >( overviewFrameElem.attribute( "overviewBlendMode", "0" ).toUInt() ) ) );
|
|
mapOverview->setInverted( overviewFrameElem.attribute( "overviewInverted" ).compare( "true", Qt::CaseInsensitive ) == 0 );
|
|
mapOverview->setCentered( overviewFrameElem.attribute( "overviewCentered" ).compare( "true", Qt::CaseInsensitive ) == 0 );
|
|
|
|
QgsFillSymbolV2* fillSymbol = nullptr;
|
|
QDomElement overviewFrameSymbolElem = overviewFrameElem.firstChildElement( "symbol" );
|
|
if ( !overviewFrameSymbolElem.isNull() )
|
|
{
|
|
fillSymbol = QgsSymbolLayerV2Utils::loadSymbol<QgsFillSymbolV2>( overviewFrameSymbolElem );
|
|
mapOverview->setFrameSymbol( fillSymbol );
|
|
}
|
|
mOverviewStack->addOverview( mapOverview );
|
|
}
|
|
|
|
//atlas
|
|
QDomNodeList atlasNodeList = itemElem.elementsByTagName( "AtlasMap" );
|
|
if ( !atlasNodeList.isEmpty() )
|
|
{
|
|
QDomElement atlasElem = atlasNodeList.at( 0 ).toElement();
|
|
mAtlasDriven = ( atlasElem.attribute( "atlasDriven", "0" ) != "0" );
|
|
if ( atlasElem.hasAttribute( "fixedScale" ) ) // deprecated XML
|
|
{
|
|
mAtlasScalingMode = ( atlasElem.attribute( "fixedScale", "0" ) != "0" ) ? Fixed : Auto;
|
|
}
|
|
else if ( atlasElem.hasAttribute( "scalingMode" ) )
|
|
{
|
|
mAtlasScalingMode = static_cast<AtlasScalingMode>( atlasElem.attribute( "scalingMode" ).toInt() );
|
|
}
|
|
mAtlasMargin = atlasElem.attribute( "margin", "0.1" ).toDouble();
|
|
}
|
|
|
|
//restore general composer item properties
|
|
QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
|
|
if ( !composerItemList.isEmpty() )
|
|
{
|
|
QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
|
|
|
|
if ( !qgsDoubleNear( composerItemElem.attribute( "rotation", "0" ).toDouble(), 0.0 ) )
|
|
{
|
|
//in versions prior to 2.1 map rotation was stored in the rotation attribute
|
|
mMapRotation = composerItemElem.attribute( "rotation", "0" ).toDouble();
|
|
}
|
|
|
|
_readXML( composerItemElem, doc );
|
|
}
|
|
|
|
updateBoundingRect();
|
|
emit itemChanged();
|
|
return true;
|
|
}
|
|
|
|
void QgsComposerMap::storeCurrentLayerSet()
|
|
{
|
|
mLayerSet = mComposition->mapSettings().layers();
|
|
|
|
if ( mKeepLayerStyles )
|
|
{
|
|
// also store styles associated with the layers
|
|
storeCurrentLayerStyles();
|
|
}
|
|
}
|
|
|
|
|
|
void QgsComposerMap::setLayerStyleOverrides( const QMap<QString, QString>& overrides )
|
|
{
|
|
if ( overrides == mLayerStyleOverrides )
|
|
return;
|
|
|
|
mLayerStyleOverrides = overrides;
|
|
emit layerStyleOverridesChanged(); // associated legends may listen to this
|
|
}
|
|
|
|
|
|
void QgsComposerMap::storeCurrentLayerStyles()
|
|
{
|
|
mLayerStyleOverrides.clear();
|
|
Q_FOREACH ( const QString& layerID, mLayerSet )
|
|
{
|
|
if ( QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( layerID ) )
|
|
{
|
|
QgsMapLayerStyle style;
|
|
style.readFromLayer( layer );
|
|
mLayerStyleOverrides.insert( layerID, style.xmlData() );
|
|
}
|
|
}
|
|
}
|
|
|
|
void QgsComposerMap::syncLayerSet()
|
|
{
|
|
if ( mLayerSet.size() < 1 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
//if layer set is fixed, do a lookup in the layer registry to also find the non-visible layers
|
|
QStringList currentLayerSet;
|
|
if ( mKeepLayerSet )
|
|
{
|
|
currentLayerSet = QgsMapLayerRegistry::instance()->mapLayers().uniqueKeys();
|
|
}
|
|
else //only consider layers visible in the map
|
|
{
|
|
currentLayerSet = mComposition->mapSettings().layers();
|
|
}
|
|
|
|
for ( int i = mLayerSet.size() - 1; i >= 0; --i )
|
|
{
|
|
if ( !currentLayerSet.contains( mLayerSet.at( i ) ) )
|
|
{
|
|
mLayerStyleOverrides.remove( mLayerSet.at( i ) );
|
|
mLayerSet.removeAt( i );
|
|
}
|
|
}
|
|
}
|
|
|
|
QgsComposerMapGrid* QgsComposerMap::grid()
|
|
{
|
|
if ( mGridStack->size() < 1 )
|
|
{
|
|
QgsComposerMapGrid* grid = new QgsComposerMapGrid( tr( "Grid %1" ).arg( 1 ), this );
|
|
mGridStack->addGrid( grid );
|
|
}
|
|
return mGridStack->grid( 0 );
|
|
}
|
|
|
|
const QgsComposerMapGrid* QgsComposerMap::constFirstMapGrid() const
|
|
{
|
|
return const_cast<QgsComposerMap*>( this )->grid();
|
|
}
|
|
|
|
void QgsComposerMap::setGridStyle( GridStyle style )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setStyle( QgsComposerMapGrid::GridStyle( style ) );
|
|
}
|
|
|
|
QgsComposerMap::GridStyle QgsComposerMap::gridStyle() const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return static_cast< QgsComposerMap::GridStyle >( g->style() );
|
|
}
|
|
|
|
void QgsComposerMap::setGridIntervalX( double interval )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setIntervalX( interval );
|
|
}
|
|
|
|
double QgsComposerMap::gridIntervalX() const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return g->intervalX();
|
|
}
|
|
|
|
void QgsComposerMap::setGridIntervalY( double interval )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setIntervalY( interval );
|
|
}
|
|
|
|
double QgsComposerMap::gridIntervalY() const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return g->intervalY();
|
|
}
|
|
|
|
void QgsComposerMap::setGridOffsetX( double offset )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setOffsetX( offset );
|
|
}
|
|
|
|
double QgsComposerMap::gridOffsetX() const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return g->offsetX();
|
|
}
|
|
|
|
void QgsComposerMap::setGridOffsetY( double offset )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setOffsetY( offset );
|
|
}
|
|
|
|
double QgsComposerMap::gridOffsetY() const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return g->offsetY();
|
|
}
|
|
|
|
void QgsComposerMap::setGridPenWidth( double w )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setGridLineWidth( w );
|
|
}
|
|
|
|
void QgsComposerMap::setGridPenColor( const QColor& c )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setGridLineColor( c );
|
|
}
|
|
|
|
void QgsComposerMap::setGridPen( const QPen& p )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setGridLineWidth( p.widthF() );
|
|
g->setGridLineColor( p.color() );
|
|
}
|
|
|
|
QPen QgsComposerMap::gridPen() const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
QPen p;
|
|
if ( g->lineSymbol() )
|
|
{
|
|
QgsLineSymbolV2* line = g->lineSymbol()->clone();
|
|
if ( !line )
|
|
{
|
|
return p;
|
|
}
|
|
p.setWidthF( line->width() );
|
|
p.setColor( line->color() );
|
|
p.setCapStyle( Qt::FlatCap );
|
|
delete line;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
void QgsComposerMap::setGridAnnotationFont( const QFont& f )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setAnnotationFont( f );
|
|
}
|
|
|
|
QFont QgsComposerMap::gridAnnotationFont() const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return g->annotationFont();
|
|
}
|
|
|
|
void QgsComposerMap::setAnnotationFontColor( const QColor& c )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setAnnotationFontColor( c );
|
|
}
|
|
|
|
QColor QgsComposerMap::annotationFontColor() const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return g->annotationFontColor();
|
|
}
|
|
|
|
void QgsComposerMap::setGridAnnotationPrecision( int p )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setAnnotationPrecision( p );
|
|
}
|
|
|
|
int QgsComposerMap::gridAnnotationPrecision() const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return g->annotationPrecision();
|
|
}
|
|
|
|
void QgsComposerMap::setShowGridAnnotation( bool show )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setAnnotationEnabled( show );
|
|
}
|
|
|
|
bool QgsComposerMap::showGridAnnotation() const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return g->annotationEnabled();
|
|
}
|
|
|
|
void QgsComposerMap::setGridAnnotationPosition( QgsComposerMap::GridAnnotationPosition p, QgsComposerMap::Border border )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
if ( p != QgsComposerMap::Disabled )
|
|
{
|
|
g->setAnnotationPosition( static_cast< QgsComposerMapGrid::AnnotationPosition >( p ), static_cast< QgsComposerMapGrid::BorderSide >( border ) );
|
|
}
|
|
else
|
|
{
|
|
g->setAnnotationDisplay( QgsComposerMapGrid::HideAll, static_cast< QgsComposerMapGrid::BorderSide >( border ) );
|
|
}
|
|
}
|
|
|
|
QgsComposerMap::GridAnnotationPosition QgsComposerMap::gridAnnotationPosition( QgsComposerMap::Border border ) const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return static_cast< QgsComposerMap::GridAnnotationPosition >( g->annotationPosition( static_cast< QgsComposerMapGrid::BorderSide >( border ) ) );
|
|
}
|
|
|
|
void QgsComposerMap::setAnnotationFrameDistance( double d )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setAnnotationFrameDistance( d );
|
|
}
|
|
|
|
double QgsComposerMap::annotationFrameDistance() const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return g->annotationFrameDistance();
|
|
}
|
|
|
|
void QgsComposerMap::setGridAnnotationDirection( GridAnnotationDirection d, QgsComposerMap::Border border )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
//map grid direction to QgsComposerMapGrid direction (values are different)
|
|
QgsComposerMapGrid::AnnotationDirection gridDirection;
|
|
switch ( d )
|
|
{
|
|
case QgsComposerMap::Horizontal:
|
|
gridDirection = QgsComposerMapGrid::Horizontal;
|
|
break;
|
|
case QgsComposerMap::Vertical:
|
|
gridDirection = QgsComposerMapGrid::Vertical;
|
|
break;
|
|
case QgsComposerMap::BoundaryDirection:
|
|
gridDirection = QgsComposerMapGrid::BoundaryDirection;
|
|
break;
|
|
default:
|
|
gridDirection = QgsComposerMapGrid::Horizontal;
|
|
}
|
|
g->setAnnotationDirection( gridDirection, static_cast< QgsComposerMapGrid::BorderSide >( border ) );
|
|
|
|
}
|
|
|
|
QgsComposerMap::GridAnnotationDirection QgsComposerMap::gridAnnotationDirection( QgsComposerMap::Border border ) const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return static_cast< QgsComposerMap::GridAnnotationDirection >( g->annotationDirection( static_cast< QgsComposerMapGrid::BorderSide >( border ) ) );
|
|
}
|
|
|
|
void QgsComposerMap::setGridAnnotationFormat( QgsComposerMap::GridAnnotationFormat f )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setAnnotationFormat( static_cast< QgsComposerMapGrid::AnnotationFormat >( f ) );
|
|
}
|
|
|
|
QgsComposerMap::GridAnnotationFormat QgsComposerMap::gridAnnotationFormat() const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return static_cast< QgsComposerMap::GridAnnotationFormat >( g->annotationFormat() );
|
|
}
|
|
|
|
void QgsComposerMap::setGridFrameStyle( GridFrameStyle style )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setFrameStyle( static_cast< QgsComposerMapGrid::FrameStyle >( style ) );
|
|
}
|
|
|
|
QgsComposerMap::GridFrameStyle QgsComposerMap::gridFrameStyle() const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return static_cast< QgsComposerMap::GridFrameStyle >( g->frameStyle() );
|
|
}
|
|
|
|
void QgsComposerMap::setGridFrameWidth( double w )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setFrameWidth( w );
|
|
}
|
|
|
|
double QgsComposerMap::gridFrameWidth() const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return g->frameWidth();
|
|
}
|
|
|
|
void QgsComposerMap::setGridFramePenSize( double w )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setFramePenSize( w );
|
|
}
|
|
|
|
double QgsComposerMap::gridFramePenSize() const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return g->framePenSize();
|
|
}
|
|
|
|
void QgsComposerMap::setGridFramePenColor( const QColor& c )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setFramePenColor( c );
|
|
}
|
|
|
|
QColor QgsComposerMap::gridFramePenColor() const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return g->framePenColor();
|
|
}
|
|
|
|
void QgsComposerMap::setGridFrameFillColor1( const QColor& c )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setFrameFillColor1( c );
|
|
}
|
|
|
|
QColor QgsComposerMap::gridFrameFillColor1() const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return g->frameFillColor1();
|
|
}
|
|
|
|
void QgsComposerMap::setGridFrameFillColor2( const QColor& c )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setFrameFillColor2( c );
|
|
}
|
|
|
|
QColor QgsComposerMap::gridFrameFillColor2() const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return g->frameFillColor2();
|
|
}
|
|
|
|
void QgsComposerMap::setCrossLength( double l )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setCrossLength( l );
|
|
}
|
|
|
|
double QgsComposerMap::crossLength()
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return g->crossLength();
|
|
}
|
|
|
|
QgsComposerMapOverview *QgsComposerMap::overview()
|
|
{
|
|
if ( mOverviewStack->size() < 1 )
|
|
{
|
|
QgsComposerMapOverview* overview = new QgsComposerMapOverview( tr( "Overview %1" ).arg( 1 ), this );
|
|
mOverviewStack->addOverview( overview );
|
|
}
|
|
return mOverviewStack->overview( 0 );
|
|
}
|
|
|
|
const QgsComposerMapOverview *QgsComposerMap::constFirstMapOverview() const
|
|
{
|
|
return const_cast<QgsComposerMap*>( this )->overview();
|
|
}
|
|
|
|
void QgsComposerMap::setGridBlendMode( QPainter::CompositionMode blendMode )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setBlendMode( blendMode );
|
|
}
|
|
|
|
QPainter::CompositionMode QgsComposerMap::gridBlendMode() const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return g->blendMode();
|
|
}
|
|
|
|
QRectF QgsComposerMap::boundingRect() const
|
|
{
|
|
return mCurrentRectangle;
|
|
}
|
|
|
|
void QgsComposerMap::updateBoundingRect()
|
|
{
|
|
QRectF rectangle = rect();
|
|
double frameExtension = mFrame ? pen().widthF() / 2.0 : 0.0;
|
|
|
|
double topExtension = 0.0;
|
|
double rightExtension = 0.0;
|
|
double bottomExtension = 0.0;
|
|
double leftExtension = 0.0;
|
|
|
|
if ( mGridStack )
|
|
mGridStack->calculateMaxGridExtension( topExtension, rightExtension, bottomExtension, leftExtension );
|
|
|
|
topExtension = qMax( topExtension, frameExtension );
|
|
rightExtension = qMax( rightExtension, frameExtension );
|
|
bottomExtension = qMax( bottomExtension, frameExtension );
|
|
leftExtension = qMax( leftExtension, frameExtension );
|
|
|
|
rectangle.setLeft( rectangle.left() - leftExtension );
|
|
rectangle.setRight( rectangle.right() + rightExtension );
|
|
rectangle.setTop( rectangle.top() - topExtension );
|
|
rectangle.setBottom( rectangle.bottom() + bottomExtension );
|
|
if ( rectangle != mCurrentRectangle )
|
|
{
|
|
prepareGeometryChange();
|
|
mCurrentRectangle = rectangle;
|
|
}
|
|
}
|
|
|
|
void QgsComposerMap::setFrameOutlineWidth( const double outlineWidth )
|
|
{
|
|
QgsComposerItem::setFrameOutlineWidth( outlineWidth );
|
|
updateBoundingRect();
|
|
}
|
|
|
|
QgsRectangle QgsComposerMap::transformedExtent() const
|
|
{
|
|
double dx = mXOffset;
|
|
double dy = mYOffset;
|
|
transformShift( dx, dy );
|
|
return QgsRectangle( currentMapExtent()->xMinimum() - dx, currentMapExtent()->yMinimum() - dy, currentMapExtent()->xMaximum() - dx, currentMapExtent()->yMaximum() - dy );
|
|
}
|
|
|
|
QPolygonF QgsComposerMap::transformedMapPolygon() const
|
|
{
|
|
double dx = mXOffset;
|
|
double dy = mYOffset;
|
|
//qWarning("offset");
|
|
//qWarning(QString::number(dx).toLocal8Bit().data());
|
|
//qWarning(QString::number(dy).toLocal8Bit().data());
|
|
transformShift( dx, dy );
|
|
//qWarning("transformed:");
|
|
//qWarning(QString::number(dx).toLocal8Bit().data());
|
|
//qWarning(QString::number(dy).toLocal8Bit().data());
|
|
QPolygonF poly = visibleExtentPolygon();
|
|
poly.translate( -dx, -dy );
|
|
return poly;
|
|
}
|
|
|
|
void QgsComposerMap::mapPolygon( const QgsRectangle& extent, QPolygonF& poly ) const
|
|
{
|
|
poly.clear();
|
|
if ( qgsDoubleNear( mEvaluatedMapRotation, 0.0 ) )
|
|
{
|
|
poly << QPointF( extent.xMinimum(), extent.yMaximum() );
|
|
poly << QPointF( extent.xMaximum(), extent.yMaximum() );
|
|
poly << QPointF( extent.xMaximum(), extent.yMinimum() );
|
|
poly << QPointF( extent.xMinimum(), extent.yMinimum() );
|
|
//ensure polygon is closed by readding first point
|
|
poly << QPointF( poly.at( 0 ) );
|
|
return;
|
|
}
|
|
|
|
//there is rotation
|
|
QgsPoint rotationPoint(( extent.xMaximum() + extent.xMinimum() ) / 2.0, ( extent.yMaximum() + extent.yMinimum() ) / 2.0 );
|
|
double dx, dy; //x-, y- shift from rotation point to corner point
|
|
|
|
//top left point
|
|
dx = rotationPoint.x() - extent.xMinimum();
|
|
dy = rotationPoint.y() - extent.yMaximum();
|
|
QgsComposerUtils::rotate( mEvaluatedMapRotation, dx, dy );
|
|
poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
|
|
|
|
//top right point
|
|
dx = rotationPoint.x() - extent.xMaximum();
|
|
dy = rotationPoint.y() - extent.yMaximum();
|
|
QgsComposerUtils::rotate( mEvaluatedMapRotation, dx, dy );
|
|
poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
|
|
|
|
//bottom right point
|
|
dx = rotationPoint.x() - extent.xMaximum();
|
|
dy = rotationPoint.y() - extent.yMinimum();
|
|
QgsComposerUtils::rotate( mEvaluatedMapRotation, dx, dy );
|
|
poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
|
|
|
|
//bottom left point
|
|
dx = rotationPoint.x() - extent.xMinimum();
|
|
dy = rotationPoint.y() - extent.yMinimum();
|
|
QgsComposerUtils::rotate( mEvaluatedMapRotation, dx, dy );
|
|
poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
|
|
|
|
//ensure polygon is closed by readding first point
|
|
poly << QPointF( poly.at( 0 ) );
|
|
}
|
|
|
|
QPolygonF QgsComposerMap::visibleExtentPolygon() const
|
|
{
|
|
QPolygonF poly;
|
|
mapPolygon( *currentMapExtent(), poly );
|
|
return poly;
|
|
}
|
|
|
|
QString QgsComposerMap::displayName() const
|
|
{
|
|
if ( !QgsComposerItem::id().isEmpty() )
|
|
{
|
|
return QgsComposerItem::id();
|
|
}
|
|
|
|
return tr( "Map %1" ).arg( mId );
|
|
}
|
|
|
|
void QgsComposerMap::requestedExtent( QgsRectangle& extent ) const
|
|
{
|
|
QgsRectangle newExtent = *currentMapExtent();
|
|
if ( qgsDoubleNear( mEvaluatedMapRotation, 0.0 ) )
|
|
{
|
|
extent = newExtent;
|
|
}
|
|
else
|
|
{
|
|
QPolygonF poly;
|
|
mapPolygon( newExtent, poly );
|
|
QRectF bRect = poly.boundingRect();
|
|
extent.setXMinimum( bRect.left() );
|
|
extent.setXMaximum( bRect.right() );
|
|
extent.setYMinimum( bRect.top() );
|
|
extent.setYMaximum( bRect.bottom() );
|
|
}
|
|
}
|
|
|
|
QgsExpressionContext* QgsComposerMap::createExpressionContext() const
|
|
{
|
|
QgsExpressionContext* context = QgsComposerItem::createExpressionContext();
|
|
|
|
//Can't utilise QgsExpressionContextUtils::mapSettingsScope as we don't always
|
|
//have a QgsMapSettings object available when the context is required, so we manually
|
|
//add the same variables here
|
|
QgsExpressionContextScope* scope = new QgsExpressionContextScope( tr( "Map Settings" ) );
|
|
|
|
//use QgsComposerItem's id, not map item's ID, since that is user-definable
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( "map_id", QgsComposerItem::id(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( "map_rotation", mMapRotation, true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( "map_scale", scale(), true ) );
|
|
|
|
QgsRectangle extent( *currentMapExtent() );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( "map_extent_width", extent.width(), true ) );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( "map_extent_height", extent.height(), true ) );
|
|
QgsGeometry* centerPoint = QgsGeometry::fromPoint( extent.center() );
|
|
scope->addVariable( QgsExpressionContextScope::StaticVariable( "map_extent_center", QVariant::fromValue( *centerPoint ), true ) );
|
|
delete centerPoint;
|
|
|
|
context->appendScope( scope );
|
|
|
|
return context;
|
|
}
|
|
|
|
double QgsComposerMap::mapUnitsToMM() const
|
|
{
|
|
double extentWidth = currentMapExtent()->width();
|
|
if ( extentWidth <= 0 )
|
|
{
|
|
return 1;
|
|
}
|
|
return rect().width() / extentWidth;
|
|
}
|
|
|
|
void QgsComposerMap::setOverviewFrameMap( int mapId )
|
|
{
|
|
QgsComposerMapOverview* o = overview();
|
|
o->setFrameMap( mapId );
|
|
}
|
|
|
|
int QgsComposerMap::overviewFrameMapId() const
|
|
{
|
|
const QgsComposerMapOverview* o = constFirstMapOverview();
|
|
return o->frameMapId();
|
|
}
|
|
|
|
void QgsComposerMap::refreshDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property, const QgsExpressionContext* context )
|
|
{
|
|
const QgsExpressionContext* evalContext = context;
|
|
QScopedPointer< QgsExpressionContext > scopedContext;
|
|
if ( !evalContext )
|
|
{
|
|
scopedContext.reset( createExpressionContext() );
|
|
evalContext = scopedContext.data();
|
|
}
|
|
|
|
//updates data defined properties and redraws item to match
|
|
if ( property == QgsComposerObject::MapRotation || property == QgsComposerObject::MapScale ||
|
|
property == QgsComposerObject::MapXMin || property == QgsComposerObject::MapYMin ||
|
|
property == QgsComposerObject::MapXMax || property == QgsComposerObject::MapYMax ||
|
|
property == QgsComposerObject::MapAtlasMargin ||
|
|
property == QgsComposerObject::AllProperties )
|
|
{
|
|
QgsRectangle beforeExtent = *currentMapExtent();
|
|
refreshMapExtents( evalContext );
|
|
emit itemChanged();
|
|
if ( *currentMapExtent() != beforeExtent )
|
|
{
|
|
emit extentChanged();
|
|
}
|
|
}
|
|
|
|
//force redraw
|
|
mCacheUpdated = false;
|
|
|
|
QgsComposerItem::refreshDataDefinedProperty( property, evalContext );
|
|
}
|
|
|
|
void QgsComposerMap::setOverviewFrameMapSymbol( QgsFillSymbolV2* symbol )
|
|
{
|
|
QgsComposerMapOverview* o = overview();
|
|
o->setFrameSymbol( symbol );
|
|
}
|
|
|
|
QgsFillSymbolV2 *QgsComposerMap::overviewFrameMapSymbol()
|
|
{
|
|
QgsComposerMapOverview* o = overview();
|
|
return o->frameSymbol();
|
|
}
|
|
|
|
QPainter::CompositionMode QgsComposerMap::overviewBlendMode() const
|
|
{
|
|
const QgsComposerMapOverview* o = constFirstMapOverview();
|
|
return o->blendMode();
|
|
}
|
|
|
|
void QgsComposerMap::setOverviewBlendMode( QPainter::CompositionMode blendMode )
|
|
{
|
|
QgsComposerMapOverview* o = overview();
|
|
o->setBlendMode( blendMode );
|
|
}
|
|
|
|
bool QgsComposerMap::overviewInverted() const
|
|
{
|
|
const QgsComposerMapOverview* o = constFirstMapOverview();
|
|
return o->inverted();
|
|
}
|
|
|
|
void QgsComposerMap::setOverviewInverted( bool inverted )
|
|
{
|
|
QgsComposerMapOverview* o = overview();
|
|
o->setInverted( inverted );
|
|
}
|
|
|
|
bool QgsComposerMap::overviewCentered() const
|
|
{
|
|
const QgsComposerMapOverview* o = constFirstMapOverview();
|
|
return o->centered();
|
|
}
|
|
|
|
void QgsComposerMap::setOverviewCentered( bool centered )
|
|
{
|
|
QgsComposerMapOverview* o = overview();
|
|
o->setCentered( centered );
|
|
//overviewExtentChanged();
|
|
}
|
|
|
|
void QgsComposerMap::setGridLineSymbol( QgsLineSymbolV2* symbol )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setLineSymbol( symbol );
|
|
}
|
|
|
|
QgsLineSymbolV2* QgsComposerMap::gridLineSymbol()
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
return g->lineSymbol();
|
|
}
|
|
|
|
void QgsComposerMap::setGridEnabled( bool enabled )
|
|
{
|
|
QgsComposerMapGrid* g = grid();
|
|
g->setEnabled( enabled );
|
|
}
|
|
|
|
bool QgsComposerMap::gridEnabled() const
|
|
{
|
|
const QgsComposerMapGrid* g = constFirstMapGrid();
|
|
return g->enabled();
|
|
}
|
|
|
|
void QgsComposerMap::transformShift( double& xShift, double& yShift ) const
|
|
{
|
|
double mmToMapUnits = 1.0 / mapUnitsToMM();
|
|
double dxScaled = xShift * mmToMapUnits;
|
|
double dyScaled = - yShift * mmToMapUnits;
|
|
|
|
QgsComposerUtils::rotate( mEvaluatedMapRotation, dxScaled, dyScaled );
|
|
|
|
xShift = dxScaled;
|
|
yShift = dyScaled;
|
|
}
|
|
|
|
QPointF QgsComposerMap::mapToItemCoords( QPointF mapCoords ) const
|
|
{
|
|
QPolygonF mapPoly = transformedMapPolygon();
|
|
if ( mapPoly.size() < 1 )
|
|
{
|
|
return QPointF( 0, 0 );
|
|
}
|
|
|
|
QgsRectangle tExtent = transformedExtent();
|
|
QgsPoint rotationPoint(( tExtent.xMaximum() + tExtent.xMinimum() ) / 2.0, ( tExtent.yMaximum() + tExtent.yMinimum() ) / 2.0 );
|
|
double dx = mapCoords.x() - rotationPoint.x();
|
|
double dy = mapCoords.y() - rotationPoint.y();
|
|
QgsComposerUtils::rotate( -mEvaluatedMapRotation, dx, dy );
|
|
QgsPoint backRotatedCoords( rotationPoint.x() + dx, rotationPoint.y() + dy );
|
|
|
|
QgsRectangle unrotatedExtent = transformedExtent();
|
|
double xItem = rect().width() * ( backRotatedCoords.x() - unrotatedExtent.xMinimum() ) / unrotatedExtent.width();
|
|
double yItem = rect().height() * ( 1 - ( backRotatedCoords.y() - unrotatedExtent.yMinimum() ) / unrotatedExtent.height() );
|
|
return QPointF( xItem, yItem );
|
|
}
|
|
|
|
void QgsComposerMap::connectMapOverviewSignals()
|
|
{
|
|
|
|
}
|
|
|
|
void QgsComposerMap::drawCanvasItems( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle )
|
|
{
|
|
if ( !mMapCanvas || !mDrawCanvasItems )
|
|
{
|
|
return;
|
|
}
|
|
|
|
QList<QGraphicsItem*> itemList = mMapCanvas->items();
|
|
if ( itemList.size() < 1 )
|
|
{
|
|
return;
|
|
}
|
|
QGraphicsItem* currentItem = nullptr;
|
|
|
|
for ( int i = itemList.size() - 1; i >= 0; --i )
|
|
{
|
|
currentItem = itemList.at( i );
|
|
//don't draw mapcanvasmap (has z value -10)
|
|
if ( !currentItem || currentItem->data( 0 ).toString() != "AnnotationItem" )
|
|
{
|
|
continue;
|
|
}
|
|
drawCanvasItem( currentItem, painter, itemStyle );
|
|
}
|
|
}
|
|
|
|
void QgsComposerMap::drawCanvasItem( QGraphicsItem* item, QPainter* painter, const QStyleOptionGraphicsItem* itemStyle )
|
|
{
|
|
if ( !item || !mMapCanvas || !item->isVisible() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
painter->save();
|
|
painter->setRenderHint( QPainter::Antialiasing );
|
|
|
|
//determine scale factor according to graphics view dpi
|
|
double scaleFactor = 1.0 / mMapCanvas->logicalDpiX() * 25.4;
|
|
|
|
double itemX, itemY;
|
|
QGraphicsItem* parent = item->parentItem();
|
|
if ( !parent )
|
|
{
|
|
QPointF mapPos = composerMapPosForItem( item );
|
|
itemX = mapPos.x();
|
|
itemY = mapPos.y();
|
|
}
|
|
else //place item relative to the parent item
|
|
{
|
|
QPointF itemScenePos = item->scenePos();
|
|
QPointF parentScenePos = parent->scenePos();
|
|
|
|
QPointF mapPos = composerMapPosForItem( parent );
|
|
|
|
itemX = mapPos.x() + ( itemScenePos.x() - parentScenePos.x() ) * scaleFactor;
|
|
itemY = mapPos.y() + ( itemScenePos.y() - parentScenePos.y() ) * scaleFactor;
|
|
}
|
|
painter->translate( itemX, itemY );
|
|
|
|
painter->scale( scaleFactor, scaleFactor );
|
|
|
|
//a little trick to let the item know that the paint request comes from the composer
|
|
item->setData( 1, "composer" );
|
|
item->paint( painter, itemStyle, nullptr );
|
|
item->setData( 1, "" );
|
|
painter->restore();
|
|
}
|
|
|
|
QPointF QgsComposerMap::composerMapPosForItem( const QGraphicsItem* item ) const
|
|
{
|
|
if ( !item || !mMapCanvas )
|
|
{
|
|
return QPointF( 0, 0 );
|
|
}
|
|
|
|
if ( currentMapExtent()->height() <= 0 || currentMapExtent()->width() <= 0 || mMapCanvas->width() <= 0 || mMapCanvas->height() <= 0 )
|
|
{
|
|
return QPointF( 0, 0 );
|
|
}
|
|
|
|
QRectF graphicsSceneRect = mMapCanvas->sceneRect();
|
|
QPointF itemScenePos = item->scenePos();
|
|
QgsRectangle mapRendererExtent = mComposition->mapSettings().visibleExtent();
|
|
|
|
double mapX = itemScenePos.x() / graphicsSceneRect.width() * mapRendererExtent.width() + mapRendererExtent.xMinimum();
|
|
double mapY = mapRendererExtent.yMaximum() - itemScenePos.y() / graphicsSceneRect.height() * mapRendererExtent.height();
|
|
return mapToItemCoords( QPointF( mapX, mapY ) );
|
|
}
|
|
|
|
void QgsComposerMap::assignFreeId()
|
|
{
|
|
if ( !mComposition )
|
|
{
|
|
return;
|
|
}
|
|
|
|
const QgsComposerMap* existingMap = mComposition->getComposerMapById( mId );
|
|
if ( !existingMap )
|
|
{
|
|
return; //keep mId as it is still available
|
|
}
|
|
|
|
int maxId = -1;
|
|
QList<const QgsComposerMap*> mapList = mComposition->composerMapItems();
|
|
QList<const QgsComposerMap*>::const_iterator mapIt = mapList.constBegin();
|
|
for ( ; mapIt != mapList.constEnd(); ++mapIt )
|
|
{
|
|
if (( *mapIt )->id() > maxId )
|
|
{
|
|
maxId = ( *mapIt )->id();
|
|
}
|
|
}
|
|
mId = maxId + 1;
|
|
updateToolTip();
|
|
}
|
|
|
|
bool QgsComposerMap::imageSizeConsideringRotation( double& width, double& height ) const
|
|
{
|
|
//kept for api compatibility with QGIS 2.0 - use mMapRotation
|
|
Q_NOWARN_DEPRECATED_PUSH
|
|
return QgsComposerItem::imageSizeConsideringRotation( width, height, mEvaluatedMapRotation );
|
|
Q_NOWARN_DEPRECATED_POP
|
|
}
|
|
|
|
bool QgsComposerMap::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const
|
|
{
|
|
//kept for api compatibility with QGIS 2.0 - use mMapRotation
|
|
Q_NOWARN_DEPRECATED_PUSH
|
|
return QgsComposerItem::cornerPointOnRotatedAndScaledRect( x, y, width, height, mEvaluatedMapRotation );
|
|
Q_NOWARN_DEPRECATED_POP
|
|
}
|
|
|
|
void QgsComposerMap::sizeChangedByRotation( double& width, double& height )
|
|
{
|
|
//kept for api compatibility with QGIS 2.0 - use mMapRotation
|
|
Q_NOWARN_DEPRECATED_PUSH
|
|
return QgsComposerItem::sizeChangedByRotation( width, height, mEvaluatedMapRotation );
|
|
Q_NOWARN_DEPRECATED_POP
|
|
}
|
|
|
|
void QgsComposerMap::setAtlasDriven( bool enabled )
|
|
{
|
|
mAtlasDriven = enabled;
|
|
|
|
if ( !enabled )
|
|
{
|
|
//if not enabling the atlas, we still need to refresh the map extents
|
|
//so that data defined extents and scale are recalculated
|
|
refreshMapExtents();
|
|
}
|
|
}
|
|
|
|
bool QgsComposerMap::atlasFixedScale() const
|
|
{
|
|
return mAtlasScalingMode == Fixed;
|
|
}
|
|
|
|
void QgsComposerMap::setAtlasFixedScale( bool fixed )
|
|
{
|
|
// implicit : if set to false => auto scaling
|
|
mAtlasScalingMode = fixed ? Fixed : Auto;
|
|
}
|
|
|
|
double QgsComposerMap::atlasMargin( const QgsComposerObject::PropertyValueType valueType )
|
|
{
|
|
if ( valueType == QgsComposerObject::EvaluatedValue )
|
|
{
|
|
//evaluate data defined atlas margin
|
|
|
|
//start with user specified margin
|
|
double margin = mAtlasMargin;
|
|
QVariant exprVal;
|
|
QScopedPointer< QgsExpressionContext > context( createExpressionContext() );
|
|
if ( dataDefinedEvaluate( QgsComposerObject::MapAtlasMargin, exprVal, *context.data() ) )
|
|
{
|
|
bool ok;
|
|
double ddMargin = exprVal.toDouble( &ok );
|
|
QgsDebugMsg( QString( "exprVal Map Atlas Margin:%1" ).arg( ddMargin ) );
|
|
if ( ok && !exprVal.isNull() )
|
|
{
|
|
//divide by 100 to convert to 0 -> 1.0 range
|
|
margin = ddMargin / 100;
|
|
}
|
|
}
|
|
return margin;
|
|
}
|
|
else
|
|
{
|
|
return mAtlasMargin;
|
|
}
|
|
}
|
|
|