32 #include "qgssettings.h"
38 #include <QCoreApplication>
40 #include <QDomElement>
50 mHtmlUnitsToLayoutUnits = htmlUnitsToLayoutUnits();
54 QString defaultFontString = settings.value( QStringLiteral(
"LayoutDesigner/defaultFont" ), QVariant(), QgsSettings::Gui ).toString();
55 if ( !defaultFontString.isEmpty() )
57 mFont.setFamily( defaultFontString );
61 mFont.setPointSizeF( 10 );
68 refreshExpressionContext();
71 if ( QThread::currentThread() == QApplication::instance()->thread() )
81 mWebPage->setIdentifier( tr(
"Layout label item" ) );
85 QPalette palette = mWebPage->palette();
86 palette.setBrush( QPalette::Base, Qt::transparent );
87 mWebPage->setPalette( palette );
89 mWebPage->mainFrame()->setZoomFactor( 10.0 );
90 mWebPage->mainFrame()->setScrollBarPolicy( Qt::Horizontal, Qt::ScrollBarAlwaysOff );
91 mWebPage->mainFrame()->setScrollBarPolicy( Qt::Vertical, Qt::ScrollBarAlwaysOff );
93 connect( mWebPage.get(), &QWebPage::loadFinished,
this, &QgsLayoutItemLabel::loadingHtmlFinished );
120 double penWidth =
frameEnabled() ? ( pen().widthF() / 2.0 ) : 0;
121 double xPenAdjust = mMarginX < 0 ? -penWidth : penWidth;
122 double yPenAdjust = mMarginY < 0 ? -penWidth : penWidth;
123 QRectF painterRect( xPenAdjust + mMarginX, yPenAdjust + mMarginY, rect().width() - 2 * xPenAdjust - 2 * mMarginX, rect().height() - 2 * yPenAdjust - 2 * mMarginY );
132 mFirstRender =
false;
137 painter->scale( 1.0 / mHtmlUnitsToLayoutUnits / 10.0, 1.0 / mHtmlUnitsToLayoutUnits / 10.0 );
138 mWebPage->setViewportSize( QSize( painterRect.width() * mHtmlUnitsToLayoutUnits * 10.0, painterRect.height() * mHtmlUnitsToLayoutUnits * 10.0 ) );
139 mWebPage->settings()->setUserStyleSheetUrl( createStylesheetUrl() );
140 mWebPage->mainFrame()->render( painter );
148 painter->setFont( mFont );
149 QgsLayoutUtils::drawText( painter, painterRect, textToDraw, mFont, mFontColor, mHAlignment, mVAlignment, Qt::TextWordWrap );
155 void QgsLayoutItemLabel::contentChanged()
173 const QUrl baseUrl = QUrl::fromLocalFile(
mLayout->project()->absoluteFilePath() );
174 mWebPage->mainFrame()->setHtml( textToDraw, baseUrl );
182 if ( !mHtmlLoaded && ( !
mLayout || !
mLayout->renderContext().isPreviewRender() ) )
188 connect( mWebPage.get(), &QWebPage::loadFinished, &loop, &QEventLoop::quit );
192 timeoutTimer.setSingleShot(
true );
193 connect( &timeoutTimer, &QTimer::timeout, &loop, &QEventLoop::quit );
194 timeoutTimer.start( 20000 );
197 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;
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();
516 refreshExpressionContext();
522 if ( evaluated == mText )
528 void QgsLayoutItemLabel::itemShiftAdjustSize(
double newWidth,
double newHeight,
double &xShift,
double &yShift )
const
531 double currentWidth = rect().width();
532 double currentHeight = rect().height();
536 double r = rotation();
537 if ( r >= 0 && r < 90 )
539 if ( mHAlignment == Qt::AlignHCenter )
541 xShift = - ( newWidth - currentWidth ) / 2.0;
543 else if ( mHAlignment == Qt::AlignRight )
545 xShift = - ( newWidth - currentWidth );
547 if ( mVAlignment == Qt::AlignVCenter )
549 yShift = -( newHeight - currentHeight ) / 2.0;
551 else if ( mVAlignment == Qt::AlignBottom )
553 yShift = - ( newHeight - currentHeight );
556 if ( r >= 90 && r < 180 )
558 if ( mHAlignment == Qt::AlignHCenter )
560 yShift = -( newHeight - currentHeight ) / 2.0;
562 else if ( mHAlignment == Qt::AlignRight )
564 yShift = -( newHeight - currentHeight );
566 if ( mVAlignment == Qt::AlignTop )
568 xShift = -( newWidth - currentWidth );
570 else if ( mVAlignment == Qt::AlignVCenter )
572 xShift = -( newWidth - currentWidth / 2.0 );
575 else if ( r >= 180 && r < 270 )
577 if ( mHAlignment == Qt::AlignHCenter )
579 xShift = -( newWidth - currentWidth ) / 2.0;
581 else if ( mHAlignment == Qt::AlignLeft )
583 xShift = -( newWidth - currentWidth );
585 if ( mVAlignment == Qt::AlignVCenter )
587 yShift = ( newHeight - currentHeight ) / 2.0;
589 else if ( mVAlignment == Qt::AlignTop )
591 yShift = ( newHeight - currentHeight );
594 else if ( r >= 270 && r < 360 )
596 if ( mHAlignment == Qt::AlignHCenter )
598 yShift = -( newHeight - currentHeight ) / 2.0;
600 else if ( mHAlignment == Qt::AlignLeft )
602 yShift = -( newHeight - currentHeight );
604 if ( mVAlignment == Qt::AlignBottom )
606 xShift = -( newWidth - currentWidth );
608 else if ( mVAlignment == Qt::AlignVCenter )
610 xShift = -( newWidth - currentWidth / 2.0 );
615 QUrl QgsLayoutItemLabel::createStylesheetUrl()
const
618 stylesheet += QStringLiteral(
"body { margin: %1 %2;" ).arg( std::max( mMarginY * mHtmlUnitsToLayoutUnits, 0.0 ) ).arg( std::max( mMarginX * mHtmlUnitsToLayoutUnits, 0.0 ) );
620 stylesheet += QStringLiteral(
"color: rgba(%1,%2,%3,%4);" ).arg( mFontColor.red() ).arg( mFontColor.green() ).arg( mFontColor.blue() ).arg( QString::number( mFontColor.alphaF(),
'f', 4 ) );
621 stylesheet += QStringLiteral(
"text-align: %1; }" ).arg( mHAlignment == Qt::AlignLeft ? QStringLiteral(
"left" ) : mHAlignment == Qt::AlignRight ? QStringLiteral(
"right" ) : mHAlignment == Qt::AlignHCenter ? QStringLiteral(
"center" ) : QStringLiteral(
"justify" ) );
624 ba.append( stylesheet.toUtf8() );
625 QUrl cssFileURL = QUrl( QString(
"data:text/css;charset=utf-8;base64," + ba.toBase64() ) );
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.
static QDomElement toXmlElement(const QFont &font, QDomDocument &document, const QString &elementName)
Returns a DOM element containing the properties of the font.
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.
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.
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...
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 double fontHeightMM(const QFont &font)
Calculate a font height in millimeters, including workarounds for QT font rendering issues.
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...
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 ...
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.
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.
@ LayoutMillimeters
Millimeters.
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.