38 #include <QCoreApplication> 
   40 #include <QDomElement> 
   50   mHtmlUnitsToLayoutUnits = htmlUnitsToLayoutUnits();
 
   54   const 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   const double penWidth = 
frameEnabled() ? ( pen().widthF() / 2.0 ) : 0;
 
  121   const double xPenAdjust = mMarginX < 0 ? -penWidth : penWidth;
 
  122   const double yPenAdjust = mMarginY < 0 ? -penWidth : penWidth;
 
  123   const 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   const QString constant = QStringLiteral( 
"$CURRENT_DATE" );
 
  294   const int currentDatePos = 
text.indexOf( constant );
 
  295   if ( currentDatePos != -1 )
 
  299     const int openingBracketPos = 
text.indexOf( 
'(', currentDatePos );
 
  300     const 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   const double penWidth = 
frameEnabled() ? ( pen().widthF() / 2.0 ) : 0;
 
  361   const double width = textWidth + 2 * mMarginX + 2 * penWidth;
 
  362   const 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     const 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   const QDomNodeList fontColorList = itemElem.elementsByTagName( QStringLiteral( 
"FontColor" ) );
 
  431   if ( !fontColorList.isEmpty() )
 
  433     const QDomElement fontColorElem = fontColorList.at( 0 ).toElement();
 
  434     const int red = fontColorElem.attribute( QStringLiteral( 
"red" ), QStringLiteral( 
"0" ) ).toInt();
 
  435     const int green = fontColorElem.attribute( QStringLiteral( 
"green" ), QStringLiteral( 
"0" ) ).toInt();
 
  436     const int blue = fontColorElem.attribute( QStringLiteral( 
"blue" ), QStringLiteral( 
"0" ) ).toInt();
 
  437     const 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       const 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   const 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   const double currentWidth = rect().width();
 
  532   const double currentHeight = rect().height();
 
  536   const 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.
This class is a composition of two QSettings instances:
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
@ 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.