QGIS API Documentation  2.9.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
qgscomposerhtml.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscomposerhtml.cpp
3  ------------------------------------------------------------
4  begin : July 2012
5  copyright : (C) 2012 by Marco Hugentobler
6  email : marco dot hugentobler at sourcepole dot ch
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgscomposerhtml.h"
17 #include "qgscomposerframe.h"
18 #include "qgscomposition.h"
21 #include "qgsmessagelog.h"
22 #include "qgsexpression.h"
23 #include "qgslogger.h"
25 #include "qgsvectorlayer.h"
26 #include "qgsproject.h"
27 
28 #include <QCoreApplication>
29 #include <QPainter>
30 #include <QWebFrame>
31 #include <QWebPage>
32 #include <QImage>
33 #include <QNetworkReply>
34 
35 QgsComposerHtml::QgsComposerHtml( QgsComposition* c, bool createUndoCommands )
36  : QgsComposerMultiFrame( c, createUndoCommands )
37  , mContentMode( QgsComposerHtml::Url )
38  , mWebPage( 0 )
39  , mLoaded( false )
40  , mHtmlUnitsToMM( 1.0 )
41  , mRenderedPage( 0 )
42  , mEvaluateExpressions( true )
43  , mUseSmartBreaks( true )
44  , mMaxBreakDistance( 10 )
45  , mExpressionFeature( 0 )
46  , mExpressionLayer( 0 )
47  , mDistanceArea( 0 )
48  , mEnableUserStylesheet( false )
49  , mFetcher( 0 )
50 {
51  mDistanceArea = new QgsDistanceArea();
52  mHtmlUnitsToMM = htmlUnitsToMM();
53  mWebPage = new QWebPage();
54  mWebPage->mainFrame()->setScrollBarPolicy( Qt::Horizontal, Qt::ScrollBarAlwaysOff );
55  mWebPage->mainFrame()->setScrollBarPolicy( Qt::Vertical, Qt::ScrollBarAlwaysOff );
56 
57  //This makes the background transparent. Found on http://blog.qt.digia.com/blog/2009/06/30/transparent-qwebview-or-qwebpage/
58  QPalette palette = mWebPage->palette();
59  palette.setBrush( QPalette::Base, Qt::transparent );
60  mWebPage->setPalette( palette );
61 
62  mWebPage->setNetworkAccessManager( QgsNetworkAccessManager::instance() );
63  QObject::connect( mWebPage, SIGNAL( loadFinished( bool ) ), this, SLOT( frameLoaded( bool ) ) );
64  if ( mComposition )
65  {
66  QObject::connect( mComposition, SIGNAL( itemRemoved( QgsComposerItem* ) ), this, SLOT( handleFrameRemoval( QgsComposerItem* ) ) );
67  }
68 
69  // data defined strings
70  mDataDefinedNames.insert( QgsComposerObject::SourceUrl, QString( "dataDefinedSourceUrl" ) );
71 
73  {
74  //a html item added while atlas preview is enabled needs to have the expression context set,
75  //otherwise fields in the html aren't correctly evaluated until atlas preview feature changes (#9457)
77  }
78 
79  //connect to atlas feature changes
80  //to update the expression context
81  connect( &mComposition->atlasComposition(), SIGNAL( featureChanged( QgsFeature* ) ), this, SLOT( refreshExpressionContext() ) );
82 
83  mFetcher = new QgsNetworkContentFetcher();
84  connect( mFetcher, SIGNAL( finished() ), this, SLOT( frameLoaded() ) );
85 
86 }
87 
89  : QgsComposerMultiFrame( 0, false )
90  , mContentMode( QgsComposerHtml::Url )
91  , mWebPage( 0 )
92  , mLoaded( false )
93  , mHtmlUnitsToMM( 1.0 )
94  , mRenderedPage( 0 )
95  , mEvaluateExpressions( true )
96  , mUseSmartBreaks( true )
97  , mMaxBreakDistance( 10 )
98  , mExpressionFeature( 0 )
99  , mExpressionLayer( 0 )
100  , mDistanceArea( 0 )
101  , mEnableUserStylesheet( false )
102  , mFetcher( 0 )
103 {
104  mDistanceArea = new QgsDistanceArea();
105  mFetcher = new QgsNetworkContentFetcher();
106  connect( mFetcher, SIGNAL( finished() ), this, SLOT( frameLoaded() ) );
107 }
108 
110 {
111  delete mDistanceArea;
112  delete mWebPage;
113  delete mRenderedPage;
114  mFetcher->deleteLater();
115 }
116 
117 void QgsComposerHtml::setUrl( const QUrl& url )
118 {
119  if ( !mWebPage )
120  {
121  return;
122  }
123 
124  mUrl = url;
125  loadHtml( true );
126  emit changed();
127 }
128 
129 void QgsComposerHtml::setHtml( const QString html )
130 {
131  mHtml = html;
132  //TODO - this signal should be emitted, but without changing the signal which sets the html
133  //to an equivalent of editingFinished it causes a lot of problems. Need to investigate
134  //ways of doing this using QScintilla widgets.
135  //emit changed();
136 }
137 
138 void QgsComposerHtml::setEvaluateExpressions( bool evaluateExpressions )
139 {
140  mEvaluateExpressions = evaluateExpressions;
141  loadHtml( true );
142  emit changed();
143 }
144 
145 void QgsComposerHtml::loadHtml( const bool useCache )
146 {
147  if ( !mWebPage )
148  {
149  return;
150  }
151 
152  QString loadedHtml;
153  switch ( mContentMode )
154  {
156  {
157 
158  QString currentUrl = mUrl.toString();
159 
160  //data defined url set?
161  QVariant exprVal;
163  {
164  currentUrl = exprVal.toString().trimmed();;
165  QgsDebugMsg( QString( "exprVal Source Url:%1" ).arg( currentUrl ) );
166  }
167  if ( currentUrl.isEmpty() )
168  {
169  return;
170  }
171  if ( !( useCache && currentUrl == mLastFetchedUrl ) )
172  {
173  loadedHtml = fetchHtml( QUrl( currentUrl ) );
174  mLastFetchedUrl = currentUrl;
175  }
176  else
177  {
178  loadedHtml = mFetchedHtml;
179  }
180 
181  break;
182  }
184  loadedHtml = mHtml;
185  break;
186  }
187 
188  //evaluate expressions
189  if ( mEvaluateExpressions )
190  {
191  loadedHtml = QgsExpression::replaceExpressionText( loadedHtml, mExpressionFeature, mExpressionLayer, 0, mDistanceArea );
192  }
193 
194  mLoaded = false;
195 
196  //reset page size. otherwise viewport size increases but never decreases again
197  mWebPage->setViewportSize( QSize( maxFrameWidth() * mHtmlUnitsToMM, 0 ) );
198 
199  //set html, using the specified url as base if in Url mode
200  mWebPage->mainFrame()->setHtml( loadedHtml, mContentMode == QgsComposerHtml::Url ? QUrl( mActualFetchedUrl ) : QUrl() );
201 
202  //set user stylesheet
203  QWebSettings* settings = mWebPage->settings();
204  if ( mEnableUserStylesheet && ! mUserStylesheet.isEmpty() )
205  {
206  QByteArray ba;
207  ba.append( mUserStylesheet.toUtf8() );
208  QUrl cssFileURL = QUrl( "data:text/css;charset=utf-8;base64," + ba.toBase64() );
209  settings->setUserStyleSheetUrl( cssFileURL );
210  }
211  else
212  {
213  settings->setUserStyleSheetUrl( QUrl() );
214  }
215 
216  while ( !mLoaded )
217  {
218  qApp->processEvents();
219  }
220 
222  //trigger a repaint
223  emit contentsChanged();
224 }
225 
226 void QgsComposerHtml::frameLoaded( bool ok )
227 {
228  Q_UNUSED( ok );
229  mLoaded = true;
230 }
231 
232 double QgsComposerHtml::maxFrameWidth() const
233 {
234  double maxWidth = 0;
235  QList<QgsComposerFrame*>::const_iterator frameIt = mFrameItems.constBegin();
236  for ( ; frameIt != mFrameItems.constEnd(); ++frameIt )
237  {
238  maxWidth = qMax( maxWidth, ( double )(( *frameIt )->boundingRect().width() ) );
239  }
240 
241  return maxWidth;
242 }
243 
245 {
246  if ( frameCount() < 1 ) return;
247 
248  QSize contentsSize = mWebPage->mainFrame()->contentsSize();
249 
250  //find maximum frame width
251  double maxWidth = maxFrameWidth();
252  //set content width to match maximum frame width
253  contentsSize.setWidth( maxWidth * mHtmlUnitsToMM );
254 
255  mWebPage->setViewportSize( contentsSize );
256  mSize.setWidth( contentsSize.width() / mHtmlUnitsToMM );
257  mSize.setHeight( contentsSize.height() / mHtmlUnitsToMM );
258  if ( contentsSize.isValid() )
259  {
260  renderCachedImage();
261  }
263  emit changed();
264 }
265 
266 void QgsComposerHtml::renderCachedImage()
267 {
268  //render page to cache image
269  if ( mRenderedPage )
270  {
271  delete mRenderedPage;
272  }
273  mRenderedPage = new QImage( mWebPage->viewportSize(), QImage::Format_ARGB32 );
274  if ( mRenderedPage->isNull() )
275  {
276  return;
277  }
278  mRenderedPage->fill( Qt::transparent );
279  QPainter painter;
280  painter.begin( mRenderedPage );
281  mWebPage->mainFrame()->render( &painter );
282  painter.end();
283 }
284 
285 QString QgsComposerHtml::fetchHtml( QUrl url )
286 {
287  //pause until HTML fetch
288  mLoaded = false;
289  mFetcher->fetchContent( url );
290 
291  while ( !mLoaded )
292  {
293  qApp->processEvents();
294  }
295 
296  mFetchedHtml = mFetcher->contentAsString();
297  mActualFetchedUrl = mFetcher->reply()->url().toString();
298  return mFetchedHtml;
299 }
300 
302 {
303  return mSize;
304 }
305 
306 void QgsComposerHtml::render( QPainter* p, const QRectF& renderExtent, const int frameIndex )
307 {
308  Q_UNUSED( frameIndex );
309 
310  if ( !mWebPage )
311  {
312  return;
313  }
314 
315  p->save();
316  p->setRenderHint( QPainter::Antialiasing );
317  p->scale( 1.0 / mHtmlUnitsToMM, 1.0 / mHtmlUnitsToMM );
318  p->translate( 0.0, -renderExtent.top() * mHtmlUnitsToMM );
319  mWebPage->mainFrame()->render( p, QRegion( renderExtent.left(), renderExtent.top() * mHtmlUnitsToMM, renderExtent.width() * mHtmlUnitsToMM, renderExtent.height() * mHtmlUnitsToMM ) );
320  p->restore();
321 }
322 
323 double QgsComposerHtml::htmlUnitsToMM()
324 {
325  if ( !mComposition )
326  {
327  return 1.0;
328  }
329 
330  return ( mComposition->printResolution() / 72.0 ); //webkit seems to assume a standard dpi of 96
331 }
332 
333 void QgsComposerHtml::addFrame( QgsComposerFrame* frame, bool recalcFrameSizes )
334 {
335  mFrameItems.push_back( frame );
336  QObject::connect( frame, SIGNAL( sizeChanged() ), this, SLOT( recalculateFrameSizes() ) );
337  if ( mComposition )
338  {
339  mComposition->addComposerHtmlFrame( this, frame );
340  }
341 
342  if ( recalcFrameSizes )
343  {
345  }
346 }
347 
348 bool candidateSort( const QPair<int, int> &c1, const QPair<int, int> &c2 )
349 {
350  if ( c1.second < c2.second )
351  return true;
352  else if ( c1.second > c2.second )
353  return false;
354  else if ( c1.first > c2.first )
355  return true;
356  else
357  return false;
358 }
359 
361 {
362  if ( !mWebPage || !mRenderedPage || !mUseSmartBreaks )
363  {
364  return yPos;
365  }
366 
367  //convert yPos to pixels
368  int idealPos = yPos * htmlUnitsToMM();
369 
370  //if ideal break pos is past end of page, there's nothing we need to do
371  if ( idealPos >= mRenderedPage->height() )
372  {
373  return yPos;
374  }
375 
376  int maxSearchDistance = mMaxBreakDistance * htmlUnitsToMM();
377 
378  //loop through all lines just before ideal break location, up to max distance
379  //of maxSearchDistance
380  int changes = 0;
381  QRgb currentColor;
382  bool currentPixelTransparent = false;
383  bool previousPixelTransparent = false;
384  QRgb pixelColor;
385  QList< QPair<int, int> > candidates;
386  int minRow = qMax( idealPos - maxSearchDistance, 0 );
387  for ( int candidateRow = idealPos; candidateRow >= minRow; --candidateRow )
388  {
389  changes = 0;
390  currentColor = qRgba( 0, 0, 0, 0 );
391  //check all pixels in this line
392  for ( int col = 0; col < mRenderedPage->width(); ++col )
393  {
394  //count how many times the pixels change color in this row
395  //eventually, we select a row to break at with the minimum number of color changes
396  //since this is likely a line break, or gap between table cells, etc
397  //but very unlikely to be midway through a text line or picture
398  pixelColor = mRenderedPage->pixel( col, candidateRow );
399  currentPixelTransparent = qAlpha( pixelColor ) == 0;
400  if ( pixelColor != currentColor && !( currentPixelTransparent && previousPixelTransparent ) )
401  {
402  //color has changed
403  currentColor = pixelColor;
404  changes++;
405  }
406  previousPixelTransparent = currentPixelTransparent;
407  }
408  candidates.append( qMakePair( candidateRow, changes ) );
409  }
410 
411  //sort candidate rows by number of changes ascending, row number descending
412  qSort( candidates.begin(), candidates.end(), candidateSort );
413  //first candidate is now the largest row with smallest number of changes
414 
415  //ok, now take the mid point of the best candidate position
416  //we do this so that the spacing between text lines is likely to be split in half
417  //otherwise the html will be broken immediately above a line of text, which
418  //looks a little messy
419  int maxCandidateRow = candidates[0].first;
420  int minCandidateRow = maxCandidateRow + 1;
421  int minCandidateChanges = candidates[0].second;
422 
423  QList< QPair<int, int> >::iterator it;
424  for ( it = candidates.begin(); it != candidates.end(); ++it )
425  {
426  if (( *it ).second != minCandidateChanges || ( *it ).first != minCandidateRow - 1 )
427  {
428  //no longer in a consecutive block of rows of minimum pixel color changes
429  //so return the row mid-way through the block
430  //first converting back to mm
431  return ( minCandidateRow + ( maxCandidateRow - minCandidateRow ) / 2 ) / htmlUnitsToMM();
432  }
433  minCandidateRow = ( *it ).first;
434  }
435 
436  //above loop didn't work for some reason
437  //return first candidate converted to mm
438  return candidates[0].first / htmlUnitsToMM();
439 }
440 
441 void QgsComposerHtml::setUseSmartBreaks( bool useSmartBreaks )
442 {
443  mUseSmartBreaks = useSmartBreaks;
445  emit changed();
446 }
447 
448 void QgsComposerHtml::setMaxBreakDistance( double maxBreakDistance )
449 {
450  mMaxBreakDistance = maxBreakDistance;
452  emit changed();
453 }
454 
455 void QgsComposerHtml::setUserStylesheet( const QString stylesheet )
456 {
457  mUserStylesheet = stylesheet;
458  //TODO - this signal should be emitted, but without changing the signal which sets the css
459  //to an equivalent of editingFinished it causes a lot of problems. Need to investigate
460  //ways of doing this using QScintilla widgets.
461  //emit changed();
462 }
463 
464 void QgsComposerHtml::setUserStylesheetEnabled( const bool stylesheetEnabled )
465 {
466  if ( mEnableUserStylesheet != stylesheetEnabled )
467  {
468  mEnableUserStylesheet = stylesheetEnabled;
469  loadHtml( true );
470  emit changed();
471  }
472 }
473 
475 {
476  return tr( "<html frame>" );
477 }
478 
479 bool QgsComposerHtml::writeXML( QDomElement& elem, QDomDocument & doc, bool ignoreFrames ) const
480 {
481  QDomElement htmlElem = doc.createElement( "ComposerHtml" );
482  htmlElem.setAttribute( "contentMode", QString::number(( int ) mContentMode ) );
483  htmlElem.setAttribute( "url", mUrl.toString() );
484  htmlElem.setAttribute( "html", mHtml );
485  htmlElem.setAttribute( "evaluateExpressions", mEvaluateExpressions ? "true" : "false" );
486  htmlElem.setAttribute( "useSmartBreaks", mUseSmartBreaks ? "true" : "false" );
487  htmlElem.setAttribute( "maxBreakDistance", QString::number( mMaxBreakDistance ) );
488  htmlElem.setAttribute( "stylesheet", mUserStylesheet );
489  htmlElem.setAttribute( "stylesheetEnabled", mEnableUserStylesheet ? "true" : "false" );
490 
491  bool state = _writeXML( htmlElem, doc, ignoreFrames );
492  elem.appendChild( htmlElem );
493  return state;
494 }
495 
496 bool QgsComposerHtml::readXML( const QDomElement& itemElem, const QDomDocument& doc, bool ignoreFrames )
497 {
498  if ( !ignoreFrames )
499  {
500  deleteFrames();
501  }
502 
503  //first create the frames
504  if ( !_readXML( itemElem, doc, ignoreFrames ) )
505  {
506  return false;
507  }
508 
509  bool contentModeOK;
510  mContentMode = ( QgsComposerHtml::ContentMode )itemElem.attribute( "contentMode" ).toInt( &contentModeOK );
511  if ( !contentModeOK )
512  {
513  mContentMode = QgsComposerHtml::Url;
514  }
515  mEvaluateExpressions = itemElem.attribute( "evaluateExpressions", "true" ) == "true" ? true : false;
516  mUseSmartBreaks = itemElem.attribute( "useSmartBreaks", "true" ) == "true" ? true : false;
517  mMaxBreakDistance = itemElem.attribute( "maxBreakDistance", "10" ).toDouble();
518  mHtml = itemElem.attribute( "html" );
519  mUserStylesheet = itemElem.attribute( "stylesheet" );
520  mEnableUserStylesheet = itemElem.attribute( "stylesheetEnabled", "false" ) == "true" ? true : false;
521 
522  //finally load the set url
523  QString urlString = itemElem.attribute( "url" );
524  if ( !urlString.isEmpty() )
525  {
526  mUrl = urlString;
527  }
528  loadHtml( true );
529 
530  //since frames had to be created before, we need to emit a changed signal to refresh the widget
531  emit changed();
532  return true;
533 }
534 
535 void QgsComposerHtml::setExpressionContext( QgsFeature* feature, QgsVectorLayer* layer )
536 {
537  mExpressionFeature = feature;
538  mExpressionLayer = layer;
539 
540  //setup distance area conversion
541  if ( layer )
542  {
543  mDistanceArea->setSourceCrs( layer->crs().srsid() );
544  }
545  else if ( mComposition )
546  {
547  //set to composition's mapsettings' crs
548  mDistanceArea->setSourceCrs( mComposition->mapSettings().destinationCrs().srsid() );
549  }
550  if ( mComposition )
551  {
553  }
554  mDistanceArea->setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );
555 }
556 
558 {
559  QgsVectorLayer * vl = 0;
560  QgsFeature* feature = 0;
561 
563  {
565  }
567  {
569  }
570 
571  setExpressionContext( feature, vl );
572  loadHtml( true );
573 }
574 
576 {
577  //updates data defined properties and redraws item to match
578  if ( property == QgsComposerObject::SourceUrl || property == QgsComposerObject::AllProperties )
579  {
580  loadHtml( true );
581  }
583 }
virtual void recalculateFrameSizes()
Recalculates the portion of the multiframe item which is shown in each of it's component frames...
QgsComposition::AtlasMode atlasMode() const
Returns the current atlas mode of the composition.
QString contentAsString() const
Returns the fetched content as a string.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
bool writeXML(QDomElement &elem, QDomDocument &doc, bool ignoreFrames=false) const override
Stores state information about multiframe in DOM element.
virtual QString displayName() const override
Get multiframe display name.
const QgsMapSettings & mapSettings() const
Return setting of QGIS map canvas.
void setSourceCrs(long srsid)
sets source spatial reference system (by QGIS CRS)
void setHtml(const QString html)
Sets the HTML to display in the item when the item is using the QgsComposerHtml::ManualHtml mode...
void setUserStylesheet(const QString stylesheet)
Sets the user stylesheet CSS rules to use while rendering the HTML content.
QMap< QgsComposerObject::DataDefinedProperty, QString > mDataDefinedNames
Map of data defined properties for the item to string name to use when exporting item to xml...
static QgsNetworkAccessManager * instance()
Definition: qgssingleton.h:23
A item that forms part of a map composition.
virtual void refreshDataDefinedProperty(const QgsComposerObject::DataDefinedProperty property=QgsComposerObject::AllProperties) override
bool enabled() const
Returns whether the atlas generation is enabled.
void fetchContent(const QUrl url)
Fetches content from a remote URL and handles redirects.
bool hasCrsTransformEnabled() const
returns true if projections are enabled for this layer set
QNetworkReply * reply()
Returns a reference to the network reply.
DataDefinedProperty
Data defined properties for different item types.
bool setEllipsoid(const QString &ellipsoid)
sets ellipsoid by its acronym
void setEvaluateExpressions(bool evaluateExpressions)
Sets whether the html item will evaluate QGIS expressions prior to rendering the HTML content...
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:113
QSizeF totalSize() const override
Returns the total size of the multiframe's content.
bool dataDefinedEvaluate(const QgsComposerObject::DataDefinedProperty property, QVariant &expressionValue)
Evaluate a data defined property and return the calculated value.
bool useSmartBreaks() const
Returns whether html item is using smart breaks.
QString html() const
Returns the HTML source displayed in the item if the item is using the QgsComposerHtml::ManualHtml mo...
bool _readXML(const QDomElement &itemElem, const QDomDocument &doc, bool ignoreFrames=false)
Restores state information about base multiframe object from a DOM element.
HTTP network content fetcher.
int printResolution() const
void recalculateFrameSizes() override
Recalculates the frame sizes for the current viewport dimensions.
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
Abstract base class for composer items with the ability to distribute the content to several frames (...
void addFrame(QgsComposerFrame *frame, bool recalcFrameSizes=true) override
Adds a frame to the multiframe.
QList< QgsComposerFrame * > mFrameItems
bool _writeXML(QDomElement &elem, QDomDocument &doc, bool ignoreFrames=false) const
Stores state information about base multiframe object in DOM element.
void setMaxBreakDistance(double maxBreakDistance)
Sets the maximum distance allowed when calculating where to place page breaks in the html...
bool evaluateExpressions() const
Returns whether html item will evaluate QGIS expressions prior to rendering the HTML content...
void setUseSmartBreaks(bool useSmartBreaks)
Sets whether the html item should use smart breaks.
int frameCount() const
Returns the number of frames associated with this multiframe.
void loadHtml(const bool useCache=false)
Reloads the html source from the url and redraws the item.
Graphics scene for map printing.
QgsFeature * currentFeature()
Returns the current atlas feature.
Frame item for a composer multiframe item.
const QUrl & url() const
Returns the URL of the content displayed in the item if the item is using the QgsComposerHtml::Url mo...
General purpose distance and area calculator.
QgsComposition * mComposition
void deleteFrames()
Removes and deletes all child frames.
void refreshExpressionContext()
void contentsChanged()
Emitted when the contents of the multi frame have changed and the frames must be redrawn.
double maxBreakDistance() const
Returns the maximum distance allowed when calculating where to place page breaks in the html...
void addComposerHtmlFrame(QgsComposerHtml *html, QgsComposerFrame *frame)
Adds composer html frame and advises composer to create a widget for it (through signal) ...
void setUrl(const QUrl &url)
Sets the URL for content to display in the item when the item is using the QgsComposerHtml::Url mode...
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:351
const CORE_EXPORT QString GEO_NONE
Constant that holds the string representation for "No ellips/No CRS".
Definition: qgis.cpp:74
const QgsCoordinateReferenceSystem & crs() const
Returns layer's spatial reference system.
QgsAtlasComposition & atlasComposition()
QgsVectorLayer * coverageLayer() const
Returns the coverage layer used for the atlas features.
void setUserStylesheetEnabled(const bool stylesheetEnabled)
Sets whether user stylesheets are enabled for the HTML content.
bool readXML(const QDomElement &itemElem, const QDomDocument &doc, bool ignoreFrames=false) override
Reads multiframe state information from a DOM element.
Represents a vector layer which manages a vector based data sets.
ContentMode
Source modes for the HTML content to render in the item.
double findNearbyPageBreak(double yPos) override
Finds the optimal position to break a frame at.
void handleFrameRemoval(QgsComposerItem *item)
Called before a frame is going to be removed.
bool candidateSort(const QPair< int, int > &c1, const QPair< int, int > &c2)
virtual void refreshDataDefinedProperty(const DataDefinedProperty property=AllProperties)
Refreshes a data defined property for the item by reevaluating the property's value and redrawing the...
void setEllipsoidalMode(bool flag)
sets whether coordinates must be projected to ellipsoid before measuring
void render(QPainter *p, const QRectF &renderExtent, const int frameIndex) override
Renders a portion of the multiframe's content into a painter.
void changed()
Emitted when the properties of a multi frame have changed, and the GUI item widget must be updated...
#define tr(sourceText)
static QString replaceExpressionText(const QString &action, const QgsFeature *feat, QgsVectorLayer *layer, const QMap< QString, QVariant > *substitutionMap=0, const QgsDistanceArea *distanceArea=0)
This function currently replaces each expression between [% and %] in the string with the result of i...