/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2008 jOpenDocument, by ILM Informatique. All rights reserved.
*
* The contents of this file are subject to the terms of the GNU
* General Public License Version 3 only ("GPL").
* You may not use this file except in compliance with the License.
* You can obtain a copy of the License at http://www.gnu.org/licenses/gpl-3.0.html
* See the License for the specific language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each file.
*
*/
package org.jopendocument.io;
import java.util.List;
import java.util.Stack;
import org.jopendocument.model.OpenDocument;
import org.jopendocument.model.draw.DrawFrame;
import org.jopendocument.model.draw.DrawImage;
import org.jopendocument.model.number.NumberNumberStyle;
import org.jopendocument.model.office.OfficeAutomaticStyles;
import org.jopendocument.model.office.OfficeBody;
import org.jopendocument.model.office.OfficeScripts;
import org.jopendocument.model.office.OfficeSpreadsheet;
import org.jopendocument.model.style.StyleFontFace;
import org.jopendocument.model.style.StyleParagraphProperties;
import org.jopendocument.model.style.StyleStyle;
import org.jopendocument.model.style.StyleTableCellProperties;
import org.jopendocument.model.style.StyleTableColumnProperties;
import org.jopendocument.model.style.StyleTableRowProperties;
import org.jopendocument.model.style.StyleTextProperties;
import org.jopendocument.model.table.TableShapes;
import org.jopendocument.model.table.TableTable;
import org.jopendocument.model.table.TableTableCell;
import org.jopendocument.model.table.TableTableColumn;
import org.jopendocument.model.table.TableTableRow;
import org.jopendocument.model.text.TextP;
import org.jopendocument.model.text.TextSpan;
import org.jopendocument.util.ValueHelper;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
public class SaxContentUnmarshaller extends DefaultHandler {
private OfficeAutomaticStyles autostyles;
private OfficeBody body;
private Object current;
private final OpenDocument document;
private FontFaceDecls fontDeclarations;
private OfficeScripts scripts;
private final Stack<Object> stack;
// -----
public SaxContentUnmarshaller(final OpenDocument openDocument) {
this.document = openDocument;
this.stack = new Stack<Object>();
}
// ----- callbacks: -----
private void assertParsed(final Attributes attribs, final int l) {
if (attribs.getLength() > l) {
for (int i = 0; i < attribs.getLength(); i++) {
System.err.println(attribs.getQName(i) + " -> " + attribs.getValue(i));
}
throw new IllegalStateException("Somme attributes are not parsed");
}
}
public void characters(final char[] data, final int start, final int length) {
final StringBuffer s = new StringBuffer();
s.append(data, start, length);
if (this.current instanceof TextP) {
((TextP) this.current).addToLastTextSpan(s.toString());
} else if (this.current instanceof TextSpan) {
((TextSpan) this.current).concantValue(s.toString());
}
}
// -----
private static void dumpAttributes(final Attributes attribs) {
System.err.println("Dump attributes:");
for (int i = 0; i < attribs.getLength(); i++) {
System.err.println("'" + attribs.getQName(i) + "' -> '" + attribs.getValue(i) + "'");
}
}
// -----
public void dumpAutoStyles() {
final List<StyleStyle> l = this.autostyles.getStyles();
for (final StyleStyle style : l) {
System.out.println(style);
}
}
public void dumpSpreadSheets() {
final List<OfficeSpreadsheet> l = this.body.getOfficeSpreadsheets();
for (final OfficeSpreadsheet sheet : l) {
System.out.println(sheet);
final List<TableTable> tables = sheet.getTables();
for (final TableTable table : tables) {
dumpRows(table);
final List<TableTableColumn> cols = table.getColumnsInRange(table.getPrintStartCol(), table.getPrintStopCol());
for (final TableTableColumn col : cols) {
System.out.println(col.getWidth());
}
}
}
}
private void dumpRows(final TableTable table) {
for (final TableTableRow r : table.getRows()) {
final TableTableCell[] cells = r.getCellsInRange(table.getPrintStartCol(), table.getPrintStopCol());
for (final TableTableCell cell : cells) {
if (cell.getTextP() != null) {
final TextP text = cell.getTextP();
final List<TextSpan> lt = text.getTextSpans();
System.out.println("TextP:" + lt);
}
}
}
}
public void dumpSpreadSheetsRows() {
final List<OfficeSpreadsheet> l = this.body.getOfficeSpreadsheets();
for (final OfficeSpreadsheet sheet : l) {
System.out.println(sheet);
final List<TableTable> tables = sheet.getTables();
for (final TableTable table : tables) {
System.out.println("Table ===================");
for (final TableTableRow r : table.getRows()) {
System.out.println(r.getText() + " repeated:" + r.getTableNumberRowsRepeated());
}
}
}
}
public void endElement(final String uri, final String localName, final String qName) {
this.pop();
}
public OfficeAutomaticStyles getAutomaticstyles() {
return this.autostyles;
}
// -----
public OfficeBody getBody() {
return this.body;
}
// -----
private void pop() {
if (!this.stack.isEmpty()) {
this.stack.pop();
}
if (!this.stack.isEmpty()) {
this.current = this.stack.peek();
}
}
private void push(final Object o) {
this.current = o;
this.stack.push(o);
}
public void startElement(final String uri, final String localName, final String qName, final Attributes attribs) {
if (qName.equals("office:automatic-styles")) {
this.autostyles = new OfficeAutomaticStyles();
this.document.setAutomaticStyles(this.autostyles);
this.push(this.autostyles);
} else if (qName.equals("style:style")) {
final StyleStyle style = new StyleStyle();
style.setStyleName(attribs.getValue("style:name"));
style.setStyleFamily(attribs.getValue("style:family"));
style.setStyleParentStyleName(attribs.getValue("style:parent-style-name"));
style.setMasterPageName(attribs.getValue("style:master-page-name"));
// style:data-style-name="N108"
if (this.current instanceof OfficeAutomaticStyles) {
this.autostyles.addStyle(style);
} else {
System.err.println("Not OfficeAutomaticStyles:" + this.current);
Thread.dumpStack();
}
this.push(style);
} else if (qName.equals("number:number-style")) {
final NumberNumberStyle style = new NumberNumberStyle();
style.setStyleName(attribs.getValue("style:name"));
style.setStyleFamily(attribs.getValue("style:family"));
// style:data-style-name="N108"
if (this.current instanceof OfficeAutomaticStyles) {
this.autostyles.addStyle(style);
} else {
System.err.println("Not OfficeAutomaticStyles:" + this.current);
Thread.dumpStack();
}
this.push(style);
} else if (qName.equals("style:table-row-properties")) {
final StyleTableRowProperties props = new StyleTableRowProperties();
props.setFoBreakBefore(attribs.getValue("fo:break-before"));
props.setRowHeight(attribs.getValue("style:row-height"));
props.setUseOptimalRowHeight(attribs.getValue("style:use-optimal-row-height"));
if (this.current instanceof StyleStyle) {
((StyleStyle) this.current).setTableRowProperties(props);
} else {
System.err.println("Not StyleStyle:" + this.current);
Thread.dumpStack();
}
this.push(props);
} else if (qName.equals("style:table-properties")) {
final StyleTableProperties props = new StyleTableProperties();
props.setDisplay(ValueHelper.getBoolean(attribs.getValue("table:display")));
props.setWritingMode(attribs.getValue("style:writing-mode"));
if (this.current instanceof StyleStyle) {
((StyleStyle) this.current).setTableProperties(props);
} else {
System.err.println("Not StyleStyle:" + this.current);
Thread.dumpStack();
}
this.push(props);
} else if (qName.equals("style:table-cell-properties")) {
final StyleTableCellProperties props = new StyleTableCellProperties();
props.setVerticalAlign(attribs.getValue("style:vertical-align"));
props.setBackgroundColor(attribs.getValue("fo:background-color"));
props.setPadding(attribs.getValue("fo:padding"));
props.setTextAlignSource(attribs.getValue("style:text-align-source"));
props.setRepeatContent(attribs.getValue("style:repeat-content"));
props.setBorderLeft(attribs.getValue("fo:border-left"));
props.setBorderRight(attribs.getValue("fo:border-right"));
props.setBorderTop(attribs.getValue("fo:border-top"));
props.setBorderBottom(attribs.getValue("fo:border-bottom"));
// doit etre apres pour overrider le border!
props.setBorder(attribs.getValue("fo:border"));
props.setWrapOption(attribs.getValue("fo:wrap-option"));
if (this.current instanceof StyleStyle) {
((StyleStyle) this.current).setTableCellProperties(props);
} else {
System.err.println("Not StyleStyle:" + this.current);
Thread.dumpStack();
}
this.push(props);
} else if (qName.equals("style:text-properties")) {
final StyleTextProperties props = new StyleTextProperties();
props.setFontName(attribs.getValue("style:font-name"));
props.setFontSize(attribs.getValue("fo:font-size"));
props.setFontWeight(attribs.getValue("fo:font-weight"));
props.setColor(attribs.getValue("fo:color"));
// fo:hyphenate="true"
if (this.current instanceof StyleStyle) {
((StyleStyle) this.current).setTextProperties(props);
} else {
System.err.println("Not StyleStyle:" + this.current);
Thread.dumpStack();
}
this.push(props);
} else if (qName.equals("style:table-column-properties")) {
final StyleTableColumnProperties props = new StyleTableColumnProperties();
props.setFoBreakBefore(attribs.getValue("fo:break-before"));
props.setStyleColumnWidth(attribs.getValue("style:column-width"));
if (this.current instanceof StyleStyle) {
((StyleStyle) this.current).setTableColumnProperties(props);
} else {
System.err.println("Not StyleStyle:" + this.current);
Thread.dumpStack();
}
this.push(props);
} else if (qName.equals("style:paragraph-properties")) {
final StyleParagraphProperties props = new StyleParagraphProperties();
props.setTextAlign(attribs.getValue("fo:text-align"));
props.setMarginLeft(attribs.getValue("fo:margin-left"));
if (this.current instanceof StyleStyle) {
((StyleStyle) this.current).setParagraphProperties(props);
} else {
System.err.println("Not StyleStyle:" + this.current);
Thread.dumpStack();
}
this.push(props);
} else if (qName.equals("office:body")) {
this.body = new OfficeBody();
this.push(this.body);
} else if (qName.equals("office:spreadsheet")) {
final OfficeSpreadsheet spread = new OfficeSpreadsheet();
if (this.current instanceof OfficeBody) {
((OfficeBody) this.current).addOfficeSpreadsheet(spread);
} else {
System.err.println("Not StyleStyle:" + this.current);
Thread.dumpStack();
}
this.push(spread);
} else if (qName.equals("table:table")) {
final TableTable table = new TableTable();
dumpAttributes(attribs);
table.setTableName(attribs.getValue("table:name"));
table.setTableStyleName(attribs.getValue("table:style-name"));
final String printranges = attribs.getValue("table:print-ranges");
if (printranges != null) {
table.setTablePrintRanges(printranges);
}
this.assertParsed(attribs, 3);
if (this.current instanceof OfficeSpreadsheet) {
((OfficeSpreadsheet) this.current).addTable(table);
} else {
System.err.println("Not OfficeSpreadsheet:" + this.current);
Thread.dumpStack();
}
this.push(table);
} else if (qName.equals("table:table-column")) {
final TableTableColumn col = new TableTableColumn();
col.setTableStyleName(attribs.getValue("table:style-name"));
col.setTableDefaultCellStyleName(attribs.getValue("table:default-cell-style-name"));
col.setTableNumberColumnsRepeated(attribs.getValue("table:number-columns-repeated"));
this.assertParsed(attribs, 3);
if (this.current instanceof TableTable) {
((TableTable) this.current).addColumn(col);
} else {
System.err.println("Not TableTable:" + this.current);
Thread.dumpStack();
}
this.push(col);
} else if (qName.equals("table:table-row")) {
final TableTableRow row = new TableTableRow();
row.setTableStyleName(attribs.getValue("table:style-name"));
row.setTableNumberRowsRepeated(attribs.getValue("table:number-rows-repeated"));
if (this.current instanceof TableTable) {
((TableTable) this.current).addRow(row);
} else {
System.err.println("Not TableTable:" + this.current);
}
this.push(row);
} else if (qName.equals("table:table-cell") || qName.equals("table:covered-table-cell")) {
final TableTableCell cell = new TableTableCell();
cell.setTableStyleName(attribs.getValue("table:style-name"));
cell.setTableNumberColumnsRepeated(attribs.getValue("table:number-columns-repeated"));
cell.setTableNumberColumnsSpanned(attribs.getValue("table:number-columns-spanned"));
cell.setTableNumberRowsSpanned(attribs.getValue("table:number-rows-spanned"));
cell.setTableValueType(attribs.getValue("office:value-type"));
if (qName.equals("table:covered-table-cell")) {
cell.setCovered(true);
}
if (this.current instanceof TableTableRow) {
((TableTableRow) this.current).addCell(cell);
} else {
System.err.println("Not TableTableRow:" + this.current);
Thread.dumpStack();
}
this.push(cell);
} else if (qName.equals("text:p")) {
final TextP p = new TextP();
// TODO: gerer le multi textp dans une cellule
if (this.current instanceof TableTableCell) {
((TableTableCell) this.current).setTextP(p);
} else if (this.current instanceof DrawImage) {
((DrawImage) this.current).setTextP(p);
} else {
System.err.println("Not TableTableCell:" + this.current + " classe:" + this.current.getClass());
Thread.dumpStack();
}
this.push(p);
} else if (qName.equals("text:span")) {
final TextSpan textspan = new TextSpan();
textspan.setTextStyle(this.autostyles.getTextStyle(attribs.getValue("text:style-name")));
if (this.current instanceof TextP) {
((TextP) this.current).addTextSpan(textspan);
} else {
System.err.println("Not TextP:" + this.current);
Thread.dumpStack();
}
this.push(textspan);
} else if (qName.equals("draw:frame")) {
final DrawFrame p = new DrawFrame();
p.setSvgWidth(attribs.getValue("svg:width"));
p.setSvgHeight(attribs.getValue("svg:height"));
p.setSvgX(attribs.getValue("svg:x"));
p.setSvgY(attribs.getValue("svg:y"));
if (this.current instanceof TableTableCell) {
((TableTableCell) this.current).addDrawFrame(p);
} else if (this.current instanceof TableShapes) {
((TableShapes) this.current).addDrawFrame(p);
} else {
System.err.println("Not TableTableCell:" + this.current);
Thread.dumpStack();
}
this.push(p);
} else if (qName.equals("draw:image")) {
final DrawImage p = new DrawImage();
final String link = attribs.getValue("xlink:href");
p.setXlinkHref(link);
this.document.preloadImage(link);
if (this.current instanceof DrawFrame) {
((DrawFrame) this.current).setDrawImage(p);
} else {
System.err.println("Not DrawFrame:" + this.current);
Thread.dumpStack();
}
this.push(p);
} else if (qName.equals("table:shapes")) {
final TableShapes p = new TableShapes();
if (this.current instanceof TableTable) {
((TableTable) this.current).setTableShapes(p);
} else {
System.err.println("Not TableTable:" + this.current);
Thread.dumpStack();
}
this.push(p);
} else if (qName.equals("office:scripts")) {
this.scripts = new OfficeScripts();
this.push(this.scripts);
} else if (qName.equals("office:font-face-decls")) {
this.fontDeclarations = new FontFaceDecls();
this.push(this.fontDeclarations);
} else if (qName.equals("style:font-face")) {
final StyleFontFace p = new StyleFontFace();
p.setStyleName(attribs.getValue("style:name"));
p.setFontFamily(attribs.getValue("svg:font-family"));
p.setFontFamilyGeneric(attribs.getValue("style:font-family-generic"));
p.setFontPitch(attribs.getValue("style:font-pitch"));
if (this.current instanceof FontFaceDecls) {
((FontFaceDecls) this.current).addFontFace(p);
} else {
System.err.println("Not FontFaceDecls:" + this.current);
Thread.dumpStack();
}
this.push(p);
}
else {
System.err.println("content.xml : ignoring :" + qName);
this.push(uri);
}
}
}