QGIS API Documentation  2.99.0-Master (0a63d1f)
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 "qgsstyle.h"
21 #include "qgslogger.h"
22 #include "qgsmapsettings.h"
23 #include "qgscomposerutils.h"
24 #include <QGraphicsRectItem>
25 #include <QGraphicsView>
26 #include <QPainter>
27 
28 //QgsPaperGrid
29 
30 QgsPaperGrid::QgsPaperGrid( double x, double y, double width, double height, QgsComposition* composition ): QGraphicsRectItem( 0, 0, width, height ), mComposition( composition )
31 {
32  setFlag( QGraphicsItem::ItemIsSelectable, false );
33  setFlag( QGraphicsItem::ItemIsMovable, false );
34  setZValue( 1000 );
35  setPos( x, y );
36 }
37 
38 void QgsPaperGrid::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
39 {
40  Q_UNUSED( itemStyle );
41  Q_UNUSED( pWidget );
42 
43  //draw grid
44  if ( mComposition )
45  {
46  if ( mComposition->gridVisible() && mComposition->plotStyle() == QgsComposition::Preview
47  && mComposition->snapGridResolution() > 0 )
48  {
49  int gridMultiplyX = static_cast< int >( mComposition->snapGridOffsetX() / mComposition->snapGridResolution() );
50  int gridMultiplyY = static_cast< int >( mComposition->snapGridOffsetY() / mComposition->snapGridResolution() );
51  double currentXCoord = mComposition->snapGridOffsetX() - gridMultiplyX * mComposition->snapGridResolution();
52  double currentYCoord;
53  double minYCoord = mComposition->snapGridOffsetY() - gridMultiplyY * mComposition->snapGridResolution();
54 
55  painter->save();
56  //turn of antialiasing so grid is nice and sharp
57  painter->setRenderHint( QPainter::Antialiasing, false );
58 
59  if ( mComposition->gridStyle() == QgsComposition::Solid )
60  {
61  painter->setPen( mComposition->gridPen() );
62 
63  //draw vertical lines
64  for ( ; currentXCoord <= rect().width(); currentXCoord += mComposition->snapGridResolution() )
65  {
66  painter->drawLine( QPointF( currentXCoord, 0 ), QPointF( currentXCoord, rect().height() ) );
67  }
68 
69  //draw horizontal lines
70  currentYCoord = minYCoord;
71  for ( ; currentYCoord <= rect().height(); currentYCoord += mComposition->snapGridResolution() )
72  {
73  painter->drawLine( QPointF( 0, currentYCoord ), QPointF( rect().width(), currentYCoord ) );
74  }
75  }
76  else //'Dots' or 'Crosses'
77  {
78  QPen gridPen = mComposition->gridPen();
79  painter->setPen( gridPen );
80  painter->setBrush( QBrush( gridPen.color() ) );
81  double halfCrossLength = 1;
82  if ( mComposition->gridStyle() == QgsComposition::Dots )
83  {
84  //dots are actually drawn as tiny crosses a few pixels across
85  //check QGraphicsView to get current transform
86  if ( scene() )
87  {
88  QList<QGraphicsView*> viewList = scene()->views();
89  if ( !viewList.isEmpty() )
90  {
91  QGraphicsView* currentView = viewList.at( 0 );
92  if ( currentView->isVisible() )
93  {
94  //set halfCrossLength to equivalent of 1 pixel
95  halfCrossLength = 1 / currentView->transform().m11();
96  }
97  }
98  }
99  }
100  else if ( mComposition->gridStyle() == QgsComposition::Crosses )
101  {
102  halfCrossLength = mComposition->snapGridResolution() / 6;
103  }
104 
105  for ( ; currentXCoord <= rect().width(); currentXCoord += mComposition->snapGridResolution() )
106  {
107  currentYCoord = minYCoord;
108  for ( ; currentYCoord <= rect().height(); currentYCoord += mComposition->snapGridResolution() )
109  {
110  painter->drawLine( QPointF( currentXCoord - halfCrossLength, currentYCoord ), QPointF( currentXCoord + halfCrossLength, currentYCoord ) );
111  painter->drawLine( QPointF( currentXCoord, currentYCoord - halfCrossLength ), QPointF( currentXCoord, currentYCoord + halfCrossLength ) );
112  }
113  }
114  }
115  painter->restore();
116  }
117  }
118 }
119 
120 
121 //QgsPaperItem
122 
124  mPageGrid( nullptr )
125 {
126  initialize();
127 }
128 
129 QgsPaperItem::QgsPaperItem( qreal x, qreal y, qreal width, qreal height, QgsComposition* composition ): QgsComposerItem( x, y, width, height, composition, false ),
130  mPageGrid( nullptr ), mPageMargin( 0 )
131 {
132  initialize();
133 }
134 
135 QgsPaperItem::QgsPaperItem(): QgsComposerItem( nullptr, false ),
136  mPageGrid( nullptr ), mPageMargin( 0 )
137 {
138  initialize();
139 }
140 
142 {
143  delete mPageGrid;
144 }
145 
146 void QgsPaperItem::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
147 {
148  Q_UNUSED( itemStyle );
149  Q_UNUSED( pWidget );
150  if ( !painter || !mComposition || !mComposition->pagesVisible() )
151  {
152  return;
153  }
154 
155  //setup painter scaling to dots so that raster symbology is drawn to scale
156  double dotsPerMM = painter->device()->logicalDpiX() / 25.4;
157 
158  //setup render context
160  context.setForceVectorOutput( true );
161 
162  QgsExpressionContext expressionContext = createExpressionContext();
163  context.setExpressionContext( expressionContext );
164 
165  painter->save();
166 
168  {
169  //if in preview mode, draw page border and shadow so that it's
170  //still possible to tell where pages with a transparent style begin and end
171  painter->setRenderHint( QPainter::Antialiasing, false );
172 
173  //shadow
174  painter->setBrush( QBrush( QColor( 150, 150, 150 ) ) );
175  painter->setPen( Qt::NoPen );
176  painter->drawRect( QRectF( 1, 1, rect().width() + 1, rect().height() + 1 ) );
177 
178  //page area
179  painter->setBrush( QColor( 215, 215, 215 ) );
180  painter->setPen( QPen( QColor( 100, 100, 100 ) ) );
181  painter->drawRect( QRectF( 0, 0, rect().width(), rect().height() ) );
182  }
183 
184  painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
185 
186  painter->setRenderHint( QPainter::Antialiasing );
188 
189  calculatePageMargin();
190  QPolygonF pagePolygon = QPolygonF( QRectF( mPageMargin * dotsPerMM, mPageMargin * dotsPerMM,
191  ( rect().width() - 2 * mPageMargin ) * dotsPerMM, ( rect().height() - 2 * mPageMargin ) * dotsPerMM ) );
192  QList<QPolygonF> rings; //empty list
193 
194  mComposition->pageStyleSymbol()->renderPolygon( pagePolygon, &rings, nullptr, context );
195  mComposition->pageStyleSymbol()->stopRender( context );
196  painter->restore();
197 }
198 
199 void QgsPaperItem::calculatePageMargin()
200 {
201  //get max bleed from symbol
203 
204  //Now subtract 1 pixel to prevent semi-transparent borders at edge of solid page caused by
205  //anti-aliased painting. This may cause a pixel to be cropped from certain edge lines/symbols,
206  //but that can be counteracted by adding a dummy transparent line symbol layer with a wider line width
207  mPageMargin = maxBleed - ( 25.4 / mComposition->printResolution() );
208 }
209 
210 bool QgsPaperItem::writeXml( QDomElement& elem, QDomDocument & doc ) const
211 {
212  Q_UNUSED( elem );
213  Q_UNUSED( doc );
214  return true;
215 }
216 
217 bool QgsPaperItem::readXml( const QDomElement& itemElem, const QDomDocument& doc )
218 {
219  Q_UNUSED( itemElem );
220  Q_UNUSED( doc );
221  return true;
222 }
223 
224 void QgsPaperItem::setSceneRect( const QRectF& rectangle )
225 {
226  QgsComposerItem::setSceneRect( rectangle );
227  //update size and position of attached QgsPaperGrid to reflect new page size and position
228  mPageGrid->setRect( 0, 0, rect().width(), rect().height() );
229  mPageGrid->setPos( pos().x(), pos().y() );
230 }
231 
232 void QgsPaperItem::initialize()
233 {
234  setFlag( QGraphicsItem::ItemIsSelectable, false );
235  setFlag( QGraphicsItem::ItemIsMovable, false );
236  setZValue( 0 );
237 
238  //even though we aren't going to use it to draw the page, set the pen width as 4
239  //so that the page border and shadow is fully rendered within its scene rect
240  //(QGraphicsRectItem considers the pen width when calculating an item's scene rect)
241  setPen( QPen( QBrush( Qt::NoBrush ), 4 ) );
242 
243  if ( mComposition )
244  {
245  //create a new QgsPaperGrid for this page, and add it to the composition
246  mPageGrid = new QgsPaperGrid( pos().x(), pos().y(), rect().width(), rect().height(), mComposition );
247  mComposition->addItem( mPageGrid );
248 
249  //connect to atlas feature changes
250  //to update symbol style (in case of data-defined symbology)
251  connect( &mComposition->atlasComposition(), SIGNAL( featureChanged( QgsFeature* ) ), this, SLOT( repaint() ) );
252  }
253 }
void setForceVectorOutput(bool force)
QPen gridPen() const
double snapGridOffsetY() const
double snapGridOffsetX() const
int printResolution() const
A item that forms part of a map composition.
QgsPaperGrid(double x, double y, double width, double height, QgsComposition *composition)
bool gridVisible() const
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:136
void startRender(QgsRenderContext &context, const QgsFields &fields=QgsFields())
Begins the rendering process for the symbol.
Definition: qgssymbol.cpp:387
QgsComposition::PlotStyle plotStyle() const
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
Definition: qgssymbol.cpp:1732
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.
static QgsRenderContext createRenderContext(QgsComposition *composition, QPainter &painter)
Creates a render context suitable for the specified composition and QPainter destination.
Item representing a grid.
Definition: qgspaperitem.h:28
void repaint() override
QgsPaperItem(QgsComposition *c)
Graphics scene for map printing.
static double estimateMaxSymbolBleed(QgsSymbol *symbol)
Returns the maximum estimated bleed for the symbol.
virtual QgsExpressionContext createExpressionContext() const override
Creates an expression context relating to the item&#39;s current state.
QgsComposition * mComposition
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
Reimplementation of QCanvasItem::paint.
Contains information about the context of a rendering operation.
QgsFillSymbol * pageStyleSymbol()
Note: added in version 2.1.
const QgsComposition * composition() const
Returns the composition the item is attached to.
GridStyle gridStyle() 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...
double snapGridResolution() const
QgsAtlasComposition & atlasComposition()
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
Reimplementation of QCanvasItem::paint.
bool writeXml(QDomElement &elem, QDomDocument &doc) const override
Stores state in Dom element.
QgsComposerItem(QgsComposition *composition, bool manageZValue=true)
Constructor.
bool pagesVisible() const
Returns whether the page items are be visible in the composition.
void stopRender(QgsRenderContext &context)
Ends the rendering process.
Definition: qgssymbol.cpp:408
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.