38 #include <QCoreApplication> 40 #include <QDomElement> 49 mHtmlUnitsToLayoutUnits = htmlUnitsToLayoutUnits();
53 QString defaultFontString = settings.
value( QStringLiteral(
"LayoutDesigner/defaultFont" ), QVariant(),
QgsSettings::Gui ).toString();
54 if ( !defaultFontString.isEmpty() )
56 mFont.setFamily( defaultFontString );
60 mFont.setPointSizeF( 10 );
67 refreshExpressionContext();
70 mWebPage->setIdentifier( tr(
"Layout label item" ) );
74 QPalette palette = mWebPage->palette();
75 palette.setBrush( QPalette::Base, Qt::transparent );
76 mWebPage->setPalette( palette );
78 mWebPage->mainFrame()->setZoomFactor( 10.0 );
79 mWebPage->mainFrame()->setScrollBarPolicy( Qt::Horizontal, Qt::ScrollBarAlwaysOff );
80 mWebPage->mainFrame()->setScrollBarPolicy( Qt::Vertical, Qt::ScrollBarAlwaysOff );
82 connect( mWebPage.get(), &QWebPage::loadFinished,
this, &QgsLayoutItemLabel::loadingHtmlFinished );
108 double penWidth =
frameEnabled() ? ( pen().widthF() / 2.0 ) : 0;
109 double xPenAdjust = mMarginX < 0 ? -penWidth : penWidth;
110 double yPenAdjust = mMarginY < 0 ? -penWidth : penWidth;
111 QRectF painterRect( xPenAdjust + mMarginX, yPenAdjust + mMarginY, rect().width() - 2 * xPenAdjust - 2 * mMarginX, rect().height() - 2 * yPenAdjust - 2 * mMarginY );
120 mFirstRender =
false;
122 painter->scale( 1.0 / mHtmlUnitsToLayoutUnits / 10.0, 1.0 / mHtmlUnitsToLayoutUnits / 10.0 );
123 mWebPage->setViewportSize( QSize( painterRect.width() * mHtmlUnitsToLayoutUnits * 10.0, painterRect.height() * mHtmlUnitsToLayoutUnits * 10.0 ) );
124 mWebPage->settings()->setUserStyleSheetUrl( createStylesheetUrl() );
125 mWebPage->mainFrame()->render( painter );
132 painter->setFont( mFont );
133 QgsLayoutUtils::drawText( painter, painterRect, textToDraw, mFont, mFontColor, mHAlignment, mVAlignment, Qt::TextWordWrap );
141 void QgsLayoutItemLabel::contentChanged()
154 const QUrl baseUrl = QUrl::fromLocalFile(
mLayout->project()->absoluteFilePath() );
155 mWebPage->mainFrame()->setHtml( textToDraw, baseUrl );
166 connect( mWebPage.get(), &QWebPage::loadFinished, &loop, &QEventLoop::quit );
170 timeoutTimer.setSingleShot(
true );
171 connect( &timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit );
172 timeoutTimer.start( 20000 );
175 loop.exec( QEventLoop::ExcludeUserInputEvents );
184 void QgsLayoutItemLabel::loadingHtmlFinished(
bool result )
190 double QgsLayoutItemLabel::htmlUnitsToLayoutUnits()
211 mLayout->itemsModel()->updateItemDisplayName(
this );
225 if (
mLayout &&
id().isEmpty() )
228 mLayout->itemsModel()->updateItemDisplayName(
this );
232 void QgsLayoutItemLabel::refreshExpressionContext()
241 mDistanceArea->setSourceCrs( layer->
crs(),
mLayout->project()->transformContext() );
248 mDistanceArea->setSourceCrs( referenceMap->
crs(),
mLayout->project()->transformContext() );
250 mDistanceArea->setEllipsoid(
mLayout->project()->ellipsoid() );
258 QString displayText = mText;
259 replaceDateText( displayText );
266 void QgsLayoutItemLabel::replaceDateText( QString &
text )
const 268 QString constant = QStringLiteral(
"$CURRENT_DATE" );
269 int currentDatePos = text.indexOf( constant );
270 if ( currentDatePos != -1 )
274 int openingBracketPos = text.indexOf(
'(', currentDatePos );
275 int closingBracketPos = text.indexOf(
')', openingBracketPos + 1 );
276 if ( openingBracketPos != -1 &&
277 closingBracketPos != -1 &&
278 ( closingBracketPos - openingBracketPos ) > 1 &&
279 openingBracketPos == currentDatePos + constant.size() )
281 formatText = text.mid( openingBracketPos + 1, closingBracketPos - openingBracketPos - 1 );
282 text.replace( currentDatePos, closingBracketPos - currentDatePos + 1, QDate::currentDate().toString( formatText ) );
286 text.replace( QLatin1String(
"$CURRENT_DATE" ), QDate::currentDate().toString() );
300 prepareGeometryChange();
306 prepareGeometryChange();
312 prepareGeometryChange();
323 itemShiftAdjustSize( newSize.width(), newSize.height(), xShift, yShift );
326 attemptSetSceneRect( QRectF( pos().x() + xShift, pos().y() + yShift, newSize.width(), newSize.height() ) );
334 double penWidth =
frameEnabled() ? ( pen().widthF() / 2.0 ) : 0;
336 double width = textWidth + 2 * mMarginX + 2 * penWidth + 1;
337 double height = fontHeight + 2 * mMarginY + 2 * penWidth;
349 layoutLabelElem.setAttribute( QStringLiteral(
"htmlState" ), static_cast< int >( mMode ) );
351 layoutLabelElem.setAttribute( QStringLiteral(
"labelText" ), mText );
352 layoutLabelElem.setAttribute( QStringLiteral(
"marginX" ), QString::number( mMarginX ) );
353 layoutLabelElem.setAttribute( QStringLiteral(
"marginY" ), QString::number( mMarginY ) );
354 layoutLabelElem.setAttribute( QStringLiteral(
"halign" ), mHAlignment );
355 layoutLabelElem.setAttribute( QStringLiteral(
"valign" ), mVAlignment );
359 layoutLabelElem.appendChild( labelFontElem );
362 QDomElement fontColorElem = doc.createElement( QStringLiteral(
"FontColor" ) );
363 fontColorElem.setAttribute( QStringLiteral(
"red" ), mFontColor.red() );
364 fontColorElem.setAttribute( QStringLiteral(
"green" ), mFontColor.green() );
365 fontColorElem.setAttribute( QStringLiteral(
"blue" ), mFontColor.blue() );
366 fontColorElem.setAttribute( QStringLiteral(
"alpha" ), mFontColor.alpha() );
367 layoutLabelElem.appendChild( fontColorElem );
377 mText = itemElem.attribute( QStringLiteral(
"labelText" ) );
380 mMode =
static_cast< Mode >( itemElem.attribute( QStringLiteral(
"htmlState" ) ).toInt() );
383 bool marginXOk =
false;
384 bool marginYOk =
false;
385 mMarginX = itemElem.attribute( QStringLiteral(
"marginX" ) ).toDouble( &marginXOk );
386 mMarginY = itemElem.attribute( QStringLiteral(
"marginY" ) ).toDouble( &marginYOk );
387 if ( !marginXOk || !marginYOk )
390 double margin = itemElem.attribute( QStringLiteral(
"margin" ), QStringLiteral(
"1.0" ) ).toDouble();
396 mHAlignment =
static_cast< Qt::AlignmentFlag
>( itemElem.attribute( QStringLiteral(
"halign" ) ).toInt() );
399 mVAlignment =
static_cast< Qt::AlignmentFlag
>( itemElem.attribute( QStringLiteral(
"valign" ) ).toInt() );
405 QDomNodeList fontColorList = itemElem.elementsByTagName( QStringLiteral(
"FontColor" ) );
406 if ( !fontColorList.isEmpty() )
408 QDomElement fontColorElem = fontColorList.at( 0 ).toElement();
409 int red = fontColorElem.attribute( QStringLiteral(
"red" ), QStringLiteral(
"0" ) ).toInt();
410 int green = fontColorElem.attribute( QStringLiteral(
"green" ), QStringLiteral(
"0" ) ).toInt();
411 int blue = fontColorElem.attribute( QStringLiteral(
"blue" ), QStringLiteral(
"0" ) ).toInt();
412 int alpha = fontColorElem.attribute( QStringLiteral(
"alpha" ), QStringLiteral(
"255" ) ).toInt();
413 mFontColor = QColor( red, green, blue, alpha );
417 mFontColor = QColor( 0, 0, 0 );
425 if ( !
id().isEmpty() )
433 return tr(
"<HTML Label>" );
439 QString
text = mText;
440 if ( text.isEmpty() )
442 return tr(
"<Label>" );
444 if ( text.length() > 25 )
446 return QString( tr(
"%1…" ) ).arg( text.left( 25 ).simplified() );
450 return text.simplified();
459 QRectF rectangle = rect();
460 double penWidth =
frameEnabled() ? ( pen().widthF() / 2.0 ) : 0;
461 rectangle.adjust( -penWidth, -penWidth, penWidth, penWidth );
465 rectangle.adjust( mMarginX, 0, -mMarginX, 0 );
469 rectangle.adjust( 0, mMarginY, 0, -mMarginY );
478 prepareGeometryChange();
484 prepareGeometryChange();
490 refreshExpressionContext();
493 void QgsLayoutItemLabel::itemShiftAdjustSize(
double newWidth,
double newHeight,
double &xShift,
double &yShift )
const 496 double currentWidth = rect().width();
497 double currentHeight = rect().height();
501 double r = rotation();
502 if ( r >= 0 && r < 90 )
504 if ( mHAlignment == Qt::AlignHCenter )
506 xShift = - ( newWidth - currentWidth ) / 2.0;
508 else if ( mHAlignment == Qt::AlignRight )
510 xShift = - ( newWidth - currentWidth );
512 if ( mVAlignment == Qt::AlignVCenter )
514 yShift = -( newHeight - currentHeight ) / 2.0;
516 else if ( mVAlignment == Qt::AlignBottom )
518 yShift = - ( newHeight - currentHeight );
521 if ( r >= 90 && r < 180 )
523 if ( mHAlignment == Qt::AlignHCenter )
525 yShift = -( newHeight - currentHeight ) / 2.0;
527 else if ( mHAlignment == Qt::AlignRight )
529 yShift = -( newHeight - currentHeight );
531 if ( mVAlignment == Qt::AlignTop )
533 xShift = -( newWidth - currentWidth );
535 else if ( mVAlignment == Qt::AlignVCenter )
537 xShift = -( newWidth - currentWidth / 2.0 );
540 else if ( r >= 180 && r < 270 )
542 if ( mHAlignment == Qt::AlignHCenter )
544 xShift = -( newWidth - currentWidth ) / 2.0;
546 else if ( mHAlignment == Qt::AlignLeft )
548 xShift = -( newWidth - currentWidth );
550 if ( mVAlignment == Qt::AlignVCenter )
552 yShift = ( newHeight - currentHeight ) / 2.0;
554 else if ( mVAlignment == Qt::AlignTop )
556 yShift = ( newHeight - currentHeight );
559 else if ( r >= 270 && r < 360 )
561 if ( mHAlignment == Qt::AlignHCenter )
563 yShift = -( newHeight - currentHeight ) / 2.0;
565 else if ( mHAlignment == Qt::AlignLeft )
567 yShift = -( newHeight - currentHeight );
569 if ( mVAlignment == Qt::AlignBottom )
571 xShift = -( newWidth - currentWidth );
573 else if ( mVAlignment == Qt::AlignVCenter )
575 xShift = -( newWidth - currentWidth / 2.0 );
580 QUrl QgsLayoutItemLabel::createStylesheetUrl()
const 583 stylesheet += QStringLiteral(
"body { margin: %1 %2;" ).arg( std::max( mMarginY * mHtmlUnitsToLayoutUnits, 0.0 ) ).arg( std::max( mMarginX * mHtmlUnitsToLayoutUnits, 0.0 ) );
585 stylesheet += QStringLiteral(
"color: rgba(%1,%2,%3,%4);" ).arg( mFontColor.red() ).arg( mFontColor.green() ).arg( mFontColor.blue() ).arg( QString::number( mFontColor.alphaF(),
'f', 4 ) );
586 stylesheet += QStringLiteral(
"text-align: %1; }" ).arg( mHAlignment == Qt::AlignLeft ? QStringLiteral(
"left" ) : mHAlignment == Qt::AlignRight ? QStringLiteral(
"right" ) : mHAlignment == Qt::AlignHCenter ? QStringLiteral(
"center" ) : QStringLiteral(
"justify" ) );
589 ba.append( stylesheet.toUtf8() );
590 QUrl cssFileURL = QUrl(
"data:text/css;charset=utf-8;base64," + ba.toBase64() );
void setMargin(double margin)
Sets the margin between the edge of the frame and the label contents.
The class is used as a container of context for various read/write operations on other objects...
void draw(QgsLayoutItemRenderContext &context) override
Draws the item's contents using the specified item render context.
bool writePropertiesToElement(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores item state within an XML DOM element.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QRectF boundingRect() const override
Base class for graphical items within a QgsLayout.
Mode mode() const
Returns the label's current mode.
static double textWidthMM(const QFont &font, const QString &text)
Calculate a font width in millimeters for a text string, including workarounds for QT font rendering ...
This class is a composition of two QSettings instances:
A layout item subclass for text labels.
Label displays rendered HTML content.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
int type() const override
bool frameEnabled() const
Returns true if the item includes a frame.
static QgsLayoutItemLabel * create(QgsLayout *layout)
Returns a new label item for the specified layout.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
virtual void setFrameStrokeWidth(QgsLayoutMeasurement width)
Sets the frame stroke width.
void setMarginX(double margin)
Sets the horizontal margin between the edge of the frame and the label contents, in layout units...
void setFrameStrokeWidth(QgsLayoutMeasurement strokeWidth) override
Sets the frame stroke width.
QString text() const
Returns the label's preset text.
static QString asCSS(const QFont &font, double pointToPixelMultiplier=1.0)
Returns a CSS string representing the specified font as closely as possible.
virtual void drawFrame(QgsRenderContext &context)
Draws the frame around the item.
Layout graphical items for displaying a map.
const QgsLayout * layout() const
Returns the layout the object is attached to.
This class provides a method of storing measurements for use in QGIS layouts using a variety of diffe...
QString currentText() const
Returns the text as it appears on the label (with evaluated expressions and other dynamic content)...
QgsLayoutItemLabel(QgsLayout *layout)
Constructor for QgsLayoutItemLabel, with the specified parent layout.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
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...
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
QPointer< QgsLayout > mLayout
void setMode(Mode mode)
Sets the label's current mode, allowing the label to switch between font based and HTML based renderi...
void setMarginY(double margin)
Sets the vertical margin between the edge of the frame and the label contents, in layout units...
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.
QString id() const
Returns the item's ID name.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
static void drawText(QPainter *painter, QPointF position, const QString &text, const QFont &font, const QColor &color=QColor())
Draws text on a painter at a specific position, taking care of layout specific issues (calculation to...
void setBackgroundEnabled(bool drawBackground)
Sets whether this item has a background drawn under it or not.
Contains settings and helpers relating to a render of a QgsLayoutItem.
Label displays text rendered using a single font.
QSizeF sizeForText() const
Returns the required item size (in layout units) for the label's text to fill the item...
A general purpose distance and area calculator, capable of performing ellipsoid based calculations...
static QgsNetworkAccessManager * instance(Qt::ConnectionType connectionType=Qt::BlockingQueuedConnection)
Returns a pointer to the active QgsNetworkAccessManager for the current thread.
static double fontHeightMM(const QFont &font)
Calculate a font height in millimeters, including workarounds for QT font rendering issues...
QPainter * painter()
Returns the destination QPainter for the render operation.
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used for rendering the map.
void setFont(const QFont &font)
Sets the label's current font.
void setFrameEnabled(bool drawFrame) override
Sets whether this item has a frame drawn around it or not.
bool readPropertiesFromElement(const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets item state from a DOM element.
virtual void setFrameEnabled(bool drawFrame)
Sets whether this item has a frame drawn around it or not.
static QDomElement toXmlElement(const QFont &font, QDomDocument &document, const QString &elementName)
Returns a DOM element containing the properties of the font.
void adjustSizeToText()
Resizes the item so that the label's text fits to the item.
QFont font() const
Returns the label's current font.
QString displayName() const override
Gets item display name.
This class provides a method of storing sizes, consisting of a width and height, for use in QGIS layo...
void changed()
Emitted when the object's properties change.
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
Represents a vector layer which manages a vector based data sets.
void refresh() override
Refreshes the item, causing a recalculation of any property overrides and recalculation of its positi...
QWebPage subclass which redirects JavaScript errors and console output to the QGIS message log...
void setText(const QString &text)
Sets the label's preset text.
QgsCoordinateReferenceSystem crs
QIcon icon() const override
Returns the item's icon.
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...