diff --git a/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/SharedStringSource.java b/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/SharedStringSource.java index 6979a7c7e..3a2794caf 100644 --- a/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/SharedStringSource.java +++ b/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/SharedStringSource.java @@ -39,9 +39,4 @@ public interface SharedStringSource { * @return The 0-based position of the newly added string. */ public int putSharedString(String s); - - /** - * Write back out - */ - public void save() throws IOException; } diff --git a/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/StylesSource.java b/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/StylesSource.java index dc328ff10..45a11a46a 100644 --- a/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/StylesSource.java +++ b/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/StylesSource.java @@ -16,14 +16,10 @@ ==================================================================== */ package org.apache.poi.ss.usermodel; -import java.io.IOException; - public interface StylesSource { public String getNumberFormatAt(long idx); public long putNumberFormat(String fmt); - /** - * Write back out - */ - public void save() throws IOException; + public Font getFontAt(long idx); + public long putFont(Font font); } diff --git a/src/ooxml/java/org/apache/poi/xssf/model/SharedStringsTable.java b/src/ooxml/java/org/apache/poi/xssf/model/SharedStringsTable.java index 33e5bfe81..c6d8d2a86 100644 --- a/src/ooxml/java/org/apache/poi/xssf/model/SharedStringsTable.java +++ b/src/ooxml/java/org/apache/poi/xssf/model/SharedStringsTable.java @@ -25,7 +25,6 @@ import java.util.LinkedList; import org.apache.poi.ss.usermodel.SharedStringSource; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlOptions; -import org.openxml4j.opc.PackagePart; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRst; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSst; import org.openxmlformats.schemas.spreadsheetml.x2006.main.SstDocument; @@ -34,32 +33,28 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.SstDocument; /** * Table of strings shared across all sheets in a workbook. * - * FIXME: I don't like having a dependency on PackagePart (from OpenXML4J) in model classes. - * I'd rather let Workbook keep track of all part-document relationships and keep all other - * classes clean. -- Ugo - * * @version $Id$ */ public class SharedStringsTable implements SharedStringSource, XSSFModel { private final LinkedList strings = new LinkedList(); + private SstDocument doc; - private PackagePart part; - /** - * Create a new SharedStringsTable by reading it from a PackagePart. + * Create a new SharedStringsTable, by reading it + * from the InputStream of a PackagePart. * - * @param part The PackagePart to read. + * @param is The input stream containing the XML document. * @throws IOException if an error occurs while reading. */ - public SharedStringsTable(PackagePart part) throws IOException { - this.part = part; - InputStream is = part.getInputStream(); - try { - readFrom(is); - } finally { - if (is != null) is.close(); - } + public SharedStringsTable(InputStream is) throws IOException { + readFrom(is); + } + /** + * Create a new, empty SharedStringsTable + */ + public SharedStringsTable() { + doc = SstDocument.Factory.newInstance(); } /** @@ -70,7 +65,7 @@ public class SharedStringsTable implements SharedStringSource, XSSFModel { */ public void readFrom(InputStream is) throws IOException { try { - SstDocument doc = SstDocument.Factory.parse(is); + doc = SstDocument.Factory.parse(is); for (CTRst rst : doc.getSst().getSiArray()) { strings.add(rst.getT()); } @@ -91,20 +86,6 @@ public class SharedStringsTable implements SharedStringSource, XSSFModel { return strings.size() - 1; } - /** - * Save this table to its own PackagePart. - * - * @throws IOException if an error occurs while writing. - */ - public void save() throws IOException { - OutputStream out = this.part.getOutputStream(); - try { - writeTo(out); - } finally { - out.close(); - } - } - /** * Write this table out as XML. * diff --git a/src/ooxml/java/org/apache/poi/xssf/model/StylesTable.java b/src/ooxml/java/org/apache/poi/xssf/model/StylesTable.java index 122a1b440..c5227c1c1 100644 --- a/src/ooxml/java/org/apache/poi/xssf/model/StylesTable.java +++ b/src/ooxml/java/org/apache/poi/xssf/model/StylesTable.java @@ -25,13 +25,14 @@ import java.util.Hashtable; import java.util.LinkedList; import java.util.Map.Entry; +import org.apache.poi.ss.usermodel.Font; import org.apache.poi.ss.usermodel.StylesSource; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlOptions; -import org.openxml4j.opc.PackagePart; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBorder; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTFill; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTFont; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTFonts; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTNumFmt; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTNumFmts; import org.openxmlformats.schemas.spreadsheetml.x2006.main.StyleSheetDocument;; @@ -40,10 +41,6 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.StyleSheetDocument;; /** * Table of styles shared across all sheets in a workbook. * - * FIXME: I don't like having a dependency on PackagePart (from OpenXML4J) in model classes. - * I'd rather let Workbook keep track of all part-document relationships and keep all other - * classes clean. -- Ugo - * * @version $Id: SharedStringsTable.java 612495 2008-01-16 16:08:22Z ugo $ */ public class StylesTable implements StylesSource, XSSFModel { @@ -52,23 +49,28 @@ public class StylesTable implements StylesSource, XSSFModel { private final LinkedList fills = new LinkedList(); private final LinkedList borders = new LinkedList(); - private PackagePart part; + /** + * The first style id available for use as a custom style + */ + public static final long FIRST_CUSTOM_STYLE_ID = 165; + private StyleSheetDocument doc; /** - * Create a new StylesTable by reading it from a PackagePart. + * Create a new StylesTable, by reading it from + * the InputStream of a a PackagePart. * - * @param part The PackagePart to read. + * @param is The input stream containing the XML document. * @throws IOException if an error occurs while reading. */ - public StylesTable(PackagePart part) throws IOException { - this.part = part; - InputStream is = part.getInputStream(); - try { - readFrom(is); - } finally { - if (is != null) is.close(); - } + public StylesTable(InputStream is) throws IOException { + readFrom(is); + } + /** + * Create a new, empty StylesTable + */ + public StylesTable() { + doc = StyleSheetDocument.Factory.newInstance(); } /** @@ -106,7 +108,6 @@ public class StylesTable implements StylesSource, XSSFModel { public String getNumberFormatAt(long idx) { return numberFormats.get(idx); } - public synchronized long putNumberFormat(String fmt) { if (numberFormats.containsValue(fmt)) { // Find the key, and return that @@ -120,7 +121,7 @@ public class StylesTable implements StylesSource, XSSFModel { } // Find a spare key, and add that - long newKey = 1; + long newKey = FIRST_CUSTOM_STYLE_ID; while(numberFormats.containsKey(newKey)) { newKey++; } @@ -128,6 +129,15 @@ public class StylesTable implements StylesSource, XSSFModel { return newKey; } + public Font getFontAt(long idx) { + // TODO + return null; + } + public synchronized long putFont(Font font) { + // TODO + return -1; + } + /** * For unit testing only */ @@ -154,20 +164,6 @@ public class StylesTable implements StylesSource, XSSFModel { } - /** - * Save this table to its own PackagePart. - * - * @throws IOException if an error occurs while writing. - */ - public void save() throws IOException { - OutputStream out = this.part.getOutputStream(); - try { - writeTo(out); - } finally { - out.close(); - } - } - /** * Write this table out as XML. * @@ -193,7 +189,12 @@ public class StylesTable implements StylesSource, XSSFModel { doc.getStyleSheet().setNumFmts(formats); // Fonts - // TODO + CTFonts fnts = CTFonts.Factory.newInstance(); + fnts.setCount(fonts.size()); + fnts.setFontArray( + fonts.toArray(new CTFont[fonts.size()]) + ); + doc.getStyleSheet().setFonts(fnts); // Fills // TODO diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java index 57d37a404..62d6878fd 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java @@ -18,7 +18,9 @@ package org.apache.poi.xssf.usermodel; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; +import java.lang.reflect.Constructor; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -65,22 +67,6 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorksheetDocument; public class XSSFWorkbook extends POIXMLDocument implements Workbook { - public static class XSSFRelation { - private String TYPE; - private String REL; - private String DEFAULT_NAME; - private Class CLASS; - private XSSFRelation(String TYPE, String REL, String DEFAULT_NAME, Class CLASS) { - this.TYPE = TYPE; - this.REL = REL; - this.DEFAULT_NAME = DEFAULT_NAME; - this.CLASS = CLASS; - } - public String getContentType() { return TYPE; } - public String getRelation() { return REL; } - public String getDefaultFileName() { return DEFAULT_NAME; } - } - public static final XSSFRelation WORKSHEET = new XSSFRelation( "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet", @@ -112,6 +98,70 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook { null ); + public static class XSSFRelation { + private String TYPE; + private String REL; + private String DEFAULT_NAME; + private Class CLASS; + private XSSFRelation(String TYPE, String REL, String DEFAULT_NAME, Class CLASS) { + this.TYPE = TYPE; + this.REL = REL; + this.DEFAULT_NAME = DEFAULT_NAME; + this.CLASS = CLASS; + } + public String getContentType() { return TYPE; } + public String getRelation() { return REL; } + public String getDefaultFileName() { return DEFAULT_NAME; } + + /** + * Load, off the specified core part + */ + private XSSFModel load(PackagePart corePart) throws Exception { + Constructor c = CLASS.getConstructor(InputStream.class); + XSSFModel model = null; + + PackageRelationshipCollection prc = + corePart.getRelationshipsByType(REL); + Iterator it = prc.iterator(); + if(it.hasNext()) { + PackageRelationship rel = it.next(); + PackagePartName relName = PackagingURIHelper.createPartName(rel.getTargetURI()); + PackagePart part = corePart.getPackage().getPart(relName); + InputStream is = part.getInputStream(); + try { + model = c.newInstance(is); + } finally { + is.close(); + } + } else { + log.log(POILogger.WARN, "No part " + DEFAULT_NAME + " found"); + } + return model; + } + /** + * Save, with the default name + */ + private void save(XSSFModel model, PackagePart corePart) throws IOException { + save(model, corePart, DEFAULT_NAME); + } + /** + * Save, with the specified name + */ + private void save(XSSFModel model, PackagePart corePart, String name) throws IOException { + PackagePartName ppName = null; + try { + ppName = PackagingURIHelper.createPartName(name); + } catch(InvalidFormatException e) { + throw new IllegalStateException(e); + } + corePart.addRelationship(ppName, TargetMode.INTERNAL, REL); + PackagePart part = corePart.getPackage().createPart(ppName, TYPE); + OutputStream out = part.getOutputStream(); + model.writeTo(out); + out.close(); + } + } + private CTWorkbook workbook; private List sheets = new LinkedList(); @@ -138,34 +188,22 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook { WorkbookDocument doc = WorkbookDocument.Factory.parse(getCorePart().getInputStream()); this.workbook = doc.getWorkbook(); - PackageRelationshipCollection prc; - Iterator it; - - // Load shared strings - prc = getCorePart().getRelationshipsByType(SHARED_STRINGS.getRelation()); - it = prc.iterator(); - if (it.hasNext()) { - PackageRelationship rel = it.next(); - PackagePart part = getTargetPart(rel); - this.sharedStringSource = new SharedStringsTable(part); - } else { - log.log(POILogger.WARN, "No shared strings part found"); - } - // Load styles source - prc = getCorePart().getRelationshipsByType(STYLES.getRelation()); - it = prc.iterator(); - if (it.hasNext()) { - PackageRelationship rel = it.next(); - PackagePart part = getTargetPart(rel); - this.stylesSource = new StylesTable(part); - } else { - log.log(POILogger.WARN, "No styles part found"); + try { + // Load shared strings + this.sharedStringSource = (SharedStringSource) + SHARED_STRINGS.load(getCorePart()); + // Load styles source + this.stylesSource = (StylesSource) + STYLES.load(getCorePart()); + } catch(Exception e) { + throw new IOException(e.getMessage()); } // Load individual sheets for (CTSheet ctSheet : this.workbook.getSheets().getSheetArray()) { PackagePart part = getPackagePart(ctSheet); if (part == null) { + log.log(POILogger.WARN, "Sheet with name " + ctSheet.getName() + " was defined, but didn't exist, skipping"); continue; } WorksheetDocument worksheetDoc = WorksheetDocument.Factory.parse(part.getInputStream()); @@ -572,21 +610,11 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook { // Write shared strings and styles if(sharedStringSource != null) { SharedStringsTable sst = (SharedStringsTable)sharedStringSource; - PackagePartName sstName = PackagingURIHelper.createPartName(SHARED_STRINGS.getDefaultFileName()); - corePart.addRelationship(sstName, TargetMode.INTERNAL, SHARED_STRINGS.getRelation()); - PackagePart sstPart = pkg.createPart(sstName, SHARED_STRINGS.getContentType()); - out = sstPart.getOutputStream(); - sst.writeTo(out); - out.close(); + SHARED_STRINGS.save(sst, corePart); } if(stylesSource != null) { StylesTable st = (StylesTable)stylesSource; - PackagePartName stName = PackagingURIHelper.createPartName(STYLES.getDefaultFileName()); - corePart.addRelationship(stName, TargetMode.INTERNAL, STYLES.getRelation()); - PackagePart stPart = pkg.createPart(stName, STYLES.getContentType()); - out = stPart.getOutputStream(); - st.writeTo(out); - out.close(); + STYLES.save(st, corePart); } // All done diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java index 89a066107..f99dbebac 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java @@ -31,8 +31,17 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook; public class TestXSSFWorkbook extends TestCase { - - public void testGetSheetIndex() { + public TestXSSFWorkbook(String name) { + super(name); + + // Use system out logger + System.setProperty( + "org.apache.poi.util.POILogger", + "org.apache.poi.util.SystemOutLogger" + ); + } + + public void testGetSheetIndex() { XSSFWorkbook workbook = new XSSFWorkbook(); Sheet sheet1 = workbook.createSheet("sheet1"); Sheet sheet2 = workbook.createSheet("sheet2"); @@ -127,7 +136,7 @@ public class TestXSSFWorkbook extends TestCase { Sheet sheet2 = workbook.createSheet("sheet2"); Sheet sheet3 = workbook.createSheet("sheet3"); File file = File.createTempFile("poi-", ".xlsx"); - System.out.println("Saving to " + file.getAbsolutePath()); + System.out.println("Saving newly created file to " + file.getAbsolutePath()); OutputStream out = new FileOutputStream(file); workbook.write(out); out.close(); @@ -194,5 +203,17 @@ public class TestXSSFWorkbook extends TestCase { assertEquals(2, st._getFillsSize()); // Has 1 border assertEquals(1, st._getBordersSize()); + + // Add two more styles + assertEquals(StylesTable.FIRST_CUSTOM_STYLE_ID + 8, + st.putNumberFormat("testFORMAT")); + assertEquals(StylesTable.FIRST_CUSTOM_STYLE_ID + 8, + st.putNumberFormat("testFORMAT")); + assertEquals(StylesTable.FIRST_CUSTOM_STYLE_ID + 9, + st.putNumberFormat("testFORMAT2")); + assertEquals(10, st._getNumberFormatSize()); + + // Save, load back in again, and check + // TODO } }