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 layoutLabelElem.appendChild( fontColorElem );
376 mText = itemElem.attribute( QStringLiteral(
"labelText" ) );
379 mMode =
static_cast< Mode >( itemElem.attribute( QStringLiteral(
"htmlState" ) ).toInt() );
382 bool marginXOk =
false;
383 bool marginYOk =
false;
384 mMarginX = itemElem.attribute( QStringLiteral(
"marginX" ) ).toDouble( &marginXOk );
385 mMarginY = itemElem.attribute( QStringLiteral(
"marginY" ) ).toDouble( &marginYOk );
386 if ( !marginXOk || !marginYOk )
389 double margin = itemElem.attribute( QStringLiteral(
"margin" ), QStringLiteral(
"1.0" ) ).toDouble();
395 mHAlignment =
static_cast< Qt::AlignmentFlag
>( itemElem.attribute( QStringLiteral(
"halign" ) ).toInt() );
398 mVAlignment =
static_cast< Qt::AlignmentFlag
>( itemElem.attribute( QStringLiteral(
"valign" ) ).toInt() );
404 QDomNodeList fontColorList = itemElem.elementsByTagName( QStringLiteral(
"FontColor" ) );
405 if ( !fontColorList.isEmpty() )
407 QDomElement fontColorElem = fontColorList.at( 0 ).toElement();
408 int red = fontColorElem.attribute( QStringLiteral(
"red" ), QStringLiteral(
"0" ) ).toInt();
409 int green = fontColorElem.attribute( QStringLiteral(
"green" ), QStringLiteral(
"0" ) ).toInt();
410 int blue = fontColorElem.attribute( QStringLiteral(
"blue" ), QStringLiteral(
"0" ) ).toInt();
411 mFontColor = QColor( red, green, blue );
415 mFontColor = QColor( 0, 0, 0 );
423 if ( !
id().isEmpty() )
431 return tr(
"<HTML Label>" );
437 QString
text = mText;
438 if ( text.isEmpty() )
440 return tr(
"<Label>" );
442 if ( text.length() > 25 )
444 return QString( tr(
"%1…" ) ).arg( text.left( 25 ).simplified() );
448 return text.simplified();
457 QRectF rectangle = rect();
458 double penWidth =
frameEnabled() ? ( pen().widthF() / 2.0 ) : 0;
459 rectangle.adjust( -penWidth, -penWidth, penWidth, penWidth );
463 rectangle.adjust( mMarginX, 0, -mMarginX, 0 );
467 rectangle.adjust( 0, mMarginY, 0, -mMarginY );
476 prepareGeometryChange();
482 prepareGeometryChange();
488 refreshExpressionContext();
491 void QgsLayoutItemLabel::itemShiftAdjustSize(
double newWidth,
double newHeight,
double &xShift,
double &yShift )
const 494 double currentWidth = rect().width();
495 double currentHeight = rect().height();
499 double r = rotation();
500 if ( r >= 0 && r < 90 )
502 if ( mHAlignment == Qt::AlignHCenter )
504 xShift = - ( newWidth - currentWidth ) / 2.0;
506 else if ( mHAlignment == Qt::AlignRight )
508 xShift = - ( newWidth - currentWidth );
510 if ( mVAlignment == Qt::AlignVCenter )
512 yShift = -( newHeight - currentHeight ) / 2.0;
514 else if ( mVAlignment == Qt::AlignBottom )
516 yShift = - ( newHeight - currentHeight );
519 if ( r >= 90 && r < 180 )
521 if ( mHAlignment == Qt::AlignHCenter )
523 yShift = -( newHeight - currentHeight ) / 2.0;
525 else if ( mHAlignment == Qt::AlignRight )
527 yShift = -( newHeight - currentHeight );
529 if ( mVAlignment == Qt::AlignTop )
531 xShift = -( newWidth - currentWidth );
533 else if ( mVAlignment == Qt::AlignVCenter )
535 xShift = -( newWidth - currentWidth / 2.0 );
538 else if ( r >= 180 && r < 270 )
540 if ( mHAlignment == Qt::AlignHCenter )
542 xShift = -( newWidth - currentWidth ) / 2.0;
544 else if ( mHAlignment == Qt::AlignLeft )
546 xShift = -( newWidth - currentWidth );
548 if ( mVAlignment == Qt::AlignVCenter )
550 yShift = ( newHeight - currentHeight ) / 2.0;
552 else if ( mVAlignment == Qt::AlignTop )
554 yShift = ( newHeight - currentHeight );
557 else if ( r >= 270 && r < 360 )
559 if ( mHAlignment == Qt::AlignHCenter )
561 yShift = -( newHeight - currentHeight ) / 2.0;
563 else if ( mHAlignment == Qt::AlignLeft )
565 yShift = -( newHeight - currentHeight );
567 if ( mVAlignment == Qt::AlignBottom )
569 xShift = -( newWidth - currentWidth );
571 else if ( mVAlignment == Qt::AlignVCenter )
573 xShift = -( newWidth - currentWidth / 2.0 );
578 QUrl QgsLayoutItemLabel::createStylesheetUrl()
const 581 stylesheet += QStringLiteral(
"body { margin: %1 %2;" ).arg( std::max( mMarginY * mHtmlUnitsToLayoutUnits, 0.0 ) ).arg( std::max( mMarginX * mHtmlUnitsToLayoutUnits, 0.0 ) );
583 stylesheet += QStringLiteral(
"color: %1;" ).arg( mFontColor.name() );
584 stylesheet += QStringLiteral(
"text-align: %1; }" ).arg( mHAlignment == Qt::AlignLeft ? QStringLiteral(
"left" ) : mHAlignment == Qt::AlignRight ? QStringLiteral(
"right" ) : mHAlignment == Qt::AlignHCenter ? QStringLiteral(
"center" ) : QStringLiteral(
"justify" ) );
587 ba.append( stylesheet.toUtf8() );
588 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...