/* * 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); } } }