1 /* This file is part of the KDE project
2  * Copyright (C) 2007-2008 by Adam Pigg (adam@piggz.co.uk)
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "KReportDocument.h"
19 #include "KReportUnit.h"
20 #include "KReportDetailSectionData.h"
21 #include "KReportItemBase.h"
22 #include "KReportUtils_p.h"
23 #include "KReportPageSize.h"
24 
25 #include <QDomElement>
26 #include <QApplication>
27 #include "kreport_debug.h"
28 
29 class Q_DECL_HIDDEN KReportDocument::Private
30 {
31 public:
32     bool valid;
33     QString title;
34     QString name;
35     QString query;
36 #ifdef KREPORT_SCRIPTING
37     QString script;
38     QString interpreter;
39 #endif
40     bool externalData;
41     KReportPrivate::PageLayout pageLayout;
42     QString pageSize;
43     QString labelType;
44 
45     KReportSectionData * pageHeaderFirst = nullptr;
46     KReportSectionData * pageHeaderOdd = nullptr;
47     KReportSectionData * pageHeaderEven = nullptr;
48     KReportSectionData * pageHeaderLast = nullptr;
49     KReportSectionData * pageHeaderAny = nullptr;
50 
51     KReportSectionData * reportHeader = nullptr;
52     KReportSectionData * reportFooter = nullptr;
53 
54     KReportSectionData * pageFooterFirst = nullptr;
55     KReportSectionData * pageFooterOdd = nullptr;
56     KReportSectionData * pageFooterEven = nullptr;
57     KReportSectionData * pageFooterLast = nullptr;
58     KReportSectionData * pageFooterAny = nullptr;
59 
60     KReportDetailSectionData* detailSection = nullptr;
61 };
62 
KReportDocument(QObject * parent)63 KReportDocument::KReportDocument(QObject *parent)
64         : QObject(parent),
65         d(new Private)
66 {
67     d->valid = true;
68 }
69 
KReportDocument(const QDomElement & elemSource,QObject * parent)70 KReportDocument::KReportDocument(const QDomElement & elemSource, QObject *parent)
71         : QObject(parent),
72         d(new Private)
73 {
74     d->valid = false;
75 
76     if (elemSource.tagName() != QLatin1String("report:content")) {
77         kreportWarning() << "QDomElement is not <report:content> tag"
78                    << elemSource.text();
79         return;
80     }
81 
82     QDomNodeList sections = elemSource.childNodes();
83     for (int nodeCounter = 0; nodeCounter < sections.count(); nodeCounter++) {
84         QDomElement elemThis = sections.item(nodeCounter).toElement();
85         if (elemThis.tagName() == QLatin1String("report:title")) {
86             d->title = elemThis.text();
87 #ifdef KREPORT_SCRIPTING
88         } else if (elemThis.tagName() == QLatin1String("report:script")) {
89             d->script = elemThis.text();
90             d->interpreter = elemThis.attribute(QLatin1String("report:script-interpreter"));
91 #endif
92         } else if (elemThis.tagName() == QLatin1String("report:page-style")) {
93             QString pagetype = elemThis.firstChild().nodeValue();
94 
95             //Full page mode is required to allow margins to be set to whatever the user has specified
96             d->pageLayout.setMode(QPageLayout::FullPageMode);
97 
98             if (pagetype == QLatin1String("predefined")) {
99                 setPageSize(elemThis.attribute(QLatin1String("report:page-size"), QLatin1String("A4")));
100                 d->pageLayout.setPageSize(QPageSize(KReportPageSize::pageSize(pageSize())));
101             } else if (pagetype == QLatin1String("custom")) {
102                 kreportDebug() << "Setting custom page size in document to " << KReportUnit::parseValue(elemThis.attribute(QLatin1String("report:custom-page-width"), QLatin1String("5.0cm"))) << KReportUnit::parseValue(elemThis.attribute(QLatin1String("report:custom-page-height"), QLatin1String("5.0cm"))) ;
103                 QPageSize custom(QSize(KReportUnit::parseValue(elemThis.attribute(QLatin1String("report:custom-page-width"), QLatin1String("5.0cm")))  , KReportUnit::parseValue(elemThis.attribute(QLatin1String("report:custom-page-height"), QLatin1String("5.0cm"))) ), QString(), QPageSize::ExactMatch);
104 
105                 d->pageLayout.setPageSize(custom);
106             } else if (pagetype == QLatin1String("label")) {
107                 setLabelType(elemThis.firstChild().nodeValue());
108             }
109             //! @todo add config for default margins or add within templates support
110             d->pageLayout.setUnits(QPageLayout::Point);
111             d->pageLayout.setLeftMargin(KReportUnit::parseValue(elemThis.attribute(
112                 QLatin1String("fo:margin-left"), DEFAULT_PAGE_MARGIN_STRING)));
113             d->pageLayout.setRightMargin(KReportUnit::parseValue(elemThis.attribute(
114                 QLatin1String("fo:margin-right"), DEFAULT_PAGE_MARGIN_STRING)));
115             d->pageLayout.setTopMargin(KReportUnit::parseValue(elemThis.attribute(
116                 QLatin1String("fo:margin-top"), DEFAULT_PAGE_MARGIN_STRING)));
117             d->pageLayout.setBottomMargin(KReportUnit::parseValue(elemThis.attribute(
118                 QLatin1String("fo:margin-bottom"), DEFAULT_PAGE_MARGIN_STRING)));
119             d->pageLayout.setOrientation(
120                 elemThis.attribute(QLatin1String("report:print-orientation"),
121                                    QLatin1String("portrait"))
122                         == QLatin1String("portrait")
123                     ? QPageLayout::Portrait
124                     : QPageLayout::Landscape);
125         } else if (elemThis.tagName() == QLatin1String("report:body")) {
126             QDomNodeList sectionlist = elemThis.childNodes();
127             QDomNode sec;
128 
129             for (int s = 0; s < sectionlist.count(); ++s) {
130                 sec = sectionlist.item(s);
131                 if (sec.isElement()) {
132                     QString sn = sec.nodeName().toLower();
133                     //kreportDebug() << sn;
134                     if (sn == QLatin1String("report:section")) {
135                         KReportSectionData * sd = new KReportSectionData(sec.toElement(), this);
136                         if (!sd->isValid()) {
137                             kreportDebug() << "Invalid section";
138                             delete sd;
139                         } else {
140                             //kreportDebug() << "Adding section of type " << sd->type();
141                             switch (sd->type()) {
142                             case KReportSectionData::Type::PageHeaderFirst:
143                                 d->pageHeaderFirst = sd;
144                                 break;
145                             case KReportSectionData::Type::PageHeaderOdd:
146                                 d->pageHeaderOdd = sd;
147                                 break;
148                             case KReportSectionData::Type::PageHeaderEven:
149                                 d->pageHeaderEven = sd;
150                                 break;
151                             case KReportSectionData::Type::PageHeaderLast:
152                                 d->pageHeaderLast = sd;
153                                 break;
154                             case KReportSectionData::Type::PageHeaderAny:
155                                 d->pageHeaderAny = sd;
156                                 break;
157                             case KReportSectionData::Type::ReportHeader:
158                                 d->reportHeader = sd;
159                                 break;
160                             case KReportSectionData::Type::ReportFooter:
161                                 d->reportFooter = sd;
162                                 break;
163                             case KReportSectionData::Type::PageFooterFirst:
164                                 d->pageFooterFirst = sd;
165                                 break;
166                             case KReportSectionData::Type::PageFooterOdd:
167                                 d->pageFooterOdd = sd;
168                                 break;
169                             case KReportSectionData::Type::PageFooterEven:
170                                 d->pageFooterEven = sd;
171                                 break;
172                             case KReportSectionData::Type::PageFooterLast:
173                                 d->pageFooterLast = sd;
174                                 break;
175                             case KReportSectionData::Type::PageFooterAny:
176                                 d->pageFooterAny = sd;
177                                 break;
178                             default:
179                                 ;
180                             }
181                         }
182 
183                     } else if (sn == QLatin1String("report:detail")) {
184                         KReportDetailSectionData * dsd = new KReportDetailSectionData(sec.toElement(), this);
185 
186                         if (dsd->isValid()) {
187                             d->detailSection = dsd;
188                         } else {
189                             kreportDebug() << "Invalid detail section";
190                             delete dsd;
191                         }
192                     }
193                 } else {
194                     kreportWarning() << "Encountered an unknown Element: "  << elemThis.tagName();
195                 }
196             }
197         }
198 
199         d->valid = true;
200     }
201 }
202 
~KReportDocument()203 KReportDocument::~KReportDocument()
204 {
205     delete d;
206 }
207 
objects() const208 QList<KReportItemBase*> KReportDocument::objects() const
209 {
210     QList<KReportItemBase*> obs;
211     for (int i = static_cast<int>(KReportSectionData::Type::PageHeaderFirst);
212          i <= static_cast<int>(KReportSectionData::Type::PageFooterAny); i++)
213     {
214         KReportSectionData *sec = section(static_cast<KReportSectionData::Type>(i));
215         if (sec) {
216             obs << sec->objects();
217         }
218     }
219 
220     if (d->detailSection) {
221         //kreportDebug() << "Number of groups: " << m_detailSection->m_groupList.count();
222         foreach(KReportDetailGroupSectionData* g, d->detailSection->groupList) {
223             if (g->groupHeader) {
224                 obs << g->groupHeader->objects();
225             }
226             if (g->groupFooter) {
227                 obs << g->groupFooter->objects();
228             }
229         }
230         if (d->detailSection->detailSection)
231             obs << d->detailSection->detailSection->objects();
232     }
233 
234     /*kreportDebug() << "Object List:";
235     foreach(KReportItemBase* o, obs) {
236         kreportDebug() << o->entityName();
237     }*/
238     return obs;
239 }
240 
object(const QString & n) const241 KReportItemBase* KReportDocument::object(const QString& n) const
242 {
243     QList<KReportItemBase*> obs = objects();
244 
245     foreach(KReportItemBase* o, obs) {
246         if (o->entityName() == n) {
247             return o;
248         }
249     }
250     return nullptr;
251 }
252 
sections() const253 QList<KReportSectionData*> KReportDocument::sections() const
254 {
255     QList<KReportSectionData*> secs;
256     for (int i = static_cast<int>(KReportSectionData::Type::PageHeaderFirst);
257          i <= static_cast<int>(KReportSectionData::Type::PageFooterAny); i++)
258     {
259         KReportSectionData *sec = section(static_cast<KReportSectionData::Type>(i));
260         if (sec) {
261             secs << sec;
262         }
263     }
264 
265     if (d->detailSection) {
266         //kreportDebug() << "Number of groups: " << m_detailSection->m_groupList.count();
267         foreach(KReportDetailGroupSectionData* g, d->detailSection->groupList) {
268             if (g->groupHeader) {
269                 secs << g->groupHeader;
270             }
271             if (g->groupFooter) {
272                 secs << g->groupFooter;
273             }
274         }
275         if (d->detailSection->detailSection)
276             secs << d->detailSection->detailSection;
277     }
278 
279     return secs;
280 }
281 
section(const QString & sn) const282 KReportSectionData* KReportDocument::section(const QString& sn) const
283 {
284     QList<KReportSectionData*> secs = sections();
285 
286     foreach(KReportSectionData *sec, secs) {
287         if (sec->name() == sn) {
288             return sec;
289         }
290     }
291     return nullptr;
292 }
293 
section(KReportSectionData::Type type) const294 KReportSectionData* KReportDocument::section(KReportSectionData::Type type) const
295 {
296     KReportSectionData *sec;
297     switch (type) {
298     case KReportSectionData::Type::PageHeaderAny:
299         sec = d->pageHeaderAny;
300         break;
301     case KReportSectionData::Type::PageHeaderEven:
302         sec = d->pageHeaderEven;
303         break;
304     case KReportSectionData::Type::PageHeaderOdd:
305         sec = d->pageHeaderOdd;
306         break;
307     case KReportSectionData::Type::PageHeaderFirst:
308         sec = d->pageHeaderFirst;
309         break;
310     case KReportSectionData::Type::PageHeaderLast:
311         sec = d->pageHeaderLast;
312         break;
313     case KReportSectionData::Type::PageFooterAny:
314         sec = d->pageFooterAny;
315         break;
316     case KReportSectionData::Type::PageFooterEven:
317         sec = d->pageFooterEven;
318         break;
319     case KReportSectionData::Type::PageFooterOdd:
320         sec = d->pageFooterOdd;
321         break;
322     case KReportSectionData::Type::PageFooterFirst:
323         sec = d->pageFooterFirst;
324         break;
325     case KReportSectionData::Type::PageFooterLast:
326         sec = d->pageFooterLast;
327         break;
328     case KReportSectionData::Type::ReportHeader:
329         sec = d->reportHeader;
330         break;
331     case KReportSectionData::Type::ReportFooter:
332         sec = d->reportFooter;
333         break;
334     default:
335         sec = nullptr;
336     }
337     return sec;
338 }
339 
pageLayout() const340 QPageLayout KReportDocument::pageLayout() const
341 {
342     return d->pageLayout;
343 }
344 
isValid() const345 bool KReportDocument::isValid() const
346 {
347     return d->valid;
348 }
349 
title() const350 QString KReportDocument::title() const
351 {
352     return d->title;
353 }
354 
externalData() const355 bool KReportDocument::externalData() const
356 {
357     return d->externalData;
358 }
359 
360 #ifdef KREPORT_SCRIPTING
script() const361 QString KReportDocument::script() const
362 {
363     return d->script;
364 }
365 
interpreter() const366 QString KReportDocument::interpreter() const
367 {
368     return d->interpreter;
369 }
370 #endif
371 
name() const372 QString KReportDocument::name() const
373 {
374     return d->name;
375 }
376 
setName(const QString & n)377 void KReportDocument::setName(const QString& n)
378 {
379     d->name = n;
380 }
381 
query() const382 QString KReportDocument::query() const
383 {
384     return d->query;
385 }
386 
pageSize()387 QString KReportDocument::pageSize()
388 {
389     return d->pageSize;
390 }
391 
setPageSize(const QString & size)392 void KReportDocument::setPageSize(const QString& size)
393 {
394     d->pageSize = size;
395 }
396 
labelType() const397 QString KReportDocument::labelType() const
398 {
399     return d->labelType;
400 }
401 
setLabelType(const QString & label)402 void KReportDocument::setLabelType(const QString& label)
403 {
404     d->labelType = label;
405 }
406 
detail() const407 KReportDetailSectionData * KReportDocument::detail() const
408 {
409     return d->detailSection;
410 }
411 
412