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 &sectionElement, 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