QGIS API Documentation  2.2.0-Valmiera
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 "qgscomposition.h"
20 #include "qgscoordinatetransform.h"
21 #include "qgslogger.h"
22 #include "qgsmaprenderer.h"
23 #include "qgsmaplayerregistry.h"
24 #include "qgsmaptopixel.h"
25 #include "qgsproject.h"
26 #include "qgsrasterlayer.h"
27 #include "qgsrendercontext.h"
28 #include "qgsscalecalculator.h"
29 #include "qgsvectorlayer.h"
30 #include "qgspallabeling.h"
31 #include "qgsexpression.h"
32 
33 #include "qgslabel.h"
34 #include "qgslabelattributes.h"
35 #include "qgssymbollayerv2utils.h" //for pointOnLineWithDistance
36 
37 #include <QGraphicsScene>
38 #include <QGraphicsView>
39 #include <QPainter>
40 #include <QSettings>
41 #include <cmath>
42 
43 QgsComposerMap::QgsComposerMap( QgsComposition *composition, int x, int y, int width, int height )
44  : QgsComposerItem( x, y, width, height, composition ), mMapRotation( 0 ), mKeepLayerSet( false ),
45  mOverviewFrameMapId( -1 ), mOverviewBlendMode( QPainter::CompositionMode_SourceOver ), mOverviewInverted( false ), mOverviewCentered( false ),
46  mGridEnabled( false ), mGridStyle( Solid ),
47  mGridIntervalX( 0.0 ), mGridIntervalY( 0.0 ), mGridOffsetX( 0.0 ), mGridOffsetY( 0.0 ), mGridAnnotationFontColor( QColor( 0, 0, 0 ) ),
48  mGridAnnotationPrecision( 3 ), mShowGridAnnotation( false ), mGridBlendMode( QPainter::CompositionMode_SourceOver ),
49  mLeftGridAnnotationPosition( OutsideMapFrame ), mRightGridAnnotationPosition( OutsideMapFrame ),
50  mTopGridAnnotationPosition( OutsideMapFrame ), mBottomGridAnnotationPosition( OutsideMapFrame ), mAnnotationFrameDistance( 1.0 ),
51  mLeftGridAnnotationDirection( Horizontal ), mRightGridAnnotationDirection( Horizontal ), mTopGridAnnotationDirection( Horizontal ),
52  mBottomGridAnnotationDirection( Horizontal ), mGridFrameStyle( NoGridFrame ), mGridFrameWidth( 2.0 ),
53  mGridFramePenThickness( 0.5 ), mGridFramePenColor( QColor( 0, 0, 0 ) ), mGridFrameFillColor1( Qt::white ), mGridFrameFillColor2( Qt::black ),
54  mCrossLength( 3 ), mMapCanvas( 0 ), mDrawCanvasItems( true ), mAtlasDriven( false ), mAtlasFixedScale( false ), mAtlasMargin( 0.10 )
55 {
58  mGridLineSymbol = 0;
61 
62  mId = 0;
63  assignFreeId();
64 
67  mCurrentRectangle = rect();
68 
69  // Cache
70  mCacheUpdated = false;
71  mDrawing = false;
72 
73  //Offset
74  mXOffset = 0.0;
75  mYOffset = 0.0;
76 
77  //get default composer font from settings
78  QSettings settings;
79  QString defaultFontString = settings.value( "/Composer/defaultFont" ).toString();
80  if ( !defaultFontString.isEmpty() )
81  {
82  mGridAnnotationFont.setFamily( defaultFontString );
83  }
84 
85  //get the color for map canvas background and set map background color accordingly
86  int bgRedInt = QgsProject::instance()->readNumEntry( "Gui", "/CanvasColorRedPart", 255 );
87  int bgGreenInt = QgsProject::instance()->readNumEntry( "Gui", "/CanvasColorGreenPart", 255 );
88  int bgBlueInt = QgsProject::instance()->readNumEntry( "Gui", "/CanvasColorBluePart", 255 );
89  mBackgroundColor = QColor( bgRedInt, bgGreenInt, bgBlueInt );
90 
92 
93  //calculate mExtent based on width/height ratio and map canvas extent
94  if ( mMapRenderer )
95  {
97  }
98  setSceneRect( QRectF( x, y, width, height ) );
99  setToolTip( tr( "Map %1" ).arg( mId ) );
100 
102 }
103 
105  : QgsComposerItem( 0, 0, 10, 10, composition ), mMapRotation( 0 ), mKeepLayerSet( false ), mOverviewFrameMapId( -1 ),
106  mOverviewBlendMode( QPainter::CompositionMode_SourceOver ), mOverviewInverted( false ), mOverviewCentered( false ),
107  mGridEnabled( false ), mGridStyle( Solid ),
108  mGridIntervalX( 0.0 ), mGridIntervalY( 0.0 ), mGridOffsetX( 0.0 ), mGridOffsetY( 0.0 ), mGridAnnotationFontColor( QColor( 0, 0, 0 ) ),
109  mGridAnnotationPrecision( 3 ), mShowGridAnnotation( false ), mGridBlendMode( QPainter::CompositionMode_SourceOver ),
110  mLeftGridAnnotationPosition( OutsideMapFrame ), mRightGridAnnotationPosition( OutsideMapFrame ),
111  mTopGridAnnotationPosition( OutsideMapFrame ), mBottomGridAnnotationPosition( OutsideMapFrame ), mAnnotationFrameDistance( 1.0 ),
112  mLeftGridAnnotationDirection( Horizontal ), mRightGridAnnotationDirection( Horizontal ), mTopGridAnnotationDirection( Horizontal ),
113  mBottomGridAnnotationDirection( Horizontal ), mGridFrameStyle( NoGridFrame ), mGridFrameWidth( 2.0 ), mGridFramePenThickness( 0.5 ),
114  mGridFramePenColor( QColor( 0, 0, 0 ) ), mGridFrameFillColor1( Qt::white ), mGridFrameFillColor2( Qt::black ),
115  mCrossLength( 3 ), mMapCanvas( 0 ), mDrawCanvasItems( true ), mAtlasDriven( false ), mAtlasFixedScale( false ), mAtlasMargin( 0.10 )
116 {
118  mGridLineSymbol = 0;
120 
121  //Offset
122  mXOffset = 0.0;
123  mYOffset = 0.0;
124 
126 
129  mId = mComposition->composerMapItems().size();
131  mCurrentRectangle = rect();
132 
133  setToolTip( tr( "Map %1" ).arg( mId ) );
134 
136 }
137 
138 void QgsComposerMap::adjustExtentToItemShape( double itemWidth, double itemHeight, QgsRectangle& extent ) const
139 {
140  double itemWidthHeightRatio = itemWidth / itemHeight;
141  double newWidthHeightRatio = extent.width() / extent.height();
142 
143  if ( itemWidthHeightRatio <= newWidthHeightRatio )
144  {
145  //enlarge height of new extent, ensuring the map center stays the same
146  double newHeight = extent.width() / itemWidthHeightRatio;
147  double deltaHeight = newHeight - extent.height();
148  extent.setYMinimum( extent.yMinimum() - deltaHeight / 2 );
149  extent.setYMaximum( extent.yMaximum() + deltaHeight / 2 );
150  }
151  else
152  {
153  //enlarge width of new extent, ensuring the map center stays the same
154  double newWidth = itemWidthHeightRatio * extent.height();
155  double deltaWidth = newWidth - extent.width();
156  extent.setXMinimum( extent.xMinimum() - deltaWidth / 2 );
157  extent.setXMaximum( extent.xMaximum() + deltaWidth / 2 );
158  }
159 }
160 
162 {
164  delete mGridLineSymbol;
165 }
166 
167 /* This function is called by paint() and cache() to render the map. It does not override any functions
168 from QGraphicsItem. */
169 void QgsComposerMap::draw( QPainter *painter, const QgsRectangle& extent, const QSizeF& size, double dpi, double* forceWidthScale )
170 {
171  if ( !painter )
172  {
173  return;
174  }
175 
176  if ( !mMapRenderer )
177  {
178  return;
179  }
180 
181  QgsMapRenderer theMapRenderer;
182  theMapRenderer.setExtent( extent );
183  theMapRenderer.setOutputSize( size, dpi );
184  if ( mMapRenderer->labelingEngine() )
185  theMapRenderer.setLabelingEngine( mMapRenderer->labelingEngine()->clone() );
186 
187  //set layers to render
188  theMapRenderer.setLayerSet( layersToRender() );
189 
190  theMapRenderer.setDestinationCrs( mMapRenderer->destinationCrs() );
192 
193  //set antialiasing if enabled in options
194  QSettings settings;
195  // Changed to enable anti aliased rendering by default as of QGIS 1.7
196  if ( settings.value( "/qgis/enable_anti_aliasing", true ).toBool() )
197  {
198  painter->setRenderHint( QPainter::Antialiasing );
199  }
200 
201  QgsRenderContext* theRendererContext = theMapRenderer.rendererContext();
202  if ( theRendererContext )
203  {
204  theRendererContext->setDrawEditingInformation( false );
205  theRendererContext->setRenderingStopped( false );
206 
209  {
210  //if outputing composer, disable optimisations like layer simplification
211  theRendererContext->setUseRenderingOptimization( false );
212  }
213 
214  // force vector output (no caching of marker images etc.)
215  theRendererContext->setForceVectorOutput( true );
216 
217  // make the renderer respect the composition's useAdvancedEffects flag
218  theRendererContext->setUseAdvancedEffects( mComposition->useAdvancedEffects() );
219  }
220 
221  //force composer map scale for scale dependent visibility
222  double bk_scale = theMapRenderer.scale();
223  theMapRenderer.setScale( scale() );
224 
225  //layer caching (as QImages) cannot be done for composer prints
226  QSettings s;
227  bool bkLayerCaching = s.value( "/qgis/enable_render_caching", false ).toBool();
228  s.setValue( "/qgis/enable_render_caching", false );
229 
230  //update $map variable. Use QgsComposerItem's id since that is user-definable
232 
233  if ( forceWidthScale ) //force wysiwyg line widths / marker sizes
234  {
235  theMapRenderer.render( painter, forceWidthScale );
236  }
237  else
238  {
239  theMapRenderer.render( painter );
240  }
241  s.setValue( "/qgis/enable_render_caching", bkLayerCaching );
242 
243  theMapRenderer.setScale( bk_scale );
244 }
245 
247 {
248  if ( mPreviewMode == Rectangle )
249  {
250  return;
251  }
252 
253  if ( mDrawing )
254  {
255  return;
256  }
257 
258  mDrawing = true;
259 
260  //in case of rotation, we need to request a larger rectangle and create a larger cache image
261  QgsRectangle requestExtent;
262  requestedExtent( requestExtent );
263 
264  double horizontalVScaleFactor = horizontalViewScaleFactor();
265  if ( horizontalVScaleFactor < 0 )
266  {
267  //make sure scale factor is positive
268  horizontalVScaleFactor = mLastValidViewScaleFactor > 0 ? mLastValidViewScaleFactor : 1;
269  }
270 
271  int w = requestExtent.width() * mapUnitsToMM() * horizontalVScaleFactor;
272  int h = requestExtent.height() * mapUnitsToMM() * horizontalVScaleFactor;
273 
274  if ( w > 5000 ) //limit size of image for better performance
275  {
276  w = 5000;
277  }
278 
279  if ( h > 5000 )
280  {
281  h = 5000;
282  }
283 
284  double forcedWidthScaleFactor = w / requestExtent.width() / mapUnitsToMM();
285 
286  mCacheImage = QImage( w, h, QImage::Format_ARGB32 );
287 
288  if ( hasBackground() )
289  {
290  //Initially fill image with specified background color. This ensures that layers with blend modes will
291  //preview correctly
292  mCacheImage.fill( backgroundColor().rgba() );
293  }
294  else
295  {
296  //no background, but start with empty fill to avoid artifacts
297  mCacheImage.fill( QColor( 255, 255, 255, 0 ).rgba() );
298  }
299 
300  double mapUnitsPerPixel = currentMapExtent()->width() / w;
301 
302  // WARNING: ymax in QgsMapToPixel is device height!!!
303  QgsMapToPixel transform( mapUnitsPerPixel, h, requestExtent.yMinimum(), requestExtent.xMinimum() );
304 
305  QPainter p( &mCacheImage );
306 
307  draw( &p, requestExtent, QSizeF( w, h ), mCacheImage.logicalDpiX(), &forcedWidthScaleFactor );
308  p.end();
309  mCacheUpdated = true;
310 
311  mDrawing = false;
312 }
313 
314 void QgsComposerMap::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
315 {
316  Q_UNUSED( pWidget );
317 
318  if ( !mComposition || !painter )
319  {
320  return;
321  }
322 
323  QRectF thisPaintRect = QRectF( 0, 0, QGraphicsRectItem::rect().width(), QGraphicsRectItem::rect().height() );
324  painter->save();
325  painter->setClipRect( thisPaintRect );
326 
328  {
329  // Fill with background color
330  drawBackground( painter );
331  QFont messageFont( "", 12 );
332  painter->setFont( messageFont );
333  painter->setPen( QColor( 0, 0, 0, 125 ) );
334  painter->drawText( thisPaintRect, tr( "Map will be printed here" ) );
335  }
337  {
338  //draw cached pixmap. This function does not call cache() any more because
339  //Qt 4.4.0 and 4.4.1 have problems with recursive paintings
340  //QgsComposerMap::cache() and QgsComposerMap::update() need to be called by
341  //client functions
342 
343  //Background color is already included in cached image, so no need to draw
344 
345  QgsRectangle requestRectangle;
346  requestedExtent( requestRectangle );
347 
348  QgsRectangle cExtent = *currentMapExtent();
349 
350  double imagePixelWidth = cExtent.width() / requestRectangle.width() * mCacheImage.width() ; //how many pixels of the image are for the map extent?
351  double scale = rect().width() / imagePixelWidth;
352  QgsPoint rotationPoint = QgsPoint(( cExtent.xMaximum() + cExtent.xMinimum() ) / 2.0, ( cExtent.yMaximum() + cExtent.yMinimum() ) / 2.0 );
353 
354  //shift such that rotation point is at 0/0 point in the coordinate system
355  double yShiftMM = ( requestRectangle.yMaximum() - rotationPoint.y() ) * mapUnitsToMM();
356  double xShiftMM = ( requestRectangle.xMinimum() - rotationPoint.x() ) * mapUnitsToMM();
357 
358  //shift such that top left point of the extent at point 0/0 in item coordinate system
359  double xTopLeftShift = ( rotationPoint.x() - cExtent.xMinimum() ) * mapUnitsToMM();
360  double yTopLeftShift = ( cExtent.yMaximum() - rotationPoint.y() ) * mapUnitsToMM();
361 
362  painter->save();
363 
364  painter->translate( mXOffset, mYOffset );
365  painter->translate( xTopLeftShift, yTopLeftShift );
366  painter->rotate( mMapRotation );
367  painter->translate( xShiftMM, -yShiftMM );
368  painter->scale( scale, scale );
369  painter->drawImage( 0, 0, mCacheImage );
370 
371  //restore rotation
372  painter->restore();
373 
374  //draw canvas items
375  drawCanvasItems( painter, itemStyle );
376  }
377  else if ( mComposition->plotStyle() == QgsComposition::Print ||
379  {
380  if ( mDrawing )
381  {
382  return;
383  }
384 
385  mDrawing = true;
386  QPaintDevice* thePaintDevice = painter->device();
387  if ( !thePaintDevice )
388  {
389  return;
390  }
391 
392  // Fill with background color
393  drawBackground( painter );
394 
395  QgsRectangle requestRectangle;
396  requestedExtent( requestRectangle );
397 
398  QgsRectangle cExtent = *currentMapExtent();
399 
400  QSizeF theSize( requestRectangle.width() * mapUnitsToMM(), requestRectangle.height() * mapUnitsToMM() );
401 
402  QgsPoint rotationPoint = QgsPoint(( cExtent.xMaximum() + cExtent.xMinimum() ) / 2.0, ( cExtent.yMaximum() + cExtent.yMinimum() ) / 2.0 );
403 
404  //shift such that rotation point is at 0/0 point in the coordinate system
405  double yShiftMM = ( requestRectangle.yMaximum() - rotationPoint.y() ) * mapUnitsToMM();
406  double xShiftMM = ( requestRectangle.xMinimum() - rotationPoint.x() ) * mapUnitsToMM();
407 
408  //shift such that top left point of the extent at point 0/0 in item coordinate system
409  double xTopLeftShift = ( rotationPoint.x() - cExtent.xMinimum() ) * mapUnitsToMM();
410  double yTopLeftShift = ( cExtent.yMaximum() - rotationPoint.y() ) * mapUnitsToMM();
411  painter->save();
412  painter->translate( mXOffset, mYOffset );
413  painter->translate( xTopLeftShift, yTopLeftShift );
414  painter->rotate( mMapRotation );
415  painter->translate( xShiftMM, -yShiftMM );
416  draw( painter, requestRectangle, theSize, 25.4 ); //scene coordinates seem to be in mm
417 
418  //restore rotation
419  painter->restore();
420 
421  //draw canvas items
422  drawCanvasItems( painter, itemStyle );
423 
424  mDrawing = false;
425  }
426 
427  painter->setClipRect( thisPaintRect , Qt::NoClip );
428 
429  if ( mGridEnabled )
430  {
431  drawGrid( painter );
432  }
433  if ( mOverviewFrameMapId != -1 )
434  {
435  drawOverviewMapExtent( painter );
436  }
437  drawFrame( painter );
438  if ( isSelected() )
439  {
440  drawSelectionBoxes( painter );
441  }
442 
443  painter->restore();
444 }
445 
447 {
448  syncLayerSet(); //layer list may have changed
449  mCacheUpdated = false;
450  cache();
451  QGraphicsRectItem::update();
452 }
453 
455 {
456  if ( mPreviewMode == Render )
457  {
459  }
460 }
461 
463 {
464  mCacheUpdated = u;
465 }
466 
468 {
469  //use stored layer set or read current set from main canvas
470  QStringList renderLayerSet;
471  if ( mKeepLayerSet )
472  {
473  renderLayerSet = mLayerSet;
474  }
475  else
476  {
477  renderLayerSet = mMapRenderer->layerSet();
478  }
479 
480  //remove atlas coverage layer if required
481  //TODO - move setting for hiding coverage layer to map item properties
483  {
485  {
486  //hiding coverage layer
487  int removeAt = renderLayerSet.indexOf( mComposition->atlasComposition().coverageLayer()->id() );
488  if ( removeAt != -1 )
489  {
490  renderLayerSet.removeAt( removeAt );
491  }
492  }
493  }
494 
495  return renderLayerSet;
496 }
497 
498 double QgsComposerMap::scale() const
499 {
500  QgsScaleCalculator calculator;
501  calculator.setMapUnits( mMapRenderer->mapUnits() );
502  calculator.setDpi( 25.4 ); //QGraphicsView units are mm
503  return calculator.calculate( *currentMapExtent(), rect().width() );
504 }
505 
506 void QgsComposerMap::resize( double dx, double dy )
507 {
508  //setRect
509  QRectF currentRect = rect();
510  QRectF newSceneRect = QRectF( pos().x(), pos().y(), currentRect.width() + dx, currentRect.height() + dy );
511  setSceneRect( newSceneRect );
512  updateItem();
513 }
514 
515 void QgsComposerMap::moveContent( double dx, double dy )
516 {
517  if ( !mDrawing )
518  {
519  transformShift( dx, dy );
520  currentMapExtent()->setXMinimum( currentMapExtent()->xMinimum() + dx );
521  currentMapExtent()->setXMaximum( currentMapExtent()->xMaximum() + dx );
522  currentMapExtent()->setYMinimum( currentMapExtent()->yMinimum() + dy );
523  currentMapExtent()->setYMaximum( currentMapExtent()->yMaximum() + dy );
524  cache();
525  update();
526  emit itemChanged();
527  emit extentChanged();
528  }
529 }
530 
531 void QgsComposerMap::zoomContent( int delta, double x, double y )
532 {
533  if ( mDrawing )
534  {
535  return;
536  }
537 
538  QSettings settings;
539 
540  //read zoom mode
541  //0: zoom, 1: zoom and recenter, 2: zoom to cursor, 3: nothing
542  int zoomMode = settings.value( "/qgis/wheel_action", 2 ).toInt();
543  if ( zoomMode == 3 ) //do nothing
544  {
545  return;
546  }
547 
548  double zoomFactor = settings.value( "/qgis/zoom_factor", 2.0 ).toDouble();
549 
550  //find out new center point
551  double centerX = ( currentMapExtent()->xMaximum() + currentMapExtent()->xMinimum() ) / 2;
552  double centerY = ( currentMapExtent()->yMaximum() + currentMapExtent()->yMinimum() ) / 2;
553 
554  if ( zoomMode != 0 )
555  {
556  //find out map coordinates of mouse position
557  double mapMouseX = currentMapExtent()->xMinimum() + ( x / rect().width() ) * ( currentMapExtent()->xMaximum() - currentMapExtent()->xMinimum() );
558  double mapMouseY = currentMapExtent()->yMinimum() + ( 1 - ( y / rect().height() ) ) * ( currentMapExtent()->yMaximum() - currentMapExtent()->yMinimum() );
559  if ( zoomMode == 1 ) //zoom and recenter
560  {
561  centerX = mapMouseX;
562  centerY = mapMouseY;
563  }
564  else if ( zoomMode == 2 ) //zoom to cursor
565  {
566  centerX = mapMouseX + ( centerX - mapMouseX ) * ( 1.0 / zoomFactor );
567  centerY = mapMouseY + ( centerY - mapMouseY ) * ( 1.0 / zoomFactor );
568  }
569  }
570 
571  double newIntervalX, newIntervalY;
572 
573  if ( delta > 0 )
574  {
575  newIntervalX = ( currentMapExtent()->xMaximum() - currentMapExtent()->xMinimum() ) / zoomFactor;
576  newIntervalY = ( currentMapExtent()->yMaximum() - currentMapExtent()->yMinimum() ) / zoomFactor;
577  }
578  else if ( delta < 0 )
579  {
580  newIntervalX = ( currentMapExtent()->xMaximum() - currentMapExtent()->xMinimum() ) * zoomFactor;
581  newIntervalY = ( currentMapExtent()->yMaximum() - currentMapExtent()->yMinimum() ) * zoomFactor;
582  }
583  else //no need to zoom
584  {
585  return;
586  }
587 
588  currentMapExtent()->setXMaximum( centerX + newIntervalX / 2 );
589  currentMapExtent()->setXMinimum( centerX - newIntervalX / 2 );
590  currentMapExtent()->setYMaximum( centerY + newIntervalY / 2 );
591  currentMapExtent()->setYMinimum( centerY - newIntervalY / 2 );
592 
593  cache();
594  update();
595  emit itemChanged();
596  emit extentChanged();
597 }
598 
599 void QgsComposerMap::setSceneRect( const QRectF& rectangle )
600 {
601  double w = rectangle.width();
602  double h = rectangle.height();
603  //prepareGeometryChange();
604 
605  QgsComposerItem::setSceneRect( rectangle );
606 
607  //QGraphicsRectItem::update();
608  double newHeight = mExtent.width() * h / w ;
610  mCacheUpdated = false;
611 
613  update();
614  emit itemChanged();
615  emit extentChanged();
616 }
617 
619 {
620  if ( mExtent == extent )
621  {
622  return;
623  }
624  mExtent = extent;
625 
626  //adjust height
627  QRectF currentRect = rect();
628 
629  double newHeight = currentRect.width() * extent.height() / extent.width();
630 
631  setSceneRect( QRectF( pos().x(), pos().y(), currentRect.width(), newHeight ) );
632  updateItem();
633 }
634 
636 {
637  if ( mAtlasFeatureExtent == extent )
638  {
639  return;
640  }
641 
642  //don't adjust size of item, instead adjust size of bounds to fit
643  QgsRectangle newExtent = extent;
644 
645  //Make sure the width/height ratio is the same as the map item size
646  double currentWidthHeightRatio = rect().width() / rect().height();
647  double newWidthHeightRatio = newExtent.width() / newExtent.height();
648 
649  if ( currentWidthHeightRatio < newWidthHeightRatio )
650  {
651  //enlarge height of new extent, ensuring the map center stays the same
652  double newHeight = newExtent.width() / currentWidthHeightRatio;
653  double deltaHeight = newHeight - newExtent.height();
654  newExtent.setYMinimum( extent.yMinimum() - deltaHeight / 2 );
655  newExtent.setYMaximum( extent.yMaximum() + deltaHeight / 2 );
656  }
657  else if ( currentWidthHeightRatio >= newWidthHeightRatio )
658  {
659  //enlarge width of new extent, ensuring the map center stays the same
660  double newWidth = currentWidthHeightRatio * newExtent.height();
661  double deltaWidth = newWidth - newExtent.width();
662  newExtent.setXMinimum( extent.xMinimum() - deltaWidth / 2 );
663  newExtent.setXMaximum( extent.xMaximum() + deltaWidth / 2 );
664  }
665 
666  mAtlasFeatureExtent = newExtent;
667  mCacheUpdated = false;
668  updateItem();
669  emit itemChanged();
670  emit extentChanged();
671 }
672 
674 {
675  //atlas preview has been toggled, so update item and extents
676  mCacheUpdated = false;
677  updateItem();
678  emit itemChanged();
679  emit extentChanged();
680 }
681 
683 {
684  //non-const version
686  {
687  //if atlas is enabled, and we are either exporting the composition or previewing the atlas, then
688  //return the current temporary atlas feature extent
689  return &mAtlasFeatureExtent;
690  }
691  else
692  {
693  //otherwise return permenant user set extent
694  return &mExtent;
695  }
696 }
697 
699 {
700  //const version
702  {
703  //if atlas is enabled, and we are either exporting the composition or previewing the atlas, then
704  //return the current temporary atlas feature extent
705  return &mAtlasFeatureExtent;
706  }
707  else
708  {
709  //otherwise return permenant user set extent
710  return &mExtent;
711  }
712 }
713 
714 void QgsComposerMap::setNewScale( double scaleDenominator )
715 {
716  double currentScaleDenominator = scale();
717 
718  if ( scaleDenominator == currentScaleDenominator )
719  {
720  return;
721  }
722 
723  double scaleRatio = scaleDenominator / currentScaleDenominator;
724  currentMapExtent()->scale( scaleRatio );
725  mCacheUpdated = false;
726  cache();
727  update();
728  emit itemChanged();
729  emit extentChanged();
730 }
731 
733 {
734  mPreviewMode = m;
735  emit itemChanged();
736 }
737 
738 void QgsComposerMap::setOffset( double xOffset, double yOffset )
739 {
740  mXOffset = xOffset;
741  mYOffset = yOffset;
742 }
743 
745 {
746  //kept for api compatibility with QGIS 2.0
747  setMapRotation( r );
748 }
749 
751 {
752  mMapRotation = r;
753  emit mapRotationChanged( r );
754  emit itemChanged();
755  update();
756 }
757 
759 {
761  {
762  cache();
763  }
765 }
766 
768 {
769  if ( !mMapRenderer )
770  {
771  return false;
772  }
773 
774  QStringList layers = mMapRenderer->layerSet();
775 
776  QStringList::const_iterator layer_it = layers.constBegin();
777  QgsMapLayer* currentLayer = 0;
778 
779  for ( ; layer_it != layers.constEnd(); ++layer_it )
780  {
781  currentLayer = QgsMapLayerRegistry::instance()->mapLayer( *layer_it );
782  if ( currentLayer )
783  {
784  QgsRasterLayer* currentRasterLayer = qobject_cast<QgsRasterLayer *>( currentLayer );
785  if ( currentRasterLayer )
786  {
787  const QgsRasterDataProvider* rasterProvider = 0;
788  if (( rasterProvider = currentRasterLayer->dataProvider() ) )
789  {
790  if ( rasterProvider->name() == "wms" )
791  {
792  return true;
793  }
794  }
795  }
796  }
797  }
798  return false;
799 }
800 
802 {
803  // check if map contains advanced effects like blend modes, or flattened layers for transparency
804  if ( !mMapRenderer )
805  {
806  return false;
807  }
808 
809  QStringList layers = mMapRenderer->layerSet();
810 
811  //Also need to check PAL labeling for blend modes
812  QgsPalLabeling* lbl = dynamic_cast<QgsPalLabeling*>( mMapRenderer->labelingEngine() );
813 
814  QStringList::const_iterator layer_it = layers.constBegin();
815  QgsMapLayer* currentLayer = 0;
816 
817  for ( ; layer_it != layers.constEnd(); ++layer_it )
818  {
819  currentLayer = QgsMapLayerRegistry::instance()->mapLayer( *layer_it );
820  if ( currentLayer )
821  {
822  if ( currentLayer->blendMode() != QPainter::CompositionMode_SourceOver )
823  {
824  return true;
825  }
826  // if vector layer, check labels and feature blend mode
827  QgsVectorLayer* currentVectorLayer = qobject_cast<QgsVectorLayer *>( currentLayer );
828  if ( currentVectorLayer )
829  {
830  if ( currentVectorLayer->layerTransparency() != 0 )
831  {
832  return true;
833  }
834  if ( currentVectorLayer->featureBlendMode() != QPainter::CompositionMode_SourceOver )
835  {
836  return true;
837  }
838  // check label blend modes
839  if ( lbl->willUseLayer( currentVectorLayer ) )
840  {
841  // Check all label blending properties
842  QgsPalLayerSettings& layerSettings = lbl->layer( currentVectorLayer->id() );
843  if (( layerSettings.blendMode != QPainter::CompositionMode_SourceOver ) ||
844  ( layerSettings.bufferSize != 0 && layerSettings.bufferBlendMode != QPainter::CompositionMode_SourceOver ) ||
845  ( layerSettings.shadowDraw && layerSettings.shadowBlendMode != QPainter::CompositionMode_SourceOver ) ||
846  ( layerSettings.shapeDraw && layerSettings.shapeBlendMode != QPainter::CompositionMode_SourceOver ) )
847  {
848  return true;
849  }
850  }
851  }
852  }
853  }
854 
855  return false;
856 }
857 
859 {
860  //connect signal from layer registry to update in case of new or deleted layers
862  if ( layerRegistry )
863  {
864  connect( layerRegistry, SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( updateCachedImage() ) );
865  connect( layerRegistry, SIGNAL( layerWasAdded( QgsMapLayer* ) ), this, SLOT( updateCachedImage() ) );
866  }
867 }
868 
869 bool QgsComposerMap::writeXML( QDomElement& elem, QDomDocument & doc ) const
870 {
871  if ( elem.isNull() )
872  {
873  return false;
874  }
875 
876  QDomElement composerMapElem = doc.createElement( "ComposerMap" );
877  composerMapElem.setAttribute( "id", mId );
878 
879  //previewMode
880  if ( mPreviewMode == Cache )
881  {
882  composerMapElem.setAttribute( "previewMode", "Cache" );
883  }
884  else if ( mPreviewMode == Render )
885  {
886  composerMapElem.setAttribute( "previewMode", "Render" );
887  }
888  else //rectangle
889  {
890  composerMapElem.setAttribute( "previewMode", "Rectangle" );
891  }
892 
893  if ( mKeepLayerSet )
894  {
895  composerMapElem.setAttribute( "keepLayerSet", "true" );
896  }
897  else
898  {
899  composerMapElem.setAttribute( "keepLayerSet", "false" );
900  }
901 
902  if ( mDrawCanvasItems )
903  {
904  composerMapElem.setAttribute( "drawCanvasItems", "true" );
905  }
906  else
907  {
908  composerMapElem.setAttribute( "drawCanvasItems", "false" );
909  }
910 
911  //overview map frame
912  QDomElement overviewFrameElem = doc.createElement( "overviewFrame" );
913  overviewFrameElem.setAttribute( "overviewFrameMap", mOverviewFrameMapId );
914  overviewFrameElem.setAttribute( "overviewBlendMode", QgsMapRenderer::getBlendModeEnum( mOverviewBlendMode ) );
915  if ( mOverviewInverted )
916  {
917  overviewFrameElem.setAttribute( "overviewInverted", "true" );
918  }
919  else
920  {
921  overviewFrameElem.setAttribute( "overviewInverted", "false" );
922  }
923 
924  overviewFrameElem.setAttribute( "overviewCentered", mOverviewCentered ? "true" : "false" );
925 
926  QDomElement overviewFrameStyleElem = QgsSymbolLayerV2Utils::saveSymbol( QString(), mOverviewFrameMapSymbol, doc );
927  overviewFrameElem.appendChild( overviewFrameStyleElem );
928  composerMapElem.appendChild( overviewFrameElem );
929 
930 
931  //extent
932  QDomElement extentElem = doc.createElement( "Extent" );
933  extentElem.setAttribute( "xmin", qgsDoubleToString( mExtent.xMinimum() ) );
934  extentElem.setAttribute( "xmax", qgsDoubleToString( mExtent.xMaximum() ) );
935  extentElem.setAttribute( "ymin", qgsDoubleToString( mExtent.yMinimum() ) );
936  extentElem.setAttribute( "ymax", qgsDoubleToString( mExtent.yMaximum() ) );
937  composerMapElem.appendChild( extentElem );
938 
939  //map rotation
940  composerMapElem.setAttribute( "mapRotation", QString::number( mMapRotation ) );
941 
942  //layer set
943  QDomElement layerSetElem = doc.createElement( "LayerSet" );
944  QStringList::const_iterator layerIt = mLayerSet.constBegin();
945  for ( ; layerIt != mLayerSet.constEnd(); ++layerIt )
946  {
947  QDomElement layerElem = doc.createElement( "Layer" );
948  QDomText layerIdText = doc.createTextNode( *layerIt );
949  layerElem.appendChild( layerIdText );
950  layerSetElem.appendChild( layerElem );
951  }
952  composerMapElem.appendChild( layerSetElem );
953 
954  //overview map frame
955  composerMapElem.setAttribute( "overviewFrameMap", mOverviewFrameMapId );
956 
957  //grid
958  QDomElement gridElem = doc.createElement( "Grid" );
959  gridElem.setAttribute( "show", mGridEnabled );
960  gridElem.setAttribute( "gridStyle", mGridStyle );
961  gridElem.setAttribute( "intervalX", qgsDoubleToString( mGridIntervalX ) );
962  gridElem.setAttribute( "intervalY", qgsDoubleToString( mGridIntervalY ) );
963  gridElem.setAttribute( "offsetX", qgsDoubleToString( mGridOffsetX ) );
964  gridElem.setAttribute( "offsetY", qgsDoubleToString( mGridOffsetY ) );
965  gridElem.setAttribute( "crossLength", qgsDoubleToString( mCrossLength ) );
966  gridElem.setAttribute( "gridFrameStyle", mGridFrameStyle );
967  gridElem.setAttribute( "gridFrameWidth", qgsDoubleToString( mGridFrameWidth ) );
968  gridElem.setAttribute( "gridFramePenThickness", qgsDoubleToString( mGridFramePenThickness ) );
969  //grid frame pen color
970  QDomElement framePenColorElem = doc.createElement( "framePenColor" );
971  framePenColorElem.setAttribute( "red", mGridFramePenColor.red() );
972  framePenColorElem.setAttribute( "green", mGridFramePenColor.green() );
973  framePenColorElem.setAttribute( "blue", mGridFramePenColor.blue() );
974  framePenColorElem.setAttribute( "alpha", mGridFramePenColor.alpha() );
975  gridElem.appendChild( framePenColorElem );
976  //grid frame fill colors
977  QDomElement frameFillColor1Elem = doc.createElement( "frameFillColor1" );
978  frameFillColor1Elem.setAttribute( "red", mGridFrameFillColor1.red() );
979  frameFillColor1Elem.setAttribute( "green", mGridFrameFillColor1.green() );
980  frameFillColor1Elem.setAttribute( "blue", mGridFrameFillColor1.blue() );
981  frameFillColor1Elem.setAttribute( "alpha", mGridFrameFillColor1.alpha() );
982  gridElem.appendChild( frameFillColor1Elem );
983  QDomElement frameFillColor2Elem = doc.createElement( "frameFillColor2" );
984  frameFillColor2Elem.setAttribute( "red", mGridFrameFillColor2.red() );
985  frameFillColor2Elem.setAttribute( "green", mGridFrameFillColor2.green() );
986  frameFillColor2Elem.setAttribute( "blue", mGridFrameFillColor2.blue() );
987  frameFillColor2Elem.setAttribute( "alpha", mGridFrameFillColor2.alpha() );
988  gridElem.appendChild( frameFillColor2Elem );
989 
990  gridElem.setAttribute( "gridBlendMode", QgsMapRenderer::getBlendModeEnum( mGridBlendMode ) );
991  QDomElement gridLineStyleElem = QgsSymbolLayerV2Utils::saveSymbol( QString(), mGridLineSymbol, doc );
992  gridElem.appendChild( gridLineStyleElem );
993 
994  //grid annotation
995  QDomElement annotationElem = doc.createElement( "Annotation" );
996  annotationElem.setAttribute( "format", mGridAnnotationFormat );
997  annotationElem.setAttribute( "show", mShowGridAnnotation );
998  annotationElem.setAttribute( "leftPosition", mLeftGridAnnotationPosition );
999  annotationElem.setAttribute( "rightPosition", mRightGridAnnotationPosition );
1000  annotationElem.setAttribute( "topPosition", mTopGridAnnotationPosition );
1001  annotationElem.setAttribute( "bottomPosition", mBottomGridAnnotationPosition );
1002  annotationElem.setAttribute( "leftDirection", mLeftGridAnnotationDirection );
1003  annotationElem.setAttribute( "rightDirection", mRightGridAnnotationDirection );
1004  annotationElem.setAttribute( "topDirection", mTopGridAnnotationDirection );
1005  annotationElem.setAttribute( "bottomDirection", mBottomGridAnnotationDirection );
1006  annotationElem.setAttribute( "frameDistance", QString::number( mAnnotationFrameDistance ) );
1007  annotationElem.setAttribute( "font", mGridAnnotationFont.toString() );
1008  annotationElem.setAttribute( "precision", mGridAnnotationPrecision );
1009  //annotation font color
1010  QDomElement annotationFontColorElem = doc.createElement( "fontColor" );
1011  annotationFontColorElem.setAttribute( "red", mGridAnnotationFontColor.red() );
1012  annotationFontColorElem.setAttribute( "green", mGridAnnotationFontColor.green() );
1013  annotationFontColorElem.setAttribute( "blue", mGridAnnotationFontColor.blue() );
1014  annotationFontColorElem.setAttribute( "alpha", mGridAnnotationFontColor.alpha() );
1015  annotationElem.appendChild( annotationFontColorElem );
1016 
1017  gridElem.appendChild( annotationElem );
1018  composerMapElem.appendChild( gridElem );
1019 
1020  //atlas
1021  QDomElement atlasElem = doc.createElement( "AtlasMap" );
1022  atlasElem.setAttribute( "atlasDriven", mAtlasDriven );
1023  atlasElem.setAttribute( "fixedScale", mAtlasFixedScale );
1024  atlasElem.setAttribute( "margin", qgsDoubleToString( mAtlasMargin ) );
1025  composerMapElem.appendChild( atlasElem );
1026 
1027  elem.appendChild( composerMapElem );
1028  return _writeXML( composerMapElem, doc );
1029 }
1030 
1031 bool QgsComposerMap::readXML( const QDomElement& itemElem, const QDomDocument& doc )
1032 {
1033  if ( itemElem.isNull() )
1034  {
1035  return false;
1036  }
1037 
1038  QString idRead = itemElem.attribute( "id", "not found" );
1039  if ( idRead != "not found" )
1040  {
1041  mId = idRead.toInt();
1042  }
1044 
1045  //previewMode
1046  QString previewMode = itemElem.attribute( "previewMode" );
1047  if ( previewMode == "Cache" )
1048  {
1049  mPreviewMode = Cache;
1050  }
1051  else if ( previewMode == "Render" )
1052  {
1053  mPreviewMode = Render;
1054  }
1055  else
1056  {
1058  }
1059 
1060  QDomElement overviewFrameElem = itemElem.firstChildElement( "overviewFrame" );
1061  if ( !overviewFrameElem.isNull() )
1062  {
1063  setOverviewFrameMap( overviewFrameElem.attribute( "overviewFrameMap", "-1" ).toInt() );
1064  setOverviewBlendMode( QgsMapRenderer::getCompositionMode(( QgsMapRenderer::BlendMode ) overviewFrameElem.attribute( "overviewBlendMode", "0" ).toUInt() ) );
1065 
1066  QString overviewInvertedFlag = overviewFrameElem.attribute( "overviewInverted" );
1067  if ( overviewInvertedFlag.compare( "true", Qt::CaseInsensitive ) == 0 )
1068  {
1069  setOverviewInverted( true );
1070  }
1071  else
1072  {
1073  setOverviewInverted( false );
1074  }
1075 
1076  if ( overviewFrameElem.attribute( "overviewCentered" ).compare( "true", Qt::CaseInsensitive ) == 0 )
1077  {
1078  mOverviewCentered = true;
1079  }
1080  else
1081  {
1082  mOverviewCentered = false;
1083  }
1084 
1085  QDomElement overviewFrameSymbolElem = overviewFrameElem.firstChildElement( "symbol" );
1086  if ( !overviewFrameSymbolElem.isNull() )
1087  {
1088  delete mOverviewFrameMapSymbol;
1089  mOverviewFrameMapSymbol = dynamic_cast<QgsFillSymbolV2*>( QgsSymbolLayerV2Utils::loadSymbol( overviewFrameSymbolElem ) );
1090  }
1091  }
1092 
1093  //extent
1094  QDomNodeList extentNodeList = itemElem.elementsByTagName( "Extent" );
1095  if ( extentNodeList.size() > 0 )
1096  {
1097  QDomElement extentElem = extentNodeList.at( 0 ).toElement();
1098  double xmin, xmax, ymin, ymax;
1099  xmin = extentElem.attribute( "xmin" ).toDouble();
1100  xmax = extentElem.attribute( "xmax" ).toDouble();
1101  ymin = extentElem.attribute( "ymin" ).toDouble();
1102  ymax = extentElem.attribute( "ymax" ).toDouble();
1103 
1104  mExtent = QgsRectangle( xmin, ymin, xmax, ymax );
1105  }
1106 
1107  //map rotation
1108  if ( itemElem.attribute( "mapRotation", "0" ).toDouble() != 0 )
1109  {
1110  mMapRotation = itemElem.attribute( "mapRotation", "0" ).toDouble();
1111  }
1112 
1113  //mKeepLayerSet flag
1114  QString keepLayerSetFlag = itemElem.attribute( "keepLayerSet" );
1115  if ( keepLayerSetFlag.compare( "true", Qt::CaseInsensitive ) == 0 )
1116  {
1117  mKeepLayerSet = true;
1118  }
1119  else
1120  {
1121  mKeepLayerSet = false;
1122  }
1123 
1124  QString drawCanvasItemsFlag = itemElem.attribute( "drawCanvasItems" );
1125  if ( drawCanvasItemsFlag.compare( "true", Qt::CaseInsensitive ) == 0 )
1126  {
1127  mDrawCanvasItems = true;
1128  }
1129  else
1130  {
1131  mDrawCanvasItems = false;
1132  }
1133 
1134  //mLayerSet
1135  QDomNodeList layerSetNodeList = itemElem.elementsByTagName( "LayerSet" );
1136  QStringList layerSet;
1137  if ( layerSetNodeList.size() > 0 )
1138  {
1139  QDomElement layerSetElem = layerSetNodeList.at( 0 ).toElement();
1140  QDomNodeList layerIdNodeList = layerSetElem.elementsByTagName( "Layer" );
1141  for ( int i = 0; i < layerIdNodeList.size(); ++i )
1142  {
1143  layerSet << layerIdNodeList.at( i ).toElement().text();
1144  }
1145  }
1146  mLayerSet = layerSet;
1147 
1148  mDrawing = false;
1149  mNumCachedLayers = 0;
1150  mCacheUpdated = false;
1151 
1152  //grid
1153  QDomNodeList gridNodeList = itemElem.elementsByTagName( "Grid" );
1154  if ( gridNodeList.size() > 0 )
1155  {
1156  QDomElement gridElem = gridNodeList.at( 0 ).toElement();
1157  mGridEnabled = ( gridElem.attribute( "show", "0" ) != "0" );
1158  mGridStyle = QgsComposerMap::GridStyle( gridElem.attribute( "gridStyle", "0" ).toInt() );
1159  mGridIntervalX = gridElem.attribute( "intervalX", "0" ).toDouble();
1160  mGridIntervalY = gridElem.attribute( "intervalY", "0" ).toDouble();
1161  mGridOffsetX = gridElem.attribute( "offsetX", "0" ).toDouble();
1162  mGridOffsetY = gridElem.attribute( "offsetY", "0" ).toDouble();
1163  mCrossLength = gridElem.attribute( "crossLength", "3" ).toDouble();
1164  mGridFrameStyle = ( QgsComposerMap::GridFrameStyle )gridElem.attribute( "gridFrameStyle", "0" ).toInt();
1165  mGridFrameWidth = gridElem.attribute( "gridFrameWidth", "2.0" ).toDouble();
1166  mGridFramePenThickness = gridElem.attribute( "gridFramePenThickness", "0.5" ).toDouble();
1167 
1168  //grid frame pen color
1169  QDomNodeList gridFramePenColorList = gridElem.elementsByTagName( "framePenColor" );
1170  if ( gridFramePenColorList.size() > 0 )
1171  {
1172  QDomElement penColorElem = gridFramePenColorList.at( 0 ).toElement();
1173  int red = penColorElem.attribute( "red", "0" ).toInt();
1174  int green = penColorElem.attribute( "green", "0" ).toInt();
1175  int blue = penColorElem.attribute( "blue", "0" ).toInt();
1176  int alpha = penColorElem.attribute( "alpha", "255" ).toInt();
1177  mGridFramePenColor = QColor( red, green, blue, alpha );
1178  }
1179  else
1180  {
1181  mGridFramePenColor = QColor( 0, 0, 0 );
1182  }
1183  //grid frame fill color 1
1184  QDomNodeList gridFrameFillColor1List = gridElem.elementsByTagName( "frameFillColor1" );
1185  if ( gridFrameFillColor1List.size() > 0 )
1186  {
1187  QDomElement fillColorElem = gridFrameFillColor1List.at( 0 ).toElement();
1188  int red = fillColorElem.attribute( "red", "0" ).toInt();
1189  int green = fillColorElem.attribute( "green", "0" ).toInt();
1190  int blue = fillColorElem.attribute( "blue", "0" ).toInt();
1191  int alpha = fillColorElem.attribute( "alpha", "255" ).toInt();
1192  mGridFrameFillColor1 = QColor( red, green, blue, alpha );
1193  }
1194  else
1195  {
1196  mGridFrameFillColor1 = Qt::white;
1197  }
1198  //grid frame fill color 2
1199  QDomNodeList gridFrameFillColor2List = gridElem.elementsByTagName( "frameFillColor2" );
1200  if ( gridFrameFillColor2List.size() > 0 )
1201  {
1202  QDomElement fillColorElem = gridFrameFillColor2List.at( 0 ).toElement();
1203  int red = fillColorElem.attribute( "red", "0" ).toInt();
1204  int green = fillColorElem.attribute( "green", "0" ).toInt();
1205  int blue = fillColorElem.attribute( "blue", "0" ).toInt();
1206  int alpha = fillColorElem.attribute( "alpha", "255" ).toInt();
1207  mGridFrameFillColor2 = QColor( red, green, blue, alpha );
1208  }
1209  else
1210  {
1211  mGridFrameFillColor2 = Qt::black;
1212  }
1213 
1214  setGridBlendMode( QgsMapRenderer::getCompositionMode(( QgsMapRenderer::BlendMode ) gridElem.attribute( "gridBlendMode", "0" ).toUInt() ) );
1215 
1216  QDomElement gridSymbolElem = gridElem.firstChildElement( "symbol" );
1217  delete mGridLineSymbol;
1218  if ( gridSymbolElem.isNull( ) )
1219  {
1220  //old project file, read penWidth /penColorRed, penColorGreen, penColorBlue
1222  mGridLineSymbol->setWidth( gridElem.attribute( "penWidth", "0" ).toDouble() );
1223  mGridLineSymbol->setColor( QColor( gridElem.attribute( "penColorRed", "0" ).toInt(),
1224  gridElem.attribute( "penColorGreen", "0" ).toInt(),
1225  gridElem.attribute( "penColorBlue", "0" ).toInt() ) );
1226  }
1227  else
1228  {
1229  mGridLineSymbol = dynamic_cast<QgsLineSymbolV2*>( QgsSymbolLayerV2Utils::loadSymbol( gridSymbolElem ) );
1230  }
1231 
1232  QDomNodeList annotationNodeList = gridElem.elementsByTagName( "Annotation" );
1233  if ( annotationNodeList.size() > 0 )
1234  {
1235  QDomElement annotationElem = annotationNodeList.at( 0 ).toElement();
1236  mShowGridAnnotation = ( annotationElem.attribute( "show", "0" ) != "0" );
1237  mGridAnnotationFormat = QgsComposerMap::GridAnnotationFormat( annotationElem.attribute( "format", "0" ).toInt() );
1238  mLeftGridAnnotationPosition = QgsComposerMap::GridAnnotationPosition( annotationElem.attribute( "leftPosition", "0" ).toInt() );
1239  mRightGridAnnotationPosition = QgsComposerMap::GridAnnotationPosition( annotationElem.attribute( "rightPosition", "0" ).toInt() );
1240  mTopGridAnnotationPosition = QgsComposerMap::GridAnnotationPosition( annotationElem.attribute( "topPosition", "0" ).toInt() );
1241  mBottomGridAnnotationPosition = QgsComposerMap::GridAnnotationPosition( annotationElem.attribute( "bottomPosition", "0" ).toInt() );
1242  mLeftGridAnnotationDirection = QgsComposerMap::GridAnnotationDirection( annotationElem.attribute( "leftDirection", "0" ).toInt() );
1243  mRightGridAnnotationDirection = QgsComposerMap::GridAnnotationDirection( annotationElem.attribute( "rightDirection", "0" ).toInt() );
1244  mTopGridAnnotationDirection = QgsComposerMap::GridAnnotationDirection( annotationElem.attribute( "topDirection", "0" ).toInt() );
1245  mBottomGridAnnotationDirection = QgsComposerMap::GridAnnotationDirection( annotationElem.attribute( "bottomDirection", "0" ).toInt() );
1246  mAnnotationFrameDistance = annotationElem.attribute( "frameDistance", "0" ).toDouble();
1247  mGridAnnotationFont.fromString( annotationElem.attribute( "font", "" ) );
1248 
1249  //annotation font color
1250  QDomNodeList annotationFontColorList = annotationElem.elementsByTagName( "fontColor" );
1251  if ( annotationFontColorList.size() > 0 )
1252  {
1253  QDomElement fontColorElem = annotationFontColorList.at( 0 ).toElement();
1254  int red = fontColorElem.attribute( "red", "0" ).toInt();
1255  int green = fontColorElem.attribute( "green", "0" ).toInt();
1256  int blue = fontColorElem.attribute( "blue", "0" ).toInt();
1257  int alpha = fontColorElem.attribute( "alpha", "255" ).toInt();
1258  mGridAnnotationFontColor = QColor( red, green, blue, alpha );
1259  }
1260  else
1261  {
1262  mGridAnnotationFontColor = QColor( 0, 0, 0 );
1263  }
1264 
1265  mGridAnnotationPrecision = annotationElem.attribute( "precision", "3" ).toInt();
1266  }
1267  }
1268 
1269  //atlas
1270  QDomNodeList atlasNodeList = itemElem.elementsByTagName( "AtlasMap" );
1271  if ( atlasNodeList.size() > 0 )
1272  {
1273  QDomElement atlasElem = atlasNodeList.at( 0 ).toElement();
1274  mAtlasDriven = ( atlasElem.attribute( "atlasDriven", "0" ) != "0" );
1275  mAtlasFixedScale = ( atlasElem.attribute( "fixedScale", "0" ) != "0" );
1276  mAtlasMargin = atlasElem.attribute( "margin", "0.1" ).toDouble();
1277  }
1278 
1279  //restore general composer item properties
1280  QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
1281  if ( composerItemList.size() > 0 )
1282  {
1283  QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
1284 
1285  if ( composerItemElem.attribute( "rotation", "0" ).toDouble() != 0 )
1286  {
1287  //in versions prior to 2.1 map rotation was stored in the rotation attribute
1288  mMapRotation = composerItemElem.attribute( "rotation", "0" ).toDouble();
1289  }
1290 
1291  _readXML( composerItemElem, doc );
1292  }
1293 
1295  emit itemChanged();
1296  return true;
1297 }
1298 
1300 {
1301  if ( mMapRenderer )
1302  {
1304  }
1305 }
1306 
1308 {
1309  if ( mLayerSet.size() < 1 && !mMapRenderer )
1310  {
1311  return;
1312  }
1313 
1314  //if layer set is fixed, do a lookup in the layer registry to also find the non-visible layers
1315  QStringList currentLayerSet;
1316  if ( mKeepLayerSet )
1317  {
1318  currentLayerSet = QgsMapLayerRegistry::instance()->mapLayers().uniqueKeys();
1319  }
1320  else //only consider layers visible in the map
1321  {
1322  currentLayerSet = mMapRenderer->layerSet();
1323  }
1324 
1325  for ( int i = mLayerSet.size() - 1; i >= 0; --i )
1326  {
1327  if ( !currentLayerSet.contains( mLayerSet.at( i ) ) )
1328  {
1329  mLayerSet.removeAt( i );
1330  }
1331  }
1332 }
1333 
1334 void QgsComposerMap::drawGrid( QPainter* p )
1335 {
1336  QList< QPair< double, QLineF > > verticalLines;
1337  yGridLines( verticalLines );
1338  QList< QPair< double, QLineF > >::const_iterator vIt = verticalLines.constBegin();
1339  QList< QPair< double, QLineF > > horizontalLines;
1340  xGridLines( horizontalLines );
1341  QList< QPair< double, QLineF > >::const_iterator hIt = horizontalLines.constBegin();
1342 
1343  QRectF thisPaintRect = QRectF( 0, 0, QGraphicsRectItem::rect().width(), QGraphicsRectItem::rect().height() );
1344  p->setClipRect( thisPaintRect );
1345 
1346  // set the blend mode for drawing grid lines
1347  p->save();
1348  p->setCompositionMode( mGridBlendMode );
1349 
1350  //simpler approach: draw vertical lines first, then horizontal ones
1352  {
1353  for ( ; vIt != verticalLines.constEnd(); ++vIt )
1354  {
1355  drawGridLine( vIt->second, p );
1356  }
1357 
1358  for ( ; hIt != horizontalLines.constEnd(); ++hIt )
1359  {
1360  drawGridLine( hIt->second, p );
1361  }
1362  }
1363  else //cross
1364  {
1365  QPointF intersectionPoint, crossEnd1, crossEnd2;
1366  for ( ; vIt != verticalLines.constEnd(); ++vIt )
1367  {
1368  //start mark
1369  crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( vIt->second.p1(), vIt->second.p2(), mCrossLength );
1370  drawGridLine( QLineF( vIt->second.p1(), crossEnd1 ), p );
1371 
1372  //test for intersection with every horizontal line
1373  hIt = horizontalLines.constBegin();
1374  for ( ; hIt != horizontalLines.constEnd(); ++hIt )
1375  {
1376  if ( hIt->second.intersect( vIt->second, &intersectionPoint ) == QLineF::BoundedIntersection )
1377  {
1378  crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, vIt->second.p1(), mCrossLength );
1379  crossEnd2 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, vIt->second.p2(), mCrossLength );
1380  drawGridLine( QLineF( crossEnd1, crossEnd2 ), p );
1381  }
1382  }
1383  //end mark
1384  QPointF crossEnd2 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( vIt->second.p2(), vIt->second.p1(), mCrossLength );
1385  drawGridLine( QLineF( vIt->second.p2(), crossEnd2 ), p );
1386  }
1387 
1388  hIt = horizontalLines.constBegin();
1389  for ( ; hIt != horizontalLines.constEnd(); ++hIt )
1390  {
1391  //start mark
1392  crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( hIt->second.p1(), hIt->second.p2(), mCrossLength );
1393  drawGridLine( QLineF( hIt->second.p1(), crossEnd1 ), p );
1394 
1395  vIt = verticalLines.constBegin();
1396  for ( ; vIt != verticalLines.constEnd(); ++vIt )
1397  {
1398  if ( vIt->second.intersect( hIt->second, &intersectionPoint ) == QLineF::BoundedIntersection )
1399  {
1400  crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, hIt->second.p1(), mCrossLength );
1401  crossEnd2 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, hIt->second.p2(), mCrossLength );
1402  drawGridLine( QLineF( crossEnd1, crossEnd2 ), p );
1403  }
1404  }
1405  //end mark
1406  crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( hIt->second.p2(), hIt->second.p1(), mCrossLength );
1407  drawGridLine( QLineF( hIt->second.p2(), crossEnd1 ), p );
1408  }
1409  }
1410  // reset composition mode
1411  p->restore();
1412 
1413  p->setClipRect( thisPaintRect , Qt::NoClip );
1414 
1416  {
1417  drawGridFrame( p, horizontalLines, verticalLines );
1418  }
1419 
1420  if ( mShowGridAnnotation )
1421  {
1422  drawCoordinateAnnotations( p, horizontalLines, verticalLines );
1423  }
1424 
1425 }
1426 
1427 void QgsComposerMap::drawGridFrame( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines )
1428 {
1429  //Sort the coordinate positions for each side
1430  QMap< double, double > leftGridFrame;
1431  QMap< double, double > rightGridFrame;
1432  QMap< double, double > topGridFrame;
1433  QMap< double, double > bottomGridFrame;
1434 
1435  sortGridLinesOnBorders( hLines, vLines, leftGridFrame, rightGridFrame, topGridFrame, bottomGridFrame );
1436 
1437  drawGridFrameBorder( p, leftGridFrame, QgsComposerMap::Left );
1438  drawGridFrameBorder( p, rightGridFrame, QgsComposerMap::Right );
1439  drawGridFrameBorder( p, topGridFrame, QgsComposerMap::Top );
1440  drawGridFrameBorder( p, bottomGridFrame, QgsComposerMap::Bottom );
1441 }
1442 
1443 void QgsComposerMap::drawGridLine( const QLineF& line, QPainter* p )
1444 {
1445  if ( !mGridLineSymbol || !p )
1446  {
1447  return;
1448  }
1449 
1450  //setup render context
1451  QgsRenderContext context;
1452  context.setPainter( p );
1453  if ( mPreviewMode == Rectangle )
1454  {
1455  return;
1456  }
1457  else
1458  {
1459  context.setScaleFactor( 1.0 );
1460  context.setRasterScaleFactor( mComposition->printResolution() / 25.4 );
1461  }
1462 
1463  QPolygonF poly;
1464  poly << line.p1() << line.p2();
1465  mGridLineSymbol->startRender( context );
1466  mGridLineSymbol->renderPolyline( poly, 0, context );
1467  mGridLineSymbol->stopRender( context );
1468 }
1469 
1470 void QgsComposerMap::drawGridFrameBorder( QPainter* p, const QMap< double, double >& borderPos, Border border )
1471 {
1472  double currentCoord = - mGridFrameWidth;
1473  bool color1 = true;
1474  double x = 0;
1475  double y = 0;
1476  double width = 0;
1477  double height = 0;
1478 
1479  QMap< double, double > pos = borderPos;
1480  pos.insert( 0, 0 );
1481  if ( border == Left || border == Right )
1482  {
1483  pos.insert( rect().height(), rect().height() );
1484  pos.insert( rect().height() + mGridFrameWidth, rect().height() + mGridFrameWidth );
1485  }
1486  else //top or bottom
1487  {
1488  pos.insert( rect().width(), rect().width() );
1489  pos.insert( rect().width() + mGridFrameWidth, rect().width() + mGridFrameWidth );
1490  }
1491 
1492  //set pen to current frame pen
1493  QPen framePen = QPen( mGridFramePenColor );
1494  framePen.setWidthF( mGridFramePenThickness );
1495  framePen.setJoinStyle( Qt::MiterJoin );
1496  p->setPen( framePen );
1497 
1498  QMap< double, double >::const_iterator posIt = pos.constBegin();
1499  for ( ; posIt != pos.constEnd(); ++posIt )
1500  {
1501  p->setBrush( QBrush( color1 ? mGridFrameFillColor1 : mGridFrameFillColor2 ) );
1502  if ( border == Left || border == Right )
1503  {
1504  height = posIt.key() - currentCoord;
1505  width = mGridFrameWidth;
1506  x = ( border == Left ) ? -mGridFrameWidth : rect().width();
1507  y = currentCoord;
1508  }
1509  else //top or bottom
1510  {
1511  height = mGridFrameWidth;
1512  width = posIt.key() - currentCoord;
1513  x = currentCoord;
1514  y = ( border == Top ) ? -mGridFrameWidth : rect().height();
1515  }
1516  p->drawRect( QRectF( x, y, width, height ) );
1517  currentCoord = posIt.key();
1518  color1 = !color1;
1519  }
1520 }
1521 
1522 void QgsComposerMap::drawCoordinateAnnotations( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines )
1523 {
1524  if ( !p )
1525  {
1526  return;
1527  }
1528 
1529 
1530  QString currentAnnotationString;
1531  QList< QPair< double, QLineF > >::const_iterator it = hLines.constBegin();
1532  for ( ; it != hLines.constEnd(); ++it )
1533  {
1534  currentAnnotationString = gridAnnotationString( it->first, Latitude );
1535  drawCoordinateAnnotation( p, it->second.p1(), currentAnnotationString );
1536  drawCoordinateAnnotation( p, it->second.p2(), currentAnnotationString );
1537  }
1538 
1539  it = vLines.constBegin();
1540  for ( ; it != vLines.constEnd(); ++it )
1541  {
1542  currentAnnotationString = gridAnnotationString( it->first, Longitude );
1543  drawCoordinateAnnotation( p, it->second.p1(), currentAnnotationString );
1544  drawCoordinateAnnotation( p, it->second.p2(), currentAnnotationString );
1545  }
1546 }
1547 
1548 void QgsComposerMap::drawCoordinateAnnotation( QPainter* p, const QPointF& pos, QString annotationString )
1549 {
1550  Border frameBorder = borderForLineCoord( pos );
1551  double textWidth = textWidthMillimeters( mGridAnnotationFont, annotationString );
1552  //relevant for annotations is the height of digits
1553  double textHeight = fontHeightCharacterMM( mGridAnnotationFont, QChar( '0' ) );
1554  double xpos = pos.x();
1555  double ypos = pos.y();
1556  int rotation = 0;
1557 
1558  double gridFrameDistance = ( mGridFrameStyle == NoGridFrame ) ? 0 : mGridFrameWidth + ( mGridFramePenThickness / 2.0 );
1559 
1560  if ( frameBorder == Left )
1561  {
1562 
1564  {
1566  {
1567  xpos += textHeight + mAnnotationFrameDistance;
1568  ypos += textWidth / 2.0;
1569  rotation = 270;
1570  }
1571  else
1572  {
1573  xpos += mAnnotationFrameDistance;
1574  ypos += textHeight / 2.0;
1575  }
1576  }
1577  else if ( mLeftGridAnnotationPosition == OutsideMapFrame ) //Outside map frame
1578  {
1580  {
1581  xpos -= ( mAnnotationFrameDistance + gridFrameDistance );
1582  ypos += textWidth / 2.0;
1583  rotation = 270;
1584  }
1585  else
1586  {
1587  xpos -= ( textWidth + mAnnotationFrameDistance + gridFrameDistance );
1588  ypos += textHeight / 2.0;
1589  }
1590  }
1591  else
1592  {
1593  return;
1594  }
1595 
1596  }
1597  else if ( frameBorder == Right )
1598  {
1600  {
1602  {
1603  xpos -= mAnnotationFrameDistance;
1604  ypos += textWidth / 2.0;
1605  rotation = 270;
1606  }
1607  else
1608  {
1609  xpos -= textWidth + mAnnotationFrameDistance;
1610  ypos += textHeight / 2.0;
1611  }
1612  }
1613  else if ( mRightGridAnnotationPosition == OutsideMapFrame )//OutsideMapFrame
1614  {
1616  {
1617  xpos += ( textHeight + mAnnotationFrameDistance + gridFrameDistance );
1618  ypos += textWidth / 2.0;
1619  rotation = 270;
1620  }
1621  else //Horizontal
1622  {
1623  xpos += ( mAnnotationFrameDistance + gridFrameDistance );
1624  ypos += textHeight / 2.0;
1625  }
1626  }
1627  else
1628  {
1629  return;
1630  }
1631  }
1632  else if ( frameBorder == Bottom )
1633  {
1635  {
1637  {
1638  ypos -= mAnnotationFrameDistance;
1639  xpos -= textWidth / 2.0;
1640  }
1641  else //Vertical
1642  {
1643  xpos += textHeight / 2.0;
1644  ypos -= mAnnotationFrameDistance;
1645  rotation = 270;
1646  }
1647  }
1648  else if ( mBottomGridAnnotationPosition == OutsideMapFrame ) //OutsideMapFrame
1649  {
1651  {
1652  ypos += ( mAnnotationFrameDistance + textHeight + gridFrameDistance );
1653  xpos -= textWidth / 2.0;
1654  }
1655  else //Vertical
1656  {
1657  xpos += textHeight / 2.0;
1658  ypos += ( textWidth + mAnnotationFrameDistance + gridFrameDistance );
1659  rotation = 270;
1660  }
1661  }
1662  else
1663  {
1664  return;
1665  }
1666  }
1667  else //Top
1668  {
1670  {
1672  {
1673  xpos -= textWidth / 2.0;
1674  ypos += textHeight + mAnnotationFrameDistance;
1675  }
1676  else //Vertical
1677  {
1678  xpos += textHeight / 2.0;
1679  ypos += textWidth + mAnnotationFrameDistance;
1680  rotation = 270;
1681  }
1682  }
1683  else if ( mTopGridAnnotationPosition == OutsideMapFrame ) //OutsideMapFrame
1684  {
1686  {
1687  xpos -= textWidth / 2.0;
1688  ypos -= ( mAnnotationFrameDistance + gridFrameDistance );
1689  }
1690  else //Vertical
1691  {
1692  xpos += textHeight / 2.0;
1693  ypos -= ( mAnnotationFrameDistance + gridFrameDistance );
1694  rotation = 270;
1695  }
1696  }
1697  else
1698  {
1699  return;
1700  }
1701  }
1702 
1703  drawAnnotation( p, QPointF( xpos, ypos ), rotation, annotationString );
1704 }
1705 
1706 void QgsComposerMap::drawAnnotation( QPainter* p, const QPointF& pos, int rotation, const QString& annotationText )
1707 {
1708  p->save();
1709  p->translate( pos );
1710  p->rotate( rotation );
1711  p->setPen( QPen( QColor( mGridAnnotationFontColor ) ) );
1712  drawText( p, 0, 0, annotationText, mGridAnnotationFont );
1713  p->restore();
1714 }
1715 
1717 {
1718  if ( mGridAnnotationFormat == Decimal )
1719  {
1720  return QString::number( value, 'f', mGridAnnotationPrecision );
1721  }
1722 
1723  QgsPoint p;
1724  p.setX( coord == Longitude ? value : 0 );
1725  p.setY( coord == Longitude ? 0 : value );
1726 
1727  QString annotationString;
1729  {
1730  annotationString = p.toDegreesMinutes( mGridAnnotationPrecision );
1731  }
1732  else //DegreeMinuteSecond
1733  {
1734  annotationString = p.toDegreesMinutesSeconds( mGridAnnotationPrecision );
1735  }
1736 
1737  QStringList split = annotationString.split( "," );
1738  if ( coord == Longitude )
1739  {
1740  return split.at( 0 );
1741  }
1742  else
1743  {
1744  if ( split.size() < 2 )
1745  {
1746  return "";
1747  }
1748  return split.at( 1 );
1749  }
1750 }
1751 
1752 int QgsComposerMap::xGridLines( QList< QPair< double, QLineF > >& lines ) const
1753 {
1754  lines.clear();
1755  if ( mGridIntervalY <= 0.0 )
1756  {
1757  return 1;
1758  }
1759 
1760 
1761  QPolygonF mapPolygon = transformedMapPolygon();
1762  QRectF mapBoundingRect = mapPolygon.boundingRect();
1763 
1764  //consider to round up to the next step in case the left boundary is > 0
1765  double roundCorrection = mapBoundingRect.top() > 0 ? 1.0 : 0.0;
1766  double currentLevel = ( int )(( mapBoundingRect.top() - mGridOffsetY ) / mGridIntervalY + roundCorrection ) * mGridIntervalY + mGridOffsetY;
1767 
1768  if ( qgsDoubleNear( mMapRotation, 0.0 ) )
1769  {
1770  //no rotation. Do it 'the easy way'
1771 
1772  double yCanvasCoord;
1773 
1774  while ( currentLevel <= mapBoundingRect.bottom() )
1775  {
1776  yCanvasCoord = rect().height() * ( 1 - ( currentLevel - mapBoundingRect.top() ) / mapBoundingRect.height() );
1777  lines.push_back( qMakePair( currentLevel, QLineF( 0, yCanvasCoord, rect().width(), yCanvasCoord ) ) );
1778  currentLevel += mGridIntervalY;
1779  }
1780  }
1781 
1782  //the four border lines
1783  QVector<QLineF> borderLines;
1784  borderLines << QLineF( mapPolygon.at( 0 ), mapPolygon.at( 1 ) );
1785  borderLines << QLineF( mapPolygon.at( 1 ), mapPolygon.at( 2 ) );
1786  borderLines << QLineF( mapPolygon.at( 2 ), mapPolygon.at( 3 ) );
1787  borderLines << QLineF( mapPolygon.at( 3 ), mapPolygon.at( 0 ) );
1788 
1789  QList<QPointF> intersectionList; //intersects between border lines and grid lines
1790 
1791  while ( currentLevel <= mapBoundingRect.bottom() )
1792  {
1793  intersectionList.clear();
1794  QLineF gridLine( mapBoundingRect.left(), currentLevel, mapBoundingRect.right(), currentLevel );
1795 
1796  QVector<QLineF>::const_iterator it = borderLines.constBegin();
1797  for ( ; it != borderLines.constEnd(); ++it )
1798  {
1799  QPointF intersectionPoint;
1800  if ( it->intersect( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
1801  {
1802  intersectionList.push_back( intersectionPoint );
1803  if ( intersectionList.size() >= 2 )
1804  {
1805  break; //we already have two intersections, skip further tests
1806  }
1807  }
1808  }
1809 
1810  if ( intersectionList.size() >= 2 )
1811  {
1812  lines.push_back( qMakePair( currentLevel, QLineF( mapToItemCoords( intersectionList.at( 0 ) ), mapToItemCoords( intersectionList.at( 1 ) ) ) ) );
1813  }
1814  currentLevel += mGridIntervalY;
1815  }
1816 
1817 
1818  return 0;
1819 }
1820 
1821 int QgsComposerMap::yGridLines( QList< QPair< double, QLineF > >& lines ) const
1822 {
1823  lines.clear();
1824  if ( mGridIntervalX <= 0.0 )
1825  {
1826  return 1;
1827  }
1828 
1829  QPolygonF mapPolygon = transformedMapPolygon();
1830  QRectF mapBoundingRect = mapPolygon.boundingRect();
1831 
1832  //consider to round up to the next step in case the left boundary is > 0
1833  double roundCorrection = mapBoundingRect.left() > 0 ? 1.0 : 0.0;
1834  double currentLevel = ( int )(( mapBoundingRect.left() - mGridOffsetX ) / mGridIntervalX + roundCorrection ) * mGridIntervalX + mGridOffsetX;
1835 
1836  if ( qgsDoubleNear( mMapRotation, 0.0 ) )
1837  {
1838  //no rotation. Do it 'the easy way'
1839  double xCanvasCoord;
1840 
1841  while ( currentLevel <= mapBoundingRect.right() )
1842  {
1843  xCanvasCoord = rect().width() * ( currentLevel - mapBoundingRect.left() ) / mapBoundingRect.width();
1844  lines.push_back( qMakePair( currentLevel, QLineF( xCanvasCoord, 0, xCanvasCoord, rect().height() ) ) );
1845  currentLevel += mGridIntervalX;
1846  }
1847  }
1848 
1849  //the four border lines
1850  QVector<QLineF> borderLines;
1851  borderLines << QLineF( mapPolygon.at( 0 ), mapPolygon.at( 1 ) );
1852  borderLines << QLineF( mapPolygon.at( 1 ), mapPolygon.at( 2 ) );
1853  borderLines << QLineF( mapPolygon.at( 2 ), mapPolygon.at( 3 ) );
1854  borderLines << QLineF( mapPolygon.at( 3 ), mapPolygon.at( 0 ) );
1855 
1856  QList<QPointF> intersectionList; //intersects between border lines and grid lines
1857 
1858  while ( currentLevel <= mapBoundingRect.right() )
1859  {
1860  intersectionList.clear();
1861  QLineF gridLine( currentLevel, mapBoundingRect.bottom(), currentLevel, mapBoundingRect.top() );
1862 
1863  QVector<QLineF>::const_iterator it = borderLines.constBegin();
1864  for ( ; it != borderLines.constEnd(); ++it )
1865  {
1866  QPointF intersectionPoint;
1867  if ( it->intersect( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
1868  {
1869  intersectionList.push_back( intersectionPoint );
1870  if ( intersectionList.size() >= 2 )
1871  {
1872  break; //we already have two intersections, skip further tests
1873  }
1874  }
1875  }
1876 
1877  if ( intersectionList.size() >= 2 )
1878  {
1879  lines.push_back( qMakePair( currentLevel, QLineF( mapToItemCoords( intersectionList.at( 0 ) ), mapToItemCoords( intersectionList.at( 1 ) ) ) ) );
1880  }
1881  currentLevel += mGridIntervalX;
1882  }
1883 
1884  return 0;
1885 }
1886 
1888 {
1889  if ( mGridLineSymbol )
1890  {
1891  mGridLineSymbol->setWidth( w );
1892  }
1893 }
1894 
1895 void QgsComposerMap::setGridPenColor( const QColor& c )
1896 {
1897  if ( mGridLineSymbol )
1898  {
1899  mGridLineSymbol->setColor( c );
1900  }
1901 }
1902 
1903 void QgsComposerMap::setGridPen( const QPen& p )
1904 {
1905  setGridPenWidth( p.widthF() );
1906  setGridPenColor( p.color() );
1907 }
1908 
1910 {
1911  QPen p;
1912  if ( mGridLineSymbol )
1913  {
1914  p.setWidthF( mGridLineSymbol->width() );
1915  p.setColor( mGridLineSymbol->color() );
1916  p.setCapStyle( Qt::FlatCap );
1917  }
1918  return p;
1919 }
1920 
1921 void QgsComposerMap::setGridBlendMode( QPainter::CompositionMode blendMode )
1922 {
1924  update();
1925 }
1926 
1928 {
1929  return mCurrentRectangle;
1930 }
1931 
1933 {
1934  QRectF rectangle = rect();
1935  double extension = maxExtension();
1936  rectangle.setLeft( rectangle.left() - extension );
1937  rectangle.setRight( rectangle.right() + extension );
1938  rectangle.setTop( rectangle.top() - extension );
1939  rectangle.setBottom( rectangle.bottom() + extension );
1940  if ( rectangle != mCurrentRectangle )
1941  {
1942  prepareGeometryChange();
1943  mCurrentRectangle = rectangle;
1944  }
1945 }
1946 
1948 {
1949  QgsComposerItem::setFrameOutlineWidth( outlineWidth );
1951 }
1952 
1954 {
1955  double dx = mXOffset;
1956  double dy = mYOffset;
1957  transformShift( dx, dy );
1958  return QgsRectangle( currentMapExtent()->xMinimum() - dx, currentMapExtent()->yMinimum() - dy, currentMapExtent()->xMaximum() - dx, currentMapExtent()->yMaximum() - dy );
1959 }
1960 
1962 {
1963  double dx = mXOffset;
1964  double dy = mYOffset;
1965  //qWarning("offset");
1966  //qWarning(QString::number(dx).toLocal8Bit().data());
1967  //qWarning(QString::number(dy).toLocal8Bit().data());
1968  transformShift( dx, dy );
1969  //qWarning("transformed:");
1970  //qWarning(QString::number(dx).toLocal8Bit().data());
1971  //qWarning(QString::number(dy).toLocal8Bit().data());
1972  QPolygonF poly;
1973  mapPolygon( poly );
1974  poly.translate( -dx, -dy );
1975  return poly;
1976 }
1977 
1979 {
1980  double frameExtension = mFrame ? pen().widthF() / 2.0 : 0.0;
1983  {
1984  return frameExtension;
1985  }
1986 
1987  QList< QPair< double, QLineF > > xLines;
1988  QList< QPair< double, QLineF > > yLines;
1989 
1990  int xGridReturn = xGridLines( xLines );
1991  int yGridReturn = yGridLines( yLines );
1992 
1993  if ( xGridReturn != 0 && yGridReturn != 0 )
1994  {
1995  return frameExtension;
1996  }
1997 
1998  double maxExtension = 0;
1999  double currentExtension = 0;
2000  QString currentAnnotationString;
2001 
2002  QList< QPair< double, QLineF > >::const_iterator it = xLines.constBegin();
2003  for ( ; it != xLines.constEnd(); ++it )
2004  {
2005  currentAnnotationString = gridAnnotationString( it->first, Latitude );
2006  currentExtension = qMax( textWidthMillimeters( mGridAnnotationFont, currentAnnotationString ), fontAscentMillimeters( mGridAnnotationFont ) );
2007  maxExtension = qMax( maxExtension, currentExtension );
2008  }
2009 
2010  it = yLines.constBegin();
2011  for ( ; it != yLines.constEnd(); ++it )
2012  {
2013  currentAnnotationString = gridAnnotationString( it->first, Longitude );
2014  currentExtension = qMax( textWidthMillimeters( mGridAnnotationFont, currentAnnotationString ), fontAscentMillimeters( mGridAnnotationFont ) );
2015  maxExtension = qMax( maxExtension, currentExtension );
2016  }
2017 
2018  //grid frame
2019  double gridFrameDist = ( mGridFrameStyle == NoGridFrame ) ? 0 : mGridFrameWidth + ( mGridFramePenThickness / 2.0 );
2020  return qMax( frameExtension, maxExtension + mAnnotationFrameDistance + gridFrameDist );
2021 }
2022 
2023 void QgsComposerMap::mapPolygon( const QgsRectangle& extent, QPolygonF& poly ) const
2024 {
2025  poly.clear();
2026  if ( mMapRotation == 0 )
2027  {
2028  poly << QPointF( extent.xMinimum(), extent.yMaximum() );
2029  poly << QPointF( extent.xMaximum(), extent.yMaximum() );
2030  poly << QPointF( extent.xMaximum(), extent.yMinimum() );
2031  poly << QPointF( extent.xMinimum(), extent.yMinimum() );
2032  return;
2033  }
2034 
2035  //there is rotation
2036  QgsPoint rotationPoint(( extent.xMaximum() + extent.xMinimum() ) / 2.0, ( extent.yMaximum() + extent.yMinimum() ) / 2.0 );
2037  double dx, dy; //x-, y- shift from rotation point to corner point
2038 
2039  //top left point
2040  dx = rotationPoint.x() - extent.xMinimum();
2041  dy = rotationPoint.y() - extent.yMaximum();
2042  rotate( mMapRotation, dx, dy );
2043  poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy );
2044 
2045  //top right point
2046  dx = rotationPoint.x() - extent.xMaximum();
2047  dy = rotationPoint.y() - extent.yMaximum();
2048  rotate( mMapRotation, dx, dy );
2049  poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy );
2050 
2051  //bottom right point
2052  dx = rotationPoint.x() - extent.xMaximum();
2053  dy = rotationPoint.y() - extent.yMinimum();
2054  rotate( mMapRotation, dx, dy );
2055  poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy );
2056 
2057  //bottom left point
2058  dx = rotationPoint.x() - extent.xMinimum();
2059  dy = rotationPoint.y() - extent.yMinimum();
2060  rotate( mMapRotation, dx, dy );
2061  poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy );
2062 }
2063 
2064 void QgsComposerMap::mapPolygon( QPolygonF& poly ) const
2065 {
2066  return mapPolygon( *currentMapExtent(), poly );
2067 }
2068 
2070 {
2071  QgsRectangle newExtent = *currentMapExtent();
2072  if ( mMapRotation == 0 )
2073  {
2074  extent = newExtent;
2075  }
2076  else
2077  {
2078  QPolygonF poly;
2079  mapPolygon( newExtent, poly );
2080  QRectF bRect = poly.boundingRect();
2081  extent.setXMinimum( bRect.left() );
2082  extent.setXMaximum( bRect.right() );
2083  extent.setYMinimum( bRect.top() );
2084  extent.setYMaximum( bRect.bottom() );
2085  }
2086 }
2087 
2089 {
2090  double extentWidth = currentMapExtent()->width();
2091  if ( extentWidth <= 0 )
2092  {
2093  return 1;
2094  }
2095  return rect().width() / extentWidth;
2096 }
2097 
2099 {
2100  if ( mOverviewFrameMapId != -1 )
2101  {
2102  const QgsComposerMap* map = mComposition->getComposerMapById( mapId );
2103  if ( map )
2104  {
2105  QObject::disconnect( map, SIGNAL( extentChanged() ), this, SLOT( overviewExtentChanged() ) );
2106  }
2107  }
2108  mOverviewFrameMapId = mapId;
2109  if ( mOverviewFrameMapId != -1 )
2110  {
2111  const QgsComposerMap* map = mComposition->getComposerMapById( mapId );
2112  if ( map )
2113  {
2114  QObject::connect( map, SIGNAL( extentChanged() ), this, SLOT( overviewExtentChanged() ) );
2115  }
2116  }
2117  update();
2118 }
2119 
2121 {
2122  //if using overview centering, update the map's extent
2123  if ( mOverviewCentered && mOverviewFrameMapId != -1 )
2124  {
2126 
2127  const QgsComposerMap* overviewFrameMap = mComposition->getComposerMapById( mOverviewFrameMapId );
2128  QgsRectangle otherExtent = *overviewFrameMap->currentMapExtent();
2129 
2130  QgsPoint center = otherExtent.center();
2131  QgsRectangle movedExtent( center.x() - currentMapExtent()->width() / 2,
2132  center.y() - currentMapExtent()->height() / 2,
2133  center.x() - currentMapExtent()->width() / 2 + currentMapExtent()->width(),
2134  center.y() - currentMapExtent()->height() / 2 + currentMapExtent()->height() );
2135  *currentMapExtent() = movedExtent;
2136 
2137  emit itemChanged();
2138  emit extentChanged();
2139  }
2140 
2141  //redraw so that overview gets updated
2142  cache();
2143  update();
2144 }
2145 
2146 
2148 {
2149  delete mOverviewFrameMapSymbol;
2150  mOverviewFrameMapSymbol = symbol;
2151 }
2152 
2153 void QgsComposerMap::setOverviewBlendMode( QPainter::CompositionMode blendMode )
2154 {
2156  update();
2157 }
2158 
2160 {
2161  mOverviewInverted = inverted;
2162  update();
2163 }
2164 
2166 {
2167  mOverviewCentered = centered;
2169 }
2170 
2172 {
2173  delete mGridLineSymbol;
2174  mGridLineSymbol = symbol;
2175 }
2176 
2177 void QgsComposerMap::transformShift( double& xShift, double& yShift ) const
2178 {
2179  double mmToMapUnits = 1.0 / mapUnitsToMM();
2180  double dxScaled = xShift * mmToMapUnits;
2181  double dyScaled = - yShift * mmToMapUnits;
2182 
2183  rotate( mMapRotation, dxScaled, dyScaled );
2184 
2185  xShift = dxScaled;
2186  yShift = dyScaled;
2187 }
2188 
2189 QPointF QgsComposerMap::mapToItemCoords( const QPointF& mapCoords ) const
2190 {
2191  QPolygonF mapPoly = transformedMapPolygon();
2192  if ( mapPoly.size() < 1 )
2193  {
2194  return QPointF( 0, 0 );
2195  }
2196 
2197  QgsRectangle tExtent = transformedExtent();
2198  QgsPoint rotationPoint(( tExtent.xMaximum() + tExtent.xMinimum() ) / 2.0, ( tExtent.yMaximum() + tExtent.yMinimum() ) / 2.0 );
2199  double dx = mapCoords.x() - rotationPoint.x();
2200  double dy = mapCoords.y() - rotationPoint.y();
2201  rotate( -mMapRotation, dx, dy );
2202  QgsPoint backRotatedCoords( rotationPoint.x() + dx, rotationPoint.y() + dy );
2203 
2204  QgsRectangle unrotatedExtent = transformedExtent();
2205  double xItem = rect().width() * ( backRotatedCoords.x() - unrotatedExtent.xMinimum() ) / unrotatedExtent.width();
2206  double yItem = rect().height() * ( 1 - ( backRotatedCoords.y() - unrotatedExtent.yMinimum() ) / unrotatedExtent.height() );
2207  return QPointF( xItem, yItem );
2208 }
2209 
2211 {
2212  if ( p.x() <= pen().widthF() )
2213  {
2214  return Left;
2215  }
2216  else if ( p.x() >= ( rect().width() - pen().widthF() ) )
2217  {
2218  return Right;
2219  }
2220  else if ( p.y() <= pen().widthF() )
2221  {
2222  return Top;
2223  }
2224  else
2225  {
2226  return Bottom;
2227  }
2228 }
2229 
2230 void QgsComposerMap::drawCanvasItems( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle )
2231 {
2232  if ( !mMapCanvas || !mDrawCanvasItems )
2233  {
2234  return;
2235  }
2236 
2237  QList<QGraphicsItem*> itemList = mMapCanvas->items();
2238  if ( itemList.size() < 1 )
2239  {
2240  return;
2241  }
2242  QGraphicsItem* currentItem = 0;
2243 
2244  for ( int i = itemList.size() - 1; i >= 0; --i )
2245  {
2246  currentItem = itemList.at( i );
2247  //don't draw mapcanvasmap (has z value -10)
2248  if ( !currentItem || currentItem->data( 0 ).toString() != "AnnotationItem" )
2249  {
2250  continue;
2251  }
2252  drawCanvasItem( currentItem, painter, itemStyle );
2253  }
2254 }
2255 
2256 void QgsComposerMap::drawCanvasItem( QGraphicsItem* item, QPainter* painter, const QStyleOptionGraphicsItem* itemStyle )
2257 {
2258  if ( !item || !mMapCanvas || !mMapRenderer || !item->isVisible() )
2259  {
2260  return;
2261  }
2262 
2263  painter->save();
2264 
2265  QgsRectangle rendererExtent = mMapRenderer->extent();
2266  QgsRectangle composerMapExtent = *currentMapExtent();
2267 
2268  //determine scale factor according to graphics view dpi
2269  double scaleFactor = 1.0 / mMapCanvas->logicalDpiX() * 25.4;
2270 
2271  double itemX, itemY;
2272  QGraphicsItem* parent = item->parentItem();
2273  if ( !parent )
2274  {
2275  QPointF mapPos = composerMapPosForItem( item );
2276  itemX = mapPos.x();
2277  itemY = mapPos.y();
2278  }
2279  else //place item relative to the parent item
2280  {
2281  QPointF itemScenePos = item->scenePos();
2282  QPointF parentScenePos = parent->scenePos();
2283 
2284  QPointF mapPos = composerMapPosForItem( parent );
2285 
2286  itemX = mapPos.x() + ( itemScenePos.x() - parentScenePos.x() ) * scaleFactor;
2287  itemY = mapPos.y() + ( itemScenePos.y() - parentScenePos.y() ) * scaleFactor;
2288  }
2289  painter->translate( itemX, itemY );
2290 
2291 
2292  painter->scale( scaleFactor, scaleFactor );
2293 
2294  //a little trick to let the item know that the paint request comes from the composer
2295  item->setData( 1, "composer" );
2296  item->paint( painter, itemStyle, 0 );
2297  item->setData( 1, "" );
2298  painter->restore();
2299 }
2300 
2301 QPointF QgsComposerMap::composerMapPosForItem( const QGraphicsItem* item ) const
2302 {
2303  if ( !item || !mMapCanvas || !mMapRenderer )
2304  {
2305  return QPointF( 0, 0 );
2306  }
2307 
2308  if ( currentMapExtent()->height() <= 0 || currentMapExtent()->width() <= 0 || mMapCanvas->width() <= 0 || mMapCanvas->height() <= 0 )
2309  {
2310  return QPointF( 0, 0 );
2311  }
2312 
2313  QRectF graphicsSceneRect = mMapCanvas->sceneRect();
2314  QPointF itemScenePos = item->scenePos();
2315  QgsRectangle mapRendererExtent = mMapRenderer->extent();
2316 
2317  double mapX = itemScenePos.x() / graphicsSceneRect.width() * mapRendererExtent.width() + mapRendererExtent.xMinimum();
2318  double mapY = mapRendererExtent.yMaximum() - itemScenePos.y() / graphicsSceneRect.height() * mapRendererExtent.height();
2319  return mapToItemCoords( QPointF( mapX, mapY ) );
2320 }
2321 
2323 {
2324  switch ( border )
2325  {
2326  case QgsComposerMap::Left:
2328  break;
2329  case QgsComposerMap::Right:
2331  break;
2332  case QgsComposerMap::Top:
2334  break;
2337  break;
2338  default:
2339  return;
2340  }
2342  update();
2343 }
2344 
2346 {
2347  switch ( border )
2348  {
2349  case QgsComposerMap::Left:
2351  break;
2352  case QgsComposerMap::Right:
2354  break;
2355  case QgsComposerMap::Top:
2357  break;
2359  default:
2361  break;
2362  }
2363 }
2364 
2366 {
2367  switch ( border )
2368  {
2369  case QgsComposerMap::Left:
2371  break;
2372  case QgsComposerMap::Right:
2374  break;
2375  case QgsComposerMap::Top:
2377  break;
2380  break;
2381  default:
2382  return;
2383  break;
2384  }
2386  update();
2387 }
2388 
2390 {
2391  switch ( border )
2392  {
2393  case QgsComposerMap::Left:
2395  break;
2396  case QgsComposerMap::Right:
2398  break;
2399  case QgsComposerMap::Top:
2401  break;
2403  default:
2405  break;
2406  }
2407 }
2408 
2409 void QgsComposerMap::sortGridLinesOnBorders( const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines, QMap< double, double >& leftFrameEntries,
2410  QMap< double, double >& rightFrameEntries, QMap< double, double >& topFrameEntries, QMap< double, double >& bottomFrameEntries ) const
2411 {
2412  QList< QPair< double, QPointF > > borderPositions;
2413  QList< QPair< double, QLineF > >::const_iterator it = hLines.constBegin();
2414  for ( ; it != hLines.constEnd(); ++it )
2415  {
2416  borderPositions << qMakePair( it->first, it->second.p1() );
2417  borderPositions << qMakePair( it->first, it->second.p2() );
2418  }
2419  it = vLines.constBegin();
2420  for ( ; it != vLines.constEnd(); ++it )
2421  {
2422  borderPositions << qMakePair( it->first, it->second.p1() );
2423  borderPositions << qMakePair( it->first, it->second.p2() );
2424  }
2425 
2426  QList< QPair< double, QPointF > >::const_iterator bIt = borderPositions.constBegin();
2427  for ( ; bIt != borderPositions.constEnd(); ++bIt )
2428  {
2429  Border frameBorder = borderForLineCoord( bIt->second );
2430  if ( frameBorder == QgsComposerMap::Left )
2431  {
2432  leftFrameEntries.insert( bIt->second.y(), bIt->first );
2433  }
2434  else if ( frameBorder == QgsComposerMap::Right )
2435  {
2436  rightFrameEntries.insert( bIt->second.y(), bIt->first );
2437  }
2438  else if ( frameBorder == QgsComposerMap::Top )
2439  {
2440  topFrameEntries.insert( bIt->second.x(), bIt->first );
2441  }
2442  else //Bottom
2443  {
2444  bottomFrameEntries.insert( bIt->second.x(), bIt->first );
2445  }
2446  }
2447 }
2448 
2450 {
2451  if ( mOverviewFrameMapId == -1 || !mComposition )
2452  {
2453  return;
2454  }
2455 
2457  {
2458  //if map item is set to rectangle preview mode and we are not exporting the composition
2459  //then don't draw an overview rectangle
2460  return;
2461  }
2462 
2463  const QgsComposerMap* overviewFrameMap = mComposition->getComposerMapById( mOverviewFrameMapId );
2464  if ( !overviewFrameMap )
2465  {
2466  return;
2467  }
2468 
2469  QgsRectangle otherExtent = *overviewFrameMap->currentMapExtent();
2470  QgsRectangle thisExtent = *currentMapExtent();
2471  QgsRectangle intersectRect = thisExtent.intersect( &otherExtent );
2472 
2473  QgsRenderContext context;
2474  context.setPainter( p );
2475  context.setScaleFactor( 1.0 );
2476  context.setRasterScaleFactor( mComposition->printResolution() / 25.4 );
2477 
2478  p->save();
2479  p->setCompositionMode( mOverviewBlendMode );
2480  p->translate( mXOffset, mYOffset );
2482 
2483  //construct a polygon corresponding to the intersecting map extent
2484  QPolygonF intersectPolygon;
2485  double x = ( intersectRect.xMinimum() - thisExtent.xMinimum() ) / thisExtent.width() * rect().width();
2486  double y = ( thisExtent.yMaximum() - intersectRect.yMaximum() ) / thisExtent.height() * rect().height();
2487  double width = intersectRect.width() / thisExtent.width() * rect().width();
2488  double height = intersectRect.height() / thisExtent.height() * rect().height();
2489  intersectPolygon << QPointF( x, y ) << QPointF( x + width, y ) << QPointF( x + width, y + height ) << QPointF( x, y + height ) << QPointF( x, y );
2490 
2491  QList<QPolygonF> rings; //empty list
2492  if ( !mOverviewInverted )
2493  {
2494  //Render the intersecting map extent
2495  mOverviewFrameMapSymbol->renderPolygon( intersectPolygon, &rings, 0, context );;
2496  }
2497  else
2498  {
2499  //We are inverting the overview frame (ie, shading outside the intersecting extent)
2500  //Construct a polygon corresponding to the overview map extent
2501  QPolygonF outerPolygon;
2502  outerPolygon << QPointF( 0, 0 ) << QPointF( rect().width(), 0 ) << QPointF( rect().width(), rect().height() ) << QPointF( 0, rect().height() ) << QPointF( 0, 0 );
2503 
2504  //Intersecting extent is an inner ring for the shaded area
2505  rings.append( intersectPolygon );
2506  mOverviewFrameMapSymbol->renderPolygon( outerPolygon, &rings, 0, context );
2507  }
2508 
2509  mOverviewFrameMapSymbol->stopRender( context );
2510  p->restore();
2511 }
2512 
2514 {
2515  delete mOverviewFrameMapSymbol;
2516  QgsStringMap properties;
2517  properties.insert( "color", "255,0,0,255" );
2518  properties.insert( "style", "solid" );
2519  properties.insert( "style_border", "no" );
2522 }
2523 
2525 {
2526  delete mGridLineSymbol;
2527  QgsStringMap properties;
2528  properties.insert( "color", "0,0,0,255" );
2529  properties.insert( "width", "0.3" );
2530  properties.insert( "capstyle", "flat" );
2532 }
2533 
2535 {
2536  QString format = QgsProject::instance()->readEntry( "PositionPrecision", "/DegreeFormat", "D" );
2537 
2538  bool degreeUnits = true;
2539  if ( mMapRenderer )
2540  {
2541  degreeUnits = ( mMapRenderer->mapUnits() == QGis::Degrees );
2542  }
2543 
2544  if ( format == "DM" && degreeUnits )
2545  {
2547  }
2548  else if ( format == "DMS" && degreeUnits )
2549  {
2551  }
2552  else
2553  {
2555  }
2556 }
2557 
2559 {
2560  if ( !mComposition )
2561  {
2562  return;
2563  }
2564 
2565  const QgsComposerMap* existingMap = mComposition->getComposerMapById( mId );
2566  if ( !existingMap )
2567  {
2568  return; //keep mId as it is still available
2569  }
2570 
2571  int maxId = -1;
2572  QList<const QgsComposerMap*> mapList = mComposition->composerMapItems();
2573  QList<const QgsComposerMap*>::const_iterator mapIt = mapList.constBegin();
2574  for ( ; mapIt != mapList.constEnd(); ++mapIt )
2575  {
2576  if (( *mapIt )->id() > maxId )
2577  {
2578  maxId = ( *mapIt )->id();
2579  }
2580  }
2581  mId = maxId + 1;
2582 }
2583 
2584 bool QgsComposerMap::imageSizeConsideringRotation( double& width, double& height ) const
2585 {
2586  //kept for api compatibility with QGIS 2.0 - use mMapRotation
2588 }
2589 
2590 bool QgsComposerMap::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const
2591 {
2592  //kept for api compatibility with QGIS 2.0 - use mMapRotation
2594 }
2595 
2596 void QgsComposerMap::sizeChangedByRotation( double& width, double& height )
2597 {
2598  //kept for api compatibility with QGIS 2.0 - use mMapRotation
2599  return QgsComposerItem::sizeChangedByRotation( width, height, mMapRotation );
2600 }