QGIS API Documentation  2.9.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgscomposerpicture.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscomposerpicture.cpp
3  -------------------
4  begin : September 2005
5  copyright : (C) 2005 by Radim Blazek
6  email : radim.blazek@gmail.com
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 "qgscomposerpicture.h"
19 #include "qgscomposerutils.h"
20 #include "qgscomposermap.h"
21 #include "qgscomposition.h"
22 #include "qgsatlascomposition.h"
23 #include "qgsproject.h"
24 #include "qgsexpression.h"
25 #include "qgsvectorlayer.h"
26 #include "qgsmessagelog.h"
27 #include "qgsdatadefined.h"
29 #include <QDomDocument>
30 #include <QDomElement>
31 #include <QFileInfo>
32 #include <QImageReader>
33 #include <QPainter>
34 #include <QSvgRenderer>
35 #include <QNetworkRequest>
36 #include <QNetworkReply>
37 #include <QEventLoop>
38 #include <QCoreApplication>
39 
41  : QgsComposerItem( composition )
42  , mMode( Unknown )
43  , mPictureRotation( 0 )
44  , mRotationMap( 0 )
45  , mResizeMode( QgsComposerPicture::Zoom )
46  , mPictureAnchor( UpperLeft )
47  , mHasExpressionError( false )
48 {
49  mPictureWidth = rect().width();
50  init();
51 }
52 
53 QgsComposerPicture::QgsComposerPicture() : QgsComposerItem( 0 ),
54  mMode( Unknown ),
55  mPictureRotation( 0 ),
56  mRotationMap( 0 ),
57  mResizeMode( QgsComposerPicture::Zoom ),
58  mPictureAnchor( UpperLeft ),
59  mHasExpressionError( false )
60 {
61  mPictureHeight = rect().height();
62  init();
63 }
64 
65 void QgsComposerPicture::init()
66 {
67  //default to no background
68  setBackgroundEnabled( false );
69 
70  //data defined strings
71  mDataDefinedNames.insert( QgsComposerObject::PictureSource, QString( "dataDefinedSource" ) );
72 
73  //insert PictureSource data defined property (only required due to deprecated API elements,
74  //remove after 3.0
75  setDataDefinedProperty( QgsComposerObject::PictureSource, false, true, QString(), QString() );
76 
77  //connect some signals
78 
79  //connect to atlas feature changing
80  //to update the picture source expression
81  connect( &mComposition->atlasComposition(), SIGNAL( featureChanged( QgsFeature* ) ), this, SLOT( refreshPicture() ) );
82 
83  //connect to composer print resolution changing
84  connect( mComposition, SIGNAL( printResolutionChanged() ), this, SLOT( recalculateSize() ) );
85 }
86 
88 {
89 
90 }
91 
92 void QgsComposerPicture::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
93 {
94  Q_UNUSED( itemStyle );
95  Q_UNUSED( pWidget );
96  if ( !painter )
97  {
98  return;
99  }
100  if ( !shouldDrawItem() )
101  {
102  return;
103  }
104 
105  drawBackground( painter );
106 
107  //int newDpi = ( painter->device()->logicalDpiX() + painter->device()->logicalDpiY() ) / 2;
108 
109  //picture resizing
110  if ( mMode != Unknown )
111  {
112  double boundRectWidthMM;
113  double boundRectHeightMM;
114  QRect imageRect;
115  if ( mResizeMode == QgsComposerPicture::Zoom || mResizeMode == QgsComposerPicture::ZoomResizeFrame )
116  {
117  boundRectWidthMM = mPictureWidth;
118  boundRectHeightMM = mPictureHeight;
119  imageRect = QRect( 0, 0, mImage.width(), mImage.height() );
120  }
121  else if ( mResizeMode == QgsComposerPicture::Stretch )
122  {
123  boundRectWidthMM = rect().width();
124  boundRectHeightMM = rect().height();
125  imageRect = QRect( 0, 0, mImage.width(), mImage.height() );
126  }
127  else if ( mResizeMode == QgsComposerPicture::Clip )
128  {
129  boundRectWidthMM = rect().width();
130  boundRectHeightMM = rect().height();
131  int imageRectWidthPixels = mImage.width();
132  int imageRectHeightPixels = mImage.height();
133  imageRect = clippedImageRect( boundRectWidthMM, boundRectHeightMM,
134  QSize( imageRectWidthPixels, imageRectHeightPixels ) );
135  }
136  else
137  {
138  boundRectWidthMM = rect().width();
139  boundRectHeightMM = rect().height();
140  imageRect = QRect( 0, 0, rect().width() * mComposition->printResolution() / 25.4,
141  rect().height() * mComposition->printResolution() / 25.4 );
142  }
143  painter->save();
144  //antialiasing on
145  painter->setRenderHint( QPainter::Antialiasing, true );
146 
147  //zoom mode - calculate anchor point and rotation
148  if ( mResizeMode == Zoom )
149  {
150  //TODO - allow placement modes with rotation set. for now, setting a rotation
151  //always places picture in center of frame
152  if ( mPictureRotation != 0 )
153  {
154  painter->translate( rect().width() / 2.0, rect().height() / 2.0 );
155  painter->rotate( mPictureRotation );
156  painter->translate( -boundRectWidthMM / 2.0, -boundRectHeightMM / 2.0 );
157  }
158  else
159  {
160  //shift painter to edge/middle of frame depending on placement
161  double diffX = rect().width() - boundRectWidthMM;
162  double diffY = rect().height() - boundRectHeightMM;
163 
164  double dX = 0;
165  double dY = 0;
166  switch ( mPictureAnchor )
167  {
168  case UpperLeft:
169  case MiddleLeft:
170  case LowerLeft:
171  //nothing to do
172  break;
173  case UpperMiddle:
174  case Middle:
175  case LowerMiddle:
176  dX = diffX / 2.0;
177  break;
178  case UpperRight:
179  case MiddleRight:
180  case LowerRight:
181  dX = diffX;
182  break;
183  }
184  switch ( mPictureAnchor )
185  {
186  case UpperLeft:
187  case UpperMiddle:
188  case UpperRight:
189  //nothing to do
190  break;
191  case MiddleLeft:
192  case Middle:
193  case MiddleRight:
194  dY = diffY / 2.0;
195  break;
196  case LowerLeft:
197  case LowerMiddle:
198  case LowerRight:
199  dY = diffY;
200  break;
201  }
202  painter->translate( dX, dY );
203  }
204  }
205  else if ( mResizeMode == ZoomResizeFrame )
206  {
207  if ( mPictureRotation != 0 )
208  {
209  painter->translate( rect().width() / 2.0, rect().height() / 2.0 );
210  painter->rotate( mPictureRotation );
211  painter->translate( -boundRectWidthMM / 2.0, -boundRectHeightMM / 2.0 );
212  }
213  }
214 
215  if ( mMode == SVG )
216  {
217  mSVG.render( painter, QRectF( 0, 0, boundRectWidthMM, boundRectHeightMM ) );
218  }
219  else if ( mMode == RASTER )
220  {
221  painter->drawImage( QRectF( 0, 0, boundRectWidthMM, boundRectHeightMM ), mImage, imageRect );
222  }
223 
224  painter->restore();
225  }
226 
227  //frame and selection boxes
228  drawFrame( painter );
229  if ( isSelected() )
230  {
231  drawSelectionBoxes( painter );
232  }
233 }
234 
235 QRect QgsComposerPicture::clippedImageRect( double &boundRectWidthMM, double &boundRectHeightMM, QSize imageRectPixels )
236 {
237  int boundRectWidthPixels = boundRectWidthMM * mComposition->printResolution() / 25.4;
238  int boundRectHeightPixels = boundRectHeightMM * mComposition->printResolution() / 25.4;
239 
240  //update boundRectWidth/Height so that they exactly match pixel bounds
241  boundRectWidthMM = boundRectWidthPixels * 25.4 / mComposition->printResolution();
242  boundRectHeightMM = boundRectHeightPixels * 25.4 / mComposition->printResolution();
243 
244  //calculate part of image which fits in bounds
245  int leftClip = 0;
246  int topClip = 0;
247 
248  //calculate left crop
249  switch ( mPictureAnchor )
250  {
251  case UpperLeft:
252  case MiddleLeft:
253  case LowerLeft:
254  leftClip = 0;
255  break;
256  case UpperMiddle:
257  case Middle:
258  case LowerMiddle:
259  leftClip = ( imageRectPixels.width() - boundRectWidthPixels ) / 2;
260  break;
261  case UpperRight:
262  case MiddleRight:
263  case LowerRight:
264  leftClip = imageRectPixels.width() - boundRectWidthPixels;
265  break;
266  }
267 
268  //calculate top crop
269  switch ( mPictureAnchor )
270  {
271  case UpperLeft:
272  case UpperMiddle:
273  case UpperRight:
274  topClip = 0;
275  break;
276  case MiddleLeft:
277  case Middle:
278  case MiddleRight:
279  topClip = ( imageRectPixels.height() - boundRectHeightPixels ) / 2;
280  break;
281  case LowerLeft:
282  case LowerMiddle:
283  case LowerRight:
284  topClip = imageRectPixels.height() - boundRectHeightPixels;
285  break;
286  }
287 
288  return QRect( leftClip, topClip, boundRectWidthPixels, boundRectHeightPixels );
289 }
290 
291 void QgsComposerPicture::setPictureFile( const QString& path )
292 {
293  setPicturePath( path );
294 }
295 
297 {
298  QString source = mSourcePath;
299 
300  //data defined source set?
301  mHasExpressionError = false;
302  QVariant exprVal;
304  {
306  {
307  source = exprVal.toString().trimmed();
308  QgsDebugMsg( QString( "exprVal PictureSource:%1" ).arg( source ) );
309  }
310  else
311  {
312  mHasExpressionError = true;
313  source = QString();
314  QgsMessageLog::logMessage( tr( "Picture expression eval error" ) );
315  }
316  }
317 
318  loadPicture( source );
319 }
320 
321 void QgsComposerPicture::loadRemotePicture( const QString &url )
322 {
323  //remote location
324 
325  QgsNetworkContentFetcher fetcher;
326  //pause until HTML fetch
327  mLoaded = false;
328  fetcher.fetchContent( QUrl( url ) );
329  connect( &fetcher, SIGNAL( finished() ), this, SLOT( remotePictureLoaded() ) );
330 
331  while ( !mLoaded )
332  {
333  qApp->processEvents();
334  }
335 
336  QNetworkReply* reply = fetcher.reply();
337  if ( reply )
338  {
339  QImageReader imageReader( reply );
340  mImage = imageReader.read();
341  mMode = RASTER;
342  reply->deleteLater();
343  }
344  else
345  {
346  mMode = Unknown;
347  }
348 }
349 
350 void QgsComposerPicture::loadLocalPicture( const QString &path )
351 {
352  QFile pic;
353  pic.setFileName( path );
354 
355  if ( !pic.exists() )
356  {
357  mMode = Unknown;
358  }
359  else
360  {
361  QFileInfo sourceFileInfo( pic );
362  QString sourceFileSuffix = sourceFileInfo.suffix();
363  if ( sourceFileSuffix.compare( "svg", Qt::CaseInsensitive ) == 0 )
364  {
365  //try to open svg
366  mSVG.load( pic.fileName() );
367  if ( mSVG.isValid() )
368  {
369  mMode = SVG;
370  QRect viewBox = mSVG.viewBox(); //take width/height ratio from view box instead of default size
371  mDefaultSvgSize.setWidth( viewBox.width() );
372  mDefaultSvgSize.setHeight( viewBox.height() );
373  }
374  else
375  {
376  mMode = Unknown;
377  }
378  }
379  else
380  {
381  //try to open raster with QImageReader
382  QImageReader imageReader( pic.fileName() );
383  if ( imageReader.read( &mImage ) )
384  {
385  mMode = RASTER;
386  }
387  else
388  {
389  mMode = Unknown;
390  }
391  }
392  }
393 
394 }
395 
396 void QgsComposerPicture::remotePictureLoaded()
397 {
398  mLoaded = true;
399 }
400 
401 void QgsComposerPicture::loadPicture( const QString &path )
402 {
403  if ( path.startsWith( "http" ) )
404  {
405  //remote location
406  loadRemotePicture( path );
407  }
408  else
409  {
410  //local location
411  loadLocalPicture( path );
412  }
413  if ( mMode != Unknown ) //make sure we start with a new QImage
414  {
415  recalculateSize();
416  }
417  else if ( mHasExpressionError || !( path.isEmpty() ) )
418  {
419  //trying to load an invalid file or bad expression, show cross picture
420  mMode = SVG;
421  QString badFile = QString( ":/images/composer/missing_image.svg" );
422  mSVG.load( badFile );
423  if ( mSVG.isValid() )
424  {
425  mMode = SVG;
426  QRect viewBox = mSVG.viewBox(); //take width/height ratio from view box instead of default size
427  mDefaultSvgSize.setWidth( viewBox.width() );
428  mDefaultSvgSize.setHeight( viewBox.height() );
429  recalculateSize();
430  }
431  }
432 
433  emit itemChanged();
434 }
435 
436 QRectF QgsComposerPicture::boundedImageRect( double deviceWidth, double deviceHeight )
437 {
438  double imageToDeviceRatio;
439  if ( mImage.width() / deviceWidth > mImage.height() / deviceHeight )
440  {
441  imageToDeviceRatio = deviceWidth / mImage.width();
442  double height = imageToDeviceRatio * mImage.height();
443  return QRectF( 0, 0, deviceWidth, height );
444  }
445  else
446  {
447  imageToDeviceRatio = deviceHeight / mImage.height();
448  double width = imageToDeviceRatio * mImage.width();
449  return QRectF( 0, 0, width, deviceHeight );
450  }
451 }
452 
453 QRectF QgsComposerPicture::boundedSVGRect( double deviceWidth, double deviceHeight )
454 {
455  double imageToSvgRatio;
456  if ( deviceWidth / mDefaultSvgSize.width() > deviceHeight / mDefaultSvgSize.height() )
457  {
458  imageToSvgRatio = deviceHeight / mDefaultSvgSize.height();
459  double width = mDefaultSvgSize.width() * imageToSvgRatio;
460  return QRectF( 0, 0, width, deviceHeight );
461  }
462  else
463  {
464  imageToSvgRatio = deviceWidth / mDefaultSvgSize.width();
465  double height = mDefaultSvgSize.height() * imageToSvgRatio;
466  return QRectF( 0, 0, deviceWidth, height );
467  }
468 }
469 
470 QSizeF QgsComposerPicture::pictureSize()
471 {
472  if ( mMode == SVG )
473  {
474  return mDefaultSvgSize;
475  }
476  else if ( mMode == RASTER )
477  {
478  return QSizeF( mImage.width(), mImage.height() );
479  }
480  else
481  {
482  return QSizeF( 0, 0 );
483  }
484 }
485 
486 #if 0
487 QRectF QgsComposerPicture::boundedSVGRect( double deviceWidth, double deviceHeight )
488 {
489  double imageToSvgRatio;
490  if ( deviceWidth / mDefaultSvgSize.width() < deviceHeight / mDefaultSvgSize.height() )
491  {
492  imageToSvgRatio = deviceWidth / mDefaultSvgSize.width();
493  double height = mDefaultSvgSize.height() * imageToSvgRatio;
494  return QRectF( 0, 0, deviceWidth, height );
495  }
496  else
497  {
498  imageToSvgRatio = deviceHeight / mDefaultSvgSize.height();
499  double width = mDefaultSvgSize.width() * imageToSvgRatio;
500  return QRectF( 0, 0, width, deviceHeight );
501  }
502 }
503 #endif //0
504 
505 void QgsComposerPicture::setSceneRect( const QRectF& rectangle )
506 {
507 
508  QSizeF currentPictureSize = pictureSize();
509 
510  if ( mResizeMode == QgsComposerPicture::Clip )
511  {
512  QgsComposerItem::setSceneRect( rectangle );
513  mPictureWidth = rectangle.width();
514  mPictureHeight = rectangle.height();
515  return;
516  }
517 
518  QRectF newRect = rectangle;
519 
520  if ( mResizeMode == ZoomResizeFrame && !rect().isEmpty() && !( currentPictureSize.isEmpty() ) )
521  {
522  QSizeF targetImageSize;
523  if ( mPictureRotation == 0 )
524  {
525  targetImageSize = currentPictureSize;
526  }
527  else
528  {
529  //calculate aspect ratio of bounds of rotated image
530  QTransform tr;
531  tr.rotate( mPictureRotation );
532  QRectF rotatedBounds = tr.mapRect( QRectF( 0, 0, currentPictureSize.width(), currentPictureSize.height() ) );
533  targetImageSize = QSizeF( rotatedBounds.width(), rotatedBounds.height() );
534  }
535 
536  //if height has changed more than width, then fix width and set height correspondingly
537  //else, do the opposite
538  if ( qAbs( rect().width() - rectangle.width() ) <
539  qAbs( rect().height() - rectangle.height() ) )
540  {
541  newRect.setHeight( targetImageSize.height() * newRect.width() / targetImageSize.width() );
542  }
543  else
544  {
545  newRect.setWidth( targetImageSize.width() * newRect.height() / targetImageSize.height() );
546  }
547  }
548  else if ( mResizeMode == FrameToImageSize )
549  {
550  if ( !( currentPictureSize.isEmpty() ) )
551  {
552  newRect.setWidth( currentPictureSize.width() * 25.4 / mComposition->printResolution() );
553  newRect.setHeight( currentPictureSize.height() * 25.4 / mComposition->printResolution() );
554  }
555  }
556 
557  //find largest scaling of picture with this rotation which fits in item
558  if ( mResizeMode == Zoom || mResizeMode == ZoomResizeFrame )
559  {
560  QRectF rotatedImageRect = QgsComposerUtils::largestRotatedRectWithinBounds( QRectF( 0, 0, currentPictureSize.width(), currentPictureSize.height() ), newRect, mPictureRotation );
561  mPictureWidth = rotatedImageRect.width();
562  mPictureHeight = rotatedImageRect.height();
563  }
564  else
565  {
566  mPictureWidth = newRect.width();
567  mPictureHeight = newRect.height();
568  }
569 
571  emit itemChanged();
572 }
573 
575 {
576  //kept for compatibility for QGIS2.0 api
577  setPictureRotation( r );
578 }
579 
581 {
582  double oldRotation = mPictureRotation;
583  mPictureRotation = r;
584 
585  if ( mResizeMode == Zoom )
586  {
587  //find largest scaling of picture with this rotation which fits in item
588  QSizeF currentPictureSize = pictureSize();
589  QRectF rotatedImageRect = QgsComposerUtils::largestRotatedRectWithinBounds( QRectF( 0, 0, currentPictureSize.width(), currentPictureSize.height() ), rect(), mPictureRotation );
590  mPictureWidth = rotatedImageRect.width();
591  mPictureHeight = rotatedImageRect.height();
592  update();
593  }
594  else if ( mResizeMode == ZoomResizeFrame )
595  {
596  QSizeF currentPictureSize = pictureSize();
597  QRectF oldRect = QRectF( pos().x(), pos().y(), rect().width(), rect().height() );
598 
599  //calculate actual size of image inside frame
600  QRectF rotatedImageRect = QgsComposerUtils::largestRotatedRectWithinBounds( QRectF( 0, 0, currentPictureSize.width(), currentPictureSize.height() ), rect(), oldRotation );
601 
602  //rotate image rect by new rotation and get bounding box
603  QTransform tr;
604  tr.rotate( mPictureRotation );
605  QRectF newRect = tr.mapRect( QRectF( 0, 0, rotatedImageRect.width(), rotatedImageRect.height() ) );
606 
607  //keep the center in the same location
608  newRect.moveCenter( oldRect.center() );
610  emit itemChanged();
611  }
612 
613  emit pictureRotationChanged( mPictureRotation );
614 }
615 
616 void QgsComposerPicture::setRotationMap( int composerMapId )
617 {
618  if ( !mComposition )
619  {
620  return;
621  }
622 
623  if ( composerMapId == -1 ) //disable rotation from map
624  {
625  QObject::disconnect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setPictureRotation( double ) ) );
626  mRotationMap = 0;
627  }
628 
629  const QgsComposerMap* map = mComposition->getComposerMapById( composerMapId );
630  if ( !map )
631  {
632  return;
633  }
634  if ( mRotationMap )
635  {
636  QObject::disconnect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setPictureRotation( double ) ) );
637  }
638  mPictureRotation = map->mapRotation();
639  QObject::connect( map, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setPictureRotation( double ) ) );
640  mRotationMap = map;
641  update();
642  emit pictureRotationChanged( mPictureRotation );
643 }
644 
646 {
647  mResizeMode = mode;
649  || ( mode == QgsComposerPicture::Zoom && mPictureRotation != 0 ) )
650  {
651  //call set scene rect to force item to resize to fit picture
652  recalculateSize();
653  }
654  update();
655 }
656 
658 {
659  //call set scene rect with current position/size, as this will trigger the
660  //picture item to recalculate its frame and image size
661  setSceneRect( QRectF( pos().x(), pos().y(), rect().width(), rect().height() ) );
662 }
663 
665 {
667  {
668  refreshPicture();
669  }
670 
672 }
673 
675 {
677  refreshPicture();
678 }
679 
681 {
683  refreshPicture();
684 }
685 
687 {
688  return picturePath();
689 }
690 
691 void QgsComposerPicture::setPicturePath( const QString &path )
692 {
693  mSourcePath = path;
694  refreshPicture();
695 }
696 
698 {
699  return mSourcePath;
700 }
701 
702 bool QgsComposerPicture::writeXML( QDomElement& elem, QDomDocument & doc ) const
703 {
704  if ( elem.isNull() )
705  {
706  return false;
707  }
708  QDomElement composerPictureElem = doc.createElement( "ComposerPicture" );
709  composerPictureElem.setAttribute( "file", QgsProject::instance()->writePath( mSourcePath ) );
710  composerPictureElem.setAttribute( "pictureWidth", QString::number( mPictureWidth ) );
711  composerPictureElem.setAttribute( "pictureHeight", QString::number( mPictureHeight ) );
712  composerPictureElem.setAttribute( "resizeMode", QString::number(( int )mResizeMode ) );
713  composerPictureElem.setAttribute( "anchorPoint", QString::number(( int )mPictureAnchor ) );
714 
715  //rotation
716  composerPictureElem.setAttribute( "pictureRotation", QString::number( mPictureRotation ) );
717  if ( !mRotationMap )
718  {
719  composerPictureElem.setAttribute( "mapId", -1 );
720  }
721  else
722  {
723  composerPictureElem.setAttribute( "mapId", mRotationMap->id() );
724  }
725 
726  _writeXML( composerPictureElem, doc );
727  elem.appendChild( composerPictureElem );
728  return true;
729 }
730 
731 bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocument& doc )
732 {
733  if ( itemElem.isNull() )
734  {
735  return false;
736  }
737 
738  mPictureWidth = itemElem.attribute( "pictureWidth", "10" ).toDouble();
739  mPictureHeight = itemElem.attribute( "pictureHeight", "10" ).toDouble();
740  mResizeMode = QgsComposerPicture::ResizeMode( itemElem.attribute( "resizeMode", "0" ).toInt() );
741  //when loading from xml, default to anchor point of middle to match pre 2.4 behaviour
742  mPictureAnchor = ( QgsComposerItem::ItemPositionMode ) itemElem.attribute( "anchorPoint", QString::number( QgsComposerItem::Middle ) ).toInt();
743 
744  QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
745  if ( composerItemList.size() > 0 )
746  {
747  QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
748 
749  if ( composerItemElem.attribute( "rotation", "0" ).toDouble() != 0 )
750  {
751  //in versions prior to 2.1 picture rotation was stored in the rotation attribute
752  mPictureRotation = composerItemElem.attribute( "rotation", "0" ).toDouble();
753  }
754 
755  _readXML( composerItemElem, doc );
756  }
757 
758  mDefaultSvgSize = QSize( 0, 0 );
759 
760  if ( itemElem.hasAttribute( "sourceExpression" ) )
761  {
762  //update pre 2.5 picture expression to use data defined expression
763  QString sourceExpression = itemElem.attribute( "sourceExpression", "" );
764  QString useExpression = itemElem.attribute( "useExpression" );
765  bool expressionActive;
766  if ( useExpression.compare( "true", Qt::CaseInsensitive ) == 0 )
767  {
768  expressionActive = true;
769  }
770  else
771  {
772  expressionActive = false;
773  }
774 
775  setDataDefinedProperty( QgsComposerObject::PictureSource, expressionActive, true, sourceExpression, QString() );
776  }
777 
778  mSourcePath = QgsProject::instance()->readPath( itemElem.attribute( "file" ) );
779 
780  //picture rotation
781  if ( itemElem.attribute( "pictureRotation", "0" ).toDouble() != 0 )
782  {
783  mPictureRotation = itemElem.attribute( "pictureRotation", "0" ).toDouble();
784  }
785 
786  //rotation map
787  int rotationMapId = itemElem.attribute( "mapId", "-1" ).toInt();
788  if ( rotationMapId == -1 )
789  {
790  mRotationMap = 0;
791  }
792  else if ( mComposition )
793  {
794 
795  if ( mRotationMap )
796  {
797  QObject::disconnect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
798  }
799  mRotationMap = mComposition->getComposerMapById( rotationMapId );
800  QObject::connect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
801  }
802 
803  refreshPicture();
804 
805  emit itemChanged();
806  return true;
807 }
808 
810 {
811  if ( !mRotationMap )
812  {
813  return -1;
814  }
815  else
816  {
817  return mRotationMap->id();
818  }
819 }
820 
822 {
823  mPictureAnchor = anchor;
824  update();
825 }
826 
828 {
830 }
831 
833 {
835 }
836 
837 bool QgsComposerPicture::imageSizeConsideringRotation( double& width, double& height ) const
838 {
839  //kept for api compatibility with QGIS 2.0 - use mPictureRotation
841  return QgsComposerItem::imageSizeConsideringRotation( width, height, mPictureRotation );
843 }
844 
845 bool QgsComposerPicture::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const
846 {
847  //kept for api compatibility with QGIS 2.0 - use mPictureRotation
849  return QgsComposerItem::cornerPointOnRotatedAndScaledRect( x, y, width, height, mPictureRotation );
851 }
852 
853 void QgsComposerPicture::sizeChangedByRotation( double& width, double& height )
854 {
855  //kept for api compatibility with QGIS 2.0 - use mPictureRotation
857  return QgsComposerItem::sizeChangedByRotation( width, height, mPictureRotation );
859 }