34 #include <QDomDocument>
35 #include <QDomElement>
36 #include <QModelIndex>
55 m_cell.addElement(element, horizontalAlignment);
61 qWarning(
"Unexpected vspace inside cell!");
71 for (QDomElement element = tableNode.firstChildElement(); !element.isNull(); element = element.nextSiblingElement()) {
72 if (testForErrorAndFillErrorDetails())
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();
85 if (bgColor.isValid())
88 cellReportBuilder.copyStateFrom(builder);
90 if (m_xmlElementHandler && !m_xmlElementHandler->
startCell(cell, element))
93 if (!processNode(element, &cellReportBuilder, inHeader, inFooter))
96 if (m_xmlElementHandler && !m_xmlElementHandler->
endCell(cell, element))
101 if (testForErrorAndFillErrorDetails())
110 if (bgColor.isValid())
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);
120 tableElement.
setWidth(widthStr.toInt());
128 if (element.hasAttribute(QStringLiteral(
"pointsize"))) {
129 const int pointSize = element.attribute(QStringLiteral(
"pointsize")).toInt();
131 font.setPointSize(pointSize);
133 if (element.hasAttribute(QStringLiteral(
"font"))) {
134 font.setFamily(element.attribute(QStringLiteral(
"font")));
141 if (element.hasAttribute(QStringLiteral(
"font")) || element.hasAttribute(QStringLiteral(
"pointsize"))) {
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()));
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);
166 double marginTop = 20.0;
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);
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());
186 if (docElement.hasAttribute(QStringLiteral(
"font")) || docElement.hasAttribute(QStringLiteral(
"pointsize"))) {
188 m_report->setDefaultFont(font);
191 if (m_xmlElementHandler && !m_xmlElementHandler->startReport(*m_report, docElement)) {
193 *m_errorDetails = m_xmlElementHandler->errorDetails();
198 if (!processNode(docElement, builder,
false,
false))
201 if (m_xmlElementHandler)
202 m_xmlElementHandler->endReport(*m_report, docElement);
204 if (testForErrorAndFillErrorDetails())
213 error(QObject::tr(
"<%1> is only supported in WordProcessing mode").arg(element.tagName()));
216 if (element.hasAttribute(QStringLiteral(
"inline"))) {
219 Qt::AlignmentFlag alignment = Qt::AlignLeft;
220 if (element.hasAttribute(QStringLiteral(
"alignment")))
226 bool KDReports::XmlParser::processNode(
const QDomNode &node,
KDReports::ReportBuilder *builder,
bool inHeader,
bool inFooter)
229 for (QDomElement element = node.firstChildElement(); !element.isNull(); element = element.nextSiblingElement()) {
231 if (testForErrorAndFillErrorDetails())
234 const QString name = element.tagName();
235 if (name == QLatin1String(
"text")) {
239 const QString text = extractText(element, &
id, m_report->d->m_currentModel, m_report->d->m_currentRow);
241 textElement.
setId(
id);
243 if (bgColor.isValid())
245 if (element.hasAttribute(QStringLiteral(
"pointsize"))) {
246 const int pointSize = element.attribute(QStringLiteral(
"pointsize")).toInt();
250 if (element.hasAttribute(QStringLiteral(
"color"))) {
251 const QString name = element.attribute(QStringLiteral(
"color"));
254 if (element.hasAttribute(QStringLiteral(
"font"))) {
255 textElement.
setFontFamily(element.attribute(QStringLiteral(
"font")));
257 if (element.hasAttribute(QStringLiteral(
"bold"))) {
259 if (element.attribute(QStringLiteral(
"bold")) == QLatin1String(
"true"))
263 if (element.hasAttribute(QStringLiteral(
"italic"))) {
265 if (element.attribute(QStringLiteral(
"italic")) == QLatin1String(
"true"))
269 if (element.hasAttribute(QStringLiteral(
"strikeout"))) {
270 bool strikeOut =
false;
271 if (element.attribute(QStringLiteral(
"strikeout")) == QLatin1String(
"true"))
275 if (element.hasAttribute(QStringLiteral(
"underline"))) {
276 bool underline =
false;
277 if (element.attribute(QStringLiteral(
"underline")) == QLatin1String(
"true"))
282 const QString oldId = textElement.
id();
284 if (m_xmlElementHandler && !m_xmlElementHandler->textElement(textElement, element))
287 if (textElement.
id() != oldId) {
289 const QHash<QString, QString>::const_iterator it = m_textValues.constFind(textElement.
id());
290 if (it != m_textValues.constEnd()) {
296 error(QObject::tr(
"<text> is only supported in WordProcessing mode"));
298 if (element.hasAttribute(QStringLiteral(
"inline"))) {
301 Qt::AlignmentFlag alignment = Qt::AlignLeft;
302 if (element.hasAttribute(QStringLiteral(
"alignment")))
309 }
else if (name == QLatin1String(
"html")) {
313 const QString text = extractText(element, &
id);
315 htmlElement.
setId(
id);
317 if (bgColor.isValid())
320 const QString oldId = htmlElement.
id();
322 if (m_xmlElementHandler && !m_xmlElementHandler->htmlElement(htmlElement, element))
325 if (htmlElement.
id() != oldId) {
327 const QHash<QString, QString>::const_iterator it = m_textValues.constFind(htmlElement.
id());
328 if (it != m_textValues.constEnd()) {
333 addElement(htmlElement, builder, element);
335 }
else if (name == QLatin1String(
"tabs")) {
338 error(QObject::tr(
"<tabs> is only supported in WordProcessing mode"));
340 parseTabs(builder, element);
343 }
else if (name == QLatin1String(
"paragraph-margins")) {
346 error(QObject::tr(
"<paragraph-margins> is only supported in WordProcessing mode"));
348 parseParagraphMargins(builder, element);
351 }
else if (name == QLatin1String(
"hr")) {
354 htmlElement.
setHtml(QStringLiteral(
"<hr>"));
355 if (m_xmlElementHandler && !m_xmlElementHandler->htmlElement(htmlElement, element))
358 addElement(htmlElement, builder, element);
360 }
else if (name == QLatin1String(
"vspace")) {
362 if (!element.hasAttribute(QStringLiteral(
"size")))
364 int size = element.attribute(QStringLiteral(
"size")).toInt();
366 error(QObject::tr(
"<vspace> is only supported in WordProcessing mode"));
368 if (builder != m_report->d->builder()) {
369 error(QObject::tr(
"<vspace> not allowed in headers, footers, or table cells"));
373 if (m_xmlElementHandler && !m_xmlElementHandler->vspace(size, element))
375 m_report->addVerticalSpacing(size);
376 }
else if (name == QLatin1String(
"table")) {
378 const QString model = element.attribute(QStringLiteral(
"model"));
379 if (model.isEmpty()) {
381 error(QObject::tr(
"<table> without a model is only supported in WordProcessing mode"));
385 const int headerRowCount = element.attribute(QStringLiteral(
"headerRowCount")).toInt();
387 if (element.hasAttribute(QStringLiteral(
"cellpadding")))
388 tableElement.
setPadding(element.attribute(QStringLiteral(
"cellpadding")).toInt());
389 parseCommonTableAttributes(tableElement, element);
391 if (m_xmlElementHandler && !m_xmlElementHandler->startTableElement(tableElement, element))
394 if (!parseTableContents(tableElement, element, *builder, inHeader, inFooter))
397 if (m_xmlElementHandler && !m_xmlElementHandler->endTableElement(tableElement, element))
400 addElement(tableElement, builder, element);
404 if (element.attribute(QStringLiteral(
"verticalHeaderVisible")) == QLatin1String(
"false"))
405 tableElement.setVerticalHeaderVisible(
false);
406 if (element.attribute(QStringLiteral(
"horizontalHeaderVisible")) == QLatin1String(
"false"))
407 tableElement.setHorizontalHeaderVisible(
false);
409 if (headerBgColor.isValid())
410 tableElement.setHeaderBackground(headerBgColor);
411 parseCommonTableAttributes(tableElement, element);
412 if (m_xmlElementHandler && !m_xmlElementHandler->autoTableElement(tableElement, element))
416 m_report->mainTable()->setAutoTableElement(tableElement);
418 addElement(tableElement, builder, element);
421 }
else if (name == QLatin1String(
"chart")) {
426 if (bgColor.isValid())
427 chartElement.setBackground(bgColor);
431 if (element.hasAttribute(QStringLiteral(
"width"))) {
432 QString str = element.attribute(QStringLiteral(
"width"));
433 if (str.endsWith(QLatin1Char(
'%'))) {
439 if (element.hasAttribute(QStringLiteral(
"height"))) {
440 QString str = element.attribute(QStringLiteral(
"height"));
441 if (str.endsWith(QLatin1Char(
'%'))) {
445 height = str.toInt();
447 chartElement.setSize(width, height, unit);
449 if (m_xmlElementHandler && !m_xmlElementHandler->chartElement(chartElement, element))
452 addElement(chartElement, builder, element);
454 }
else if (name == QLatin1String(
"image")) {
458 QImage image = extractImage(element, &
id);
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);
467 imageElement.setWidth(widthStr.toInt());
469 }
else if (element.hasAttribute(QStringLiteral(
"height"))) {
470 QString heightStr = element.attribute(QStringLiteral(
"height"));
471 if (heightStr.endsWith(QLatin1Char(
'%'))) {
472 heightStr.truncate(heightStr.length() - 1);
475 imageElement.setHeight(heightStr.toInt());
477 }
else if (element.hasAttribute(QStringLiteral(
"fitToPage"))) {
478 imageElement.setFitToPage();
481 if (m_xmlElementHandler && !m_xmlElementHandler->imageElement(imageElement, element))
484 addElement(imageElement, builder, element);
486 }
else if (name == QLatin1String(
"header")) {
490 if (m_xmlElementHandler && !m_xmlElementHandler->startHeader(header, element))
492 if (!processNode(element, &header.d->
m_builder,
true,
false))
494 if (m_xmlElementHandler)
495 m_xmlElementHandler->endHeader(header, element);
496 }
else if (name == QLatin1String(
"footer")) {
500 if (m_xmlElementHandler && !m_xmlElementHandler->startFooter(footer, element))
502 if (!processNode(element, &footer.d->
m_builder,
false,
true))
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"));
511 if (!element.hasAttribute(QStringLiteral(
"type"))) {
512 error(QObject::tr(
"<variable> tags must have a 'type' attribute"));
517 const QString type = element.attribute(QStringLiteral(
"type"));
519 if (m_xmlElementHandler && !m_xmlElementHandler->variable(vt, element))
523 }
else if (name == QLatin1String(
"page-break")) {
524 if (m_xmlElementHandler && !m_xmlElementHandler->pageBreak(element))
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();
532 if (!processNode(element, builder, inHeader, inFooter))
536 }
else if (name == QLatin1String(
"custom")) {
537 if (m_xmlElementHandler)
538 m_xmlElementHandler->customElement(element);
539 }
else if (name == QLatin1String(
"hline")) {
542 if (element.hasAttribute(QStringLiteral(
"thickness"))) {
543 const double thickness = element.attribute(QStringLiteral(
"thickness")).toDouble();
547 if (element.hasAttribute(QStringLiteral(
"color"))) {
552 if (element.hasAttribute(QStringLiteral(
"margin"))) {
553 const int margin = element.attribute(QStringLiteral(
"margin")).toInt();
557 if (m_xmlElementHandler && !m_xmlElementHandler->hLineElement(hLineElement, element))
560 addElement(hLineElement, builder, element);
562 error(QObject::tr(
"KDReports::Report::loadFromXML(): Unknown element %1").arg(name));
566 if (testForErrorAndFillErrorDetails())
575 for (QDomElement element = tabsElement.firstChildElement(); !element.isNull(); element = element.nextSiblingElement()) {
576 if (element.tagName() == QLatin1String(
"tab")) {
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;
587 tab.type = QTextOption::LeftTab;
590 const QString delimiter = element.attribute(QStringLiteral(
"delimiter"));
591 if (!delimiter.isEmpty())
592 tab.delimiter = delimiter.at(0);
594 const QString strPos = element.attribute(QStringLiteral(
"position"));
596 if (strPos == QLatin1String(
"page")) {
597 tab.delimiter = QChar::fromLatin1(
'P');
599 pos = strPos.toDouble();
605 if (!m_xmlElementHandler || m_xmlElementHandler->tabs(tabs, tabsElement))
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))
619 QImage KDReports::XmlParser::extractImage(
const QDomElement &element, QString *pId)
const
621 if (element.hasAttribute(QStringLiteral(
"id"))) {
622 const QString
id = element.attribute(QStringLiteral(
"id"));
624 const QHash<QString, QImage>::const_iterator it = m_imageValues.find(
id);
625 if (it != m_imageValues.end()) {
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));
640 QString KDReports::XmlParser::extractText(
const QDomElement &element, QString *pId,
const QAbstractItemModel *currentModel,
int currentRow)
const
642 if (element.hasAttribute(QStringLiteral(
"id"))) {
643 const QString
id = element.attribute(QStringLiteral(
"id"));
645 const QHash<QString, QString>::const_iterator it = m_textValues.find(
id);
646 if (it != m_textValues.end()) {
649 }
else if (element.hasAttribute(QStringLiteral(
"model"))) {
650 const QString modelName = element.attribute(QStringLiteral(
"model"));
654 if (model == currentModel && currentRow > -1) {
657 row = element.attribute(QStringLiteral(
"row")).toInt();
659 const int column = element.attribute(QStringLiteral(
"column")).toInt();
660 const QModelIndex index = model->index(row, column);
661 return model->data(index).toString();
665 return element.text();
668 bool KDReports::XmlParser::testForErrorAndFillErrorDetails()
670 if (m_xmlElementHandler && m_xmlElementHandler->errorDetails().hasError()) {
672 *m_errorDetails = m_xmlElementHandler->errorDetails();
678 void KDReports::XmlParser::error(
const QString &errorString)
681 m_errorDetails->setDriverMessage(errorString);
683 qWarning(
"%s", qPrintable(errorString));