QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules 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 }
void setActive(bool active)
Q_DECL_DEPRECATED bool imageSizeConsideringRotation(double &width, double &height, double rotation) const
Calculates width and hight of the picture (in mm) such that it fits into the item frame with the give...
void setSceneRect(const QRectF &rectangle)
Sets this items bound in scene coordinates such that 1 item size units corresponds to 1 scene size un...
bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
Sets state from Dom document.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void itemChanged()
Emitted when the item changes.
QgsComposerPicture(QgsComposition *composition)
Q_DECL_DEPRECATED bool imageSizeConsideringRotation(double &width, double &height) const
Calculates width and hight of the picture (in mm) such that it fits into the item frame with the give...
Mode mode() const
Returns the current picture mode (image format).
QMap< QgsComposerObject::DataDefinedProperty, QString > mDataDefinedNames
Map of data defined properties for the item to string name to use when exporting item to xml...
A item that forms part of a map composition.
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:435
static QRectF largestRotatedRectWithinBounds(const QRectF originalRect, const QRectF boundsRect, const double rotation)
Calculates the largest scaled version of originalRect which fits within boundsRect, when it is rotated by a specified amount.
void fetchContent(const QUrl url)
Fetches content from a remote URL and handles redirects.
virtual void setRotation(double r)
Sets the picture rotation within the item bounds.
QString expressionString() const
virtual void drawFrame(QPainter *p)
Draw black frame around item.
QString picturePath() const
Returns the path of the source image.
QNetworkReply * reply()
Returns a reference to the network reply.
DataDefinedProperty
Data defined properties for different item types.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:113
QString readPath(QString filename) const
turn filename read from the project file to an absolute path
bool dataDefinedEvaluate(const QgsComposerObject::DataDefinedProperty property, QVariant &expressionValue)
Evaluate a data defined property and return the calculated value.
A composer class that displays svg files or raster format (jpg, png, ...)
static void logMessage(QString message, QString tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
void recalculateSize()
Forces a recalculation of the picture's frame size.
bool _readXML(const QDomElement &itemElem, const QDomDocument &doc)
Reads parameter that are not subclass specific in document.
QgsDataDefined * dataDefinedProperty(const DataDefinedProperty property) const
Returns a reference to the data defined settings for one of the item's data defined properties...
void setPictureAnchor(QgsComposerItem::ItemPositionMode anchor)
Sets the picture's anchor point, which controls how it is placed within the picture item's frame...
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget)
Reimplementation of QCanvasItem::paint.
virtual void refreshDataDefinedProperty(const QgsComposerObject::DataDefinedProperty property=QgsComposerObject::AllProperties)
Refreshes a data defined property for the item by reevaluating the property's value and redrawing the...
HTTP network content fetcher.
virtual void drawSelectionBoxes(QPainter *p)
Draws additional graphics on selected items.
int printResolution() const
virtual void setResizeMode(ResizeMode mode)
Sets the resize mode used for drawing the picture within the item bounds.
virtual void setUsePictureExpression(bool useExpression)
Sets whether the picture should use an expression based image source path.
bool shouldDrawItem() const
Returns whether the item should be drawn in the current context.
double mapRotation(QgsComposerObject::PropertyValueType valueType=QgsComposerObject::EvaluatedValue) const
Returns the rotation used for drawing the map within the composer item.
void setBackgroundEnabled(const bool drawBackground)
Set whether this item has a Background drawn around it or not.
Graphics scene for map printing.
Object representing map window.
Q_DECL_DEPRECATED QString pictureFile() const
Returns the path of the source image file.
bool writeXML(QDomElement &elem, QDomDocument &doc) const
Stores state in Dom element.
Q_DECL_DEPRECATED bool cornerPointOnRotatedAndScaledRect(double &x, double &y, double width, double height) const
Calculates corner point after rotation and scaling.
void pictureRotationChanged(double newRotation)
Is emitted on picture rotation change.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:436
int id() const
Get identification number.
Q_DECL_DEPRECATED void setPictureFile(const QString &path)
Sets the source file of the image (may be svg or a raster format).
QgsComposition * mComposition
void refreshPicture()
Recalculates the source image (if using an expression for picture's source) and reloads and redraws t...
virtual void refreshDataDefinedProperty(const QgsComposerObject::DataDefinedProperty property=QgsComposerObject::AllProperties)
Refreshes a data defined property for the item by reevaluating the property's value and redrawing the...
Q_DECL_DEPRECATED bool cornerPointOnRotatedAndScaledRect(double &x, double &y, double width, double height, double rotation) const
Calculates corner point after rotation and scaling.
bool _writeXML(QDomElement &itemElem, QDomDocument &doc) const
Writes parameter that are not subclass specific in document.
virtual void drawBackground(QPainter *p)
Draw background.
Q_DECL_DEPRECATED QString pictureExpression() const
Returns the expression the item is using for the picture source.
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:362
virtual void setSceneRect(const QRectF &rectangle)
Sets this items bound in scene coordinates such that 1 item size units corresponds to 1 scene size un...
void setDataDefinedProperty(const DataDefinedProperty property, const bool active, const bool useExpression, const QString &expression, const QString &field)
Sets parameters for a data defined property for the item.
QgsAtlasComposition & atlasComposition()
void setRotationMap(int composerMapId)
Sets the map object for rotation (by id).
void setPicturePath(const QString &path)
Sets the source path of the image (may be svg or a raster format).
virtual void setPictureRotation(double r)
Sets the picture rotation within the item bounds.
const QgsComposerMap * getComposerMapById(const int id) const
Returns the composer map with specified id.
int rotationMap() const
Returns the id of the rotation map.
void setExpressionString(const QString &expr)
bool isActive() const
virtual void setPictureExpression(QString expression)
Sets an expression to use for the picture source.
Q_DECL_DEPRECATED void sizeChangedByRotation(double &width, double &height, double rotation)
Calculates width / height of the bounding box of a rotated rectangle.
Q_DECL_DEPRECATED bool usePictureExpression() const
Returns whether the picture item is using an expression for the image source.
Q_DECL_DEPRECATED void sizeChangedByRotation(double &width, double &height)
Calculates width / height of the bounding box of a rotated rectangle.
#define tr(sourceText)