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