QGIS API Documentation  2.8.2-Wien
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgspaperitem.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgspaperitem.cpp
3  -------------------
4  begin : September 2008
5  copyright : (C) 2008 by Marco Hugentobler
6  email : marco dot hugentobler at karto dot baug dot ethz dot ch
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 "qgspaperitem.h"
19 #include "qgscomposition.h"
20 #include "qgsstylev2.h"
21 #include "qgslogger.h"
22 #include <QGraphicsRectItem>
23 #include <QGraphicsView>
24 #include <QPainter>
25 
26 //QgsPaperGrid
27 
28 QgsPaperGrid::QgsPaperGrid( double x, double y, double width, double height, QgsComposition* composition ): QGraphicsRectItem( 0, 0, width, height ), mComposition( composition )
29 {
30  setFlag( QGraphicsItem::ItemIsSelectable, false );
31  setFlag( QGraphicsItem::ItemIsMovable, false );
32  setZValue( 1000 );
33  setPos( x, y );
34 }
35 
37 {
38 }
39 
40 void QgsPaperGrid::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
41 {
42  Q_UNUSED( itemStyle );
43  Q_UNUSED( pWidget );
44 
45  //draw grid
46  if ( mComposition )
47  {
48  if ( mComposition->gridVisible() && mComposition->plotStyle() == QgsComposition::Preview
49  && mComposition->snapGridResolution() > 0 )
50  {
51  int gridMultiplyX = ( int )( mComposition->snapGridOffsetX() / mComposition->snapGridResolution() );
52  int gridMultiplyY = ( int )( mComposition->snapGridOffsetY() / mComposition->snapGridResolution() );
53  double currentXCoord = mComposition->snapGridOffsetX() - gridMultiplyX * mComposition->snapGridResolution();
54  double currentYCoord;
55  double minYCoord = mComposition->snapGridOffsetY() - gridMultiplyY * mComposition->snapGridResolution();
56 
57  painter->save();
58  //turn of antialiasing so grid is nice and sharp
59  painter->setRenderHint( QPainter::Antialiasing, false );
60 
61  if ( mComposition->gridStyle() == QgsComposition::Solid )
62  {
63  painter->setPen( mComposition->gridPen() );
64 
65  //draw vertical lines
66  for ( ; currentXCoord <= rect().width(); currentXCoord += mComposition->snapGridResolution() )
67  {
68  painter->drawLine( QPointF( currentXCoord, 0 ), QPointF( currentXCoord, rect().height() ) );
69  }
70 
71  //draw horizontal lines
72  currentYCoord = minYCoord;
73  for ( ; currentYCoord <= rect().height(); currentYCoord += mComposition->snapGridResolution() )
74  {
75  painter->drawLine( QPointF( 0, currentYCoord ), QPointF( rect().width(), currentYCoord ) );
76  }
77  }
78  else //'Dots' or 'Crosses'
79  {
80  QPen gridPen = mComposition->gridPen();
81  painter->setPen( gridPen );
82  painter->setBrush( QBrush( gridPen.color() ) );
83  double halfCrossLength = 1;
84  if ( mComposition->gridStyle() == QgsComposition::Dots )
85  {
86  //dots are actually drawn as tiny crosses a few pixels across
87  //check QGraphicsView to get current transform
88  if ( scene() )
89  {
90  QList<QGraphicsView*> viewList = scene()->views();
91  if ( viewList.size() > 0 )
92  {
93  QGraphicsView* currentView = viewList.at( 0 );
94  if ( currentView->isVisible() )
95  {
96  //set halfCrossLength to equivalent of 1 pixel
97  halfCrossLength = 1 / currentView->transform().m11();
98  }
99  }
100  }
101  }
102  else if ( mComposition->gridStyle() == QgsComposition::Crosses )
103  {
104  halfCrossLength = mComposition->snapGridResolution() / 6;
105  }
106 
107  for ( ; currentXCoord <= rect().width(); currentXCoord += mComposition->snapGridResolution() )
108  {
109  currentYCoord = minYCoord;
110  for ( ; currentYCoord <= rect().height(); currentYCoord += mComposition->snapGridResolution() )
111  {
112  painter->drawLine( QPointF( currentXCoord - halfCrossLength, currentYCoord ), QPointF( currentXCoord + halfCrossLength, currentYCoord ) );
113  painter->drawLine( QPointF( currentXCoord, currentYCoord - halfCrossLength ), QPointF( currentXCoord, currentYCoord + halfCrossLength ) );
114  }
115  }
116  }
117  painter->restore();
118  }
119  }
120 }
121 
122 
123 //QgsPaperItem
124 
126  mPageGrid( 0 )
127 {
128  initialize();
129 }
130 
131 QgsPaperItem::QgsPaperItem( qreal x, qreal y, qreal width, qreal height, QgsComposition* composition ): QgsComposerItem( x, y, width, height, composition, false ),
132  mPageGrid( 0 ), mPageMargin( 0 )
133 {
134  initialize();
135 }
136 
137 QgsPaperItem::QgsPaperItem(): QgsComposerItem( 0, false ),
138  mPageGrid( 0 ), mPageMargin( 0 )
139 {
140  initialize();
141 }
142 
144 {
145  delete mPageGrid;
146 }
147 
148 void QgsPaperItem::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
149 {
150  Q_UNUSED( itemStyle );
151  Q_UNUSED( pWidget );
152  if ( !painter )
153  {
154  return;
155  }
156 
157  //setup painter scaling to dots so that raster symbology is drawn to scale
158  double dotsPerMM = painter->device()->logicalDpiX() / 25.4;
159 
160  //setup render context
162  //context units should be in dots
163  ms.setOutputDpi( painter->device()->logicalDpiX() );
165  context.setPainter( painter );
166  context.setForceVectorOutput( true );
167 
168  painter->save();
169 
171  {
172  //if in preview mode, draw page border and shadow so that it's
173  //still possible to tell where pages with a transparent style begin and end
174  painter->setRenderHint( QPainter::Antialiasing, false );
175 
176  //shadow
177  painter->setBrush( QBrush( QColor( 150, 150, 150 ) ) );
178  painter->setPen( Qt::NoPen );
179  painter->drawRect( QRectF( 1, 1, rect().width() + 1, rect().height() + 1 ) );
180 
181  //page area
182  painter->setBrush( QColor( 215, 215, 215 ) );
183  painter->setPen( QPen( QColor( 100, 100, 100 ) ) );
184  painter->drawRect( QRectF( 0, 0, rect().width(), rect().height() ) );
185  }
186 
187  painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
188 
189  painter->setRenderHint( QPainter::Antialiasing );
191 
192  calculatePageMargin();
193  QPolygonF pagePolygon = QPolygonF( QRectF( mPageMargin * dotsPerMM, mPageMargin * dotsPerMM,
194  ( rect().width() - 2 * mPageMargin ) * dotsPerMM, ( rect().height() - 2 * mPageMargin ) * dotsPerMM ) );
195  QList<QPolygonF> rings; //empty list
196 
197  //need to render using atlas feature properties?
199  {
200  //using an atlas, so render using current atlas feature
201  //since there may be data defined symbols using atlas feature properties
202  mComposition->pageStyleSymbol()->renderPolygon( pagePolygon, &rings, mComposition->atlasComposition().currentFeature(), context );
203  }
204  else
205  {
206  mComposition->pageStyleSymbol()->renderPolygon( pagePolygon, &rings, 0, context );
207  }
208 
209  mComposition->pageStyleSymbol()->stopRender( context );
210  painter->restore();
211 }
212 
213 void QgsPaperItem::calculatePageMargin()
214 {
215  //get max bleed from symbol
217 
218  //Now subtract 1 pixel to prevent semi-transparent borders at edge of solid page caused by
219  //anti-aliased painting. This may cause a pixel to be cropped from certain edge lines/symbols,
220  //but that can be counteracted by adding a dummy transparent line symbol layer with a wider line width
221  mPageMargin = maxBleed - ( 25.4 / mComposition->printResolution() );
222 }
223 
224 bool QgsPaperItem::writeXML( QDomElement& elem, QDomDocument & doc ) const
225 {
226  Q_UNUSED( elem );
227  Q_UNUSED( doc );
228  return true;
229 }
230 
231 bool QgsPaperItem::readXML( const QDomElement& itemElem, const QDomDocument& doc )
232 {
233  Q_UNUSED( itemElem );
234  Q_UNUSED( doc );
235  return true;
236 }
237 
238 void QgsPaperItem::setSceneRect( const QRectF& rectangle )
239 {
240  QgsComposerItem::setSceneRect( rectangle );
241  //update size and position of attached QgsPaperGrid to reflect new page size and position
242  mPageGrid->setRect( 0, 0, rect().width(), rect().height() );
243  mPageGrid->setPos( pos().x(), pos().y() );
244 }
245 
246 void QgsPaperItem::initialize()
247 {
248  setFlag( QGraphicsItem::ItemIsSelectable, false );
249  setFlag( QGraphicsItem::ItemIsMovable, false );
250  setZValue( 0 );
251 
252  //even though we aren't going to use it to draw the page, set the pen width as 4
253  //so that the page border and shadow is fully rendered within its scene rect
254  //(QGraphicsRectItem considers the pen width when calculating an item's scene rect)
255  setPen( QPen( QBrush( Qt::NoBrush ), 4 ) );
256 
257  if ( mComposition )
258  {
259  //create a new QgsPaperGrid for this page, and add it to the composition
260  mPageGrid = new QgsPaperGrid( pos().x(), pos().y(), rect().width(), rect().height(), mComposition );
261  mComposition->addItem( mPageGrid );
262 
263  //connect to atlas feature changes
264  //to update symbol style (in case of data-defined symbology)
265  connect( &mComposition->atlasComposition(), SIGNAL( featureChanged( QgsFeature* ) ), this, SLOT( repaint() ) );
266  }
267 }