[Bug 61972] Adding chart in Document of MS-Word File without reading Temp MS-Word File. Thanks to Sandeep Tiwari. This closes #91

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1821764 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
PJ Fanning 2018-01-20 23:01:18 +00:00
parent f628f27f5b
commit 48a5e63ad7
11 changed files with 1029 additions and 579 deletions

View File

@ -39,11 +39,12 @@ import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
import org.apache.poi.xddf.usermodel.chart.XDDFChart;
import org.apache.poi.xssf.usermodel.XSSFRelation; import org.apache.poi.xssf.usermodel.XSSFRelation;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
/** /**
* Represents an entry of a OOXML package. * Represents an entry of a OOXML package.
*
* <p> * <p>
* Each POIXMLDocumentPart keeps a reference to the underlying a {@link org.apache.poi.openxml4j.opc.PackagePart}. * Each POIXMLDocumentPart keeps a reference to the underlying a {@link org.apache.poi.openxml4j.opc.PackagePart}.
* </p> * </p>
@ -55,6 +56,25 @@ public class POIXMLDocumentPart {
private PackagePart packagePart; private PackagePart packagePart;
private POIXMLDocumentPart parent; private POIXMLDocumentPart parent;
private Map<String, RelationPart> relations = new LinkedHashMap<>(); private Map<String, RelationPart> relations = new LinkedHashMap<>();
private boolean isCommited = false;
/**
* to check whether embedded part is already committed
*
* @return return true if embedded part is committed
*/
public boolean isCommited() {
return isCommited;
}
/**
* setter method to set embedded part is committed
*
* @param isCommited boolean value
*/
public void setCommited(boolean isCommited) {
this.isCommited = isCommited;
}
/** /**
* The RelationPart is a cached relationship between the document, which contains the RelationPart, * The RelationPart is a cached relationship between the document, which contains the RelationPart,
@ -80,7 +100,6 @@ public class POIXMLDocumentPart {
/** /**
* @param <T> the cast of the caller to a document sub class * @param <T> the cast of the caller to a document sub class
*
* @return the child document part * @return the child document part
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -143,7 +162,6 @@ public class POIXMLDocumentPart {
* *
* @param part - The package part that holds xml data representing this sheet. * @param part - The package part that holds xml data representing this sheet.
* @see #read(POIXMLFactory, java.util.Map) * @see #read(POIXMLFactory, java.util.Map)
*
* @since POI 3.14-Beta1 * @since POI 3.14-Beta1
*/ */
public POIXMLDocumentPart(PackagePart part) { public POIXMLDocumentPart(PackagePart part) {
@ -157,7 +175,6 @@ public class POIXMLDocumentPart {
* @param parent - Parent part * @param parent - Parent part
* @param part - The package part that holds xml data representing this sheet. * @param part - The package part that holds xml data representing this sheet.
* @see #read(POIXMLFactory, java.util.Map) * @see #read(POIXMLFactory, java.util.Map)
*
* @since POI 3.14-Beta1 * @since POI 3.14-Beta1
*/ */
public POIXMLDocumentPart(POIXMLDocumentPart parent, PackagePart part) { public POIXMLDocumentPart(POIXMLDocumentPart parent, PackagePart part) {
@ -171,7 +188,6 @@ public class POIXMLDocumentPart {
* current core document * current core document
* *
* @param pkg the package to be rebased * @param pkg the package to be rebased
*
* @throws InvalidFormatException if there was an error in the core document relation * @throws InvalidFormatException if there was an error in the core document relation
* @throws IllegalStateException if there are more than one core document relations * @throws IllegalStateException if there are more than one core document relations
*/ */
@ -226,8 +242,7 @@ public class POIXMLDocumentPart {
* {@link POIXMLDocumentPart} with a {@link PackageRelationship#getId()} * {@link POIXMLDocumentPart} with a {@link PackageRelationship#getId()}
* matching the given parameter value. * matching the given parameter value.
* *
* @param id * @param id The relation id to look for
* The relation id to look for
* @return the target part of the relation, or null, if none exists * @return the target part of the relation, or null, if none exists
*/ */
public final POIXMLDocumentPart getRelationById(String id) { public final POIXMLDocumentPart getRelationById(String id) {
@ -242,10 +257,8 @@ public class POIXMLDocumentPart {
* {@link POIXMLDocumentPart} with a {@link PackageRelationship#getId()} * {@link POIXMLDocumentPart} with a {@link PackageRelationship#getId()}
* matching the given parameter value. * matching the given parameter value.
* *
* @param id * @param id The relation id to look for
* The relation id to look for
* @return the target relation part, or null, if none exists * @return the target relation part, or null, if none exists
*
* @since 4.0.0 * @since 4.0.0
*/ */
public final RelationPart getRelationPartById(String id) { public final RelationPart getRelationPartById(String id) {
@ -257,12 +270,11 @@ public class POIXMLDocumentPart {
* {@link PackageRelationship}, that sources from the {@link PackagePart} of * {@link PackageRelationship}, that sources from the {@link PackagePart} of
* this {@link POIXMLDocumentPart} to the {@link PackagePart} of the given * this {@link POIXMLDocumentPart} to the {@link PackagePart} of the given
* parameter value.<p> * parameter value.<p>
* * <p>
* There can be multiple references to the given {@link POIXMLDocumentPart} * There can be multiple references to the given {@link POIXMLDocumentPart}
* and only the first in the order of creation is returned. * and only the first in the order of creation is returned.
* *
* @param part * @param part The {@link POIXMLDocumentPart} for which the according
* The {@link POIXMLDocumentPart} for which the according
* relation-id shall be found. * relation-id shall be found.
* @return The value of the {@link PackageRelationship#getId()} or null, if * @return The value of the {@link PackageRelationship#getId()} or null, if
* parts are not related. * parts are not related.
@ -282,9 +294,7 @@ public class POIXMLDocumentPart {
* @param relId the preferred relation id, when null the next free relation id will be used * @param relId the preferred relation id, when null the next free relation id will be used
* @param relationshipType the package relationship type * @param relationshipType the package relationship type
* @param part the child to add * @param part the child to add
*
* @return the new RelationPart * @return the new RelationPart
*
* @since 3.14-Beta1 * @since 3.14-Beta1
*/ */
public final RelationPart addRelation(String relId, POIXMLRelation relationshipType, POIXMLDocumentPart part) { public final RelationPart addRelation(String relId, POIXMLRelation relationshipType, POIXMLDocumentPart part) {
@ -313,7 +323,7 @@ public class POIXMLDocumentPart {
/** /**
* Remove the relation to the specified part in this package and remove the * Remove the relation to the specified part in this package and remove the
* part, if it is no longer needed.<p> * part, if it is no longer needed.<p>
* * <p>
* If there are multiple relationships to the same part, this will only * If there are multiple relationships to the same part, this will only
* remove the first relationship in the order of creation. The removal * remove the first relationship in the order of creation. The removal
* via the part id ({@link #removeRelation(String)} is preferred. * via the part id ({@link #removeRelation(String)} is preferred.
@ -327,15 +337,13 @@ public class POIXMLDocumentPart {
/** /**
* Remove the relation to the specified part in this package and remove the * Remove the relation to the specified part in this package and remove the
* part, if it is no longer needed and flag is set to true.<p> * part, if it is no longer needed and flag is set to true.<p>
* * <p>
* If there are multiple relationships to the same part, this will only * If there are multiple relationships to the same part, this will only
* remove the first relationship in the order of creation. The removal * remove the first relationship in the order of creation. The removal
* via the part id ({@link #removeRelation(String, boolean)} is preferred. * via the part id ({@link #removeRelation(String, boolean)} is preferred.
* *
* @param part * @param part The related part, to which the relation shall be removed.
* The related part, to which the relation shall be removed. * @param removeUnusedParts true, if the part shall be removed from the package if not
* @param removeUnusedParts
* true, if the part shall be removed from the package if not
* needed any longer. * needed any longer.
* @return true, if the relation was removed * @return true, if the relation was removed
*/ */
@ -347,13 +355,12 @@ public class POIXMLDocumentPart {
/** /**
* Remove the relation to the specified part in this package and remove the * Remove the relation to the specified part in this package and remove the
* part, if it is no longer needed.<p> * part, if it is no longer needed.<p>
* * <p>
* If there are multiple relationships to the same part, this will only * If there are multiple relationships to the same part, this will only
* remove the first relationship in the order of creation. The removal * remove the first relationship in the order of creation. The removal
* via the part id ({@link #removeRelation(String)} is preferred. * via the part id ({@link #removeRelation(String)} is preferred.
* *
* @param partId the part id which relation is to be removed from this document * @param partId the part id which relation is to be removed from this document
*
* @since 4.0.0 * @since 4.0.0
*/ */
protected final void removeRelation(String partId) { protected final void removeRelation(String partId) {
@ -364,13 +371,10 @@ public class POIXMLDocumentPart {
* Remove the relation to the specified part in this package and remove the * Remove the relation to the specified part in this package and remove the
* part, if it is no longer needed and flag is set to true.<p> * part, if it is no longer needed and flag is set to true.<p>
* *
* @param partId * @param partId The related part id, to which the relation shall be removed.
* The related part id, to which the relation shall be removed. * @param removeUnusedParts true, if the part shall be removed from the package if not
* @param removeUnusedParts
* true, if the part shall be removed from the package if not
* needed any longer. * needed any longer.
* @return true, if the relation was removed * @return true, if the relation was removed
*
* @since 4.0.0 * @since 4.0.0
*/ */
private final boolean removeRelation(String partId, boolean removeUnusedParts) { private final boolean removeRelation(String partId, boolean removeUnusedParts) {
@ -402,7 +406,6 @@ public class POIXMLDocumentPart {
} }
/** /**
* Returns the parent POIXMLDocumentPart. All parts except root have not-null parent. * Returns the parent POIXMLDocumentPart. All parts except root have not-null parent.
* *
@ -420,9 +423,9 @@ public class POIXMLDocumentPart {
/** /**
* Save the content in the underlying package part. * Save the content in the underlying package part.
* Default implementation is empty meaning that the package part is left unmodified. * Default implementation is empty meaning that the package part is left unmodified.
* * <p>
* Sub-classes should override and add logic to marshal the "model" into Ooxml4J. * Sub-classes should override and add logic to marshal the "model" into Ooxml4J.
* * <p>
* For example, the code saving a generic XML entry may look as follows: * For example, the code saving a generic XML entry may look as follows:
* <pre> * <pre>
* protected void commit() throws IOException { * protected void commit() throws IOException {
@ -445,10 +448,14 @@ public class POIXMLDocumentPart {
* Recursively fires {@link #commit()} for each package part * Recursively fires {@link #commit()} for each package part
* *
* @param alreadySaved context set containing already visited nodes * @param alreadySaved context set containing already visited nodes
*
* @throws IOException a related part may throw an IOException if the changes can't be saved * @throws IOException a related part may throw an IOException if the changes can't be saved
*/ */
protected final void onSave(Set<PackagePart> alreadySaved) throws IOException { protected final void onSave(Set<PackagePart> alreadySaved) throws IOException {
//if part is already committed then return
if (this.isCommited) {
return;
}
// this usually clears out previous content in the part... // this usually clears out previous content in the part...
prepareForCommit(); prepareForCommit();
@ -465,7 +472,7 @@ public class POIXMLDocumentPart {
/** /**
* Ensure that a memory based package part does not have lingering data from previous * Ensure that a memory based package part does not have lingering data from previous
* commit() calls. * commit() calls.
* * <p>
* Note: This is overwritten for some objects, as *PictureData seem to store the actual content * Note: This is overwritten for some objects, as *PictureData seem to store the actual content
* in the part directly without keeping a copy like all others therefore we need to handle them differently. * in the part directly without keeping a copy like all others therefore we need to handle them differently.
*/ */
@ -482,8 +489,7 @@ public class POIXMLDocumentPart {
* @param descriptor the part descriptor * @param descriptor the part descriptor
* @param factory the factory that will create an instance of the requested relation * @param factory the factory that will create an instance of the requested relation
* @return the created child POIXMLDocumentPart * @return the created child POIXMLDocumentPart
* @throws PartAlreadyExistsException * @throws PartAlreadyExistsException If rule M1.12 is not verified : Packages shall not contain
* If rule M1.12 is not verified : Packages shall not contain
* equivalent part names and package implementers shall neither * equivalent part names and package implementers shall neither
* create nor recognize packages with equivalent part names. * create nor recognize packages with equivalent part names.
*/ */
@ -498,8 +504,7 @@ public class POIXMLDocumentPart {
* @param factory the factory that will create an instance of the requested relation * @param factory the factory that will create an instance of the requested relation
* @param idx part number * @param idx part number
* @return the created child POIXMLDocumentPart * @return the created child POIXMLDocumentPart
* @throws PartAlreadyExistsException * @throws PartAlreadyExistsException If rule M1.12 is not verified : Packages shall not contain
* If rule M1.12 is not verified : Packages shall not contain
* equivalent part names and package implementers shall neither * equivalent part names and package implementers shall neither
* create nor recognize packages with equivalent part names. * create nor recognize packages with equivalent part names.
*/ */
@ -566,8 +571,7 @@ public class POIXMLDocumentPart {
* @param idx part number * @param idx part number
* @param noRelation if true, then no relationship is added. * @param noRelation if true, then no relationship is added.
* @return the created child POIXMLDocumentPart * @return the created child POIXMLDocumentPart
* @throws PartAlreadyExistsException * @throws PartAlreadyExistsException If rule M1.12 is not verified : Packages shall not contain
* If rule M1.12 is not verified : Packages shall not contain
* equivalent part names and package implementers shall neither * equivalent part names and package implementers shall neither
* create nor recognize packages with equivalent part names. * create nor recognize packages with equivalent part names.
*/ */
@ -605,7 +609,6 @@ public class POIXMLDocumentPart {
* *
* @param factory the factory object that creates POIXMLFactory instances * @param factory the factory object that creates POIXMLFactory instances
* @param context context map containing already visited noted keyed by targetURI * @param context context map containing already visited noted keyed by targetURI
*
* @throws OpenXML4JException thrown when a related part can't be read * @throws OpenXML4JException thrown when a related part can't be read
*/ */
protected void read(POIXMLFactory factory, Map<PackagePart, POIXMLDocumentPart> context) throws OpenXML4JException { protected void read(POIXMLFactory factory, Map<PackagePart, POIXMLDocumentPart> context) throws OpenXML4JException {
@ -643,6 +646,11 @@ public class POIXMLDocumentPart {
POIXMLDocumentPart childPart = context.get(p); POIXMLDocumentPart childPart = context.get(p);
if (childPart == null) { if (childPart == null) {
childPart = factory.createDocumentPart(this, p); childPart = factory.createDocumentPart(this, p);
//here we are checking if part if embedded and excel then set it to chart class
//so that at the time to writing we can also write updated embedded part
if (this instanceof XDDFChart && childPart instanceof XSSFWorkbook) {
((XDDFChart) this).setWorkbook((XSSFWorkbook) childPart);
}
childPart.parent = this; childPart.parent = this;
// already add child to context, so other children can reference it // already add child to context, so other children can reference it
context.put(p, childPart); context.put(p, childPart);
@ -704,10 +712,10 @@ public class POIXMLDocumentPart {
* from {@link org.apache.poi.xwpf.usermodel.XWPFDocument} without reflection. It should be removed. * from {@link org.apache.poi.xwpf.usermodel.XWPFDocument} without reflection. It should be removed.
* *
* @param part the part which is to be read * @param part the part which is to be read
*
* @throws IOException if the part can't be read * @throws IOException if the part can't be read
*/ */
@Internal @Deprecated @Internal
@Deprecated
public static void _invokeOnDocumentRead(POIXMLDocumentPart part) throws IOException { public static void _invokeOnDocumentRead(POIXMLDocumentPart part) throws IOException {
part.onDocumentRead(); part.onDocumentRead();
} }

View File

@ -22,6 +22,7 @@ package org.apache.poi.xddf.usermodel.chart;
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS; import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -29,12 +30,32 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.xml.namespace.QName;
import org.apache.poi.POIXMLDocument;
import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.POIXMLException;
import org.apache.poi.POIXMLFactory;
import org.apache.poi.POIXMLRelation;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.exceptions.NotOfficeXmlFileException;
import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.xddf.usermodel.XDDFShapeProperties; import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
import org.apache.poi.xslf.usermodel.XSLFChart;
import org.apache.poi.xslf.usermodel.XSLFFactory;
import org.apache.poi.xslf.usermodel.XSLFRelation;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.usermodel.XWPFFactory;
import org.apache.poi.xwpf.usermodel.XWPFRelation;
import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTBarChart; import org.openxmlformats.schemas.drawingml.x2006.chart.CTBarChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTBoolean; import org.openxmlformats.schemas.drawingml.x2006.chart.CTBoolean;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTCatAx; import org.openxmlformats.schemas.drawingml.x2006.chart.CTCatAx;
@ -54,6 +75,13 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
@Beta @Beta
public abstract class XDDFChart extends POIXMLDocumentPart { public abstract class XDDFChart extends POIXMLDocumentPart {
/**
* Underlying workbook
*/
private XSSFWorkbook workbook;
private int chartIndex = 0;
protected List<XDDFChartAxis> axes = new ArrayList<>(); protected List<XDDFChartAxis> axes = new ArrayList<>();
/** /**
@ -82,7 +110,6 @@ public abstract class XDDFChart extends POIXMLDocumentPart {
* *
* @param part the package part holding the chart data, * @param part the package part holding the chart data,
* the content type must be <code>application/vnd.openxmlformats-officedocument.drawingml.chart+xml</code> * the content type must be <code>application/vnd.openxmlformats-officedocument.drawingml.chart+xml</code>
*
* @since POI 3.14-Beta1 * @since POI 3.14-Beta1
*/ */
protected XDDFChart(PackagePart part) throws IOException, XmlException { protected XDDFChart(PackagePart part) throws IOException, XmlException {
@ -206,8 +233,10 @@ public abstract class XDDFChart extends POIXMLDocumentPart {
} }
public void plot(XDDFChartData data) { public void plot(XDDFChartData data) {
XSSFSheet sheet = getSheet();
for (XDDFChartData.Series series : data.getSeries()) { for (XDDFChartData.Series series : data.getSeries()) {
series.plot(); series.plot();
fillSheet(sheet, series.getCategoryData(), series.getValuesData());
} }
} }
@ -347,4 +376,247 @@ public abstract class XDDFChart extends POIXMLDocumentPart {
} }
} }
/**
* method to create relationship with embedded part
* for example writing xlsx file stream into output stream
*
* @param chartRelation relationship object
* @param chartFactory ChartFactory object
* @param chartIndex index used to suffix on file
* @return return relation part which used to write relation in .rels file and get relation id
* @since POI 4.0.0
*/
public PackageRelationship createRelationshipInChart(POIXMLRelation chartRelation, POIXMLFactory chartFactory, int chartIndex) {
POIXMLDocumentPart documentPart = createRelationship(chartRelation, chartFactory, chartIndex, true).getDocumentPart();
documentPart.setCommited(true);
return this.addRelation(null, chartRelation, documentPart).getRelationship();
}
/**
* if embedded part was null then create new part
*
* @param chartRelation chart relation object
* @param chartWorkbookRelation chart workbook relation object
* @param chartFactory factory object of POIXMLFactory (XWPFFactory/XSLFFactory)
* @return return the new package part
* @throws InvalidFormatException
* @since POI 4.0.0
*/
private PackagePart createWorksheetPart(POIXMLRelation chartRelation, POIXMLRelation chartWorkbookRelation, POIXMLFactory chartFactory) throws InvalidFormatException {
PackageRelationship xlsx = createRelationshipInChart(XSLFRelation.WORKBOOK_RELATIONSHIP, XSLFFactory.getInstance(), chartIndex);
this.setExternalId(xlsx.getId());
return getTargetPart(xlsx);
}
/**
* this method write the XSSFWorkbook object data into embedded excel file
*
* @param workbook XSSFworkbook object
* @throws IOException
* @throws InvalidFormatException
* @since POI 4.0.0
*/
public void saveWorkbook(XSSFWorkbook workbook) throws IOException, InvalidFormatException {
PackagePart worksheetPart = getWorksheetPart(true);
if (worksheetPart == null) {
POIXMLRelation chartRelation = null;
POIXMLRelation chartWorkbookRelation = null;
POIXMLFactory chartFactory = null;
if (this instanceof XSLFChart) {
chartRelation = XSLFRelation.CHART;
chartWorkbookRelation = XSLFRelation.WORKBOOK_RELATIONSHIP;
chartFactory = XSLFFactory.getInstance();
} else {
chartRelation = XWPFRelation.CHART;
chartRelation = XWPFRelation.WORKBOOK_RELATIONSHIP;
chartFactory = XWPFFactory.getInstance();
}
worksheetPart = createWorksheetPart(chartRelation, chartWorkbookRelation, chartFactory);
}
try (OutputStream xlsOut = worksheetPart.getOutputStream()) {
workbook.write(xlsOut);
}
}
/**
* this method writes the data into sheet
*
* @param sheet sheet of embedded excel
* @param categoryData category values
* @param valuesData data values
* @since POI 4.0.0
*/
protected void fillSheet(XSSFSheet sheet, XDDFDataSource<?> categoryData, XDDFNumericalDataSource<?> valuesData) {
int numOfPoints = categoryData.getPointCount();
for (int i = 0; i < numOfPoints; i++) {
XSSFRow row = sheet.createRow(i + 1); // first row is for title
row.createCell(0).setCellValue(categoryData.getPointAt(i).toString());
row.createCell(1).setCellValue(valuesData.getPointAt(i).doubleValue());
}
}
/**
* import content from other chart to created chart
*
* @param other chart object
* @since POI 4.0.0
*/
public void importContent(XDDFChart other) {
this.chart.set(other.chart);
}
/**
* save chart xml
*/
@Override
protected void commit() throws IOException {
XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
xmlOptions.setSaveSyntheticDocumentElement(new QName(CTChartSpace.type.getName().getNamespaceURI(), "chartSpace", "c"));
if (workbook != null) {
try {
saveWorkbook(workbook);
} catch (InvalidFormatException e) {
throw new POIXMLException(e);
}
}
PackagePart part = getPackagePart();
try (OutputStream out = part.getOutputStream()) {
chartSpace.save(out, xmlOptions);
}
}
/**
* set sheet time in excel file
*
* @param title title of sheet
* @return return cell reference
* @since POI 4.0.0
*/
public CellReference setSheetTitle(String title) {
XSSFSheet sheet = getSheet();
sheet.createRow(0).createCell(1).setCellValue(title);
return new CellReference(sheet.getSheetName(), 0, 1, true, true);
}
/**
* @param range
* @return
* @since POI 4.0.0
*/
public String formatRange(CellRangeAddress range) {
return range.formatAsString(getSheet().getSheetName(), true);
}
/**
* get sheet object of embedded excel file
*
* @return excel sheet object
* @since POI 4.0.0
*/
private XSSFSheet getSheet() {
XSSFSheet sheet = null;
try {
sheet = getWorkbook().getSheetAt(0);
} catch (InvalidFormatException ife) {
} catch (IOException ioe) {
}
return sheet;
}
/**
* default method for worksheet part
*
* @return return embedded worksheet part
* @throws InvalidFormatException
* @since POI 4.0.0
*/
private PackagePart getWorksheetPart() throws InvalidFormatException {
return getWorksheetPart(false);
}
/**
* this method is used to get worksheet part
* if call is from saveworkbook method then check isCommitted
* isCommitted variable shows that we are writing xssfworkbook object into output stream of embedded part
*
* @param isCommitted if it's true then it shows that we are writing xssfworkbook object into output stream of embedded part
* @return returns the packagepart of embedded file
* @throws InvalidFormatException
* @since POI 4.0.0
*/
private PackagePart getWorksheetPart(boolean isCommitted) throws InvalidFormatException {
for (RelationPart part : getRelationParts()) {
if (POIXMLDocument.PACK_OBJECT_REL_TYPE.equals(part.getRelationship().getRelationshipType())) {
if (isCommitted) {
part.getDocumentPart().setCommited(true);
}
return getTargetPart(part.getRelationship());
}
}
return null;
}
/**
* @return returns the workbook object of embedded excel file
* @throws IOException
* @throws InvalidFormatException
* @since POI 4.0.0
*/
public XSSFWorkbook getWorkbook() throws IOException, InvalidFormatException {
if (workbook == null) {
try {
PackagePart worksheetPart = getWorksheetPart();
if (worksheetPart == null) {
workbook = new XSSFWorkbook();
workbook.createSheet();
} else {
workbook = new XSSFWorkbook(worksheetPart.getInputStream());
}
} catch (NotOfficeXmlFileException e) {
workbook = new XSSFWorkbook();
workbook.createSheet();
}
}
return workbook;
}
/**
* while reading chart from template file then we need to parse and store embedded excel
* file in chart object show that we can modify value according to use
*
* @param workbook workbook object which we read from chart embedded part
* @since POI 4.0.0
*/
public void setWorkbook(XSSFWorkbook workbook) {
this.workbook = workbook;
}
/**
* set the relation id of embedded excel relation id into external data relation tag
*
* @param id relation id of embedded excel relation id into external data relation tag
* @since POI 4.0.0
*/
public void setExternalId(String id) {
getCTChartSpace().addNewExternalData().setId(id);
}
/**
* @return method return chart index
* @since POI 4.0.0
*/
protected int getChartIndex() {
return chartIndex;
}
/**
* set chart index which can be use for relation part
*
* @param chartIndex chart index which can be use for relation part
*/
public void setChartIndex(int chartIndex) {
this.chartIndex = chartIndex;
}
} }

View File

@ -305,16 +305,11 @@ implements SlideShow<XSLFShape,XSLFTextParagraph> {
int chartIdx = findNextAvailableFileNameIndex(XSLFRelation.CHART, _charts.size() + 1); int chartIdx = findNextAvailableFileNameIndex(XSLFRelation.CHART, _charts.size() + 1);
XSLFChart chart = (XSLFChart) createRelationship(XSLFRelation.CHART, XSLFFactory.getInstance(), chartIdx, true).getDocumentPart(); XSLFChart chart = (XSLFChart) createRelationship(XSLFRelation.CHART, XSLFFactory.getInstance(), chartIdx, true).getDocumentPart();
slide.addRelation(null, XSLFRelation.CHART, chart); slide.addRelation(null, XSLFRelation.CHART, chart);
createWorkbookRelationship(chart, chartIdx); chart.setChartIndex(chartIdx);
_charts.add(chart); _charts.add(chart);
return chart; return chart;
} }
protected PackageRelationship createWorkbookRelationship(XSLFChart chart, int chartIdx) {
POIXMLDocumentPart worksheet = createRelationship(XSLFChart.WORKBOOK_RELATIONSHIP, XSLFFactory.getInstance(), chartIdx, true).getDocumentPart();
return chart.addRelation(null, XSLFChart.WORKBOOK_RELATIONSHIP, worksheet).getRelationship();
}
/** /**
* Return notes slide for the specified slide or create new if it does not exist yet. * Return notes slide for the specified slide or create new if it does not exist yet.
*/ */
@ -433,7 +428,6 @@ implements SlideShow<XSLFShape,XSLFTextParagraph> {
} }
/** /**
*
* @param newIndex 0-based index of the slide * @param newIndex 0-based index of the slide
*/ */
public void setSlideOrder(XSLFSlide slide, int newIndex) { public void setSlideOrder(XSLFSlide slide, int newIndex) {
@ -505,7 +499,6 @@ implements SlideShow<XSLFShape,XSLFTextParagraph> {
* *
* @param pictureData The bytes of the picture * @param pictureData The bytes of the picture
* @param format The format of the picture. * @param format The format of the picture.
*
* @return the picture data * @return the picture data
*/ */
@Override @Override
@ -540,13 +533,11 @@ implements SlideShow<XSLFShape,XSLFTextParagraph> {
* *
* @param is The stream to read image from * @param is The stream to read image from
* @param format The format of the picture * @param format The format of the picture
*
* @return the picture data * @return the picture data
* @since 3.15 beta 2 * @since 3.15 beta 2
*/ */
@Override @Override
public XSLFPictureData addPicture(InputStream is, PictureType format) throws IOException public XSLFPictureData addPicture(InputStream is, PictureType format) throws IOException {
{
return addPicture(IOUtils.toByteArray(is), format); return addPicture(IOUtils.toByteArray(is), format);
} }
@ -556,13 +547,11 @@ implements SlideShow<XSLFShape,XSLFTextParagraph> {
* *
* @param pict The file containing the image to add * @param pict The file containing the image to add
* @param format The format of the picture. * @param format The format of the picture.
*
* @return the picture data * @return the picture data
* @since 3.15 beta 2 * @since 3.15 beta 2
*/ */
@Override @Override
public XSLFPictureData addPicture(File pict, PictureType format) throws IOException public XSLFPictureData addPicture(File pict, PictureType format) throws IOException {
{
int length = (int) pict.length(); int length = (int) pict.length();
byte[] data = IOUtils.safelyAllocate(length, MAX_RECORD_LENGTH); byte[] data = IOUtils.safelyAllocate(length, MAX_RECORD_LENGTH);
try (InputStream is = new FileInputStream(pict)) { try (InputStream is = new FileInputStream(pict)) {

View File

@ -19,56 +19,23 @@
package org.apache.poi.xslf.usermodel; package org.apache.poi.xslf.usermodel;
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import javax.xml.namespace.QName;
import org.apache.poi.POIXMLDocument; import org.apache.poi.POIXMLDocument;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.POIXMLException;
import org.apache.poi.POIXMLRelation; import org.apache.poi.POIXMLRelation;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.exceptions.NotOfficeXmlFileException;
import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
import org.apache.poi.xddf.usermodel.chart.XDDFChart; import org.apache.poi.xddf.usermodel.chart.XDDFChart;
import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTChartSpace;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTTitle; import org.openxmlformats.schemas.drawingml.x2006.chart.CTTitle;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody;
/** /**
* Represents a Chart in a .pptx presentation * Represents a Chart in a .pptx presentation
*
*
*/ */
@Beta @Beta
public final class XSLFChart extends XDDFChart { public final class XSLFChart extends XDDFChart {
protected static final POIXMLRelation WORKBOOK_RELATIONSHIP = new POIXMLRelation(
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
POIXMLDocument.PACK_OBJECT_REL_TYPE,
"/ppt/embeddings/Microsoft_Excel_Worksheet#.xlsx",
XSSFWorkbook.class
){};
/**
* Underlying workbook
*/
private XSSFWorkbook workbook;
/** /**
* Construct a PresentationML chart. * Construct a PresentationML chart.
@ -82,7 +49,6 @@ public final class XSLFChart extends XDDFChart {
* *
* @param part the package part holding the chart data, * @param part the package part holding the chart data,
* the content type must be <code>application/vnd.openxmlformats-officedocument.drawingml.chart+xml</code> * the content type must be <code>application/vnd.openxmlformats-officedocument.drawingml.chart+xml</code>
*
* @since POI 3.14-Beta1 * @since POI 3.14-Beta1
*/ */
protected XSLFChart(PackagePart part) throws IOException, XmlException { protected XSLFChart(PackagePart part) throws IOException, XmlException {
@ -110,118 +76,4 @@ public final class XSLFChart extends XDDFChart {
}; };
} }
} }
public CellReference setSheetTitle(String title) {
XSSFSheet sheet = getSheet();
sheet.createRow(0).createCell(1).setCellValue(title);
return new CellReference(sheet.getSheetName(), 0, 1, true, true);
}
public String formatRange(CellRangeAddress range) {
return range.formatAsString(getSheet().getSheetName(), true);
}
private XSSFSheet getSheet() {
XSSFSheet sheet = null;
try {
sheet = getWorkbook().getSheetAt(0);
} catch (InvalidFormatException ife) {
} catch (IOException ioe) {
}
return sheet;
}
private PackagePart getWorksheetPart() throws InvalidFormatException {
for (RelationPart part : getRelationParts()) {
if (WORKBOOK_RELATIONSHIP.getRelation().equals(part.getRelationship().getRelationshipType())) {
return getTargetPart(part.getRelationship());
}
}
return null;
}
protected XSSFWorkbook getWorkbook() throws IOException, InvalidFormatException {
if (workbook == null) {
try {
PackagePart worksheetPart = getWorksheetPart();
if (worksheetPart == null) {
workbook = new XSSFWorkbook();
workbook.createSheet();
} else {
workbook = new XSSFWorkbook(worksheetPart.getInputStream());
}
} catch (NotOfficeXmlFileException e) {
workbook = new XSSFWorkbook();
workbook.createSheet();
}
}
return workbook;
}
private XMLSlideShow getSlideShow() {
POIXMLDocumentPart p = getParent();
while(p != null) {
if(p instanceof XMLSlideShow){
return (XMLSlideShow)p;
}
p = p.getParent();
}
throw new IllegalStateException("SlideShow was not found");
}
private PackagePart createWorksheetPart() throws InvalidFormatException {
Integer chartIdx = XSLFRelation.CHART.getFileNameIndex(this);
return getTargetPart(getSlideShow().createWorkbookRelationship(this, chartIdx));
}
protected void saveWorkbook(XSSFWorkbook workbook) throws IOException, InvalidFormatException {
PackagePart worksheetPart = getWorksheetPart();
if (worksheetPart == null) {
worksheetPart = createWorksheetPart();
}
try (OutputStream xlsOut = worksheetPart.getOutputStream()) {
workbook.write(xlsOut);
}
}
private void fillSheet(XSSFSheet sheet, XDDFDataSource<?> categoryData, XDDFNumericalDataSource<?> valuesData) {
int numOfPoints = categoryData.getPointCount();
for (int i = 0; i < numOfPoints; i++) {
XSSFRow row = sheet.createRow(i + 1); // first row is for title
row.createCell(0).setCellValue(categoryData.getPointAt(i).toString());
row.createCell(1).setCellValue(valuesData.getPointAt(i).doubleValue());
}
}
@Override
public void plot(XDDFChartData data) {
super.plot(data);
XSSFSheet sheet = getSheet();
for(XDDFChartData.Series series : data.getSeries()) {
fillSheet(sheet, series.getCategoryData(), series.getValuesData());
}
}
public void importContent(XSLFChart other) {
this.chart.set(other.chart);
}
@Override
protected void commit() throws IOException {
XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
xmlOptions.setSaveSyntheticDocumentElement(new QName(CTChartSpace.type.getName().getNamespaceURI(), "chartSpace", "c"));
if (workbook != null) {
try {
saveWorkbook(workbook);
} catch (InvalidFormatException e) {
throw new POIXMLException(e);
}
}
PackagePart part = getPackagePart();
try (OutputStream out = part.getOutputStream()) {
chartSpace.save(out, xmlOptions);
}
}
} }

View File

@ -19,10 +19,12 @@ package org.apache.poi.xslf.usermodel;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.apache.poi.POIXMLDocument;
import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.POIXMLRelation; import org.apache.poi.POIXMLRelation;
import org.apache.poi.sl.usermodel.PictureData.PictureType; import org.apache.poi.sl.usermodel.PictureData.PictureType;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
@Beta @Beta
public class XSLFRelation extends POIXMLRelation { public class XSLFRelation extends POIXMLRelation {
@ -137,6 +139,13 @@ public class XSLFRelation extends POIXMLRelation {
null null
); );
public static final XSLFRelation WORKBOOK_RELATIONSHIP = new XSLFRelation(
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
POIXMLDocument.PACK_OBJECT_REL_TYPE,
"/ppt/embeddings/Microsoft_Excel_Worksheet#.xlsx",
XSSFWorkbook.class
);
public static final XSLFRelation CHART = new XSLFRelation( public static final XSLFRelation CHART = new XSLFRelation(
"application/vnd.openxmlformats-officedocument.drawingml.chart+xml", "application/vnd.openxmlformats-officedocument.drawingml.chart+xml",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart",

View File

@ -329,6 +329,15 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
this(openPackage(path)); this(openPackage(path));
} }
/**
* Constructs a XSSFWorkbook object using Package Part.
* @param part package part
* @since POI 4.0.0
*/
public XSSFWorkbook(PackagePart part) throws IOException {
this(part.getInputStream());
}
protected void beforeDocumentRead() { protected void beforeDocumentRead() {
// Ensure it isn't a XLSB file, which we don't support // Ensure it isn't a XLSB file, which we don't support
if (getCorePart().getContentType().equals(XSSFRelation.XLSB_BINARY_WORKBOOK.getContentType())) { if (getCorePart().getContentType().equals(XSSFRelation.XLSB_BINARY_WORKBOOK.getContentType())) {

View File

@ -17,13 +17,8 @@
package org.apache.poi.xwpf.usermodel; package org.apache.poi.xwpf.usermodel;
import static org.apache.poi.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
import javax.xml.namespace.QName;
import org.apache.poi.POIXMLException; import org.apache.poi.POIXMLException;
import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackagePart;
@ -31,40 +26,52 @@ import org.apache.poi.util.Beta;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.xddf.usermodel.chart.XDDFChart; import org.apache.poi.xddf.usermodel.chart.XDDFChart;
import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlOptions; import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTChartSpace;
/** /**
* Represents a Chart in a .docx file * Represents a Chart in a .docx file
*/ */
@Beta @Beta
public class XWPFChart extends XDDFChart { public class XWPFChart extends XDDFChart {
/**
* default width of chart in emu
*/
public static final int DEFAULT_WIDTH = 500000;
/**
* default height of chart in emu
*/
public static final int DEFAULT_HEIGHT = 500000;
// lazy initialization // lazy initialization
private Long checksum; private Long checksum;
/**
* this object is used to modify drawing properties
*/
private CTInline ctInline;
/**
* constructor to
* Create a new chart in document
*
* @since POI 4.0.0
*/
protected XWPFChart() {
super();
}
/** /**
* Construct a chart from a package part. * Construct a chart from a package part.
* *
* @param part the package part holding the chart data, * @param part the package part holding the chart data,
* the content type must be <code>application/vnd.openxmlformats-officedocument.drawingml.chart+xml</code> * the content type must be <code>application/vnd.openxmlformats-officedocument.drawingml.chart+xml</code>
*
* @since POI 4.0.0 * @since POI 4.0.0
*/ */
protected XWPFChart(PackagePart part) throws IOException, XmlException { protected XWPFChart(PackagePart part) throws IOException, XmlException {
super(part); super(part);
} }
@Override
protected void commit() throws IOException {
XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
xmlOptions.setSaveSyntheticDocumentElement(new QName(CTChartSpace.type.getName().getNamespaceURI(), "chartSpace", "c"));
try (OutputStream out = getPackagePart().getOutputStream()) {
chartSpace.save(out, xmlOptions);
}
}
public Long getChecksum() { public Long getChecksum() {
if (this.checksum == null) { if (this.checksum == null) {
InputStream is = null; InputStream is = null;
@ -120,4 +127,160 @@ public class XWPFChart extends XDDFChart {
public int hashCode() { public int hashCode() {
return getChecksum().hashCode(); return getChecksum().hashCode();
} }
/**
* initialize in line object
*
* @param inline this object is used to adjust the margin and dimension of chart
* @since POI 4.0.0
*/
protected void setAttachTo(CTInline ctInline) {
this.ctInline = ctInline;
}
/**
* set chart height
*
* @param height height of chart
* @since POI 4.0.0
*/
public void setChartHeight(long height) {
ctInline.getExtent().setCy(height);
}
/**
* set chart width
*
* @param width width of chart
* @since POI 4.0.0
*/
public void setChartWidth(long width) {
ctInline.getExtent().setCx(width);
}
/**
* get chart height
*
* @since POI 4.0.0
*/
public long getChartHeight() {
return ctInline.getExtent().getCy();
}
/**
* get chart width
*
* @since POI 4.0.0
*/
public long getChartWidth() {
return ctInline.getExtent().getCx();
}
/**
* set chart height and width
*
* @param width width of chart
* @param height height of chart
* @since POI 4.0.0
*/
public void setChartBoundingBox(long width, long height) {
this.setChartWidth(width);
this.setChartHeight(height);
}
/**
* set margin from top
*
* @param margin margin from top
* @since POI 4.0.0
*/
public void setChartTopMargin(long margin) {
ctInline.setDistT(margin);
}
/**
* get margin from Top
*
* @param margin
* @since POI 4.0.0
*/
public long getChartTopMargin(long margin) {
return ctInline.getDistT();
}
/**
* set margin from bottom
*
* @param margin margin from Bottom
* @since POI 4.0.0
*/
public void setChartBottomMargin(long margin) {
ctInline.setDistB(margin);
}
/**
* get margin from Bottom
*
* @param margin
* @since POI 4.0.0
*/
public long getChartBottomMargin(long margin) {
return ctInline.getDistB();
}
/**
* set margin from left
*
* @param margin margin from left
* @since POI 4.0.0
*/
public void setChartLeftMargin(long margin) {
ctInline.setDistL(margin);
}
/**
* get margin from left
*
* @param margin
* @since POI 4.0.0
*/
public long getChartLeftMargin(long margin) {
return ctInline.getDistL();
}
/**
* set margin from Right
*
* @param margin from right
* @since POI 4.0.0
*/
public void setChartRightMargin(long margin) {
ctInline.setDistR(margin);
}
/**
* get margin from Right
*
* @param margin
* @since POI 4.0.0
*/
public long getChartRightMargin(long margin) {
return ctInline.getDistR();
}
/**
* set chart margin
*
* @param top margin from top
* @param right margin from right
* @param bottom margin from bottom
* @param left margin from left
* @since POI 4.0.0
*/
public void setChartMargin(long top, long right, long bottom, long left) {
this.setChartBottomMargin(bottom);
this.setChartRightMargin(right);
this.setChartLeftMargin(left);
this.setChartRightMargin(right);
}
} }

View File

@ -63,6 +63,7 @@ import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions; import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTComment; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTComment;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDocument1; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDocument1;
@ -245,7 +246,6 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody {
} else if (relation.equals(XWPFRelation.CHART.getRelation())) { } else if (relation.equals(XWPFRelation.CHART.getRelation())) {
//now we can use all methods to modify charts in XWPFDocument //now we can use all methods to modify charts in XWPFDocument
XWPFChart chartData = (XWPFChart) p; XWPFChart chartData = (XWPFChart) p;
// chartData.onDocumentRead(); // ??? there is nothing to be done there!!!
charts.add(chartData); charts.add(chartData);
} else if (relation.equals(XWPFRelation.GLOSSARY_DOCUMENT.getRelation())) { } else if (relation.equals(XWPFRelation.GLOSSARY_DOCUMENT.getRelation())) {
// We don't currently process the glossary itself // We don't currently process the glossary itself
@ -356,6 +356,7 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody {
public List<XWPFChart> getCharts() { public List<XWPFChart> getCharts() {
return Collections.unmodifiableList(charts); return Collections.unmodifiableList(charts);
} }
/** /**
* @see org.apache.poi.xwpf.usermodel.IBody#getTableArray(int) * @see org.apache.poi.xwpf.usermodel.IBody#getTableArray(int)
*/ */
@ -468,6 +469,7 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody {
public XWPFHeaderFooterPolicy getHeaderFooterPolicy() { public XWPFHeaderFooterPolicy getHeaderFooterPolicy() {
return headerFooterPolicy; return headerFooterPolicy;
} }
public XWPFHeaderFooterPolicy createHeaderFooterPolicy() { public XWPFHeaderFooterPolicy createHeaderFooterPolicy() {
if (headerFooterPolicy == null) { if (headerFooterPolicy == null) {
// if (! ctDocument.getBody().isSetSectPr()) { // if (! ctDocument.getBody().isSetSectPr()) {
@ -1608,4 +1610,59 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody {
public XWPFDocument getXWPFDocument() { public XWPFDocument getXWPFDocument() {
return this; return this;
} }
/**
* This method is used to create template for chart XML
* no need to read MS-Word file and modify charts
*
* @return This method return object of XWPFChart Object with default height and width
* @throws InvalidFormatException
* @throws IOException
* @since POI 4.0.0
*/
public XWPFChart createChart() throws InvalidFormatException, IOException {
return createChart(XWPFChart.DEFAULT_WIDTH, XWPFChart.DEFAULT_HEIGHT);
}
/**
* This method is used to create template for chart XML
* no need to read MS-Word file and modify charts
*
* @param width width of chart in document
* @param height height of chart in document
* @return This method return object of XWPFChart
* @throws InvalidFormatException
* @throws IOException
* @since POI 4.0.0
*/
public XWPFChart createChart(int width, int height) throws InvalidFormatException, IOException {
//get chart number
int chartNumber = getPackagePart().getPackage().
getPartsByContentType(XWPFRelation.CHART.getContentType()).size() + 1;
//create relationship in document for new chart
RelationPart rp = createRelationship(
XWPFRelation.CHART, XWPFFactory.getInstance(), chartNumber, false);
//get chart relationship id
String chartId = rp.getRelationship().getId();
//create paragraph and run object
XWPFRun xRun = this.createParagraph().createRun();
CTInline inline = xRun.addChart(width, height, chartId);
//get package part of xwpfchart object
XWPFChart xwpfChart = rp.getDocumentPart();
xwpfChart.setChartIndex(chartNumber);
//set in line object into xwpfchart object
xwpfChart.setAttachTo(inline);
//add chart object to chart list
charts.add(xwpfChart);
return xwpfChart;
}
} }

View File

@ -20,9 +20,11 @@ package org.apache.poi.xwpf.usermodel;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.apache.poi.POIXMLDocument;
import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.POIXMLRelation; import org.apache.poi.POIXMLRelation;
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes; import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
/** /**
* @author Yegor Kozlov * @author Yegor Kozlov
@ -112,6 +114,14 @@ public final class XWPFRelation extends POIXMLRelation {
"/word/theme/theme#.xml", "/word/theme/theme#.xml",
null null
); );
public static final XWPFRelation WORKBOOK_RELATIONSHIP = new XWPFRelation(
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
POIXMLDocument.PACK_OBJECT_REL_TYPE,
"/word/embeddings/Microsoft_Excel_Worksheet#.xlsx",
XSSFWorkbook.class
);
public static final XWPFRelation CHART = new XWPFRelation( public static final XWPFRelation CHART = new XWPFRelation(
"application/vnd.openxmlformats-officedocument.drawingml.chart+xml", "application/vnd.openxmlformats-officedocument.drawingml.chart+xml",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart",

View File

@ -39,6 +39,8 @@ import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlString; import org.apache.xmlbeans.XmlString;
import org.apache.xmlbeans.XmlToken; import org.apache.xmlbeans.XmlToken;
import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl; import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTRelId;
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip; import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;
import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties; import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObject; import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObject;
@ -1025,6 +1027,62 @@ public class XWPFRun implements ISDTContents, IRunElement, CharacterRun {
} }
} }
/**
* this method add chart template into document
*
* @param width set width of chart object
* @param height set height of chart object
* @param chartRelId relation id of chart in document relation file
* @throws InvalidFormatException
* @throws IOException
* @since POI 4.0.0
*/
@Internal
public CTInline addChart(int width, int height, String chartRelId)
throws InvalidFormatException, IOException {
try {
CTInline inline = run.addNewDrawing().addNewInline();
//xml part of chart in document
String xml =
"<a:graphic xmlns:a=\"" + CTGraphicalObject.type.getName().getNamespaceURI() + "\">" +
"<a:graphicData uri=\"" + CTChart.type.getName().getNamespaceURI() + "\">" +
"<c:chart xmlns:c=\"" + CTChart.type.getName().getNamespaceURI() + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" r:id=\"" + chartRelId + "\" />" +
"</a:graphicData>" +
"</a:graphic>";
InputSource is = new InputSource(new StringReader(xml));
org.w3c.dom.Document doc = DocumentHelper.readDocument(is);
inline.set(XmlToken.Factory.parse(doc.getDocumentElement(), DEFAULT_XML_OPTIONS));
// Setup the inline with 0 margin
inline.setDistT(0);
inline.setDistR(0);
inline.setDistB(0);
inline.setDistL(0);
CTNonVisualDrawingProps docPr = inline.addNewDocPr();
long id = getParent().getDocument().getDrawingIdManager().reserveNew();
docPr.setId(id);
//This name is not visible in Word anywhere.
docPr.setName("chart " + id);
CTPositiveSize2D extent = inline.addNewExtent();
//set hegiht and width of drawaing object;
extent.setCx(width);
extent.setCy(height);
return inline;
} catch (XmlException e) {
throw new IllegalStateException(e);
} catch (SAXException e) {
throw new IllegalStateException(e);
}
}
/** /**
* Returns the embedded pictures of the run. These * Returns the embedded pictures of the run. These
* are pictures which reference an external, * are pictures which reference an external,
@ -1071,7 +1129,6 @@ public class XWPFRun implements ISDTContents, IRunElement, CharacterRun {
} }
/** /**
*
* @return the phonetic (ruby) string associated with this run or an empty String if none exists * @return the phonetic (ruby) string associated with this run or an empty String if none exists
*/ */
public String getPhonetic() { public String getPhonetic() {
@ -1096,7 +1153,6 @@ public class XWPFRun implements ISDTContents, IRunElement, CharacterRun {
} }
/** /**
*
* @param rubyObj rubyobject * @param rubyObj rubyobject
* @param text buffer to which to append the content * @param text buffer to which to append the content
* @param extractPhonetic extract the phonetic (rt) component or the base component * @param extractPhonetic extract the phonetic (rt) component or the base component

View File

@ -20,6 +20,7 @@ package org.apache.poi.xwpf.usermodel;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData; import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFChartData; import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
import org.apache.poi.xwpf.XWPFTestDataSamples; import org.apache.poi.xwpf.XWPFTestDataSamples;
@ -37,8 +38,7 @@ public class TestXWPFChart extends TestCase {
/** /**
* test method to check charts are not null * test method to check charts are not null
*/ */
public void testRead() throws IOException public void testRead() throws IOException {
{
XWPFDocument sampleDoc = XWPFTestDataSamples.openSampleDocument("61745.docx"); XWPFDocument sampleDoc = XWPFTestDataSamples.openSampleDocument("61745.docx");
List<XWPFChart> charts = sampleDoc.getCharts(); List<XWPFChart> charts = sampleDoc.getCharts();
assertNotNull(charts); assertNotNull(charts);
@ -58,8 +58,7 @@ public class TestXWPFChart extends TestCase {
/** /**
* test method to add chart title and check whether it's set * test method to add chart title and check whether it's set
*/ */
public void testChartTitle() throws IOException public void testChartTitle() throws IOException {
{
XWPFDocument sampleDoc = XWPFTestDataSamples.openSampleDocument("61745.docx"); XWPFDocument sampleDoc = XWPFTestDataSamples.openSampleDocument("61745.docx");
List<XWPFChart> charts = sampleDoc.getCharts(); List<XWPFChart> charts = sampleDoc.getCharts();
XWPFChart chart = charts.get(0); XWPFChart chart = charts.get(0);
@ -75,11 +74,11 @@ public class TestXWPFChart extends TestCase {
r.setT("XWPF CHART"); r.setT("XWPF CHART");
assertEquals("XWPF CHART", chart.getCTChart().getTitle().getTx().getRich().getPArray(0).getRArray(0).getT()); assertEquals("XWPF CHART", chart.getCTChart().getTitle().getTx().getRich().getPArray(0).getRArray(0).getT());
} }
/** /**
* test method to check relationship * test method to check relationship
*/ */
public void testChartRelation() throws IOException public void testChartRelation() throws IOException {
{
XWPFDocument sampleDoc = XWPFTestDataSamples.openSampleDocument("61745.docx"); XWPFDocument sampleDoc = XWPFTestDataSamples.openSampleDocument("61745.docx");
List<XWPFChart> charts = sampleDoc.getCharts(); List<XWPFChart> charts = sampleDoc.getCharts();
XWPFChart chart = charts.get(0); XWPFChart chart = charts.get(0);
@ -87,4 +86,30 @@ public class TestXWPFChart extends TestCase {
assertEquals("/word/document.xml", chart.getParent().getPackagePart().getPartName().getName()); assertEquals("/word/document.xml", chart.getParent().getPackagePart().getPartName().getName());
assertEquals("/word/charts/chart1.xml", chart.getPackagePart().getPartName().getName()); assertEquals("/word/charts/chart1.xml", chart.getPackagePart().getPartName().getName());
} }
/**
* test method to check adding chart in document
*/
public static void testAddChartsToNewDocument() throws InvalidFormatException, IOException {
XWPFDocument document = new XWPFDocument();
XWPFChart chart = document.createChart();
assertEquals(1, document.getCharts().size());
assertNotNull(chart);
assertNotNull(chart.getCTChartSpace());
assertNotNull(chart.getCTChart());
assertEquals(XWPFChart.DEFAULT_HEIGHT, chart.getChartHeight());
assertEquals(XWPFChart.DEFAULT_WIDTH, chart.getChartWidth());
XWPFChart chart2 = document.createChart();
assertEquals(2, document.getCharts().size());
assertNotNull(chart2);
assertNotNull(chart2.getCTChartSpace());
assertNotNull(chart2.getCTChart());
chart.setChartHeight(500500);
assertEquals(500500, chart.getChartHeight());
assertNotNull(XWPFTestDataSamples.writeOutAndReadBack(document));
}
} }