/* * 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.model; import org.jopendocument.util.ImageUtils; import org.jopendocument.util.StreamUtils; import java.awt.Image; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import javax.swing.ImageIcon; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; import org.jopendocument.io.SaxContentUnmarshaller; import org.jopendocument.io.SaxStylesUnmarshaller; import org.jopendocument.model.office.OfficeAutomaticStyles; import org.jopendocument.model.office.OfficeBody; import org.jopendocument.model.office.OfficeMasterStyles; import org.jopendocument.model.office.OfficeSpreadsheet; import org.jopendocument.model.office.OfficeStyles; import org.jopendocument.model.style.StyleDefaultStyle; import org.jopendocument.model.style.StylePageLayoutProperties; import org.jopendocument.model.style.StyleStyle; import org.jopendocument.model.table.TableTable; import org.jopendocument.model.table.TableTableRow; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; import org.xml.sax.helpers.XMLReaderFactory; public class OpenDocument { private static final int MAX_IN_MEMORY_HQ_IMAGE = 10; private OfficeAutomaticStyles autoStyles; private OfficeBody body; private final Map<String, Image> images = new HashMap<String, Image>(); private final Map<String, Image> imagesHQ = new HashMap<String, Image>(); private OfficeMasterStyles masterStyles; private List<PrintedPage> pages; private OfficeStyles styles; private ZipFile zipFile; private Map<Integer, Integer> splitRowValues = new HashMap<Integer, Integer>(); // Sheet -> // split /** * Creates an empty document You may use a loadFrom method on it */ public OpenDocument() { } /** * Creates a document from a file * * @param f a spreadsheet file (in Open Document format) */ public OpenDocument(final File f) { this.loadFrom(f); this.loadODSP(); } private void computePages() { this.pages = new ArrayList<PrintedPage>(); final List<OfficeSpreadsheet> l = this.body.getOfficeSpreadsheets(); int currentHeight = 0; for (final OfficeSpreadsheet sheet : l) { final List<TableTable> tables = sheet.getTables(); for (final TableTable t : tables) { final StylePageLayoutProperties pageLayoutProperties = t.getPageLayoutProperties(); int pageHeight = 0; if (pageLayoutProperties != null) { pageHeight = pageLayoutProperties.getPageHeight(); } final int printStartRow = t.getPrintStartRow(); final int printStopRow = t.getPrintStopRow(); final int printStartCol = t.getPrintStartCol(); final int printStopCol = t.getPrintStopCol(); System.out.println("PageHeigth:"+pageHeight); final List<TableTableRow> rows = t.getRowsInRange(printStartRow, printStopRow); final int splitRow = this.getSplitEveryRow(tables.indexOf(t)); PrintedPage p = new PrintedPage(); final int rowCount = rows.size(); for (int j = 0; j < rowCount; j++) { final TableTableRow row = rows.get(j); p.addRow(row); if (splitRow > 0) { if (j > 0 && (j + 1) % (splitRow + 1) == 0) { this.pages.add(p); p = new PrintedPage(); } } else { currentHeight += row.getHeight(); if (currentHeight > pageHeight) { currentHeight = 0; this.pages.add(p); p = new PrintedPage(); } } } if (!this.pages.contains(p) && !p.isEmpty()) { this.pages.add(p); } } } } public OfficeAutomaticStyles getAutomaticStyles() { return this.autoStyles; } public OfficeBody getBody() { return this.body; } public Image getImage(final String xlinkHref) { final Image i = this.images.get(xlinkHref); if (i != null) { return i; } final ZipEntry entry = this.zipFile.getEntry(xlinkHref); byte[] bs = null; try { final InputStream stream = this.zipFile.getInputStream(entry); final ByteArrayOutputStream out = new ByteArrayOutputStream(); final int BUFFER_SIZE = 4096; final byte[] buffer = new byte[BUFFER_SIZE]; while (true) { final int count = stream.read(buffer, 0, BUFFER_SIZE); if (count == -1) { break; } out.write(buffer, 0, count); } out.close(); bs = out.toByteArray(); stream.read(bs); } catch (final IOException e) { e.printStackTrace(); } final ImageIcon ic = new ImageIcon(bs); final Image image = ic.getImage(); if (ic.getImageLoadStatus() != java.awt.MediaTracker.COMPLETE) { throw new IllegalStateException("Unable to load:'" + xlinkHref + "'"); } this.images.put(xlinkHref, image); return image; } public Image getImage(final String xlinkHref, final int width, final int height) { final String key = width + "," + height; Image im = this.imagesHQ.get(key); if (im != null) { return im; } im = ImageUtils.createQualityResizedImage(this.getImage(xlinkHref), width, height); // On fait un peu de ménage si trop de d'images if (this.imagesHQ.size() > MAX_IN_MEMORY_HQ_IMAGE) { this.imagesHQ.clear(); } this.imagesHQ.put(key, im); return im; } public OfficeMasterStyles getMasterStyles() { return this.masterStyles; } public PrintedPage getPrintedPage(final int i) { if (this.pages == null) { this.computePages(); } return this.pages.get(i); } public int getPrintedPageCount() { return this.pages.size(); } private void loadODSP() { final String path = this.getZipFile().getName() + "p"; final File f = new File(path); if (!f.exists()) { System.err.println("ODSP Not Exist"); return; } final SAXBuilder builder = new SAXBuilder(); try { final Document document = builder.build(f); final Element root = document.getRootElement(); final Element splitrow = root.getChild("spliteveryrow"); if (splitrow != null) { final List<Element> l = splitrow.getChildren("sheet"); for (final Element element : l) { final String s = element.getAttributeValue("number"); if (s != null && s.trim().length() > 0) { final int i = Integer.valueOf(s); final String value = element.getValue(); if (value != null && value.trim().length() > 0) { int row = Integer.valueOf(value); final int n = Integer.valueOf(s); splitRowValues.put(n, row); } } } } } catch (final JDOMException e) { e.printStackTrace(); } catch (final IOException e) { e.printStackTrace(); } } public int getSplitEveryRow(final int indexOfSheet) { final Integer value = this.splitRowValues.get(indexOfSheet); if (value != null) { return value; } return -1; } public OfficeStyles getStyles() { return this.styles; } public ZipFile getZipFile() { return this.zipFile; } public void importAutoStylesFrom(final OfficeAutomaticStyles stylesToAdd) { for (final StyleStyle s : stylesToAdd.getStyles()) { this.autoStyles.addStyle(s); } } public void init(final OfficeBody aBody, final OfficeAutomaticStyles bodyAutoStyles, final OfficeStyles s, final OfficeAutomaticStyles auto, final OfficeMasterStyles masters) { if (aBody == null) { throw new IllegalArgumentException("OfficeBody cannot be null"); } if (bodyAutoStyles == null) { throw new IllegalArgumentException("OfficeAutomaticStyles cannot be null"); } if (s == null) { throw new IllegalArgumentException("OfficeStyles cannot be null"); } if (auto == null) { throw new IllegalArgumentException("OfficeAutomaticStyles cannot be null"); } if (masters == null) { throw new IllegalArgumentException("OfficeMasterStyles cannot be null"); } this.body = aBody; this.body.setDocument(this); this.styles = s; this.autoStyles = auto; this.importAutoStylesFrom(bodyAutoStyles); StyleDefaultStyle mainDefaultCellStyle = s.getDefaultCellStyle(); if (mainDefaultCellStyle == null) { mainDefaultCellStyle = new StyleDefaultStyle(); mainDefaultCellStyle.setStyleFamily("table-cell"); } final StyleStyle defaultCellStyle = new StyleStyle(); defaultCellStyle.setStyleName("Default"); defaultCellStyle.setTextProperties(mainDefaultCellStyle.getStyleTextProperties()); defaultCellStyle.setStyleProperties(mainDefaultCellStyle.getStyleProperties()); this.autoStyles.addStyle(defaultCellStyle); this.masterStyles = masters; } public void loadFrom(final File f) { final SaxContentUnmarshaller contentHandler = new SaxContentUnmarshaller(this); final SaxStylesUnmarshaller stylesHandler = new SaxStylesUnmarshaller(); try { this.zipFile = new ZipFile(f); final XMLReader rdr = XMLReaderFactory.createXMLReader(); rdr.setContentHandler(contentHandler); final ZipEntry contnetEntry = this.zipFile.getEntry("content.xml"); final InputSource inputSource1 = new InputSource(new InputStreamReader(this.zipFile.getInputStream(contnetEntry), "UTF-8")); rdr.parse(inputSource1); rdr.setContentHandler(stylesHandler); final ZipEntry stylesEntry = this.zipFile.getEntry("styles.xml"); if (stylesEntry != null) { final InputSource inputSource2 = new InputSource(new InputStreamReader(this.zipFile.getInputStream(stylesEntry), "UTF-8")); rdr.parse(inputSource2); } } catch (final Exception e1) { e1.printStackTrace(); } this.init(contentHandler.getBody(), contentHandler.getAutomaticstyles(), stylesHandler.getStyles(), stylesHandler.getAutomaticStyles(), stylesHandler.getMasterStyles()); } public void loadFrom(final String fileName) { this.loadFrom(new File(fileName)); } public void loadFrom(final URL url) throws IOException { if (!url.getPath().toLowerCase().endsWith(".ods")) { throw new IllegalArgumentException("This class is only for ODS files"); } final File file = File.createTempFile("jOpenDocument", ".ods"); file.deleteOnExit(); final FileOutputStream fileOutputStream = new FileOutputStream(file); StreamUtils.copy(url.openStream(), fileOutputStream); fileOutputStream.close(); this.loadFrom(file); } public void preloadImage(final String xlinkHref) { this.getImage(xlinkHref); } public void setAutomaticStyles(final OfficeAutomaticStyles autostyles) { this.autoStyles = autostyles; } public void setMasterStyles(final OfficeMasterStyles masterStyles) { this.masterStyles = masterStyles; } }