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();
516 refreshExpressionContext();
519 void QgsLayoutItemLabel::itemShiftAdjustSize(
double newWidth,
double newHeight,
double &xShift,
double &yShift )
const 522 double currentWidth = rect().width();
523 double currentHeight = rect().height();
527 double r = rotation();
528 if ( r >= 0 && r < 90 )
530 if ( mHAlignment == Qt::AlignHCenter )
532 xShift = - ( newWidth - currentWidth ) / 2.0;
534 else if ( mHAlignment == Qt::AlignRight )
536 xShift = - ( newWidth - currentWidth );
538 if ( mVAlignment == Qt::AlignVCenter )
540 yShift = -( newHeight - currentHeight ) / 2.0;
542 else if ( mVAlignment == Qt::AlignBottom )
544 yShift = - ( newHeight - currentHeight );
547 if ( r >= 90 && r < 180 )
549 if ( mHAlignment == Qt::AlignHCenter )
551 yShift = -( newHeight - currentHeight ) / 2.0;
553 else if ( mHAlignment == Qt::AlignRight )
555 yShift = -( newHeight - currentHeight );
557 if ( mVAlignment == Qt::AlignTop )
559 xShift = -( newWidth - currentWidth );
561 else if ( mVAlignment == Qt::AlignVCenter )
563 xShift = -( newWidth - currentWidth / 2.0 );
566 else if ( r >= 180 && r < 270 )
568 if ( mHAlignment == Qt::AlignHCenter )
570 xShift = -( newWidth - currentWidth ) / 2.0;
572 else if ( mHAlignment == Qt::AlignLeft )
574 xShift = -( newWidth - currentWidth );
576 if ( mVAlignment == Qt::AlignVCenter )
578 yShift = ( newHeight - currentHeight ) / 2.0;
580 else if ( mVAlignment == Qt::AlignTop )
582 yShift = ( newHeight - currentHeight );
585 else if ( r >= 270 && r < 360 )
587 if ( mHAlignment == Qt::AlignHCenter )
589 yShift = -( newHeight - currentHeight ) / 2.0;
591 else if ( mHAlignment == Qt::AlignLeft )
593 yShift = -( newHeight - currentHeight );
595 if ( mVAlignment == Qt::AlignBottom )
597 xShift = -( newWidth - currentWidth );
599 else if ( mVAlignment == Qt::AlignVCenter )
601 xShift = -( newWidth - currentWidth / 2.0 );
606 QUrl QgsLayoutItemLabel::createStylesheetUrl()
const 609 stylesheet += QStringLiteral(
"body { margin: %1 %2;" ).arg( std::max( mMarginY * mHtmlUnitsToLayoutUnits, 0.0 ) ).arg( std::max( mMarginX * mHtmlUnitsToLayoutUnits, 0.0 ) );
611 stylesheet += QStringLiteral(
"color: rgba(%1,%2,%3,%4);" ).arg( mFontColor.red() ).arg( mFontColor.green() ).arg( mFontColor.blue() ).arg( QString::number( mFontColor.alphaF(),
'f', 4 ) );
612 stylesheet += QStringLiteral(
"text-align: %1; }" ).arg( mHAlignment == Qt::AlignLeft ? QStringLiteral(
"left" ) : mHAlignment == Qt::AlignRight ? QStringLiteral(
"right" ) : mHAlignment == Qt::AlignHCenter ? QStringLiteral(
"center" ) : QStringLiteral(
"justify" ) );
615 ba.append( stylesheet.toUtf8() );
616 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.
virtual void invalidateCache()
Forces a deferred update of any cached image the item uses.
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.
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...
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...