QGIS API Documentation  2.2.0-Valmiera
 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 : [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 "qgscomposerpicture.h"
19 #include "qgscomposermap.h"
20 #include "qgscomposition.h"
21 #include "qgsproject.h"
22 #include <QDomDocument>
23 #include <QDomElement>
24 #include <QFileInfo>
25 #include <QImageReader>
26 #include <QPainter>
27 #include <QSvgRenderer>
28 
29 
31  : QgsComposerItem( composition ), mMode( Unknown ), mPictureRotation( 0 ), mRotationMap( 0 )
32 {
33  mPictureWidth = rect().width();
34 }
35 
36 QgsComposerPicture::QgsComposerPicture(): QgsComposerItem( 0 ), mMode( Unknown ), mPictureRotation( 0 ), mRotationMap( 0 )
37 {
38  mPictureHeight = rect().height();
39 }
40 
42 {
43 
44 }
45 
46 void QgsComposerPicture::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
47 {
48  Q_UNUSED( itemStyle );
49  Q_UNUSED( pWidget );
50  if ( !painter )
51  {
52  return;
53  }
54 
55  drawBackground( painter );
56 
57  //int newDpi = ( painter->device()->logicalDpiX() + painter->device()->logicalDpiY() ) / 2;
58 
59  if ( mMode != Unknown )
60  {
61  double boundRectWidthMM = mPictureWidth;
62  double boundRectHeightMM = mPictureHeight;
63 
64  painter->save();
65  painter->translate( rect().width() / 2.0, rect().height() / 2.0 );
66  painter->rotate( mPictureRotation );
67  painter->translate( -boundRectWidthMM / 2.0, -boundRectHeightMM / 2.0 );
68 
69  if ( mMode == SVG )
70  {
71  mSVG.render( painter, QRectF( 0, 0, boundRectWidthMM, boundRectHeightMM ) );
72  }
73  else if ( mMode == RASTER )
74  {
75  painter->drawImage( QRectF( 0, 0, boundRectWidthMM, boundRectHeightMM ), mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) );
76  }
77 
78  painter->restore();
79  }
80 
81  //frame and selection boxes
82  drawFrame( painter );
83  if ( isSelected() )
84  {
85  drawSelectionBoxes( painter );
86  }
87 }
88 
89 void QgsComposerPicture::setPictureFile( const QString& path )
90 {
91  mSourceFile.setFileName( path );
92  if ( !mSourceFile.exists() )
93  {
94  mMode = Unknown;
95  }
96 
97  QFileInfo sourceFileInfo( mSourceFile );
98  QString sourceFileSuffix = sourceFileInfo.suffix();
99  if ( sourceFileSuffix.compare( "svg", Qt::CaseInsensitive ) == 0 )
100  {
101  //try to open svg
102  mSVG.load( mSourceFile.fileName() );
103  if ( mSVG.isValid() )
104  {
105  mMode = SVG;
106  QRect viewBox = mSVG.viewBox(); //take width/height ratio from view box instead of default size
107  mDefaultSvgSize.setWidth( viewBox.width() );
108  mDefaultSvgSize.setHeight( viewBox.height() );
109  }
110  else
111  {
112  mMode = Unknown;
113  }
114  }
115  else
116  {
117  //try to open raster with QImageReader
118  QImageReader imageReader( mSourceFile.fileName() );
119  if ( imageReader.read( &mImage ) )
120  {
121  mMode = RASTER;
122  }
123  else
124  {
125  mMode = Unknown;
126  }
127  }
128 
129  if ( mMode != Unknown ) //make sure we start with a new QImage
130  {
131  setSceneRect( QRectF( pos().x(), pos().y(), rect().width(), rect().height() ) );
132  }
133  emit itemChanged();
134 }
135 
136 QRectF QgsComposerPicture::boundedImageRect( double deviceWidth, double deviceHeight )
137 {
138  double imageToDeviceRatio;
139  if ( mImage.width() / deviceWidth > mImage.height() / deviceHeight )
140  {
141  imageToDeviceRatio = deviceWidth / mImage.width();
142  double height = imageToDeviceRatio * mImage.height();
143  return QRectF( 0, 0, deviceWidth, height );
144  }
145  else
146  {
147  imageToDeviceRatio = deviceHeight / mImage.height();
148  double width = imageToDeviceRatio * mImage.width();
149  return QRectF( 0, 0, width, deviceHeight );
150  }
151 }
152 
153 QRectF QgsComposerPicture::boundedSVGRect( double deviceWidth, double deviceHeight )
154 {
155  double imageToSvgRatio;
156  if ( deviceWidth / mDefaultSvgSize.width() > deviceHeight / mDefaultSvgSize.height() )
157  {
158  imageToSvgRatio = deviceHeight / mDefaultSvgSize.height();
159  double width = mDefaultSvgSize.width() * imageToSvgRatio;
160  return QRectF( 0, 0, width, deviceHeight );
161  }
162  else
163  {
164  imageToSvgRatio = deviceWidth / mDefaultSvgSize.width();
165  double height = mDefaultSvgSize.height() * imageToSvgRatio;
166  return QRectF( 0, 0, deviceWidth, height );
167  }
168 }
169 
171 {
172  if ( mMode == SVG )
173  {
174  return mDefaultSvgSize;
175  }
176  else if ( mMode == RASTER )
177  {
178  return QSizeF( mImage.width(), mImage.height() );
179  }
180  else
181  {
182  return QSizeF( 0, 0 );
183  }
184 }
185 
186 #if 0
187 QRectF QgsComposerPicture::boundedSVGRect( double deviceWidth, double deviceHeight )
188 {
189  double imageToSvgRatio;
190  if ( deviceWidth / mDefaultSvgSize.width() < deviceHeight / mDefaultSvgSize.height() )
191  {
192  imageToSvgRatio = deviceWidth / mDefaultSvgSize.width();
193  double height = mDefaultSvgSize.height() * imageToSvgRatio;
194  return QRectF( 0, 0, deviceWidth, height );
195  }
196  else
197  {
198  imageToSvgRatio = deviceHeight / mDefaultSvgSize.height();
199  double width = mDefaultSvgSize.width() * imageToSvgRatio;
200  return QRectF( 0, 0, width, deviceHeight );
201  }
202 }
203 #endif //0
204 
205 void QgsComposerPicture::setSceneRect( const QRectF& rectangle )
206 {
207  QgsComposerItem::setSceneRect( rectangle );
208 
209  //find largest scaling of picture with this rotation which fits in item
210  QSizeF currentPictureSize = pictureSize();
211  QRectF rotatedImageRect = largestRotatedRectWithinBounds( QRectF( 0, 0, currentPictureSize.width(), currentPictureSize.height() ), rectangle, mPictureRotation );
212  mPictureWidth = rotatedImageRect.width();
213  mPictureHeight = rotatedImageRect.height();
214 
215  emit itemChanged();
216 }
217 
219 {
220  //kept for compatibility for QGIS2.0 api
221  setPictureRotation( r );
222 }
223 
225 {
226  mPictureRotation = r;
227 
228  //find largest scaling of picture with this rotation which fits in item
229  QSizeF currentPictureSize = pictureSize();
230  QRectF rotatedImageRect = largestRotatedRectWithinBounds( QRectF( 0, 0, currentPictureSize.width(), currentPictureSize.height() ), rect(), mPictureRotation );
231  mPictureWidth = rotatedImageRect.width();
232  mPictureHeight = rotatedImageRect.height();
233 
234  update();
236 }
237 
238 void QgsComposerPicture::setRotationMap( int composerMapId )
239 {
240  if ( !mComposition )
241  {
242  return;
243  }
244 
245  if ( composerMapId == -1 ) //disable rotation from map
246  {
247  QObject::disconnect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setPictureRotation( double ) ) );
248  mRotationMap = 0;
249  }
250 
251  const QgsComposerMap* map = mComposition->getComposerMapById( composerMapId );
252  if ( !map )
253  {
254  return;
255  }
256  if ( mRotationMap )
257  {
258  QObject::disconnect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setPictureRotation( double ) ) );
259  }
260  mPictureRotation = map->mapRotation();
261  QObject::connect( map, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setPictureRotation( double ) ) );
262  mRotationMap = map;
263  update();
265 }
266 
268 {
269  return mSourceFile.fileName();
270 }
271 
272 bool QgsComposerPicture::writeXML( QDomElement& elem, QDomDocument & doc ) const
273 {
274  if ( elem.isNull() )
275  {
276  return false;
277  }
278  QDomElement composerPictureElem = doc.createElement( "ComposerPicture" );
279  composerPictureElem.setAttribute( "file", QgsProject::instance()->writePath( mSourceFile.fileName() ) );
280  composerPictureElem.setAttribute( "pictureWidth", QString::number( mPictureWidth ) );
281  composerPictureElem.setAttribute( "pictureHeight", QString::number( mPictureHeight ) );
282 
283  //rotation
284  composerPictureElem.setAttribute( "pictureRotation", QString::number( mPictureRotation ) );
285  if ( !mRotationMap )
286  {
287  composerPictureElem.setAttribute( "mapId", -1 );
288  }
289  else
290  {
291  composerPictureElem.setAttribute( "mapId", mRotationMap->id() );
292  }
293 
294  _writeXML( composerPictureElem, doc );
295  elem.appendChild( composerPictureElem );
296  return true;
297 }
298 
299 bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocument& doc )
300 {
301  if ( itemElem.isNull() )
302  {
303  return false;
304  }
305 
306  mPictureWidth = itemElem.attribute( "pictureWidth", "10" ).toDouble();
307  mPictureHeight = itemElem.attribute( "pictureHeight", "10" ).toDouble();
308 
309  QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
310  if ( composerItemList.size() > 0 )
311  {
312  QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
313 
314  if ( composerItemElem.attribute( "rotation", "0" ).toDouble() != 0 )
315  {
316  //in versions prior to 2.1 picture rotation was stored in the rotation attribute
317  mPictureRotation = composerItemElem.attribute( "rotation", "0" ).toDouble();
318  }
319 
320  _readXML( composerItemElem, doc );
321  }
322 
323  mDefaultSvgSize = QSize( 0, 0 );
324 
325  QString fileName = QgsProject::instance()->readPath( itemElem.attribute( "file" ) );
326  setPictureFile( fileName );
327 
328  //picture rotation
329  if ( itemElem.attribute( "pictureRotation", "0" ).toDouble() != 0 )
330  {
331  mPictureRotation = itemElem.attribute( "pictureRotation", "0" ).toDouble();
332  }
333 
334  //rotation map
335  int rotationMapId = itemElem.attribute( "mapId", "-1" ).toInt();
336  if ( rotationMapId == -1 )
337  {
338  mRotationMap = 0;
339  }
340  else if ( mComposition )
341  {
342 
343  if ( mRotationMap )
344  {
345  QObject::disconnect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
346  }
347  mRotationMap = mComposition->getComposerMapById( rotationMapId );
348  QObject::connect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
349  }
350 
351  emit itemChanged();
352  return true;
353 }
354 
356 {
357  if ( !mRotationMap )
358  {
359  return -1;
360  }
361  else
362  {
363  return mRotationMap->id();
364  }
365 }
366 
367 bool QgsComposerPicture::imageSizeConsideringRotation( double& width, double& height ) const
368 {
369  //kept for api compatibility with QGIS 2.0 - use mPictureRotation
371 }
372 
373 bool QgsComposerPicture::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const
374 {
375  //kept for api compatibility with QGIS 2.0 - use mPictureRotation
377 }
378 
379 void QgsComposerPicture::sizeChangedByRotation( double& width, double& height )
380 {
381  //kept for api compatibility with QGIS 2.0 - use mPictureRotation
383 }