1 /*************************************************************************** 2 qgsabstractreportsection.h 3 --------------------------- 4 begin : December 2017 5 copyright : (C) 2017 by Nyall Dawson 6 email : nyall dot dawson at gmail dot com 7 ***************************************************************************/ 8 /*************************************************************************** 9 * * 10 * This program is free software; you can redistribute it and/or modify * 11 * it under the terms of the GNU General Public License as published by * 12 * the Free Software Foundation; either version 2 of the License, or * 13 * (at your option) any later version. * 14 * * 15 ***************************************************************************/ 16 #ifndef QGSABSTRACTREPORTSECTION_H 17 #define QGSABSTRACTREPORTSECTION_H 18 19 #include "qgis_core.h" 20 #include "qgsabstractlayoutiterator.h" 21 #include "qgslayoutreportcontext.h" 22 #include "qgsvectorlayerref.h" 23 24 25 ///@cond NOT_STABLE 26 27 // This is not considered stable API - it is exposed to python bindings only for unit testing! 28 29 /** 30 * \ingroup core 31 * \class QgsReportSectionContext 32 * \brief Current context for a report section. 33 * \warning This is not considered stable API, and may change in future QGIS releases. It is 34 * exposed to the Python bindings for unit testing purposes only. 35 * \since QGIS 3.0 36 */ 37 class CORE_EXPORT QgsReportSectionContext 38 { 39 public: 40 41 //! Current feature 42 QgsFeature feature; 43 44 //! Current coverage layer 45 QgsVectorLayer *currentLayer = nullptr; 46 47 //! Current field filters 48 QVariantMap fieldFilters; 49 }; 50 51 /** 52 * \ingroup core 53 * \class QgsAbstractReportSection 54 * \brief An abstract base class for QgsReport subsections. 55 * \warning This is not considered stable API, and may change in future QGIS releases. It is 56 * exposed to the Python bindings for unit testing purposes only. 57 * \since QGIS 3.0 58 */ 59 class CORE_EXPORT QgsAbstractReportSection : public QgsAbstractLayoutIterator 60 { 61 62 #ifdef SIP_RUN 63 SIP_CONVERT_TO_SUBCLASS_CODE 64 if ( dynamic_cast< QgsReportSectionFieldGroup * >( sipCpp ) ) 65 sipType = sipType_QgsReportSectionFieldGroup; 66 else if ( dynamic_cast< QgsReportSectionLayout * >( sipCpp ) ) 67 sipType = sipType_QgsReportSectionLayout; 68 else 69 sipType = NULL; 70 SIP_END 71 #endif 72 73 public: 74 75 /** 76 * Constructor for QgsAbstractReportSection, attached to the specified \a parent section. 77 * Note that ownership is not transferred to \a parent. 78 */ 79 QgsAbstractReportSection( QgsAbstractReportSection *parentSection = nullptr ); 80 81 ~QgsAbstractReportSection() override; 82 83 //! QgsAbstractReportSection cannot be copied 84 QgsAbstractReportSection( const QgsAbstractReportSection &other ) = delete; 85 86 //! QgsAbstractReportSection cannot be copied 87 QgsAbstractReportSection &operator=( const QgsAbstractReportSection &other ) = delete; 88 89 /** 90 * Returns the section subclass type. 91 */ 92 virtual QString type() const = 0; 93 94 /** 95 * Returns a user-visible, translated description of the section. 96 */ 97 virtual QString description() const = 0; 98 99 /** 100 * Returns an icon representing the section. 101 */ 102 virtual QIcon icon() const = 0; 103 104 /** 105 * Clones the report section. Ownership of the returned section is 106 * transferred to the caller. 107 * 108 * Subclasses should call copyCommonProperties() in their clone() 109 * implementations. 110 */ 111 virtual QgsAbstractReportSection *clone() const = 0 SIP_FACTORY; 112 113 /** 114 * Returns the parent report section. 115 */ parentSection()116 QgsAbstractReportSection *parentSection() { return mParent; } 117 118 /** 119 * Returns the associated project. 120 */ 121 QgsProject *project(); 122 123 // TODO - how to handle this? count()124 int count() const override { return -1; } 125 126 QString filePath( const QString &baseFilePath, const QString &extension ) override; 127 QgsLayout *layout() override; 128 bool beginRender() override; 129 bool next() override; 130 bool endRender() override; 131 132 /** 133 * Resets the section, ready for a new iteration. 134 */ 135 virtual void reset(); 136 137 /** 138 * Called just before rendering the section's header. Should return TRUE if the header 139 * is to be included for this section, or FALSE to skip the header for the current 140 * section. 141 * \see prepareFooter() 142 */ 143 virtual bool prepareHeader(); 144 145 /** 146 * Called just before rendering the section's footer. Should return TRUE if the footer 147 * is to be included for this section, or FALSE to skip the footerfor the current 148 * section. 149 * \see prepareHeader() 150 */ 151 virtual bool prepareFooter(); 152 153 /** 154 * Returns the next body layout to export, or NULLPTR if 155 * no body layout is required this iteration. 156 * 157 * \a ok will be set to FALSE if no bodies remain for this section. 158 */ nextBody(bool & ok SIP_OUT)159 virtual QgsLayout *nextBody( bool &ok SIP_OUT ) { ok = false; return nullptr; } 160 161 /** 162 * Returns TRUE if the header for the section is enabled. 163 * \see setHeaderEnabled() 164 * \see header() 165 * \see setHeader() 166 */ headerEnabled()167 bool headerEnabled() const { return mHeaderEnabled; } 168 169 /** 170 * Sets whether the header for the section is \a enabled. 171 * \see headerEnabled() 172 * \see header() 173 * \see setHeader() 174 */ setHeaderEnabled(bool enabled)175 void setHeaderEnabled( bool enabled ) { mHeaderEnabled = enabled; } 176 177 /** 178 * Returns the header for the section. Note that the header is only 179 * included if headerEnabled() is TRUE. 180 * \see setHeaderEnabled() 181 * \see headerEnabled() 182 * \see setHeader() 183 */ header()184 QgsLayout *header() { return mHeader.get(); } 185 186 /** 187 * Sets the \a header for the section. Note that the header is only 188 * included if headerEnabled() is TRUE. Ownership of \a header 189 * is transferred to the report section. 190 * \see setHeaderEnabled() 191 * \see headerEnabled() 192 * \see header() 193 */ 194 void setHeader( QgsLayout *header SIP_TRANSFER ); 195 196 /** 197 * Returns TRUE if the footer for the section is enabled. 198 * \see setFooterEnabled() 199 * \see footer() 200 * \see setFooter() 201 */ footerEnabled()202 bool footerEnabled() const { return mFooterEnabled; } 203 204 /** 205 * Sets whether the footer for the section is \a enabled. 206 * \see footerEnabled() 207 * \see footer() 208 * \see setFooter() 209 */ setFooterEnabled(bool enabled)210 void setFooterEnabled( bool enabled ) { mFooterEnabled = enabled; } 211 212 /** 213 * Returns the footer for the section. Note that the footer is only 214 * included if footerEnabled() is TRUE. 215 * \see setFooterEnabled() 216 * \see footerEnabled() 217 * \see setFooter() 218 */ footer()219 QgsLayout *footer() { return mFooter.get(); } 220 221 /** 222 * Sets the \a footer for the section. Note that the footer is only 223 * included if footerEnabled() is TRUE. Ownership of \a footer 224 * is transferred to the report section. 225 * \see setFooterEnabled() 226 * \see footerEnabled() 227 * \see footer() 228 */ 229 void setFooter( QgsLayout *footer SIP_TRANSFER ); 230 231 /** 232 * Returns the number of child sections for this report section. The child 233 * sections form the body of the report section. 234 * \see children() 235 */ childCount()236 int childCount() const { return mChildren.count(); } 237 238 /** 239 * Returns the row number of the section within it's parent section. 240 */ 241 int row() const; 242 243 /** 244 * Returns all child sections for this report section. The child 245 * sections form the body of the report section. 246 * \see childCount() 247 * \see child() 248 * \see appendChild() 249 * \see insertChild() 250 * \see removeChild() 251 */ childSections()252 QList< QgsAbstractReportSection * > childSections() const { return mChildren; } 253 254 /** 255 * Returns the child section at the specified \a index. 256 * \see children() 257 */ 258 QgsAbstractReportSection *childSection( int index ); 259 260 /** 261 * Adds a child \a section, transferring ownership of the section to this section. 262 * \see children() 263 * \see insertChild() 264 */ 265 void appendChild( QgsAbstractReportSection *section SIP_TRANSFER ); 266 267 /** 268 * Inserts a child \a section at the specified \a index, transferring ownership of the section to this section. 269 * \see children() 270 * \see appendChild() 271 */ 272 void insertChild( int index, QgsAbstractReportSection *section SIP_TRANSFER ); 273 274 /** 275 * Removes a child \a section, deleting it. 276 * \see children() 277 */ 278 void removeChild( QgsAbstractReportSection *section ); 279 280 /** 281 * Removes the child section at the specified \a index, deleting it. 282 * \see children() 283 */ 284 void removeChildAt( int index ); 285 286 /** 287 * Sets the current \a context for this section. 288 * \see context() 289 */ 290 void setContext( const QgsReportSectionContext &context ); 291 292 /** 293 * Returns the current context for this section. 294 * \see setContext() 295 */ context()296 const QgsReportSectionContext &context() const { return mContext; } 297 298 /** 299 * Stores the section state in a DOM element. 300 * \see readXml() 301 */ 302 bool writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context ) const; 303 304 /** 305 * Sets the item state from a DOM element. 306 * \see writeXml() 307 */ 308 bool readXml( const QDomElement §ionElement, const QDomDocument &document, const QgsReadWriteContext &context ); 309 310 /** 311 * Refreshes the section when global layout related options change. 312 */ 313 virtual void reloadSettings(); 314 315 /** 316 * Accepts the specified style entity \a visitor, causing it to visit all style entities associated 317 * with the report. 318 * 319 * Returns TRUE if the visitor should continue visiting other objects, or FALSE if visiting 320 * should be canceled. 321 * 322 * \since QGIS 3.10 323 */ 324 bool accept( QgsStyleEntityVisitorInterface *visitor ) const; 325 326 protected: 327 328 //! Report sub-sections 329 enum SubSection 330 { 331 Header, //!< Header for section 332 Body, //!< Body of section 333 Children, //!< Child sections 334 Footer, //!< Footer for section 335 End, //!< End of section (i.e. past all available content) 336 }; 337 338 /** 339 * Copies the common properties of a report section to a \a destination section. 340 * This method should be called from clone() implementations. 341 */ 342 void copyCommonProperties( QgsAbstractReportSection *destination ) const; 343 344 /** 345 * Sets the \a parent report section. 346 */ setParentSection(QgsAbstractReportSection * parent)347 virtual void setParentSection( QgsAbstractReportSection *parent ) { mParent = parent; } 348 349 /** 350 * Stores section state within an XML DOM element. 351 * \see writeXml() 352 * \see readPropertiesFromElement() 353 */ 354 virtual bool writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const; 355 356 /** 357 * Sets section state from a DOM element. 358 * \see writePropertiesToElement() 359 * \see readXml() 360 */ 361 virtual bool readPropertiesFromElement( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context ); 362 363 private: 364 365 QgsAbstractReportSection *mParent = nullptr; 366 367 int mSectionNumber = 0; 368 SubSection mNextSection = Header; 369 int mNextChild = 0; 370 QgsLayout *mCurrentLayout = nullptr; 371 372 bool mHeaderEnabled = false; 373 bool mFooterEnabled = false; 374 std::unique_ptr< QgsLayout > mHeader; 375 std::unique_ptr< QgsLayout > mFooter; 376 377 QList< QgsAbstractReportSection * > mChildren; 378 379 QgsReportSectionContext mContext; 380 381 #ifdef SIP_RUN 382 QgsAbstractReportSection( const QgsAbstractReportSection &other ); 383 #endif 384 }; 385 386 ///@endcond 387 388 #endif //QGSABSTRACTREPORTSECTION_H 389