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

© 2007-2021 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 on Sat Jan 8 2022 02:38:32 for KD Reports API Documentation by doxygen 1.8.17