QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgslayoutitemhtml.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayoutitemhtml.cpp
3  ------------------------------------------------------------
4  begin : October 2017
5  copyright : (C) 2017 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
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 "qgslayoutitemhtml.h"
17 #include "qgslayoutframe.h"
18 #include "qgslayout.h"
20 #include "qgsmessagelog.h"
21 #include "qgsexpression.h"
22 #include "qgslogger.h"
24 #include "qgsvectorlayer.h"
25 #include "qgsproject.h"
26 #include "qgsdistancearea.h"
27 #include "qgsjsonutils.h"
28 #include "qgsmapsettings.h"
29 #include "qgswebpage.h"
30 #include "qgswebframe.h"
31 #include "qgslayoutitemmap.h"
32 
33 #include <QCoreApplication>
34 #include <QPainter>
35 #include <QImage>
36 #include <QNetworkReply>
37 
38 // clazy:excludeall=lambda-in-connect
39 
41  : QgsLayoutMultiFrame( layout )
42 {
43  mHtmlUnitsToLayoutUnits = htmlUnitsToLayoutUnits();
44 
45  // only possible on the main thread!
46  if ( QThread::currentThread() == QApplication::instance()->thread() )
47  {
48  mWebPage = qgis::make_unique< QgsWebPage >();
49  }
50  else
51  {
52  QgsMessageLog::logMessage( QObject::tr( "Cannot load HTML content in background threads" ) );
53  }
54 
55  if ( mWebPage )
56  {
57  mWebPage->setIdentifier( tr( "Layout HTML item" ) );
58  mWebPage->mainFrame()->setScrollBarPolicy( Qt::Horizontal, Qt::ScrollBarAlwaysOff );
59  mWebPage->mainFrame()->setScrollBarPolicy( Qt::Vertical, Qt::ScrollBarAlwaysOff );
60 
61  //This makes the background transparent. Found on http://blog.qt.digia.com/blog/2009/06/30/transparent-qwebview-or-qwebpage/
62  QPalette palette = mWebPage->palette();
63  palette.setBrush( QPalette::Base, Qt::transparent );
64  mWebPage->setPalette( palette );
65 
66  mWebPage->setNetworkAccessManager( QgsNetworkAccessManager::instance() );
67  }
68 
69  //a html item added to a layout needs to have the initial expression context set,
70  //otherwise fields in the html aren't correctly evaluated until atlas preview feature changes (#9457)
71  setExpressionContext( mLayout->reportContext().feature(), mLayout->reportContext().layer() );
72 
73  connect( &mLayout->reportContext(), &QgsLayoutReportContext::changed, this, &QgsLayoutItemHtml::refreshExpressionContext );
74 
75  mFetcher = new QgsNetworkContentFetcher();
76 }
77 
79 {
80  mFetcher->deleteLater();
81 }
82 
84 {
86 }
87 
89 {
90  return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemHtml.svg" ) );
91 }
92 
94 {
95  return new QgsLayoutItemHtml( layout );
96 }
97 
98 void QgsLayoutItemHtml::setUrl( const QUrl &url )
99 {
100  if ( !mWebPage )
101  {
102  return;
103  }
104 
105  mUrl = url;
106  loadHtml( true );
107  emit changed();
108 }
109 
110 void QgsLayoutItemHtml::setHtml( const QString &html )
111 {
112  mHtml = html;
113  //TODO - this signal should be emitted, but without changing the signal which sets the html
114  //to an equivalent of editingFinished it causes a lot of problems. Need to investigate
115  //ways of doing this using QScintilla widgets.
116  //emit changed();
117 }
118 
119 void QgsLayoutItemHtml::setEvaluateExpressions( bool evaluateExpressions )
120 {
121  mEvaluateExpressions = evaluateExpressions;
122  loadHtml( true );
123  emit changed();
124 }
125 
126 void QgsLayoutItemHtml::loadHtml( const bool useCache, const QgsExpressionContext *context )
127 {
128  if ( !mWebPage )
129  {
130  return;
131  }
132 
134  const QgsExpressionContext *evalContext = context ? context : &scopedContext;
135 
136  QString loadedHtml;
137  switch ( mContentMode )
138  {
140  {
141 
142  QString currentUrl = mUrl.toString();
143 
144  //data defined url set?
145  bool ok = false;
146  currentUrl = mDataDefinedProperties.valueAsString( QgsLayoutObject::SourceUrl, *evalContext, currentUrl, &ok );
147  if ( ok )
148  {
149  currentUrl = currentUrl.trimmed();
150  QgsDebugMsg( QStringLiteral( "exprVal Source Url:%1" ).arg( currentUrl ) );
151  }
152  if ( currentUrl.isEmpty() )
153  {
154  return;
155  }
156  if ( !( useCache && currentUrl == mLastFetchedUrl ) )
157  {
158  loadedHtml = fetchHtml( QUrl( currentUrl ) );
159  mLastFetchedUrl = currentUrl;
160  }
161  else
162  {
163  loadedHtml = mFetchedHtml;
164  }
165 
166  break;
167  }
169  loadedHtml = mHtml;
170  break;
171  }
172 
173  //evaluate expressions
174  if ( mEvaluateExpressions )
175  {
176  loadedHtml = QgsExpression::replaceExpressionText( loadedHtml, evalContext, &mDistanceArea );
177  }
178 
179  bool loaded = false;
180 
181  QEventLoop loop;
182  connect( mWebPage.get(), &QWebPage::loadFinished, &loop, [&loaded, &loop ] { loaded = true; loop.quit(); } );
183  connect( mFetcher, &QgsNetworkContentFetcher::finished, &loop, [&loaded, &loop ] { loaded = true; loop.quit(); } );
184 
185  //reset page size. otherwise viewport size increases but never decreases again
186  mWebPage->setViewportSize( QSize( maxFrameWidth() * mHtmlUnitsToLayoutUnits, 0 ) );
187 
188  //set html, using the specified url as base if in Url mode or the project file if in manual mode
189  const QUrl baseUrl = mContentMode == QgsLayoutItemHtml::Url ?
190  QUrl( mActualFetchedUrl ) :
191  QUrl::fromLocalFile( mLayout->project()->absoluteFilePath() );
192 
193  mWebPage->mainFrame()->setHtml( loadedHtml, baseUrl );
194 
195  //set user stylesheet
196  QWebSettings *settings = mWebPage->settings();
197  if ( mEnableUserStylesheet && ! mUserStylesheet.isEmpty() )
198  {
199  QByteArray ba;
200  ba.append( mUserStylesheet.toUtf8() );
201  QUrl cssFileURL = QUrl( QString( "data:text/css;charset=utf-8;base64," + ba.toBase64() ) );
202  settings->setUserStyleSheetUrl( cssFileURL );
203  }
204  else
205  {
206  settings->setUserStyleSheetUrl( QUrl() );
207  }
208 
209  if ( !loaded )
210  loop.exec( QEventLoop::ExcludeUserInputEvents );
211 
212  //inject JSON feature
213  if ( !mAtlasFeatureJSON.isEmpty() )
214  {
215  JavascriptExecutorLoop jsLoop;
216 
217  mWebPage->mainFrame()->addToJavaScriptWindowObject( QStringLiteral( "loop" ), &jsLoop );
218  mWebPage->mainFrame()->evaluateJavaScript( QStringLiteral( "if ( typeof setFeature === \"function\" ) { try{ setFeature(%1); } catch (err) { loop.reportError(err.message); } }; loop.done();" ).arg( mAtlasFeatureJSON ) );
219 
220  jsLoop.execIfNotDone();
221  }
222 
224  //trigger a repaint
225  emit contentsChanged();
226 }
227 
228 double QgsLayoutItemHtml::maxFrameWidth() const
229 {
230  double maxWidth = 0;
231  for ( QgsLayoutFrame *frame : mFrameItems )
232  {
233  maxWidth = std::max( maxWidth, static_cast< double >( frame->boundingRect().width() ) );
234  }
235 
236  return maxWidth;
237 }
238 
240 {
241  if ( frameCount() < 1 )
242  return;
243 
244  if ( !mWebPage )
245  return;
246 
247  QSize contentsSize = mWebPage->mainFrame()->contentsSize();
248 
249  //find maximum frame width
250  double maxWidth = maxFrameWidth();
251  //set content width to match maximum frame width
252  contentsSize.setWidth( maxWidth * mHtmlUnitsToLayoutUnits );
253 
254  mWebPage->setViewportSize( contentsSize );
255  mSize.setWidth( contentsSize.width() / mHtmlUnitsToLayoutUnits );
256  mSize.setHeight( contentsSize.height() / mHtmlUnitsToLayoutUnits );
257  if ( contentsSize.isValid() )
258  {
259  renderCachedImage();
260  }
262  emit changed();
263 }
264 
265 void QgsLayoutItemHtml::renderCachedImage()
266 {
267  if ( !mWebPage )
268  return;
269 
270  //render page to cache image
271  mRenderedPage = QImage( mWebPage->viewportSize(), QImage::Format_ARGB32 );
272  if ( mRenderedPage.isNull() )
273  {
274  return;
275  }
276  mRenderedPage.fill( Qt::transparent );
277  QPainter painter;
278  painter.begin( &mRenderedPage );
279  mWebPage->mainFrame()->render( &painter );
280  painter.end();
281 }
282 
283 QString QgsLayoutItemHtml::fetchHtml( const QUrl &url )
284 {
285  //pause until HTML fetch
286  bool loaded = false;
287  QEventLoop loop;
288  connect( mFetcher, &QgsNetworkContentFetcher::finished, &loop, [&loaded, &loop ] { loaded = true; loop.quit(); } );
289  mFetcher->fetchContent( url );
290 
291  if ( !loaded )
292  loop.exec( QEventLoop::ExcludeUserInputEvents );
293 
294  mFetchedHtml = mFetcher->contentAsString();
295  mActualFetchedUrl = mFetcher->reply()->url().toString();
296  return mFetchedHtml;
297 }
298 
300 {
301  return mSize;
302 }
303 
304 void QgsLayoutItemHtml::render( QgsLayoutItemRenderContext &context, const QRectF &renderExtent, const int )
305 {
306  if ( !mWebPage )
307  return;
308 
309  QPainter *painter = context.renderContext().painter();
310  QgsScopedQPainterState painterState( painter );
311  // painter is scaled to dots, so scale back to layout units
312  painter->scale( context.renderContext().scaleFactor() / mHtmlUnitsToLayoutUnits, context.renderContext().scaleFactor() / mHtmlUnitsToLayoutUnits );
313  painter->translate( 0.0, -renderExtent.top() * mHtmlUnitsToLayoutUnits );
314  mWebPage->mainFrame()->render( painter, QRegion( renderExtent.left(), renderExtent.top() * mHtmlUnitsToLayoutUnits, renderExtent.width() * mHtmlUnitsToLayoutUnits, renderExtent.height() * mHtmlUnitsToLayoutUnits ) );
315 }
316 
317 double QgsLayoutItemHtml::htmlUnitsToLayoutUnits()
318 {
319  if ( !mLayout )
320  {
321  return 1.0;
322  }
323 
324  return mLayout->convertToLayoutUnits( QgsLayoutMeasurement( mLayout->renderContext().dpi() / 72.0, QgsUnitTypes::LayoutMillimeters ) ); //webkit seems to assume a standard dpi of 96
325 }
326 
327 bool candidateSort( QPair<int, int> c1, QPair<int, int> c2 )
328 {
329  if ( c1.second < c2.second )
330  return true;
331  else if ( c1.second > c2.second )
332  return false;
333  else if ( c1.first > c2.first )
334  return true;
335  else
336  return false;
337 }
338 
340 {
341  if ( !mWebPage || mRenderedPage.isNull() || !mUseSmartBreaks )
342  {
343  return yPos;
344  }
345 
346  //convert yPos to pixels
347  int idealPos = yPos * htmlUnitsToLayoutUnits();
348 
349  //if ideal break pos is past end of page, there's nothing we need to do
350  if ( idealPos >= mRenderedPage.height() )
351  {
352  return yPos;
353  }
354 
355  int maxSearchDistance = mMaxBreakDistance * htmlUnitsToLayoutUnits();
356 
357  //loop through all lines just before ideal break location, up to max distance
358  //of maxSearchDistance
359  int changes = 0;
360  QRgb currentColor;
361  bool currentPixelTransparent = false;
362  bool previousPixelTransparent = false;
363  QRgb pixelColor;
364  QList< QPair<int, int> > candidates;
365  int minRow = std::max( idealPos - maxSearchDistance, 0 );
366  for ( int candidateRow = idealPos; candidateRow >= minRow; --candidateRow )
367  {
368  changes = 0;
369  currentColor = qRgba( 0, 0, 0, 0 );
370  //check all pixels in this line
371  for ( int col = 0; col < mRenderedPage.width(); ++col )
372  {
373  //count how many times the pixels change color in this row
374  //eventually, we select a row to break at with the minimum number of color changes
375  //since this is likely a line break, or gap between table cells, etc
376  //but very unlikely to be midway through a text line or picture
377  pixelColor = mRenderedPage.pixel( col, candidateRow );
378  currentPixelTransparent = qAlpha( pixelColor ) == 0;
379  if ( pixelColor != currentColor && !( currentPixelTransparent && previousPixelTransparent ) )
380  {
381  //color has changed
382  currentColor = pixelColor;
383  changes++;
384  }
385  previousPixelTransparent = currentPixelTransparent;
386  }
387  candidates.append( qMakePair( candidateRow, changes ) );
388  }
389 
390  //sort candidate rows by number of changes ascending, row number descending
391  std::sort( candidates.begin(), candidates.end(), candidateSort );
392  //first candidate is now the largest row with smallest number of changes
393 
394  //OK, now take the mid point of the best candidate position
395  //we do this so that the spacing between text lines is likely to be split in half
396  //otherwise the html will be broken immediately above a line of text, which
397  //looks a little messy
398  int maxCandidateRow = candidates[0].first;
399  int minCandidateRow = maxCandidateRow + 1;
400  int minCandidateChanges = candidates[0].second;
401 
402  QList< QPair<int, int> >::iterator it;
403  for ( it = candidates.begin(); it != candidates.end(); ++it )
404  {
405  if ( ( *it ).second != minCandidateChanges || ( *it ).first != minCandidateRow - 1 )
406  {
407  //no longer in a consecutive block of rows of minimum pixel color changes
408  //so return the row mid-way through the block
409  //first converting back to mm
410  return ( minCandidateRow + ( maxCandidateRow - minCandidateRow ) / 2 ) / htmlUnitsToLayoutUnits();
411  }
412  minCandidateRow = ( *it ).first;
413  }
414 
415  //above loop didn't work for some reason
416  //return first candidate converted to mm
417  return candidates[0].first / htmlUnitsToLayoutUnits();
418 }
419 
420 void QgsLayoutItemHtml::setUseSmartBreaks( bool useSmartBreaks )
421 {
422  mUseSmartBreaks = useSmartBreaks;
424  emit changed();
425 }
426 
427 void QgsLayoutItemHtml::setMaxBreakDistance( double maxBreakDistance )
428 {
429  mMaxBreakDistance = maxBreakDistance;
431  emit changed();
432 }
433 
434 void QgsLayoutItemHtml::setUserStylesheet( const QString &stylesheet )
435 {
436  mUserStylesheet = stylesheet;
437  //TODO - this signal should be emitted, but without changing the signal which sets the css
438  //to an equivalent of editingFinished it causes a lot of problems. Need to investigate
439  //ways of doing this using QScintilla widgets.
440  //emit changed();
441 }
442 
443 void QgsLayoutItemHtml::setUserStylesheetEnabled( const bool stylesheetEnabled )
444 {
445  if ( mEnableUserStylesheet != stylesheetEnabled )
446  {
447  mEnableUserStylesheet = stylesheetEnabled;
448  loadHtml( true );
449  emit changed();
450  }
451 }
452 
454 {
455  return tr( "<HTML frame>" );
456 }
457 
458 bool QgsLayoutItemHtml::writePropertiesToElement( QDomElement &htmlElem, QDomDocument &, const QgsReadWriteContext & ) const
459 {
460  htmlElem.setAttribute( QStringLiteral( "contentMode" ), QString::number( static_cast< int >( mContentMode ) ) );
461  htmlElem.setAttribute( QStringLiteral( "url" ), mUrl.toString() );
462  htmlElem.setAttribute( QStringLiteral( "html" ), mHtml );
463  htmlElem.setAttribute( QStringLiteral( "evaluateExpressions" ), mEvaluateExpressions ? "true" : "false" );
464  htmlElem.setAttribute( QStringLiteral( "useSmartBreaks" ), mUseSmartBreaks ? "true" : "false" );
465  htmlElem.setAttribute( QStringLiteral( "maxBreakDistance" ), QString::number( mMaxBreakDistance ) );
466  htmlElem.setAttribute( QStringLiteral( "stylesheet" ), mUserStylesheet );
467  htmlElem.setAttribute( QStringLiteral( "stylesheetEnabled" ), mEnableUserStylesheet ? "true" : "false" );
468  return true;
469 }
470 
471 bool QgsLayoutItemHtml::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &, const QgsReadWriteContext & )
472 {
473  bool contentModeOK;
474  mContentMode = static_cast< QgsLayoutItemHtml::ContentMode >( itemElem.attribute( QStringLiteral( "contentMode" ) ).toInt( &contentModeOK ) );
475  if ( !contentModeOK )
476  {
477  mContentMode = QgsLayoutItemHtml::Url;
478  }
479  mEvaluateExpressions = itemElem.attribute( QStringLiteral( "evaluateExpressions" ), QStringLiteral( "true" ) ) == QLatin1String( "true" );
480  mUseSmartBreaks = itemElem.attribute( QStringLiteral( "useSmartBreaks" ), QStringLiteral( "true" ) ) == QLatin1String( "true" );
481  mMaxBreakDistance = itemElem.attribute( QStringLiteral( "maxBreakDistance" ), QStringLiteral( "10" ) ).toDouble();
482  mHtml = itemElem.attribute( QStringLiteral( "html" ) );
483  mUserStylesheet = itemElem.attribute( QStringLiteral( "stylesheet" ) );
484  mEnableUserStylesheet = itemElem.attribute( QStringLiteral( "stylesheetEnabled" ), QStringLiteral( "false" ) ) == QLatin1String( "true" );
485 
486  //finally load the set url
487  QString urlString = itemElem.attribute( QStringLiteral( "url" ) );
488  if ( !urlString.isEmpty() )
489  {
490  mUrl = urlString;
491  }
492  loadHtml( true );
493 
494  //since frames had to be created before, we need to emit a changed signal to refresh the widget
495  emit changed();
496  return true;
497 }
498 
499 void QgsLayoutItemHtml::setExpressionContext( const QgsFeature &feature, QgsVectorLayer *layer )
500 {
501  mExpressionFeature = feature;
502  mExpressionLayer = layer;
503 
504  //setup distance area conversion
505  if ( layer )
506  {
507  mDistanceArea.setSourceCrs( layer->crs(), mLayout->project()->transformContext() );
508  }
509  else if ( mLayout )
510  {
511  //set to composition's mapsettings' crs
512  QgsLayoutItemMap *referenceMap = mLayout->referenceMap();
513  if ( referenceMap )
514  mDistanceArea.setSourceCrs( referenceMap->crs(), mLayout->project()->transformContext() );
515  }
516  if ( mLayout )
517  {
518  mDistanceArea.setEllipsoid( mLayout->project()->ellipsoid() );
519  }
520 
521  if ( feature.isValid() )
522  {
523  // create JSON representation of feature
524  QgsJsonExporter exporter( layer );
525  exporter.setIncludeRelated( true );
526  mAtlasFeatureJSON = exporter.exportFeature( feature );
527  }
528  else
529  {
530  mAtlasFeatureJSON.clear();
531  }
532 }
533 
534 void QgsLayoutItemHtml::refreshExpressionContext()
535 {
536  QgsVectorLayer *vl = nullptr;
537  QgsFeature feature;
538 
539  if ( mLayout )
540  {
541  vl = mLayout->reportContext().layer();
542  feature = mLayout->reportContext().feature();
543  }
544 
545  setExpressionContext( feature, vl );
546  loadHtml( true );
547 }
548 
550 {
552 
553  //updates data defined properties and redraws item to match
554  if ( property == QgsLayoutObject::SourceUrl || property == QgsLayoutObject::AllProperties )
555  {
556  loadHtml( true, &context );
557  }
558 }
559 
560 //JavascriptExecutorLoop
562 
563 void JavascriptExecutorLoop::done()
564 {
565  mDone = true;
566  quit();
567 }
568 
569 void JavascriptExecutorLoop::execIfNotDone()
570 {
571  if ( !mDone )
572  exec( QEventLoop::ExcludeUserInputEvents );
573 
574  // gross, but nothing else works, so f*** it.. it's not worth spending a day trying to find a non-hacky way
575  // to force the web page to update following the js execution
576  for ( int i = 0; i < 100; i++ )
577  qApp->processEvents();
578 }
579 
580 void JavascriptExecutorLoop::reportError( const QString &error )
581 {
582  mDone = true;
583  QgsMessageLog::logMessage( tr( "HTML setFeature function error: %1" ).arg( error ), tr( "Layout" ) );
584  quit();
585 }
586 
QgsLayoutMultiFrame::frame
QgsLayoutFrame * frame(int index) const
Returns the child frame at a specified index from the multiframe.
Definition: qgslayoutmultiframe.cpp:469
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:370
QgsMapLayer::crs
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:89
QgsLayoutObject::layout
const QgsLayout * layout() const
Returns the layout the object is attached to.
Definition: qgslayoutobject.cpp:126
QgsLayoutMultiFrame::createExpressionContext
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Definition: qgslayoutmultiframe.cpp:283
QgsLayoutItemHtml::evaluateExpressions
bool evaluateExpressions() const
Returns whether html item will evaluate QGIS expressions prior to rendering the HTML content.
Definition: qgslayoutitemhtml.h:125
QgsLayoutItemHtml::setUserStylesheetEnabled
void setUserStylesheetEnabled(bool enabled)
Sets whether user stylesheets are enabled for the HTML content.
Definition: qgslayoutitemhtml.cpp:443
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Definition: qgsapplication.cpp:626
QgsLayoutItemHtml::render
void render(QgsLayoutItemRenderContext &context, const QRectF &renderExtent, int frameIndex) override
Renders a portion of the multiframe's content into a render context.
Definition: qgslayoutitemhtml.cpp:304
QgsLayoutItemHtml::setUseSmartBreaks
void setUseSmartBreaks(bool useSmartBreaks)
Sets whether the html item should use smart breaks.
Definition: qgslayoutitemhtml.cpp:420
QgsReadWriteContext
The class is used as a container of context for various read/write operations on other objects.
Definition: qgsreadwritecontext.h:35
qgsexpression.h
qgswebframe.h
QgsLayoutItemHtml::setHtml
void setHtml(const QString &html)
Sets the html to display in the item when the item is using the QgsLayoutItemHtml::ManualHtml mode.
Definition: qgslayoutitemhtml.cpp:110
QWebSettings
The QWebSettings class is a collection of stubs to mimic the API of a QWebSettings on systems where Q...
Definition: qgswebpage.h:43
QgsLayoutItemRenderContext
Contains settings and helpers relating to a render of a QgsLayoutItem.
Definition: qgslayoutitem.h:45
QgsLayoutItemHtml
A layout multiframe subclass for HTML content.
Definition: qgslayoutitemhtml.h:37
QgsLayoutObject::mDataDefinedProperties
QgsPropertyCollection mDataDefinedProperties
Definition: qgslayoutobject.h:345
QgsLayoutItemHtml::totalSize
QSizeF totalSize() const override
Returns the total size of the multiframe's content, in layout units.
Definition: qgslayoutitemhtml.cpp:299
QgsLayoutItemHtml::readPropertiesFromElement
bool readPropertiesFromElement(const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context) override
Sets multiframe state from a DOM element.
Definition: qgslayoutitemhtml.cpp:471
QgsLayoutItemHtml::QgsLayoutItemHtml
QgsLayoutItemHtml(QgsLayout *layout)
Constructor for QgsLayoutItemHtml, with the specified parent layout.
Definition: qgslayoutitemhtml.cpp:40
QgsLayoutItemHtml::refreshDataDefinedProperty
void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::AllProperties) override
Definition: qgslayoutitemhtml.cpp:549
QgsLayoutItemHtml::setUserStylesheet
void setUserStylesheet(const QString &stylesheet)
Sets the user stylesheet CSS rules to use while rendering the HTML content.
Definition: qgslayoutitemhtml.cpp:434
QgsLayoutItemHtml::icon
QIcon icon() const override
Returns the item's icon.
Definition: qgslayoutitemhtml.cpp:88
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsLayoutMultiFrame
Abstract base class for layout items with the ability to distribute the content to several frames (Qg...
Definition: qgslayoutmultiframe.h:49
qgsmapsettings.h
QgsRenderContext::scaleFactor
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
Definition: qgsrendercontext.h:333
QgsLayoutItemHtml::setUrl
void setUrl(const QUrl &url)
Sets the url for content to display in the item when the item is using the QgsLayoutItemHtml::Url mod...
Definition: qgslayoutitemhtml.cpp:98
QgsLayoutObject::changed
void changed()
Emitted when the object's properties change.
QgsLayoutMultiFrame::mFrameItems
QList< QgsLayoutFrame * > mFrameItems
Definition: qgslayoutmultiframe.h:408
qgslayoutframe.h
qgswebpage.h
QgsDistanceArea::setEllipsoid
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
Definition: qgsdistancearea.cpp:66
QgsLayoutItemHtml::loadHtml
void loadHtml(bool useCache=false, const QgsExpressionContext *context=nullptr)
Reloads the html source from the url and redraws the item.
Definition: qgslayoutitemhtml.cpp:126
QgsLayoutItemHtml::ContentMode
ContentMode
Source modes for the HTML content to render in the item.
Definition: qgslayoutitemhtml.h:44
QgsLayoutObject::AllProperties
@ AllProperties
All properties for item.
Definition: qgslayoutobject.h:135
QgsNetworkContentFetcher
HTTP network content fetcher.
Definition: qgsnetworkcontentfetcher.h:38
QgsLayoutFrame
Base class for frame items, which form a layout multiframe item.
Definition: qgslayoutframe.h:32
QgsFeature::isValid
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:185
QgsNetworkContentFetcher::fetchContent
void fetchContent(const QUrl &url, const QString &authcfg=QString())
Fetches content from a remote URL and handles redirects.
Definition: qgsnetworkcontentfetcher.cpp:37
QgsLayoutItemHtml::maxBreakDistance
double maxBreakDistance() const
Returns the maximum distance allowed when calculating where to place page breaks in the html.
Definition: qgslayoutitemhtml.h:170
qgsnetworkaccessmanager.h
candidateSort
bool candidateSort(QPair< int, int > c1, QPair< int, int > c2)
Definition: qgslayoutitemhtml.cpp:327
QgsLayoutItemHtml::useSmartBreaks
bool useSmartBreaks() const
Returns whether html item is using smart breaks.
Definition: qgslayoutitemhtml.h:141
QgsNetworkContentFetcher::reply
QNetworkReply * reply()
Returns a reference to the network reply.
Definition: qgsnetworkcontentfetcher.cpp:76
QgsLayoutItemHtml::setEvaluateExpressions
void setEvaluateExpressions(bool evaluateExpressions)
Sets whether the html item will evaluate QGIS expressions prior to rendering the HTML content.
Definition: qgslayoutitemhtml.cpp:119
QgsLayoutItemHtml::html
QString html() const
Returns the HTML source displayed in the item if the item is using the QgsLayoutItemHtml::ManualHtml ...
Definition: qgslayoutitemhtml.h:116
QgsLayoutItemHtml::recalculateFrameSizes
void recalculateFrameSizes() override
Recalculates the frame sizes for the current viewport dimensions.
Definition: qgslayoutitemhtml.cpp:239
QgsDistanceArea::setSourceCrs
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
Definition: qgsdistancearea.cpp:60
QgsScopedQPainterState
Scoped object for saving and restoring a QPainter object's state.
Definition: qgsrendercontext.h:1120
QgsLayoutMultiFrame::contentsChanged
void contentsChanged()
Emitted when the contents of the multi frame have changed and the frames must be redrawn.
QgsLayoutItemHtml::writePropertiesToElement
bool writePropertiesToElement(QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context) const override
Stores multiframe state within an XML DOM element.
Definition: qgslayoutitemhtml.cpp:458
QgsLayoutReportContext::changed
void changed()
Emitted certain settings in the context is changed, e.g.
qgslayout.h
QgsLayoutItemMap::crs
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used for rendering the map.
Definition: qgslayoutitemmap.cpp:292
QgsNetworkAccessManager::instance
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
Definition: qgsnetworkaccessmanager.cpp:121
QgsAbstractPropertyCollection::valueAsString
QString valueAsString(int key, const QgsExpressionContext &context, const QString &defaultString=QString(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a string.
Definition: qgspropertycollection.cpp:42
qgsvectorlayer.h
QgsLayoutItemMap
Layout graphical items for displaying a map.
Definition: qgslayoutitemmap.h:318
QgsJsonExporter
Handles exporting QgsFeature features to GeoJSON features.
Definition: qgsjsonutils.h:46
QgsLayoutItemRenderContext::renderContext
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
Definition: qgslayoutitem.h:72
QgsLayoutItemHtml::ManualHtml
@ ManualHtml
HTML content is manually set for the item.
Definition: qgslayoutitemhtml.h:46
QgsLayoutItemHtml::type
int type() const override
Returns unique multiframe type id.
Definition: qgslayoutitemhtml.cpp:83
QgsLayoutItemHtml::displayName
QString displayName() const override
Returns the multiframe display name.
Definition: qgslayoutitemhtml.cpp:453
QgsLayoutObject::mLayout
QPointer< QgsLayout > mLayout
Definition: qgslayoutobject.h:343
QgsLayout
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:50
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:387
QgsLayoutItemHtml::setMaxBreakDistance
void setMaxBreakDistance(double distance)
Sets the maximum distance allowed when calculating where to place page breaks in the html.
Definition: qgslayoutitemhtml.cpp:427
QgsLayoutItemHtml::~QgsLayoutItemHtml
~QgsLayoutItemHtml() override
Definition: qgslayoutitemhtml.cpp:78
QgsNetworkContentFetcher::contentAsString
QString contentAsString() const
Returns the fetched content as a string.
Definition: qgsnetworkcontentfetcher.cpp:86
QgsNetworkContentFetcher::finished
void finished()
Emitted when content has loaded.
QgsMessageLog::logMessage
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Definition: qgsmessagelog.cpp:27
QgsLayoutItemHtml::url
QUrl url() const
Returns the URL of the content displayed in the item if the item is using the QgsLayoutItemHtml::Url ...
Definition: qgslayoutitemhtml.h:97
qgsdistancearea.h
QgsLayoutMultiFrame::recalculateFrameSizes
virtual void recalculateFrameSizes()
Recalculates the portion of the multiframe item which is shown in each of its component frames.
Definition: qgslayoutmultiframe.cpp:96
QgsFeature
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:56
qgsnetworkcontentfetcher.h
QgsLayoutItemRegistry::LayoutHtml
@ LayoutHtml
Html multiframe item.
Definition: qgslayoutitemregistry.h:332
QgsUnitTypes::LayoutMillimeters
@ LayoutMillimeters
Millimeters.
Definition: qgsunittypes.h:182
qgsjsonutils.h
qgslogger.h
QgsRenderContext::painter
QPainter * painter()
Returns the destination QPainter for the render operation.
Definition: qgsrendercontext.h:179
QgsLayoutItemHtml::create
static QgsLayoutItemHtml * create(QgsLayout *layout)
Returns a new QgsLayoutItemHtml for the specified parent layout.
Definition: qgslayoutitemhtml.cpp:93
QgsLayoutObject::SourceUrl
@ SourceUrl
Html source url.
Definition: qgslayoutobject.h:191
QgsExpression::replaceExpressionText
static QString replaceExpressionText(const QString &action, const QgsExpressionContext *context, const QgsDistanceArea *distanceArea=nullptr)
This function replaces each expression between [% and %] in the string with the result of its evaluat...
Definition: qgsexpression.cpp:430
qgsproject.h
QgsLayoutMeasurement
This class provides a method of storing measurements for use in QGIS layouts using a variety of diffe...
Definition: qgslayoutmeasurement.h:34
QgsLayoutMultiFrame::frameCount
int frameCount() const
Returns the number of frames associated with this multiframe.
Definition: qgslayoutmultiframe.h:265
qgslayoutitemhtml.h
QgsLayoutObject::DataDefinedProperty
DataDefinedProperty
Data defined properties for different item types.
Definition: qgslayoutobject.h:133
QgsLayoutItemHtml::findNearbyPageBreak
double findNearbyPageBreak(double yPos) override
Finds the optimal position to break a frame at.
Definition: qgslayoutitemhtml.cpp:339
qgslayoutitemmap.h
qgsmessagelog.h
QgsLayoutItemHtml::Url
@ Url
Using this mode item fetches its content via a url.
Definition: qgslayoutitemhtml.h:45