QGIS API Documentation  2.12.0-Lyon
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 || !mComposition || !mComposition->pagesVisible() )
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  QgsExpressionContext* expressionContext = createExpressionContext();
168  context.setExpressionContext( *expressionContext );
169  delete expressionContext;
170 
171  painter->save();
172 
174  {
175  //if in preview mode, draw page border and shadow so that it's
176  //still possible to tell where pages with a transparent style begin and end
177  painter->setRenderHint( QPainter::Antialiasing, false );
178 
179  //shadow
180  painter->setBrush( QBrush( QColor( 150, 150, 150 ) ) );
181  painter->setPen( Qt::NoPen );
182  painter->drawRect( QRectF( 1, 1, rect().width() + 1, rect().height() + 1 ) );
183 
184  //page area
185  painter->setBrush( QColor( 215, 215, 215 ) );
186  painter->setPen( QPen( QColor( 100, 100, 100 ) ) );
187  painter->drawRect( QRectF( 0, 0, rect().width(), rect().height() ) );
188  }
189 
190  painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
191 
192  painter->setRenderHint( QPainter::Antialiasing );
194 
195  calculatePageMargin();
196  QPolygonF pagePolygon = QPolygonF( QRectF( mPageMargin * dotsPerMM, mPageMargin * dotsPerMM,
197  ( rect().width() - 2 * mPageMargin ) * dotsPerMM, ( rect().height() - 2 * mPageMargin ) * dotsPerMM ) );
198  QList<QPolygonF> rings; //empty list
199 
200  mComposition->pageStyleSymbol()->renderPolygon( pagePolygon, &rings, 0, context );
201  mComposition->pageStyleSymbol()->stopRender( context );
202  painter->restore();
203 }
204 
205 void QgsPaperItem::calculatePageMargin()
206 {
207  //get max bleed from symbol
209 
210  //Now subtract 1 pixel to prevent semi-transparent borders at edge of solid page caused by
211  //anti-aliased painting. This may cause a pixel to be cropped from certain edge lines/symbols,
212  //but that can be counteracted by adding a dummy transparent line symbol layer with a wider line width
213  mPageMargin = maxBleed - ( 25.4 / mComposition->printResolution() );
214 }
215 
217 {
218  Q_UNUSED( elem );
219  Q_UNUSED( doc );
220  return true;
221 }
222 
223 bool QgsPaperItem::readXML( const QDomElement& itemElem, const QDomDocument& doc )
224 {
225  Q_UNUSED( itemElem );
226  Q_UNUSED( doc );
227  return true;
228 }
229 
230 void QgsPaperItem::setSceneRect( const QRectF& rectangle )
231 {
232  QgsComposerItem::setSceneRect( rectangle );
233  //update size and position of attached QgsPaperGrid to reflect new page size and position
234  mPageGrid->setRect( 0, 0, rect().width(), rect().height() );
235  mPageGrid->setPos( pos().x(), pos().y() );
236 }
237 
238 void QgsPaperItem::initialize()
239 {
240  setFlag( QGraphicsItem::ItemIsSelectable, false );
241  setFlag( QGraphicsItem::ItemIsMovable, false );
242  setZValue( 0 );
243 
244  //even though we aren't going to use it to draw the page, set the pen width as 4
245  //so that the page border and shadow is fully rendered within its scene rect
246  //(QGraphicsRectItem considers the pen width when calculating an item's scene rect)
247  setPen( QPen( QBrush( Qt::NoBrush ), 4 ) );
248 
249  if ( mComposition )
250  {
251  //create a new QgsPaperGrid for this page, and add it to the composition
252  mPageGrid = new QgsPaperGrid( pos().x(), pos().y(), rect().width(), rect().height(), mComposition );
253  mComposition->addItem( mPageGrid );
254 
255  //connect to atlas feature changes
256  //to update symbol style (in case of data-defined symbology)
257  connect( &mComposition->atlasComposition(), SIGNAL( featureChanged( QgsFeature* ) ), this, SLOT( repaint() ) );
258  }
259 }
void setForceVectorOutput(bool force)
qreal x() const
qreal y() const
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
QgsFillSymbolV2 * pageStyleSymbol()
Note: added in version 2.1.
bool writeXML(QDomElement &elem, QDomDocument &doc) const override
Stores state in Dom element.
void setRenderHint(RenderHint hint, bool on)
void setFlag(GraphicsItemFlag flag, bool enabled)
void setOutputDpi(int dpi)
Set DPI used for conversion between real world units (e.g. mm) and pixels.
const QgsMapSettings & mapSettings() const
Return setting of QGIS map canvas.
const QPen & gridPen() const
void scale(qreal sx, qreal sy)
const T & at(int i) const
A item that forms part of a map composition.
QgsPaperGrid(double x, double y, double width, double height, QgsComposition *composition)
bool isVisible() const
void save()
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:176
void drawLine(const QLineF &line)
QGraphicsScene * scene() const
virtual QgsExpressionContext * createExpressionContext() const override
Creates an expression context relating to the objects's current state.
int size() const
void setRect(const QRectF &rectangle)
The QgsMapSettings class contains configuration for rendering of the map.
void drawRect(const QRectF &rectangle)
QColor color() const
QTransform transform() const
QPointF pos() const
void startRender(QgsRenderContext &context, const QgsFields *fields=0)
int printResolution() const
void setPen(const QColor &color)
void setPos(const QPointF &pos)
QList< QGraphicsView * > views() const
qreal m11() const
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
bool readXML(const QDomElement &itemElem, const QDomDocument &doc) override
Sets state from Dom document.
QPaintDevice * device() const
Item representing a grid.
Definition: qgspaperitem.h:26
void setBrush(const QBrush &brush)
void setPainter(QPainter *p)
void repaint() override
QgsPaperItem(QgsComposition *c)
static double estimateMaxSymbolBleed(QgsSymbolV2 *symbol)
Returns the maximum estimated bleed for the symbol.
Graphics scene for map printing.
int logicalDpiX() const
GridStyle gridStyle() const
void restore()
QgsComposition * mComposition
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
Reimplementation of QCanvasItem::paint.
double snapGridOffsetY() const
bool pagesVisible() const
Returns whether the page items are be visible in the composition.
Contains information about the context of a rendering operation.
double snapGridOffsetX() const
qreal width() const
void stopRender(QgsRenderContext &context)
void setPen(const QPen &pen)
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
double snapGridResolution() const
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...
virtual void setSceneRect(const QRectF &rectangle) override
Sets this items bound in scene coordinates such that 1 item size units corresponds to 1 scene size un...
bool gridVisible() const
qreal height() const
QgsAtlasComposition & atlasComposition()
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
Reimplementation of QCanvasItem::paint.
void addItem(QGraphicsItem *item)
QgsComposition::PlotStyle plotStyle() const
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void setZValue(qreal z)
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
QRectF rect() const