28 #include <QDomDocument>
29 #include <QDomElement>
30 #include <QModelIndex>
47 m_cell.addInlineElement(element);
52 m_cell.addElement(element, horizontalAlignment);
56 m_cell.addVariable(variable);
60 m_cell.addVerticalSpacing(space);
70 for (QDomElement element = tableNode.firstChildElement(); !element.isNull(); element = element.nextSiblingElement()) {
71 if (testForErrorAndFillErrorDetails())
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();
84 if (bgColor.isValid())
87 cellReportBuilder.copyStateFrom(builder);
89 if (m_xmlElementHandler && !m_xmlElementHandler->
startCell(cell, element))
92 if (!processNode(element, &cellReportBuilder, inHeader, inFooter))
95 if (m_xmlElementHandler && !m_xmlElementHandler->
endCell(cell, element))
100 if (testForErrorAndFillErrorDetails())
109 if (bgColor.isValid())
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);
119 tableElement.
setWidth(widthStr.toInt());
127 if (element.hasAttribute(QStringLiteral(
"pointsize"))) {
128 const int pointSize = element.attribute(QStringLiteral(
"pointsize")).toInt();
130 font.setPointSize(pointSize);
132 if (element.hasAttribute(QStringLiteral(
"font"))) {
133 font.setFamily(element.attribute(QStringLiteral(
"font")));
140 if (element.hasAttribute(QStringLiteral(
"font")) || element.hasAttribute(QStringLiteral(
"pointsize"))) {
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()));
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);
165 double marginTop = 20.0;
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);
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());
185 if (docElement.hasAttribute(QStringLiteral(
"font")) || docElement.hasAttribute(QStringLiteral(
"pointsize"))) {
187 m_report->setDefaultFont(font);
190 if (m_xmlElementHandler && !m_xmlElementHandler->startReport(*m_report, docElement)) {
192 *m_errorDetails = m_xmlElementHandler->errorDetails();
197 if (!processNode(docElement, builder,
false,
false))
200 if (m_xmlElementHandler)
201 m_xmlElementHandler->endReport(*m_report, docElement);
203 if (testForErrorAndFillErrorDetails())
212 error(QObject::tr(
"<%1> is only supported in WordProcessing mode").arg(element.tagName()));
215 if (element.hasAttribute(QStringLiteral(
"inline"))) {
218 Qt::AlignmentFlag alignment = Qt::AlignLeft;
219 if (element.hasAttribute(QStringLiteral(
"alignment")))
225 bool KDReports::XmlParser::processNode(
const QDomNode &node,
KDReports::ReportBuilder *builder,
bool inHeader,
bool inFooter)
228 for (QDomElement element = node.firstChildElement(); !element.isNull(); element = element.nextSiblingElement()) {
230 if (testForErrorAndFillErrorDetails())
233 const QString name = element.tagName();
234 if (name == QLatin1String(
"text")) {
238 const QString text = extractText(element, &
id, m_report->d->m_currentModel, m_report->d->m_currentRow);
240 textElement.
setId(
id);
242 if (bgColor.isValid())
244 if (element.hasAttribute(QStringLiteral(
"pointsize"))) {
245 const int pointSize = element.attribute(QStringLiteral(
"pointsize")).toInt();
249 if (element.hasAttribute(QStringLiteral(
"color"))) {
250 const QString name = element.attribute(QStringLiteral(
"color"));
253 if (element.hasAttribute(QStringLiteral(
"font"))) {
254 textElement.
setFontFamily(element.attribute(QStringLiteral(
"font")));
256 if (element.hasAttribute(QStringLiteral(
"bold"))) {
258 if (element.attribute(QStringLiteral(
"bold")) == QLatin1String(
"true"))
262 if (element.hasAttribute(QStringLiteral(
"italic"))) {
264 if (element.attribute(QStringLiteral(
"italic")) == QLatin1String(
"true"))
268 if (element.hasAttribute(QStringLiteral(
"strikeout"))) {
269 bool strikeOut =
false;
270 if (element.attribute(QStringLiteral(
"strikeout")) == QLatin1String(
"true"))
274 if (element.hasAttribute(QStringLiteral(
"underline"))) {
275 bool underline =
false;
276 if (element.attribute(QStringLiteral(
"underline")) == QLatin1String(
"true"))
281 const QString oldId = textElement.
id();
283 if (m_xmlElementHandler && !m_xmlElementHandler->textElement(textElement, element))
286 if (textElement.
id() != oldId) {
288 const QHash<QString, QString>::const_iterator it = m_textValues.constFind(textElement.
id());
289 if (it != m_textValues.constEnd()) {
295 error(QObject::tr(
"<text> is only supported in WordProcessing mode"));
297 if (element.hasAttribute(QStringLiteral(
"inline"))) {
300 Qt::AlignmentFlag alignment = Qt::AlignLeft;
301 if (element.hasAttribute(QStringLiteral(
"alignment")))
308 }
else if (name == QLatin1String(
"html")) {
312 const QString text = extractText(element, &
id);
314 htmlElement.
setId(
id);
316 if (bgColor.isValid())
319 const QString oldId = htmlElement.
id();
321 if (m_xmlElementHandler && !m_xmlElementHandler->htmlElement(htmlElement, element))
324 if (htmlElement.
id() != oldId) {
326 const QHash<QString, QString>::const_iterator it = m_textValues.constFind(htmlElement.
id());
327 if (it != m_textValues.constEnd()) {
332 addElement(htmlElement, builder, element);
334 }
else if (name == QLatin1String(
"tabs")) {
337 error(QObject::tr(
"<tabs> is only supported in WordProcessing mode"));
339 parseTabs(builder, element);
342 }
else if (name == QLatin1String(
"paragraph-margins")) {
345 error(QObject::tr(
"<paragraph-margins> is only supported in WordProcessing mode"));
347 parseParagraphMargins(builder, element);
350 }
else if (name == QLatin1String(
"hr")) {
353 htmlElement.
setHtml(QStringLiteral(
"<hr>"));
354 if (m_xmlElementHandler && !m_xmlElementHandler->htmlElement(htmlElement, element))
357 addElement(htmlElement, builder, element);
359 }
else if (name == QLatin1String(
"vspace")) {
361 if (!element.hasAttribute(QStringLiteral(
"size")))
363 int size = element.attribute(QStringLiteral(
"size")).toInt();
365 error(QObject::tr(
"<vspace> is only supported in WordProcessing mode"));
367 if (builder != m_report->d->builder()) {
368 error(QObject::tr(
"<vspace> not allowed in headers, footers, or table cells"));
372 if (m_xmlElementHandler && !m_xmlElementHandler->vspace(size, element))
374 m_report->addVerticalSpacing(size);
375 }
else if (name == QLatin1String(
"table")) {
377 const QString model = element.attribute(QStringLiteral(
"model"));
378 if (model.isEmpty()) {
380 error(QObject::tr(
"<table> without a model is only supported in WordProcessing mode"));
384 const int headerRowCount = element.attribute(QStringLiteral(
"headerRowCount")).toInt();
386 if (element.hasAttribute(QStringLiteral(
"cellpadding")))
387 tableElement.
setPadding(element.attribute(QStringLiteral(
"cellpadding")).toInt());
388 parseCommonTableAttributes(tableElement, element);
390 if (m_xmlElementHandler && !m_xmlElementHandler->startTableElement(tableElement, element))
393 if (!parseTableContents(tableElement, element, *builder, inHeader, inFooter))
396 if (m_xmlElementHandler && !m_xmlElementHandler->endTableElement(tableElement, element))
399 addElement(tableElement, builder, element);
403 if (element.attribute(QStringLiteral(
"verticalHeaderVisible")) == QLatin1String(
"false"))
404 tableElement.setVerticalHeaderVisible(
false);
405 if (element.attribute(QStringLiteral(
"horizontalHeaderVisible")) == QLatin1String(
"false"))
406 tableElement.setHorizontalHeaderVisible(
false);
408 if (headerBgColor.isValid())
409 tableElement.setHeaderBackground(headerBgColor);
410 parseCommonTableAttributes(tableElement, element);
411 if (m_xmlElementHandler && !m_xmlElementHandler->autoTableElement(tableElement, element))
415 m_report->mainTable()->setAutoTableElement(tableElement);
417 addElement(tableElement, builder, element);
420 }
else if (name == QLatin1String(
"chart")) {
425 if (bgColor.isValid())
426 chartElement.setBackground(bgColor);
430 if (element.hasAttribute(QStringLiteral(
"width"))) {
431 QString str = element.attribute(QStringLiteral(
"width"));
432 if (str.endsWith(QLatin1Char(
'%'))) {
438 if (element.hasAttribute(QStringLiteral(
"height"))) {
439 QString str = element.attribute(QStringLiteral(
"height"));
440 if (str.endsWith(QLatin1Char(
'%'))) {
444 height = str.toInt();
446 chartElement.setSize(width, height, unit);
448 if (m_xmlElementHandler && !m_xmlElementHandler->chartElement(chartElement, element))
451 addElement(chartElement, builder, element);
453 }
else if (name == QLatin1String(
"image")) {
457 QImage image = extractImage(element, &
id);
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);
466 imageElement.setWidth(widthStr.toInt());
468 }
else if (element.hasAttribute(QStringLiteral(
"height"))) {
469 QString heightStr = element.attribute(QStringLiteral(
"height"));
470 if (heightStr.endsWith(QLatin1Char(
'%'))) {
471 heightStr.truncate(heightStr.length() - 1);
474 imageElement.setHeight(heightStr.toInt());
476 }
else if (element.hasAttribute(QStringLiteral(
"fitToPage"))) {
477 imageElement.setFitToPage();
480 if (m_xmlElementHandler && !m_xmlElementHandler->imageElement(imageElement, element))
483 addElement(imageElement, builder, element);
485 }
else if (name == QLatin1String(
"header")) {
489 if (m_xmlElementHandler && !m_xmlElementHandler->startHeader(header, element))
491 if (!processNode(element, &header.d->m_builder,
true,
false))
493 if (m_xmlElementHandler)
494 m_xmlElementHandler->endHeader(header, element);
495 }
else if (name == QLatin1String(
"footer")) {
499 if (m_xmlElementHandler && !m_xmlElementHandler->startFooter(footer, element))
501 if (!processNode(element, &footer.d->m_builder,
false,
true))
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"));
510 if (!element.hasAttribute(QStringLiteral(
"type"))) {
511 error(QObject::tr(
"<variable> tags must have a 'type' attribute"));
516 const QString type = element.attribute(QStringLiteral(
"type"));
518 if (m_xmlElementHandler && !m_xmlElementHandler->variable(vt, element))
522 }
else if (name == QLatin1String(
"page-break")) {
523 if (m_xmlElementHandler && !m_xmlElementHandler->pageBreak(element))
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();
531 if (!processNode(element, builder, inHeader, inFooter))
535 }
else if (name == QLatin1String(
"custom")) {
536 if (m_xmlElementHandler)
537 m_xmlElementHandler->customElement(element);
538 }
else if (name == QLatin1String(
"hline")) {
541 if (element.hasAttribute(QStringLiteral(
"thickness"))) {
542 const double thickness = element.attribute(QStringLiteral(
"thickness")).toDouble();
546 if (element.hasAttribute(QStringLiteral(
"color"))) {
551 if (element.hasAttribute(QStringLiteral(
"margin"))) {
552 const int margin = element.attribute(QStringLiteral(
"margin")).toInt();
556 if (m_xmlElementHandler && !m_xmlElementHandler->hLineElement(hLineElement, element))
559 addElement(hLineElement, builder, element);
561 error(QObject::tr(
"KDReports::Report::loadFromXML(): Unknown element %1").arg(name));
565 if (testForErrorAndFillErrorDetails())
574 for (QDomElement element = tabsElement.firstChildElement(); !element.isNull(); element = element.nextSiblingElement()) {
575 if (element.tagName() == QLatin1String(
"tab")) {
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;
586 tab.type = QTextOption::LeftTab;
589 const QString delimiter = element.attribute(QStringLiteral(
"delimiter"));
590 if (!delimiter.isEmpty())
591 tab.delimiter = delimiter.at(0);
593 const QString strPos = element.attribute(QStringLiteral(
"position"));
595 if (strPos == QLatin1String(
"page")) {
596 tab.delimiter = QChar::fromLatin1(
'P');
598 pos = strPos.toDouble();
604 if (!m_xmlElementHandler || m_xmlElementHandler->tabs(tabs, tabsElement))
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))
618 QImage KDReports::XmlParser::extractImage(
const QDomElement &element, QString *pId)
const
620 if (element.hasAttribute(QStringLiteral(
"id"))) {
621 const QString
id = element.attribute(QStringLiteral(
"id"));
623 const QHash<QString, QImage>::const_iterator it = m_imageValues.find(
id);
624 if (it != m_imageValues.end()) {
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));
639 QString KDReports::XmlParser::extractText(
const QDomElement &element, QString *pId,
const QAbstractItemModel *currentModel,
int currentRow)
const
641 if (element.hasAttribute(QStringLiteral(
"id"))) {
642 const QString
id = element.attribute(QStringLiteral(
"id"));
644 const QHash<QString, QString>::const_iterator it = m_textValues.find(
id);
645 if (it != m_textValues.end()) {
648 }
else if (element.hasAttribute(QStringLiteral(
"model"))) {
649 const QString modelName = element.attribute(QStringLiteral(
"model"));
653 if (model == currentModel && currentRow > -1) {
656 row = element.attribute(QStringLiteral(
"row")).toInt();
658 const int column = element.attribute(QStringLiteral(
"column")).toInt();
659 const QModelIndex index = model->index(row, column);
660 return model->data(index).toString();
664 return element.text();
667 bool KDReports::XmlParser::testForErrorAndFillErrorDetails()
669 if (m_xmlElementHandler && m_xmlElementHandler->errorDetails().hasError()) {
671 *m_errorDetails = m_xmlElementHandler->errorDetails();
677 void KDReports::XmlParser::error(
const QString &errorString)
680 m_errorDetails->setDriverMessage(errorString);
682 qWarning(
"%s", qPrintable(errorString));
#define REPORTBUILDER_CTOR_ARGNAMES
#define REPORTBUILDER_CTOR_ARGDEFS
static QFont parseFontAttributes(const QDomElement &element)
static void parseHeaderFooterAttribute(KDReports::Header &header, const QDomElement &element)
void setPadding(qreal padding)
void setBorder(qreal border)
void setWidth(qreal width, Unit unit=Millimeters)
void setColumnSpan(int columnSpan)
void setRowSpan(int rowSpan)
void setBackground(const QBrush &brush)
void setThickness(qreal t)
void setColor(const QColor &color)
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)
QTextCursor & contentDocumentCursor()
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)
void setHeaderRowCount(int count)
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.
@ Millimeters
Millimeters (the default)
QAbstractItemModel * modelForKey(const QString &key)