QGIS API Documentation 3.41.0-Master (45a0abf3bec)
Loading...
Searching...
No Matches
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 "moc_qgslayoutitemhtml.cpp"
18#include "qgslayoutframe.h"
19#include "qgslayout.h"
21#include "qgsmessagelog.h"
22#include "qgsexpression.h"
23#include "qgslogger.h"
25#include "qgsvectorlayer.h"
26#include "qgsproject.h"
27#include "qgsdistancearea.h"
28#include "qgsjsonutils.h"
29#include "qgsmapsettings.h"
30#include "qgswebpage.h"
31#include "qgswebframe.h"
32#include "qgslayoutitemlabel.h"
33#include "qgslayoutitemmap.h"
36
37#include <QCoreApplication>
38#include <QPainter>
39#include <QImage>
40#include <QNetworkReply>
41#include <QThread>
42#include <QUrl>
43#include <QAbstractTextDocumentLayout>
44
45// clazy:excludeall=lambda-in-connect
46
48 : QgsLayoutMultiFrame( layout )
49{
50 mHtmlUnitsToLayoutUnits = htmlUnitsToLayoutUnits();
51
52 // only possible on the main thread!
53 if ( QThread::currentThread() == QApplication::instance()->thread() )
54 {
55 mWebPage = std::make_unique< QgsWebPage >();
56 }
57 else
58 {
59 QgsMessageLog::logMessage( QObject::tr( "Cannot load HTML content in background threads" ) );
60 }
61
62 if ( mWebPage )
63 {
64 mWebPage->setIdentifier( tr( "Layout HTML item" ) );
65 mWebPage->mainFrame()->setScrollBarPolicy( Qt::Horizontal, Qt::ScrollBarAlwaysOff );
66 mWebPage->mainFrame()->setScrollBarPolicy( Qt::Vertical, Qt::ScrollBarAlwaysOff );
67
68 //This makes the background transparent. Found on http://blog.qt.digia.com/blog/2009/06/30/transparent-qwebview-or-qwebpage/
69 QPalette palette = mWebPage->palette();
70 palette.setBrush( QPalette::Base, Qt::transparent );
71 mWebPage->setPalette( palette );
72
73 mWebPage->setNetworkAccessManager( QgsNetworkAccessManager::instance() );
74 }
75
76 //a html item added to a layout needs to have the initial expression context set,
77 //otherwise fields in the html aren't correctly evaluated until atlas preview feature changes (#9457)
78 setExpressionContext( mLayout->reportContext().feature(), mLayout->reportContext().layer() );
79
80 connect( &mLayout->reportContext(), &QgsLayoutReportContext::changed, this, &QgsLayoutItemHtml::refreshExpressionContext );
81
82 mFetcher = new QgsNetworkContentFetcher();
83}
84
86{
87 mFetcher->deleteLater();
88}
89
94
96{
97 return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemHtml.svg" ) );
98}
99
104
106{
108 QgsLayoutFrame *frame = new QgsLayoutFrame( label->layout(), html );
109 frame->setVisible( label->isVisible() );
110 frame->setLocked( label->isLocked() );
111 frame->setItemOpacity( label->itemOpacity() );
112 frame->setRotation( label->rotation() );
115 frame->attemptResize( label->sizeWithUnits() );
116 frame->setZValue( label->zValue() );
117 frame->setParentGroup( label->parentGroup() );
123 html->addFrame( frame );
124 html->setContentMode( QgsLayoutItemHtml::ManualHtml );
125 html->setHtml( label->currentText() );
126 html->setUserStylesheetEnabled( true );
127 html->setUserStylesheet( label->createStylesheet() );
128 html->loadHtml();
129 return html;
130}
131
132void QgsLayoutItemHtml::setUrl( const QUrl &url )
133{
134 if ( !mWebPage )
135 {
136 return;
137 }
138
139 mUrl = url;
140 loadHtml( true );
141 emit changed();
142}
143
144void QgsLayoutItemHtml::setHtml( const QString &html )
145{
146 mHtml = html;
147 //TODO - this signal should be emitted, but without changing the signal which sets the html
148 //to an equivalent of editingFinished it causes a lot of problems. Need to investigate
149 //ways of doing this using QScintilla widgets.
150 //emit changed();
151}
152
153void QgsLayoutItemHtml::setEvaluateExpressions( bool evaluateExpressions )
154{
155 mEvaluateExpressions = evaluateExpressions;
156 loadHtml( true );
157 emit changed();
158}
159
160void QgsLayoutItemHtml::loadHtml( const bool useCache, const QgsExpressionContext *context )
161{
162 if ( !mWebPage )
163 {
164 return;
165 }
166
167 const QgsExpressionContext scopedContext = createExpressionContext();
168 const QgsExpressionContext *evalContext = context ? context : &scopedContext;
169
170 QString loadedHtml;
171 switch ( mContentMode )
172 {
174 {
175
176 QString currentUrl = mUrl.toString();
177
178 //data defined url set?
179 bool ok = false;
180 currentUrl = mDataDefinedProperties.valueAsString( QgsLayoutObject::DataDefinedProperty::SourceUrl, *evalContext, currentUrl, &ok );
181 if ( ok )
182 {
183 currentUrl = currentUrl.trimmed();
184 QgsDebugMsgLevel( QStringLiteral( "exprVal Source Url:%1" ).arg( currentUrl ), 2 );
185 }
186 if ( currentUrl.isEmpty() )
187 {
188 return;
189 }
190 if ( !( useCache && currentUrl == mLastFetchedUrl ) )
191 {
192 loadedHtml = fetchHtml( QUrl( currentUrl ) );
193 mLastFetchedUrl = currentUrl;
194 }
195 else
196 {
197 loadedHtml = mFetchedHtml;
198 }
199
200 break;
201 }
203 loadedHtml = mHtml;
204 break;
205 }
206
207 //evaluate expressions
208 if ( mEvaluateExpressions )
209 {
210 loadedHtml = QgsExpression::replaceExpressionText( loadedHtml, evalContext, &mDistanceArea );
211 }
212
213 bool loaded = false;
214
215 QEventLoop loop;
216 connect( mWebPage.get(), &QWebPage::loadFinished, &loop, [&loaded, &loop ] { loaded = true; loop.quit(); } );
217 connect( mFetcher, &QgsNetworkContentFetcher::finished, &loop, [&loaded, &loop ] { loaded = true; loop.quit(); } );
218
219 //reset page size. otherwise viewport size increases but never decreases again
220 mWebPage->setViewportSize( QSize( maxFrameWidth() * mHtmlUnitsToLayoutUnits, 0 ) );
221
222 //set html, using the specified url as base if in Url mode or the project file if in manual mode
223 const QUrl baseUrl = mContentMode == QgsLayoutItemHtml::Url ?
224 QUrl( mActualFetchedUrl ) :
225 QUrl::fromLocalFile( mLayout->project()->absoluteFilePath() );
226
227 mWebPage->mainFrame()->setHtml( loadedHtml, baseUrl );
228
229 //set user stylesheet
230 QWebSettings *settings = mWebPage->settings();
231 if ( mEnableUserStylesheet && ! mUserStylesheet.isEmpty() )
232 {
233 QByteArray ba;
234 ba.append( mUserStylesheet.toUtf8() );
235 const QUrl cssFileURL = QUrl( QString( "data:text/css;charset=utf-8;base64," + ba.toBase64() ) );
236 settings->setUserStyleSheetUrl( cssFileURL );
237 }
238 else
239 {
240 settings->setUserStyleSheetUrl( QUrl() );
241 }
242
243 if ( !loaded )
244 loop.exec( QEventLoop::ExcludeUserInputEvents );
245
246#ifdef WITH_QTWEBKIT
247 //inject JSON feature
248 if ( !mAtlasFeatureJSON.isEmpty() )
249 {
250 JavascriptExecutorLoop jsLoop;
251
252 mWebPage->mainFrame()->addToJavaScriptWindowObject( QStringLiteral( "loop" ), &jsLoop );
253 mWebPage->mainFrame()->evaluateJavaScript( QStringLiteral( "if ( typeof setFeature === \"function\" ) { try{ setFeature(%1); } catch (err) { loop.reportError(err.message); } }; loop.done();" ).arg( mAtlasFeatureJSON ) );
254
255 jsLoop.execIfNotDone();
256 }
257#endif
258
260 //trigger a repaint
261 emit contentsChanged();
262}
263
264double QgsLayoutItemHtml::maxFrameWidth() const
265{
266 double maxWidth = 0;
268 {
269 maxWidth = std::max( maxWidth, static_cast< double >( frame->boundingRect().width() ) );
270 }
271
272 return maxWidth;
273}
274
276{
277 if ( frameCount() < 1 )
278 return;
279
280 if ( !mWebPage )
281 return;
282
283 QSize contentsSize = mWebPage->mainFrame()->contentsSize();
284
285 //find maximum frame width
286 const double maxWidth = maxFrameWidth();
287 //set content width to match maximum frame width
288 contentsSize.setWidth( maxWidth * mHtmlUnitsToLayoutUnits );
289
290 mWebPage->setViewportSize( contentsSize );
291 mSize.setWidth( contentsSize.width() / mHtmlUnitsToLayoutUnits );
292 mSize.setHeight( contentsSize.height() / mHtmlUnitsToLayoutUnits );
293 if ( contentsSize.isValid() )
294 {
295 renderCachedImage();
296 }
298 emit changed();
299}
300
301void QgsLayoutItemHtml::renderCachedImage()
302{
303 if ( !mWebPage )
304 return;
305
306 //render page to cache image
307 mRenderedPage = QImage( mWebPage->viewportSize(), QImage::Format_ARGB32 );
308 if ( mRenderedPage.isNull() )
309 {
310 return;
311 }
312 mRenderedPage.fill( Qt::transparent );
313 QPainter painter;
314 painter.begin( &mRenderedPage );
315 mWebPage->mainFrame()->render( &painter );
316 painter.end();
317}
318
319QString QgsLayoutItemHtml::fetchHtml( const QUrl &url )
320{
321 //pause until HTML fetch
322 bool loaded = false;
323 QEventLoop loop;
324 connect( mFetcher, &QgsNetworkContentFetcher::finished, &loop, [&loaded, &loop ] { loaded = true; loop.quit(); } );
325 mFetcher->fetchContent( url );
326
327 if ( !loaded )
328 loop.exec( QEventLoop::ExcludeUserInputEvents );
329
330 mFetchedHtml = mFetcher->contentAsString();
331 mActualFetchedUrl = mFetcher->reply()->url().toString();
332 return mFetchedHtml;
333}
334
336{
337 return mSize;
338}
339
340void QgsLayoutItemHtml::render( QgsLayoutItemRenderContext &context, const QRectF &renderExtent, const int frameIndex )
341{
342#ifdef WITH_QTWEBKIT
343 Q_UNUSED( frameIndex )
344 if ( !mWebPage )
345 return;
346
347 QPainter *painter = context.renderContext().painter();
348 const QgsScopedQPainterState painterState( painter );
349 // painter is scaled to dots, so scale back to layout units
350 painter->scale( context.renderContext().scaleFactor() / mHtmlUnitsToLayoutUnits, context.renderContext().scaleFactor() / mHtmlUnitsToLayoutUnits );
351 painter->translate( 0.0, -renderExtent.top() * mHtmlUnitsToLayoutUnits );
352 mWebPage->mainFrame()->render( painter, QRegion( renderExtent.left(), renderExtent.top() * mHtmlUnitsToLayoutUnits, renderExtent.width() * mHtmlUnitsToLayoutUnits, renderExtent.height() * mHtmlUnitsToLayoutUnits ) );
353#else
354 Q_UNUSED( renderExtent )
355 if ( mLayout->renderContext().isPreviewRender() )
356 {
357 if ( QgsLayoutFrame *currentFrame = frame( frameIndex ) )
358 {
359 QPainter *painter = context.renderContext().painter();
360
361 // painter is scaled to dots, so scale back to layout units
362 const QRectF painterRect = QRectF( currentFrame->rect().left() * context.renderContext().scaleFactor(),
363 currentFrame->rect().top() * context.renderContext().scaleFactor(),
364 currentFrame->rect().width() * context.renderContext().scaleFactor(),
365 currentFrame->rect().height() * context.renderContext().scaleFactor()
366 );
367
368 painter->setBrush( QBrush( QColor( 255, 125, 125, 125 ) ) );
369 painter->setPen( Qt::NoPen );
370 painter->drawRect( painterRect );
371 painter->setBrush( Qt::NoBrush );
372
373 painter->setPen( QColor( 200, 0, 0, 255 ) );
374 QTextDocument td;
375 td.setTextWidth( painterRect.width() );
376 td.setHtml( QStringLiteral( "<span style=\"color: rgb(200,0,0);\"><b>%1</b><br>%2</span>" ).arg(
377 tr( "WebKit not available!" ),
378 tr( "The item cannot be rendered because this QGIS install was built without WebKit support." ) ) );
379 painter->setClipRect( painterRect );
380 QAbstractTextDocumentLayout::PaintContext ctx;
381 td.documentLayout()->draw( painter, ctx );
382 }
383 }
384#endif
385}
386
387double QgsLayoutItemHtml::htmlUnitsToLayoutUnits()
388{
389 if ( !mLayout )
390 {
391 return 1.0;
392 }
393
394 return mLayout->convertToLayoutUnits( QgsLayoutMeasurement( mLayout->renderContext().dpi() / 72.0, Qgis::LayoutUnit::Millimeters ) ); //webkit seems to assume a standard dpi of 96
395}
396
397bool candidateSort( QPair<int, int> c1, QPair<int, int> c2 )
398{
399 if ( c1.second < c2.second )
400 return true;
401 else if ( c1.second > c2.second )
402 return false;
403 else if ( c1.first > c2.first )
404 return true;
405 else
406 return false;
407}
408
410{
411 if ( !mWebPage || mRenderedPage.isNull() || !mUseSmartBreaks )
412 {
413 return yPos;
414 }
415
416 //convert yPos to pixels
417 const int idealPos = yPos * htmlUnitsToLayoutUnits();
418
419 //if ideal break pos is past end of page, there's nothing we need to do
420 if ( idealPos >= mRenderedPage.height() )
421 {
422 return yPos;
423 }
424
425 const int maxSearchDistance = mMaxBreakDistance * htmlUnitsToLayoutUnits();
426
427 //loop through all lines just before ideal break location, up to max distance
428 //of maxSearchDistance
429 int changes = 0;
430 QRgb currentColor;
431 bool currentPixelTransparent = false;
432 bool previousPixelTransparent = false;
433 QRgb pixelColor;
434 QList< QPair<int, int> > candidates;
435 const int minRow = std::max( idealPos - maxSearchDistance, 0 );
436 for ( int candidateRow = idealPos; candidateRow >= minRow; --candidateRow )
437 {
438 changes = 0;
439 currentColor = qRgba( 0, 0, 0, 0 );
440 //check all pixels in this line
441 for ( int col = 0; col < mRenderedPage.width(); ++col )
442 {
443 //count how many times the pixels change color in this row
444 //eventually, we select a row to break at with the minimum number of color changes
445 //since this is likely a line break, or gap between table cells, etc
446 //but very unlikely to be midway through a text line or picture
447 pixelColor = mRenderedPage.pixel( col, candidateRow );
448 currentPixelTransparent = qAlpha( pixelColor ) == 0;
449 if ( pixelColor != currentColor && !( currentPixelTransparent && previousPixelTransparent ) )
450 {
451 //color has changed
452 currentColor = pixelColor;
453 changes++;
454 }
455 previousPixelTransparent = currentPixelTransparent;
456 }
457 candidates.append( qMakePair( candidateRow, changes ) );
458 }
459
460 //sort candidate rows by number of changes ascending, row number descending
461 std::sort( candidates.begin(), candidates.end(), candidateSort );
462 //first candidate is now the largest row with smallest number of changes
463
464 //OK, now take the mid point of the best candidate position
465 //we do this so that the spacing between text lines is likely to be split in half
466 //otherwise the html will be broken immediately above a line of text, which
467 //looks a little messy
468 const int maxCandidateRow = candidates[0].first;
469 int minCandidateRow = maxCandidateRow + 1;
470 const int minCandidateChanges = candidates[0].second;
471
472 QList< QPair<int, int> >::iterator it;
473 for ( it = candidates.begin(); it != candidates.end(); ++it )
474 {
475 if ( ( *it ).second != minCandidateChanges || ( *it ).first != minCandidateRow - 1 )
476 {
477 //no longer in a consecutive block of rows of minimum pixel color changes
478 //so return the row mid-way through the block
479 //first converting back to mm
480 return ( minCandidateRow + ( maxCandidateRow - minCandidateRow ) / 2 ) / htmlUnitsToLayoutUnits();
481 }
482 minCandidateRow = ( *it ).first;
483 }
484
485 //above loop didn't work for some reason
486 //return first candidate converted to mm
487 return candidates[0].first / htmlUnitsToLayoutUnits();
488}
489
490void QgsLayoutItemHtml::setUseSmartBreaks( bool useSmartBreaks )
491{
492 mUseSmartBreaks = useSmartBreaks;
494 emit changed();
495}
496
497void QgsLayoutItemHtml::setMaxBreakDistance( double maxBreakDistance )
498{
499 mMaxBreakDistance = maxBreakDistance;
501 emit changed();
502}
503
504void QgsLayoutItemHtml::setUserStylesheet( const QString &stylesheet )
505{
506 mUserStylesheet = stylesheet;
507 //TODO - this signal should be emitted, but without changing the signal which sets the css
508 //to an equivalent of editingFinished it causes a lot of problems. Need to investigate
509 //ways of doing this using QScintilla widgets.
510 //emit changed();
511}
512
513void QgsLayoutItemHtml::setUserStylesheetEnabled( const bool stylesheetEnabled )
514{
515 if ( mEnableUserStylesheet != stylesheetEnabled )
516 {
517 mEnableUserStylesheet = stylesheetEnabled;
518 loadHtml( true );
519 emit changed();
520 }
521}
522
524{
525 return tr( "<HTML frame>" );
526}
527
528bool QgsLayoutItemHtml::writePropertiesToElement( QDomElement &htmlElem, QDomDocument &, const QgsReadWriteContext & ) const
529{
530 htmlElem.setAttribute( QStringLiteral( "contentMode" ), QString::number( static_cast< int >( mContentMode ) ) );
531 htmlElem.setAttribute( QStringLiteral( "url" ), mUrl.toString() );
532 htmlElem.setAttribute( QStringLiteral( "html" ), mHtml );
533 htmlElem.setAttribute( QStringLiteral( "evaluateExpressions" ), mEvaluateExpressions ? "true" : "false" );
534 htmlElem.setAttribute( QStringLiteral( "useSmartBreaks" ), mUseSmartBreaks ? "true" : "false" );
535 htmlElem.setAttribute( QStringLiteral( "maxBreakDistance" ), QString::number( mMaxBreakDistance ) );
536 htmlElem.setAttribute( QStringLiteral( "stylesheet" ), mUserStylesheet );
537 htmlElem.setAttribute( QStringLiteral( "stylesheetEnabled" ), mEnableUserStylesheet ? "true" : "false" );
538 return true;
539}
540
541bool QgsLayoutItemHtml::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &, const QgsReadWriteContext & )
542{
543 bool contentModeOK;
544 mContentMode = static_cast< QgsLayoutItemHtml::ContentMode >( itemElem.attribute( QStringLiteral( "contentMode" ) ).toInt( &contentModeOK ) );
545 if ( !contentModeOK )
546 {
547 mContentMode = QgsLayoutItemHtml::Url;
548 }
549 mEvaluateExpressions = itemElem.attribute( QStringLiteral( "evaluateExpressions" ), QStringLiteral( "true" ) ) == QLatin1String( "true" );
550 mUseSmartBreaks = itemElem.attribute( QStringLiteral( "useSmartBreaks" ), QStringLiteral( "true" ) ) == QLatin1String( "true" );
551 mMaxBreakDistance = itemElem.attribute( QStringLiteral( "maxBreakDistance" ), QStringLiteral( "10" ) ).toDouble();
552 mHtml = itemElem.attribute( QStringLiteral( "html" ) );
553 mUserStylesheet = itemElem.attribute( QStringLiteral( "stylesheet" ) );
554 mEnableUserStylesheet = itemElem.attribute( QStringLiteral( "stylesheetEnabled" ), QStringLiteral( "false" ) ) == QLatin1String( "true" );
555
556 //finally load the set url
557 const QString urlString = itemElem.attribute( QStringLiteral( "url" ) );
558 if ( !urlString.isEmpty() )
559 {
560 mUrl = urlString;
561 }
562 loadHtml( true );
563
564 //since frames had to be created before, we need to emit a changed signal to refresh the widget
565 emit changed();
566 return true;
567}
568
569void QgsLayoutItemHtml::setExpressionContext( const QgsFeature &feature, QgsVectorLayer *layer )
570{
571 mExpressionFeature = feature;
572 mExpressionLayer = layer;
573
574 //setup distance area conversion
575 if ( layer )
576 {
577 mDistanceArea.setSourceCrs( layer->crs(), mLayout->project()->transformContext() );
578 }
579 else if ( mLayout )
580 {
581 //set to composition's mapsettings' crs
582 QgsLayoutItemMap *referenceMap = mLayout->referenceMap();
583 if ( referenceMap )
584 mDistanceArea.setSourceCrs( referenceMap->crs(), mLayout->project()->transformContext() );
585 }
586 if ( mLayout )
587 {
588 mDistanceArea.setEllipsoid( mLayout->project()->ellipsoid() );
589 }
590
591 if ( feature.isValid() )
592 {
593 // create JSON representation of feature
594 QgsJsonExporter exporter( layer );
595 exporter.setIncludeRelated( true );
596 mAtlasFeatureJSON = exporter.exportFeature( feature );
597 }
598 else
599 {
600 mAtlasFeatureJSON.clear();
601 }
602}
603
604void QgsLayoutItemHtml::refreshExpressionContext()
605{
606 QgsVectorLayer *vl = nullptr;
607 QgsFeature feature;
608
609 if ( mLayout )
610 {
611 vl = mLayout->reportContext().layer();
612 feature = mLayout->reportContext().feature();
613 }
614
615 setExpressionContext( feature, vl );
616 loadHtml( true );
617}
618
620{
622
623 //updates data defined properties and redraws item to match
625 {
626 loadHtml( true, &context );
627 }
628}
629
630//JavascriptExecutorLoop
632
633void JavascriptExecutorLoop::done()
634{
635 mDone = true;
636 quit();
637}
638
639void JavascriptExecutorLoop::execIfNotDone()
640{
641 if ( !mDone )
642 exec( QEventLoop::ExcludeUserInputEvents );
643
644 // gross, but nothing else works, so f*** it.. it's not worth spending a day trying to find a non-hacky way
645 // to force the web page to update following the js execution
646 for ( int i = 0; i < 100; i++ )
647 qApp->processEvents();
648}
649
650void JavascriptExecutorLoop::reportError( const QString &error )
651{
652 mDone = true;
653 QgsMessageLog::logMessage( tr( "HTML setFeature function error: %1" ).arg( error ), tr( "Layout" ) );
654 quit();
655}
656
The QWebSettings class is a collection of stubs to mimic the API of a QWebSettings on systems where Q...
Definition qgswebpage.h:43
@ Millimeters
Millimeters.
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:58
bool isValid() const
Returns the validity of this feature.
Handles exporting QgsFeature features to GeoJSON features.
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 ...
void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::DataDefinedProperty::AllProperties) 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.
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.
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
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.
int frameIndex(QgsLayoutFrame *frame) const
Returns the index of a frame within the multiframe.
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.
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:49
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:83
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