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