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