QGIS API Documentation  2.99.0-Master (69af2f5)
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 
168  //set layers to render
169  QList<QgsMapLayer *> layers = layersToRender( &expressionContext );
170  if ( -1 != mCurrentExportLayer )
171  {
172  const int layerIdx = mCurrentExportLayer - ( hasBackground() ? 1 : 0 );
173  if ( layerIdx >= 0 && layerIdx < layers.length() )
174  {
175  // exporting with separate layers (e.g., to svg layers), so we only want to render a single map layer
176  QgsMapLayer *ml = layers[ layers.length() - layerIdx - 1 ];
177  layers.clear();
178  layers << ml;
179  }
180  else
181  {
182  // exporting decorations such as map frame/grid/overview, so no map layers required
183  layers.clear();
184  }
185  }
186  jobMapSettings.setLayers( layers );
187  jobMapSettings.setLayerStyleOverrides( layerStyleOverridesToRender( expressionContext ) );
188 
191  {
192  //if outputting composer, disable optimisations like layer simplification
193  jobMapSettings.setFlag( QgsMapSettings::UseRenderingOptimization, false );
194  }
195 
197  jobMapSettings.setExpressionContext( context );
198 
199  // composer-specific overrides of flags
200  jobMapSettings.setFlag( QgsMapSettings::ForceVectorOutput, true ); // force vector output (no caching of marker images etc.)
201  jobMapSettings.setFlag( QgsMapSettings::Antialiasing, true );
202  jobMapSettings.setFlag( QgsMapSettings::DrawEditingInfo, false );
203  jobMapSettings.setFlag( QgsMapSettings::DrawSelection, false );
204  jobMapSettings.setFlag( QgsMapSettings::UseAdvancedEffects, mComposition->useAdvancedEffects() ); // respect the composition's useAdvancedEffects flag
205 
206  jobMapSettings.datumTransformStore().setDestinationCrs( renderCrs );
207 
209 
210  return jobMapSettings;
211 }
212 
213 void QgsComposerMap::recreateCachedImageInBackground()
214 {
215  if ( mPainterJob )
216  {
217  disconnect( mPainterJob.get(), &QgsMapRendererCustomPainterJob::finished, this, &QgsComposerMap::painterJobFinished );
218  QgsMapRendererCustomPainterJob *oldJob = mPainterJob.release();
219  QPainter *oldPainter = mPainter.release();
220  QImage *oldImage = mCacheRenderingImage.release();
221  connect( oldJob, &QgsMapRendererCustomPainterJob::finished, this, [oldPainter, oldJob, oldImage]
222  {
223  oldJob->deleteLater();
224  delete oldPainter;
225  delete oldImage;
226  } );
227  oldJob->cancelWithoutBlocking();
228  }
229  else
230  {
231  mCacheRenderingImage.reset( nullptr );
232  }
233 
234  Q_ASSERT( !mPainterJob );
235  Q_ASSERT( !mPainter );
236  Q_ASSERT( !mCacheRenderingImage );
237 
238  double horizontalVScaleFactor = horizontalViewScaleFactor();
239  if ( horizontalVScaleFactor < 0 )
240  {
241  //make sure scale factor is positive
242  horizontalVScaleFactor = mLastValidViewScaleFactor > 0 ? mLastValidViewScaleFactor : 1;
243  }
244 
245  const QgsRectangle &ext = *currentMapExtent();
246  double widthMM = ext.width() * mapUnitsToMM();
247  double heightMM = ext.height() * mapUnitsToMM();
248 
249  int w = widthMM * horizontalVScaleFactor;
250  int h = heightMM * horizontalVScaleFactor;
251 
252  // limit size of image for better performance
253  if ( w > 5000 || h > 5000 )
254  {
255  if ( w > h )
256  {
257  w = 5000;
258  h = w * heightMM / widthMM;
259  }
260  else
261  {
262  h = 5000;
263  w = h * widthMM / heightMM;
264  }
265  }
266 
267  if ( w <= 0 || h <= 0 )
268  return;
269 
270  mCacheRenderingImage.reset( new QImage( w, h, QImage::Format_ARGB32 ) );
271 
272  // set DPI of the image
273  mCacheRenderingImage->setDotsPerMeterX( 1000 * w / widthMM );
274  mCacheRenderingImage->setDotsPerMeterY( 1000 * h / heightMM );
275 
276  if ( hasBackground() )
277  {
278  //Initially fill image with specified background color. This ensures that layers with blend modes will
279  //preview correctly
280  mCacheRenderingImage->fill( backgroundColor().rgba() );
281  }
282  else
283  {
284  //no background, but start with empty fill to avoid artifacts
285  mCacheRenderingImage->fill( QColor( 255, 255, 255, 0 ).rgba() );
286  }
287 
288  mCacheInvalidated = false;
289  mPainter.reset( new QPainter( mCacheRenderingImage.get() ) );
290  QgsMapSettings settings( mapSettings( ext, QSizeF( w, h ), mCacheRenderingImage->logicalDpiX() ) );
291  mPainterJob.reset( new QgsMapRendererCustomPainterJob( settings, mPainter.get() ) );
292  connect( mPainterJob.get(), &QgsMapRendererCustomPainterJob::finished, this, &QgsComposerMap::painterJobFinished );
293  mPainterJob->start();
294 }
295 
296 void QgsComposerMap::painterJobFinished()
297 {
298  mPainter->end();
299  mPainterJob.reset( nullptr );
300  mPainter.reset( nullptr );
301  mCacheFinalImage = std::move( mCacheRenderingImage );
302  mLastRenderedImageOffsetX = 0;
303  mLastRenderedImageOffsetY = 0;
304  updateItem();
305 }
306 
307 void QgsComposerMap::paint( QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *pWidget )
308 {
309  Q_UNUSED( pWidget );
310 
311  if ( !mComposition || !painter || !painter->device() )
312  {
313  return;
314  }
315  if ( !shouldDrawItem() )
316  {
317  return;
318  }
319 
320  QRectF thisPaintRect = QRectF( 0, 0, QGraphicsRectItem::rect().width(), QGraphicsRectItem::rect().height() );
321  if ( thisPaintRect.width() == 0 || thisPaintRect.height() == 0 )
322  return;
323 
324  painter->save();
325  painter->setClipRect( thisPaintRect );
326 
328  {
329  if ( !mCacheFinalImage || mCacheFinalImage->isNull() )
330  {
331  // No initial render available - so draw some preview text alerting user
332  drawBackground( painter );
333  painter->setBrush( QBrush( QColor( 125, 125, 125, 125 ) ) );
334  painter->drawRect( thisPaintRect );
335  painter->setBrush( Qt::NoBrush );
336  QFont messageFont;
337  messageFont.setPointSize( 12 );
338  painter->setFont( messageFont );
339  painter->setPen( QColor( 255, 255, 255, 255 ) );
340  painter->drawText( thisPaintRect, Qt::AlignCenter | Qt::AlignHCenter, tr( "Rendering map" ) );
341  if ( !mPainterJob )
342  {
343  // this is the map's very first paint - trigger a cache update
344  recreateCachedImageInBackground();
345  }
346  }
347  else
348  {
349  if ( mCacheInvalidated )
350  {
351  // cache was invalidated - trigger a background update
352  recreateCachedImageInBackground();
353  }
354 
355  //Background color is already included in cached image, so no need to draw
356 
357  double imagePixelWidth = mCacheFinalImage->width(); //how many pixels of the image are for the map extent?
358  double scale = rect().width() / imagePixelWidth;
359 
360  painter->save();
361 
362  painter->translate( mLastRenderedImageOffsetX + mXOffset, mLastRenderedImageOffsetY + mYOffset );
363  painter->scale( scale, scale );
364  painter->drawImage( 0, 0, *mCacheFinalImage );
365 
366  //restore rotation
367  painter->restore();
368  }
369  }
370  else if ( mComposition->plotStyle() == QgsComposition::Print ||
372  {
373  if ( mDrawing )
374  {
375  return;
376  }
377 
378  mDrawing = true;
379  QPaintDevice *paintDevice = painter->device();
380  if ( !paintDevice )
381  {
382  return;
383  }
384 
385  // Fill with background color
386  if ( shouldDrawPart( Background ) )
387  {
388  drawBackground( painter );
389  }
390 
391  QgsRectangle cExtent = *currentMapExtent();
392 
393  QSizeF size( cExtent.width() * mapUnitsToMM(), cExtent.height() * mapUnitsToMM() );
394 
395  painter->save();
396  painter->translate( mXOffset, mYOffset );
397 
398  double dotsPerMM = paintDevice->logicalDpiX() / 25.4;
399  size *= dotsPerMM; // output size will be in dots (pixels)
400  painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
401  draw( painter, cExtent, size, paintDevice->logicalDpiX() );
402 
403  //restore rotation
404  painter->restore();
405  mDrawing = false;
406  }
407 
408  painter->setClipRect( thisPaintRect, Qt::NoClip );
409  if ( shouldDrawPart( OverviewMapExtent ) )
410  {
411  mOverviewStack->drawItems( painter );
412  }
413  if ( shouldDrawPart( Grid ) )
414  {
415  mGridStack->drawItems( painter );
416  }
417 
418  //draw canvas items
419  drawAnnotations( painter );
420 
421  if ( shouldDrawPart( Frame ) )
422  {
423  drawFrame( painter );
424  }
425  if ( isSelected() && shouldDrawPart( SelectionBoxes ) )
426  {
427  drawSelectionBoxes( painter );
428  }
429 
430  painter->restore();
431 }
432 
434 {
435  mCacheInvalidated = true;
436  updateItem();
437 }
438 
440 {
441  return
442  ( hasBackground() ? 1 : 0 )
443  + layersToRender().length()
444  + 1 // for grids, if they exist
445  + 1 // for overviews, if they exist
446  + ( hasFrame() ? 1 : 0 )
447  + ( isSelected() ? 1 : 0 )
448  ;
449 }
450 
451 bool QgsComposerMap::shouldDrawPart( PartType part ) const
452 {
453  if ( -1 == mCurrentExportLayer )
454  {
455  //all parts of the composer map are visible
456  return true;
457  }
458 
459  int idx = numberExportLayers();
460  if ( isSelected() )
461  {
462  --idx;
463  if ( SelectionBoxes == part )
464  {
465  return mCurrentExportLayer == idx;
466  }
467  }
468 
469  if ( hasFrame() )
470  {
471  --idx;
472  if ( Frame == part )
473  {
474  return mCurrentExportLayer == idx;
475  }
476  }
477  --idx;
478  if ( OverviewMapExtent == part )
479  {
480  return mCurrentExportLayer == idx;
481  }
482  --idx;
483  if ( Grid == part )
484  {
485  return mCurrentExportLayer == idx;
486  }
487  if ( hasBackground() )
488  {
489  if ( Background == part )
490  {
491  return mCurrentExportLayer == 0;
492  }
493  }
494 
495  return true; // for Layer
496 }
497 
498 QList<QgsMapLayer *> QgsComposerMap::layersToRender( const QgsExpressionContext *context ) const
499 {
501  const QgsExpressionContext *evalContext = context ? context : &scopedContext;
502 
503  QList<QgsMapLayer *> renderLayers;
504 
505  if ( mFollowVisibilityPreset )
506  {
507  QString presetName = mFollowVisibilityPresetName;
508 
509  // preset name can be overridden by data-defined one
510  presetName = mDataDefinedProperties.valueAsString( QgsComposerObject::MapStylePreset, *evalContext, presetName );
511 
512  if ( mComposition->project()->mapThemeCollection()->hasMapTheme( presetName ) )
513  renderLayers = mComposition->project()->mapThemeCollection()->mapThemeVisibleLayers( presetName );
514  else // fallback to using map canvas layers
516  }
517  else if ( !layers().isEmpty() )
518  {
519  renderLayers = layers();
520  }
521  else
522  {
524  }
525 
526  bool ok = false;
527  QString ddLayers = mDataDefinedProperties.valueAsString( QgsComposerObject::MapLayers, *evalContext, QString(), &ok );
528  if ( ok )
529  {
530  renderLayers.clear();
531 
532  QStringList layerNames = ddLayers.split( '|' );
533  //need to convert layer names to layer ids
534  Q_FOREACH ( const QString &name, layerNames )
535  {
536  QList< QgsMapLayer * > matchingLayers = mComposition->project()->mapLayersByName( name );
537  Q_FOREACH ( QgsMapLayer *layer, matchingLayers )
538  {
539  renderLayers << layer;
540  }
541  }
542  }
543 
544  //remove atlas coverage layer if required
545  //TODO - move setting for hiding coverage layer to map item properties
547  {
549  {
550  //hiding coverage layer
551  int removeAt = renderLayers.indexOf( mComposition->atlasComposition().coverageLayer() );
552  if ( removeAt != -1 )
553  {
554  renderLayers.removeAt( removeAt );
555  }
556  }
557  }
558 
559  return renderLayers;
560 }
561 
562 QMap<QString, QString> QgsComposerMap::layerStyleOverridesToRender( const QgsExpressionContext &context ) const
563 {
564  if ( mFollowVisibilityPreset )
565  {
566  QString presetName = mFollowVisibilityPresetName;
567 
568  // data defined preset name?
569  presetName = mDataDefinedProperties.valueAsString( QgsComposerObject::MapStylePreset, context, presetName );
570 
571  if ( mComposition->project()->mapThemeCollection()->hasMapTheme( presetName ) )
573  else
574  return QMap<QString, QString>();
575  }
576  else if ( mKeepLayerStyles )
577  {
578  return mLayerStyleOverrides;
579  }
580  else
581  {
582  return QMap<QString, QString>();
583  }
584 }
585 
586 double QgsComposerMap::scale() const
587 {
588  QgsScaleCalculator calculator;
589  calculator.setMapUnits( crs().mapUnits() );
590  calculator.setDpi( 25.4 ); //QGraphicsView units are mm
591  return calculator.calculate( *currentMapExtent(), rect().width() );
592 }
593 
594 void QgsComposerMap::resize( double dx, double dy )
595 {
596  //setRect
597  QRectF currentRect = rect();
598  QRectF newSceneRect = QRectF( pos().x(), pos().y(), currentRect.width() + dx, currentRect.height() + dy );
599  setSceneRect( newSceneRect );
600  updateItem();
601 }
602 
603 void QgsComposerMap::moveContent( double dx, double dy )
604 {
605  mLastRenderedImageOffsetX -= dx;
606  mLastRenderedImageOffsetY -= dy;
607  if ( !mDrawing )
608  {
609  transformShift( dx, dy );
610  currentMapExtent()->setXMinimum( currentMapExtent()->xMinimum() + dx );
611  currentMapExtent()->setXMaximum( currentMapExtent()->xMaximum() + dx );
612  currentMapExtent()->setYMinimum( currentMapExtent()->yMinimum() + dy );
613  currentMapExtent()->setYMaximum( currentMapExtent()->yMaximum() + dy );
614 
615  //in case data defined extents are set, these override the calculated values
616  refreshMapExtents();
617 
618  invalidateCache();
619  emit itemChanged();
620  emit extentChanged();
621  }
622 }
623 
624 void QgsComposerMap::zoomContent( const double factor, const QPointF point, const ZoomMode mode )
625 {
626  if ( mDrawing )
627  {
628  return;
629  }
630 
631  if ( mode == QgsComposerItem::NoZoom )
632  {
633  //do nothing
634  return;
635  }
636 
637  //find out map coordinates of position
638  double mapX = currentMapExtent()->xMinimum() + ( point.x() / rect().width() ) * ( currentMapExtent()->xMaximum() - currentMapExtent()->xMinimum() );
639  double mapY = currentMapExtent()->yMinimum() + ( 1 - ( point.y() / rect().height() ) ) * ( currentMapExtent()->yMaximum() - currentMapExtent()->yMinimum() );
640 
641  //find out new center point
642  double centerX = ( currentMapExtent()->xMaximum() + currentMapExtent()->xMinimum() ) / 2;
643  double centerY = ( currentMapExtent()->yMaximum() + currentMapExtent()->yMinimum() ) / 2;
644 
645  if ( mode != QgsComposerItem::Zoom )
646  {
647  if ( mode == QgsComposerItem::ZoomRecenter )
648  {
649  centerX = mapX;
650  centerY = mapY;
651  }
652  else if ( mode == QgsComposerItem::ZoomToPoint )
653  {
654  centerX = mapX + ( centerX - mapX ) * ( 1.0 / factor );
655  centerY = mapY + ( centerY - mapY ) * ( 1.0 / factor );
656  }
657  }
658 
659  double newIntervalX, newIntervalY;
660 
661  if ( factor > 0 )
662  {
663  newIntervalX = ( currentMapExtent()->xMaximum() - currentMapExtent()->xMinimum() ) / factor;
664  newIntervalY = ( currentMapExtent()->yMaximum() - currentMapExtent()->yMinimum() ) / factor;
665  }
666  else //no need to zoom
667  {
668  return;
669  }
670 
671  currentMapExtent()->setXMaximum( centerX + newIntervalX / 2 );
672  currentMapExtent()->setXMinimum( centerX - newIntervalX / 2 );
673  currentMapExtent()->setYMaximum( centerY + newIntervalY / 2 );
674  currentMapExtent()->setYMinimum( centerY - newIntervalY / 2 );
675 
676  if ( mAtlasDriven && mAtlasScalingMode == Fixed && mComposition->atlasMode() != QgsComposition::AtlasOff )
677  {
678  //if map is atlas controlled and set to fixed scaling mode, then scale changes should be treated as permanent
679  //and also apply to the map's original extent (see #9602)
680  //we can't use the scaleRatio calculated earlier, as the scale can vary depending on extent for geographic coordinate systems
681  QgsScaleCalculator calculator;
682  calculator.setMapUnits( crs().mapUnits() );
683  calculator.setDpi( 25.4 ); //QGraphicsView units are mm
684  double scaleRatio = scale() / calculator.calculate( mExtent, rect().width() );
685  mExtent.scale( scaleRatio );
686  }
687 
688  //recalculate data defined scale and extents, since that may override zoom
689  refreshMapExtents();
690 
691  invalidateCache();
692  emit itemChanged();
693  emit extentChanged();
694 }
695 
696 void QgsComposerMap::setSceneRect( const QRectF &rectangle )
697 {
698  double w = rectangle.width();
699  double h = rectangle.height();
700  //prepareGeometryChange();
701 
702  QgsComposerItem::setSceneRect( rectangle );
703 
704  //QGraphicsRectItem::update();
705  double newHeight = mExtent.width() * h / w;
706  mExtent = QgsRectangle( mExtent.xMinimum(), mExtent.yMinimum(), mExtent.xMaximum(), mExtent.yMinimum() + newHeight );
707 
708  //recalculate data defined scale and extents
709  refreshMapExtents();
711  invalidateCache();
712  emit itemChanged();
713  emit extentChanged();
714 }
715 
717 {
718  if ( *currentMapExtent() == extent )
719  {
720  return;
721  }
723 
724  //recalculate data defined scale and extents, since that may override extent
725  refreshMapExtents();
726 
727  //adjust height
728  QRectF currentRect = rect();
729 
730  double newHeight = currentRect.width() * currentMapExtent()->height() / currentMapExtent()->width();
731 
732  setSceneRect( QRectF( pos().x(), pos().y(), currentRect.width(), newHeight ) );
733  updateItem();
734 }
735 
737 {
738  QgsRectangle newExtent = extent;
739  QgsRectangle currentExtent = *currentMapExtent();
740  //Make sure the width/height ratio is the same as the current composer map extent.
741  //This is to keep the map item frame size fixed
742  double currentWidthHeightRatio = 1.0;
743  if ( !currentExtent.isNull() )
744  currentWidthHeightRatio = currentExtent.width() / currentExtent.height();
745  else
746  currentWidthHeightRatio = rect().width() / rect().height();
747  double newWidthHeightRatio = newExtent.width() / newExtent.height();
748 
749  if ( currentWidthHeightRatio < newWidthHeightRatio )
750  {
751  //enlarge height of new extent, ensuring the map center stays the same
752  double newHeight = newExtent.width() / currentWidthHeightRatio;
753  double deltaHeight = newHeight - newExtent.height();
754  newExtent.setYMinimum( newExtent.yMinimum() - deltaHeight / 2 );
755  newExtent.setYMaximum( newExtent.yMaximum() + deltaHeight / 2 );
756  }
757  else
758  {
759  //enlarge width of new extent, ensuring the map center stays the same
760  double newWidth = currentWidthHeightRatio * newExtent.height();
761  double deltaWidth = newWidth - newExtent.width();
762  newExtent.setXMinimum( newExtent.xMinimum() - deltaWidth / 2 );
763  newExtent.setXMaximum( newExtent.xMaximum() + deltaWidth / 2 );
764  }
765 
766  if ( *currentMapExtent() == newExtent )
767  {
768  return;
769  }
770  *currentMapExtent() = newExtent;
771 
772  //recalculate data defined scale and extents, since that may override extent
773  refreshMapExtents();
774 
775  invalidateCache();
776  emit itemChanged();
777  emit extentChanged();
778 }
779 
781 {
782  if ( mAtlasFeatureExtent != extent )
783  {
784  //don't adjust size of item, instead adjust size of bounds to fit
785  QgsRectangle newExtent = extent;
786 
787  //Make sure the width/height ratio is the same as the map item size
788  double currentWidthHeightRatio = rect().width() / rect().height();
789  double newWidthHeightRatio = newExtent.width() / newExtent.height();
790 
791  if ( currentWidthHeightRatio < newWidthHeightRatio )
792  {
793  //enlarge height of new extent, ensuring the map center stays the same
794  double newHeight = newExtent.width() / currentWidthHeightRatio;
795  double deltaHeight = newHeight - newExtent.height();
796  newExtent.setYMinimum( extent.yMinimum() - deltaHeight / 2 );
797  newExtent.setYMaximum( extent.yMaximum() + deltaHeight / 2 );
798  }
799  else
800  {
801  //enlarge width of new extent, ensuring the map center stays the same
802  double newWidth = currentWidthHeightRatio * newExtent.height();
803  double deltaWidth = newWidth - newExtent.width();
804  newExtent.setXMinimum( extent.xMinimum() - deltaWidth / 2 );
805  newExtent.setXMaximum( extent.xMaximum() + deltaWidth / 2 );
806  }
807 
808  mAtlasFeatureExtent = newExtent;
809  }
810 
811  //recalculate data defined scale and extents, since that may override extents
812  refreshMapExtents();
813 
814  emit preparedForAtlas();
815  invalidateCache();
816  emit itemChanged();
817  emit extentChanged();
818 }
819 
821 {
822  //non-const version
823  if ( mAtlasDriven && mComposition->atlasMode() != QgsComposition::AtlasOff )
824  {
825  //if atlas is enabled, and we are either exporting the composition or previewing the atlas, then
826  //return the current temporary atlas feature extent
827  return &mAtlasFeatureExtent;
828  }
829  else
830  {
831  //otherwise return permanent user set extent
832  return &mExtent;
833  }
834 }
835 
837 {
838  if ( mCrs.isValid() )
839  return mCrs;
840  else if ( mComposition && mComposition->project() )
841  return mComposition->project()->crs();
843 }
844 
846 {
847  mCrs = crs;
848 }
849 
851 {
852  //const version
853  if ( mAtlasDriven && mComposition->atlasMode() != QgsComposition::AtlasOff )
854  {
855  //if atlas is enabled, and we are either exporting the composition or previewing the atlas, then
856  //return the current temporary atlas feature extent
857  return &mAtlasFeatureExtent;
858  }
859  else
860  {
861  //otherwise return permanent user set extent
862  return &mExtent;
863  }
864 }
865 
866 void QgsComposerMap::setNewScale( double scaleDenominator, bool forceUpdate )
867 {
868  double currentScaleDenominator = scale();
869 
870  if ( qgsDoubleNear( scaleDenominator, currentScaleDenominator ) || qgsDoubleNear( scaleDenominator, 0.0 ) )
871  {
872  return;
873  }
874 
875  double scaleRatio = scaleDenominator / currentScaleDenominator;
876  currentMapExtent()->scale( scaleRatio );
877 
878  if ( mAtlasDriven && mAtlasScalingMode == Fixed && mComposition->atlasMode() != QgsComposition::AtlasOff )
879  {
880  //if map is atlas controlled and set to fixed scaling mode, then scale changes should be treated as permanent
881  //and also apply to the map's original extent (see #9602)
882  //we can't use the scaleRatio calculated earlier, as the scale can vary depending on extent for geographic coordinate systems
883  QgsScaleCalculator calculator;
884  calculator.setMapUnits( crs().mapUnits() );
885  calculator.setDpi( 25.4 ); //QGraphicsView units are mm
886  scaleRatio = scaleDenominator / calculator.calculate( mExtent, rect().width() );
887  mExtent.scale( scaleRatio );
888  }
889 
890  invalidateCache();
891  if ( forceUpdate )
892  {
893  emit itemChanged();
894  }
895  emit extentChanged();
896 }
897 
898 void QgsComposerMap::setOffset( double xOffset, double yOffset )
899 {
900  mXOffset = xOffset;
901  mYOffset = yOffset;
902 }
903 
904 void QgsComposerMap::setMapRotation( double rotation )
905 {
906  mMapRotation = rotation;
907  mEvaluatedMapRotation = mMapRotation;
908  invalidateCache();
909  emit mapRotationChanged( rotation );
910  emit itemChanged();
911 }
912 
914 {
915  return valueType == QgsComposerObject::EvaluatedValue ? mEvaluatedMapRotation : mMapRotation;
916 }
917 
918 void QgsComposerMap::refreshMapExtents( const QgsExpressionContext *context )
919 {
921  const QgsExpressionContext *evalContext = context ? context : &scopedContext;
922 
923  //data defined map extents set?
924  QVariant exprVal;
925 
926  QgsRectangle newExtent = *currentMapExtent();
927  bool useDdXMin = false;
928  bool useDdXMax = false;
929  bool useDdYMin = false;
930  bool useDdYMax = false;
931  double minXD = 0;
932  double minYD = 0;
933  double maxXD = 0;
934  double maxYD = 0;
935 
936  bool ok = false;
937  minXD = mDataDefinedProperties.valueAsDouble( QgsComposerObject::MapXMin, *evalContext, 0.0, &ok );
938  if ( ok )
939  {
940  useDdXMin = true;
941  newExtent.setXMinimum( minXD );
942  }
943  minYD = mDataDefinedProperties.valueAsDouble( QgsComposerObject::MapYMin, *evalContext, 0.0, &ok );
944  if ( ok )
945  {
946  useDdYMin = true;
947  newExtent.setYMinimum( minYD );
948  }
949  maxXD = mDataDefinedProperties.valueAsDouble( QgsComposerObject::MapXMax, *evalContext, 0.0, &ok );
950  if ( ok )
951  {
952  useDdXMax = true;
953  newExtent.setXMaximum( maxXD );
954  }
955  maxYD = mDataDefinedProperties.valueAsDouble( QgsComposerObject::MapYMax, *evalContext, 0.0, &ok );
956  if ( ok )
957  {
958  useDdYMax = true;
959  newExtent.setYMaximum( maxYD );
960  }
961 
962  if ( newExtent != *currentMapExtent() )
963  {
964  //calculate new extents to fit data defined extents
965 
966  //Make sure the width/height ratio is the same as in current map extent.
967  //This is to keep the map item frame and the page layout fixed
968  double currentWidthHeightRatio = currentMapExtent()->width() / currentMapExtent()->height();
969  double newWidthHeightRatio = newExtent.width() / newExtent.height();
970 
971  if ( currentWidthHeightRatio < newWidthHeightRatio )
972  {
973  //enlarge height of new extent, ensuring the map center stays the same
974  double newHeight = newExtent.width() / currentWidthHeightRatio;
975  double deltaHeight = newHeight - newExtent.height();
976  newExtent.setYMinimum( newExtent.yMinimum() - deltaHeight / 2 );
977  newExtent.setYMaximum( newExtent.yMaximum() + deltaHeight / 2 );
978  }
979  else
980  {
981  //enlarge width of new extent, ensuring the map center stays the same
982  double newWidth = currentWidthHeightRatio * newExtent.height();
983  double deltaWidth = newWidth - newExtent.width();
984  newExtent.setXMinimum( newExtent.xMinimum() - deltaWidth / 2 );
985  newExtent.setXMaximum( newExtent.xMaximum() + deltaWidth / 2 );
986  }
987 
988  *currentMapExtent() = newExtent;
989  }
990 
991  //now refresh scale, as this potentially overrides extents
992 
993  //data defined map scale set?
994  double scaleD = mDataDefinedProperties.valueAsDouble( QgsComposerObject::MapScale, *evalContext, 0.0, &ok );
995  if ( ok )
996  {
997  setNewScale( scaleD, false );
998  newExtent = *currentMapExtent();
999  }
1000 
1001  if ( useDdXMax || useDdXMin || useDdYMax || useDdYMin )
1002  {
1003  //if only one of min/max was set for either x or y, then make sure our extent is locked on that value
1004  //as we can do this without altering the scale
1005  if ( useDdXMin && !useDdXMax )
1006  {
1007  double xMax = currentMapExtent()->xMaximum() - ( currentMapExtent()->xMinimum() - minXD );
1008  newExtent.setXMinimum( minXD );
1009  newExtent.setXMaximum( xMax );
1010  }
1011  else if ( !useDdXMin && useDdXMax )
1012  {
1013  double xMin = currentMapExtent()->xMinimum() - ( currentMapExtent()->xMaximum() - maxXD );
1014  newExtent.setXMinimum( xMin );
1015  newExtent.setXMaximum( maxXD );
1016  }
1017  if ( useDdYMin && !useDdYMax )
1018  {
1019  double yMax = currentMapExtent()->yMaximum() - ( currentMapExtent()->yMinimum() - minYD );
1020  newExtent.setYMinimum( minYD );
1021  newExtent.setYMaximum( yMax );
1022  }
1023  else if ( !useDdYMin && useDdYMax )
1024  {
1025  double yMin = currentMapExtent()->yMinimum() - ( currentMapExtent()->yMaximum() - maxYD );
1026  newExtent.setYMinimum( yMin );
1027  newExtent.setYMaximum( maxYD );
1028  }
1029 
1030  if ( newExtent != *currentMapExtent() )
1031  {
1032  *currentMapExtent() = newExtent;
1033  }
1034  }
1035 
1036  //lastly, map rotation overrides all
1037  double mapRotation = mMapRotation;
1038 
1039  //data defined map rotation set?
1040  mapRotation = mDataDefinedProperties.valueAsDouble( QgsComposerObject::MapRotation, *evalContext, mapRotation );
1041 
1042  if ( !qgsDoubleNear( mEvaluatedMapRotation, mapRotation ) )
1043  {
1044  mEvaluatedMapRotation = mapRotation;
1045  emit mapRotationChanged( mapRotation );
1046  }
1047 }
1048 
1050 {
1051  Q_FOREACH ( QgsMapLayer *layer, layersToRender() )
1052  {
1053  if ( QgsRasterLayer *currentRasterLayer = qobject_cast<QgsRasterLayer *>( layer ) )
1054  {
1055  const QgsRasterDataProvider *rasterProvider = nullptr;
1056  if ( ( rasterProvider = currentRasterLayer->dataProvider() ) )
1057  {
1058  if ( rasterProvider->name() == QLatin1String( "wms" ) )
1059  {
1060  return true;
1061  }
1062  }
1063  }
1064  }
1065  return false;
1066 }
1067 
1069 {
1070  //check easy things first
1071 
1072  //overviews
1073  if ( mOverviewStack->containsAdvancedEffects() )
1074  {
1075  return true;
1076  }
1077 
1078  //grids
1079  if ( mGridStack->containsAdvancedEffects() )
1080  {
1081  return true;
1082  }
1083 
1084 
1085  QgsMapSettings ms;
1086  ms.setLayers( layersToRender() );
1087  return ( !QgsMapSettingsUtils::containsAdvancedEffects( ms ).isEmpty() );
1088 }
1089 
1090 void QgsComposerMap::connectUpdateSlot()
1091 {
1092  //connect signal from layer registry to update in case of new or deleted layers
1093  QgsProject *project = mComposition->project();
1094  if ( project )
1095  {
1096  // handles updating the stored layer state BEFORE the layers are removed
1097  connect( project, static_cast < void ( QgsProject::* )( const QList<QgsMapLayer *>& layers ) > ( &QgsProject::layersWillBeRemoved ),
1098  this, &QgsComposerMap::layersAboutToBeRemoved );
1099  // redraws the map AFTER layers are removed
1100  connect( project->layerTreeRoot(), &QgsLayerTree::layerOrderChanged, this, [ = ]
1101  {
1102  if ( layers().isEmpty() )
1103  {
1104  //using project layers, and layer order has changed
1105  invalidateCache();
1106  }
1107  } );
1108 
1109  connect( project, &QgsProject::crsChanged, this, [ = ]
1110  {
1111  if ( !mCrs.isValid() )
1112  {
1113  //using project CRS, which just changed....
1114  invalidateCache();
1115  }
1116  } );
1117 
1118  }
1120 }
1121 
1122 bool QgsComposerMap::writeXml( QDomElement &elem, QDomDocument &doc ) const
1123 {
1124  if ( elem.isNull() )
1125  {
1126  return false;
1127  }
1128 
1129  QDomElement composerMapElem = doc.createElement( QStringLiteral( "ComposerMap" ) );
1130  composerMapElem.setAttribute( QStringLiteral( "id" ), mId );
1131 
1132  if ( mKeepLayerSet )
1133  {
1134  composerMapElem.setAttribute( QStringLiteral( "keepLayerSet" ), QStringLiteral( "true" ) );
1135  }
1136  else
1137  {
1138  composerMapElem.setAttribute( QStringLiteral( "keepLayerSet" ), QStringLiteral( "false" ) );
1139  }
1140 
1141  if ( mDrawAnnotations )
1142  {
1143  composerMapElem.setAttribute( QStringLiteral( "drawCanvasItems" ), QStringLiteral( "true" ) );
1144  }
1145  else
1146  {
1147  composerMapElem.setAttribute( QStringLiteral( "drawCanvasItems" ), QStringLiteral( "false" ) );
1148  }
1149 
1150  //extent
1151  QDomElement extentElem = doc.createElement( QStringLiteral( "Extent" ) );
1152  extentElem.setAttribute( QStringLiteral( "xmin" ), qgsDoubleToString( mExtent.xMinimum() ) );
1153  extentElem.setAttribute( QStringLiteral( "xmax" ), qgsDoubleToString( mExtent.xMaximum() ) );
1154  extentElem.setAttribute( QStringLiteral( "ymin" ), qgsDoubleToString( mExtent.yMinimum() ) );
1155  extentElem.setAttribute( QStringLiteral( "ymax" ), qgsDoubleToString( mExtent.yMaximum() ) );
1156  composerMapElem.appendChild( extentElem );
1157 
1158  if ( mCrs.isValid() )
1159  {
1160  QDomElement crsElem = doc.createElement( QStringLiteral( "crs" ) );
1161  mCrs.writeXml( crsElem, doc );
1162  composerMapElem.appendChild( crsElem );
1163  }
1164 
1165  // follow map theme
1166  composerMapElem.setAttribute( QStringLiteral( "followPreset" ), mFollowVisibilityPreset ? "true" : "false" );
1167  composerMapElem.setAttribute( QStringLiteral( "followPresetName" ), mFollowVisibilityPresetName );
1168 
1169  //map rotation
1170  composerMapElem.setAttribute( QStringLiteral( "mapRotation" ), QString::number( mMapRotation ) );
1171 
1172  //layer set
1173  QDomElement layerSetElem = doc.createElement( QStringLiteral( "LayerSet" ) );
1174  Q_FOREACH ( const QgsMapLayerRef &layerRef, mLayers )
1175  {
1176  if ( !layerRef )
1177  continue;
1178  QDomElement layerElem = doc.createElement( QStringLiteral( "Layer" ) );
1179  QDomText layerIdText = doc.createTextNode( layerRef.layerId );
1180  layerElem.appendChild( layerIdText );
1181 
1182  layerElem.setAttribute( QStringLiteral( "name" ), layerRef.name );
1183  layerElem.setAttribute( QStringLiteral( "source" ), layerRef.source );
1184  layerElem.setAttribute( QStringLiteral( "provider" ), layerRef.provider );
1185 
1186  layerSetElem.appendChild( layerElem );
1187  }
1188  composerMapElem.appendChild( layerSetElem );
1189 
1190  // override styles
1191  if ( mKeepLayerStyles )
1192  {
1193  QDomElement stylesElem = doc.createElement( QStringLiteral( "LayerStyles" ) );
1194  QMap<QString, QString>::const_iterator styleIt = mLayerStyleOverrides.constBegin();
1195  for ( ; styleIt != mLayerStyleOverrides.constEnd(); ++styleIt )
1196  {
1197  QDomElement styleElem = doc.createElement( QStringLiteral( "LayerStyle" ) );
1198 
1199  QgsMapLayerRef ref( styleIt.key() );
1200  ref.resolve( mComposition->project() );
1201 
1202  styleElem.setAttribute( QStringLiteral( "layerid" ), ref.layerId );
1203  styleElem.setAttribute( QStringLiteral( "name" ), ref.name );
1204  styleElem.setAttribute( QStringLiteral( "source" ), ref.source );
1205  styleElem.setAttribute( QStringLiteral( "provider" ), ref.provider );
1206 
1207  QgsMapLayerStyle style( styleIt.value() );
1208  style.writeXml( styleElem );
1209  stylesElem.appendChild( styleElem );
1210  }
1211  composerMapElem.appendChild( stylesElem );
1212  }
1213 
1214  //write a dummy "Grid" element to prevent crashes on pre 2.5 versions (refs #10905)
1215  QDomElement gridElem = doc.createElement( QStringLiteral( "Grid" ) );
1216  composerMapElem.appendChild( gridElem );
1217 
1218  //grids
1219  mGridStack->writeXml( composerMapElem, doc );
1220 
1221  //overviews
1222  mOverviewStack->writeXml( composerMapElem, doc );
1223 
1224  //atlas
1225  QDomElement atlasElem = doc.createElement( QStringLiteral( "AtlasMap" ) );
1226  atlasElem.setAttribute( QStringLiteral( "atlasDriven" ), mAtlasDriven );
1227  atlasElem.setAttribute( QStringLiteral( "scalingMode" ), mAtlasScalingMode );
1228  atlasElem.setAttribute( QStringLiteral( "margin" ), qgsDoubleToString( mAtlasMargin ) );
1229  composerMapElem.appendChild( atlasElem );
1230 
1231  elem.appendChild( composerMapElem );
1232  return _writeXml( composerMapElem, doc );
1233 }
1234 
1235 bool QgsComposerMap::readXml( const QDomElement &itemElem, const QDomDocument &doc )
1236 {
1237  if ( itemElem.isNull() )
1238  {
1239  return false;
1240  }
1241 
1242  setUpdatesEnabled( false );
1243 
1244  QString idRead = itemElem.attribute( QStringLiteral( "id" ), QStringLiteral( "not found" ) );
1245  if ( idRead != QLatin1String( "not found" ) )
1246  {
1247  mId = idRead.toInt();
1248  updateToolTip();
1249  }
1250 
1251  QgsReadWriteContext context;
1253 
1254  //extent
1255  QDomNodeList extentNodeList = itemElem.elementsByTagName( QStringLiteral( "Extent" ) );
1256  if ( !extentNodeList.isEmpty() )
1257  {
1258  QDomElement extentElem = extentNodeList.at( 0 ).toElement();
1259  double xmin, xmax, ymin, ymax;
1260  xmin = extentElem.attribute( QStringLiteral( "xmin" ) ).toDouble();
1261  xmax = extentElem.attribute( QStringLiteral( "xmax" ) ).toDouble();
1262  ymin = extentElem.attribute( QStringLiteral( "ymin" ) ).toDouble();
1263  ymax = extentElem.attribute( QStringLiteral( "ymax" ) ).toDouble();
1264  setNewExtent( QgsRectangle( xmin, ymin, xmax, ymax ) );
1265  }
1266 
1267  QDomNodeList crsNodeList = itemElem.elementsByTagName( QStringLiteral( "crs" ) );
1268  if ( !crsNodeList.isEmpty() )
1269  {
1270  QDomElement crsElem = crsNodeList.at( 0 ).toElement();
1271  mCrs.readXml( crsElem );
1272  }
1273  else
1274  {
1276  }
1277 
1278  //map rotation
1279  if ( !qgsDoubleNear( itemElem.attribute( QStringLiteral( "mapRotation" ), QStringLiteral( "0" ) ).toDouble(), 0.0 ) )
1280  {
1281  mMapRotation = itemElem.attribute( QStringLiteral( "mapRotation" ), QStringLiteral( "0" ) ).toDouble();
1282  }
1283 
1284  // follow map theme
1285  mFollowVisibilityPreset = itemElem.attribute( QStringLiteral( "followPreset" ) ).compare( QLatin1String( "true" ) ) == 0;
1286  mFollowVisibilityPresetName = itemElem.attribute( QStringLiteral( "followPresetName" ) );
1287 
1288  //mKeepLayerSet flag
1289  QString keepLayerSetFlag = itemElem.attribute( QStringLiteral( "keepLayerSet" ) );
1290  if ( keepLayerSetFlag.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 )
1291  {
1292  mKeepLayerSet = true;
1293  }
1294  else
1295  {
1296  mKeepLayerSet = false;
1297  }
1298 
1299  QString drawCanvasItemsFlag = itemElem.attribute( QStringLiteral( "drawCanvasItems" ), QStringLiteral( "true" ) );
1300  if ( drawCanvasItemsFlag.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 )
1301  {
1302  mDrawAnnotations = true;
1303  }
1304  else
1305  {
1306  mDrawAnnotations = false;
1307  }
1308 
1309  mLayerStyleOverrides.clear();
1310 
1311  //mLayers
1312  mLayers.clear();
1313  QDomNodeList layerSetNodeList = itemElem.elementsByTagName( QStringLiteral( "LayerSet" ) );
1314  if ( !layerSetNodeList.isEmpty() )
1315  {
1316  QDomElement layerSetElem = layerSetNodeList.at( 0 ).toElement();
1317  QDomNodeList layerIdNodeList = layerSetElem.elementsByTagName( QStringLiteral( "Layer" ) );
1318  mLayers.reserve( layerIdNodeList.size() );
1319  for ( int i = 0; i < layerIdNodeList.size(); ++i )
1320  {
1321  QDomElement layerElem = layerIdNodeList.at( i ).toElement();
1322  QString layerId = layerElem.text();
1323  QString layerName = layerElem.attribute( QStringLiteral( "name" ) );
1324  QString layerSource = layerElem.attribute( QStringLiteral( "source" ) );
1325  QString layerProvider = layerElem.attribute( QStringLiteral( "provider" ) );
1326 
1327  QgsMapLayerRef ref( layerId, layerName, layerSource, layerProvider );
1329  mLayers << ref;
1330  }
1331  }
1332 
1333  // override styles
1334  QDomNodeList layerStylesNodeList = itemElem.elementsByTagName( QStringLiteral( "LayerStyles" ) );
1335  mKeepLayerStyles = !layerStylesNodeList.isEmpty();
1336  if ( mKeepLayerStyles )
1337  {
1338  QDomElement layerStylesElem = layerStylesNodeList.at( 0 ).toElement();
1339  QDomNodeList layerStyleNodeList = layerStylesElem.elementsByTagName( QStringLiteral( "LayerStyle" ) );
1340  for ( int i = 0; i < layerStyleNodeList.size(); ++i )
1341  {
1342  const QDomElement &layerStyleElement = layerStyleNodeList.at( i ).toElement();
1343  QString layerId = layerStyleElement.attribute( QStringLiteral( "layerid" ) );
1344  QString layerName = layerStyleElement.attribute( QStringLiteral( "name" ) );
1345  QString layerSource = layerStyleElement.attribute( QStringLiteral( "source" ) );
1346  QString layerProvider = layerStyleElement.attribute( QStringLiteral( "provider" ) );
1347  QgsMapLayerRef ref( layerId, layerName, layerSource, layerProvider );
1349 
1350  QgsMapLayerStyle style;
1351  style.readXml( layerStyleElement );
1352  mLayerStyleOverrides.insert( ref.layerId, style.xmlData() );
1353  }
1354  }
1355 
1356  mDrawing = false;
1357  mNumCachedLayers = 0;
1358  mCacheInvalidated = true;
1359 
1360  //overviews
1361  mOverviewStack->readXml( itemElem, doc );
1362 
1363  //grids
1364  mGridStack->readXml( itemElem, doc );
1365 
1366  //load grid / grid annotation in old xml format
1367  //only do this if the grid stack didn't load any grids, otherwise this will
1368  //be the dummy element created by QGIS >= 2.5 (refs #10905)
1369  QDomNodeList gridNodeList = itemElem.elementsByTagName( QStringLiteral( "Grid" ) );
1370  if ( mGridStack->size() == 0 && !gridNodeList.isEmpty() )
1371  {
1372  QDomElement gridElem = gridNodeList.at( 0 ).toElement();
1373  QgsComposerMapGrid *mapGrid = new QgsComposerMapGrid( tr( "Grid %1" ).arg( 1 ), this );
1374  mapGrid->setEnabled( gridElem.attribute( QStringLiteral( "show" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
1375  mapGrid->setStyle( QgsComposerMapGrid::GridStyle( gridElem.attribute( QStringLiteral( "gridStyle" ), QStringLiteral( "0" ) ).toInt() ) );
1376  mapGrid->setIntervalX( gridElem.attribute( QStringLiteral( "intervalX" ), QStringLiteral( "0" ) ).toDouble() );
1377  mapGrid->setIntervalY( gridElem.attribute( QStringLiteral( "intervalY" ), QStringLiteral( "0" ) ).toDouble() );
1378  mapGrid->setOffsetX( gridElem.attribute( QStringLiteral( "offsetX" ), QStringLiteral( "0" ) ).toDouble() );
1379  mapGrid->setOffsetY( gridElem.attribute( QStringLiteral( "offsetY" ), QStringLiteral( "0" ) ).toDouble() );
1380  mapGrid->setCrossLength( gridElem.attribute( QStringLiteral( "crossLength" ), QStringLiteral( "3" ) ).toDouble() );
1381  mapGrid->setFrameStyle( static_cast< QgsComposerMapGrid::FrameStyle >( gridElem.attribute( QStringLiteral( "gridFrameStyle" ), QStringLiteral( "0" ) ).toInt() ) );
1382  mapGrid->setFrameWidth( gridElem.attribute( QStringLiteral( "gridFrameWidth" ), QStringLiteral( "2.0" ) ).toDouble() );
1383  mapGrid->setFramePenSize( gridElem.attribute( QStringLiteral( "gridFramePenThickness" ), QStringLiteral( "0.5" ) ).toDouble() );
1384  mapGrid->setFramePenColor( QgsSymbolLayerUtils::decodeColor( gridElem.attribute( QStringLiteral( "framePenColor" ), QStringLiteral( "0,0,0" ) ) ) );
1385  mapGrid->setFrameFillColor1( QgsSymbolLayerUtils::decodeColor( gridElem.attribute( QStringLiteral( "frameFillColor1" ), QStringLiteral( "255,255,255,255" ) ) ) );
1386  mapGrid->setFrameFillColor2( QgsSymbolLayerUtils::decodeColor( gridElem.attribute( QStringLiteral( "frameFillColor2" ), QStringLiteral( "0,0,0,255" ) ) ) );
1387  mapGrid->setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( itemElem.attribute( QStringLiteral( "gridBlendMode" ), QStringLiteral( "0" ) ).toUInt() ) ) );
1388  QDomElement gridSymbolElem = gridElem.firstChildElement( QStringLiteral( "symbol" ) );
1389  QgsLineSymbol *lineSymbol = nullptr;
1390  if ( gridSymbolElem.isNull() )
1391  {
1392  //old project file, read penWidth /penColorRed, penColorGreen, penColorBlue
1393  lineSymbol = QgsLineSymbol::createSimple( QgsStringMap() );
1394  lineSymbol->setWidth( gridElem.attribute( QStringLiteral( "penWidth" ), QStringLiteral( "0" ) ).toDouble() );
1395  lineSymbol->setColor( QColor( gridElem.attribute( QStringLiteral( "penColorRed" ), QStringLiteral( "0" ) ).toInt(),
1396  gridElem.attribute( QStringLiteral( "penColorGreen" ), QStringLiteral( "0" ) ).toInt(),
1397  gridElem.attribute( QStringLiteral( "penColorBlue" ), QStringLiteral( "0" ) ).toInt() ) );
1398  }
1399  else
1400  {
1401  lineSymbol = QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( gridSymbolElem, context );
1402  }
1403  mapGrid->setLineSymbol( lineSymbol );
1404 
1405  //annotation
1406  QDomNodeList annotationNodeList = gridElem.elementsByTagName( QStringLiteral( "Annotation" ) );
1407  if ( !annotationNodeList.isEmpty() )
1408  {
1409  QDomElement annotationElem = annotationNodeList.at( 0 ).toElement();
1410  mapGrid->setAnnotationEnabled( annotationElem.attribute( QStringLiteral( "show" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
1411  mapGrid->setAnnotationFormat( QgsComposerMapGrid::AnnotationFormat( annotationElem.attribute( QStringLiteral( "format" ), QStringLiteral( "0" ) ).toInt() ) );
1412  mapGrid->setAnnotationPosition( QgsComposerMapGrid::AnnotationPosition( annotationElem.attribute( QStringLiteral( "leftPosition" ), QStringLiteral( "0" ) ).toInt() ), QgsComposerMapGrid::Left );
1413  mapGrid->setAnnotationPosition( QgsComposerMapGrid::AnnotationPosition( annotationElem.attribute( QStringLiteral( "rightPosition" ), QStringLiteral( "0" ) ).toInt() ), QgsComposerMapGrid::Right );
1414  mapGrid->setAnnotationPosition( QgsComposerMapGrid::AnnotationPosition( annotationElem.attribute( QStringLiteral( "topPosition" ), QStringLiteral( "0" ) ).toInt() ), QgsComposerMapGrid::Top );
1415  mapGrid->setAnnotationPosition( QgsComposerMapGrid::AnnotationPosition( annotationElem.attribute( QStringLiteral( "bottomPosition" ), QStringLiteral( "0" ) ).toInt() ), QgsComposerMapGrid::Bottom );
1416  mapGrid->setAnnotationDirection( QgsComposerMapGrid::AnnotationDirection( annotationElem.attribute( QStringLiteral( "leftDirection" ), QStringLiteral( "0" ) ).toInt() ), QgsComposerMapGrid::Left );
1417  mapGrid->setAnnotationDirection( QgsComposerMapGrid::AnnotationDirection( annotationElem.attribute( QStringLiteral( "rightDirection" ), QStringLiteral( "0" ) ).toInt() ), QgsComposerMapGrid::Right );
1418  mapGrid->setAnnotationDirection( QgsComposerMapGrid::AnnotationDirection( annotationElem.attribute( QStringLiteral( "topDirection" ), QStringLiteral( "0" ) ).toInt() ), QgsComposerMapGrid::Top );
1419  mapGrid->setAnnotationDirection( QgsComposerMapGrid::AnnotationDirection( annotationElem.attribute( QStringLiteral( "bottomDirection" ), QStringLiteral( "0" ) ).toInt() ), QgsComposerMapGrid::Bottom );
1420  mapGrid->setAnnotationFrameDistance( annotationElem.attribute( QStringLiteral( "frameDistance" ), QStringLiteral( "0" ) ).toDouble() );
1421  QFont annotationFont;
1422  annotationFont.fromString( annotationElem.attribute( QStringLiteral( "font" ), QLatin1String( "" ) ) );
1423  mapGrid->setAnnotationFont( annotationFont );
1424  mapGrid->setAnnotationFontColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "fontColor" ), QStringLiteral( "0,0,0,255" ) ) ) );
1425 
1426  mapGrid->setAnnotationPrecision( annotationElem.attribute( QStringLiteral( "precision" ), QStringLiteral( "3" ) ).toInt() );
1427  }
1428  mGridStack->addGrid( mapGrid );
1429  }
1430 
1431  //load overview in old xml format
1432  QDomElement overviewFrameElem = itemElem.firstChildElement( QStringLiteral( "overviewFrame" ) );
1433  if ( !overviewFrameElem.isNull() )
1434  {
1435  QgsComposerMapOverview *mapOverview = new QgsComposerMapOverview( tr( "Overview %1" ).arg( mOverviewStack->size() + 1 ), this );
1436 
1437  mapOverview->setFrameMap( overviewFrameElem.attribute( QStringLiteral( "overviewFrameMap" ), QStringLiteral( "-1" ) ).toInt() );
1438  mapOverview->setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( overviewFrameElem.attribute( QStringLiteral( "overviewBlendMode" ), QStringLiteral( "0" ) ).toUInt() ) ) );
1439  mapOverview->setInverted( overviewFrameElem.attribute( QStringLiteral( "overviewInverted" ) ).compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 );
1440  mapOverview->setCentered( overviewFrameElem.attribute( QStringLiteral( "overviewCentered" ) ).compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 );
1441 
1442  QgsFillSymbol *fillSymbol = nullptr;
1443  QDomElement overviewFrameSymbolElem = overviewFrameElem.firstChildElement( QStringLiteral( "symbol" ) );
1444  if ( !overviewFrameSymbolElem.isNull() )
1445  {
1446  fillSymbol = QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( overviewFrameSymbolElem, context );
1447  mapOverview->setFrameSymbol( fillSymbol );
1448  }
1449  mOverviewStack->addOverview( mapOverview );
1450  }
1451 
1452  //atlas
1453  QDomNodeList atlasNodeList = itemElem.elementsByTagName( QStringLiteral( "AtlasMap" ) );
1454  if ( !atlasNodeList.isEmpty() )
1455  {
1456  QDomElement atlasElem = atlasNodeList.at( 0 ).toElement();
1457  mAtlasDriven = ( atlasElem.attribute( QStringLiteral( "atlasDriven" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
1458  if ( atlasElem.hasAttribute( QStringLiteral( "fixedScale" ) ) ) // deprecated XML
1459  {
1460  mAtlasScalingMode = ( atlasElem.attribute( QStringLiteral( "fixedScale" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) ) ? Fixed : Auto;
1461  }
1462  else if ( atlasElem.hasAttribute( QStringLiteral( "scalingMode" ) ) )
1463  {
1464  mAtlasScalingMode = static_cast<AtlasScalingMode>( atlasElem.attribute( QStringLiteral( "scalingMode" ) ).toInt() );
1465  }
1466  mAtlasMargin = atlasElem.attribute( QStringLiteral( "margin" ), QStringLiteral( "0.1" ) ).toDouble();
1467  }
1468 
1469  //restore general composer item properties
1470  QDomNodeList composerItemList = itemElem.elementsByTagName( QStringLiteral( "ComposerItem" ) );
1471  if ( !composerItemList.isEmpty() )
1472  {
1473  QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
1474 
1475  if ( !qgsDoubleNear( composerItemElem.attribute( QStringLiteral( "rotation" ), QStringLiteral( "0" ) ).toDouble(), 0.0 ) )
1476  {
1477  //in versions prior to 2.1 map rotation was stored in the rotation attribute
1478  mMapRotation = composerItemElem.attribute( QStringLiteral( "rotation" ), QStringLiteral( "0" ) ).toDouble();
1479  }
1480 
1481  _readXml( composerItemElem, doc );
1482  }
1483 
1485  setUpdatesEnabled( true );
1486 
1487  emit itemChanged();
1488  return true;
1489 }
1490 
1491 QList<QgsMapLayer *> QgsComposerMap::layers() const
1492 {
1493  return _qgis_listRefToRaw( mLayers );
1494 }
1495 
1496 void QgsComposerMap::setLayers( const QList<QgsMapLayer *> &layers )
1497 {
1498  mLayers = _qgis_listRawToRef( layers );
1499 }
1500 
1501 
1502 void QgsComposerMap::setLayerStyleOverrides( const QMap<QString, QString> &overrides )
1503 {
1504  if ( overrides == mLayerStyleOverrides )
1505  return;
1506 
1507  mLayerStyleOverrides = overrides;
1508  emit layerStyleOverridesChanged(); // associated legends may listen to this
1509 }
1510 
1511 
1513 {
1514  mLayerStyleOverrides.clear();
1515  Q_FOREACH ( const QgsMapLayerRef &layerRef, mLayers )
1516  {
1517  if ( QgsMapLayer *layer = layerRef.get() )
1518  {
1519  QgsMapLayerStyle style;
1520  style.readFromLayer( layer );
1521  mLayerStyleOverrides.insert( layer->id(), style.xmlData() );
1522  }
1523  }
1524 }
1525 
1526 void QgsComposerMap::layersAboutToBeRemoved( QList< QgsMapLayer * > layers )
1527 {
1528  if ( !mLayers.isEmpty() || mLayerStyleOverrides.isEmpty() )
1529  {
1530  Q_FOREACH ( QgsMapLayer *layer, layers )
1531  {
1532  mLayerStyleOverrides.remove( layer->id() );
1533  }
1534  _qgis_removeLayers( mLayers, layers );
1535  }
1536 }
1537 
1539 {
1540  if ( mGridStack->size() < 1 )
1541  {
1542  QgsComposerMapGrid *grid = new QgsComposerMapGrid( tr( "Grid %1" ).arg( 1 ), this );
1543  mGridStack->addGrid( grid );
1544  }
1545  return mGridStack->grid( 0 );
1546 }
1547 
1548 const QgsComposerMapGrid *QgsComposerMap::constFirstMapGrid() const
1549 {
1550  return const_cast<QgsComposerMap *>( this )->grid();
1551 }
1552 
1554 {
1555  if ( mOverviewStack->size() < 1 )
1556  {
1557  QgsComposerMapOverview *overview = new QgsComposerMapOverview( tr( "Overview %1" ).arg( 1 ), this );
1558  mOverviewStack->addOverview( overview );
1559  }
1560  return mOverviewStack->overview( 0 );
1561 }
1562 
1563 const QgsComposerMapOverview *QgsComposerMap::constFirstMapOverview() const
1564 {
1565  return const_cast<QgsComposerMap *>( this )->overview();
1566 }
1567 
1569 {
1570  return mCurrentRectangle;
1571 }
1572 
1574 {
1575  QRectF rectangle = rect();
1576  double frameExtension = mFrame ? pen().widthF() / 2.0 : 0.0;
1577 
1578  double topExtension = 0.0;
1579  double rightExtension = 0.0;
1580  double bottomExtension = 0.0;
1581  double leftExtension = 0.0;
1582 
1583  if ( mGridStack )
1584  mGridStack->calculateMaxGridExtension( topExtension, rightExtension, bottomExtension, leftExtension );
1585 
1586  topExtension = qMax( topExtension, frameExtension );
1587  rightExtension = qMax( rightExtension, frameExtension );
1588  bottomExtension = qMax( bottomExtension, frameExtension );
1589  leftExtension = qMax( leftExtension, frameExtension );
1590 
1591  rectangle.setLeft( rectangle.left() - leftExtension );
1592  rectangle.setRight( rectangle.right() + rightExtension );
1593  rectangle.setTop( rectangle.top() - topExtension );
1594  rectangle.setBottom( rectangle.bottom() + bottomExtension );
1595  if ( rectangle != mCurrentRectangle )
1596  {
1597  prepareGeometryChange();
1598  mCurrentRectangle = rectangle;
1599  }
1600 }
1601 
1602 void QgsComposerMap::setFrameStrokeWidth( const double strokeWidth )
1603 {
1604  QgsComposerItem::setFrameStrokeWidth( strokeWidth );
1606 }
1607 
1608 QgsRectangle QgsComposerMap::transformedExtent() const
1609 {
1610  double dx = mXOffset;
1611  double dy = mYOffset;
1612  transformShift( dx, dy );
1613  return QgsRectangle( currentMapExtent()->xMinimum() - dx, currentMapExtent()->yMinimum() - dy, currentMapExtent()->xMaximum() - dx, currentMapExtent()->yMaximum() - dy );
1614 }
1615 
1617 {
1618  double dx = mXOffset;
1619  double dy = mYOffset;
1620  //qWarning("offset");
1621  //qWarning(QString::number(dx).toLocal8Bit().data());
1622  //qWarning(QString::number(dy).toLocal8Bit().data());
1623  transformShift( dx, dy );
1624  //qWarning("transformed:");
1625  //qWarning(QString::number(dx).toLocal8Bit().data());
1626  //qWarning(QString::number(dy).toLocal8Bit().data());
1627  QPolygonF poly = visibleExtentPolygon();
1628  poly.translate( -dx, -dy );
1629  return poly;
1630 }
1631 
1632 void QgsComposerMap::mapPolygon( const QgsRectangle &extent, QPolygonF &poly ) const
1633 {
1634  poly.clear();
1635  if ( qgsDoubleNear( mEvaluatedMapRotation, 0.0 ) )
1636  {
1637  poly << QPointF( extent.xMinimum(), extent.yMaximum() );
1638  poly << QPointF( extent.xMaximum(), extent.yMaximum() );
1639  poly << QPointF( extent.xMaximum(), extent.yMinimum() );
1640  poly << QPointF( extent.xMinimum(), extent.yMinimum() );
1641  //ensure polygon is closed by readding first point
1642  poly << QPointF( poly.at( 0 ) );
1643  return;
1644  }
1645 
1646  //there is rotation
1647  QgsPointXY rotationPoint( ( extent.xMaximum() + extent.xMinimum() ) / 2.0, ( extent.yMaximum() + extent.yMinimum() ) / 2.0 );
1648  double dx, dy; //x-, y- shift from rotation point to corner point
1649 
1650  //top left point
1651  dx = rotationPoint.x() - extent.xMinimum();
1652  dy = rotationPoint.y() - extent.yMaximum();
1653  QgsComposerUtils::rotate( mEvaluatedMapRotation, dx, dy );
1654  poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
1655 
1656  //top right point
1657  dx = rotationPoint.x() - extent.xMaximum();
1658  dy = rotationPoint.y() - extent.yMaximum();
1659  QgsComposerUtils::rotate( mEvaluatedMapRotation, dx, dy );
1660  poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
1661 
1662  //bottom right point
1663  dx = rotationPoint.x() - extent.xMaximum();
1664  dy = rotationPoint.y() - extent.yMinimum();
1665  QgsComposerUtils::rotate( mEvaluatedMapRotation, dx, dy );
1666  poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
1667 
1668  //bottom left point
1669  dx = rotationPoint.x() - extent.xMinimum();
1670  dy = rotationPoint.y() - extent.yMinimum();
1671  QgsComposerUtils::rotate( mEvaluatedMapRotation, dx, dy );
1672  poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
1673 
1674  //ensure polygon is closed by readding first point
1675  poly << QPointF( poly.at( 0 ) );
1676 }
1677 
1679 {
1680  QPolygonF poly;
1681  mapPolygon( *currentMapExtent(), poly );
1682  return poly;
1683 }
1684 
1686 {
1687  if ( !QgsComposerItem::id().isEmpty() )
1688  {
1689  return QgsComposerItem::id();
1690  }
1691 
1692  return tr( "Map %1" ).arg( mId );
1693 }
1694 
1696 {
1697  QgsRectangle newExtent = *currentMapExtent();
1698  if ( qgsDoubleNear( mEvaluatedMapRotation, 0.0 ) )
1699  {
1700  extent = newExtent;
1701  }
1702  else
1703  {
1704  QPolygonF poly;
1705  mapPolygon( newExtent, poly );
1706  QRectF bRect = poly.boundingRect();
1707  extent.setXMinimum( bRect.left() );
1708  extent.setXMaximum( bRect.right() );
1709  extent.setYMinimum( bRect.top() );
1710  extent.setYMaximum( bRect.bottom() );
1711  }
1712 }
1713 
1715 {
1717 
1718  //Can't utilize QgsExpressionContextUtils::mapSettingsScope as we don't always
1719  //have a QgsMapSettings object available when the context is required, so we manually
1720  //add the same variables here
1721  QgsExpressionContextScope *scope = new QgsExpressionContextScope( tr( "Map Settings" ) );
1722 
1723  //use QgsComposerItem's id, not map item's ID, since that is user-definable
1724  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_id" ), QgsComposerItem::id(), true ) );
1725  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_rotation" ), mMapRotation, true ) );
1726  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_scale" ), scale(), true ) );
1727 
1729  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent" ), QVariant::fromValue( QgsGeometry::fromRect( extent ) ), true ) );
1730  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_width" ), extent.width(), true ) );
1731  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_height" ), extent.height(), true ) );
1732  QgsGeometry centerPoint = QgsGeometry::fromPoint( extent.center() );
1733  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_extent_center" ), QVariant::fromValue( centerPoint ), true ) );
1734 
1735  if ( mComposition )
1736  {
1737  QgsCoordinateReferenceSystem mapCrs = crs();
1738  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs" ), mapCrs.authid(), true ) );
1739  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_crs_definition" ), mapCrs.toProj4(), true ) );
1740  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "map_units" ), QgsUnitTypes::toString( mapCrs.mapUnits() ), true ) );
1741  }
1742 
1743  context.appendScope( scope );
1744 
1745  return context;
1746 }
1747 
1749 {
1750  double extentWidth = currentMapExtent()->width();
1751  if ( extentWidth <= 0 )
1752  {
1753  return 1;
1754  }
1755  return rect().width() / extentWidth;
1756 }
1757 
1759 {
1761  const QgsExpressionContext *evalContext = context ? context : &scopedContext;
1762 
1763  //updates data defined properties and redraws item to match
1764  if ( property == QgsComposerObject::MapRotation || property == QgsComposerObject::MapScale ||
1765  property == QgsComposerObject::MapXMin || property == QgsComposerObject::MapYMin ||
1766  property == QgsComposerObject::MapXMax || property == QgsComposerObject::MapYMax ||
1767  property == QgsComposerObject::MapAtlasMargin ||
1768  property == QgsComposerObject::AllProperties )
1769  {
1770  QgsRectangle beforeExtent = *currentMapExtent();
1771  refreshMapExtents( evalContext );
1772  emit itemChanged();
1773  if ( *currentMapExtent() != beforeExtent )
1774  {
1775  emit extentChanged();
1776  }
1777  }
1778 
1779  //force redraw
1780  mCacheInvalidated = true;
1781 
1782  QgsComposerItem::refreshDataDefinedProperty( property, evalContext );
1783 }
1784 
1785 void QgsComposerMap::transformShift( double &xShift, double &yShift ) const
1786 {
1787  double mmToMapUnits = 1.0 / mapUnitsToMM();
1788  double dxScaled = xShift * mmToMapUnits;
1789  double dyScaled = - yShift * mmToMapUnits;
1790 
1791  QgsComposerUtils::rotate( mEvaluatedMapRotation, dxScaled, dyScaled );
1792 
1793  xShift = dxScaled;
1794  yShift = dyScaled;
1795 }
1796 
1797 QPointF QgsComposerMap::mapToItemCoords( QPointF mapCoords ) const
1798 {
1799  QPolygonF mapPoly = transformedMapPolygon();
1800  if ( mapPoly.size() < 1 )
1801  {
1802  return QPointF( 0, 0 );
1803  }
1804 
1805  QgsRectangle tExtent = transformedExtent();
1806  QgsPointXY rotationPoint( ( tExtent.xMaximum() + tExtent.xMinimum() ) / 2.0, ( tExtent.yMaximum() + tExtent.yMinimum() ) / 2.0 );
1807  double dx = mapCoords.x() - rotationPoint.x();
1808  double dy = mapCoords.y() - rotationPoint.y();
1809  QgsComposerUtils::rotate( -mEvaluatedMapRotation, dx, dy );
1810  QgsPointXY backRotatedCoords( rotationPoint.x() + dx, rotationPoint.y() + dy );
1811 
1812  QgsRectangle unrotatedExtent = transformedExtent();
1813  double xItem = rect().width() * ( backRotatedCoords.x() - unrotatedExtent.xMinimum() ) / unrotatedExtent.width();
1814  double yItem = rect().height() * ( 1 - ( backRotatedCoords.y() - unrotatedExtent.yMinimum() ) / unrotatedExtent.height() );
1815  return QPointF( xItem, yItem );
1816 }
1817 
1818 void QgsComposerMap::drawAnnotations( QPainter *painter )
1819 {
1820  if ( !mComposition || !mComposition->project() || !mDrawAnnotations )
1821  {
1822  return;
1823  }
1824 
1825  QList< QgsAnnotation * > annotations = mComposition->project()->annotationManager()->annotations();
1826  if ( annotations.isEmpty() )
1827  return;
1828 
1830  rc.setForceVectorOutput( true );
1832  QList< QgsMapLayer * > layers = layersToRender( &rc.expressionContext() );
1833 
1834  Q_FOREACH ( QgsAnnotation *annotation, annotations )
1835  {
1836  if ( !annotation || !annotation->isVisible() )
1837  {
1838  continue;
1839  }
1840  if ( annotation->mapLayer() && !layers.contains( annotation->mapLayer() ) )
1841  continue;
1842 
1843  drawAnnotation( annotation, rc );
1844  }
1845 }
1846 
1847 void QgsComposerMap::drawAnnotation( const QgsAnnotation *annotation, QgsRenderContext &context )
1848 {
1849  if ( !annotation || !annotation->isVisible() || !context.painter() || !context.painter()->device() )
1850  {
1851  return;
1852  }
1853 
1854  context.painter()->save();
1855  context.painter()->setRenderHint( QPainter::Antialiasing, context.flags() & QgsRenderContext::Antialiasing );
1856 
1857  double itemX, itemY;
1858  if ( annotation->hasFixedMapPosition() )
1859  {
1860  QPointF mapPos = composerMapPosForItem( annotation );
1861  itemX = mapPos.x();
1862  itemY = mapPos.y();
1863  }
1864  else
1865  {
1866  itemX = annotation->relativePosition().x() * rect().width();
1867  itemY = annotation->relativePosition().y() * rect().height();
1868  }
1869  context.painter()->translate( itemX, itemY );
1870 
1871  //setup painter scaling to dots so that symbology is drawn to scale
1872  double dotsPerMM = context.painter()->device()->logicalDpiX() / 25.4;
1873  context.painter()->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
1874 
1875  annotation->render( context );
1876  context.painter()->restore();
1877 }
1878 
1879 QPointF QgsComposerMap::composerMapPosForItem( const QgsAnnotation *annotation ) const
1880 {
1881  if ( !annotation )
1882  return QPointF( 0, 0 );
1883 
1884  double mapX = 0.0;
1885  double mapY = 0.0;
1886 
1887  mapX = annotation->mapPosition().x();
1888  mapY = annotation->mapPosition().y();
1889  QgsCoordinateReferenceSystem annotationCrs = annotation->mapPositionCrs();
1890 
1891  if ( annotationCrs != crs() )
1892  {
1893  //need to reproject
1894  QgsCoordinateTransform t( annotationCrs, crs() );
1895  double z = 0.0;
1896  t.transformInPlace( mapX, mapY, z );
1897  }
1898 
1899  return mapToItemCoords( QPointF( mapX, mapY ) );
1900 }
1901 
1903 {
1904  if ( !mComposition )
1905  {
1906  return;
1907  }
1908 
1909  const QgsComposerMap *existingMap = mComposition->getComposerMapById( mId );
1910  if ( !existingMap )
1911  {
1912  return; //keep mId as it is still available
1913  }
1914 
1915  int maxId = -1;
1916  QList<const QgsComposerMap *> mapList = mComposition->composerMapItems();
1917  QList<const QgsComposerMap *>::const_iterator mapIt = mapList.constBegin();
1918  for ( ; mapIt != mapList.constEnd(); ++mapIt )
1919  {
1920  if ( ( *mapIt )->id() > maxId )
1921  {
1922  maxId = ( *mapIt )->id();
1923  }
1924  }
1925  mId = maxId + 1;
1926  updateToolTip();
1927 }
1928 
1930 {
1931  mAtlasDriven = enabled;
1932 
1933  if ( !enabled )
1934  {
1935  //if not enabling the atlas, we still need to refresh the map extents
1936  //so that data defined extents and scale are recalculated
1937  refreshMapExtents();
1938  }
1939 }
1940 
1942 {
1943  if ( valueType == QgsComposerObject::EvaluatedValue )
1944  {
1945  //evaluate data defined atlas margin
1946 
1947  //start with user specified margin
1948  double margin = mAtlasMargin;
1950 
1951  bool ok = false;
1952  double ddMargin = mDataDefinedProperties.valueAsDouble( QgsComposerObject::MapAtlasMargin, context, 0.0, &ok );
1953  if ( ok )
1954  {
1955  //divide by 100 to convert to 0 -> 1.0 range
1956  margin = ddMargin / 100;
1957  }
1958  return margin;
1959  }
1960  else
1961  {
1962  return mAtlasMargin;
1963  }
1964 }
1965 
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:1064
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.
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:340
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:203
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:86
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:1517
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:191
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:84
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:78
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.
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:422
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.