QGIS API Documentation  2.17.0-Master (eef6f05)
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 = static_cast< int >( mComposition->snapGridOffsetX() / mComposition->snapGridResolution() );
52  int gridMultiplyY = static_cast< 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.isEmpty() )
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( nullptr )
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( nullptr ), mPageMargin( 0 )
133 {
134  initialize();
135 }
136 
137 QgsPaperItem::QgsPaperItem(): QgsComposerItem( nullptr, false ),
138  mPageGrid( nullptr ), 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, nullptr, 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)
const QPen & gridPen() const
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.
double snapGridOffsetY() const
bool writeXML(QDomElement &elem, QDomDocument &doc) const override
Stores state in Dom element.
double snapGridOffsetX() const
void setRenderHint(RenderHint hint, bool on)
void setFlag(GraphicsItemFlag flag, bool enabled)
int printResolution() 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)
void setOutputDpi(double dpi)
Set DPI used for conversion between real world units (e.g. mm) and pixels.
bool gridVisible() const
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:187
void drawLine(const QLineF &line)
QGraphicsScene * scene() const
virtual QgsExpressionContext * createExpressionContext() const override
Creates an expression context relating to the item&#39;s current state.
void setRect(const QRectF &rectangle)
QgsComposition::PlotStyle plotStyle() const
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=nullptr)
void setPen(const QColor &color)
void setPos(const QPointF &pos)
QList< QGraphicsView * > views() const
qreal m11() const
bool isEmpty() 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:27
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.
const QgsMapSettings & mapSettings() const
Return setting of QGIS map canvas.
int logicalDpiX() const
void restore()
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.
qreal width() const
void stopRender(QgsRenderContext &context)
const QgsComposition * composition() const
Returns the composition the item is attached to.
void setPen(const QPen &pen)
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
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
qreal height() const
QgsAtlasComposition & atlasComposition()
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
Reimplementation of QCanvasItem::paint.
QgsComposerItem(QgsComposition *composition, bool manageZValue=true)
Constructor.
bool pagesVisible() const
Returns whether the page items are be visible in the composition.
void addItem(QGraphicsItem *item)
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