Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgslayoutitemhtml.h 3 : : ------------------------------------------------------------ 4 : : begin : October 2017 5 : : copyright : (C) 2017 by Nyall Dawson 6 : : email : nyall dot dawson at gmail dot com 7 : : *************************************************************************** 8 : : * * 9 : : * This program is free software; you can redistribute it and/or modify * 10 : : * it under the terms of the GNU General Public License as published by * 11 : : * the Free Software Foundation; either version 2 of the License, or * 12 : : * (at your option) any later version. * 13 : : * * 14 : : ***************************************************************************/ 15 : : 16 : : #ifndef QGSLAYOUTITEMHTML_H 17 : : #define QGSLAYOUTITEMHTML_H 18 : : 19 : : #include "qgis_core.h" 20 : : #include "qgis_sip.h" 21 : : #include "qgslayoutmultiframe.h" 22 : : #include "qgsfeature.h" 23 : : #include "qgsdistancearea.h" 24 : : #include <QUrl> 25 : : 26 : : class QgsWebPage; 27 : : class QImage; 28 : : class QgsVectorLayer; 29 : : class QgsNetworkContentFetcher; 30 : : 31 : : /** 32 : : * \ingroup core 33 : : * \brief A layout multiframe subclass for HTML content. 34 : : * \since QGIS 3.0 35 : : */ 36 : : class CORE_EXPORT QgsLayoutItemHtml: public QgsLayoutMultiFrame 37 : : { 38 : 0 : Q_OBJECT 39 : : 40 : : public: 41 : : 42 : : //! Source modes for the HTML content to render in the item 43 : : enum ContentMode 44 : : { 45 : : Url, //!< Using this mode item fetches its content via a url 46 : : ManualHtml //!< HTML content is manually set for the item 47 : : }; 48 : : 49 : : /** 50 : : * Constructor for QgsLayoutItemHtml, with the specified parent \a layout. 51 : : * 52 : : * Ownership is transferred to the layout. 53 : : */ 54 : : QgsLayoutItemHtml( QgsLayout *layout SIP_TRANSFERTHIS ); 55 : : 56 : : ~QgsLayoutItemHtml() override; 57 : : 58 : : int type() const override; 59 : : QIcon icon() const override; 60 : : 61 : : /** 62 : : * Returns a new QgsLayoutItemHtml for the specified parent \a layout. 63 : : */ 64 : : static QgsLayoutItemHtml *create( QgsLayout *layout ) SIP_FACTORY; 65 : : 66 : : /** 67 : : * Sets the source \a mode for item's HTML content. 68 : : * \see contentMode() 69 : : * \see setUrl() 70 : : * \see setHtml() 71 : : */ 72 : 0 : void setContentMode( ContentMode mode ) { mContentMode = mode; } 73 : : 74 : : /** 75 : : * Returns the source mode for item's HTML content. 76 : : * \see setContentMode() 77 : : * \see url() 78 : : * \see html() 79 : : */ 80 : : ContentMode contentMode() const { return mContentMode; } 81 : : 82 : : /** 83 : : * Sets the \a url for content to display in the item when the item is using 84 : : * the QgsLayoutItemHtml::Url mode. Content is automatically fetched and the 85 : : * HTML item refreshed after calling this function. 86 : : * \see url() 87 : : * \see contentMode() 88 : : */ 89 : : void setUrl( const QUrl &url ); 90 : : 91 : : /** 92 : : * Returns the URL of the content displayed in the item if the item is using 93 : : * the QgsLayoutItemHtml::Url mode. 94 : : * \see setUrl() 95 : : * \see contentMode() 96 : : */ 97 : : QUrl url() const { return mUrl; } 98 : : 99 : : /** 100 : : * Sets the \a html to display in the item when the item is using 101 : : * the QgsLayoutItemHtml::ManualHtml mode. Setting the HTML using this function 102 : : * does not automatically refresh the item's contents. Call loadHtml to trigger 103 : : * a refresh of the item after setting the HTML content. 104 : : * \see html() 105 : : * \see contentMode() 106 : : * \see loadHtml() 107 : : */ 108 : : void setHtml( const QString &html ); 109 : : 110 : : /** 111 : : * Returns the HTML source displayed in the item if the item is using 112 : : * the QgsLayoutItemHtml::ManualHtml mode. 113 : : * \see setHtml() 114 : : * \see contentMode() 115 : : */ 116 : : QString html() const { return mHtml; } 117 : : 118 : : /** 119 : : * Returns whether html item will evaluate QGIS expressions prior to rendering 120 : : * the HTML content. If set, any content inside [% %] tags will be 121 : : * treated as a QGIS expression and evaluated against the current atlas 122 : : * feature. 123 : : * \see setEvaluateExpressions() 124 : : */ 125 : : bool evaluateExpressions() const { return mEvaluateExpressions; } 126 : : 127 : : /** 128 : : * Sets whether the html item will evaluate QGIS expressions prior to rendering 129 : : * the HTML content. If set, any content inside [% %] tags will be 130 : : * treated as a QGIS expression and evaluated against the current atlas 131 : : * feature. 132 : : * \see evaluateExpressions() 133 : : */ 134 : : void setEvaluateExpressions( bool evaluateExpressions ); 135 : : 136 : : /** 137 : : * Returns whether html item is using smart breaks. Smart breaks prevent 138 : : * the html frame contents from breaking mid-way though a line of text. 139 : : * \see setUseSmartBreaks() 140 : : */ 141 : : bool useSmartBreaks() const { return mUseSmartBreaks; } 142 : : 143 : : /** 144 : : * Sets whether the html item should use smart breaks. Smart breaks prevent 145 : : * the html frame contents from breaking mid-way though a line of text. 146 : : * \see useSmartBreaks() 147 : : */ 148 : : void setUseSmartBreaks( bool useSmartBreaks ); 149 : : 150 : : /** 151 : : * Sets the maximum \a distance allowed when calculating where to place page breaks 152 : : * in the html. This distance is the maximum amount of empty space allowed 153 : : * at the bottom of a frame after calculating the optimum break location. Setting 154 : : * a larger value will result in better choice of page break location, but more 155 : : * wasted space at the bottom of frames. This setting is only effective if 156 : : * useSmartBreaks is TRUE. 157 : : * \see maxBreakDistance() 158 : : * \see setUseSmartBreaks() 159 : : */ 160 : : void setMaxBreakDistance( double distance ); 161 : : 162 : : /** 163 : : * Returns the maximum distance allowed when calculating where to place page breaks 164 : : * in the html. This distance is the maximum amount of empty space allowed 165 : : * at the bottom of a frame after calculating the optimum break location. This setting 166 : : * is only effective if useSmartBreaks is TRUE. 167 : : * \see setMaxBreakDistance() 168 : : * \see useSmartBreaks() 169 : : */ 170 : : double maxBreakDistance() const { return mMaxBreakDistance; } 171 : : 172 : : /** 173 : : * Sets the user \a stylesheet CSS rules to use while rendering the HTML content. These 174 : : * allow for overriding the styles specified within the HTML source. Setting the stylesheet 175 : : * using this function does not automatically refresh the item's contents. Call loadHtml 176 : : * to trigger a refresh of the item after setting the stylesheet rules. 177 : : * \see userStylesheet() 178 : : * \see setUserStylesheetEnabled() 179 : : * \see loadHtml() 180 : : */ 181 : : void setUserStylesheet( const QString &stylesheet ); 182 : : 183 : : /** 184 : : * Returns the user stylesheet CSS rules used while rendering the HTML content. These 185 : : * overriding the styles specified within the HTML source. 186 : : * \see setUserStylesheet() 187 : : * \see userStylesheetEnabled() 188 : : */ 189 : : QString userStylesheet() const { return mUserStylesheet; } 190 : : 191 : : /** 192 : : * Sets whether user stylesheets are \a enabled for the HTML content. 193 : : * \see userStylesheetEnabled() 194 : : * \see setUserStylesheet() 195 : : */ 196 : : void setUserStylesheetEnabled( bool enabled ); 197 : : 198 : : /** 199 : : * Returns whether user stylesheets are enabled for the HTML content. 200 : : * \see setUserStylesheetEnabled() 201 : : * \see userStylesheet() 202 : : */ 203 : : bool userStylesheetEnabled() const { return mEnableUserStylesheet; } 204 : : 205 : : QString displayName() const override; 206 : : QSizeF totalSize() const override; 207 : : void render( QgsLayoutItemRenderContext &context, const QRectF &renderExtent, int frameIndex ) override; 208 : : 209 : : //overridden to break frames without dividing lines of text 210 : : double findNearbyPageBreak( double yPos ) override; 211 : : 212 : : public slots: 213 : : 214 : : /** 215 : : * Reloads the html source from the url and redraws the item. 216 : : * \param useCache set to TRUE to use a cached copy of remote html 217 : : * content 218 : : * \param context expression context for evaluating data defined urls and expressions in html 219 : : * \see setUrl 220 : : * \see url 221 : : */ 222 : : void loadHtml( bool useCache = false, const QgsExpressionContext *context = nullptr ); 223 : : 224 : : //! Recalculates the frame sizes for the current viewport dimensions 225 : : void recalculateFrameSizes() override; 226 : : 227 : : void refreshDataDefinedProperty( QgsLayoutObject::DataDefinedProperty property = QgsLayoutObject::AllProperties ) override; 228 : : 229 : : protected: 230 : : 231 : : bool writePropertiesToElement( QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context ) const override; 232 : : bool readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context ) override; 233 : : 234 : : private: 235 : : ContentMode mContentMode = QgsLayoutItemHtml::Url; 236 : : QUrl mUrl; 237 : : std::unique_ptr< QgsWebPage > mWebPage; 238 : : QString mHtml; 239 : : QString mFetchedHtml; 240 : : QString mLastFetchedUrl; 241 : : QString mActualFetchedUrl; //may be different if page was redirected 242 : : QSizeF mSize; //total size in mm 243 : : double mHtmlUnitsToLayoutUnits = 1.0; 244 : : QImage mRenderedPage; 245 : : bool mEvaluateExpressions = true; 246 : : bool mUseSmartBreaks = true; 247 : : double mMaxBreakDistance = 10.0; 248 : : 249 : : QgsFeature mExpressionFeature; 250 : : QgsVectorLayer *mExpressionLayer = nullptr; 251 : : QgsDistanceArea mDistanceArea; 252 : : 253 : : QString mUserStylesheet; 254 : : bool mEnableUserStylesheet = false; 255 : : 256 : : //! JSON string representation of current atlas feature 257 : : QString mAtlasFeatureJSON; 258 : : 259 : : QgsNetworkContentFetcher *mFetcher = nullptr; 260 : : 261 : : double htmlUnitsToLayoutUnits(); //calculate scale factor 262 : : 263 : : //renders a snapshot of the page to a cached image 264 : : void renderCachedImage(); 265 : : 266 : : //fetches html content from a url and returns it as a string 267 : : QString fetchHtml( const QUrl &url ); 268 : : 269 : : //! Sets the current feature, the current layer and a list of local variable substitutions for evaluating expressions 270 : : void setExpressionContext( const QgsFeature &feature, QgsVectorLayer *layer ); 271 : : 272 : : //! Calculates the max width of frames in the html multiframe 273 : : double maxFrameWidth() const; 274 : : 275 : : void refreshExpressionContext(); 276 : : 277 : : QgsLayoutItemHtml( const QgsLayoutItemHtml & ) = delete; 278 : : QgsLayoutItemHtml &operator=( const QgsLayoutItemHtml & ) = delete; 279 : : }; 280 : : 281 : : ///@cond PRIVATE 282 : : #ifndef SIP_RUN 283 : 0 : class JavascriptExecutorLoop : public QEventLoop 284 : : { 285 : 0 : Q_OBJECT 286 : : public slots: 287 : : 288 : : void done(); 289 : : void execIfNotDone(); 290 : : void reportError( const QString &error ); 291 : : 292 : : private: 293 : : 294 : 0 : bool mDone = false; 295 : : 296 : : }; 297 : : #endif 298 : : ///@endcond 299 : : 300 : : #endif // QGSLAYOUTITEMHTML_H