40 #include <QCoreApplication>
42 #include <QDomElement>
52 mHtmlUnitsToLayoutUnits = htmlUnitsToLayoutUnits();
56 const QString defaultFontString = settings.
value( QStringLiteral(
"LayoutDesigner/defaultFont" ), QVariant(),
QgsSettings::Gui ).toString();
57 if ( !defaultFontString.isEmpty() )
59 QFont f = mFormat.
font();
60 f.setFamily( defaultFontString );
73 refreshExpressionContext();
76 if ( QThread::currentThread() == QApplication::instance()->thread() )
86 mWebPage->setIdentifier( tr(
"Layout label item" ) );
90 QPalette palette = mWebPage->palette();
91 palette.setBrush( QPalette::Base, Qt::transparent );
92 mWebPage->setPalette( palette );
94 mWebPage->mainFrame()->setZoomFactor( 10.0 );
95 mWebPage->mainFrame()->setScrollBarPolicy( Qt::Horizontal, Qt::ScrollBarAlwaysOff );
96 mWebPage->mainFrame()->setScrollBarPolicy( Qt::Vertical, Qt::ScrollBarAlwaysOff );
98 connect( mWebPage.get(), &QWebPage::loadFinished,
this, &QgsLayoutItemLabel::loadingHtmlFinished );
122 double rectScale = 1.0;
133 const double penWidth =
frameEnabled() ? ( pen().widthF() / 2.0 ) : 0;
134 const double xPenAdjust = mMarginX < 0 ? -penWidth : penWidth;
135 const double yPenAdjust = mMarginY < 0 ? -penWidth : penWidth;
136 const QRectF painterRect( ( xPenAdjust + mMarginX ) * rectScale,
137 ( yPenAdjust + mMarginY ) * rectScale,
138 ( rect().width() - 2 * xPenAdjust - 2 * mMarginX ) * rectScale,
139 ( rect().height() - 2 * yPenAdjust - 2 * mMarginY ) * rectScale );
148 mFirstRender =
false;
153 painter->scale( 1.0 / mHtmlUnitsToLayoutUnits / 10.0, 1.0 / mHtmlUnitsToLayoutUnits / 10.0 );
154 mWebPage->setViewportSize( QSize( painterRect.width() * mHtmlUnitsToLayoutUnits * 10.0, painterRect.height() * mHtmlUnitsToLayoutUnits * 10.0 ) );
155 mWebPage->settings()->setUserStyleSheetUrl( createStylesheetUrl() );
156 mWebPage->mainFrame()->render( painter );
177 void QgsLayoutItemLabel::contentChanged()
195 const QUrl baseUrl = QUrl::fromLocalFile(
mLayout->project()->absoluteFilePath() );
196 mWebPage->mainFrame()->setHtml( textToDraw, baseUrl );
204 if ( !mHtmlLoaded && ( !
mLayout || !
mLayout->renderContext().isPreviewRender() ) )
210 connect( mWebPage.get(), &QWebPage::loadFinished, &loop, &QEventLoop::quit );
214 timeoutTimer.setSingleShot(
true );
215 connect( &timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit );
216 timeoutTimer.start( 20000 );
219 loop.exec( QEventLoop::ExcludeUserInputEvents );
229 void QgsLayoutItemLabel::loadingHtmlFinished(
bool result )
237 double QgsLayoutItemLabel::htmlUnitsToLayoutUnits()
258 mLayout->itemsModel()->updateItemDisplayName(
this );
272 if (
mLayout &&
id().isEmpty() )
275 mLayout->itemsModel()->updateItemDisplayName(
this );
279 void QgsLayoutItemLabel::refreshExpressionContext()
288 mDistanceArea->setSourceCrs( layer->
crs(),
mLayout->project()->transformContext() );
295 mDistanceArea->setSourceCrs( referenceMap->
crs(),
mLayout->project()->transformContext() );
297 mDistanceArea->setEllipsoid(
mLayout->project()->ellipsoid() );
305 QString displayText = mText;
306 replaceDateText( displayText );
313 void QgsLayoutItemLabel::replaceDateText( QString &text )
const
315 const QString constant = QStringLiteral(
"$CURRENT_DATE" );
316 const int currentDatePos =
text.indexOf( constant );
317 if ( currentDatePos != -1 )
321 const int openingBracketPos =
text.indexOf(
'(', currentDatePos );
322 const int closingBracketPos =
text.indexOf(
')', openingBracketPos + 1 );
323 if ( openingBracketPos != -1 &&
324 closingBracketPos != -1 &&
325 ( closingBracketPos - openingBracketPos ) > 1 &&
326 openingBracketPos == currentDatePos + constant.size() )
328 formatText =
text.mid( openingBracketPos + 1, closingBracketPos - openingBracketPos - 1 );
329 text.replace( currentDatePos, closingBracketPos - currentDatePos + 1, QDate::currentDate().toString( formatText ) );
333 text.replace( QLatin1String(
"$CURRENT_DATE" ), QDate::currentDate().toString() );
341 if ( f.pointSizeF() > 0 )
342 mFormat.
setSize( f.pointSizeF() );
359 prepareGeometryChange();
365 prepareGeometryChange();
371 prepareGeometryChange();
382 itemShiftAdjustSize( newSize.width(), newSize.height(), xShift, yShift );
385 attemptSetSceneRect( QRectF( pos().x() + xShift, pos().y() + yShift, newSize.width(), newSize.height() ) );
392 const QStringList lines =
currentText().split(
'\n' );
396 const double penWidth =
frameEnabled() ? ( pen().widthF() / 2.0 ) : 0;
398 const double width = textWidth + 2 * mMarginX + 2 * penWidth;
399 const double height = fontHeight + 2 * mMarginY + 2 * penWidth;
406 return mFormat.
font();
411 layoutLabelElem.setAttribute( QStringLiteral(
"htmlState" ),
static_cast< int >( mMode ) );
413 layoutLabelElem.setAttribute( QStringLiteral(
"labelText" ), mText );
414 layoutLabelElem.setAttribute( QStringLiteral(
"marginX" ), QString::number( mMarginX ) );
415 layoutLabelElem.setAttribute( QStringLiteral(
"marginY" ), QString::number( mMarginY ) );
416 layoutLabelElem.setAttribute( QStringLiteral(
"halign" ), mHAlignment );
417 layoutLabelElem.setAttribute( QStringLiteral(
"valign" ), mVAlignment );
419 QDomElement textElem = mFormat.
writeXml( doc, rwContext );
420 layoutLabelElem.appendChild( textElem );
430 mText = itemElem.attribute( QStringLiteral(
"labelText" ) );
433 mMode =
static_cast< Mode >( itemElem.attribute( QStringLiteral(
"htmlState" ) ).toInt() );
436 bool marginXOk =
false;
437 bool marginYOk =
false;
438 mMarginX = itemElem.attribute( QStringLiteral(
"marginX" ) ).toDouble( &marginXOk );
439 mMarginY = itemElem.attribute( QStringLiteral(
"marginY" ) ).toDouble( &marginYOk );
440 if ( !marginXOk || !marginYOk )
443 const double margin = itemElem.attribute( QStringLiteral(
"margin" ), QStringLiteral(
"1.0" ) ).toDouble();
449 mHAlignment =
static_cast< Qt::AlignmentFlag
>( itemElem.attribute( QStringLiteral(
"halign" ) ).toInt() );
452 mVAlignment =
static_cast< Qt::AlignmentFlag
>( itemElem.attribute( QStringLiteral(
"valign" ) ).toInt() );
455 QDomNodeList textFormatNodeList = itemElem.elementsByTagName( QStringLiteral(
"text-style" ) );
456 if ( !textFormatNodeList.isEmpty() )
458 QDomElement textFormatElem = textFormatNodeList.at( 0 ).toElement();
459 mFormat.
readXml( textFormatElem, context );
466 f.fromString( itemElem.attribute( QStringLiteral(
"font" ), QString() ) );
469 if ( f.pointSizeF() > 0 )
471 mFormat.
setSize( f.pointSizeF() );
474 else if ( f.pixelSize() > 0 )
476 mFormat.
setSize( f.pixelSize() );
481 const QDomNodeList fontColorList = itemElem.elementsByTagName( QStringLiteral(
"FontColor" ) );
482 if ( !fontColorList.isEmpty() )
484 const QDomElement fontColorElem = fontColorList.at( 0 ).toElement();
485 const int red = fontColorElem.attribute( QStringLiteral(
"red" ), QStringLiteral(
"0" ) ).toInt();
486 const int green = fontColorElem.attribute( QStringLiteral(
"green" ), QStringLiteral(
"0" ) ).toInt();
487 const int blue = fontColorElem.attribute( QStringLiteral(
"blue" ), QStringLiteral(
"0" ) ).toInt();
488 const int alpha = fontColorElem.attribute( QStringLiteral(
"alpha" ), QStringLiteral(
"255" ) ).toInt();
489 mFormat.
setColor( QColor( red, green, blue, alpha ) );
491 else if ( textFormatNodeList.isEmpty() )
493 mFormat.
setColor( QColor( 0, 0, 0 ) );
502 if ( !
id().isEmpty() )
510 return tr(
"<HTML Label>" );
516 const QString
text = mText;
517 if (
text.isEmpty() )
519 return tr(
"<Label>" );
521 if (
text.length() > 25 )
523 return QString( tr(
"%1…" ) ).arg(
text.left( 25 ).simplified() );
527 return text.simplified();
536 QRectF rectangle = rect();
537 const double penWidth =
frameEnabled() ? ( pen().widthF() / 2.0 ) : 0;
538 rectangle.adjust( -penWidth, -penWidth, penWidth, penWidth );
542 rectangle.adjust( mMarginX, 0, -mMarginX, 0 );
546 rectangle.adjust( 0, mMarginY, 0, -mMarginY );
555 prepareGeometryChange();
561 prepareGeometryChange();
568 refreshExpressionContext();
574 if ( evaluated == mText )
580 void QgsLayoutItemLabel::itemShiftAdjustSize(
double newWidth,
double newHeight,
double &xShift,
double &yShift )
const
583 const double currentWidth = rect().width();
584 const double currentHeight = rect().height();
588 const double r = rotation();
589 if ( r >= 0 && r < 90 )
591 if ( mHAlignment == Qt::AlignHCenter )
593 xShift = - ( newWidth - currentWidth ) / 2.0;
595 else if ( mHAlignment == Qt::AlignRight )
597 xShift = - ( newWidth - currentWidth );
599 if ( mVAlignment == Qt::AlignVCenter )
601 yShift = -( newHeight - currentHeight ) / 2.0;
603 else if ( mVAlignment == Qt::AlignBottom )
605 yShift = - ( newHeight - currentHeight );
608 if ( r >= 90 && r < 180 )
610 if ( mHAlignment == Qt::AlignHCenter )
612 yShift = -( newHeight - currentHeight ) / 2.0;
614 else if ( mHAlignment == Qt::AlignRight )
616 yShift = -( newHeight - currentHeight );
618 if ( mVAlignment == Qt::AlignTop )
620 xShift = -( newWidth - currentWidth );
622 else if ( mVAlignment == Qt::AlignVCenter )
624 xShift = -( newWidth - currentWidth / 2.0 );
627 else if ( r >= 180 && r < 270 )
629 if ( mHAlignment == Qt::AlignHCenter )
631 xShift = -( newWidth - currentWidth ) / 2.0;
633 else if ( mHAlignment == Qt::AlignLeft )
635 xShift = -( newWidth - currentWidth );
637 if ( mVAlignment == Qt::AlignVCenter )
639 yShift = ( newHeight - currentHeight ) / 2.0;
641 else if ( mVAlignment == Qt::AlignTop )
643 yShift = ( newHeight - currentHeight );
646 else if ( r >= 270 && r < 360 )
648 if ( mHAlignment == Qt::AlignHCenter )
650 yShift = -( newHeight - currentHeight ) / 2.0;
652 else if ( mHAlignment == Qt::AlignLeft )
654 yShift = -( newHeight - currentHeight );
656 if ( mVAlignment == Qt::AlignBottom )
658 xShift = -( newWidth - currentWidth );
660 else if ( mVAlignment == Qt::AlignVCenter )
662 xShift = -( newWidth - currentWidth / 2.0 );
667 QUrl QgsLayoutItemLabel::createStylesheetUrl()
const
670 stylesheet += QStringLiteral(
"body { margin: %1 %2;" ).arg( std::max( mMarginY * mHtmlUnitsToLayoutUnits, 0.0 ) ).arg( std::max( mMarginX * mHtmlUnitsToLayoutUnits, 0.0 ) );
671 QFont f = mFormat.
font();
675 f.setPointSizeF( mFormat.
size() / 0.352778 );
678 f.setPixelSize( mFormat.
size() );
681 f.setPointSizeF( mFormat.
size() );
684 f.setPointSizeF( mFormat.
size() * 72 );
694 stylesheet += QStringLiteral(
"color: rgba(%1,%2,%3,%4);" ).arg( mFormat.
color().red() ).arg( mFormat.
color().green() ).arg( mFormat.
color().blue() ).arg( QString::number( mFormat.
color().alphaF(),
'f', 4 ) );
695 stylesheet += QStringLiteral(
"text-align: %1; }" ).arg( mHAlignment == Qt::AlignLeft ? QStringLiteral(
"left" ) : mHAlignment == Qt::AlignRight ? QStringLiteral(
"right" ) : mHAlignment == Qt::AlignHCenter ? QStringLiteral(
"center" ) : QStringLiteral(
"justify" ) );
698 ba.append( stylesheet.toUtf8() );
699 QUrl cssFileURL = QUrl( QString(
"data:text/css;charset=utf-8;base64," + ba.toBase64() ) );
@ ApplyScalingWorkaroundForTextRendering
Whether a scaling workaround designed to stablise the rendering of small font sizes (or for painters ...
@ WrapLines
Automatically wrap long lines of text.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
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...
static QString asCSS(const QFont &font, double pointToPixelMultiplier=1.0)
Returns a CSS string representing the specified font as closely as possible.
static bool setFromXmlChildNode(QFont &font, const QDomElement &element, const QString &childNode)
Sets the properties of a font to match the properties stored in an XML child node.
A layout item subclass for text labels.
Mode mode() const
Returns the label's current mode.
void setMarginX(double margin)
Sets the horizontal margin between the edge of the frame and the label contents, in layout units.
void setFrameEnabled(bool drawFrame) override
Sets whether this item has a frame drawn around it or not.
QRectF boundingRect() const override
QSizeF sizeForText() const
Returns the required item size (in layout units) for the label's text to fill the item.
void setMargin(double margin)
Sets the margin between the edge of the frame and the label contents.
int type() const override
static QgsLayoutItemLabel * create(QgsLayout *layout)
Returns a new label item for the specified layout.
bool readPropertiesFromElement(const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets item state from a DOM element.
Q_DECL_DEPRECATED QFont font() const
Returns the label's current font.
QgsLayoutItemLabel(QgsLayout *layout)
Constructor for QgsLayoutItemLabel, with the specified parent layout.
void setText(const QString &text)
Sets the label's preset text.
void setFrameStrokeWidth(QgsLayoutMeasurement strokeWidth) override
Sets the frame stroke width.
void setMarginY(double margin)
Sets the vertical margin between the edge of the frame and the label contents, in layout units.
void draw(QgsLayoutItemRenderContext &context) override
Draws the item's contents using the specified item render context.
Q_DECL_DEPRECATED void setFont(const QFont &font)
Sets the label's current font.
bool writePropertiesToElement(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores item state within an XML DOM element.
void setMode(Mode mode)
Sets the label's current mode, allowing the label to switch between font based and HTML based renderi...
QString displayName() const override
Gets item display name.
QString text() const
Returns the label's preset text.
void convertToStaticText()
Converts the label's text() to a static string, by evaluating any expressions included in the text an...
QgsTextFormat textFormat() const
Returns the text format used for drawing text in the label.
void setTextFormat(const QgsTextFormat &format)
Sets the text format used for drawing text in the label.
QString currentText() const
Returns the text as it appears on the label (with evaluated expressions and other dynamic content).
QIcon icon() const override
Returns the item's icon.
void adjustSizeToText()
Resizes the item so that the label's text fits to the item.
@ ModeHtml
Label displays rendered HTML content.
@ ModeFont
Label displays text rendered using a single font.
Layout graphical items for displaying a map.
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used for rendering the map.
Contains settings and helpers relating to a render of a QgsLayoutItem.
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
Base class for graphical items within a QgsLayout.
virtual void drawFrame(QgsRenderContext &context)
Draws the frame around the item.
virtual void setFrameStrokeWidth(QgsLayoutMeasurement width)
Sets the frame stroke width.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
virtual void setFrameEnabled(bool drawFrame)
Sets whether this item has a frame drawn around it or not.
virtual void invalidateCache()
Forces a deferred update of any cached image the item uses.
QString id() const
Returns the item's ID name.
bool frameEnabled() const
Returns true if the item includes a frame.
void refresh() override
Refreshes the item, causing a recalculation of any property overrides and recalculation of its positi...
void attemptSetSceneRect(const QRectF &rect, bool includesFrame=false)
Attempts to update the item's position and size to match the passed rect in layout coordinates.
void setBackgroundEnabled(bool drawBackground)
Sets whether this item has a background drawn under it or not.
This class provides a method of storing measurements for use in QGIS layouts using a variety of diffe...
const QgsLayout * layout() const
Returns the layout the object is attached to.
void changed()
Emitted when the object's properties change.
QPointer< QgsLayout > mLayout
This class provides a method of storing sizes, consisting of a width and height, for use in QGIS layo...
static QgsRenderContext createRenderContextForLayout(QgsLayout *layout, QPainter *painter, double dpi=-1)
Creates a render context suitable for the specified layout and painter destination.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
QgsCoordinateReferenceSystem crs
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.
The class is used as a container of context for various read/write operations on other objects.
Contains information about the context of a rendering operation.
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.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
void setFlag(Qgis::RenderContextFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
Scoped object for saving and restoring a QPainter object's state.
This class is a composition of two QSettings instances:
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Container for all settings relating to text rendering.
void setColor(const QColor &color)
Sets the color that text will be rendered in.
void setSize(double size)
Sets the size for rendered text.
void setFont(const QFont &font)
Sets the font used for rendering text.
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units for the size of rendered text.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Read settings from a DOM element.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the size of rendered text.
double size() const
Returns the size for rendered text.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Write settings into a DOM element.
QColor color() const
Returns the color that text will be rendered in.
QFont font() const
Returns the font used for rendering text.
static double textWidth(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, QFontMetricsF *fontMetrics=nullptr)
Returns the width of a text based on a given format.
static void drawText(const QRectF &rect, double rotation, HAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, bool drawAsOutlines=true, VAlignment vAlignment=AlignTop, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags())
Draws text within a rectangle using the specified settings.
static HAlignment convertQtHAlignment(Qt::Alignment alignment)
Converts a Qt horizontal alignment flag to a QgsTextRenderer::HAlignment value.
static double textHeight(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, DrawMode mode=Point, QFontMetricsF *fontMetrics=nullptr, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags(), double maxLineWidth=0)
Returns the height of a text based on a given format.
static VAlignment convertQtVAlignment(Qt::Alignment alignment)
Converts a Qt vertical alignment flag to a QgsTextRenderer::VAlignment value.
@ LayoutMillimeters
Millimeters.
@ RenderUnknownUnit
Mixed or unknown units.
@ RenderMetersInMapUnits
Meters value as Map units.
@ RenderPercentage
Percentage of another measurement (e.g., canvas size, feature size)
@ RenderPoints
Points (e.g., for font sizes)
@ RenderMillimeters
Millimeters.
@ RenderMapUnits
Map units.
Represents a vector layer which manages a vector based data sets.
QWebPage subclass which redirects JavaScript errors and console output to the QGIS message log.