KD Reports API Documentation  2.2
KDReportsXmlParser.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** This file is part of the KD Reports library.
4 **
5 ** SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
6 **
7 ** SPDX-License-Identifier: MIT
8 **
9 ****************************************************************************/
10 
12 #include "KDReportsCell.h"
13 #include "KDReportsChartElement.h"
14 #include "KDReportsHLineElement.h"
15 #include "KDReportsHeader_p.h"
16 #include "KDReportsHtmlElement.h"
17 #include "KDReportsImageElement.h"
18 #include "KDReportsMainTable.h"
20 #include "KDReportsReport_p.h"
21 #include "KDReportsTableElement.h"
22 #include "KDReportsTextElement.h"
24 #include "KDReportsXmlHelper.h"
25 #include "KDReportsXmlParser_p.h"
26 
27 #include <QDebug>
28 #include <QDomDocument>
29 #include <QDomElement>
30 #include <QModelIndex>
31 
32 /* The default report builder adds things right away into the textdocument
33  * However for table cells we want to call the Cell methods, which store the stuff
34  * until the table is added to the report.
35  */
36 class CellReportBuilder : public KDReports::ReportBuilder
37 {
38 public:
39  CellReportBuilder(KDReports::Cell &cell, REPORTBUILDER_CTOR_ARGDEFS)
41  , m_cell(cell)
42  {
43  }
44 
45  /*reimp*/ void addInlineElementPublic(const KDReports::Element &element) override
46  {
47  m_cell.addInlineElement(element);
48  }
49  /*reimp*/ void addBlockElementPublic(const KDReports::Element &element, Qt::AlignmentFlag horizontalAlignment, const QColor &color = QColor()) override
50  {
51  Q_UNUSED(color);
52  m_cell.addElement(element, horizontalAlignment);
53  }
54  /*reimp*/ void addVariablePublic(KDReports::VariableType variable) override
55  {
56  m_cell.addVariable(variable);
57  }
58  /*reimp*/ void addVerticalSpacingPublic(qreal space) override
59  {
60  m_cell.addVerticalSpacing(space);
61  }
62 
63 private:
64  KDReports::Cell &m_cell;
65 };
66 
67 bool KDReports::XmlParser::parseTableContents(KDReports::TableElement &table, const QDomNode &tableNode, KDReports::ReportBuilder &builder, bool inHeader, bool inFooter)
68 {
69  // Loop over elements
70  for (QDomElement element = tableNode.firstChildElement(); !element.isNull(); element = element.nextSiblingElement()) {
71  if (testForErrorAndFillErrorDetails())
72  return false;
73 
74  const QString name = element.tagName();
75  if (name == QLatin1String("cell")) {
76  const int row = element.attribute(QStringLiteral("row")).toInt();
77  const int column = element.attribute(QStringLiteral("column")).toInt();
78  const int rowSpan = element.attribute(QStringLiteral("rowspan"), QStringLiteral("1")).toInt();
79  const int colSpan = element.attribute(QStringLiteral("colspan"), QStringLiteral("1")).toInt();
80  KDReports::Cell &cell = table.cell(row, column);
81  cell.setRowSpan(rowSpan);
82  cell.setColumnSpan(colSpan);
83  const QColor bgColor = KDReports::XmlHelper::readBackground(element);
84  if (bgColor.isValid())
85  cell.setBackground(bgColor);
86  CellReportBuilder cellReportBuilder(cell, builder.contentDocumentData(), builder.contentDocumentCursor(), builder.report());
87  cellReportBuilder.copyStateFrom(builder);
88 
89  if (m_xmlElementHandler && !m_xmlElementHandler->startCell(cell, element))
90  continue;
91 
92  if (!processNode(element, &cellReportBuilder, inHeader, inFooter))
93  return false;
94 
95  if (m_xmlElementHandler && !m_xmlElementHandler->endCell(cell, element))
96  continue;
97  }
98  }
99 
100  if (testForErrorAndFillErrorDetails())
101  return false;
102 
103  return true;
104 }
105 
106 void KDReports::XmlParser::parseCommonTableAttributes(KDReports::AbstractTableElement &tableElement, QDomElement &element)
107 {
108  const QColor bgColor = KDReports::XmlHelper::readBackground(element);
109  if (bgColor.isValid())
110  tableElement.setBackground(bgColor);
111  if (element.hasAttribute(QStringLiteral("border")))
112  tableElement.setBorder(element.attribute(QStringLiteral("border")).toDouble());
113  if (element.hasAttribute(QStringLiteral("width"))) {
114  QString widthStr = element.attribute(QStringLiteral("width"));
115  if (widthStr.endsWith(QLatin1Char('%'))) {
116  widthStr.truncate(widthStr.length() - 1);
117  tableElement.setWidth(widthStr.toInt(), KDReports::Percent);
118  } else {
119  tableElement.setWidth(widthStr.toInt());
120  }
121  }
122 }
123 
124 static QFont parseFontAttributes(const QDomElement &element)
125 {
126  QFont font;
127  if (element.hasAttribute(QStringLiteral("pointsize"))) {
128  const int pointSize = element.attribute(QStringLiteral("pointsize")).toInt();
129  if (pointSize)
130  font.setPointSize(pointSize);
131  }
132  if (element.hasAttribute(QStringLiteral("font"))) {
133  font.setFamily(element.attribute(QStringLiteral("font")));
134  }
135  return font;
136 }
137 
138 static void parseHeaderFooterAttribute(KDReports::Header &header, const QDomElement &element)
139 {
140  if (element.hasAttribute(QStringLiteral("font")) || element.hasAttribute(QStringLiteral("pointsize"))) {
141  const QFont font = parseFontAttributes(element);
142  header.setDefaultFont(font);
143  }
144 }
145 
147 {
148  // Top-level element should be <report>
149  QDomElement docElement = doc.documentElement();
150  if (docElement.tagName() != QLatin1String("report")) {
151  error(QObject::tr("Expected \"<report>\" as the topmost element, but found \"<%1>\"").arg(docElement.tagName()));
152  return false;
153  }
154 
155  // Support for default page orientation
156  if (docElement.hasAttribute(QStringLiteral("orientation"))) {
157  const QString orientation = docElement.attribute(QStringLiteral("orientation"));
158  if (orientation == QLatin1String("landscape"))
159  m_report->setPageOrientation(QPageLayout::Landscape);
160  else if (orientation == QLatin1String("portrait"))
161  m_report->setPageOrientation(QPageLayout::Portrait);
162  }
163 
164  // Support for margins
165  double marginTop = 20.0; // defaults are duplicated in KDReportsReport.cpp
166  if (docElement.hasAttribute(QStringLiteral("margin-top")))
167  marginTop = docElement.attribute(QStringLiteral("margin-top")).toDouble();
168  double marginLeft = 20.0;
169  if (docElement.hasAttribute(QStringLiteral("margin-left")))
170  marginLeft = docElement.attribute(QStringLiteral("margin-left")).toDouble();
171  double marginBottom = 20.0;
172  if (docElement.hasAttribute(QStringLiteral("margin-bottom")))
173  marginBottom = docElement.attribute(QStringLiteral("margin-bottom")).toDouble();
174  double marginRight = 20.0;
175  if (docElement.hasAttribute(QStringLiteral("margin-right")))
176  marginRight = docElement.attribute(QStringLiteral("margin-right")).toDouble();
177  m_report->setMargins(marginTop, marginLeft, marginBottom, marginRight);
178 
179  if (docElement.hasAttribute(QStringLiteral("header-body-spacing")))
180  m_report->setHeaderBodySpacing(docElement.attribute(QStringLiteral("header-body-spacing")).toDouble());
181  if (docElement.hasAttribute(QStringLiteral("footer-body-spacing")))
182  m_report->setFooterBodySpacing(docElement.attribute(QStringLiteral("footer-body-spacing")).toDouble());
183 
184  // Support for default font
185  if (docElement.hasAttribute(QStringLiteral("font")) || docElement.hasAttribute(QStringLiteral("pointsize"))) {
186  const QFont font = parseFontAttributes(docElement);
187  m_report->setDefaultFont(font);
188  }
189 
190  if (m_xmlElementHandler && !m_xmlElementHandler->startReport(*m_report, docElement)) {
191  if (m_errorDetails)
192  *m_errorDetails = m_xmlElementHandler->errorDetails();
193 
194  return false;
195  }
196 
197  if (!processNode(docElement, builder, false, false))
198  return false;
199 
200  if (m_xmlElementHandler)
201  m_xmlElementHandler->endReport(*m_report, docElement);
202 
203  if (testForErrorAndFillErrorDetails())
204  return false;
205 
206  return true;
207 }
208 
209 void KDReports::XmlParser::addElement(KDReports::Element &reportElement, KDReports::ReportBuilder *builder, const QDomElement &element)
210 {
211  if (!builder) {
212  error(QObject::tr("<%1> is only supported in WordProcessing mode").arg(element.tagName()));
213  return;
214  }
215  if (element.hasAttribute(QStringLiteral("inline"))) {
216  builder->addInlineElementPublic(reportElement);
217  } else {
218  Qt::AlignmentFlag alignment = Qt::AlignLeft;
219  if (element.hasAttribute(QStringLiteral("alignment")))
220  alignment = KDReports::XmlHelper::stringToAlignment(element.attribute(QStringLiteral("alignment")));
221  builder->addBlockElementPublic(reportElement, alignment);
222  }
223 }
224 
225 bool KDReports::XmlParser::processNode(const QDomNode &node, KDReports::ReportBuilder *builder, bool inHeader, bool inFooter)
226 {
227  // Loop over elements
228  for (QDomElement element = node.firstChildElement(); !element.isNull(); element = element.nextSiblingElement()) {
229 
230  if (testForErrorAndFillErrorDetails())
231  return false;
232 
233  const QString name = element.tagName();
234  if (name == QLatin1String("text")) {
235  // Handle <text> element
236  KDReports::TextElement textElement;
237  QString id;
238  const QString text = extractText(element, &id, m_report->d->m_currentModel, m_report->d->m_currentRow);
239  textElement.setText(text);
240  textElement.setId(id);
241  const QColor bgColor = KDReports::XmlHelper::readBackground(element);
242  if (bgColor.isValid())
243  textElement.setBackground(bgColor);
244  if (element.hasAttribute(QStringLiteral("pointsize"))) {
245  const int pointSize = element.attribute(QStringLiteral("pointsize")).toInt();
246  if (pointSize)
247  textElement.setPointSize(pointSize);
248  }
249  if (element.hasAttribute(QStringLiteral("color"))) {
250  const QString name = element.attribute(QStringLiteral("color"));
251  textElement.setTextColor(QColor(name));
252  }
253  if (element.hasAttribute(QStringLiteral("font"))) {
254  textElement.setFontFamily(element.attribute(QStringLiteral("font")));
255  }
256  if (element.hasAttribute(QStringLiteral("bold"))) {
257  bool bold = false;
258  if (element.attribute(QStringLiteral("bold")) == QLatin1String("true"))
259  bold = true;
260  textElement.setBold(bold);
261  }
262  if (element.hasAttribute(QStringLiteral("italic"))) {
263  bool italic = false;
264  if (element.attribute(QStringLiteral("italic")) == QLatin1String("true"))
265  italic = true;
266  textElement.setItalic(italic);
267  }
268  if (element.hasAttribute(QStringLiteral("strikeout"))) {
269  bool strikeOut = false;
270  if (element.attribute(QStringLiteral("strikeout")) == QLatin1String("true"))
271  strikeOut = true;
272  textElement.setStrikeOut(strikeOut);
273  }
274  if (element.hasAttribute(QStringLiteral("underline"))) {
275  bool underline = false;
276  if (element.attribute(QStringLiteral("underline")) == QLatin1String("true"))
277  underline = true;
278  textElement.setUnderline(underline);
279  }
280 
281  const QString oldId = textElement.id();
282 
283  if (m_xmlElementHandler && !m_xmlElementHandler->textElement(textElement, element))
284  continue;
285 
286  if (textElement.id() != oldId) {
287  // The handler modified the text element's id, look up the value again.
288  const QHash<QString, QString>::const_iterator it = m_textValues.constFind(textElement.id());
289  if (it != m_textValues.constEnd()) {
290  textElement.setText(*it);
291  }
292  }
293 
294  if (!builder) {
295  error(QObject::tr("<text> is only supported in WordProcessing mode"));
296  } else {
297  if (element.hasAttribute(QStringLiteral("inline"))) {
298  builder->addInlineElementPublic(textElement);
299  } else {
300  Qt::AlignmentFlag alignment = Qt::AlignLeft;
301  if (element.hasAttribute(QStringLiteral("alignment")))
302  alignment = KDReports::XmlHelper::stringToAlignment(element.attribute(QStringLiteral("alignment")));
303  const QColor bgColor = KDReports::XmlHelper::readColor(element, "paragraph-background");
304  builder->addBlockElementPublic(textElement, alignment, bgColor);
305  }
306  }
307 
308  } else if (name == QLatin1String("html")) {
309  // Handle <html> element
310  KDReports::HtmlElement htmlElement;
311  QString id;
312  const QString text = extractText(element, &id);
313  htmlElement.setHtml(text);
314  htmlElement.setId(id);
315  QColor bgColor = KDReports::XmlHelper::readBackground(element);
316  if (bgColor.isValid())
317  htmlElement.setBackground(bgColor);
318 
319  const QString oldId = htmlElement.id();
320 
321  if (m_xmlElementHandler && !m_xmlElementHandler->htmlElement(htmlElement, element))
322  continue;
323 
324  if (htmlElement.id() != oldId) {
325  // The handler modified the text element's id, look up the value again.
326  const QHash<QString, QString>::const_iterator it = m_textValues.constFind(htmlElement.id());
327  if (it != m_textValues.constEnd()) {
328  htmlElement.setHtml(*it);
329  }
330  }
331 
332  addElement(htmlElement, builder, element);
333 
334  } else if (name == QLatin1String("tabs")) {
335 
336  if (!builder) {
337  error(QObject::tr("<tabs> is only supported in WordProcessing mode"));
338  } else {
339  parseTabs(builder, element);
340  }
341 
342  } else if (name == QLatin1String("paragraph-margins")) {
343 
344  if (!builder) {
345  error(QObject::tr("<paragraph-margins> is only supported in WordProcessing mode"));
346  } else {
347  parseParagraphMargins(builder, element);
348  }
349 
350  } else if (name == QLatin1String("hr")) {
351  // Handle <hr> element
352  KDReports::HtmlElement htmlElement;
353  htmlElement.setHtml(QStringLiteral("<hr>"));
354  if (m_xmlElementHandler && !m_xmlElementHandler->htmlElement(htmlElement, element))
355  continue;
356 
357  addElement(htmlElement, builder, element);
358 
359  } else if (name == QLatin1String("vspace")) {
360  // Handle <vspace> element
361  if (!element.hasAttribute(QStringLiteral("size")))
362  continue; // size attribute is mandatory for VSpace
363  int size = element.attribute(QStringLiteral("size")).toInt();
364  if (!builder) {
365  error(QObject::tr("<vspace> is only supported in WordProcessing mode"));
366  } else {
367  if (builder != m_report->d->builder()) {
368  error(QObject::tr("<vspace> not allowed in headers, footers, or table cells"));
369  return false;
370  }
371  }
372  if (m_xmlElementHandler && !m_xmlElementHandler->vspace(size, element))
373  continue;
374  m_report->addVerticalSpacing(size);
375  } else if (name == QLatin1String("table")) {
376  // Handle <table> element
377  const QString model = element.attribute(QStringLiteral("model"));
378  if (model.isEmpty()) {
379  if (!builder) {
380  error(QObject::tr("<table> without a model is only supported in WordProcessing mode"));
381  continue;
382  }
383  KDReports::TableElement tableElement;
384  const int headerRowCount = element.attribute(QStringLiteral("headerRowCount")).toInt(); // default 0
385  tableElement.setHeaderRowCount(headerRowCount);
386  if (element.hasAttribute(QStringLiteral("cellpadding")))
387  tableElement.setPadding(element.attribute(QStringLiteral("cellpadding")).toInt());
388  parseCommonTableAttributes(tableElement, element);
389 
390  if (m_xmlElementHandler && !m_xmlElementHandler->startTableElement(tableElement, element))
391  continue;
392 
393  if (!parseTableContents(tableElement, element, *builder, inHeader, inFooter))
394  return false;
395 
396  if (m_xmlElementHandler && !m_xmlElementHandler->endTableElement(tableElement, element))
397  continue;
398 
399  addElement(tableElement, builder, element);
400 
401  } else {
402  KDReports::AutoTableElement tableElement(model);
403  if (element.attribute(QStringLiteral("verticalHeaderVisible")) == QLatin1String("false"))
404  tableElement.setVerticalHeaderVisible(false);
405  if (element.attribute(QStringLiteral("horizontalHeaderVisible")) == QLatin1String("false"))
406  tableElement.setHorizontalHeaderVisible(false);
407  QColor headerBgColor = KDReports::XmlHelper::readColor(element, "header-background");
408  if (headerBgColor.isValid())
409  tableElement.setHeaderBackground(headerBgColor);
410  parseCommonTableAttributes(tableElement, element);
411  if (m_xmlElementHandler && !m_xmlElementHandler->autoTableElement(tableElement, element))
412  continue;
413 
414  if (m_report->reportMode() == Report::SpreadSheet) {
415  m_report->mainTable()->setAutoTableElement(tableElement);
416  } else {
417  addElement(tableElement, builder, element);
418  }
419  }
420  } else if (name == QLatin1String("chart")) {
421  // Handle <chart> element
422 
423  KDReports::ChartElement chartElement(element.attribute(QStringLiteral("model")));
424  QColor bgColor = KDReports::XmlHelper::readBackground(element);
425  if (bgColor.isValid())
426  chartElement.setBackground(bgColor);
427  int width = 100;
428  int height = 100;
429  Unit unit = Millimeters;
430  if (element.hasAttribute(QStringLiteral("width"))) {
431  QString str = element.attribute(QStringLiteral("width"));
432  if (str.endsWith(QLatin1Char('%'))) {
433  str.chop(1);
434  unit = Percent;
435  }
436  width = str.toInt();
437  }
438  if (element.hasAttribute(QStringLiteral("height"))) {
439  QString str = element.attribute(QStringLiteral("height"));
440  if (str.endsWith(QLatin1Char('%'))) {
441  str.chop(1);
442  unit = Percent;
443  }
444  height = str.toInt();
445  }
446  chartElement.setSize(width, height, unit);
447 
448  if (m_xmlElementHandler && !m_xmlElementHandler->chartElement(chartElement, element))
449  continue;
450 
451  addElement(chartElement, builder, element);
452 
453  } else if (name == QLatin1String("image")) {
454  // Handle <image> element
455 
456  QString id;
457  QImage image = extractImage(element, &id);
458  KDReports::ImageElement imageElement(image);
459  imageElement.setId(id);
460  if (element.hasAttribute(QStringLiteral("width"))) {
461  QString widthStr = element.attribute(QStringLiteral("width"));
462  if (widthStr.endsWith(QLatin1Char('%'))) {
463  widthStr.truncate(widthStr.length() - 1);
464  imageElement.setWidth(widthStr.toInt(), KDReports::Percent);
465  } else {
466  imageElement.setWidth(widthStr.toInt());
467  }
468  } else if (element.hasAttribute(QStringLiteral("height"))) { // mutually exclusive with "width"!
469  QString heightStr = element.attribute(QStringLiteral("height"));
470  if (heightStr.endsWith(QLatin1Char('%'))) {
471  heightStr.truncate(heightStr.length() - 1);
472  imageElement.setHeight(heightStr.toInt(), KDReports::Percent);
473  } else {
474  imageElement.setHeight(heightStr.toInt());
475  }
476  } else if (element.hasAttribute(QStringLiteral("fitToPage"))) {
477  imageElement.setFitToPage();
478  }
479 
480  if (m_xmlElementHandler && !m_xmlElementHandler->imageElement(imageElement, element))
481  continue;
482 
483  addElement(imageElement, builder, element);
484 
485  } else if (name == QLatin1String("header")) {
486  const KDReports::HeaderLocations loc = KDReports::XmlHelper::parseHeaderLocation(element.attribute(QStringLiteral("location")));
487  KDReports::Header &header = m_report->header(loc);
488  parseHeaderFooterAttribute(header, element);
489  if (m_xmlElementHandler && !m_xmlElementHandler->startHeader(header, element))
490  continue;
491  if (!processNode(element, &header.d->m_builder, true, false))
492  return false;
493  if (m_xmlElementHandler)
494  m_xmlElementHandler->endHeader(header, element);
495  } else if (name == QLatin1String("footer")) {
496  const KDReports::HeaderLocations loc = KDReports::XmlHelper::parseHeaderLocation(element.attribute(QStringLiteral("location")));
497  KDReports::Footer &footer = m_report->footer(loc);
498  parseHeaderFooterAttribute(footer, element);
499  if (m_xmlElementHandler && !m_xmlElementHandler->startFooter(footer, element))
500  continue;
501  if (!processNode(element, &footer.d->m_builder, false, true))
502  return false;
503  if (m_xmlElementHandler)
504  m_xmlElementHandler->endFooter(footer, element);
505  } else if (name == QLatin1String("variable")) {
506  if (!inHeader && !inFooter) {
507  error(QObject::tr("<variable> tags only allowed in headers and footers"));
508  return false;
509  }
510  if (!element.hasAttribute(QStringLiteral("type"))) {
511  error(QObject::tr("<variable> tags must have a 'type' attribute"));
512  return false;
513  }
514  Q_ASSERT(builder);
515  if (builder) {
516  const QString type = element.attribute(QStringLiteral("type"));
518  if (m_xmlElementHandler && !m_xmlElementHandler->variable(vt, element))
519  continue;
520  builder->addVariablePublic(vt);
521  }
522  } else if (name == QLatin1String("page-break")) {
523  if (m_xmlElementHandler && !m_xmlElementHandler->pageBreak(element))
524  continue;
525  m_report->addPageBreak();
526  } else if (name == QLatin1String("ifdef")) {
527  if (element.hasAttribute(QStringLiteral("id"))) {
528  const QString id = element.attribute(QStringLiteral("id"));
529  const bool skip = m_textValues.value(id).isEmpty();
530  if (!skip) {
531  if (!processNode(element, builder, inHeader, inFooter))
532  return false;
533  }
534  }
535  } else if (name == QLatin1String("custom")) {
536  if (m_xmlElementHandler)
537  m_xmlElementHandler->customElement(element);
538  } else if (name == QLatin1String("hline")) {
539  KDReports::HLineElement hLineElement;
540 
541  if (element.hasAttribute(QStringLiteral("thickness"))) {
542  const double thickness = element.attribute(QStringLiteral("thickness")).toDouble();
543  hLineElement.setThickness(thickness);
544  }
545 
546  if (element.hasAttribute(QStringLiteral("color"))) {
547  const QColor color = KDReports::XmlHelper::readColor(element, "color");
548  hLineElement.setColor(color);
549  }
550 
551  if (element.hasAttribute(QStringLiteral("margin"))) {
552  const int margin = element.attribute(QStringLiteral("margin")).toInt();
553  hLineElement.setMargin(margin);
554  }
555 
556  if (m_xmlElementHandler && !m_xmlElementHandler->hLineElement(hLineElement, element))
557  continue;
558 
559  addElement(hLineElement, builder, element);
560  } else {
561  error(QObject::tr("KDReports::Report::loadFromXML(): Unknown element %1").arg(name));
562  }
563  }
564 
565  if (testForErrorAndFillErrorDetails())
566  return false;
567 
568  return true;
569 }
570 
571 void KDReports::XmlParser::parseTabs(KDReports::ReportBuilder *builder, const QDomElement &tabsElement)
572 {
574  for (QDomElement element = tabsElement.firstChildElement(); !element.isNull(); element = element.nextSiblingElement()) {
575  if (element.tagName() == QLatin1String("tab")) {
576 
577  QTextOption::Tab tab;
578  const QString tabType = element.attribute(QStringLiteral("type"));
579  if (tabType == QLatin1String("right")) {
580  tab.type = QTextOption::RightTab;
581  } else if (tabType == QLatin1String("center")) {
582  tab.type = QTextOption::CenterTab;
583  } else if (tabType == QLatin1String("delimiter")) {
584  tab.type = QTextOption::DelimiterTab;
585  } else {
586  tab.type = QTextOption::LeftTab;
587  }
588 
589  const QString delimiter = element.attribute(QStringLiteral("delimiter"));
590  if (!delimiter.isEmpty())
591  tab.delimiter = delimiter.at(0);
592 
593  const QString strPos = element.attribute(QStringLiteral("position"));
594  double pos = -1;
595  if (strPos == QLatin1String("page")) {
596  tab.delimiter = QChar::fromLatin1('P');
597  } else {
598  pos = strPos.toDouble();
599  }
600  tab.position = pos;
601  tabs.append(tab);
602  }
603  }
604  if (!m_xmlElementHandler || m_xmlElementHandler->tabs(tabs, tabsElement))
605  builder->setTabPositions(tabs);
606 }
607 
608 void KDReports::XmlParser::parseParagraphMargins(KDReports::ReportBuilder *builder, const QDomElement &element)
609 {
610  qreal left = element.attribute(QStringLiteral("left")).toDouble();
611  qreal top = element.attribute(QStringLiteral("top")).toDouble();
612  qreal right = element.attribute(QStringLiteral("right")).toDouble();
613  qreal bottom = element.attribute(QStringLiteral("bottom")).toDouble();
614  if (!m_xmlElementHandler || m_xmlElementHandler->paragraphMargin(left, top, right, bottom, element))
615  builder->setParagraphMargins(left, top, right, bottom);
616 }
617 
618 QImage KDReports::XmlParser::extractImage(const QDomElement &element, QString *pId) const
619 {
620  if (element.hasAttribute(QStringLiteral("id"))) {
621  const QString id = element.attribute(QStringLiteral("id"));
622  *pId = id;
623  const QHash<QString, QImage>::const_iterator it = m_imageValues.find(id);
624  if (it != m_imageValues.end()) {
625  return *it;
626  }
627  }
628 
629  QImage image;
630  if (element.hasAttribute(QStringLiteral("file"))) {
631  const QString fileName = element.attribute(QStringLiteral("file"));
632  if (!image.load(fileName)) {
633  qWarning("Image not found or invalid: %s", qPrintable(fileName));
634  }
635  }
636  return image;
637 }
638 
639 QString KDReports::XmlParser::extractText(const QDomElement &element, QString *pId, const QAbstractItemModel *currentModel, int currentRow) const
640 {
641  if (element.hasAttribute(QStringLiteral("id"))) {
642  const QString id = element.attribute(QStringLiteral("id"));
643  *pId = id;
644  const QHash<QString, QString>::const_iterator it = m_textValues.find(id);
645  if (it != m_textValues.end()) {
646  return *it;
647  }
648  } else if (element.hasAttribute(QStringLiteral("model"))) {
649  const QString modelName = element.attribute(QStringLiteral("model"));
650  QAbstractItemModel *model = KDReports::modelForKey(modelName);
651  if (model) {
652  int row;
653  if (model == currentModel && currentRow > -1) {
654  row = currentRow;
655  } else {
656  row = element.attribute(QStringLiteral("row")).toInt();
657  }
658  const int column = element.attribute(QStringLiteral("column")).toInt();
659  const QModelIndex index = model->index(row, column);
660  return model->data(index).toString();
661  }
662  }
663 
664  return element.text();
665 }
666 
667 bool KDReports::XmlParser::testForErrorAndFillErrorDetails()
668 {
669  if (m_xmlElementHandler && m_xmlElementHandler->errorDetails().hasError()) {
670  if (m_errorDetails)
671  *m_errorDetails = m_xmlElementHandler->errorDetails();
672  return true;
673  }
674  return false;
675 }
676 
677 void KDReports::XmlParser::error(const QString &errorString)
678 {
679  if (m_errorDetails)
680  m_errorDetails->setDriverMessage(errorString);
681  else
682  qWarning("%s", qPrintable(errorString));
683 }
#define REPORTBUILDER_CTOR_ARGNAMES
#define REPORTBUILDER_CTOR_ARGDEFS
static QFont parseFontAttributes(const QDomElement &element)
static void parseHeaderFooterAttribute(KDReports::Header &header, const QDomElement &element)
void setWidth(qreal width, Unit unit=Millimeters)
void setColumnSpan(int columnSpan)
void setRowSpan(int rowSpan)
void setBackground(const QBrush &brush)
void setColor(const QColor &color)
void setDefaultFont(const QFont &font)
void setHtml(const QString &html)
void setId(const QString &id)
ReportBuilder(KDReports::TextDocumentData &contentDocument, const QTextCursor &cursor, Report *report)
void setTabPositions(const QList< QTextOption::Tab > &tabs)
virtual void addVerticalSpacingPublic(qreal space)
virtual void addBlockElementPublic(const Element &element, Qt::AlignmentFlag horizontalAlignment, const QColor &backgroundColor=QColor())
TextDocumentData & contentDocumentData()
virtual void addVariablePublic(KDReports::VariableType variable)
virtual void addInlineElementPublic(const Element &element)
void setParagraphMargins(qreal left, qreal top, qreal right, qreal bottom)
Cell & cell(int row, int column)
void setTextColor(const QColor &color)
void setFontFamily(const QString &family)
Set font attribute: family.
void setUnderline(bool underline)
Set font attribute: underline.
void setStrikeOut(bool strikeout)
Set font attribute: strike out.
void setItalic(bool italic)
Set font attribute: italic.
void setText(const QString &text)
void setPointSize(qreal size)
Set font attribute: size in points. Can be integer or decimal.
void setBold(bool bold)
Set font attribute: bold.
void setId(const QString &id)
virtual bool startCell(KDReports::Cell &cell, QDomElement &xmlElement)
virtual bool endCell(KDReports::Cell &cell, QDomElement &xmlElement)
static KDReports::VariableType stringToVariableType(const QString &type)
static Qt::AlignmentFlag stringToAlignment(const QString &str)
static QColor readBackground(const QDomElement &element)
static QColor readColor(const QDomElement &element, const char *attributeName)
static KDReports::HeaderLocations parseHeaderLocation(const QString &xmlAttr)
bool processDocument(const QDomDocument &document, KDReports::ReportBuilder *builder)
@ Percent
Percentage of the text width, i.e. the page width minus margins.
Definition: KDReportsUnit.h:22
@ Millimeters
Millimeters (the default)
Definition: KDReportsUnit.h:21
QAbstractItemModel * modelForKey(const QString &key)

© Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
https://www.kdab.com/development-resources/qt-tools/kd-reports/
Generated by doxygen 1.9.1