Quantum GIS API Documentation  1.7.5-Wroclaw
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator 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 /* $Id$ */
18 
19 #include "qgscomposerpicture.h"
20 #include "qgscomposermap.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 
30 QgsComposerPicture::QgsComposerPicture( QgsComposition *composition ): QgsComposerItem( composition ), mMode( Unknown ), \
31  mRotationMap( 0 )
32 {
33  mPictureWidth = rect().width();
34 }
35 
36 QgsComposerPicture::QgsComposerPicture(): QgsComposerItem( 0 ), mMode( Unknown ), mRotationMap( 0 )
37 {
38  mPictureHeight = rect().height();
39 }
40 
41 
43 {
44 
45 }
46 
47 void QgsComposerPicture::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
48 {
49  if ( !painter )
50  {
51  return;
52  }
53 
54  drawBackground( painter );
55 
56  int newDpi = ( painter->device()->logicalDpiX() + painter->device()->logicalDpiY() ) / 2;
57 
58  if ( mMode != Unknown )
59  {
60  double rectPixelWidth = /*rect().width()*/mPictureWidth * newDpi / 25.4;
61  double rectPixelHeight = /*rect().height()*/ mPictureHeight * newDpi / 25.4;
62  QRectF boundRect;
63  if ( mMode == SVG )
64  {
65  boundRect = boundedSVGRect( rectPixelWidth, rectPixelHeight );
66  }
67  else if ( mMode == RASTER )
68  {
69  boundRect = boundedImageRect( rectPixelWidth, rectPixelHeight );
70  }
71 
72  double boundRectWidthMM = boundRect.width() / newDpi * 25.4;
73  double boundRectHeightMM = boundRect.height() / newDpi * 25.4;
74 
75  painter->save();
76  painter->translate( rect().width() / 2.0, rect().height() / 2.0 );
77  painter->rotate( mRotation );
78  painter->translate( -boundRectWidthMM / 2.0, -boundRectHeightMM / 2.0 );
79 
80  if ( mMode == SVG )
81  {
82  mSVG.render( painter, QRectF( 0, 0, boundRectWidthMM, boundRectHeightMM ) );
83  }
84  else if ( mMode == RASTER )
85  {
86  painter->drawImage( QRectF( 0, 0, boundRectWidthMM, boundRectHeightMM ), mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) );
87  }
88 
89  painter->restore();
90  }
91 
92  //frame and selection boxes
93  drawFrame( painter );
94  if ( isSelected() )
95  {
96  drawSelectionBoxes( painter );
97  }
98 }
99 
100 void QgsComposerPicture::setPictureFile( const QString& path )
101 {
102  mSourceFile.setFileName( path );
103  if ( !mSourceFile.exists() )
104  {
105  mMode = Unknown;
106  }
107 
108  QFileInfo sourceFileInfo( mSourceFile );
109  QString sourceFileSuffix = sourceFileInfo.suffix();
110  if ( sourceFileSuffix.compare( "svg", Qt::CaseInsensitive ) == 0 )
111  {
112  //try to open svg
113  mSVG.load( mSourceFile.fileName() );
114  if ( mSVG.isValid() )
115  {
116  mMode = SVG;
117  QRect viewBox = mSVG.viewBox(); //take width/height ratio from view box instead of default size
118  mDefaultSvgSize.setWidth( viewBox.width() );
119  mDefaultSvgSize.setHeight( viewBox.height() );
120  }
121  else
122  {
123  mMode = Unknown;
124  }
125  }
126  else
127  {
128  //try to open raster with QImageReader
129  QImageReader imageReader( mSourceFile.fileName() );
130  if ( imageReader.read( &mImage ) )
131  {
132  mMode = RASTER;
133  }
134  else
135  {
136  mMode = Unknown;
137  }
138  }
139 
140  if ( mMode != Unknown ) //make sure we start with a new QImage
141  {
142  setSceneRect( QRectF( transform().dx(), transform().dy(), rect().width(), rect().height() ) );
143  }
144  emit itemChanged();
145 }
146 
147 QRectF QgsComposerPicture::boundedImageRect( double deviceWidth, double deviceHeight )
148 {
149  double imageToDeviceRatio;
150  if ( mImage.width() / deviceWidth > mImage.height() / deviceHeight )
151  {
152  imageToDeviceRatio = deviceWidth / mImage.width();
153  double height = imageToDeviceRatio * mImage.height();
154  return QRectF( 0, 0, deviceWidth, height );
155  }
156  else
157  {
158  imageToDeviceRatio = deviceHeight / mImage.height();
159  double width = imageToDeviceRatio * mImage.width();
160  return QRectF( 0, 0, width, deviceHeight );
161  }
162 }
163 
164 QRectF QgsComposerPicture::boundedSVGRect( double deviceWidth, double deviceHeight )
165 {
166  double imageToSvgRatio;
167  if ( deviceWidth / mDefaultSvgSize.width() > deviceHeight / mDefaultSvgSize.height() )
168  {
169  imageToSvgRatio = deviceHeight / mDefaultSvgSize.height();
170  double width = mDefaultSvgSize.width() * imageToSvgRatio;
171  return QRectF( 0, 0, width, deviceHeight );
172  }
173  else
174  {
175  imageToSvgRatio = deviceWidth / mDefaultSvgSize.width();
176  double height = mDefaultSvgSize.height() * imageToSvgRatio;
177  return QRectF( 0, 0, deviceWidth, height );
178  }
179 }
180 
181 #if 0
182 QRectF QgsComposerPicture::boundedSVGRect( double deviceWidth, double deviceHeight )
183 {
184  double imageToSvgRatio;
185  if ( deviceWidth / mDefaultSvgSize.width() < deviceHeight / mDefaultSvgSize.height() )
186  {
187  imageToSvgRatio = deviceWidth / mDefaultSvgSize.width();
188  double height = mDefaultSvgSize.height() * imageToSvgRatio;
189  return QRectF( 0, 0, deviceWidth, height );
190  }
191  else
192  {
193  imageToSvgRatio = deviceHeight / mDefaultSvgSize.height();
194  double width = mDefaultSvgSize.width() * imageToSvgRatio;
195  return QRectF( 0, 0, width, deviceHeight );
196  }
197 }
198 #endif //0
199 
200 void QgsComposerPicture::setSceneRect( const QRectF& rectangle )
201 {
202  QgsComposerItem::setSceneRect( rectangle );
203 
204  //consider to change size of the shape if the rectangle changes width and/or height
205  double newPictureWidth = rectangle.width();
206  double newPictureHeight = rectangle.height();
207  imageSizeConsideringRotation( newPictureWidth, newPictureHeight );
208  mPictureWidth = newPictureWidth;
209  mPictureHeight = newPictureHeight;
210 
211  emit itemChanged();
212 }
213 
215 {
216  //adapt rectangle size
217  double width = mPictureWidth;
218  double height = mPictureHeight;
219  sizeChangedByRotation( width, height );
220 
221  //adapt scene rect to have the same center and the new width / height
222  double x = transform().dx() + rect().width() / 2.0 - width / 2.0;
223  double y = transform().dy() + rect().height() / 2.0 - height / 2.0;
224  QgsComposerItem::setSceneRect( QRectF( x, y, width, height ) );
225 
227 }
228 
229 void QgsComposerPicture::setRotationMap( int composerMapId )
230 {
231  if ( !mComposition )
232  {
233  return;
234  }
235 
236  if ( composerMapId == -1 ) //disable rotation from map
237  {
238  QObject::disconnect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
239  mRotationMap = 0;
240  }
241 
242  const QgsComposerMap* map = mComposition->getComposerMapById( composerMapId );
243  if ( !map )
244  {
245  return;
246  }
247  if ( mRotationMap )
248  {
249  QObject::disconnect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
250  }
251  mRotation = map->rotation();
252  QObject::connect( map, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
253  mRotationMap = map;
254  setRotation( map->rotation() );
255 }
256 
258 {
259  return mSourceFile.fileName();
260 }
261 
262 bool QgsComposerPicture::writeXML( QDomElement& elem, QDomDocument & doc ) const
263 {
264  if ( elem.isNull() )
265  {
266  return false;
267  }
268  QDomElement composerPictureElem = doc.createElement( "ComposerPicture" );
269  composerPictureElem.setAttribute( "file", QgsProject::instance()->writePath( mSourceFile.fileName() ) );
270  composerPictureElem.setAttribute( "pictureWidth", mPictureWidth );
271  composerPictureElem.setAttribute( "pictureHeight", mPictureHeight );
272  if ( !mRotationMap )
273  {
274  composerPictureElem.setAttribute( "mapId", -1 );
275  }
276  else
277  {
278  composerPictureElem.setAttribute( "mapId", mRotationMap->id() );
279  }
280 
281  _writeXML( composerPictureElem, doc );
282  elem.appendChild( composerPictureElem );
283  return true;
284 }
285 
286 bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocument& doc )
287 {
288  if ( itemElem.isNull() )
289  {
290  return false;
291  }
292 
293  mPictureWidth = itemElem.attribute( "pictureWidth", "10" ).toDouble();
294  mPictureHeight = itemElem.attribute( "pictureHeight", "10" ).toDouble();
295 
296  QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
297  if ( composerItemList.size() > 0 )
298  {
299  _readXML( composerItemList.at( 0 ).toElement(), doc );
300  }
301 
302 
303  mDefaultSvgSize = QSize( 0, 0 );
304 
305  QString fileName = QgsProject::instance()->readPath( itemElem.attribute( "file" ) );
306  setPictureFile( fileName );
307 
308  //rotation map
309  int rotationMapId = itemElem.attribute( "mapId", "-1" ).toInt();
310  if ( rotationMapId == -1 )
311  {
312  mRotationMap = 0;
313  }
314  else if ( mComposition )
315  {
316 
317  if ( mRotationMap )
318  {
319  QObject::disconnect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
320  }
321  mRotationMap = mComposition->getComposerMapById( rotationMapId );
322  QObject::connect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
323  }
324 
325  emit itemChanged();
326  return true;
327 }
328 
330 {
331  if ( !mRotationMap )
332  {
333  return -1;
334  }
335  else
336  {
337  return mRotationMap->id();
338  }
339 }