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 if ( QThread::currentThread() == QApplication::instance()->thread() )
80 mWebPage->setIdentifier( tr(
"Layout label item" ) );
84 QPalette palette = mWebPage->palette();
85 palette.setBrush( QPalette::Base, Qt::transparent );
86 mWebPage->setPalette( palette );
88 mWebPage->mainFrame()->setZoomFactor( 10.0 );
89 mWebPage->mainFrame()->setScrollBarPolicy( Qt::Horizontal, Qt::ScrollBarAlwaysOff );
90 mWebPage->mainFrame()->setScrollBarPolicy( Qt::Vertical, Qt::ScrollBarAlwaysOff );
92 connect( mWebPage.get(), &QWebPage::loadFinished,
this, &QgsLayoutItemLabel::loadingHtmlFinished );
119 double penWidth =
frameEnabled() ? ( pen().widthF() / 2.0 ) : 0;
120 double xPenAdjust = mMarginX < 0 ? -penWidth : penWidth;
121 double yPenAdjust = mMarginY < 0 ? -penWidth : penWidth;
122 QRectF painterRect( xPenAdjust + mMarginX, yPenAdjust + mMarginY, rect().width() - 2 * xPenAdjust - 2 * mMarginX, rect().height() - 2 * yPenAdjust - 2 * mMarginY );
131 mFirstRender =
false;
136 painter->scale( 1.0 / mHtmlUnitsToLayoutUnits / 10.0, 1.0 / mHtmlUnitsToLayoutUnits / 10.0 );
137 mWebPage->setViewportSize( QSize( painterRect.width() * mHtmlUnitsToLayoutUnits * 10.0, painterRect.height() * mHtmlUnitsToLayoutUnits * 10.0 ) );
138 mWebPage->settings()->setUserStyleSheetUrl( createStylesheetUrl() );
139 mWebPage->mainFrame()->render( painter );
147 painter->setFont( mFont );
148 QgsLayoutUtils::drawText( painter, painterRect, textToDraw, mFont, mFontColor, mHAlignment, mVAlignment, Qt::TextWordWrap );
156 void QgsLayoutItemLabel::contentChanged()
174 const QUrl baseUrl = QUrl::fromLocalFile(
mLayout->project()->absoluteFilePath() );
175 mWebPage->mainFrame()->setHtml( textToDraw, baseUrl );
183 if ( !mHtmlLoaded && ( !
mLayout || !
mLayout->renderContext().isPreviewRender() ) )
189 connect( mWebPage.get(), &QWebPage::loadFinished, &loop, &QEventLoop::quit );
193 timeoutTimer.setSingleShot(
true );
194 connect( &timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit );
195 timeoutTimer.start( 20000 );
198 loop.exec( QEventLoop::ExcludeUserInputEvents );
207 void QgsLayoutItemLabel::loadingHtmlFinished(
bool result )
215 double QgsLayoutItemLabel::htmlUnitsToLayoutUnits()
236 mLayout->itemsModel()->updateItemDisplayName(
this );
250 if (
mLayout &&
id().isEmpty() )
253 mLayout->itemsModel()->updateItemDisplayName(
this );
257 void QgsLayoutItemLabel::refreshExpressionContext()
266 mDistanceArea->setSourceCrs( layer->
crs(),
mLayout->project()->transformContext() );
273 mDistanceArea->setSourceCrs( referenceMap->
crs(),
mLayout->project()->transformContext() );
275 mDistanceArea->setEllipsoid(
mLayout->project()->ellipsoid() );
283 QString displayText = mText;
284 replaceDateText( displayText );
291 void QgsLayoutItemLabel::replaceDateText( QString &
text )
const 293 QString constant = QStringLiteral(
"$CURRENT_DATE" );
294 int currentDatePos = text.indexOf( constant );
295 if ( currentDatePos != -1 )
299 int openingBracketPos = text.indexOf(
'(', currentDatePos );
300 int closingBracketPos = text.indexOf(
')', openingBracketPos + 1 );
301 if ( openingBracketPos != -1 &&
302 closingBracketPos != -1 &&
303 ( closingBracketPos - openingBracketPos ) > 1 &&
304 openingBracketPos == currentDatePos + constant.size() )
306 formatText = text.mid( openingBracketPos + 1, closingBracketPos - openingBracketPos - 1 );
307 text.replace( currentDatePos, closingBracketPos - currentDatePos + 1, QDate::currentDate().toString( formatText ) );
311 text.replace( QLatin1String(
"$CURRENT_DATE" ), QDate::currentDate().toString() );
325 prepareGeometryChange();
331 prepareGeometryChange();
337 prepareGeometryChange();
348 itemShiftAdjustSize( newSize.width(), newSize.height(), xShift, yShift );
351 attemptSetSceneRect( QRectF( pos().x() + xShift, pos().y() + yShift, newSize.width(), newSize.height() ) );
359 double penWidth =
frameEnabled() ? ( pen().widthF() / 2.0 ) : 0;
361 double width = textWidth + 2 * mMarginX + 2 * penWidth + 1;
362 double height = fontHeight + 2 * mMarginY + 2 * penWidth;
374 layoutLabelElem.setAttribute( QStringLiteral(
"htmlState" ), static_cast< int >( mMode ) );
376 layoutLabelElem.setAttribute( QStringLiteral(
"labelText" ), mText );
377 layoutLabelElem.setAttribute( QStringLiteral(
"marginX" ), QString::number( mMarginX ) );
378 layoutLabelElem.setAttribute( QStringLiteral(
"marginY" ), QString::number( mMarginY ) );
379 layoutLabelElem.setAttribute( QStringLiteral(
"halign" ), mHAlignment );
380 layoutLabelElem.setAttribute( QStringLiteral(
"valign" ), mVAlignment );
384 layoutLabelElem.appendChild( labelFontElem );
387 QDomElement fontColorElem = doc.createElement( QStringLiteral(
"FontColor" ) );
388 fontColorElem.setAttribute( QStringLiteral(
"red" ), mFontColor.red() );
389 fontColorElem.setAttribute( QStringLiteral(
"green" ), mFontColor.green() );
390 fontColorElem.setAttribute( QStringLiteral(
"blue" ), mFontColor.blue() );
391 fontColorElem.setAttribute( QStringLiteral(
"alpha" ), mFontColor.alpha() );
392 layoutLabelElem.appendChild( fontColorElem );
402 mText = itemElem.attribute( QStringLiteral(
"labelText" ) );
405 mMode =
static_cast< Mode >( itemElem.attribute( QStringLiteral(
"htmlState" ) ).toInt() );
408 bool marginXOk =
false;
409 bool marginYOk =
false;
410 mMarginX = itemElem.attribute( QStringLiteral(
"marginX" ) ).toDouble( &marginXOk );
411 mMarginY = itemElem.attribute( QStringLiteral(
"marginY" ) ).toDouble( &marginYOk );
412 if ( !marginXOk || !marginYOk )
415 double margin = itemElem.attribute( QStringLiteral(
"margin" ), QStringLiteral(
"1.0" ) ).toDouble();
421 mHAlignment =
static_cast< Qt::AlignmentFlag
>( itemElem.attribute( QStringLiteral(
"halign" ) ).toInt() );
424 mVAlignment =
static_cast< Qt::AlignmentFlag
>( itemElem.attribute( QStringLiteral(
"valign" ) ).toInt() );
430 QDomNodeList fontColorList = itemElem.elementsByTagName( QStringLiteral(
"FontColor" ) );
431 if ( !fontColorList.isEmpty() )
433 QDomElement fontColorElem = fontColorList.at( 0 ).toElement();
434 int red = fontColorElem.attribute( QStringLiteral(
"red" ), QStringLiteral(
"0" ) ).toInt();
435 int green = fontColorElem.attribute( QStringLiteral(
"green" ), QStringLiteral(
"0" ) ).toInt();
436 int blue = fontColorElem.attribute( QStringLiteral(
"blue" ), QStringLiteral(
"0" ) ).toInt();
437 int alpha = fontColorElem.attribute( QStringLiteral(
"alpha" ), QStringLiteral(
"255" ) ).toInt();
438 mFontColor = QColor( red, green, blue, alpha );
442 mFontColor = QColor( 0, 0, 0 );
450 if ( !
id().isEmpty() )
458 return tr(
"<HTML Label>" );
464 QString
text = mText;
465 if ( text.isEmpty() )
467 return tr(
"<Label>" );
469 if ( text.length() > 25 )
471 return QString( tr(
"%1…" ) ).arg( text.left( 25 ).simplified() );
475 return text.simplified();
484 QRectF rectangle = rect();
485 double penWidth =
frameEnabled() ? ( pen().widthF() / 2.0 ) : 0;
486 rectangle.adjust( -penWidth, -penWidth, penWidth, penWidth );
490 rectangle.adjust( mMarginX, 0, -mMarginX, 0 );
494 rectangle.adjust( 0, mMarginY, 0, -mMarginY );
503 prepareGeometryChange();
509 prepareGeometryChange();
515 refreshExpressionContext();
518 void QgsLayoutItemLabel::itemShiftAdjustSize(
double newWidth,
double newHeight,
double &xShift,
double &yShift )
const 521 double currentWidth = rect().width();
522 double currentHeight = rect().height();
526 double r = rotation();
527 if ( r >= 0 && r < 90 )
529 if ( mHAlignment == Qt::AlignHCenter )
531 xShift = - ( newWidth - currentWidth ) / 2.0;
533 else if ( mHAlignment == Qt::AlignRight )
535 xShift = - ( newWidth - currentWidth );
537 if ( mVAlignment == Qt::AlignVCenter )
539 yShift = -( newHeight - currentHeight ) / 2.0;
541 else if ( mVAlignment == Qt::AlignBottom )
543 yShift = - ( newHeight - currentHeight );
546 if ( r >= 90 && r < 180 )
548 if ( mHAlignment == Qt::AlignHCenter )
550 yShift = -( newHeight - currentHeight ) / 2.0;
552 else if ( mHAlignment == Qt::AlignRight )
554 yShift = -( newHeight - currentHeight );
556 if ( mVAlignment == Qt::AlignTop )
558 xShift = -( newWidth - currentWidth );
560 else if ( mVAlignment == Qt::AlignVCenter )
562 xShift = -( newWidth - currentWidth / 2.0 );
565 else if ( r >= 180 && r < 270 )
567 if ( mHAlignment == Qt::AlignHCenter )
569 xShift = -( newWidth - currentWidth ) / 2.0;
571 else if ( mHAlignment == Qt::AlignLeft )
573 xShift = -( newWidth - currentWidth );
575 if ( mVAlignment == Qt::AlignVCenter )
577 yShift = ( newHeight - currentHeight ) / 2.0;
579 else if ( mVAlignment == Qt::AlignTop )
581 yShift = ( newHeight - currentHeight );
584 else if ( r >= 270 && r < 360 )
586 if ( mHAlignment == Qt::AlignHCenter )
588 yShift = -( newHeight - currentHeight ) / 2.0;
590 else if ( mHAlignment == Qt::AlignLeft )
592 yShift = -( newHeight - currentHeight );
594 if ( mVAlignment == Qt::AlignBottom )
596 xShift = -( newWidth - currentWidth );
598 else if ( mVAlignment == Qt::AlignVCenter )
600 xShift = -( newWidth - currentWidth / 2.0 );
605 QUrl QgsLayoutItemLabel::createStylesheetUrl()
const 608 stylesheet += QStringLiteral(
"body { margin: %1 %2;" ).arg( std::max( mMarginY * mHtmlUnitsToLayoutUnits, 0.0 ) ).arg( std::max( mMarginX * mHtmlUnitsToLayoutUnits, 0.0 ) );
610 stylesheet += QStringLiteral(
"color: rgba(%1,%2,%3,%4);" ).arg( mFontColor.red() ).arg( mFontColor.green() ).arg( mFontColor.blue() ).arg( QString::number( mFontColor.alphaF(),
'f', 4 ) );
611 stylesheet += QStringLiteral(
"text-align: %1; }" ).arg( mHAlignment == Qt::AlignLeft ? QStringLiteral(
"left" ) : mHAlignment == Qt::AlignRight ? QStringLiteral(
"right" ) : mHAlignment == Qt::AlignHCenter ? QStringLiteral(
"center" ) : QStringLiteral(
"justify" ) );
614 ba.append( stylesheet.toUtf8() );
615 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.
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.
int type() const override
static QgsLayoutItemLabel * create(QgsLayout *layout)
Returns a new label item for the specified layout.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
virtual void setFrameStrokeWidth(QgsLayoutMeasurement width)
Sets the frame stroke width.
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
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.
static QString asCSS(const QFont &font, double pointToPixelMultiplier=1.0)
Returns a CSS string representing the specified font as closely as possible.
QString currentText() const
Returns the text as it appears on the label (with evaluated expressions and other dynamic content)...
virtual void drawFrame(QgsRenderContext &context)
Draws the frame around the item.
QFont font() const
Returns the label's current font.
virtual void invalidateCache()
Forces a deferred update of any cached image the item uses.
Layout graphical items for displaying a map.
This class provides a method of storing measurements for use in QGIS layouts using a variety of diffe...
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.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
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...
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used for rendering the map.
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.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
QString text() const
Returns the label's preset text.
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.
Mode mode() const
Returns the label's current mode.
Label displays text rendered using a single font.
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.
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.
QSizeF sizeForText() const
Returns the required item size (in layout units) for the label's text to fill the item...
QString id() const
Returns the item's ID name.
static QDomElement toXmlElement(const QFont &font, QDomDocument &document, const QString &elementName)
Returns a DOM element containing the properties of the font.
const QgsLayout * layout() const
Returns the layout the object is attached to.
void adjustSizeToText()
Resizes the item so that the label's text fits to the item.
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.
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...
bool frameEnabled() const
Returns true if the item includes a frame.
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...