QGIS API Documentation  2.99.0-Master (7d4f81d)
qgscomposermap.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscomposermap.cpp
3  -------------------
4  begin : January 2005
5  copyright : (C) 2005 by Radim Blazek
6  email : [email protected]
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgscomposermap.h"
19 #include "qgscomposermapgrid.h"
20 #include "qgscomposermapoverview.h"
21 #include "qgscomposition.h"
22 #include "qgscomposerutils.h"
23 #include "qgslayertree.h"
24 #include "qgslogger.h"
26 #include "qgsmaplayerlistutils.h"
28 #include "qgsmaptopixel.h"
29 #include "qgsmapsettingsutils.h"
30 #include "qgspainting.h"
31 #include "qgspathresolver.h"
32 #include "qgsproject.h"
33 #include "qgsrasterdataprovider.h"
34 #include "qgsrasterlayer.h"
35 #include "qgsreadwritecontext.h"
36 #include "qgsrendercontext.h"
37 #include "qgsscalecalculator.h"
38 #include "qgsvectorlayer.h"
39 #include "qgspallabeling.h"
40 #include "qgsexpression.h"
41 #include "qgsmapthemecollection.h"
42 #include "qgsannotation.h"
43 #include "qgsannotationmanager.h"
44 
45 #include "qgssymbollayerutils.h" //for pointOnLineWithDistance
46 
47 #include <QGraphicsScene>
48 #include <QGraphicsView>
49 #include <QPainter>
50 #include <QSettings>
51 #include <cmath>
52 
53 QgsComposerMap::QgsComposerMap( QgsComposition *composition, int x, int y, int width, int height )
54  : QgsComposerItem( x, y, width, height, composition )
55 {
56  assignFreeId();
57 
58  mCurrentRectangle = rect();
59 
60  QgsProject *project = mComposition->project();
61 
62  //get the color for map canvas background and set map background color accordingly
63  int bgRedInt = project->readNumEntry( QStringLiteral( "Gui" ), QStringLiteral( "/CanvasColorRedPart" ), 255 );
64  int bgGreenInt = project->readNumEntry( QStringLiteral( "Gui" ), QStringLiteral( "/CanvasColorGreenPart" ), 255 );
65  int bgBlueInt = project->readNumEntry( QStringLiteral( "Gui" ), QStringLiteral( "/CanvasColorBluePart" ), 255 );
66  setBackgroundColor( QColor( bgRedInt, bgGreenInt, bgBlueInt ) );
67 
68  init();
69 
70  setSceneRect( QRectF( x, y, width, height ) );
71 }
72 
74  : QgsComposerItem( 0, 0, 10, 10, composition )
75 {
76  mId = mComposition->composerMapItems().size();
77  mCurrentRectangle = rect();
78 
79  init();
80  updateToolTip();
81 }
82 
83 void QgsComposerMap::init()
84 {
85  mGridStack = new QgsComposerMapGridStack( this );
86  mOverviewStack = new QgsComposerMapOverviewStack( this );
87  connectUpdateSlot();
88 }
89 
90 void QgsComposerMap::updateToolTip()
91 {
92  setToolTip( tr( "Map %1" ).arg( mId ) );
93 }
94 
95 void QgsComposerMap::adjustExtentToItemShape( double itemWidth, double itemHeight, QgsRectangle &extent ) const
96 {
97  double itemWidthHeightRatio = itemWidth / itemHeight;
98  double newWidthHeightRatio = extent.width() / extent.height();
99 
100  if ( itemWidthHeightRatio <= newWidthHeightRatio )
101  {
102  //enlarge height of new extent, ensuring the map center stays the same
103  double newHeight = extent.width() / itemWidthHeightRatio;
104  double deltaHeight = newHeight - extent.height();
105  extent.setYMinimum( extent.yMinimum() - deltaHeight / 2 );
106  extent.setYMaximum( extent.yMaximum() + deltaHeight / 2 );
107  }
108  else
109  {
110  //enlarge width of new extent, ensuring the map center stays the same
111  double newWidth = itemWidthHeightRatio * extent.height();
112  double deltaWidth = newWidth - extent.width();
113  extent.setXMinimum( extent.xMinimum() - deltaWidth / 2 );
114  extent.setXMaximum( extent.xMaximum() + deltaWidth / 2 );
115  }
116 }
117 
119 {
120  delete mOverviewStack;
121  delete mGridStack;
122 
123  if ( mPainterJob )
124  {
125  disconnect( mPainterJob.get(), &QgsMapRendererCustomPainterJob::finished, this, &QgsComposerMap::painterJobFinished );
126  mPainterJob->cancel();
127  mPainter->end();
128  }
129 }
130 
131 /* This function is called by paint() to render the map. It does not override any functions
132 from QGraphicsItem. */
133 void QgsComposerMap::draw( QPainter *painter, const QgsRectangle &extent, QSizeF size, double dpi, double *forceWidthScale )
134 {
135  Q_UNUSED( forceWidthScale );
136 
137  if ( !painter )
138  {
139  return;
140  }
141  if ( qgsDoubleNear( size.width(), 0.0 ) || qgsDoubleNear( size.height(), 0.0 ) )
142  {
143  //don't attempt to draw if size is invalid
144  return;
145  }
146 
147  // render
148  QgsMapRendererCustomPainterJob job( mapSettings( extent, size, dpi ), painter );
149  // Render the map in this thread. This is done because of problems
150  // with printing to printer on Windows (printing to PDF is fine though).
151  // Raster images were not displayed - see #10599
152  job.renderSynchronously();
153 }
154 
155 QgsMapSettings QgsComposerMap::mapSettings( const QgsRectangle &extent, QSizeF size, int dpi ) const
156 {
157  QgsExpressionContext expressionContext = createExpressionContext();
158  QgsCoordinateReferenceSystem renderCrs = crs();
159 
160  QgsMapSettings jobMapSettings;
161  jobMapSettings.setDestinationCrs( renderCrs );
162  jobMapSettings.setExtent( extent );
163  jobMapSettings.setOutputSize( size.toSize() );
164  jobMapSettings.setOutputDpi( dpi );
165  jobMapSettings.setBackgroundColor( Qt::transparent );
166  jobMapSettings.setRotation( mEvaluatedMapRotation );
167  jobMapSettings.setEllipsoid( mComposition->project()->ellipsoid() );
168 
169  //set layers to render
170  QList<QgsMapLayer *> layers = layersToRender( &expressionContext );
171  if ( -1 != mCurrentExportLayer )
172  {
173  const int layerIdx = mCurrentExportLayer - ( hasBackground() ? 1 : 0 );
174  if ( layerIdx >= 0 && layerIdx < layers.length() )
175  {
176  // exporting with separate layers (e.g., to svg layers), so we only want to render a single map layer
177  QgsMapLayer *ml = layers[ layers.length() - layerIdx - 1 ];
178  layers.clear();
179  layers << ml;
180  }
181  else
182  {
183  // exporting decorations such as map frame/grid/overview, so no map layers required
184  layers.clear();
185  }
186  }
187  jobMapSettings.setLayers( layers );
188  jobMapSettings.setLayerStyleOverrides( layerStyleOverridesToRender( expressionContext ) );
189 
192  {
193  //if outputting composer, disable optimisations like layer simplification
194  jobMapSettings.setFlag( QgsMapSettings::UseRenderingOptimization, false );
195  }
196 
198  jobMapSettings.setExpressionContext( context );
199 
200  // composer-specific overrides of flags
201  jobMapSettings.setFlag( QgsMapSettings::ForceVectorOutput, true ); // force vector output (no caching of marker images etc.)
202  jobMapSettings.setFlag( QgsMapSettings::Antialiasing, true );
203  jobMapSettings.setFlag( QgsMapSettings::DrawEditingInfo, false );
204  jobMapSettings.setFlag( QgsMapSettings::DrawSelection, false );
205  jobMapSettings.setFlag( QgsMapSettings::UseAdvancedEffects, mComposition->useAdvancedEffects() ); // respect the composition's useAdvancedEffects flag
206 
207  jobMapSettings.datumTransformStore().setDestinationCrs( renderCrs );
208 
210 
211  return jobMapSettings;
212 }
213 
214 void QgsComposerMap::recreateCachedImageInBackground()
215 {
216  if ( mPainterJob )
217  {
218  disconnect( mPainterJob.get(), &QgsMapRendererCustomPainterJob::finished, this, &QgsComposerMap::painterJobFinished );
219  QgsMapRendererCustomPainterJob *oldJob = mPainterJob.release();
220  QPainter *oldPainter = mPainter.release();
221  QImage *oldImage = mCacheRenderingImage.release();
222  connect( oldJob, &QgsMapRendererCustomPainterJob::finished, this, [oldPainter, oldJob, oldImage]
223  {
224  oldJob->deleteLater();
225  delete oldPainter;
226  delete oldImage;
227  } );
228  oldJob->cancelWithoutBlocking();
229  }
230  else
231  {
232  mCacheRenderingImage.reset( nullptr );
233  }
234 
235  Q_ASSERT( !mPainterJob );
236  Q_ASSERT( !mPainter );
237  Q_ASSERT( !mCacheRenderingImage );
238 
239  double horizontalVScaleFactor = horizontalViewScaleFactor();
240  if ( horizontalVScaleFactor < 0 )
241  {
242  //make sure scale factor is positive
243  horizontalVScaleFactor = mLastValidViewScaleFactor > 0 ? mLastValidViewScaleFactor : 1;
244  }
245 
246  const QgsRectangle &ext = *currentMapExtent();
247  double widthMM = ext.width() * mapUnitsToMM();
248  double heightMM = ext.height() * mapUnitsToMM();
249 
250  int w = widthMM * horizontalVScaleFactor;
251  int h = heightMM * horizontalVScaleFactor;
252 
253  // limit size of image for better performance
254  if ( w > 5000 || h > 5000 )
255  {
256  if ( w > h )
257  {
258  w = 5000;
259  h = w * heightMM / widthMM;
260  }
261  else
262  {
263  h = 5000;
264  w = h * widthMM / heightMM;
265  }
266  }
267 
268  if ( w <= 0 || h <= 0 )
269  return;
270 
271  mCacheRenderingImage.reset( new QImage( w, h, QImage::Format_ARGB32 ) );
272 
273  // set DPI of the image
274  mCacheRenderingImage->setDotsPerMeterX( 1000 * w / widthMM );
275  mCacheRenderingImage->setDotsPerMeterY( 1000 * h / heightMM );
276 
277  if ( hasBackground() )
278  {
279  //Initially fill image with specified background color. This ensures that layers with blend modes will
280  //preview correctly
281  mCacheRenderingImage->fill( backgroundColor().rgba() );
282  }
283  else
284  {
285  //no background, but start with empty fill to avoid artifacts
286  mCacheRenderingImage->fill( QColor( 255, 255, 255, 0 ).rgba() );
287  }
288 
289  mCacheInvalidated = false;
290  mPainter.reset( new QPainter( mCacheRenderingImage.get() ) );
291  QgsMapSettings settings( mapSettings( ext, QSizeF( w, h ), mCacheRenderingImage->logicalDpiX() ) );
292  mPainterJob.reset( new QgsMapRendererCustomPainterJob( settings, mPainter.get() ) );
293  connect( mPainterJob.get(), &QgsMapRendererCustomPainterJob::finished, this, &QgsComposerMap::painterJobFinished );
294  mPainterJob->start();
295 }
296 
297 void QgsComposerMap::painterJobFinished()
298 {
299  mPainter->end();
300  mPainterJob.reset( nullptr );
301  mPainter.reset( nullptr );
302  mCacheFinalImage = std::move( mCacheRenderingImage );
303  mLastRenderedImageOffsetX = 0;
304  mLastRenderedImageOffsetY = 0;
305  updateItem();
306 }
307 
308 void QgsComposerMap::paint( QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *pWidget )
309 {
310  Q_UNUSED( pWidget );
311 
312  if ( !mComposition || !painter || !painter->device() )
313  {
314  return;
315  }
316  if ( !shouldDrawItem() )
317  {
318  return;
319  }
320 
321  QRectF thisPaintRect = QRectF( 0, 0, QGraphicsRectItem::rect().width(), QGraphicsRectItem::rect().height() );
322  if ( thisPaintRect.width() == 0 || thisPaintRect.height() == 0 )
323  return;
324 
325  painter->save();
326  painter->setClipRect( thisPaintRect );
327 
329  {
330  if ( !mCacheFinalImage || mCacheFinalImage->isNull() )
331  {
332  // No initial render available - so draw some preview text alerting user
333  drawBackground( painter );
334  painter->setBrush( QBrush( QColor( 125, 125, 125, 125 ) ) );
335  painter->drawRect( thisPaintRect );
336  painter->setBrush( Qt::NoBrush );
337  QFont messageFont;
338  messageFont.setPointSize( 12 );
339  painter->setFont( messageFont );
340  painter->setPen( QColor( 255, 255, 255, 255 ) );
341  painter->drawText( thisPaintRect, Qt::AlignCenter | Qt::AlignHCenter, tr( "Rendering map" ) );
342  if ( !mPainterJob )
343  {
344  // this is the map's very first paint - trigger a cache update
345  recreateCachedImageInBackground();
346  }
347  }
348  else
349  {
350  if ( mCacheInvalidated )
351  {
352  // cache was invalidated - trigger a background update
353  recreateCachedImageInBackground();
354  }
355 
356  //Background color is already included in cached image, so no need to draw
357 
358  double imagePixelWidth = mCacheFinalImage->width(); //how many pixels of the image are for the map extent?
359  double scale = rect().width() / imagePixelWidth;
360 
361  painter->save();
362 
363  painter->translate( mLastRenderedImageOffsetX + mXOffset, mLastRenderedImageOffsetY + mYOffset );
364  painter->scale( scale, scale );
365  painter->drawImage( 0, 0, *mCacheFinalImage );
366 
367  //restore rotation
368  painter->restore();
369  }
370  }
371  else if ( mComposition->plotStyle() == QgsComposition::Print ||
373  {
374  if ( mDrawing )
375  {
376  return;
377  }
378 
379  mDrawing = true;
380  QPaintDevice *paintDevice = painter->device();
381  if ( !paintDevice )
382  {
383  return;
384  }
385 
386  // Fill with background color
387  if ( shouldDrawPart( Background ) )
388  {
389  drawBackground( painter );
390  }
391 
392  QgsRectangle cExtent = *currentMapExtent();
393 
394  QSizeF size( cExtent.width() * mapUnitsToMM(), cExtent.height() * mapUnitsToMM() );
395 
396  painter->save();
397  painter->translate( mXOffset, mYOffset );
398 
399  double dotsPerMM = paintDevice->logicalDpiX() / 25.4;
400  size *= dotsPerMM; // output size will be in dots (pixels)
401  painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
402  draw( painter, cExtent, size, paintDevice->logicalDpiX() );
403 
404  //restore rotation
405  painter->restore();
406  mDrawing = false;
407  }
408 
409  painter->setClipRect( thisPaintRect, Qt::NoClip );
410  if ( shouldDrawPart( OverviewMapExtent ) )
411  {
412  mOverviewStack->drawItems( painter );
413  }
414  if ( shouldDrawPart( Grid ) )
415  {
416  mGridStack->drawItems( painter );
417  }
418 
419  //draw canvas items
420  drawAnnotations( painter );
421 
422  if ( shouldDrawPart( Frame ) )
423  {
424  drawFrame( painter );
425  }
426  if ( isSelected() && shouldDrawPart( SelectionBoxes ) )
427  {
428  drawSelectionBoxes( painter );
429  }
430 
431  painter->restore();
432 }
433 
435 {
436  mCacheInvalidated = true;
437  updateItem();
438 }
439 
441 {
442  return
443  ( hasBackground() ? 1 : 0 )
444  + layersToRender().length()
445  + 1 // for grids, if they exist
446  + 1 // for overviews, if they exist
447  + ( hasFrame() ? 1 : 0 )
448  + ( isSelected() ? 1 : 0 )
449  ;
450 }
451 
452 bool QgsComposerMap::shouldDrawPart( PartType part ) const
453 {
454  if ( -1 == mCurrentExportLayer )
455  {
456  //all parts of the composer map are visible
457  return true;
458  }
459 
460  int idx = numberExportLayers();
461  if ( isSelected() )
462  {
463  --idx;
464  if ( SelectionBoxes == part )
465  {
466  return mCurrentExportLayer == idx;
467  }
468  }
469 
470  if ( hasFrame() )
471  {
472  --idx;
473  if ( Frame == part )
474  {
475  return mCurrentExportLayer == idx;
476  }
477  }
478  --idx;
479  if ( OverviewMapExtent == part )
480  {
481  return mCurrentExportLayer == idx;
482  }
483  --idx;
484  if ( Grid == part )
485  {
486  return mCurrentExportLayer == idx;
487  }
488  if ( hasBackground() )
489  {
490  if ( Background == part )
491  {
492  return mCurrentExportLayer == 0;
493  }
494  }
495 
496  return true; // for Layer
497 }
498 
499 QList<QgsMapLayer *> QgsComposerMap::layersToRender( const QgsExpressionContext *context ) const
500 {
502  const QgsExpressionContext *evalContext = context ? context : &scopedContext;
503 
504  QList<QgsMapLayer *> renderLayers;
505 
506  if ( mFollowVisibilityPreset )
507  {
508  QString presetName = mFollowVisibilityPresetName;
509 
510  // preset name can be overridden by data-defined one
511  presetName = mDataDefinedProperties.valueAsString( QgsComposerObject::MapStylePreset, *evalContext, presetName );
512 
513  if ( mComposition->project()->mapThemeCollection()->hasMapTheme( presetName ) )
514  renderLayers = mComposition->project()->mapThemeCollection()->mapThemeVisibleLayers( presetName );
515  else // fallback to using map canvas layers
517  }
518  else if ( !layers().isEmpty() )
519  {
520  renderLayers = layers();
521  }
522  else
523  {
525  }
526 
527  bool ok = false;
528  QString ddLayers = mDataDefinedProperties.valueAsString( QgsComposerObject::MapLayers, *evalContext, QString(), &ok );
529  if ( ok )
530  {
531  renderLayers.clear();
532 
533  QStringList layerNames = ddLayers.split( '|' );
534  //need to convert layer names to layer ids
535  Q_FOREACH ( const QString &name, layerNames )
536  {
537  QList< QgsMapLayer * > matchingLayers = mComposition->project()->mapLayersByName( name );
538  Q_FOREACH ( QgsMapLayer *layer, matchingLayers )
539  {
540  renderLayers << layer;
541  }
542  }
543  }
544 
545  //remove atlas coverage layer if required
546  //TODO - move setting for hiding coverage layer to map item properties
548  {
550  {
551  //hiding coverage layer
552  int removeAt = renderLayers.indexOf( mComposition->atlasComposition().coverageLayer() );
553  if ( removeAt != -1 )
554  {
555  renderLayers.removeAt( removeAt );
556  }
557  }
558  }
559 
560  return renderLayers;
561 }
562 
563 QMap<QString, QString> QgsComposerMap::layerStyleOverridesToRender( const QgsExpressionContext &context ) const
564 {
565  if ( mFollowVisibilityPreset )
566  {
567  QString presetName = mFollowVisibilityPresetName;
568 
569  // data defined preset name?
570  presetName = mDataDefinedProperties.valueAsString( QgsComposerObject::MapStylePreset, context, presetName );
571 
572  if ( mComposition->project()->mapThemeCollection()->hasMapTheme( presetName ) )
574  else
575  return QMap<QString, QString>();
576  }
577  else if ( mKeepLayerStyles )
578  {
579  return mLayerStyleOverrides;
580  }
581  else
582  {
583  return QMap<QString, QString>();
584  }
585 }
586 
587 double QgsComposerMap::scale() const
588 {
589  QgsScaleCalculator calculator;
590  calculator.setMapUnits( crs().mapUnits() );
591  calculator.setDpi( 25.4 ); //QGraphicsView units are mm
592  return calculator.calculate( *currentMapExtent(), rect().width() );
593 }
594 
595 void QgsComposerMap::resize( double dx, double dy )
596 {
597  //setRect
598  QRectF currentRect = rect();
599  QRectF newSceneRect = QRectF( pos().x(), pos().y(), currentRect.width() + dx, currentRect.height() + dy );
600  setSceneRect( newSceneRect );
601  updateItem();
602 }
603 
604 void QgsComposerMap::moveContent( double dx, double dy )
605 {
606  mLastRenderedImageOffsetX -= dx;
607  mLastRenderedImageOffsetY -= dy;
608  if ( !mDrawing )
609  {
610  transformShift( dx, dy );
611  currentMapExtent()->setXMinimum( currentMapExtent()->xMinimum() + dx );
612  currentMapExtent()->setXMaximum( currentMapExtent()->xMaximum() + dx );
613  currentMapExtent()->setYMinimum( currentMapExtent()->yMinimum() + dy );
614  currentMapExtent()->setYMaximum( currentMapExtent()->yMaximum() + dy );
615 
616  //in case data defined extents are set, these override the calculated values
617  refreshMapExtents();
618 
619  invalidateCache();
620  emit itemChanged();
621  emit extentChanged();
622  }
623 }
624 
625 void QgsComposerMap::zoomContent( const double factor, const QPointF point, const ZoomMode mode )
626 {
627  if ( mDrawing )
628  {
629  return;
630  }
631 
632  if ( mode == QgsComposerItem::NoZoom )
633  {
634  //do nothing
635  return;
636  }
637 
638  //find out map coordinates of position
639  double mapX = currentMapExtent()->xMinimum() + ( point.x() / rect().width() ) * ( currentMapExtent()->xMaximum() - currentMapExtent()->xMinimum() );
640  double mapY = currentMapExtent()->yMinimum() + ( 1 - ( point.y() / rect().height() ) ) * ( currentMapExtent()->yMaximum() - currentMapExtent()->yMinimum() );
641 
642  //find out new center point
643  double centerX = ( currentMapExtent()->xMaximum() + currentMapExtent()->xMinimum() ) / 2;
644  double centerY = ( currentMapExtent()->yMaximum() + currentMapExtent()->yMinimum() ) / 2;
645 
646  if ( mode != QgsComposerItem::Zoom )
647  {
648  if ( mode == QgsComposerItem::ZoomRecenter )
649  {
650  centerX = mapX;
651  centerY = mapY;
652  }
653  else if ( mode == QgsComposerItem::ZoomToPoint )
654  {
655  centerX = mapX + ( centerX - mapX ) * ( 1.0 / factor );
656  centerY = mapY + ( centerY - mapY ) * ( 1.0 / factor );
657  }
658  }
659 
660  double newIntervalX, newIntervalY;
661 
662  if ( factor > 0 )
663  {
664  newIntervalX = ( currentMapExtent()->xMaximum() - currentMapExtent()->xMinimum() ) / factor;
665  newIntervalY = ( currentMapExtent()->yMaximum() - currentMapExtent()->yMinimum() ) / factor;
666  }
667  else //no need to zoom
668  {
669  return;
670  }
671 
672  currentMapExtent()->setXMaximum( centerX + newIntervalX / 2 );
673  currentMapExtent()->setXMinimum( centerX - newIntervalX / 2 );
674  currentMapExtent()->setYMaximum( centerY + newIntervalY / 2 );
675  currentMapExtent()->setYMinimum( centerY - newIntervalY / 2 );
676 
677  if ( mAtlasDriven && mAtlasScalingMode == Fixed && mComposition->atlasMode() != QgsComposition::AtlasOff )
678  {
679  //if map is atlas controlled and set to fixed scaling mode, then scale changes should be treated as permanent
680  //and also apply to the map's original extent (see #9602)
681  //we can't use the scaleRatio calculated earlier, as the scale can vary depending on extent for geographic coordinate systems
682  QgsScaleCalculator calculator;
683  calculator.setMapUnits( crs().mapUnits() );
684  calculator.setDpi( 25.4 ); //QGraphicsView units are mm
685  double scaleRatio = scale() / calculator.calculate( mExtent, rect().width() );
686  mExtent.scale( scaleRatio );
687  }
688 
689  //recalculate data defined scale and extents, since that may override zoom
690  refreshMapExtents();
691 
692  invalidateCache();
693  emit itemChanged();
694  emit extentChanged();
695 }
696 
697 void QgsComposerMap::setSceneRect( const QRectF &rectangle )
698 {
699  double w = rectangle.width();
700  double h = rectangle.height();
701  //prepareGeometryChange();
702 
703  QgsComposerItem::setSceneRect( rectangle );
704 
705  //QGraphicsRectItem::update();
706  double newHeight = mExtent.width() * h / w;
707  mExtent = QgsRectangle( mExtent.xMinimum(), mExtent.yMinimum(), mExtent.xMaximum(), mExtent.yMinimum() + newHeight );
708 
709  //recalculate data defined scale and extents
710  refreshMapExtents();
712  invalidateCache();
713  emit itemChanged();
714  emit extentChanged();
715 }
716 
718 {
719  if ( *currentMapExtent() == extent )
720  {
721  return;
722  }
724 
725  //recalculate data defined scale and extents, since that may override extent
726  refreshMapExtents();
727 
728  //adjust height
729  QRectF currentRect = rect();
730 
731  double newHeight = currentRect.width() * currentMapExtent()->height() / currentMapExtent()->width();
732 
733  setSceneRect( QRectF( pos().x(), pos().y(), currentRect.width(), newHeight ) );
734  updateItem();
735 }
736 
738 {
739  QgsRectangle newExtent = extent;
740  QgsRectangle currentExtent = *currentMapExtent();
741  //Make sure the width/height ratio is the same as the current composer map extent.
742  //This is to keep the map item frame size fixed
743  double currentWidthHeightRatio = 1.0;
744  if ( !currentExtent.isNull() )
745  currentWidthHeightRatio = currentExtent.width() / currentExtent.height();
746  else
747  currentWidthHeightRatio = rect().width() / rect().height();
748  double newWidthHeightRatio = newExtent.width() / newExtent.height();
749 
750  if ( currentWidthHeightRatio < newWidthHeightRatio )
751  {
752  //enlarge height of new extent, ensuring the map center stays the same
753  double newHeight = newExtent.width() / currentWidthHeightRatio;
754  double deltaHeight = newHeight - newExtent.height();
755  newExtent.setYMinimum( newExtent.yMinimum() - deltaHeight / 2 );
756  newExtent.setYMaximum( newExtent.yMaximum() + deltaHeight / 2 );
757  }
758  else
759  {
760  //enlarge width of new extent, ensuring the map center stays the same
761  double newWidth = currentWidthHeightRatio * newExtent.height();
762  double deltaWidth = newWidth - newExtent.width();
763  newExtent.setXMinimum( newExtent.xMinimum() - deltaWidth / 2 );
764  newExtent.setXMaximum( newExtent.xMaximum() + deltaWidth / 2 );
765  }
766 
767  if ( *currentMapExtent() == newExtent )
768  {
769  return;
770  }
771  *currentMapExtent() = newExtent;
772 
773  //recalculate data defined scale and extents, since that may override extent
774  refreshMapExtents();
775 
776  invalidateCache();
777  emit itemChanged();
778  emit extentChanged();
779 }
780 
782 {
783  if ( mAtlasFeatureExtent != extent )
784  {
785  //don't adjust size of item, instead adjust size of bounds to fit
786  QgsRectangle newExtent = extent;
787 
788  //Make sure the width/height ratio is the same as the map item size
789  double currentWidthHeightRatio = rect().width() / rect().height();
790  double newWidthHeightRatio = newExtent.width() / newExtent.height();
791 
792  if ( currentWidthHeightRatio < newWidthHeightRatio )
793  {
794  //enlarge height of new extent, ensuring the map center stays the same
795  double newHeight = newExtent.width() / currentWidthHeightRatio;
796  double deltaHeight = newHeight - newExtent.height();
797  newExtent.setYMinimum( extent.yMinimum() - deltaHeight / 2 );
798  newExtent.setYMaximum( extent.yMaximum() + deltaHeight / 2 );
799  }
800  else
801  {
802  //enlarge width of new extent, ensuring the map center stays the same
803  double newWidth = currentWidthHeightRatio * newExtent.height();
804  double deltaWidth = newWidth - newExtent.width();
805  newExtent.setXMinimum( extent.xMinimum() - deltaWidth / 2 );
806  newExtent.setXMaximum( extent.xMaximum() + deltaWidth / 2 );
807  }
808 
809  mAtlasFeatureExtent = newExtent;
810  }
811 
812  //recalculate data defined scale and extents, since that may override extents
813  refreshMapExtents();
814 
815  emit preparedForAtlas();
816  invalidateCache();
817  emit itemChanged();
818  emit extentChanged();
819 }
820 
822 {
823  //non-const version
824  if ( mAtlasDriven && mComposition->atlasMode() != QgsComposition::AtlasOff )
825  {
826  //if atlas is enabled, and we are either exporting the composition or previewing the atlas, then
827  //return the current temporary atlas feature extent
828  return &mAtlasFeatureExtent;
829  }
830  else
831  {
832  //otherwise return permanent user set extent
833  return &mExtent;
834  }
835 }
836 
838 {
839  if ( mCrs.isValid() )
840  return mCrs;
841  else if ( mComposition && mComposition->project() )
842  return mComposition->project()->crs();
844 }
845 
847 {
848  mCrs = crs;
849 }
850 
852 {
853  //const version
854  if ( mAtlasDriven && mComposition->atlasMode() != QgsComposition::AtlasOff )
855  {
856  //if atlas is enabled, and we are either exporting the composition or previewing the atlas, then
857  //return the current temporary atlas feature extent
858  return &mAtlasFeatureExtent;
859  }
860  else
861  {
862  //otherwise return permanent user set extent
863  return &mExtent;
864  }
865 }
866 
867 void QgsComposerMap::setNewScale( double scaleDenominator, bool forceUpdate )
868 {
869  double currentScaleDenominator = scale();
870 
871  if ( qgsDoubleNear( scaleDenominator, currentScaleDenominator ) || qgsDoubleNear( scaleDenominator, 0.0 ) )
872  {
873  return;
874  }
875 
876  double scaleRatio = scaleDenominator / currentScaleDenominator;
877  currentMapExtent()->scale( scaleRatio );
878 
879  if ( mAtlasDriven && mAtlasScalingMode == Fixed && mComposition->atlasMode() != QgsComposition::AtlasOff )
880  {
881  //if map is atlas controlled and set to fixed scaling mode, then scale changes should be treated as permanent
882  //and also apply to the map's original extent (see #9602)
883  //we can't use the scaleRatio calculated earlier, as the scale can vary depending on extent for geographic coordinate systems
884  QgsScaleCalculator calculator;
885  calculator.setMapUnits( crs().mapUnits() );
886  calculator.setDpi( 25.4 ); //QGraphicsView units are mm
887  scaleRatio = scaleDenominator / calculator.calculate( mExtent, rect().width() );
888  mExtent.scale( scaleRatio );
889  }
890 
891  invalidateCache();
892  if ( forceUpdate )
893  {
894  emit itemChanged();
895  }
896  emit extentChanged();
897 }
898 
899 void QgsComposerMap::setOffset( double xOffset, double yOffset )
900 {
901  mXOffset = xOffset;
902  mYOffset = yOffset;
903 }
904 
905 void QgsComposerMap::setMapRotation( double rotation )
906 {
907  mMapRotation = rotation;
908  mEvaluatedMapRotation = mMapRotation;
909  invalidateCache();
910  emit mapRotationChanged( rotation );
911  emit itemChanged();
912 }
913 
915 {
916  return valueType == QgsComposerObject::EvaluatedValue ? mEvaluatedMapRotation : mMapRotation;
917 }
918 
919 void QgsComposerMap::refreshMapExtents( const QgsExpressionContext *context )
920 {
922  const QgsExpressionContext *evalContext = context ? context : &scopedContext;
923 
924  //data defined map extents set?
925  QVariant exprVal;
926 
927  QgsRectangle newExtent = *currentMapExtent();
928  bool useDdXMin = false;
929  bool useDdXMax = false;
930  bool useDdYMin = false;
931  bool useDdYMax = false;
932  double minXD = 0;
933  double minYD = 0;
934  double maxXD = 0;
935  double maxYD = 0;
936 
937  bool ok = false;
938  minXD = mDataDefinedProperties.valueAsDouble( QgsComposerObject::MapXMin, *evalContext, 0.0, &ok );
939  if ( ok )
940  {
941  useDdXMin = true;
942  newExtent.setXMinimum( minXD );
943  }
944  minYD = mDataDefinedProperties.valueAsDouble( QgsComposerObject::MapYMin, *evalContext, 0.0, &ok );
945  if ( ok )
946  {
947  useDdYMin = true;
948  newExtent.setYMinimum( minYD );
949  }
950  maxXD = mDataDefinedProperties.valueAsDouble( QgsComposerObject::MapXMax, *evalContext, 0.0, &ok );
951  if ( ok )
952  {
953  useDdXMax = true;
954  newExtent.setXMaximum( maxXD );
955  }
956  maxYD = mDataDefinedProperties.valueAsDouble( QgsComposerObject::MapYMax, *evalContext, 0.0, &ok );
957  if ( ok )
958  {
959  useDdYMax = true;
960  newExtent.setYMaximum( maxYD );
961  }
962 
963  if ( newExtent != *currentMapExtent() )
964  {
965  //calculate new extents to fit data defined extents
966 
967  //Make sure the width/height ratio is the same as in current map extent.
968  //This is to keep the map item frame and the page layout fixed
969  double currentWidthHeightRatio = currentMapExtent()->width() / currentMapExtent()->height();
970  double newWidthHeightRatio = newExtent.width() / newExtent.height();
971 
972  if ( currentWidthHeightRatio < newWidthHeightRatio )
973  {
974  //enlarge height of new extent, ensuring the map center stays the same
975  double newHeight = newExtent.width() / currentWidthHeightRatio;
976  double deltaHeight = newHeight - newExtent.height();
977  newExtent.setYMinimum( newExtent.yMinimum() - deltaHeight / 2 );
978  newExtent.setYMaximum( newExtent.yMaximum() + deltaHeight / 2 );
979  }
980  else
981  {
982  //enlarge width of new extent, ensuring the map center stays the same
983  double newWidth = currentWidthHeightRatio * newExtent.height();
984  double deltaWidth = newWidth - newExtent.width();
985  newExtent.setXMinimum( newExtent.xMinimum() - deltaWidth / 2 );
986  newExtent.setXMaximum( newExtent.xMaximum() + deltaWidth / 2 );
987  }
988 
989  *currentMapExtent() = newExtent;
990  }
991 
992  //now refresh scale, as this potentially overrides extents
993 
994  //data defined map scale set?
995  double scaleD = mDataDefinedProperties.valueAsDouble( QgsComposerObject::MapScale, *evalContext, 0.0, &ok );
996  if ( ok )
997  {
998  setNewScale( scaleD, false );
999  newExtent = *currentMapExtent();
1000  }
1001 
1002  if ( useDdXMax || useDdXMin || useDdYMax || useDdYMin )
1003  {
1004  //if only one of min/max was set for either x or y, then make sure our extent is locked on that value
1005  //as we can do this without altering the scale
1006  if ( useDdXMin && !useDdXMax )
1007  {
1008  double xMax = currentMapExtent()->xMaximum() - ( currentMapExtent()->xMinimum() - minXD );
1009  newExtent.setXMinimum( minXD );
1010  newExtent.setXMaximum( xMax );
1011  }
1012  else if ( !useDdXMin && useDdXMax )
1013  {
1014  double xMin = currentMapExtent()->xMinimum() - ( currentMapExtent()->xMaximum() - maxXD );
1015  newExtent.setXMinimum( xMin );
1016  newExtent.setXMaximum( maxXD );
1017  }
1018  if ( useDdYMin && !useDdYMax )
1019  {
1020  double yMax = currentMapExtent()->yMaximum() - ( currentMapExtent()->yMinimum() - minYD );
1021  newExtent.setYMinimum( minYD );
1022  newExtent.setYMaximum( yMax );
1023  }
1024  else if ( !useDdYMin && useDdYMax )
1025  {
1026  double yMin = currentMapExtent()->yMinimum() - ( currentMapExtent()->yMaximum() - maxYD );
1027  newExtent.setYMinimum( yMin );
1028  newExtent.setYMaximum( maxYD );
1029  }
1030 
1031  if ( newExtent != *currentMapExtent() )
1032  {
1033  *currentMapExtent() = newExtent;
1034  }
1035  }
1036 
1037  //lastly, map rotation overrides all
1038  double mapRotation = mMapRotation;
1039 
1040  //data defined map rotation set?
1041  mapRotation = mDataDefinedProperties.valueAsDouble( QgsComposerObject::MapRotation, *evalContext, mapRotation );
1042 
1043  if ( !qgsDoubleNear( mEvaluatedMapRotation, mapRotation ) )
1044  {
1045  mEvaluatedMapRotation = mapRotation;
1046  emit mapRotationChanged( mapRotation );
1047  }
1048 }
1049 
1051 {
1052  Q_FOREACH ( QgsMapLayer *layer, layersToRender() )
1053  {
1054  if ( QgsRasterLayer *currentRasterLayer = qobject_cast<QgsRasterLayer *>( layer ) )
1055  {
1056  const QgsRasterDataProvider *rasterProvider = nullptr;
1057  if ( ( rasterProvider = currentRasterLayer->dataProvider() ) )
1058  {
1059  if ( rasterProvider->name() == QLatin1String( "wms" ) )
1060  {
1061  return true;
1062  }
1063  }
1064  }
1065  }
1066  return false;
1067 }
1068 
1070 {
1071  //check easy things first
1072 
1073  //overviews
1074  if ( mOverviewStack->containsAdvancedEffects() )
1075  {
1076  return true;
1077  }
1078 
1079  //grids
1080  if ( mGridStack->containsAdvancedEffects() )
1081  {
1082  return true;
1083  }
1084 
1085 
1086  QgsMapSettings ms;
1087  ms.setLayers( layersToRender() );
1088  return ( !QgsMapSettingsUtils::containsAdvancedEffects( ms ).isEmpty() );
1089 }
1090 
1091 void QgsComposerMap::connectUpdateSlot()
1092 {
1093  //connect signal from layer registry to update in case of new or deleted layers
1094  QgsProject *project = mComposition->project();
1095  if ( project )
1096  {
1097  // handles updating the stored layer state BEFORE the layers are removed
1098  connect( project, static_cast < void ( QgsProject::* )( const QList<QgsMapLayer *>& layers ) > ( &QgsProject::layersWillBeRemoved ),
1099  this, &QgsComposerMap::layersAboutToBeRemoved );
1100  // redraws the map AFTER layers are removed
1101  connect( project->layerTreeRoot(), &QgsLayerTree::layerOrderChanged, this, [ = ]
1102  {
1103  if ( layers().isEmpty() )
1104  {
1105  //using project layers, and layer order has changed
1106  invalidateCache();
1107  }
1108  } );
1109 
1110  connect( project, &QgsProject::crsChanged, this, [ = ]
1111  {
1112  if ( !mCrs.isValid() )
1113  {
1114  //using project CRS, which just changed....
1115  invalidateCache();
1116  }
1117  } );
1118 
1119  }
1121 }
1122 
1123 bool QgsComposerMap::writeXml( QDomElement &elem, QDomDocument &doc ) const
1124 {
1125  if ( elem.isNull() )
1126  {
1127  return false;
1128  }
1129 
1130  QDomElement composerMapElem = doc.createElement( QStringLiteral( "ComposerMap" ) );
1131  composerMapElem.setAttribute( QStringLiteral( "id" ), mId );
1132 
1133  if ( mKeepLayerSet )
1134  {
1135  composerMapElem.setAttribute( QStringLiteral( "keepLayerSet" ), QStringLiteral( "true" ) );
1136  }
1137  else
1138  {
1139  composerMapElem.setAttribute( QStringLiteral( "keepLayerSet" ), QStringLiteral( "false" ) );
1140  }
1141 
1142  if ( mDrawAnnotations )
1143  {
1144  composerMapElem.setAttribute( QStringLiteral( "drawCanvasItems" ), QStringLiteral( "true" ) );
1145  }
1146  else
1147  {
1148  composerMapElem.setAttribute( QStringLiteral( "drawCanvasItems" ), QStringLiteral( "false" ) );
1149  }
1150 
1151  //extent
1152  QDomElement extentElem = doc.createElement( QStringLiteral( "Extent" ) );
1153  extentElem.setAttribute( QStringLiteral( "xmin" ), qgsDoubleToString( mExtent.xMinimum() ) );
1154  extentElem.setAttribute( QStringLiteral( "xmax" ), qgsDoubleToString( mExtent.xMaximum() ) );
1155  extentElem.setAttribute( QStringLiteral( "ymin" ), qgsDoubleToString( mExtent.yMinimum() ) );
1156  extentElem.setAttribute( QStringLiteral( "ymax" ), qgsDoubleToString( mExtent.yMaximum() ) );
1157  composerMapElem.appendChild( extentElem );
1158 
1159  if ( mCrs.isValid() )
1160  {
1161  QDomElement crsElem = doc.createElement( QStringLiteral( "crs" ) );
1162  mCrs.writeXml( crsElem, doc );
1163  composerMapElem.appendChild( crsElem );
1164  }
1165 
1166  // follow map theme
1167  composerMapElem.setAttribute( QStringLiteral( "followPreset" ), mFollowVisibilityPreset ? "true" : "false" );
1168  composerMapElem.setAttribute( QStringLiteral( "followPresetName" ), mFollowVisibilityPresetName );
1169 
1170  //map rotation
1171  composerMapElem.setAttribute( QStringLiteral( "mapRotation" ), QString::number( mMapRotation ) );
1172 
1173  //layer set
1174  QDomElement layerSetElem = doc.createElement( QStringLiteral( "LayerSet" ) );
1175  Q_FOREACH ( const QgsMapLayerRef &layerRef, mLayers )
1176  {
1177  if ( !layerRef )
1178  continue;
1179  QDomElement layerElem = doc.createElement( QStringLiteral( "Layer" ) );
1180  QDomText layerIdText = doc.createTextNode( layerRef.layerId );
1181  layerElem.appendChild( layerIdText );
1182 
1183  layerElem.setAttribute( QStringLiteral( "name" ), layerRef.name );
1184  layerElem.setAttribute( QStringLiteral( "source" ), layerRef.source );
1185  layerElem.setAttribute( QStringLiteral( "provider" ), layerRef.provider );
1186 
1187  layerSetElem.appendChild( layerElem );
1188  }
1189  composerMapElem.appendChild( layerSetElem );
1190 
1191  // override styles
1192  if ( mKeepLayerStyles )
1193  {
1194  QDomElement stylesElem = doc.createElement( QStringLiteral( "LayerStyles" ) );
1195  QMap<QString, QString>::const_iterator styleIt = mLayerStyleOverrides.constBegin();
1196  for ( ; styleIt != mLayerStyleOverrides.constEnd(); ++styleIt )
1197  {
1198  QDomElement styleElem = doc.createElement( QStringLiteral( "LayerStyle" ) );
1199 
1200  QgsMapLayerRef ref( styleIt.key() );
1201  ref.resolve( mComposition->project() );
1202 
1203  styleElem.setAttribute( QStringLiteral( "layerid" ), ref.layerId );
1204  styleElem.setAttribute( QStringLiteral( "name" ), ref.name );
1205  styleElem.setAttribute( QStringLiteral( "source" ), ref.source );
1206  styleElem.setAttribute( QStringLiteral( "provider" ), ref.provider );
1207 
1208  QgsMapLayerStyle style( styleIt.value() );
1209  style.writeXml( styleElem );
1210  stylesElem.appendChild( styleElem );
1211  }
1212  composerMapElem.appendChild( stylesElem );
1213  }
1214 
1215  //write a dummy "Grid" element to prevent crashes on pre 2.5 versions (refs #10905)
1216  QDomElement gridElem = doc.createElement( QStringLiteral( "Grid" ) );
1217  composerMapElem.appendChild( gridElem );
1218 
1219  //grids
1220  mGridStack->writeXml( composerMapElem, doc );
1221 
1222  //overviews
1223  mOverviewStack->writeXml( composerMapElem, doc );
1224 
1225  //atlas
1226  QDomElement atlasElem = doc.createElement( QStringLiteral( "AtlasMap" ) );
1227  atlasElem.setAttribute( QStringLiteral( "atlasDriven" ), mAtlasDriven );
1228  atlasElem.setAttribute( QStringLiteral( "scalingMode" ), mAtlasScalingMode );
1229  atlasElem.setAttribute( QStringLiteral( "margin" ), qgsDoubleToString( mAtlasMargin ) );
1230  composerMapElem.appendChild( atlasElem );
1231 
1232  elem.appendChild( composerMapElem );
1233  return _writeXml( composerMapElem, doc );
1234 }
1235 
1236 bool QgsComposerMap::readXml( const QDomElement &itemElem, const QDomDocument &doc )
1237 {
1238  if ( itemElem.isNull() )
1239  {
1240  return false;
1241  }
1242 
1243  setUpdatesEnabled( false );
1244 
1245  QString idRead = itemElem.attribute( QStringLiteral( "id" ), QStringLiteral( "not found" ) );
1246  if ( idRead != QLatin1String( "not found" ) )
1247  {
1248  mId = idRead.toInt();
1249  updateToolTip();
1250  }
1251 
1252  QgsReadWriteContext context;
1254 
1255  //extent
1256  QDomNodeList extentNodeList = itemElem.elementsByTagName( QStringLiteral( "Extent" ) );
1257  if ( !extentNodeList.isEmpty() )
1258  {
1259  QDomElement extentElem = extentNodeList.at( 0 ).toElement();
1260  double xmin, xmax, ymin, ymax;
1261  xmin = extentElem.attribute( QStringLiteral( "xmin" ) ).toDouble();
1262  xmax = extentElem.attribute( QStringLiteral( "xmax" ) ).toDouble();
1263  ymin = extentElem.attribute( QStringLiteral( "ymin" ) ).toDouble();
1264  ymax = extentElem.attribute( QStringLiteral( "ymax" ) ).toDouble();
1265  setNewExtent( QgsRectangle( xmin, ymin, xmax, ymax ) );
1266  }
1267 
1268  QDomNodeList crsNodeList = itemElem.elementsByTagName( QStringLiteral( "crs" ) );
1269  if ( !crsNodeList.isEmpty() )
1270  {
1271  QDomElement crsElem = crsNodeList.at( 0 ).toElement();
1272  mCrs.readXml( crsElem );
1273  }
1274  else
1275  {
1277  }
1278 
1279  //map rotation
1280  if ( !qgsDoubleNear( itemElem.attribute( QStringLiteral( "mapRotation" ), QStringLiteral( "0" ) ).toDouble(), 0.0 ) )
1281  {
1282  mMapRotation = itemElem.attribute( QStringLiteral( "mapRotation" ), QStringLiteral( "0" ) ).toDouble();
1283  }
1284 
1285  // follow map theme
1286  mFollowVisibilityPreset = itemElem.attribute( QStringLiteral( "followPreset" ) ).compare( QLatin1String( "true" ) ) == 0;
1287  mFollowVisibilityPresetName = itemElem.attribute( QStringLiteral( "followPresetName" ) );
1288 
1289  //mKeepLayerSet flag
1290  QString keepLayerSetFlag = itemElem.attribute( QStringLiteral( "keepLayerSet" ) );
1291  if ( keepLayerSetFlag.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 )
1292  {
1293  mKeepLayerSet = true;
1294  }
1295  else
1296  {
1297  mKeepLayerSet = false;
1298  }
1299 
1300  QString drawCanvasItemsFlag = itemElem.attribute( QStringLiteral( "drawCanvasItems" ), QStringLiteral( "true" ) );
1301  if ( drawCanvasItemsFlag.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 )
1302  {
1303  mDrawAnnotations = true;
1304  }
1305  else
1306  {
1307  mDrawAnnotations = false;
1308  }
1309 
1310  mLayerStyleOverrides.clear();
1311 
1312  //mLayers
1313  mLayers.clear();
1314  QDomNodeList layerSetNodeList = itemElem.elementsByTagName( QStringLiteral( "LayerSet" ) );
1315  if ( !layerSetNodeList.isEmpty() )
1316  {
1317  QDomElement layerSetElem = layerSetNodeList.at( 0 ).toElement();
1318  QDomNodeList layerIdNodeList = layerSetElem.elementsByTagName( QStringLiteral( "Layer" ) );
1319  mLayers.reserve( layerIdNodeList.size() );
1320  for ( int i = 0; i < layerIdNodeList.size(); ++i )
1321  {
1322  QDomElement layerElem = layerIdNodeList.at( i ).toElement();
1323  QString layerId = layerElem.text();
1324  QString layerName = layerElem.attribute( QStringLiteral( "name" ) );
1325  QString layerSource = layerElem.attribute( QStringLiteral( "source" ) );
1326  QString layerProvider = layerElem.attribute( QStringLiteral( "provider" ) );
1327 
1328  QgsMapLayerRef ref( layerId, layerName, layerSource, layerProvider );
1330  mLayers << ref;
1331  }
1332  }
1333 
1334  // override styles
1335  QDomNodeList layerStylesNodeList = itemElem.elementsByTagName( QStringLiteral( "LayerStyles" ) );
1336  mKeepLayerStyles = !layerStylesNodeList.isEmpty();
1337  if ( mKeepLayerStyles )
1338  {
1339  QDomElement layerStylesElem = layerStylesNodeList.at( 0 ).toElement();
1340  QDomNodeList layerStyleNodeList = layerStylesElem.elementsByTagName( QStringLiteral( "LayerStyle" ) );
1341  for ( int i = 0; i < layerStyleNodeList.size(); ++i )
1342  {
1343  const QDomElement &layerStyleElement = layerStyleNodeList.at( i ).toElement();
1344  QString layerId = layerStyleElement.attribute( QStringLiteral( "layerid" ) );
1345  QString layerName = layerStyleElement.attribute( QStringLiteral( "name" ) );
1346  QString layerSource = layerStyleElement.attribute( QStringLiteral( "source" ) );
1347  QString layerProvider = layerStyleElement.attribute( QStringLiteral( "provider" ) );
1348  QgsMapLayerRef ref( layerId, layerName, layerSource, layerProvider );
1350 
1351  QgsMapLayerStyle style;
1352  style.readXml( layerStyleElement );
1353  mLayerStyleOverrides.insert( ref.layerId, style.xmlData() );
1354  }
1355  }
1356 
1357  mDrawing = false;
1358  mNumCachedLayers = 0;
1359  mCacheInvalidated = true;
1360 
1361  //overviews
1362  mOverviewStack->readXml( itemElem, doc );
1363 
1364  //grids
1365  mGridStack->readXml( itemElem, doc );
1366 
1367  //load grid / grid annotation in old xml format
1368  //only do this if the grid stack didn't load any grids, otherwise this will
1369  //be the dummy element created by QGIS >= 2.5 (refs #10905)
1370  QDomNodeList gridNodeList = itemElem.elementsByTagName( QStringLiteral( "Grid" ) );
1371  if ( mGridStack->size() == 0 && !gridNodeList.isEmpty() )
1372  {
1373  QDomElement gridElem = gridNodeList.at( 0 ).toElement();
1374  QgsComposerMapGrid *mapGrid = new QgsComposerMapGrid( tr( "Grid %1" ).arg( 1 ), this );
1375  mapGrid->setEnabled( gridElem.attribute( QStringLiteral( "show" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
1376  mapGrid->setStyle( QgsComposerMapGrid::GridStyle( gridElem.attribute( QStringLiteral( "gridStyle" ), QStringLiteral( "0" ) ).toInt() ) );
1377  mapGrid->setIntervalX( gridElem.attribute( QStringLiteral( "intervalX" ), QStringLiteral( "0" ) ).toDouble() );
1378  mapGrid->setIntervalY( gridElem.attribute( QStringLiteral( "intervalY" ), QStringLiteral( "0" ) ).toDouble() );
1379  mapGrid->setOffsetX( gridElem.attribute( QStringLiteral( "offsetX" ), QStringLiteral( "0" ) ).toDouble() );
1380  mapGrid->setOffsetY( gridElem.attribute( QStringLiteral( "offsetY" ), QStringLiteral( "0" ) ).toDouble() );
1381  mapGrid->setCrossLength( gridElem.attribute( QStringLiteral( "crossLength" ), QStringLiteral( "3" ) ).toDouble() );
1382  mapGrid->setFrameStyle( static_cast< QgsComposerMapGrid::FrameStyle >( gridElem.attribute( QStringLiteral( "gridFrameStyle" ), QStringLiteral( "0" ) ).toInt() ) );
1383  mapGrid->setFrameWidth( gridElem.attribute( QStringLiteral( "gridFrameWidth" ), QStringLiteral( "2.0" ) ).toDouble() );
1384  mapGrid->setFramePenSize( gridElem.attribute( QStringLiteral( "gridFramePenThickness" ), QStringLiteral( "0.5" ) ).toDouble() );
1385  mapGrid->setFramePenColor( QgsSymbolLayerUtils::decodeColor( gridElem.attribute( QStringLiteral( "framePenColor" ), QStringLiteral( "0,0,0" ) ) ) );
1386  mapGrid->setFrameFillColor1( QgsSymbolLayerUtils::decodeColor( gridElem.attribute( QStringLiteral( "frameFillColor1" ), QStringLiteral( "255,255,255,255" ) ) ) );
1387  mapGrid->setFrameFillColor2( QgsSymbolLayerUtils::decodeColor( gridElem.attribute( QStringLiteral( "frameFillColor2" ), QStringLiteral( "0,0,0,255" ) ) ) );
1388  mapGrid->setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( itemElem.attribute( QStringLiteral( "gridBlendMode" ), QStringLiteral( "0" ) ).toUInt() ) ) );
1389  QDomElement gridSymbolElem = gridElem.firstChildElement( QStringLiteral( "symbol" ) );
1390  QgsLineSymbol *lineSymbol = nullptr;
1391  if ( gridSymbolElem.isNull() )
1392  {
1393  //old project file, read penWidth /penColorRed, penColorGreen, penColorBlue
1394  lineSymbol = QgsLineSymbol::createSimple( QgsStringMap() );
1395  lineSymbol->setWidth( gridElem.attribute( QStringLiteral( "penWidth" ), QStringLiteral( "0" ) ).toDouble() );
1396  lineSymbol->setColor( QColor( gridElem.attribute( QStringLiteral( "penColorRed" ), QStringLiteral( "0" ) ).toInt(),
1397  gridElem.attribute( QStringLiteral( "penColorGreen" ), QStringLiteral( "0" ) ).toInt(),
1398  gridElem.attribute( QStringLiteral( "penColorBlue" ), QStringLiteral( "0" ) ).toInt() ) );
1399  }
1400  else
1401  {
1402  lineSymbol = QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( gridSymbolElem, context );
1403  }
1404  mapGrid->setLineSymbol( lineSymbol );
1405 
1406  //annotation
1407  QDomNodeList annotationNodeList = gridElem.elementsByTagName( QStringLiteral( "Annotation" ) );
1408  if ( !annotationNodeList.isEmpty() )
1409  {
1410  QDomElement annotationElem = annotationNodeList.at( 0 ).toElement();
1411  mapGrid->setAnnotationEnabled( annotationElem.attribute( QStringLiteral( "show" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
1412  mapGrid->setAnnotationFormat( QgsComposerMapGrid::AnnotationFormat( annotationElem.attribute( QStringLiteral( "format" ), QStringLiteral( "0" ) ).toInt() ) );
1413  mapGrid->setAnnotationPosition( QgsComposerMapGrid::AnnotationPosition( annotationElem.attribute( QStringLiteral( "leftPosition" ), QStringLiteral( "0" ) ).toInt() ), QgsComposerMapGrid::Left );
1414  mapGrid->setAnnotationPosition( QgsComposerMapGrid::AnnotationPosition( annotationElem.attribute( QStringLiteral( "rightPosition" ), QStringLiteral( "0" ) ).toInt() ), QgsComposerMapGrid::Right );
1415  mapGrid->setAnnotationPosition( QgsComposerMapGrid::AnnotationPosition( annotationElem.attribute( QStringLiteral( "topPosition" ), QStringLiteral( "0" ) ).toInt() ), QgsComposerMapGrid::Top );
1416  mapGrid->setAnnotationPosition( QgsComposerMapGrid::AnnotationPosition( annotationElem.attribute( QStringLiteral( "bottomPosition" ), QStringLiteral( "0" ) ).toInt() ), QgsComposerMapGrid::Bottom );
1417  mapGrid->setAnnotationDirection( QgsComposerMapGrid::AnnotationDirection( annotationElem.attribute( QStringLiteral( "leftDirection" ), QStringLiteral( "0" ) ).toInt() ), QgsComposerMapGrid::Left );
1418  mapGrid->setAnnotationDirection( QgsComposerMapGrid::AnnotationDirection( annotationElem.attribute( QStringLiteral( "rightDirection" ), QStringLiteral( "0" ) ).toInt() ), QgsComposerMapGrid::Right );
1419  mapGrid->setAnnotationDirection( QgsComposerMapGrid::AnnotationDirection( annotationElem.attribute( QStringLiteral( "topDirection" ), QStringLiteral( "0" ) ).toInt() ), QgsComposerMapGrid::Top );
1420  mapGrid->setAnnotationDirection( QgsComposerMapGrid::AnnotationDirection( annotationElem.attribute( QStringLiteral( "bottomDirection" ), QStringLiteral( "0" ) ).toInt() ), QgsComposerMapGrid::Bottom );
1421  mapGrid->setAnnotationFrameDistance( annotationElem.attribute( QStringLiteral( "frameDistance" ), QStringLiteral( "0" ) ).toDouble() );
1422  QFont annotationFont;
1423  annotationFont.fromString( annotationElem.attribute( QStringLiteral( "font" ), QLatin1String( "" ) ) );
1424  mapGrid->setAnnotationFont( annotationFont );
1425  mapGrid->setAnnotationFontColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "fontColor" ), QStringLiteral( "0,0,0,255" ) ) ) );
1426 
1427  mapGrid->setAnnotationPrecision( annotationElem.attribute( QStringLiteral( "precision" ), QStringLiteral( "3" ) ).toInt() );
1428  }
1429  mGridStack->addGrid( mapGrid );
1430  }
1431 
1432  //load overview in old xml format
1433  QDomElement overviewFrameElem = itemElem.firstChildElement( QStringLiteral( "overviewFrame" ) );
1434  if ( !overviewFrameElem.isNull() )
1435  {
1436  QgsComposerMapOverview *mapOverview = new QgsComposerMapOverview( tr( "Overview %1" ).arg( mOverviewStack->size() + 1 ), this );
1437 
1438  mapOverview->setFrameMap( overviewFrameElem.attribute( QStringLiteral( "overviewFrameMap" ), QStringLiteral( "-1" ) ).toInt() );
1439  mapOverview->setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( overviewFrameElem.attribute( QStringLiteral( "overviewBlendMode" ), QStringLiteral( "0" ) ).toUInt() ) ) );
1440  mapOverview->setInverted( overviewFrameElem.attribute( QStringLiteral( "overviewInverted" ) ).compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 );
1441  mapOverview->setCentered( overviewFrameElem.attribute( QStringLiteral( "overviewCentered" ) ).compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 );
1442 
1443  QgsFillSymbol *fillSymbol = nullptr;
1444  QDomElement overviewFrameSymbolElem = overviewFrameElem.firstChildElement( QStringLiteral( "symbol" ) );
1445  if ( !overviewFrameSymbolElem.isNull() )
1446  {
1447  fillSymbol = QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( overviewFrameSymbolElem, context );
1448  mapOverview->setFrameSymbol( fillSymbol );
1449  }
1450  mOverviewStack->addOverview( mapOverview );
1451  }
1452 
1453  //atlas
1454  QDomNodeList atlasNodeList = itemElem.elementsByTagName( QStringLiteral( "AtlasMap" ) );
1455  if ( !atlasNodeList.isEmpty() )
1456  {
1457  QDomElement atlasElem = atlasNodeList.at( 0 ).toElement();
1458  mAtlasDriven = ( atlasElem.attribute( QStringLiteral( "atlasDriven" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
1459  if ( atlasElem.hasAttribute( QStringLiteral( "fixedScale" ) ) ) // deprecated XML
1460  {
1461  mAtlasScalingMode = ( atlasElem.attribute( QStringLiteral( "fixedScale" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) ) ? Fixed : Auto;
1462  }
1463  else if ( atlasElem.hasAttribute( QStringLiteral( "scalingMode" ) ) )
1464  {
1465  mAtlasScalingMode = static_cast<AtlasScalingMode>( atlasElem.attribute( QStringLiteral( "scalingMode" ) ).toInt() );
1466  }
1467  mAtlasMargin = atlasElem.attribute( QStringLiteral( "margin" ), QStringLiteral( "0.1" ) ).toDouble();
1468  }
1469 
1470  //restore general composer item properties
1471  QDomNodeList composerItemList = itemElem.elementsByTagName( QStringLiteral( "ComposerItem" ) );
1472  if ( !composerItemList.isEmpty() )
1473  {
1474  QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
1475 
1476  if ( !qgsDoubleNear( composerItemElem.attribute( QStringLiteral( "rotation" ), QStringLiteral( "0" ) ).toDouble(), 0.0 ) )
1477  {
1478  //in versions prior to 2.1 map rotation was stored in the rotation attribute
1479  mMapRotation = composerItemElem.attribute( QStringLiteral( "rotation" ), QStringLiteral( "0" ) ).toDouble();
1480  }
1481 
1482  _readXml( composerItemElem, doc );
1483  }
1484 
1486  setUpdatesEnabled( true );
1487 
1488  emit itemChanged();
1489  return true;
1490 }
1491 
1492 QList<QgsMapLayer *> QgsComposerMap::layers() const
1493 {
1494  return _qgis_listRefToRaw( mLayers );
1495 }
1496 
1497 void QgsComposerMap::setLayers( const QList<QgsMapLayer *> &layers )
1498 {
1499  mLayers = _qgis_listRawToRef( layers );
1500 }
1501 
1502 
1503 void QgsComposerMap::setLayerStyleOverrides( const QMap<QString, QString> &overrides )
1504 {
1505  if ( overrides == mLayerStyleOverrides )
1506  return;
1507 
1508  mLayerStyleOverrides = overrides;
1509  emit layerStyleOverridesChanged(); // associated legends may listen to this
1510 }
1511 
1512 
1514 {
1515  mLayerStyleOverrides.clear();
1516  Q_FOREACH ( const QgsMapLayerRef &layerRef, mLayers )
1517  {
1518  if ( QgsMapLayer *layer = layerRef.get() )
1519  {
1520  QgsMapLayerStyle style;
1521  style.readFromLayer( layer );
1522  mLayerStyleOverrides.insert( layer->id(), style.xmlData() );
1523  }
1524  }
1525 }
1526 
1527 void QgsComposerMap::layersAboutToBeRemoved( QList< QgsMapLayer * > layers )
1528 {
1529  if ( !mLayers.isEmpty() || mLayerStyleOverrides.isEmpty() )
1530  {
1531  Q_FOREACH ( QgsMapLayer *layer, layers )
1532  {
1533  mLayerStyleOverrides.remove( layer->id() );
1534  }
1535  _qgis_removeLayers( mLayers, layers );
1536  }
1537 }
1538 
1540 {
1541  if ( mGridStack->size() < 1 )
1542  {
1543  QgsComposerMapGrid *grid = new QgsComposerMapGrid( tr( "Grid %1" ).arg( 1 ), this );
1544  mGridStack->addGrid( grid );
1545  }
1546  return mGridStack->grid( 0 );
1547 }
1548 
1549 const QgsComposerMapGrid *QgsComposerMap::constFirstMapGrid() const
1550 {
1551  return const_cast<QgsComposerMap *>( this )->grid();
1552 }
1553 
1555 {
1556  if ( mOverviewStack->size() < 1 )
1557  {
1558  QgsComposerMapOverview *overview = new QgsComposerMapOverview( tr( "Overview %1" ).arg( 1 ), this );
1559  mOverviewStack->addOverview( overview );
1560  }
1561  return mOverviewStack->overview( 0 );
1562 }
1563 
1564 const QgsComposerMapOverview *QgsComposerMap::constFirstMapOverview() const
1565 {
1566  return const_cast<QgsComposerMap *>( this )->overview();
1567 }
1568 
1570 {
1571  return mCurrentRectangle;
1572 }
1573 
1575 {
1576  QRectF rectangle = rect();
1577  double frameExtension = mFrame ? pen().widthF() / 2.0 : 0.0;
1578 
1579  double topExtension = 0.0;
1580  double rightExtension = 0.0;
1581  double bottomExtension = 0.0;
1582  double leftExtension = 0.0;
1583 
1584  if ( mGridStack )
1585  mGridStack->calculateMaxGridExtension( topExtension, rightExtension, bottomExtension, leftExtension );
1586 
1587  topExtension = qMax( topExtension, frameExtension );
1588  rightExtension = qMax( rightExtension, frameExtension );
1589  bottomExtension = qMax( bottomExtension, frameExtension );
1590  leftExtension = qMax( leftExtension, frameExtension );
1591 
1592  rectangle.setLeft( rectangle.left() - leftExtension );
1593  rectangle.setRight( rectangle.right() + rightExtension );
1594  rectangle.setTop( rectangle.top() - topExtension );
1595  rectangle.setBottom( rectangle.bottom() + bottomExtension );
1596  if ( rectangle != mCurrentRectangle )
1597  {
1598  prepareGeometryChange();
1599  mCurrentRectangle = rectangle;
1600  }
1601 }
1602 
1603 void QgsComposerMap::setFrameStrokeWidth( const double strokeWidth )
1604 {
1605  QgsComposerItem::setFrameStrokeWidth( strokeWidth );
1607 }
1608 
1609 QgsRectangle QgsComposerMap::transformedExtent() const
1610 {
1611  double dx = mXOffset;
1612  double dy = mYOffset;
1613  transformShift( dx, dy );
1614  return QgsRectangle( currentMapExtent()->xMinimum() - dx, currentMapExtent()->yMinimum() - dy, currentMapExtent()->xMaximum() - dx, currentMapExtent()->yMaximum() - dy );
1615 }
1616 
1618 {
1619  double dx = mXOffset;
1620  double dy = mYOffset;
1621  //qWarning("offset");
1622  //qWarning(QString::number(dx).toLocal8Bit().data());
1623  //qWarning(QString::number(dy).toLocal8Bit().data());
1624  transformShift( dx, dy );
1625  //qWarning("transformed:");
1626  //qWarning(QString::number(dx).toLocal8Bit().data());
1627  //qWarning(QString::number(dy).toLocal8Bit().data());
1628  QPolygonF poly = visibleExtentPolygon();
1629  poly.translate( -dx, -dy );
1630  return poly;
1631 }
1632 
1633 void QgsComposerMap::mapPolygon( const QgsRectangle &extent, QPolygonF &poly ) const
1634 {
1635  poly.clear();
1636  if ( qgsDoubleNear( mEvaluatedMapRotation, 0.0 ) )
1637  {
1638  poly << QPointF( extent.xMinimum(), extent.yMaximum() );
1639  poly << QPointF( extent.xMaximum(), extent.yMaximum() );
1640  poly << QPointF( extent.xMaximum(), extent.yMinimum() );
1641  poly << QPointF( extent.xMinimum(), extent.yMinimum() );
1642  //ensure polygon is closed by readding first point
1643  poly << QPointF( poly.at( 0 ) );
1644  return;
1645  }
1646 
1647  //there is rotation
1648  QgsPointXY rotationPoint( ( extent.xMaximum() + extent.xMinimum() ) / 2.0, ( extent.yMaximum() + extent.yMinimum() ) / 2.0 );
1649  double dx, dy; //x-, y- shift from rotation point to corner point
1650 
1651  //top left point
1652  dx = rotationPoint.x() - extent.xMinimum();
1653  dy = rotationPoint.y() - extent.yMaximum();
1654  QgsComposerUtils::rotate( mEvaluatedMapRotation, dx, dy );
1655  poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
1656 
1657  //top right point
1658  dx = rotationPoint.x() - extent.xMaximum();
1659  dy = rotationPoint.y() - extent.yMaximum();
1660  QgsComposerUtils::rotate( mEvaluatedMapRotation, dx, dy );
1661  poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
1662 
1663  //bottom right point
1664  dx = rotationPoint.x() - extent.xMaximum();
1665  dy = rotationPoint.y() - extent.yMinimum();
1666  QgsComposerUtils::rotate( mEvaluatedMapRotation, dx, dy );
1667  poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
1668 
1669  //bottom left point
1670  dx = rotationPoint.x() - extent.xMinimum();
1671  dy = rotationPoint.y() - extent.yMinimum();
1672  QgsComposerUtils::rotate( mEvaluatedMapRotation, dx, dy );
1673  poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
1674 
1675  //ensure polygon is closed by readding first point
1676  poly << QPointF( poly.at( 0 ) );
1677 }
1678 
1680 {
1681  QPolygonF poly;
1682  mapPolygon( *currentMapExtent(), poly );
1683  return poly;
1684 }
1685 
1687 {
1688  if ( !QgsComposerItem::id().isEmpty() )
1689  {
1690  return QgsComposerItem::id();
1691  }
1692 
1693  return tr( "Map %1" ).arg( mId );
1694 }
1695 
1697 {
1698  QgsRectangle newExtent = *currentMapExtent();
1699  if ( qgsDoubleNear( mEvaluatedMapRotation, 0.0 ) )
1700  {
1701  extent = newExtent;
1702  }
1703  else
1704  {
1705  QPolygonF poly;
1706  mapPolygon( newExtent, poly );
1707  QRectF bRect = poly.boundingRect();
1708  extent.setXMinimum( bRect.left() );
1709  extent.setXMaximum( bRect.right() );
1710  extent.setYMinimum( bRect.top() );
1711  extent.setYMaximum( bRect.bottom() );
1712  }
1713 }
1714 
1716 {
1718 
1719  //Can't utilize QgsExpressionContextUtils::mapSettingsScope as we don't always
1720  //have a QgsMapSettings object available when the context is required, so we manually
1721  //add the same variables here
1722  QgsExpressionContextScope *scope = new QgsExpressionContextScope( tr( "Map Settings" ) );
1723 
1724  //use QgsComposerItem's id, not map item's ID, since that is user-definable
1725  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_id" ), QgsComposerItem::id(), true ) );
1726  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_rotation" ), mMapRotation, true ) );
1727  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_scale" ), scale(), true ) );
1728 
1730  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent" ), QVariant::fromValue( QgsGeometry::fromRect( extent ) ), true ) );
1731  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_width" ), extent.width(), true ) );
1732  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_height" ), extent.height(), true ) );
1733  QgsGeometry centerPoint = QgsGeometry::fromPoint( extent.center() );
1734  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_center" ), QVariant::fromValue( centerPoint ), true ) );
1735 
1736  if ( mComposition )
1737  {
1738  QgsCoordinateReferenceSystem mapCrs = crs();
1739  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs" ), mapCrs.authid(), true ) );
1740  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs_definition" ), mapCrs.toProj4(), true ) );
1741  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_units" ), QgsUnitTypes::toString( mapCrs.mapUnits() ), true ) );
1742  }
1743 
1744  context.appendScope( scope );
1745 
1746  return context;
1747 }
1748 
1750 {
1751  double extentWidth = currentMapExtent()->width();
1752  if ( extentWidth <= 0 )
1753  {
1754  return 1;
1755  }
1756  return rect().width() / extentWidth;
1757 }
1758 
1760 {
1762  const QgsExpressionContext *evalContext = context ? context : &scopedContext;
1763 
1764  //updates data defined properties and redraws item to match
1765  if ( property == QgsComposerObject::MapRotation || property == QgsComposerObject::MapScale ||
1766  property == QgsComposerObject::MapXMin || property == QgsComposerObject::MapYMin ||
1767  property == QgsComposerObject::MapXMax || property == QgsComposerObject::MapYMax ||
1768  property == QgsComposerObject::MapAtlasMargin ||
1769  property == QgsComposerObject::AllProperties )
1770  {
1771  QgsRectangle beforeExtent = *currentMapExtent();
1772  refreshMapExtents( evalContext );
1773  emit itemChanged();
1774  if ( *currentMapExtent() != beforeExtent )
1775  {
1776  emit extentChanged();
1777  }
1778  }
1779 
1780  //force redraw
1781  mCacheInvalidated = true;
1782 
1783  QgsComposerItem::refreshDataDefinedProperty( property, evalContext );
1784 }
1785 
1786 void QgsComposerMap::transformShift( double &xShift, double &yShift ) const
1787 {
1788  double mmToMapUnits = 1.0 / mapUnitsToMM();
1789  double dxScaled = xShift * mmToMapUnits;
1790  double dyScaled = - yShift * mmToMapUnits;
1791 
1792  QgsComposerUtils::rotate( mEvaluatedMapRotation, dxScaled, dyScaled );
1793 
1794  xShift = dxScaled;
1795  yShift = dyScaled;
1796 }
1797 
1798 QPointF QgsComposerMap::mapToItemCoords( QPointF mapCoords ) const
1799 {
1800  QPolygonF mapPoly = transformedMapPolygon();
1801  if ( mapPoly.size() < 1 )
1802  {
1803  return QPointF( 0, 0 );
1804  }
1805 
1806  QgsRectangle tExtent = transformedExtent();
1807  QgsPointXY rotationPoint( ( tExtent.xMaximum() + tExtent.xMinimum() ) / 2.0, ( tExtent.yMaximum() + tExtent.yMinimum() ) / 2.0 );
1808  double dx = mapCoords.x() - rotationPoint.x();
1809  double dy = mapCoords.y() - rotationPoint.y();
1810  QgsComposerUtils::rotate( -mEvaluatedMapRotation, dx, dy );
1811  QgsPointXY backRotatedCoords( rotationPoint.x() + dx, rotationPoint.y() + dy );
1812 
1813  QgsRectangle unrotatedExtent = transformedExtent();
1814  double xItem = rect().width() * ( backRotatedCoords.x() - unrotatedExtent.xMinimum() ) / unrotatedExtent.width();
1815  double yItem = rect().height() * ( 1 - ( backRotatedCoords.y() - unrotatedExtent.yMinimum() ) / unrotatedExtent.height() );
1816  return QPointF( xItem, yItem );
1817 }
1818 
1819 void QgsComposerMap::drawAnnotations( QPainter *painter )
1820 {
1821  if ( !mComposition || !mComposition->project() || !mDrawAnnotations )
1822  {
1823  return;
1824  }
1825 
1826  QList< QgsAnnotation * > annotations = mComposition->project()->annotationManager()->annotations();
1827  if ( annotations.isEmpty() )
1828  return;
1829 
1831  rc.setForceVectorOutput( true );
1833  QList< QgsMapLayer * > layers = layersToRender( &rc.expressionContext() );
1834 
1835  Q_FOREACH ( QgsAnnotation *annotation, annotations )
1836  {
1837  if ( !annotation || !annotation->isVisible() )
1838  {
1839  continue;
1840  }
1841  if ( annotation->mapLayer() && !layers.contains( annotation->mapLayer() ) )
1842  continue;
1843 
1844  drawAnnotation( annotation, rc );
1845  }
1846 }
1847 
1848 void QgsComposerMap::drawAnnotation( const QgsAnnotation *annotation, QgsRenderContext &context )
1849 {
1850  if ( !annotation || !annotation->isVisible() || !context.painter() || !context.painter()->device() )
1851  {
1852  return;
1853  }
1854 
1855  context.painter()->save();
1856  context.painter()->setRenderHint( QPainter::Antialiasing, context.flags() & QgsRenderContext::Antialiasing );
1857 
1858  double itemX, itemY;
1859  if ( annotation->hasFixedMapPosition() )
1860  {
1861  QPointF mapPos = composerMapPosForItem( annotation );
1862  itemX = mapPos.x();
1863  itemY = mapPos.y();
1864  }
1865  else
1866  {
1867  itemX = annotation->relativePosition().x() * rect().width();
1868  itemY = annotation->relativePosition().y() * rect().height();
1869  }
1870  context.painter()->translate( itemX, itemY );
1871 
1872  //setup painter scaling to dots so that symbology is drawn to scale
1873  double dotsPerMM = context.painter()->device()->logicalDpiX() / 25.4;
1874  context.painter()->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
1875 
1876  annotation->render( context );
1877  context.painter()->restore();
1878 }
1879 
1880 QPointF QgsComposerMap::composerMapPosForItem( const QgsAnnotation *annotation ) const
1881 {
1882  if ( !annotation )
1883  return QPointF( 0, 0 );
1884 
1885  double mapX = 0.0;
1886  double mapY = 0.0;
1887 
1888  mapX = annotation->mapPosition().x();
1889  mapY = annotation->mapPosition().y();
1890  QgsCoordinateReferenceSystem annotationCrs = annotation->mapPositionCrs();
1891 
1892  if ( annotationCrs != crs() )
1893  {
1894  //need to reproject
1895  QgsCoordinateTransform t( annotationCrs, crs() );
1896  double z = 0.0;
1897  t.transformInPlace( mapX, mapY, z );
1898  }
1899 
1900  return mapToItemCoords( QPointF( mapX, mapY ) );
1901 }
1902 
1904 {
1905  if ( !mComposition )
1906  {
1907  return;
1908  }
1909 
1910  const QgsComposerMap *existingMap = mComposition->getComposerMapById( mId );
1911  if ( !existingMap )
1912  {
1913  return; //keep mId as it is still available
1914  }
1915 
1916  int maxId = -1;
1917  QList<const QgsComposerMap *> mapList = mComposition->composerMapItems();
1918  QList<const QgsComposerMap *>::const_iterator mapIt = mapList.constBegin();
1919  for ( ; mapIt != mapList.constEnd(); ++mapIt )
1920  {
1921  if ( ( *mapIt )->id() > maxId )
1922  {
1923  maxId = ( *mapIt )->id();
1924  }
1925  }
1926  mId = maxId + 1;
1927  updateToolTip();
1928 }
1929 
1931 {
1932  mAtlasDriven = enabled;
1933 
1934  if ( !enabled )
1935  {
1936  //if not enabling the atlas, we still need to refresh the map extents
1937  //so that data defined extents and scale are recalculated
1938  refreshMapExtents();
1939  }
1940 }
1941 
1943 {
1944  if ( valueType == QgsComposerObject::EvaluatedValue )
1945  {
1946  //evaluate data defined atlas margin
1947 
1948  //start with user specified margin
1949  double margin = mAtlasMargin;
1951 
1952  bool ok = false;
1953  double ddMargin = mDataDefinedProperties.valueAsDouble( QgsComposerObject::MapAtlasMargin, context, 0.0, &ok );
1954  if ( ok )
1955  {
1956  //divide by 100 to convert to 0 -> 1.0 range
1957  margin = ddMargin / 100;
1958  }
1959  return margin;
1960  }
1961  else
1962  {
1963  return mAtlasMargin;
1964  }
1965 }
1966 
double scale() const
Returns the map scale.
void setStyle(const GridStyle style)
Sets the grid style, which controls how the grid is drawn over the map&#39;s contents.
void setForceVectorOutput(bool force)
void preparedForAtlas()
Is emitted when the map has been prepared for atlas rendering, just before actual rendering...
void addGrid(QgsComposerMapGrid *grid)
Adds a new map grid to the stack and takes ownership of the grid.
The class is used as a container of context for various read/write operations on other objects...
AtlasScalingMode
Scaling modes used for the serial rendering (atlas)
QgsMapSettings mapSettings(const QgsRectangle &extent, QSizeF size, int dpi) const
Return map settings that would be used for drawing of the map.
void finished()
emitted when asynchronous rendering is finished (or canceled).
Single variable definition for use within a QgsExpressionContextScope.
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
sets destination coordinate reference system
A rectangle specified with double values.
Definition: qgsrectangle.h:38
void calculateMaxGridExtension(double &top, double &right, double &bottom, double &left) const
Calculates the maximum distance grids within the stack extend beyond the QgsComposerMap&#39;s item rect...
Base class for all map layer types.
Definition: qgsmaplayer.h:54
void setExtent(const QgsRectangle &rect, bool magnified=true)
Set coordinates of the rectangle which should be rendered.
Job implementation that renders everything sequentially using a custom painter.
double horizontalViewScaleFactor() const
Returns the zoom factor of the graphics view.
double mapUnitsToMM() const
Returns the conversion factor map units -> mm.
The extent is adjusted so that each feature is fully visible.
void setAnnotationDirection(const AnnotationDirection direction, const BorderSide border)
Sets the direction for drawing frame annotations.
void setPathResolver(const QgsPathResolver &resolver)
Sets up path resolver for conversion between relative and absolute paths.
bool hasMapTheme(const QString &name) const
Returns whether a map theme with a matching name exists.
const QgsComposerMap * getComposerMapById(const int id) const
Returns the composer map with specified id.
bool isVisible() const
Returns true if the annotation is visible and should be rendered.
Definition: qgsannotation.h:86
void setBlendMode(const QPainter::CompositionMode mode)
Sets the blending mode used for drawing the grid.
double atlasMargin(const QgsComposerObject::PropertyValueType valueType=QgsComposerObject::EvaluatedValue)
Returns the margin size (percentage) used when the map is in atlas mode.
bool shouldDrawItem() const
Returns whether the item should be drawn in the current context.
static Q_INVOKABLE QString toString(QgsUnitTypes::DistanceUnit unit)
Returns a translated string representing a distance unit.
GridStyle
Grid drawing style.
virtual void setFrameStrokeWidth(const double strokeWidth)
Sets frame stroke width.
QList< QgsMapLayer * > mapThemeVisibleLayers(const QString &name) const
Returns the list of layers that are visible for the specified map theme.
void setOffsetY(const double offset)
Sets the offset for grid lines in the y-direction.
QMap< QString, QString > mapThemeStyleOverrides(const QString &name)
Get layer style overrides (for QgsMapSettings) of the visible layers for given map theme...
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:70
Use antialiasing while drawing.
void setFramePenSize(const double width)
Sets the width of the stroke drawn in the grid frame.
void assignFreeId()
Sets mId to a number not yet used in the composition.
QString xmlData() const
Return XML content of the style.
bool readXml(const QDomElement &elem, const QDomDocument &doc) override
Sets the grid stack&#39;s state from a DOM document.
void setNewAtlasFeatureExtent(const QgsRectangle &extent)
Sets new Extent for the current atlas preview and changes width, height (and implicitly also scale)...
void readXml(const QDomElement &styleElement)
Read style configuration (for project file reading)
void setOffset(double xOffset, double yOffset)
Sets offset values to shift image (useful for live updates when moving item content) ...
void setFrameSymbol(QgsFillSymbol *symbol)
Sets the fill symbol used for drawing the overview extent.
static QgsLineSymbol * createSimple(const QgsStringMap &properties)
Create a line symbol with one symbol layer: SimpleLine with specified properties. ...
Definition: qgssymbol.cpp:1070
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
void itemChanged()
Emitted when the item changes.
void setLayers(const QList< QgsMapLayer *> &layers)
Setter for stored layer set.
void addOverview(QgsComposerMapOverview *overview)
Adds a new map overview to the stack and takes ownership of the overview.
QPolygonF visibleExtentPolygon() const
Returns a polygon representing the current visible map extent, considering map extents and rotation...
QgsRectangle extent() const
double y
Definition: qgspointxy.h:47
virtual bool writeXml(QDomElement &elem, QDomDocument &doc) const
Stores the state of the item stack in a DOM node.
ZoomMode
Modes for zooming item content.
A collection of grids which is drawn above the map content in a QgsComposerMap.
void layerOrderChanged()
Emitted when the layer order has changed.
A class to represent a 2D point.
Definition: qgspointxy.h:42
void scale(double scaleFactor, const QgsPointXY *c=nullptr)
Scale the rectangle around its center point.
Layer and style map theme.
A item that forms part of a map composition.
Zoom to center of content.
TYPE * resolveWeakly(const QgsProject *project)
Resolves the map layer by attempting to find a matching layer in a project using a weak match...
void setOutputDpi(double dpi)
Set DPI used for conversion between real world units (e.g. mm) and pixels.
QString toProj4() const
Returns a Proj4 string representation of this CRS.
void crsChanged()
Emitted when the CRS of the project has changed.
void setDpi(double dpi)
Set the dpi to be used in scale calculations.
const QgsDatumTransformStore & datumTransformStore() const
void setDestinationCrs(const QgsCoordinateReferenceSystem &destCrs)
double mLastValidViewScaleFactor
Backup to restore item appearance if no view scale factor is available.
void drawItems(QPainter *painter)
Draws the items from the stack on a specified painter.
void mapRotationChanged(double newRotation)
Is emitted on rotation change to notify north arrow pictures.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:96
static const QStringList containsAdvancedEffects(const QgsMapSettings &mapSettings)
Checks whether any of the layers attached to a map settings object contain advanced effects...
QColor backgroundColor() const
Gets the background color for this item.
static QPainter::CompositionMode getCompositionMode(QgsPainting::BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode.
Definition: qgspainting.cpp:6
Flags flags() const
Return combination of flags used for rendering.
The current scale of the map is used for each feature of the atlas.
virtual void drawFrame(QPainter *p)
Draw black frame around item.
void setAnnotationFont(const QFont &font)
Sets the font used for drawing grid annotations.
void setLayerStyleOverrides(const QMap< QString, QString > &overrides)
Set map of map layer style overrides (key: layer ID, value: style name) where a different style shoul...
Map extent x maximum.
Map extent x minimum.
QString ellipsoid
Definition: qgsproject.h:86
AnnotationDirection
Direction of grid annotations.
Enable layer opacity and blending effects.
bool hasFixedMapPosition
Definition: qgsannotation.h:65
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the map&#39;s preset coordinate reference system.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:347
QList< const QgsComposerMap * > composerMapItems() const
Returns pointers to all composer maps in the scene.
AnnotationFormat
Format for displaying grid annotations.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:210
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
QgsComposition::AtlasMode atlasMode() const
Returns the current atlas mode of the composition.
QPointF relativePosition() const
Returns the relative position of the annotation, if it is not attached to a fixed map position...
DataDefinedProperty
Data defined properties for different item types.
virtual QString name() const =0
Return a provider name.
int readNumEntry(const QString &scope, const QString &key, int def=0, bool *ok=nullptr) const
void setCrossLength(const double length)
Sets the length of the cross segments drawn for the grid.
Vector graphics should not be cached and drawn as raster images.
void setFlag(Flag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
Abstract base class for annotation items which are drawn over a map.
Definition: qgsannotation.h:46
QgsComposition::PlotStyle plotStyle() const
The QgsMapSettings class contains configuration for rendering of the map.
void readFromLayer(QgsMapLayer *layer)
Store layer&#39;s active style information in the instance.
bool readXml(const QDomElement &elem, const QDomDocument &doc) override
Sets the overview stack&#39;s state from a DOM document.
static QgsRenderContext createRenderContextForMap(QgsComposerMap *map, QPainter *painter, double dpi=-1)
Creates a render context suitable for the specified composer map and painter destination.
void zoomToExtent(const QgsRectangle &extent)
Zooms the map so that the specified extent is fully visible within the map item.
bool containsAdvancedEffects() const
Returns whether any items within the stack contain advanced effects, such as blending modes...
bool readXml(const QDomElement &itemElem, const QDomDocument &doc) override
Sets state from Dom document.
Stores style information (renderer, opacity, labeling, diagrams etc.) applicable to a map layer...
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
QList< QgsMapLayer *> masterVisibleLayers() const
Returns the master list of visible layers.
void refreshItemsTriggered()
Is emitted when item in the composition must be refreshed.
void setOutputSize(QSize size)
Set the size of the resulting map image.
QString provider
Weak reference to layer provider.
bool _writeXml(QDomElement &itemElem, QDomDocument &doc) const
Writes parameter that are not subclass specific in document. Usually called from writeXml methods of ...
QString layerId
Original layer ID.
An individual overview which is drawn above the map content in a QgsComposerMap, and shows the extent...
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
double calculate(const QgsRectangle &mapExtent, int canvasWidth)
Calculate the scale denominator.
QgsMapThemeCollection mapThemeCollection
Definition: qgsproject.h:87
void updateBoundingRect()
Updates the bounding rect of this item. Call this function before doing any changes related to annota...
QgsPathResolver pathResolver() const
Return path resolver object with considering whether the project uses absolute or relative paths and ...
virtual void drawSelectionBoxes(QPainter *p)
Draws additional graphics on selected items.
friend class QgsComposerMapOverview
void setNewScale(double scaleDenominator, bool forceUpdate=true)
Sets new map scale and changes only the map extent.
bool mFrame
True if item fram needs to be painted.
Whether vector selections should be shown in the rendered map.
void setWidth(double width)
Definition: qgssymbol.cpp:1523
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:118
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:198
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:75
bool useAdvancedEffects() const
Returns true if a composition should use advanced effects such as blend modes.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setAnnotationFormat(const AnnotationFormat format)
Sets the format for drawing grid annotations.
QgsCoordinateReferenceSystem crs
Definition: qgsproject.h:85
bool hideCoverage() const
Returns true if the atlas is set to hide the coverage layer.
QString name
Weak reference to layer name.
AnnotationPosition
Position for grid annotations.
Map extent y minimum.
Enable anti-aliasing for map rendering.
void render(QgsRenderContext &context) const
Renders the annotation to a target render context.
void setCentered(const bool centered)
Sets whether the extent of the map is forced to center on the overview.
void setMapUnits(QgsUnitTypes::DistanceUnit mapUnits)
Set the map units.
void setAnnotationEnabled(const bool enabled)
Sets whether annotations should be shown for the grid.
virtual void refreshDataDefinedProperty(const QgsComposerObject::DataDefinedProperty property=QgsComposerObject::AllProperties, const QgsExpressionContext *context=nullptr) override
Refreshes a data defined property for the item by reevaluating the property&#39;s value and redrawing the...
void setNewExtent(const QgsRectangle &extent)
Sets new extent for the map.
bool drawAnnotations() const
Returns whether annotations are drawn within the composer map.
QgsPropertyCollection mDataDefinedProperties
Reads and writes project states.
Definition: qgsproject.h:79
bool hasBackground() const
Whether this item has a Background or not.
void setMapRotation(double rotation)
Sets the rotation for the map - this does not affect the composer item shape, only the way the map is...
void moveContent(double dx, double dy) override
Move content of map.
An individual grid which is drawn above the map content in a QgsComposerMap.
PropertyValueType
Specifies whether the value returned by a function should be the original, user set value...
Single scope for storing variables and functions for use within a QgsExpressionContext.
bool _readXml(const QDomElement &itemElem, const QDomDocument &doc)
Reads parameter that are not subclass specific in document. Usually called from readXml methods of su...
QString source
Weak reference to layer public source.
QList< QgsMapLayer * > mapLayersByName(const QString &layerName) const
Retrieve a list of matching registered layers by layer name.
void setFrameWidth(const double width)
Sets the grid frame width.
void setAnnotationFontColor(const QColor &color)
Sets the font color used for drawing grid annotations.
Graphics scene for map printing.
QList< QgsMapLayer * > layers() const
Getter for stored layer set.
Object representing map window.
Enable drawing of vertex markers for layers in editing mode.
QgsAnnotationManager * annotationManager()
Returns pointer to the project&#39;s annotation manager.
static void rotate(const double angle, double &x, double &y)
Rotates a point / vector around the origin.
double x
Definition: qgspointxy.h:46
Return the current evaluated value for the property.
QgsMapLayer * mapLayer() const
Returns the map layer associated with the annotation.
void setLineSymbol(QgsLineSymbol *symbol)
Sets the line symbol used for drawing grid lines.
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
void draw(QPainter *painter, const QgsRectangle &extent, QSizeF size, double dpi, double *forceWidthScale=nullptr)
Draw to paint device.
void setFrameFillColor1(const QColor &color)
Sets the first fill color used for the grid frame.
void setFramePenColor(const QColor &color)
Sets the color of the stroke drawn in the grid frame.
void setAnnotationPosition(const AnnotationPosition position, const BorderSide border)
Sets the position for the grid annotations on a specified side of the map frame.
virtual ~QgsComposerMap()
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:106
void setRotation(double rotation)
Sets the rotation of the resulting map image, in degrees clockwise.
QgsExpressionContext & expressionContext()
Gets the expression context.
Calculates scale for a given combination of canvas size, map extent, and monitor dpi.
virtual QgsExpressionContext createExpressionContext() const override
Creates an expression context relating to the item&#39;s current state.
QgsLayerTree * layerTreeRoot() const
Return pointer to the root (invisible) node of the project&#39;s layer tree.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:91
Map extent y maximum.
QPointF mapToItemCoords(QPointF mapCoords) const
Transforms map coordinates to item coordinates (considering rotation and move offset) ...
QgsComposerMapOverview * overview(const QString &overviewId) const
Returns a reference to an overview within the stack.
QgsComposition * mComposition
void layerStyleOverridesChanged()
Emitted when layer style overrides are changed...
void setBackgroundColor(const QColor &color)
Set the background color of the map.
void setLabelingEngineSettings(const QgsLabelingEngineSettings &settings)
Sets global configuration of the labeling engine.
QgsCoordinateReferenceSystem mapPositionCrs() const
Returns the CRS of the map position, or an invalid CRS if the annotation does not have a fixed map po...
Contains information about the context of a rendering operation.
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used for rendering the map.
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
virtual void refreshDataDefinedProperty(const QgsComposerObject::DataDefinedProperty property=QgsComposerObject::AllProperties, const QgsExpressionContext *context=nullptr) override
QPainter * painter()
Returns the destination QPainter for the render operation.
int numberExportLayers() const override
Get the number of layers that this item requires for exporting as layers.
QList< QgsAnnotation *> annotations() const
Returns a list of all annotations contained in the manager.
void setBackgroundColor(const QColor &backgroundColor)
Sets the background color for this item.
void layersWillBeRemoved(const QStringList &layerIds)
Emitted when one or more layers are about to be removed from the registry.
int mCurrentExportLayer
The layer that needs to be exported.
const QgsComposition * composition() const
Returns the composition the item is attached to.
virtual void setEnabled(const bool enabled)
Controls whether the item will be drawn.
virtual QString displayName() const override
Get item display name.
void writeXml(QDomElement &styleElement) const
Write style configuration (for project file writing)
QgsProject * project() const
The project associated with the composition.
bool writeXml(QDomElement &elem, QDomDocument &doc) const override
Stores state in Dom node.
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:80
QString valueAsString(int key, const QgsExpressionContext &context, const QString &defaultString=QString(), bool *ok=0) const
Calculates the current value of the property with the specified key and interprets it as a string...
virtual void setFrameStrokeWidth(const double strokeWidth) override
Sets frame stroke width.
QgsPointXY mapPosition
Definition: qgsannotation.h:66
virtual void drawBackground(QPainter *p)
Draw background.
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void requestedExtent(QgsRectangle &extent) const
Calculates the extent to request and the yShift of the top-left point in case of rotation.
This class represents a coordinate reference system (CRS).
virtual void setSceneRect(const QRectF &rectangle)
Sets this items bound in scene coordinates such that 1 item size units corresponds to 1 scene size un...
void setAnnotationPrecision(const int precision)
Sets the coordinate precision for grid annotations.
virtual QgsExpressionContext createExpressionContext() const override
Creates an expression context relating to the item&#39;s current state.
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
bool containsWmsLayer() const
True if composer map renders a WMS layer.
void setIntervalY(const double interval)
Sets the interval between grid lines in the y-direction.
Class for doing transforms between two map coordinate systems.
QgsComposerMap(QgsComposition *composition, int x, int y, int width, int height)
Constructor.
void setInverted(const bool inverted)
Sets whether the overview frame is inverted, ie, whether the shaded area is drawn outside the extent ...
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:96
void setLayers(const QList< QgsMapLayer *> &layers)
Set list of layers for map rendering.
void setFrameMap(const int mapId)
Sets overview frame map.
bool readXml(const QDomNode &node)
Restores state from the given DOM node.
void resize(double dx, double dy)
Resizes an item in x- and y direction (canvas coordinates)
virtual void updateItem()
Updates (redraws) the item, with the possibility to do custom update for subclasses.
void setSceneRect(const QRectF &rectangle) override
Sets new scene rectangle bounds and recalculates hight and extent.
QgsVectorLayer * coverageLayer() const
Returns the coverage layer used for the atlas features.
QgsAtlasComposition & atlasComposition()
void setUpdatesEnabled(bool enabled)
Sets whether updates to the item are enabled.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:101
static QgsGeometry fromPoint(const QgsPointXY &point)
Creates a new geometry from a QgsPointXY object.
Enable vector simplification and other rendering optimizations.
bool hasFrame() const
Whether this item has a frame or not.
bool containsAdvancedEffects() const
True if composer map contains layers with blend modes or flattened layers for vectors.
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=0) const
Calculates the current value of the property with the specified key and interprets it as a double...
void extentChanged()
QgsPointXY center() const
Returns the center point of the rectangle.
Definition: qgsrectangle.h:146
void setAtlasDriven(bool enabled)
Sets whether the map extent will follow the current atlas feature.
void setFrameFillColor2(const QColor &color)
Sets the second fill color used for the grid frame.
void setLayerStyleOverrides(const QMap< QString, QString > &overrides)
Setter for stored overrides of styles for layers.
void setFrameStyle(const FrameStyle style)
Sets the grid frame style.
double mapRotation(QgsComposerObject::PropertyValueType valueType=QgsComposerObject::EvaluatedValue) const
Returns the rotation used for drawing the map within the composer item, in degrees clockwise...
TYPE * resolve(const QgsProject *project)
Resolves the map layer by attempting to find a layer with matching ID within a project.
bool writeXml(QDomNode &node, QDomDocument &doc) const
Stores state to the given Dom node in the given document.
QRectF boundingRect() const override
In case of annotations, the bounding rectangle can be larger than the map item rectangle.
void transformInPlace(double &x, double &y, double &z, TransformDirection direction=ForwardTransform) const
Transforms an array of x, y and z double coordinates in place, from the source CRS to the destination...
void storeCurrentLayerStyles()
Stores the current layer styles into style overrides.
TYPE * get() const
Returns a pointer to the layer, or nullptr if the reference has not yet been matched to a layer...
virtual void zoomContent(const double factor, const QPointF point, const ZoomMode mode=QgsComposerItem::Zoom) override
Zoom content of item.
void renderSynchronously()
Render the map synchronously in this thread.
void setIntervalX(const double interval)
Sets the interval between grid lines in the x-direction.
QString id() const
Get item&#39;s id (which is not necessarly unique)
const QgsRectangle * currentMapExtent() const
Returns a pointer to the current map extent, which is either the original user specified extent or th...
Zoom and recenter content to point.
QgsComposerMapGrid * grid(const QString &gridId) const
Returns a reference to a grid within the stack.
QPolygonF transformedMapPolygon() const
Returns extent that considers rotation and shift with mOffsetX / mOffsetY.
void setOffsetX(const double offset)
Sets the offset for grid lines in the x-direction.
QString authid() const
Returns the authority identifier for the CRS.
void setBlendMode(const QPainter::CompositionMode blendMode)
Sets the blending mode used for drawing the overview.
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:65
QgsComposerMapGrid * grid()
Returns the map item&#39;s first grid.
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
void setAnnotationFrameDistance(const double distance)
Sets the distance between the map frame and annotations.
static QColor decodeColor(const QString &str)
All properties for item.
void invalidateCache()
Forces a deferred update of the cached map image on next paint.
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:125
int size() const
Returns the number of items in the stack.
Base class for raster data providers.
void setColor(const QColor &color)
Definition: qgssymbol.cpp:428
const QgsLabelingEngineSettings & labelingEngineSettings() const
Returns project&#39;s global labeling engine settings.
Zoom while maintaining relative position of point.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
QgsComposerMapOverview * overview()
Returns the map item&#39;s first overview.
A collection of overviews which are drawn above the map content in a QgsComposerMap.