You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
499 lines
19 KiB
499 lines
19 KiB
/*************************************************************************** |
|
* Copyright (C) 2006 by Tobias Koenig <tokoe@kde.org> * |
|
* * |
|
* This program is free software; you can redistribute it and/or modify * |
|
* it under the terms of the GNU General Public License as published by * |
|
* the Free Software Foundation; either version 2 of the License, or * |
|
* (at your option) any later version. * |
|
***************************************************************************/ |
|
|
|
#include "styleparser.h" |
|
|
|
#include <QDateTime> |
|
#include <QDomDocument> |
|
#include <QDomElement> |
|
#include <QFont> |
|
#include <QXmlSimpleReader> |
|
|
|
#include <KLocalizedString> |
|
|
|
#include "document.h" |
|
#include "styleinformation.h" |
|
|
|
using namespace OOO; |
|
|
|
StyleParser::StyleParser(const Document *document, const QDomDocument &domDocument, StyleInformation *styleInformation) |
|
: mDocument(document) |
|
, mDomDocument(domDocument) |
|
, mStyleInformation(styleInformation) |
|
, mMasterPageNameSet(false) |
|
{ |
|
} |
|
|
|
bool StyleParser::parse() |
|
{ |
|
if (!parseContentFile()) |
|
return false; |
|
|
|
if (!parseStyleFile()) |
|
return false; |
|
|
|
if (!parseMetaFile()) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
bool StyleParser::parseContentFile() |
|
{ |
|
const QDomElement documentElement = mDomDocument.documentElement(); |
|
QDomElement element = documentElement.firstChildElement(); |
|
while (!element.isNull()) { |
|
if (element.tagName() == QLatin1String("document-common-attrs")) { |
|
if (!parseDocumentCommonAttrs(element)) |
|
return false; |
|
} else if (element.tagName() == QLatin1String("font-face-decls")) { |
|
if (!parseFontFaceDecls(element)) |
|
return false; |
|
} else if (element.tagName() == QLatin1String("styles")) { |
|
if (!parseStyles(element)) |
|
return false; |
|
} else if (element.tagName() == QLatin1String("automatic-styles")) { |
|
if (!parseAutomaticStyles(element)) |
|
return false; |
|
} |
|
|
|
element = element.nextSiblingElement(); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
bool StyleParser::parseStyleFile() |
|
{ |
|
if (mDocument->styles().isEmpty()) |
|
return true; |
|
|
|
QXmlSimpleReader reader; |
|
|
|
QXmlInputSource source; |
|
source.setData(mDocument->styles()); |
|
|
|
QString errorMsg; |
|
int errorLine, errorCol; |
|
|
|
QDomDocument document; |
|
if (!document.setContent(&source, &reader, &errorMsg, &errorLine, &errorCol)) { |
|
qDebug("%s at (%d,%d)", qPrintable(errorMsg), errorLine, errorCol); |
|
return false; |
|
} |
|
|
|
const QDomElement documentElement = document.documentElement(); |
|
QDomElement element = documentElement.firstChildElement(); |
|
while (!element.isNull()) { |
|
if (element.tagName() == QLatin1String("styles")) { |
|
if (!parseAutomaticStyles(element)) |
|
return false; |
|
} else if (element.tagName() == QLatin1String("automatic-styles")) { |
|
if (!parseAutomaticStyles(element)) |
|
return false; |
|
} else if (element.tagName() == QLatin1String("master-styles")) { |
|
if (!parseMasterStyles(element)) |
|
return false; |
|
} |
|
|
|
element = element.nextSiblingElement(); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
bool StyleParser::parseMetaFile() |
|
{ |
|
if (mDocument->meta().isEmpty()) |
|
return true; |
|
|
|
QXmlSimpleReader reader; |
|
|
|
QXmlInputSource source; |
|
source.setData(mDocument->meta()); |
|
|
|
QString errorMsg; |
|
int errorLine, errorCol; |
|
|
|
QDomDocument document; |
|
if (!document.setContent(&source, &reader, &errorMsg, &errorLine, &errorCol)) { |
|
qDebug("%s at (%d,%d)", qPrintable(errorMsg), errorLine, errorCol); |
|
return false; |
|
} |
|
|
|
const QDomElement documentElement = document.documentElement(); |
|
QDomElement element = documentElement.firstChildElement(); |
|
while (!element.isNull()) { |
|
if (element.tagName() == QLatin1String("meta")) { |
|
QDomElement child = element.firstChildElement(); |
|
while (!child.isNull()) { |
|
if (child.tagName() == QLatin1String("generator")) { |
|
mStyleInformation->addMetaInformation(QStringLiteral("producer"), child.text(), i18n("Producer")); |
|
} else if (child.tagName() == QLatin1String("creation-date")) { |
|
const QDateTime dateTime = QDateTime::fromString(child.text(), Qt::ISODate); |
|
mStyleInformation->addMetaInformation(QStringLiteral("creationDate"), QLocale().toString(dateTime, QLocale::LongFormat), i18n("Created")); |
|
} else if (child.tagName() == QLatin1String("initial-creator")) { |
|
mStyleInformation->addMetaInformation(QStringLiteral("creator"), child.text(), i18n("Creator")); |
|
} else if (child.tagName() == QLatin1String("creator")) { |
|
mStyleInformation->addMetaInformation(QStringLiteral("author"), child.text(), i18n("Author")); |
|
} else if (child.tagName() == QLatin1String("date")) { |
|
const QDateTime dateTime = QDateTime::fromString(child.text(), Qt::ISODate); |
|
mStyleInformation->addMetaInformation(QStringLiteral("modificationDate"), QLocale().toString(dateTime, QLocale::LongFormat), i18n("Modified")); |
|
} |
|
|
|
child = child.nextSiblingElement(); |
|
} |
|
} |
|
|
|
element = element.nextSiblingElement(); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
bool StyleParser::parseDocumentCommonAttrs(QDomElement &) |
|
{ |
|
return true; |
|
} |
|
|
|
bool StyleParser::parseFontFaceDecls(QDomElement &parent) |
|
{ |
|
QDomElement element = parent.firstChildElement(); |
|
while (!element.isNull()) { |
|
if (element.tagName() == QLatin1String("font-face")) { |
|
FontFormatProperty property; |
|
property.setFamily(element.attribute(QStringLiteral("font-family"))); |
|
|
|
mStyleInformation->addFontProperty(element.attribute(QStringLiteral("name")), property); |
|
} else { |
|
qDebug("unknown tag %s", qPrintable(element.tagName())); |
|
} |
|
|
|
element = element.nextSiblingElement(); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
bool StyleParser::parseStyles(QDomElement &) |
|
{ |
|
return true; |
|
} |
|
|
|
bool StyleParser::parseMasterStyles(QDomElement &parent) |
|
{ |
|
QDomElement element = parent.firstChildElement(); |
|
while (!element.isNull()) { |
|
if (element.tagName() == QLatin1String("master-page")) { |
|
mStyleInformation->addMasterLayout(element.attribute(QStringLiteral("name")), element.attribute(QStringLiteral("page-layout-name"))); |
|
if (!mMasterPageNameSet) { |
|
mStyleInformation->setMasterPageName(element.attribute(QStringLiteral("name"))); |
|
mMasterPageNameSet = true; |
|
} |
|
} else { |
|
qDebug("unknown tag %s", qPrintable(element.tagName())); |
|
} |
|
|
|
element = element.nextSiblingElement(); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
bool StyleParser::parseAutomaticStyles(QDomElement &parent) |
|
{ |
|
QDomElement element = parent.firstChildElement(); |
|
while (!element.isNull()) { |
|
if (element.tagName() == QLatin1String("style")) { |
|
const StyleFormatProperty property = parseStyleProperty(element); |
|
mStyleInformation->addStyleProperty(element.attribute(QStringLiteral("name")), property); |
|
} else if (element.tagName() == QLatin1String("page-layout")) { |
|
QDomElement child = element.firstChildElement(); |
|
while (!child.isNull()) { |
|
if (child.tagName() == QLatin1String("page-layout-properties")) { |
|
const PageFormatProperty property = parsePageProperty(child); |
|
mStyleInformation->addPageProperty(element.attribute(QStringLiteral("name")), property); |
|
} |
|
|
|
child = child.nextSiblingElement(); |
|
} |
|
} else if (element.tagName() == QLatin1String("list-style")) { |
|
const ListFormatProperty property = parseListProperty(element); |
|
mStyleInformation->addListProperty(element.attribute(QStringLiteral("name")), property); |
|
} else if (element.tagName() == QLatin1String("default-style")) { |
|
StyleFormatProperty property = parseStyleProperty(element); |
|
property.setDefaultStyle(true); |
|
mStyleInformation->addStyleProperty(element.attribute(QStringLiteral("family")), property); |
|
} else { |
|
qDebug("unknown tag %s", qPrintable(element.tagName())); |
|
} |
|
|
|
element = element.nextSiblingElement(); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
StyleFormatProperty StyleParser::parseStyleProperty(QDomElement &parent) |
|
{ |
|
StyleFormatProperty property(mStyleInformation); |
|
|
|
property.setParentStyleName(parent.attribute(QStringLiteral("parent-style-name"))); |
|
property.setFamily(parent.attribute(QStringLiteral("family"))); |
|
if (parent.hasAttribute(QStringLiteral("master-page-name"))) { |
|
property.setMasterPageName(parent.attribute(QStringLiteral("master-page-name"))); |
|
if (!mMasterPageNameSet) { |
|
mStyleInformation->setMasterPageName(parent.attribute(QStringLiteral("master-page-name"))); |
|
mMasterPageNameSet = true; |
|
} |
|
} |
|
|
|
QDomElement element = parent.firstChildElement(); |
|
while (!element.isNull()) { |
|
if (element.tagName() == QLatin1String("paragraph-properties")) { |
|
const ParagraphFormatProperty paragraphProperty = parseParagraphProperty(element); |
|
property.setParagraphFormat(paragraphProperty); |
|
} else if (element.tagName() == QLatin1String("text-properties")) { |
|
const TextFormatProperty textProperty = parseTextProperty(element); |
|
property.setTextFormat(textProperty); |
|
} else if (element.tagName() == QLatin1String("table-column-properties")) { |
|
const TableColumnFormatProperty tableColumnProperty = parseTableColumnProperty(element); |
|
property.setTableColumnFormat(tableColumnProperty); |
|
} else if (element.tagName() == QLatin1String("table-cell-properties")) { |
|
const TableCellFormatProperty tableCellProperty = parseTableCellProperty(element); |
|
property.setTableCellFormat(tableCellProperty); |
|
} else { |
|
qDebug("unknown tag %s", qPrintable(element.tagName())); |
|
} |
|
|
|
element = element.nextSiblingElement(); |
|
} |
|
|
|
return property; |
|
} |
|
|
|
ParagraphFormatProperty StyleParser::parseParagraphProperty(QDomElement &parent) |
|
{ |
|
ParagraphFormatProperty property; |
|
|
|
property.setPageNumber(parent.attribute(QStringLiteral("page-number")).toInt()); |
|
|
|
static QMap<QString, ParagraphFormatProperty::WritingMode> map; |
|
if (map.isEmpty()) { |
|
map.insert(QStringLiteral("lr-tb"), ParagraphFormatProperty::LRTB); |
|
map.insert(QStringLiteral("rl-tb"), ParagraphFormatProperty::RLTB); |
|
map.insert(QStringLiteral("tb-rl"), ParagraphFormatProperty::TBRL); |
|
map.insert(QStringLiteral("tb-lr"), ParagraphFormatProperty::TBLR); |
|
map.insert(QStringLiteral("lr"), ParagraphFormatProperty::LR); |
|
map.insert(QStringLiteral("rl"), ParagraphFormatProperty::RL); |
|
map.insert(QStringLiteral("tb"), ParagraphFormatProperty::TB); |
|
map.insert(QStringLiteral("page"), ParagraphFormatProperty::PAGE); |
|
} |
|
property.setWritingMode(map[parent.attribute(QStringLiteral("writing-mode"))]); |
|
|
|
static QMap<QString, Qt::Alignment> alignMap; |
|
if (alignMap.isEmpty()) { |
|
alignMap.insert(QStringLiteral("center"), Qt::AlignCenter); |
|
alignMap.insert(QStringLiteral("left"), Qt::AlignLeft); |
|
alignMap.insert(QStringLiteral("right"), Qt::AlignRight); |
|
alignMap.insert(QStringLiteral("justify"), Qt::AlignJustify); |
|
if (property.writingModeIsRightToLeft()) { |
|
alignMap.insert(QStringLiteral("start"), Qt::AlignRight); |
|
alignMap.insert(QStringLiteral("end"), Qt::AlignLeft); |
|
} else { |
|
// not right to left |
|
alignMap.insert(QStringLiteral("start"), Qt::AlignLeft); |
|
alignMap.insert(QStringLiteral("end"), Qt::AlignRight); |
|
} |
|
} |
|
if (parent.hasAttribute(QStringLiteral("text-align"))) { |
|
property.setTextAlignment(alignMap[parent.attribute(QStringLiteral("text-align"), QStringLiteral("left"))]); |
|
} |
|
|
|
const QString marginLeft = parent.attribute(QStringLiteral("margin-left")); |
|
if (!marginLeft.isEmpty()) { |
|
qreal leftMargin = qRound(convertUnit(marginLeft)); |
|
property.setLeftMargin(leftMargin); |
|
} |
|
|
|
const QString colorText = parent.attribute(QStringLiteral("background-color")); |
|
if (!colorText.isEmpty() && colorText != QLatin1String("transparent")) { |
|
property.setBackgroundColor(QColor(colorText)); |
|
} |
|
|
|
return property; |
|
} |
|
|
|
TextFormatProperty StyleParser::parseTextProperty(QDomElement &parent) |
|
{ |
|
TextFormatProperty property; |
|
|
|
const QString fontSize = parent.attribute(QStringLiteral("font-size")); |
|
if (!fontSize.isEmpty()) |
|
property.setFontSize(qRound(convertUnit(fontSize))); |
|
|
|
static QMap<QString, QFont::Weight> weightMap; |
|
if (weightMap.isEmpty()) { |
|
weightMap.insert(QStringLiteral("normal"), QFont::Normal); |
|
weightMap.insert(QStringLiteral("bold"), QFont::Bold); |
|
} |
|
|
|
const QString fontWeight = parent.attribute(QStringLiteral("font-weight")); |
|
if (!fontWeight.isEmpty()) |
|
property.setFontWeight(weightMap[fontWeight]); |
|
|
|
static QMap<QString, QFont::Style> fontStyleMap; |
|
if (fontStyleMap.isEmpty()) { |
|
fontStyleMap.insert(QStringLiteral("normal"), QFont::StyleNormal); |
|
fontStyleMap.insert(QStringLiteral("italic"), QFont::StyleItalic); |
|
fontStyleMap.insert(QStringLiteral("oblique"), QFont::StyleOblique); |
|
} |
|
|
|
const QString fontStyle = parent.attribute(QStringLiteral("font-style")); |
|
if (!fontStyle.isEmpty()) |
|
property.setFontStyle(fontStyleMap.value(fontStyle, QFont::StyleNormal)); |
|
|
|
const QColor color(parent.attribute(QStringLiteral("color"))); |
|
if (color.isValid()) { |
|
property.setColor(color); |
|
} |
|
|
|
const QString colorText = parent.attribute(QStringLiteral("background-color")); |
|
if (!colorText.isEmpty() && colorText != QLatin1String("transparent")) { |
|
property.setBackgroundColor(QColor(colorText)); |
|
} |
|
|
|
return property; |
|
} |
|
|
|
PageFormatProperty StyleParser::parsePageProperty(QDomElement &parent) |
|
{ |
|
PageFormatProperty property; |
|
|
|
property.setBottomMargin(convertUnit(parent.attribute(QStringLiteral("margin-bottom")))); |
|
property.setLeftMargin(convertUnit(parent.attribute(QStringLiteral("margin-left")))); |
|
property.setTopMargin(convertUnit(parent.attribute(QStringLiteral("margin-top")))); |
|
property.setRightMargin(convertUnit(parent.attribute(QStringLiteral("margin-right")))); |
|
property.setWidth(convertUnit(parent.attribute(QStringLiteral("page-width")))); |
|
property.setHeight(convertUnit(parent.attribute(QStringLiteral("page-height")))); |
|
|
|
return property; |
|
} |
|
|
|
ListFormatProperty StyleParser::parseListProperty(QDomElement &parent) |
|
{ |
|
ListFormatProperty property; |
|
|
|
QDomElement element = parent.firstChildElement(); |
|
if (element.tagName() == QLatin1String("list-level-style-number")) |
|
property = ListFormatProperty(ListFormatProperty::Number); |
|
else |
|
property = ListFormatProperty(ListFormatProperty::Bullet); |
|
|
|
while (!element.isNull()) { |
|
if (element.tagName() == QLatin1String("list-level-style-number")) { |
|
int level = element.attribute(QStringLiteral("level")).toInt(); |
|
property.addItem(level, 0.0); |
|
} else if (element.tagName() == QLatin1String("list-level-style-bullet")) { |
|
int level = element.attribute(QStringLiteral("level")).toInt(); |
|
property.addItem(level, convertUnit(element.attribute(QStringLiteral("space-before")))); |
|
} |
|
|
|
element = element.nextSiblingElement(); |
|
} |
|
|
|
return property; |
|
} |
|
|
|
TableColumnFormatProperty StyleParser::parseTableColumnProperty(QDomElement &parent) |
|
{ |
|
TableColumnFormatProperty property; |
|
|
|
const double width = convertUnit(parent.attribute(QStringLiteral("column-width"))); |
|
property.setWidth(width); |
|
|
|
return property; |
|
} |
|
|
|
TableCellFormatProperty StyleParser::parseTableCellProperty(QDomElement &parent) |
|
{ |
|
TableCellFormatProperty property; |
|
|
|
if (parent.hasAttribute(QStringLiteral("background-color"))) |
|
property.setBackgroundColor(QColor(parent.attribute(QStringLiteral("background-color")))); |
|
|
|
property.setPadding(convertUnit(parent.attribute(QStringLiteral("padding")))); |
|
|
|
static QMap<QString, Qt::Alignment> map; |
|
if (map.isEmpty()) { |
|
map.insert(QStringLiteral("top"), Qt::AlignTop); |
|
map.insert(QStringLiteral("middle"), Qt::AlignVCenter); |
|
map.insert(QStringLiteral("bottom"), Qt::AlignBottom); |
|
map.insert(QStringLiteral("left"), Qt::AlignLeft); |
|
map.insert(QStringLiteral("right"), Qt::AlignRight); |
|
map.insert(QStringLiteral("center"), Qt::AlignHCenter); |
|
} |
|
|
|
if (parent.hasAttribute(QStringLiteral("align")) && parent.hasAttribute(QStringLiteral("vertical-align"))) { |
|
property.setAlignment(map[parent.attribute(QStringLiteral("align"))] | map[parent.attribute(QStringLiteral("vertical-align"))]); |
|
} else if (parent.hasAttribute(QStringLiteral("align"))) { |
|
property.setAlignment(map[parent.attribute(QStringLiteral("align"))]); |
|
} else if (parent.hasAttribute(QStringLiteral("vertical-align"))) { |
|
property.setAlignment(map[parent.attribute(QStringLiteral("vertical-align"))]); |
|
} |
|
|
|
return property; |
|
} |
|
|
|
double StyleParser::convertUnit(const QString &data) |
|
{ |
|
#define MM_TO_POINT(mm) ((mm)*2.83465058) |
|
#define CM_TO_POINT(cm) ((cm)*28.3465058) |
|
#define DM_TO_POINT(dm) ((dm)*283.465058) |
|
#define INCH_TO_POINT(inch) ((inch)*72.0) |
|
#define PI_TO_POINT(pi) ((pi)*12) |
|
#define DD_TO_POINT(dd) ((dd)*154.08124) |
|
#define CC_TO_POINT(cc) ((cc)*12.840103) |
|
|
|
double points = 0; |
|
if (data.endsWith(QLatin1String("pt"))) { |
|
points = data.leftRef(data.length() - 2).toDouble(); |
|
} else if (data.endsWith(QLatin1String("cm"))) { |
|
double value = data.leftRef(data.length() - 2).toDouble(); |
|
points = CM_TO_POINT(value); |
|
} else if (data.endsWith(QLatin1String("mm"))) { |
|
double value = data.leftRef(data.length() - 2).toDouble(); |
|
points = MM_TO_POINT(value); |
|
} else if (data.endsWith(QLatin1String("dm"))) { |
|
double value = data.leftRef(data.length() - 2).toDouble(); |
|
points = DM_TO_POINT(value); |
|
} else if (data.endsWith(QLatin1String("in"))) { |
|
double value = data.leftRef(data.length() - 2).toDouble(); |
|
points = INCH_TO_POINT(value); |
|
} else if (data.endsWith(QLatin1String("inch"))) { |
|
double value = data.leftRef(data.length() - 4).toDouble(); |
|
points = INCH_TO_POINT(value); |
|
} else if (data.endsWith(QLatin1String("pi"))) { |
|
double value = data.leftRef(data.length() - 4).toDouble(); |
|
points = PI_TO_POINT(value); |
|
} else if (data.endsWith(QLatin1String("dd"))) { |
|
double value = data.leftRef(data.length() - 4).toDouble(); |
|
points = DD_TO_POINT(value); |
|
} else if (data.endsWith(QLatin1String("cc"))) { |
|
double value = data.leftRef(data.length() - 4).toDouble(); |
|
points = CC_TO_POINT(value); |
|
} else { |
|
if (!data.isEmpty()) { |
|
qDebug("unknown unit for '%s'", qPrintable(data)); |
|
} |
|
points = 12; |
|
} |
|
|
|
return points; |
|
}
|
|
|