QGIS API Documentation  2.0.1-Dufour
 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 "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 ), mRotationMap( 0 )
32 {
33  mPictureWidth = rect().width();
34 }
35 
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  Q_UNUSED( itemStyle );
50  Q_UNUSED( pWidget );
51  if ( !painter )
52  {
53  return;
54  }
55 
56  drawBackground( painter );
57 
58  int newDpi = ( painter->device()->logicalDpiX() + painter->device()->logicalDpiY() ) / 2;
59 
60  if ( mMode != Unknown )
61  {
62  double rectPixelWidth = /*rect().width()*/mPictureWidth * newDpi / 25.4;
63  double rectPixelHeight = /*rect().height()*/ mPictureHeight * newDpi / 25.4;
64  QRectF boundRect;
65  if ( mMode == SVG )
66  {
67  boundRect = boundedSVGRect( rectPixelWidth, rectPixelHeight );
68  }
69  else if ( mMode == RASTER )
70  {
71  boundRect = boundedImageRect( rectPixelWidth, rectPixelHeight );
72  }
73 
74  double boundRectWidthMM = boundRect.width() / newDpi * 25.4;
75  double boundRectHeightMM = boundRect.height() / newDpi * 25.4;
76 
77  painter->save();
78  painter->translate( rect().width() / 2.0, rect().height() / 2.0 );
79  painter->rotate( mRotation );
80  painter->translate( -boundRectWidthMM / 2.0, -boundRectHeightMM / 2.0 );
81 
82  if ( mMode == SVG )
83  {
84  mSVG.render( painter, QRectF( 0, 0, boundRectWidthMM, boundRectHeightMM ) );
85  }
86  else if ( mMode == RASTER )
87  {
88  painter->drawImage( QRectF( 0, 0, boundRectWidthMM, boundRectHeightMM ), mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) );
89  }
90 
91  painter->restore();
92  }
93 
94  //frame and selection boxes
95  drawFrame( painter );
96  if ( isSelected() )
97  {
98  drawSelectionBoxes( painter );
99  }
100 }
101 
102 void QgsComposerPicture::setPictureFile( const QString& path )
103 {
104  mSourceFile.setFileName( path );
105  if ( !mSourceFile.exists() )
106  {
107  mMode = Unknown;
108  }
109 
110  QFileInfo sourceFileInfo( mSourceFile );
111  QString sourceFileSuffix = sourceFileInfo.suffix();
112  if ( sourceFileSuffix.compare( "svg", Qt::CaseInsensitive ) == 0 )
113  {
114  //try to open svg
115  mSVG.load( mSourceFile.fileName() );
116  if ( mSVG.isValid() )
117  {
118  mMode = SVG;
119  QRect viewBox = mSVG.viewBox(); //take width/height ratio from view box instead of default size
120  mDefaultSvgSize.setWidth( viewBox.width() );
121  mDefaultSvgSize.setHeight( viewBox.height() );
122  }
123  else
124  {
125  mMode = Unknown;
126  }
127  }
128  else
129  {
130  //try to open raster with QImageReader
131  QImageReader imageReader( mSourceFile.fileName() );
132  if ( imageReader.read( &mImage ) )
133  {
134  mMode = RASTER;
135  }
136  else
137  {
138  mMode = Unknown;
139  }
140  }
141 
142  if ( mMode != Unknown ) //make sure we start with a new QImage
143  {
144  setSceneRect( QRectF( transform().dx(), transform().dy(), rect().width(), rect().height() ) );
145  }
146  emit itemChanged();
147 }
148 
149 QRectF QgsComposerPicture::boundedImageRect( double deviceWidth, double deviceHeight )
150 {
151  double imageToDeviceRatio;
152  if ( mImage.width() / deviceWidth > mImage.height() / deviceHeight )
153  {
154  imageToDeviceRatio = deviceWidth / mImage.width();
155  double height = imageToDeviceRatio * mImage.height();
156  return QRectF( 0, 0, deviceWidth, height );
157  }
158  else
159  {
160  imageToDeviceRatio = deviceHeight / mImage.height();
161  double width = imageToDeviceRatio * mImage.width();
162  return QRectF( 0, 0, width, deviceHeight );
163  }
164 }
165 
166 QRectF QgsComposerPicture::boundedSVGRect( double deviceWidth, double deviceHeight )
167 {
168  double imageToSvgRatio;
169  if ( deviceWidth / mDefaultSvgSize.width() > deviceHeight / mDefaultSvgSize.height() )
170  {
171  imageToSvgRatio = deviceHeight / mDefaultSvgSize.height();
172  double width = mDefaultSvgSize.width() * imageToSvgRatio;
173  return QRectF( 0, 0, width, deviceHeight );
174  }
175  else
176  {
177  imageToSvgRatio = deviceWidth / mDefaultSvgSize.width();
178  double height = mDefaultSvgSize.height() * imageToSvgRatio;
179  return QRectF( 0, 0, deviceWidth, height );
180  }
181 }
182 
183 #if 0
184 QRectF QgsComposerPicture::boundedSVGRect( double deviceWidth, double deviceHeight )
185 {
186  double imageToSvgRatio;
187  if ( deviceWidth / mDefaultSvgSize.width() < deviceHeight / mDefaultSvgSize.height() )
188  {
189  imageToSvgRatio = deviceWidth / mDefaultSvgSize.width();
190  double height = mDefaultSvgSize.height() * imageToSvgRatio;
191  return QRectF( 0, 0, deviceWidth, height );
192  }
193  else
194  {
195  imageToSvgRatio = deviceHeight / mDefaultSvgSize.height();
196  double width = mDefaultSvgSize.width() * imageToSvgRatio;
197  return QRectF( 0, 0, width, deviceHeight );
198  }
199 }
200 #endif //0
201 
202 void QgsComposerPicture::setSceneRect( const QRectF& rectangle )
203 {
204  QgsComposerItem::setSceneRect( rectangle );
205 
206  //consider to change size of the shape if the rectangle changes width and/or height
207  double newPictureWidth = rectangle.width();
208  double newPictureHeight = rectangle.height();
209  imageSizeConsideringRotation( newPictureWidth, newPictureHeight );
210  mPictureWidth = newPictureWidth;
211  mPictureHeight = newPictureHeight;
212 
213  emit itemChanged();
214 }
215 
217 {
218  //adapt rectangle size
219  double width = mPictureWidth;
220  double height = mPictureHeight;
221  sizeChangedByRotation( width, height );
222 
223  //adapt scene rect to have the same center and the new width / height
224  double x = transform().dx() + rect().width() / 2.0 - width / 2.0;
225  double y = transform().dy() + rect().height() / 2.0 - height / 2.0;
226  QgsComposerItem::setSceneRect( QRectF( x, y, width, height ) );
227 
229 }
230 
231 void QgsComposerPicture::setRotationMap( int composerMapId )
232 {
233  if ( !mComposition )
234  {
235  return;
236  }
237 
238  if ( composerMapId == -1 ) //disable rotation from map
239  {
240  QObject::disconnect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
241  mRotationMap = 0;
242  }
243 
244  const QgsComposerMap* map = mComposition->getComposerMapById( composerMapId );
245  if ( !map )
246  {
247  return;
248  }
249  if ( mRotationMap )
250  {
251  QObject::disconnect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
252  }
253  mRotation = map->rotation();
254  QObject::connect( map, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
255  mRotationMap = map;
256  setRotation( map->rotation() );
257 }
258 
260 {
261  return mSourceFile.fileName();
262 }
263 
264 bool QgsComposerPicture::writeXML( QDomElement& elem, QDomDocument & doc ) const
265 {
266  if ( elem.isNull() )
267  {
268  return false;
269  }
270  QDomElement composerPictureElem = doc.createElement( "ComposerPicture" );
271  composerPictureElem.setAttribute( "file", QgsProject::instance()->writePath( mSourceFile.fileName() ) );
272  composerPictureElem.setAttribute( "pictureWidth", QString::number( mPictureWidth ) );
273  composerPictureElem.setAttribute( "pictureHeight", QString::number( mPictureHeight ) );
274  if ( !mRotationMap )
275  {
276  composerPictureElem.setAttribute( "mapId", -1 );
277  }
278  else
279  {
280  composerPictureElem.setAttribute( "mapId", mRotationMap->id() );
281  }
282 
283  _writeXML( composerPictureElem, doc );
284  elem.appendChild( composerPictureElem );
285  return true;
286 }
287 
288 bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocument& doc )
289 {
290  if ( itemElem.isNull() )
291  {
292  return false;
293  }
294 
295  mPictureWidth = itemElem.attribute( "pictureWidth", "10" ).toDouble();
296  mPictureHeight = itemElem.attribute( "pictureHeight", "10" ).toDouble();
297 
298  QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
299  if ( composerItemList.size() > 0 )
300  {
301  _readXML( composerItemList.at( 0 ).toElement(), doc );
302  }
303 
304 
305  mDefaultSvgSize = QSize( 0, 0 );
306 
307  QString fileName = QgsProject::instance()->readPath( itemElem.attribute( "file" ) );
308  setPictureFile( fileName );
309 
310  //rotation map
311  int rotationMapId = itemElem.attribute( "mapId", "-1" ).toInt();
312  if ( rotationMapId == -1 )
313  {
314  mRotationMap = 0;
315  }
316  else if ( mComposition )
317  {
318 
319  if ( mRotationMap )
320  {
321  QObject::disconnect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
322  }
323  mRotationMap = mComposition->getComposerMapById( rotationMapId );
324  QObject::connect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) );
325  }
326 
327  emit itemChanged();
328  return true;
329 }
330 
332 {
333  if ( !mRotationMap )
334  {
335  return -1;
336  }
337  else
338  {
339  return mRotationMap->id();
340  }
341 }
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
virtual void setRotation(double r)
A item that forms part of a map composition.
virtual void setRotation(double r)
Sets the rotation and adapts the item rect.
virtual void drawFrame(QPainter *p)
Draw black frame around item.
double mRotation
Item rotation in degrees, clockwise.
QString readPath(QString filename) const
turn filename read from the project file to an absolute path
void itemChanged()
Used e.g.
bool _readXML(const QDomElement &itemElem, const QDomDocument &doc)
Reads parameter that are not subclass specific in document.
QRectF boundedSVGRect(double deviceWidth, double deviceHeight)
Calculates bounding rect for svg file (mSourcefile) such that aspect ratio is correct.
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget)
Reimplementation of QCanvasItem::paint.
const QgsComposerMap * mRotationMap
Map that sets the rotation (or 0 if this picture uses map independent rotation)
virtual void drawSelectionBoxes(QPainter *p)
Draw selection boxes around item.
double mPictureHeight
Height of the picture (in mm)
void rotationChanged(double newRotation)
Is emitted on rotation change to notify north arrow pictures.
QgsComposition * mComposition
Graphics scene for map printing.
Object representing map window.
QString pictureFile() const
bool writeXML(QDomElement &elem, QDomDocument &doc) const
stores state in Dom element
void sizeChangedByRotation(double &width, double &height)
Calculates width / height of the bounding box of a rotated rectangle (mRotation)
double rotation() const
int id() const
Get identification number.
void setPictureFile(const QString &path)
Sets the source file of the image (may be svg or a raster format)
bool _writeXML(QDomElement &itemElem, QDomDocument &doc) const
Writes parameter that are not subclass specific in document.
virtual void drawBackground(QPainter *p)
Draw background.
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:358
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...
double mPictureWidth
Width of the picture (in mm)
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...
void setRotationMap(int composerMapId)
Sets the map object for rotation (by id).
int rotationMap() const
Returns the id of the rotation map.
QRectF boundedImageRect(double deviceWidth, double deviceHeight)
Calculates bounding rect for image such that aspect ratio is correct.
const QgsComposerMap * getComposerMapById(int id) const
Returns the composer map with specified id.