merge with trunk as of r1160685

git-svn-id: https://svn.apache.org/repos/asf/poi/tags/REL_3_8_BETA4@1160688 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yegor Kozlov 2011-08-23 13:46:44 +00:00
commit 2bbeecb657
49 changed files with 2177 additions and 517 deletions

View File

@ -32,8 +32,8 @@
</header>
<body>
<section><title>6 June 2011 - POI 3.8 beta 3 available</title>
<p>The Apache POI team is pleased to announce the release of 3.8 beta 3.
<section><title>22 August 2011 - POI 3.8 beta 4 available</title>
<p>The Apache POI team is pleased to announce the release of 3.8 beta 4.
This includes a large number of bug fixes and enhancements.
</p>
<p>A full list of changes is available in the <link href="changes.html">change log</link>.

View File

@ -34,6 +34,9 @@
<changes>
<release version="3.8-beta4" date="2011-??-??">
<action dev="poi-developers" type="fix">51678 - Extracting text from Bug51524.zip is slow</action>
<action dev="poi-developers" type="fix">51671 - HWPFDocument.write based on NPOIFSFileSystem throws a NullPointerException</action>
<action dev="poi-developers" type="add">support for tables and hyperlinks in XSLF</action>
<action dev="poi-developers" type="fix">51535 - correct signed vs unsigned short reading in NDocumentInputStream</action>
<action dev="poi-developers" type="add">51634 - support SXSSF streaming from templates</action>
<action dev="poi-developers" type="add">initial support for XSLF usermodel API</action>

View File

@ -24,6 +24,8 @@ import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
import org.apache.poi.util.POIUtils;
import org.apache.poi.hpsf.DocumentSummaryInformation;
import org.apache.poi.hpsf.MutablePropertySet;
import org.apache.poi.hpsf.PropertySet;
@ -36,6 +38,7 @@ import org.apache.poi.poifs.filesystem.DocumentInputStream;
import org.apache.poi.poifs.filesystem.Entry;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
@ -236,49 +239,34 @@ public abstract class POIDocument {
* @param target is the target POIFS to copy to
* @param excepts is a list of Strings specifying what nodes NOT to copy
*/
protected void copyNodes(POIFSFileSystem source, POIFSFileSystem target,
List<String> excepts) throws IOException {
//System.err.println("CopyNodes called");
copyNodes(source.getRoot(), target.getRoot(), excepts);
}
@Deprecated
protected void copyNodes( POIFSFileSystem source, POIFSFileSystem target,
List<String> excepts ) throws IOException
{
POIUtils.copyNodes( source, target, excepts );
}
/**
* Copies nodes from one POIFS to the other minus the excepts
* @param source is the source POIFS to copy from
* @param target is the target POIFS to copy to
* @param excepts is a list of Strings specifying what nodes NOT to copy
*/
protected void copyNodes(DirectoryNode sourceRoot, DirectoryNode targetRoot,
List<String> excepts) throws IOException {
Iterator<Entry> entries = sourceRoot.getEntries();
while (entries.hasNext()) {
Entry entry = entries.next();
if (!excepts.contains(entry.getName())) {
copyNodeRecursively(entry,targetRoot);
}
}
}
@Deprecated
protected void copyNodes( DirectoryNode sourceRoot,
DirectoryNode targetRoot, List<String> excepts ) throws IOException
{
POIUtils.copyNodes( sourceRoot, targetRoot, excepts );
}
/**
* Copies an Entry into a target POIFS directory, recursively
*/
private void copyNodeRecursively(Entry entry, DirectoryEntry target)
throws IOException {
//System.err.println("copyNodeRecursively called with "+entry.getName()+
// ","+target.getName());
DirectoryEntry newTarget = null;
if (entry.isDirectoryEntry()) {
newTarget = target.createDirectory(entry.getName());
Iterator<Entry> entries = ((DirectoryEntry)entry).getEntries();
while (entries.hasNext()) {
copyNodeRecursively(entries.next(),newTarget);
}
} else {
DocumentEntry dentry = (DocumentEntry)entry;
DocumentInputStream dstream = new DocumentInputStream(dentry);
target.createDocument(dentry.getName(),dstream);
dstream.close();
}
}
@Internal
@Deprecated
protected void copyNodeRecursively( Entry entry, DirectoryEntry target )
throws IOException
{
POIUtils.copyNodeRecursively( entry, target );
}
}

View File

@ -0,0 +1,103 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.util;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import org.apache.poi.poifs.filesystem.DirectoryEntry;
import org.apache.poi.poifs.filesystem.DocumentEntry;
import org.apache.poi.poifs.filesystem.DocumentInputStream;
import org.apache.poi.poifs.filesystem.Entry;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
@Internal
public class POIUtils
{
/**
* Copies an Entry into a target POIFS directory, recursively
*/
@Internal
public static void copyNodeRecursively( Entry entry, DirectoryEntry target )
throws IOException
{
// System.err.println("copyNodeRecursively called with "+entry.getName()+
// ","+target.getName());
DirectoryEntry newTarget = null;
if ( entry.isDirectoryEntry() )
{
newTarget = target.createDirectory( entry.getName() );
Iterator<Entry> entries = ( (DirectoryEntry) entry ).getEntries();
while ( entries.hasNext() )
{
copyNodeRecursively( entries.next(), newTarget );
}
}
else
{
DocumentEntry dentry = (DocumentEntry) entry;
DocumentInputStream dstream = new DocumentInputStream( dentry );
target.createDocument( dentry.getName(), dstream );
dstream.close();
}
}
/**
* Copies nodes from one POIFS to the other minus the excepts
*
* @param source
* is the source POIFS to copy from
* @param target
* is the target POIFS to copy to
* @param excepts
* is a list of Strings specifying what nodes NOT to copy
*/
public static void copyNodes( DirectoryEntry sourceRoot,
DirectoryEntry targetRoot, List<String> excepts )
throws IOException
{
Iterator<Entry> entries = sourceRoot.getEntries();
while ( entries.hasNext() )
{
Entry entry = entries.next();
if ( !excepts.contains( entry.getName() ) )
{
copyNodeRecursively( entry, targetRoot );
}
}
}
/**
* Copies nodes from one POIFS to the other minus the excepts
*
* @param source
* is the source POIFS to copy from
* @param target
* is the target POIFS to copy to
* @param excepts
* is a list of Strings specifying what nodes NOT to copy
*/
public static void copyNodes( POIFSFileSystem source,
POIFSFileSystem target, List<String> excepts ) throws IOException
{
// System.err.println("CopyNodes called");
copyNodes( source.getRoot(), target.getRoot(), excepts );
}
}

View File

@ -48,19 +48,10 @@ import java.util.List;
* @author Yegor Kozlov
*/
@Beta
public class XSLFAutoShape extends XSLFSimpleShape {
private final List<XSLFTextParagraph> _paragraphs;
public class XSLFAutoShape extends XSLFTextShape {
/*package*/ XSLFAutoShape(CTShape shape, XSLFSheet sheet) {
super(shape, sheet);
_paragraphs = new ArrayList<XSLFTextParagraph>();
if (shape.isSetTxBody()) {
CTTextBody txBody = shape.getTxBody();
for (CTTextParagraph p : txBody.getPList()) {
_paragraphs.add(new XSLFTextParagraph(p));
}
}
}
/*package*/
@ -74,36 +65,6 @@ public class XSLFAutoShape extends XSLFSimpleShape {
}
}
// textual properties
public String getText() {
StringBuilder out = new StringBuilder();
for (XSLFTextParagraph p : _paragraphs) {
if (out.length() > 0) out.append('\n');
out.append(p.getText());
}
return out.toString();
}
public List<XSLFTextParagraph> getTextParagraphs() {
return _paragraphs;
}
public XSLFTextParagraph addNewTextParagraph() {
CTShape shape = (CTShape) getXmlObject();
CTTextBody txBody;
if (!shape.isSetTxBody()) {
txBody = shape.addNewTxBody();
txBody.addNewBodyPr();
txBody.addNewLstStyle();
} else {
txBody = shape.getTxBody();
}
CTTextParagraph p = txBody.addNewP();
XSLFTextParagraph paragraph = new XSLFTextParagraph(p);
_paragraphs.add(paragraph);
return paragraph;
}
/**
* @param shapeId 1-based shapeId
*/
@ -160,268 +121,15 @@ public class XSLFAutoShape extends XSLFSimpleShape {
return new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2]);
}
/**
* Sets the type of vertical alignment for the text.
* One of the <code>Anchor*</code> constants defined in this class.
*
* @param anchor - the type of alignment. Default is {@link VerticalAlignment#TOP}
*/
public void setVerticalAlignment(VerticalAlignment anchor){
protected CTTextBody getTextBody(boolean create){
CTShape shape = (CTShape) getXmlObject();
if (shape.isSetTxBody()) {
CTTextBodyProperties bodyPr = shape.getTxBody().getBodyPr();
if(anchor == null) {
if(bodyPr.isSetAnchor()) bodyPr.unsetAnchor();
} else {
bodyPr.setAnchor(STTextAnchoringType.Enum.forInt(anchor.ordinal() + 1));
}
}
}
/**
* Returns the type of vertical alignment for the text.
*
* @return the type of alignment
*/
public VerticalAlignment getVerticalAlignment(){
CTShape shape = (CTShape) getXmlObject();
if (shape.isSetTxBody()) {
STTextAnchoringType.Enum val = shape.getTxBody().getBodyPr().getAnchor();
if(val != null){
return VerticalAlignment.values()[val.intValue() - 1];
}
}
return VerticalAlignment.TOP;
}
/**
*
* @param orientation vertical orientation of the text
*/
public void setTextDirection(TextDirection orientation){
CTShape shape = (CTShape) getXmlObject();
if (shape.isSetTxBody()) {
CTTextBodyProperties bodyPr = shape.getTxBody().getBodyPr();
if(orientation == null) {
if(bodyPr.isSetVert()) bodyPr.unsetVert();
} else {
bodyPr.setVert(STTextVerticalType.Enum.forInt(orientation.ordinal() + 1));
}
}
}
/**
* @return vertical orientation of the text
*/
public TextDirection getTextDirection(){
CTShape shape = (CTShape) getXmlObject();
if (shape.isSetTxBody()) {
STTextVerticalType.Enum val = shape.getTxBody().getBodyPr().getVert();
if(val != null){
return TextDirection.values()[val.intValue() - 1];
}
}
return TextDirection.HORIZONTAL;
}
/**
* Returns the distance (in points) between the bottom of the text frame
* and the bottom of the inscribed rectangle of the shape that contains the text.
*
* @return the bottom margin or -1 if not set
*/
public double getMarginBottom(){
CTShape shape = (CTShape) getXmlObject();
if (shape.isSetTxBody()) {
CTTextBodyProperties bodyPr = shape.getTxBody().getBodyPr();
return bodyPr.isSetBIns() ? Units.toPoints(bodyPr.getBIns()) : -1;
}
return -1;
}
/**
* Returns the distance (in points) between the left edge of the text frame
* and the left edge of the inscribed rectangle of the shape that contains
* the text.
*
* @return the left margin
*/
public double getMarginLeft(){
CTShape shape = (CTShape) getXmlObject();
if (shape.isSetTxBody()) {
CTTextBodyProperties bodyPr = shape.getTxBody().getBodyPr();
return bodyPr.isSetLIns() ? Units.toPoints(bodyPr.getLIns()) : -1;
}
return -1;
}
/**
* Returns the distance (in points) between the right edge of the
* text frame and the right edge of the inscribed rectangle of the shape
* that contains the text.
*
* @return the right margin
*/
public double getMarginRight(){
CTShape shape = (CTShape) getXmlObject();
if (shape.isSetTxBody()) {
CTTextBodyProperties bodyPr = shape.getTxBody().getBodyPr();
return bodyPr.isSetRIns() ? Units.toPoints(bodyPr.getRIns()) : -1;
}
return -1;
}
/**
* Returns the distance (in points) between the top of the text frame
* and the top of the inscribed rectangle of the shape that contains the text.
*
* @return the top margin
*/
public double getMarginTop(){
CTShape shape = (CTShape) getXmlObject();
if (shape.isSetTxBody()) {
CTTextBodyProperties bodyPr = shape.getTxBody().getBodyPr();
return bodyPr.isSetTIns() ? Units.toPoints(bodyPr.getTIns()) : -1;
}
return -1;
}
/**
* Sets the botom margin.
* @see #getMarginBottom()
*
* @param margin the bottom margin
*/
public void setMarginBottom(double margin){
CTShape shape = (CTShape) getXmlObject();
if (shape.isSetTxBody()) {
CTTextBodyProperties bodyPr = shape.getTxBody().getBodyPr();
if(margin == -1) bodyPr.unsetBIns();
else bodyPr.setBIns(Units.toEMU(margin));
}
}
/**
* Sets the left margin.
* @see #getMarginLeft()
*
* @param margin the left margin
*/
public void setMarginLeft(double margin){
CTShape shape = (CTShape) getXmlObject();
if (shape.isSetTxBody()) {
CTTextBodyProperties bodyPr = shape.getTxBody().getBodyPr();
if(margin == -1) bodyPr.unsetLIns();
else bodyPr.setLIns(Units.toEMU(margin));
}
}
/**
* Sets the right margin.
* @see #getMarginRight()
*
* @param margin the right margin
*/
public void setMarginRight(double margin){
CTShape shape = (CTShape) getXmlObject();
if (shape.isSetTxBody()) {
CTTextBodyProperties bodyPr = shape.getTxBody().getBodyPr();
if(margin == -1) bodyPr.unsetRIns();
else bodyPr.setRIns(Units.toEMU(margin));
}
}
/**
* Sets the top margin.
* @see #getMarginTop()
*
* @param margin the top margin
*/
public void setMarginTop(double margin){
CTShape shape = (CTShape) getXmlObject();
if (shape.isSetTxBody()) {
CTTextBodyProperties bodyPr = shape.getTxBody().getBodyPr();
if(margin == -1) bodyPr.unsetTIns();
else bodyPr.setTIns(Units.toEMU(margin));
}
}
/**
* Returns the value indicating word wrap.
* One of the <code>Wrap*</code> constants defined in this class.
*
* @return the value indicating word wrap
*/
public boolean getWordWrap(){
CTShape shape = (CTShape) getXmlObject();
if (shape.isSetTxBody()) {
return shape.getTxBody().getBodyPr().getWrap() == STTextWrappingType.SQUARE;
}
return false;
}
/**
* Specifies how the text should be wrapped
*
* @param wrap the value indicating how the text should be wrapped
*/
public void setWordWrap(boolean wrap){
CTShape shape = (CTShape) getXmlObject();
if (shape.isSetTxBody()) {
shape.getTxBody().getBodyPr().setWrap(wrap ? STTextWrappingType.SQUARE : STTextWrappingType.NONE);
}
}
/**
*
* Specifies that a shape should be auto-fit to fully contain the text described within it.
* Auto-fitting is when text within a shape is scaled in order to contain all the text inside
*
* @param value type of autofit
*/
public void setTextAutofit(TextAutofit value){
CTShape shape = (CTShape) getXmlObject();
if (shape.isSetTxBody()) {
CTTextBodyProperties bodyPr = shape.getTxBody().getBodyPr();
if(bodyPr.isSetSpAutoFit()) bodyPr.unsetSpAutoFit();
if(bodyPr.isSetNoAutofit()) bodyPr.unsetNoAutofit();
if(bodyPr.isSetNormAutofit()) bodyPr.unsetNormAutofit();
switch(value){
case NONE: bodyPr.addNewNoAutofit(); break;
case NORMAL: bodyPr.addNewNormAutofit(); break;
case SHAPE: bodyPr.addNewSpAutoFit(); break;
}
}
}
/**
*
* @return type of autofit
*/
public TextAutofit getTextAutofit(){
CTShape shape = (CTShape) getXmlObject();
if (shape.isSetTxBody()) {
CTTextBodyProperties bodyPr = shape.getTxBody().getBodyPr();
if(bodyPr.isSetNoAutofit()) return TextAutofit.NONE;
else if (bodyPr.isSetNormAutofit()) return TextAutofit.NORMAL;
else if (bodyPr.isSetSpAutoFit()) return TextAutofit.SHAPE;
}
return TextAutofit.NORMAL;
}
@Override
void onCopy(XSLFSheet srcSheet){
CTShape shape = (CTShape) getXmlObject();
if (!shape.isSetTxBody()) return;
CTPlaceholder ph = shape.getNvSpPr().getNvPr().getPh();
if(ph == null || !ph.isSetType()) return;
if(ph.getType() == STPlaceholderType.TITLE){
CTTextBody txBody = shape.getTxBody();
if (txBody == null && create) {
txBody = shape.addNewTxBody();
txBody.addNewBodyPr();
txBody.addNewLstStyle();
}
return txBody;
}
}

View File

@ -24,6 +24,7 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector;
import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame;
import java.awt.*;
@ -97,4 +98,12 @@ public class XSLFDrawing {
shape.setAnchor(new Rectangle());
return shape;
}
public XSLFTable createTable(){
CTGraphicalObjectFrame obj = _spTree.addNewGraphicFrame();
obj.set(XSLFTable.prototype(_shapeId++));
XSLFTable shape = new XSLFTable(obj, _sheet);
shape.setAnchor(new Rectangle());
return shape;
}
}

View File

@ -44,6 +44,10 @@ public class XSLFGraphicFrame extends XSLFShape {
return _shape;
}
public XSLFSheet getSheet(){
return _sheet;
}
public int getShapeType(){
throw new RuntimeException("NotImplemented");
}
@ -64,16 +68,14 @@ public class XSLFGraphicFrame extends XSLFShape {
throw new RuntimeException("NotImplemented");
}
public ShapeGroup getParent(){
throw new RuntimeException("NotImplemented");
static XSLFGraphicFrame create(CTGraphicalObjectFrame shape, XSLFSheet sheet){
String uri = shape.getGraphic().getGraphicData().getUri();
if(XSLFTable.TABLE_URI.equals(uri)){
return new XSLFTable(shape, sheet);
} else {
return new XSLFGraphicFrame(shape, sheet);
}
}
public Shape[] getShapes(){
throw new RuntimeException("NotImplemented");
}
public boolean removeShape(Shape shape){
throw new RuntimeException("NotImplemented");
}
}

View File

@ -0,0 +1,69 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.xslf.usermodel;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.util.Internal;
import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink;
import java.net.URI;
/**
* @author Yegor Kozlov
*/
public class XSLFHyperlink {
final XSLFTextRun _r;
final CTHyperlink _link;
XSLFHyperlink(CTHyperlink link, XSLFTextRun r){
_r = r;
_link = link;
}
@Internal
public CTHyperlink getXmlObject(){
return _link;
}
public void setAddress(String address){
XSLFSheet sheet = _r.getParentParagraph().getParentShape().getSheet();
PackageRelationship rel =
sheet.getPackagePart().
addExternalRelationship(address, XSLFRelation.HYPERLINK.getRelation());
_link.setId(rel.getId());
}
public void setAddress(XSLFSlide slide){
XSLFSheet sheet = _r.getParentParagraph().getParentShape().getSheet();
PackageRelationship rel =
sheet.getPackagePart().
addRelationship(slide.getPackagePart().getPartName(),
TargetMode.INTERNAL,
XSLFRelation.SLIDE.getRelation());
_link.setId(rel.getId());
_link.setAction("ppaction://hlinksldjump");
}
@Internal
public URI getTargetURI(){
XSLFSheet sheet = _r.getParentParagraph().getParentShape().getSheet();
String id = _link.getId();
return sheet.getPackagePart().getRelationship(id).getTargetURI();
}
}

View File

@ -103,6 +103,13 @@ public class XSLFRelation extends POIXMLRelation {
null, null
);
public static final XSLFRelation HYPERLINK = new XSLFRelation(
null,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
null,
null
);
public static final XSLFRelation THEME = new XSLFRelation(
"application/vnd.openxmlformats-officedocument.theme+xml",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme",

View File

@ -41,8 +41,4 @@ public abstract class XSLFShape {
public abstract String getShapeName();
public abstract int getShapeId();
void onCopy(XSLFSheet srcSheet){
}
}

View File

@ -70,7 +70,8 @@ public abstract class XSLFSheet extends POIXMLDocumentPart {
} else if (ch instanceof CTPicture){
shapes.add(new XSLFPictureShape((CTPicture)ch, this));
} else if (ch instanceof CTGraphicalObjectFrame){
shapes.add(new XSLFGraphicFrame((CTGraphicalObjectFrame)ch, this));
XSLFGraphicFrame shape = XSLFGraphicFrame.create((CTGraphicalObjectFrame)ch, this);
shapes.add(shape);
}
}
return shapes;
@ -147,6 +148,13 @@ public abstract class XSLFSheet extends POIXMLDocumentPart {
return sh;
}
public XSLFTable createTable(){
List<XSLFShape> shapes = getShapeList();
XSLFTable sh = getDrawing().createTable();
shapes.add(sh);
return sh;
}
public XSLFShape[] getShapes(){
return getShapeList().toArray(new XSLFShape[_shapes.size()]);
}

View File

@ -0,0 +1,157 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package org.apache.poi.xslf.usermodel;
import org.apache.poi.util.Internal;
import org.apache.poi.util.Units;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObjectData;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTable;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTableRow;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGroupTransform2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame;
import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrameNonVisual;
import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.awt.geom.Rectangle2D;
/**
* Represents a table in a .pptx presentation
*
* @author Yegor Kozlov
*/
public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow> {
static String TABLE_URI = "http://schemas.openxmlformats.org/drawingml/2006/table";
private CTTable _table;
private List<XSLFTableRow> _rows;
/*package*/ XSLFTable(CTGraphicalObjectFrame shape, XSLFSheet sheet){
super(shape, sheet);
for(XmlObject obj : shape.getGraphic().getGraphicData().selectPath("*")){
if(obj instanceof CTTable){
_table = (CTTable)obj;
}
}
if(_table == null) throw new IllegalStateException("CTTable element was not found");
_rows = new ArrayList<XSLFTableRow>(_table.sizeOfTrArray());
for(CTTableRow row : _table.getTrList()) _rows.add(new XSLFTableRow(row, this));
}
@Internal
public CTTable getCTTable(){
return _table;
}
public int getNumberOfColumns() {
return _table.getTblGrid().sizeOfGridColArray();
}
public int getNumberOfRows() {
return _table.sizeOfTrArray();
}
public double getColumnWidth(int idx){
return Units.toPoints(
_table.getTblGrid().getGridColArray(idx).getW());
}
public void setColumnWidth(int idx, double width){
_table.getTblGrid().getGridColArray(idx).setW(Units.toEMU(width));
}
public Iterator<XSLFTableRow> iterator(){
return _rows.iterator();
}
public List<XSLFTableRow> getRows(){
return Collections.unmodifiableList(_rows);
}
public XSLFTableRow addRow(){
CTTableRow tr = _table.addNewTr();
XSLFTableRow row = new XSLFTableRow(tr, this);
row.setHeight(20.0); // default height is 20 points
_rows.add(row);
return row;
}
static CTGraphicalObjectFrame prototype(int shapeId){
CTGraphicalObjectFrame frame = CTGraphicalObjectFrame.Factory.newInstance();
CTGraphicalObjectFrameNonVisual nvGr = frame.addNewNvGraphicFramePr();
CTNonVisualDrawingProps cnv = nvGr.addNewCNvPr();
cnv.setName("Table " + shapeId);
cnv.setId(shapeId + 1);
nvGr.addNewCNvGraphicFramePr().addNewGraphicFrameLocks().setNoGrp(true);
nvGr.addNewNvPr();
frame.addNewXfrm();
CTGraphicalObjectData gr = frame.addNewGraphic().addNewGraphicData();
XmlCursor cursor = gr.newCursor();
cursor.toNextToken();
cursor.beginElement(new QName("http://schemas.openxmlformats.org/drawingml/2006/main", "tbl"));
cursor.beginElement(new QName("http://schemas.openxmlformats.org/drawingml/2006/main", "tblPr"));
cursor.toNextToken();
cursor.beginElement(new QName("http://schemas.openxmlformats.org/drawingml/2006/main", "tblGrid"));
cursor.dispose();
gr.setUri(TABLE_URI);
return frame;
}
public Rectangle2D getAnchor(){
CTTransform2D xfrm = getXmlObject().getXfrm();
CTPoint2D off = xfrm.getOff();
long x = off.getX();
long y = off.getY();
CTPositiveSize2D ext = xfrm.getExt();
long cx = ext.getCx();
long cy = ext.getCy();
return new Rectangle2D.Double(
Units.toPoints(x), Units.toPoints(y),
Units.toPoints(cx), Units.toPoints(cy));
}
public void setAnchor(Rectangle2D anchor){
CTTransform2D xfrm = getXmlObject().getXfrm();
CTPoint2D off = xfrm.isSetOff() ? xfrm.getOff() : xfrm.addNewOff();
long x = Units.toEMU(anchor.getX());
long y = Units.toEMU(anchor.getY());
off.setX(x);
off.setY(y);
CTPositiveSize2D ext = xfrm.isSetExt() ? xfrm.getExt() : xfrm.addNewExt();
long cx = Units.toEMU(anchor.getWidth());
long cy = Units.toEMU(anchor.getHeight());
ext.setCx(cx);
ext.setCy(cy);
}
}

View File

@ -0,0 +1,290 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package org.apache.poi.xslf.usermodel;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTableCell;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBodyProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTableCellProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.STPenAlignment;
import org.openxmlformats.schemas.drawingml.x2006.main.STCompoundLine;
import org.openxmlformats.schemas.drawingml.x2006.main.STLineCap;
import org.openxmlformats.schemas.drawingml.x2006.main.STPresetLineDashVal;
import org.openxmlformats.schemas.drawingml.x2006.main.CTLineEndProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndLength;
import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndType;
import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndWidth;
import org.apache.poi.util.Internal;
import org.apache.poi.util.Units;
import java.awt.*;
/**
* Represents a cell of a table in a .pptx presentation
*
* @author Yegor Kozlov
*/
public class XSLFTableCell extends XSLFTextShape {
static double defaultBorderWidth = 1.0;
/*package*/ XSLFTableCell(CTTableCell cell, XSLFSheet sheet){
super(cell, sheet);
}
@Override
public CTTableCell getXmlObject(){
return (CTTableCell)super.getXmlObject();
}
@Override
protected CTTextBody getTextBody(boolean create){
CTTableCell cell = getXmlObject();
CTTextBody txBody = cell.getTxBody();
if (txBody == null && create) {
txBody = cell.addNewTxBody();
txBody.addNewBodyPr();
txBody.addNewLstStyle();
}
return txBody;
}
static CTTableCell prototype() {
CTTableCell cell = CTTableCell.Factory.newInstance();
CTTableCellProperties pr = cell.addNewTcPr();
pr.addNewLnL().addNewNoFill();
pr.addNewLnR().addNewNoFill();
pr.addNewLnT().addNewNoFill();
pr.addNewLnB().addNewNoFill();
return cell;
}
@Override
public void setMarginLeft(double margin){
CTTableCellProperties pr = getXmlObject().getTcPr();
if(pr == null) pr = getXmlObject().addNewTcPr();
pr.setMarL(Units.toEMU(margin));
}
@Override
public void setMarginRight(double margin){
CTTableCellProperties pr = getXmlObject().getTcPr();
if(pr == null) pr = getXmlObject().addNewTcPr();
pr.setMarR(Units.toEMU(margin));
}
@Override
public void setMarginTop(double margin){
CTTableCellProperties pr = getXmlObject().getTcPr();
if(pr == null) pr = getXmlObject().addNewTcPr();
pr.setMarT(Units.toEMU(margin));
}
@Override
public void setMarginBottom(double margin){
CTTableCellProperties pr = getXmlObject().getTcPr();
if(pr == null) pr = getXmlObject().addNewTcPr();
pr.setMarB(Units.toEMU(margin));
}
public void setBorderLeft(double width){
CTTableCellProperties pr = getXmlObject().getTcPr();
CTLineProperties ln = pr.isSetLnL() ? pr.getLnL() : pr.addNewLnL();
ln.setW(Units.toEMU(width));
}
public double getBorderLeft(){
CTTableCellProperties pr = getXmlObject().getTcPr();
CTLineProperties ln = pr.getLnL();
return ln == null || !ln.isSetW() ? defaultBorderWidth : Units.toPoints(ln.getW());
}
public void setBorderLeftColor(Color color){
CTTableCellProperties pr = getXmlObject().getTcPr();
CTLineProperties ln = pr.isSetLnL() ? pr.getLnL() : pr.addNewLnL();
setLineColor(ln, color);
}
public Color getBorderLeftColor(){
return getLineColor(getXmlObject().getTcPr().getLnL());
}
public void setBorderRight(double width){
CTTableCellProperties pr = getXmlObject().getTcPr();
CTLineProperties ln = pr.isSetLnR() ? pr.getLnR() : pr.addNewLnR();
ln.setW(Units.toEMU(width));
}
public double getBorderRight(){
CTTableCellProperties pr = getXmlObject().getTcPr();
CTLineProperties ln = pr.getLnR();
return ln == null || !ln.isSetW() ? defaultBorderWidth : Units.toPoints(ln.getW());
}
public void setBorderRightColor(Color color){
CTTableCellProperties pr = getXmlObject().getTcPr();
CTLineProperties ln = pr.isSetLnR() ? pr.getLnR() : pr.addNewLnR();
setLineColor(ln, color);
}
public Color getBorderRightColor(){
return getLineColor(getXmlObject().getTcPr().getLnR());
}
public void setBorderTop(double width){
CTTableCellProperties pr = getXmlObject().getTcPr();
CTLineProperties ln = pr.isSetLnT() ? pr.getLnT() : pr.addNewLnT();
ln.setW(Units.toEMU(width));
}
public double getBorderTop(){
CTTableCellProperties pr = getXmlObject().getTcPr();
CTLineProperties ln = pr.getLnT();
return ln == null || !ln.isSetW() ? defaultBorderWidth : Units.toPoints(ln.getW());
}
public void setBorderTopColor(Color color){
CTTableCellProperties pr = getXmlObject().getTcPr();
CTLineProperties ln = pr.isSetLnT() ? pr.getLnT() : pr.addNewLnT();
setLineColor(ln, color);
}
public Color getBorderTopColor(){
return getLineColor(getXmlObject().getTcPr().getLnT());
}
public void setBorderBottom(double width){
CTTableCellProperties pr = getXmlObject().getTcPr();
CTLineProperties ln = pr.isSetLnB() ? pr.getLnB() : pr.addNewLnB();
ln.setW(Units.toEMU(width));
}
public double getBorderBottom(){
CTTableCellProperties pr = getXmlObject().getTcPr();
CTLineProperties ln = pr.getLnB();
return ln == null || !ln.isSetW() ? defaultBorderWidth : Units.toPoints(ln.getW());
}
public void setBorderBottomColor(Color color){
CTTableCellProperties pr = getXmlObject().getTcPr();
CTLineProperties ln = pr.isSetLnB() ? pr.getLnB() : pr.addNewLnB();
setLineColor(ln, color);
}
public Color getBorderBottomColor(){
return getLineColor(getXmlObject().getTcPr().getLnB());
}
private void setLineColor(CTLineProperties ln, Color color){
if(color == null){
ln.addNewNoFill();
if(ln.isSetSolidFill()) ln.unsetSolidFill();
} else {
if(ln.isSetNoFill()) ln.unsetNoFill();
if(!ln.isSetPrstDash()) ln.addNewPrstDash().setVal(STPresetLineDashVal.SOLID);
ln.setCmpd(STCompoundLine.SNG);
ln.setAlgn(STPenAlignment.CTR);
ln.setCap(STLineCap.FLAT);
ln.addNewRound();
CTLineEndProperties hd = ln.addNewHeadEnd();
hd.setType(STLineEndType.NONE);
hd.setW(STLineEndWidth.MED);
hd.setLen(STLineEndLength.MED);
CTLineEndProperties tl = ln.addNewTailEnd();
tl.setType(STLineEndType.NONE);
tl.setW(STLineEndWidth.MED);
tl.setLen(STLineEndLength.MED);
CTSRgbColor rgb = CTSRgbColor.Factory.newInstance();
rgb.setVal(new byte[]{(byte)color.getRed(), (byte)color.getGreen(), (byte)color.getBlue()});
ln.addNewSolidFill().setSrgbClr(rgb);
}
}
private Color getLineColor(CTLineProperties ln){
if(ln == null || ln.isSetNoFill() || !ln.isSetSolidFill()) return null;
CTSolidColorFillProperties fill = ln.getSolidFill();
if(!fill.isSetSrgbClr()) {
// TODO for now return null for all colors except explicit RGB
return null;
}
byte[] val = fill.getSrgbClr().getVal();
return new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2]);
}
/**
* Specifies a solid color fill. The shape is filled entirely with the specified color.
*
* @param color the solid color fill.
* The value of <code>null</code> unsets the solidFIll attribute from the underlying xml
*/
@Override
public void setFillColor(Color color) {
CTTableCellProperties spPr = getXmlObject().getTcPr();
if (color == null) {
if(spPr.isSetSolidFill()) spPr.unsetSolidFill();
}
else {
CTSolidColorFillProperties fill = spPr.isSetSolidFill() ? spPr.getSolidFill() : spPr.addNewSolidFill();
CTSRgbColor rgb = CTSRgbColor.Factory.newInstance();
rgb.setVal(new byte[]{(byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue()});
fill.setSrgbClr(rgb);
}
}
/**
*
* @return solid fill color of null if not set
*/
@Override
public Color getFillColor(){
CTTableCellProperties spPr = getXmlObject().getTcPr();
if(!spPr.isSetSolidFill() ) return null;
CTSolidColorFillProperties fill = spPr.getSolidFill();
if(!fill.isSetSrgbClr()) {
// TODO for now return null for all colors except explicit RGB
return null;
}
byte[] val = fill.getSrgbClr().getVal();
return new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2]);
}
}

View File

@ -0,0 +1,86 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package org.apache.poi.xslf.usermodel;
import org.apache.poi.util.Units;
import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTable;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTableCell;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTableRow;
import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Iterator;
/**
* Represents a table in a .pptx presentation
*
* @author Yegor Kozlov
*/
public class XSLFTableRow implements Iterable<XSLFTableCell> {
private CTTableRow _row;
private List<XSLFTableCell> _cells;
private XSLFTable _table;
/*package*/ XSLFTableRow(CTTableRow row, XSLFTable table){
_row = row;
_table = table;
_cells = new ArrayList<XSLFTableCell>(_row.sizeOfTcArray());
for(CTTableCell cell : _row.getTcList()) {
_cells.add(new XSLFTableCell(cell, table.getSheet()));
}
}
public CTTableRow getXmlObject(){
return _row;
}
public Iterator<XSLFTableCell> iterator(){
return _cells.iterator();
}
public List<XSLFTableCell> getCells(){
return Collections.unmodifiableList(_cells);
}
public double getHeight(){
return Units.toPoints(_row.getH());
}
public void setHeight(double height){
_row.setH(Units.toEMU(height));
}
public XSLFTableCell addCell(){
CTTableCell c = _row.addNewTc();
c.set(XSLFTableCell.prototype());
XSLFTableCell cell = new XSLFTableCell(c, _table.getSheet());
_cells.add(cell);
if(_table.getNumberOfColumns() < _row.sizeOfTcArray()) {
_table.getCTTable().getTblGrid().addNewGridCol().setW(Units.toEMU(100.0));
}
return cell;
}
}

View File

@ -40,12 +40,14 @@ import java.util.List;
public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
private final CTTextParagraph _p;
private final List<XSLFTextRun> _runs;
private final XSLFTextShape _shape;
XSLFTextParagraph(CTTextParagraph p){
XSLFTextParagraph(CTTextParagraph p, XSLFTextShape shape){
_p = p;
_runs = new ArrayList<XSLFTextRun>();
_shape = shape;
for (CTRegularTextRun r : _p.getRList()) {
_runs.add(new XSLFTextRun(r));
_runs.add(new XSLFTextRun(r, this));
}
}
@ -62,6 +64,10 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
return _p;
}
XSLFTextShape getParentShape() {
return _shape;
}
public List<XSLFTextRun> getTextRuns(){
return _runs;
}
@ -72,7 +78,8 @@ public class XSLFTextParagraph implements Iterable<XSLFTextRun>{
public XSLFTextRun addNewTextRun(){
CTRegularTextRun r = _p.addNewR();
XSLFTextRun run = new XSLFTextRun(r);
r.addNewRPr();
XSLFTextRun run = new XSLFTextRun(r, this);
_runs.add(run);
return run;
}

View File

@ -36,9 +36,15 @@ import java.awt.*;
@Beta
public class XSLFTextRun {
private final CTRegularTextRun _r;
private final XSLFTextParagraph _p;
XSLFTextRun(CTRegularTextRun r){
XSLFTextRun(CTRegularTextRun r, XSLFTextParagraph p){
_r = r;
_p = p;
}
XSLFTextParagraph getParentParagraph(){
return _p;
}
public String getText(){
@ -78,7 +84,7 @@ public class XSLFTextRun {
* @return font size in points or -1 if font size is not set.
*/
public double getFontSize(){
if(!_r.isSetRPr()) return -1;
if(!_r.isSetRPr() || !_r.getRPr().isSetSz()) return -1;
return _r.getRPr().getSz()*0.01;
}
@ -198,5 +204,16 @@ public class XSLFTextRun {
public String toString(){
return "[" + getClass() + "]" + getText();
}
public XSLFHyperlink createHyperlink(){
XSLFHyperlink link = new XSLFHyperlink(_r.getRPr().addNewHlinkClick(), this);
return link;
}
public XSLFHyperlink getHyperlink(){
if(!_r.getRPr().isSetHlinkClick()) return null;
return new XSLFHyperlink(_r.getRPr().getHlinkClick(), this);
}
}

View File

@ -0,0 +1,365 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package org.apache.poi.xslf.usermodel;
import org.apache.poi.util.Beta;
import org.apache.poi.util.Units;
import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBodyProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextAnchoringType;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextVerticalType;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextWrappingType;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
/**
* Represents a shape that can hold text.
*
* @author Yegor Kozlov
*/
@Beta
public abstract class XSLFTextShape extends XSLFSimpleShape {
private final List<XSLFTextParagraph> _paragraphs;
/*package*/ XSLFTextShape(XmlObject shape, XSLFSheet sheet) {
super(shape, sheet);
_paragraphs = new ArrayList<XSLFTextParagraph>();
CTTextBody txBody = getTextBody(false);
if (txBody != null) {
for (CTTextParagraph p : txBody.getPList()) {
_paragraphs.add(new XSLFTextParagraph(p, this));
}
}
}
// textual properties
public String getText() {
StringBuilder out = new StringBuilder();
for (XSLFTextParagraph p : _paragraphs) {
if (out.length() > 0) out.append('\n');
out.append(p.getText());
}
return out.toString();
}
public List<XSLFTextParagraph> getTextParagraphs() {
return _paragraphs;
}
public XSLFTextParagraph addNewTextParagraph() {
CTTextBody txBody = getTextBody(true);
CTTextParagraph p = txBody.addNewP();
XSLFTextParagraph paragraph = new XSLFTextParagraph(p, this);
_paragraphs.add(paragraph);
return paragraph;
}
/**
* Specifies a solid color fill. The shape is filled entirely with the specified color.
*
* @param color the solid color fill.
* The value of <code>null</code> unsets the solidFIll attribute from the underlying xml
*/
public void setFillColor(Color color) {
CTShapeProperties spPr = getSpPr();
if (color == null) {
if(spPr.isSetSolidFill()) spPr.unsetSolidFill();
}
else {
CTSolidColorFillProperties fill = spPr.isSetSolidFill() ? spPr.getSolidFill() : spPr.addNewSolidFill();
CTSRgbColor rgb = CTSRgbColor.Factory.newInstance();
rgb.setVal(new byte[]{(byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue()});
fill.setSrgbClr(rgb);
}
}
/**
*
* @return solid fill color of null if not set
*/
public Color getFillColor(){
CTShapeProperties spPr = getSpPr();
if(!spPr.isSetSolidFill() ) return null;
CTSolidColorFillProperties fill = spPr.getSolidFill();
if(!fill.isSetSrgbClr()) {
// TODO for now return null for all colors except explicit RGB
return null;
}
byte[] val = fill.getSrgbClr().getVal();
return new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2]);
}
/**
* Sets the type of vertical alignment for the text.
* One of the <code>Anchor*</code> constants defined in this class.
*
* @param anchor - the type of alignment. Default is {@link org.apache.poi.xslf.usermodel.VerticalAlignment#TOP}
*/
public void setVerticalAlignment(VerticalAlignment anchor){
CTTextBodyProperties bodyPr = getTextBodyPr();
if (bodyPr != null) {
if(anchor == null) {
if(bodyPr.isSetAnchor()) bodyPr.unsetAnchor();
} else {
bodyPr.setAnchor(STTextAnchoringType.Enum.forInt(anchor.ordinal() + 1));
}
}
}
/**
* Returns the type of vertical alignment for the text.
*
* @return the type of alignment
*/
public VerticalAlignment getVerticalAlignment(){
CTTextBodyProperties bodyPr = getTextBodyPr();
if (bodyPr != null) {
STTextAnchoringType.Enum val = bodyPr.getAnchor();
if(val != null){
return VerticalAlignment.values()[val.intValue() - 1];
}
}
return VerticalAlignment.TOP;
}
/**
*
* @param orientation vertical orientation of the text
*/
public void setTextDirection(TextDirection orientation){
CTTextBodyProperties bodyPr = getTextBodyPr();
if (bodyPr != null) {
if(orientation == null) {
if(bodyPr.isSetVert()) bodyPr.unsetVert();
} else {
bodyPr.setVert(STTextVerticalType.Enum.forInt(orientation.ordinal() + 1));
}
}
}
/**
* @return vertical orientation of the text
*/
public TextDirection getTextDirection(){
CTTextBodyProperties bodyPr = getTextBodyPr();
if (bodyPr != null) {
STTextVerticalType.Enum val = bodyPr.getVert();
if(val != null){
return TextDirection.values()[val.intValue() - 1];
}
}
return TextDirection.HORIZONTAL;
}
/**
* Returns the distance (in points) between the bottom of the text frame
* and the bottom of the inscribed rectangle of the shape that contains the text.
*
* @return the bottom margin or -1 if not set
*/
public double getMarginBottom(){
CTTextBodyProperties bodyPr = getTextBodyPr();
if (bodyPr != null) {
return bodyPr.isSetBIns() ? Units.toPoints(bodyPr.getBIns()) : -1;
}
return -1;
}
/**
* Returns the distance (in points) between the left edge of the text frame
* and the left edge of the inscribed rectangle of the shape that contains
* the text.
*
* @return the left margin
*/
public double getMarginLeft(){
CTTextBodyProperties bodyPr = getTextBodyPr();
if (bodyPr != null) {
return bodyPr.isSetLIns() ? Units.toPoints(bodyPr.getLIns()) : -1;
}
return -1;
}
/**
* Returns the distance (in points) between the right edge of the
* text frame and the right edge of the inscribed rectangle of the shape
* that contains the text.
*
* @return the right margin
*/
public double getMarginRight(){
CTTextBodyProperties bodyPr = getTextBodyPr();
if (bodyPr != null) {
return bodyPr.isSetRIns() ? Units.toPoints(bodyPr.getRIns()) : -1;
}
return -1;
}
/**
* Returns the distance (in points) between the top of the text frame
* and the top of the inscribed rectangle of the shape that contains the text.
*
* @return the top margin
*/
public double getMarginTop(){
CTTextBodyProperties bodyPr = getTextBodyPr();
if (bodyPr != null) {
return bodyPr.isSetTIns() ? Units.toPoints(bodyPr.getTIns()) : -1;
}
return -1;
}
/**
* Sets the botom margin.
* @see #getMarginBottom()
*
* @param margin the bottom margin
*/
public void setMarginBottom(double margin){
CTTextBodyProperties bodyPr = getTextBodyPr();
if (bodyPr != null) {
if(margin == -1) bodyPr.unsetBIns();
else bodyPr.setBIns(Units.toEMU(margin));
}
}
/**
* Sets the left margin.
* @see #getMarginLeft()
*
* @param margin the left margin
*/
public void setMarginLeft(double margin){
CTTextBodyProperties bodyPr = getTextBodyPr();
if (bodyPr != null) {
if(margin == -1) bodyPr.unsetLIns();
else bodyPr.setLIns(Units.toEMU(margin));
}
}
/**
* Sets the right margin.
* @see #getMarginRight()
*
* @param margin the right margin
*/
public void setMarginRight(double margin){
CTTextBodyProperties bodyPr = getTextBodyPr();
if (bodyPr != null) {
if(margin == -1) bodyPr.unsetRIns();
else bodyPr.setRIns(Units.toEMU(margin));
}
}
/**
* Sets the top margin.
* @see #getMarginTop()
*
* @param margin the top margin
*/
public void setMarginTop(double margin){
CTTextBodyProperties bodyPr = getTextBodyPr();
if (bodyPr != null) {
if(margin == -1) bodyPr.unsetTIns();
else bodyPr.setTIns(Units.toEMU(margin));
}
}
/**
* Returns the value indicating word wrap.
* One of the <code>Wrap*</code> constants defined in this class.
*
* @return the value indicating word wrap
*/
public boolean getWordWrap(){
CTTextBodyProperties bodyPr = getTextBodyPr();
if (bodyPr != null) {
return bodyPr.getWrap() == STTextWrappingType.SQUARE;
}
return false;
}
/**
* Specifies how the text should be wrapped
*
* @param wrap the value indicating how the text should be wrapped
*/
public void setWordWrap(boolean wrap){
CTTextBodyProperties bodyPr = getTextBodyPr();
if (bodyPr != null) {
bodyPr.setWrap(wrap ? STTextWrappingType.SQUARE : STTextWrappingType.NONE);
}
}
/**
*
* Specifies that a shape should be auto-fit to fully contain the text described within it.
* Auto-fitting is when text within a shape is scaled in order to contain all the text inside
*
* @param value type of autofit
*/
public void setTextAutofit(TextAutofit value){
CTTextBodyProperties bodyPr = getTextBodyPr();
if (bodyPr != null) {
if(bodyPr.isSetSpAutoFit()) bodyPr.unsetSpAutoFit();
if(bodyPr.isSetNoAutofit()) bodyPr.unsetNoAutofit();
if(bodyPr.isSetNormAutofit()) bodyPr.unsetNormAutofit();
switch(value){
case NONE: bodyPr.addNewNoAutofit(); break;
case NORMAL: bodyPr.addNewNormAutofit(); break;
case SHAPE: bodyPr.addNewSpAutoFit(); break;
}
}
}
/**
*
* @return type of autofit
*/
public TextAutofit getTextAutofit(){
CTTextBodyProperties bodyPr = getTextBodyPr();
if (bodyPr != null) {
if(bodyPr.isSetNoAutofit()) return TextAutofit.NONE;
else if (bodyPr.isSetNormAutofit()) return TextAutofit.NORMAL;
else if (bodyPr.isSetSpAutoFit()) return TextAutofit.SHAPE;
}
return TextAutofit.NORMAL;
}
protected CTTextBodyProperties getTextBodyPr(){
CTTextBody textBody = getTextBody(false);
return textBody == null ? null : textBody.getBodyPr();
}
protected abstract CTTextBody getTextBody(boolean create);
}

View File

@ -210,7 +210,7 @@ public class TestXSLFAutoShape extends TestCase {
assertSame(r, p.getTextRuns().get(0));
assertEquals(-1.0, r.getFontSize());
assertFalse(r.getXmlObject().isSetRPr());
assertFalse(r.getXmlObject().getRPr().isSetSz());
r.setFontSize(10.0);
assertTrue(r.getXmlObject().isSetRPr());
assertEquals(1000, r.getXmlObject().getRPr().getSz());

View File

@ -0,0 +1,102 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.xslf.usermodel;
import junit.framework.TestCase;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.util.*;
import java.util.List;
import java.net.URI;
import org.apache.poi.xslf.XSLFTestDataSamples;
import org.apache.poi.xssf.usermodel.XSSFTable;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.TargetMode;
/**
* @author Yegor Kozlov
*/
public class TestXSLFHyperlink extends TestCase {
public void testRead(){
XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("shapes.pptx");
XSLFSlide slide = ppt.getSlides()[4];
XSLFShape[] shapes = slide.getShapes();
XSLFTable tbl = (XSLFTable)shapes[0];
XSLFTableCell cell1 = tbl.getRows().get(1).getCells().get(0);
assertEquals("Web Page", cell1.getText());
XSLFHyperlink link1 = cell1.getTextParagraphs().get(0).getTextRuns().get(0).getHyperlink();
assertNotNull(link1);
assertEquals(URI.create("http://poi.apache.org/"), link1.getTargetURI());
XSLFTableCell cell2 = tbl.getRows().get(2).getCells().get(0);
assertEquals("Place in this document", cell2.getText());
XSLFHyperlink link2 = cell2.getTextParagraphs().get(0).getTextRuns().get(0).getHyperlink();
assertNotNull(link2);
assertEquals(URI.create("/ppt/slides/slide2.xml"), link2.getTargetURI());
XSLFTableCell cell3 = tbl.getRows().get(3).getCells().get(0);
assertEquals("Email", cell3.getText());
XSLFHyperlink link3 = cell3.getTextParagraphs().get(0).getTextRuns().get(0).getHyperlink();
assertNotNull(link3);
assertEquals(URI.create("mailto:dev@poi.apache.org?subject=Hi%20There"), link3.getTargetURI());
}
public void testCreate() throws Exception {
XMLSlideShow ppt = new XMLSlideShow();
XSLFSlide slide1 = ppt.createSlide();
XSLFSlide slide2 = ppt.createSlide();
int numRel = slide1.getPackagePart().getRelationships().size();
assertEquals(1, numRel);
XSLFTextBox sh1 = slide1.createTextBox();
XSLFTextRun r1 = sh1.addNewTextParagraph().addNewTextRun();
r1.setText("Web Page");
XSLFHyperlink link1 = r1.createHyperlink();
link1.setAddress("http://poi.apache.org/");
assertEquals(URI.create("http://poi.apache.org/"), link1.getTargetURI());
assertEquals(numRel + 1, slide1.getPackagePart().getRelationships().size());
String id1 = link1.getXmlObject().getId();
assertNotNull(id1);
PackageRelationship rel1 = slide1.getPackagePart().getRelationship(id1);
assertNotNull(rel1);
assertEquals(id1, rel1.getId());
assertEquals(TargetMode.EXTERNAL, rel1.getTargetMode());
assertEquals(XSLFRelation.HYPERLINK.getRelation(), rel1.getRelationshipType());
XSLFTextBox sh2 = slide1.createTextBox();
XSLFTextRun r2 = sh2.addNewTextParagraph().addNewTextRun();
r2.setText("Place in this document");
XSLFHyperlink link2 = r2.createHyperlink();
link2.setAddress(slide2);
assertEquals(URI.create("/ppt/slides/slide2.xml"), link2.getTargetURI());
assertEquals(numRel + 2, slide1.getPackagePart().getRelationships().size());
String id2 = link2.getXmlObject().getId();
assertNotNull(id2);
PackageRelationship rel2 = slide1.getPackagePart().getRelationship(id2);
assertNotNull(rel2);
assertEquals(id2, rel2.getId());
assertEquals(TargetMode.INTERNAL, rel2.getTargetMode());
assertEquals(XSLFRelation.SLIDE.getRelation(), rel2.getRelationshipType());
}
}

View File

@ -31,7 +31,6 @@ public class TestXSLFShape extends TestCase {
public void testReadTextShapes() {
XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("shapes.pptx");
XSLFSlide[] slides = ppt.getSlides();
assertEquals(3, slides.length);
XSLFSlide slide1 = slides[0];
XSLFShape[] shapes1 = slide1.getShapes();

View File

@ -30,7 +30,6 @@ public class TestXSLFSlide extends TestCase {
public void testReadShapes(){
XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("shapes.pptx");
XSLFSlide[] slides = ppt.getSlides();
assertEquals(3, slides.length);
XSLFSlide slide1 = slides[0];
XSLFShape[] shapes1 = slide1.getShapes();
@ -85,6 +84,14 @@ public class TestXSLFSlide extends TestCase {
assertTrue(groupShapes[2] instanceof XSLFAutoShape);
assertEquals("Right Arrow 3", groupShapes[2].getShapeName());
XSLFSlide slide4 = slides[3];
XSLFShape[] shapes4 = slide4.getShapes();
assertEquals(1, shapes4.length);
assertTrue(shapes4[0] instanceof XSLFTable);
XSLFTable tbl = (XSLFTable)shapes4[0];
assertEquals(3, tbl.getNumberOfColumns());
assertEquals(6, tbl.getNumberOfRows());
}
public void testCreateSlide(){

View File

@ -0,0 +1,150 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.xslf.usermodel;
import junit.framework.TestCase;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.util.*;
import java.util.List;
import org.apache.poi.xslf.XSLFTestDataSamples;
import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame;
/**
* @author Yegor Kozlov
*/
public class TestXSLFTable extends TestCase {
public void testRead(){
XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("shapes.pptx");
XSLFSlide slide = ppt.getSlides()[3];
XSLFShape[] shapes = slide.getShapes();
assertEquals(1, shapes.length);
assertTrue(shapes[0] instanceof XSLFTable);
XSLFTable tbl = (XSLFTable)shapes[0];
assertEquals(3, tbl.getNumberOfColumns());
assertEquals(6, tbl.getNumberOfRows());
assertNotNull(tbl.getCTTable());
List<XSLFTableRow> rows = tbl.getRows();
assertEquals(6, rows.size());
assertEquals(90.0, tbl.getColumnWidth(0));
assertEquals(240.0, tbl.getColumnWidth(1));
assertEquals(150.0, tbl.getColumnWidth(2));
for(XSLFTableRow row : tbl){
// all rows have the same height
assertEquals(29.2, row.getHeight());
}
XSLFTableRow row0 = rows.get(0);
List<XSLFTableCell> cells0 = row0.getCells();
assertEquals(3, cells0.size());
assertEquals("header1", cells0.get(0).getText());
assertEquals("header2", cells0.get(1).getText());
assertEquals("header3", cells0.get(2).getText());
XSLFTableRow row1 = rows.get(1);
List<XSLFTableCell> cells1 = row1.getCells();
assertEquals(3, cells1.size());
assertEquals("A1", cells1.get(0).getText());
assertEquals("B1", cells1.get(1).getText());
assertEquals("C1", cells1.get(2).getText());
}
public void testCreate() {
XMLSlideShow ppt = new XMLSlideShow();
XSLFSlide slide = ppt.createSlide();
XSLFTable tbl = slide.createTable();
assertNotNull(tbl.getCTTable());
assertNotNull(tbl.getCTTable().getTblGrid());
assertNotNull(tbl.getCTTable().getTblPr());
assertTrue(tbl.getXmlObject() instanceof CTGraphicalObjectFrame);
assertEquals("Table 1", tbl.getShapeName());
assertEquals(2, tbl.getShapeId());
assertEquals(0, tbl.getRows().size());
assertEquals(0, tbl.getCTTable().sizeOfTrArray());
assertEquals(0, tbl.getCTTable().getTblGrid().sizeOfGridColArray());
assertEquals(0, tbl.getNumberOfColumns());
assertEquals(0, tbl.getNumberOfRows());
XSLFTableRow row0 = tbl.addRow();
assertNotNull(row0.getXmlObject());
assertEquals(1, tbl.getNumberOfRows());
assertSame(row0, tbl.getRows().get(0));
assertEquals(20.0, row0.getHeight());
row0.setHeight(30.0);
assertEquals(30.0, row0.getHeight());
assertEquals(0, row0.getCells().size());
XSLFTableCell cell0 = row0.addCell();
assertNotNull(cell0.getXmlObject());
// by default table cell has no borders
assertTrue(cell0.getXmlObject().getTcPr().getLnB().isSetNoFill());
assertTrue(cell0.getXmlObject().getTcPr().getLnT().isSetNoFill());
assertTrue(cell0.getXmlObject().getTcPr().getLnL().isSetNoFill());
assertTrue(cell0.getXmlObject().getTcPr().getLnR().isSetNoFill());
assertSame(cell0, row0.getCells().get(0));
assertEquals(1, tbl.getNumberOfColumns());
assertEquals(100.0, tbl.getColumnWidth(0));
cell0.addNewTextParagraph().addNewTextRun().setText("POI");
assertEquals("POI", cell0.getText());
XSLFTableCell cell1 = row0.addCell();
assertSame(cell1, row0.getCells().get(1));
assertEquals(2, tbl.getNumberOfColumns());
assertEquals(100.0, tbl.getColumnWidth(1));
cell1.addNewTextParagraph().addNewTextRun().setText("Apache");
assertEquals("Apache", cell1.getText());
assertEquals(1.0, cell1.getBorderBottom());
cell1.setBorderBottom(2.0);
assertEquals(2.0, cell1.getBorderBottom());
assertNull(cell1.getBorderBottomColor());
cell1.setBorderBottomColor(Color.yellow);
assertEquals(Color.yellow, cell1.getBorderBottomColor());
assertEquals(1.0, cell1.getBorderTop());
cell1.setBorderTop(2.0);
assertEquals(2.0, cell1.getBorderTop());
assertNull(cell1.getBorderTopColor());
cell1.setBorderTopColor(Color.yellow);
assertEquals(Color.yellow, cell1.getBorderTopColor());
assertEquals(1.0, cell1.getBorderLeft());
cell1.setBorderLeft(2.0);
assertEquals(2.0, cell1.getBorderLeft());
assertNull(cell1.getBorderLeftColor());
cell1.setBorderLeftColor(Color.yellow);
assertEquals(Color.yellow, cell1.getBorderLeftColor());
assertEquals(1.0, cell1.getBorderRight());
cell1.setBorderRight(2.0);
assertEquals(2.0, cell1.getBorderRight());
assertNull(cell1.getBorderRightColor());
cell1.setBorderRightColor(Color.yellow);
assertEquals(Color.yellow, cell1.getBorderRightColor());
}
}

View File

@ -22,6 +22,7 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import org.apache.poi.hpsf.DocumentSummaryInformation;
import org.apache.poi.hpsf.SummaryInformation;
@ -65,8 +66,10 @@ import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.DocumentEntry;
import org.apache.poi.poifs.filesystem.Entry;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.Internal;
import org.apache.poi.util.POIUtils;
/**
@ -81,6 +84,10 @@ public final class HWPFDocument extends HWPFDocumentCore
private static final String PROPERTY_PRESERVE_BIN_TABLES = "org.apache.poi.hwpf.preserveBinTables";
private static final String PROPERTY_PRESERVE_TEXT_TABLE = "org.apache.poi.hwpf.preserveTextTable";
private static final String STREAM_DATA = "Data";
private static final String STREAM_TABLE_0 = "0Table";
private static final String STREAM_TABLE_1 = "1Table";
/** And for making sense of CP lengths in the FIB */
@Deprecated
protected CPSplitCalculator _cpSplit;
@ -181,7 +188,7 @@ public final class HWPFDocument extends HWPFDocumentCore
*/
public HWPFDocument(POIFSFileSystem pfilesystem) throws IOException
{
this(pfilesystem.getRoot());
this(pfilesystem.getRoot());
}
/**
@ -213,7 +220,7 @@ public final class HWPFDocument extends HWPFDocumentCore
{
// Load the main stream and FIB
// Also handles HPSF bits
super(directory);
super(directory);
// Do the CP Split
_cpSplit = new CPSplitCalculator(_fib);
@ -224,20 +231,20 @@ public final class HWPFDocument extends HWPFDocumentCore
}
// use the fib to determine the name of the table stream.
String name = "0Table";
String name = STREAM_TABLE_0;
if (_fib.isFWhichTblStm())
{
name = "1Table";
name = STREAM_TABLE_1;
}
// Grab the table stream.
DocumentEntry tableProps;
try {
tableProps =
(DocumentEntry)directory.getEntry(name);
} catch(FileNotFoundException fnfe) {
throw new IllegalStateException("Table Stream '" + name + "' wasn't found - Either the document is corrupt, or is Word95 (or earlier)");
}
try {
tableProps =
(DocumentEntry)directory.getEntry(name);
} catch(FileNotFoundException fnfe) {
throw new IllegalStateException("Table Stream '" + name + "' wasn't found - Either the document is corrupt, or is Word95 (or earlier)");
}
// read in the table stream.
_tableStream = new byte[tableProps.getSize()];
@ -249,9 +256,9 @@ public final class HWPFDocument extends HWPFDocumentCore
try
{
DocumentEntry dataProps =
(DocumentEntry)directory.getEntry("Data");
(DocumentEntry)directory.getEntry(STREAM_DATA);
_dataStream = new byte[dataProps.getSize()];
directory.createDocumentInputStream("Data").read(_dataStream);
directory.createDocumentInputStream(STREAM_DATA).read(_dataStream);
}
catch(java.io.FileNotFoundException e)
{
@ -396,7 +403,7 @@ public final class HWPFDocument extends HWPFDocumentCore
@Deprecated
public CPSplitCalculator getCPSplitCalculator()
{
return _cpSplit;
return _cpSplit;
}
public DocumentProperties getDocProperties()
@ -512,7 +519,7 @@ public final class HWPFDocument extends HWPFDocumentCore
* separators and footnote separators.
*/
public Range getHeaderStoryRange() {
return getRange( SubdocumentType.HEADER );
return getRange( SubdocumentType.HEADER );
}
/**
@ -550,7 +557,7 @@ public final class HWPFDocument extends HWPFDocumentCore
* @return PicturesTable object, that is able to extract images from this document
*/
public PicturesTable getPicturesTable() {
return _pictures;
return _pictures;
}
@Internal
@ -636,8 +643,8 @@ public final class HWPFDocument extends HWPFDocumentCore
{
// initialize our streams for writing.
HWPFFileSystem docSys = new HWPFFileSystem();
HWPFOutputStream wordDocumentStream = docSys.getStream("WordDocument");
HWPFOutputStream tableStream = docSys.getStream("1Table");
HWPFOutputStream wordDocumentStream = docSys.getStream(STREAM_WORD_DOCUMENT);
HWPFOutputStream tableStream = docSys.getStream(STREAM_TABLE_1);
//HWPFOutputStream dataStream = docSys.getStream("Data");
int tableOffset = 0;
@ -910,6 +917,9 @@ public final class HWPFDocument extends HWPFDocumentCore
mainBuf = tempBuf;
}
// Table1 stream will be used
_fib.setFWhichTblStm( true );
// write out the FileInformationBlock.
//_fib.serialize(mainBuf, 0);
_fib.writeTo(mainBuf, tableStream);
@ -934,52 +944,95 @@ public final class HWPFDocument extends HWPFDocumentCore
dataBuf = tempBuf;
}
// // spit out the Word document.
// POIFSFileSystem pfs = new POIFSFileSystem();
//
// pfs.createDocument(new ByteArrayInputStream(mainBuf), "WordDocument");
// pfs.createDocument(new ByteArrayInputStream(tableBuf), "1Table");
// pfs.createDocument(new ByteArrayInputStream(dataBuf), "Data");
// writeProperties(pfs);
// create new document preserving order of entries
POIFSFileSystem pfs = new POIFSFileSystem();
boolean docWritten = false;
boolean dataWritten = false;
boolean objectPoolWritten = false;
boolean tableWritten = false;
boolean propertiesWritten = false;
for ( Iterator<Entry> iter = directory.getEntries(); iter.hasNext(); )
{
Entry entry = iter.next();
if ( entry.getName().equals( STREAM_WORD_DOCUMENT ) )
{
if ( !docWritten )
{
pfs.createDocument( new ByteArrayInputStream( mainBuf ),
STREAM_WORD_DOCUMENT );
docWritten = true;
}
}
else if ( entry.getName().equals( STREAM_OBJECT_POOL ) )
{
if ( !objectPoolWritten )
{
_objectPool.writeTo( pfs.getRoot() );
objectPoolWritten = true;
}
}
else if ( entry.getName().equals( STREAM_TABLE_0 )
|| entry.getName().equals( STREAM_TABLE_1 ) )
{
if ( !tableWritten )
{
pfs.createDocument( new ByteArrayInputStream( tableBuf ),
STREAM_TABLE_1 );
tableWritten = true;
}
}
else if ( entry.getName().equals(
SummaryInformation.DEFAULT_STREAM_NAME )
|| entry.getName().equals(
DocumentSummaryInformation.DEFAULT_STREAM_NAME ) )
{
if ( !propertiesWritten )
{
writeProperties( pfs );
propertiesWritten = true;
}
}
else if ( entry.getName().equals( STREAM_DATA ) )
{
if ( !dataWritten )
{
pfs.createDocument( new ByteArrayInputStream( dataBuf ),
STREAM_DATA );
dataWritten = true;
}
}
else
{
POIUtils.copyNodeRecursively( entry, pfs.getRoot() );
}
}
POIFSFileSystem pfs = directory.getFileSystem();
deleteEntrySafe( pfs, "WordDocument" );
deleteEntrySafe( pfs, "0Table" );
deleteEntrySafe( pfs, "1Table" );
deleteEntrySafe( pfs, "Data" );
if ( !docWritten )
pfs.createDocument( new ByteArrayInputStream( mainBuf ),
STREAM_WORD_DOCUMENT );
if ( !tableWritten )
pfs.createDocument( new ByteArrayInputStream( tableBuf ),
STREAM_TABLE_1 );
if ( !propertiesWritten )
writeProperties( pfs );
if ( !dataWritten )
pfs.createDocument( new ByteArrayInputStream( dataBuf ),
STREAM_DATA );
if ( !objectPoolWritten )
_objectPool.writeTo( pfs.getRoot() );
// read properties only if they were not read
getSummaryInformation();
// update properties in case user changed them
deleteEntrySafe( pfs, SummaryInformation.DEFAULT_STREAM_NAME );
deleteEntrySafe( pfs, DocumentSummaryInformation.DEFAULT_STREAM_NAME );
writeProperties( pfs );
pfs.createDocument( new ByteArrayInputStream( mainBuf ), "WordDocument" );
pfs.createDocument( new ByteArrayInputStream( tableBuf ), "1Table" );
pfs.createDocument( new ByteArrayInputStream( dataBuf ), "Data" );
pfs.writeFilesystem( out );
this.directory = pfs.getRoot();
/*
* since we updated all references in FIB and etc, using new arrays to
* access data
*/
this.directory = pfs.getRoot();
this._tableStream = tableStream.toByteArray();
this._dataStream = dataBuf;
}
private static void deleteEntrySafe( POIFSFileSystem pfs, final String name )
{
try
{
pfs.getRoot().getEntry( name ).delete();
}
catch ( FileNotFoundException exc )
{
// ok
}
}
@Internal
public byte[] getDataStream()
{
@ -988,7 +1041,7 @@ public final class HWPFDocument extends HWPFDocumentCore
@Internal
public byte[] getTableStream()
{
return _tableStream;
return _tableStream;
}
public int registerList(HWPFList list)

View File

@ -22,12 +22,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import org.apache.poi.hwpf.usermodel.ObjectsPool;
import org.apache.poi.poifs.filesystem.DirectoryEntry;
import org.apache.poi.hwpf.usermodel.ObjectPoolImpl;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.POIDocument;
import org.apache.poi.hwpf.model.CHPBinTable;
@ -38,7 +32,10 @@ import org.apache.poi.hwpf.model.PAPBinTable;
import org.apache.poi.hwpf.model.SectionTable;
import org.apache.poi.hwpf.model.StyleSheet;
import org.apache.poi.hwpf.model.TextPieceTable;
import org.apache.poi.hwpf.usermodel.ObjectPoolImpl;
import org.apache.poi.hwpf.usermodel.ObjectsPool;
import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.poifs.filesystem.DirectoryEntry;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.DocumentEntry;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
@ -53,6 +50,9 @@ import org.apache.poi.util.Internal;
*/
public abstract class HWPFDocumentCore extends POIDocument
{
protected static final String STREAM_OBJECT_POOL = "ObjectPool";
protected static final String STREAM_WORD_DOCUMENT = "WordDocument";
/** Holds OLE2 objects */
protected ObjectPoolImpl _objectPool;
@ -141,40 +141,34 @@ public abstract class HWPFDocumentCore extends POIDocument
* @throws IOException If there is an unexpected IOException from the passed
* in POIFSFileSystem.
*/
public HWPFDocumentCore(DirectoryNode directory) throws IOException
{
public HWPFDocumentCore(DirectoryNode directory) throws IOException {
// Sort out the hpsf properties
super(directory);
super(directory);
// read in the main stream.
DocumentEntry documentProps = (DocumentEntry)
directory.getEntry("WordDocument");
directory.getEntry("WordDocument");
_mainStream = new byte[documentProps.getSize()];
directory.createDocumentInputStream("WordDocument").read(_mainStream);
directory.createDocumentInputStream(STREAM_WORD_DOCUMENT).read(_mainStream);
// Create our FIB, and check for the doc being encrypted
_fib = new FileInformationBlock(_mainStream);
if(_fib.isFEncrypted()) {
throw new EncryptedDocumentException("Cannot process encrypted word files!");
if (_fib.isFEncrypted()) {
throw new EncryptedDocumentException("Cannot process encrypted word files!");
}
{
DirectoryEntry objectPoolEntry;
try
{
objectPoolEntry = (DirectoryEntry) directory
.getEntry( "ObjectPool" );
}
catch ( FileNotFoundException exc )
{
objectPoolEntry = directory.createDirectory( "ObjectPool" );
}
_objectPool = new ObjectPoolImpl( objectPoolEntry );
}
DirectoryEntry objectPoolEntry;
try {
objectPoolEntry = (DirectoryEntry) directory
.getEntry(STREAM_OBJECT_POOL);
} catch (FileNotFoundException exc) {
objectPoolEntry = null;
}
_objectPool = new ObjectPoolImpl(objectPoolEntry);
}
/**
/**
* Returns the range which covers the whole of the document, but excludes
* any headers and footers.
*/

View File

@ -81,6 +81,13 @@ public abstract class AbstractWordConverter
{
return start < o.start ? -1 : start == o.start ? 0 : 1;
}
@Override
public String toString()
{
return "Structure [" + start + "; " + end + "): "
+ structure.toString();
}
}
private static final byte BEL_MARK = 7;
@ -116,8 +123,9 @@ public abstract class AbstractWordConverter
return;
}
if ( ( another.start > structure.start && another.end <= structure.end )
|| ( another.start >= structure.start && another.end < structure.end ) )
if ( ( structure.start < another.start && another.start < structure.end )
|| ( structure.start < another.start && another.end <= structure.end )
|| ( structure.start <= another.start && another.end < structure.end ) )
{
iterator.remove();
continue;
@ -316,7 +324,7 @@ public abstract class AbstractWordConverter
if ( structure.structure instanceof Bookmark )
{
// other bookmarks with same bundaries
// other bookmarks with same boundaries
List<Bookmark> bookmarks = new LinkedList<Bookmark>();
for ( Bookmark bookmark : ( (HWPFDocument) wordDocument )
.getBookmarks()
@ -334,8 +342,8 @@ public abstract class AbstractWordConverter
bookmarkStack.addAll( bookmarks );
try
{
Range subrange = new Range( structure.start, structure.end,
range )
int end = Math.min( range.getEndOffset(), structure.end );
Range subrange = new Range( structure.start, end, range )
{
@Override
public String toString()
@ -364,15 +372,17 @@ public abstract class AbstractWordConverter
+ structure.structure.getClass() );
}
previous = structure.end;
previous = Math.min( range.getEndOffset(), structure.end );
}
if ( previous != range.getStartOffset() )
{
if ( previous > range.getEndOffset() )
{
logger.log( POILogger.WARN, "Latest structure in " + range
+ " ended after range (" + previous + ")" );
logger.log( POILogger.WARN, "Latest structure in ", range,
" ended at #" + previous, " after range boundaries [",
range.getStartOffset() + "; " + range.getEndOffset(),
")" );
return true;
}
@ -597,11 +607,20 @@ public abstract class AbstractWordConverter
public void processDocument( HWPFDocumentCore wordDocument )
{
final SummaryInformation summaryInformation = wordDocument
.getSummaryInformation();
if ( summaryInformation != null )
try
{
processDocumentInformation( summaryInformation );
final SummaryInformation summaryInformation = wordDocument
.getSummaryInformation();
if ( summaryInformation != null )
{
processDocumentInformation( summaryInformation );
}
}
catch ( Exception exc )
{
logger.log( POILogger.WARN,
"Unable to process document summary information: ", exc,
exc );
}
final Range docRange = wordDocument.getRange();
@ -846,6 +865,9 @@ public abstract class AbstractWordConverter
return false;
}
protected abstract void processPageBreak( HWPFDocumentCore wordDocument,
Element flow );
protected abstract void processPageref( HWPFDocumentCore wordDocument,
Element currentBlock, Range textRange, int currentTableLevel,
String pageref );
@ -884,6 +906,11 @@ public abstract class AbstractWordConverter
continue;
}
if ( paragraph.text().equals( "\u000c" ) )
{
processPageBreak( wordDocument, flow );
}
if ( paragraph.getIlfo() != currentListInfo )
{
currentListInfo = paragraph.getIlfo();

View File

@ -130,7 +130,7 @@ public class AbstractWordUtils
return true;
}
static void compactChildNodes( Element parentElement, String childTagName )
static void compactChildNodesR( Element parentElement, String childTagName )
{
NodeList childNodes = parentElement.getChildNodes();
for ( int i = 0; i < childNodes.getLength() - 1; i++ )
@ -146,6 +146,16 @@ public class AbstractWordUtils
child2.getParentNode().removeChild( child2 );
i--;
}
childNodes = parentElement.getChildNodes();
for ( int i = 0; i < childNodes.getLength() - 1; i++ )
{
Node child = childNodes.item( i );
if ( child instanceof Element )
{
compactChildNodesR( (Element) child, childTagName );
}
}
}
static boolean equals( String str1, String str2 )
@ -306,13 +316,26 @@ public class AbstractWordUtils
}
}
public static String getColor24( int value )
public static String getOpacity( int argbValue )
{
if ( value == -1 )
int opacity = (int) ( ( argbValue & 0xFF000000l ) >>> 24 );
if ( opacity == 0 || opacity == 0xFF )
return ".0";
return "" + ( opacity / (float) 0xFF );
}
public static String getColor24( int argbValue )
{
if ( argbValue == -1 )
throw new IllegalArgumentException( "This colorref is empty" );
int bgrValue = argbValue & 0x00FFFFFF;
int rgbValue = ( bgrValue & 0x0000FF ) << 16 | ( bgrValue & 0x00FF00 )
| ( bgrValue & 0xFF0000 ) >> 16;
// http://www.w3.org/TR/REC-html40/types.html#h-6.5
switch ( value )
switch ( rgbValue )
{
case 0xFFFFFF:
return "white";
@ -349,7 +372,7 @@ public class AbstractWordUtils
}
StringBuilder result = new StringBuilder( "#" );
String hex = Integer.toHexString( value );
String hex = Integer.toHexString( rgbValue );
for ( int i = hex.length(); i < 6; i++ )
{
result.append( '0' );

View File

@ -22,49 +22,117 @@ package org.apache.poi.hwpf.converter;
import org.apache.poi.util.Beta;
/**
* Comment me
* Utility class to translate numbers in letters, usually for lists.
*
* @author Ryan Ackley
* @author Sergey Vladimirov (vlsergey {at} gmail {dot} com)
*/
@Beta
public final class NumberFormatter
{
private static String[] C_LETTERS = new String[] { "a", "b", "c", "d", "e",
"f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r",
"s", "t", "u", "v", "x", "y", "z" };
private static final String[] ENGLISH_LETTERS = new String[] { "a", "b",
"c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
"p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" };
private static String[] C_ROMAN = new String[] { "i", "ii", "iii", "iv",
"v", "vi", "vii", "viii", "ix", "x", "xi", "xii", "xiii", "xiv",
"xv", "xvi", "xvii", "xviii", "xix", "xx", "xxi", "xxii", "xxiii",
"xxiv", "xxv", "xxvi", "xxvii", "xxviii", "xxix", "xxx", "xxxi",
"xxxii", "xxxiii", "xxxiv", "xxxv", "xxxvi", "xxxvii", "xxxvii",
"xxxviii", "xxxix", "xl", "xli", "xlii", "xliii", "xliv", "xlv",
"xlvi", "xlvii", "xlviii", "xlix", "l" };
private static final String[] ROMAN_LETTERS = { "m", "cm", "d", "cd", "c",
"xc", "l", "xl", "x", "ix", "v", "iv", "i" };
private final static int T_ARABIC = 0;
private final static int T_LOWER_LETTER = 4;
private final static int T_LOWER_ROMAN = 2;
private final static int T_ORDINAL = 5;
private final static int T_UPPER_LETTER = 3;
private final static int T_UPPER_ROMAN = 1;
private static final int[] ROMAN_VALUES = { 1000, 900, 500, 400, 100, 90,
50, 40, 10, 9, 5, 4, 1 };
private static final int T_ARABIC = 0;
private static final int T_LOWER_LETTER = 4;
private static final int T_LOWER_ROMAN = 2;
private static final int T_ORDINAL = 5;
private static final int T_UPPER_LETTER = 3;
private static final int T_UPPER_ROMAN = 1;
public static String getNumber( int num, int style )
{
switch ( style )
{
case T_UPPER_ROMAN:
return C_ROMAN[num - 1].toUpperCase();
return toRoman( num ).toUpperCase();
case T_LOWER_ROMAN:
return C_ROMAN[num - 1];
return toRoman( num );
case T_UPPER_LETTER:
return C_LETTERS[num - 1].toUpperCase();
return toLetters( num ).toUpperCase();
case T_LOWER_LETTER:
return C_LETTERS[num - 1];
return toLetters( num );
case T_ARABIC:
case T_ORDINAL:
default:
return String.valueOf( num );
}
}
private static String toLetters( int number )
{
final int base = 26;
if ( number <= 0 )
throw new IllegalArgumentException( "Unsupported number: " + number );
if ( number < base + 1 )
return ENGLISH_LETTERS[number - 1];
long toProcess = number;
StringBuilder stringBuilder = new StringBuilder();
int maxPower = 0;
{
int boundary = 0;
while ( toProcess > boundary )
{
maxPower++;
boundary = boundary * base + base;
if ( boundary > Integer.MAX_VALUE )
throw new IllegalArgumentException( "Unsupported number: "
+ toProcess );
}
}
maxPower--;
for ( int p = maxPower; p > 0; p-- )
{
long boundary = 0;
long shift = 1;
for ( int i = 0; i < p; i++ )
{
shift *= base;
boundary = boundary * base + base;
}
int count = 0;
while ( toProcess > boundary )
{
count++;
toProcess -= shift;
}
stringBuilder.append( ENGLISH_LETTERS[count - 1] );
}
stringBuilder.append( ENGLISH_LETTERS[(int) toProcess - 1] );
return stringBuilder.toString();
}
private static String toRoman( int number )
{
if ( number <= 0 )
throw new IllegalArgumentException( "Unsupported number: " + number );
StringBuilder result = new StringBuilder();
for ( int i = 0; i < ROMAN_LETTERS.length; i++ )
{
String letter = ROMAN_LETTERS[i];
int value = ROMAN_VALUES[i];
while ( number >= value )
{
number -= value;
result.append( letter );
}
}
return result.toString();
}
}

View File

@ -50,6 +50,8 @@ import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
/**
@ -119,6 +121,8 @@ public class WordToFoConverter extends AbstractWordConverter
private AtomicInteger internalLinkCounter = new AtomicInteger( 0 );
private boolean outputCharactersLanguage = false;
private Set<String> usedIds = new LinkedHashSet<String>();
/**
@ -202,6 +206,11 @@ public class WordToFoConverter extends AbstractWordConverter
return foDocumentFacade.getDocument();
}
public boolean isOutputCharactersLanguage()
{
return outputCharactersLanguage;
}
@Override
protected void outputCharacters( Element block, CharacterRun characterRun,
String text )
@ -211,11 +220,15 @@ public class WordToFoConverter extends AbstractWordConverter
Triplet triplet = getCharacterRunTriplet( characterRun );
if ( WordToFoUtils.isNotEmpty( triplet.fontName ) )
WordToFoUtils.setFontFamily( inline, characterRun.getFontName() );
WordToFoUtils.setFontFamily( inline, triplet.fontName );
WordToFoUtils.setBold( inline, triplet.bold );
WordToFoUtils.setItalic( inline, triplet.italic );
WordToFoUtils.setFontSize( inline, characterRun.getFontSize() / 2 );
WordToFoUtils.setCharactersProperties( characterRun, inline );
if ( isOutputCharactersLanguage() )
WordToFoUtils.setLanguage( characterRun, inline );
block.appendChild( inline );
Text textNode = foDocumentFacade.createText( text );
@ -411,6 +424,32 @@ public class WordToFoConverter extends AbstractWordConverter
block.appendChild( foDocumentFacade.createBlock() );
}
@Override
protected void processPageBreak( HWPFDocumentCore wordDocument, Element flow )
{
Element block = null;
NodeList childNodes = flow.getChildNodes();
if ( childNodes.getLength() > 0 )
{
Node lastChild = childNodes.item( childNodes.getLength() - 1 );
if ( lastChild instanceof Element )
{
Element lastElement = (Element) lastChild;
if ( !lastElement.hasAttribute( "break-after" ) )
{
block = lastElement;
}
}
}
if ( block == null )
{
block = foDocumentFacade.createBlock();
flow.appendChild( block );
}
block.setAttribute( "break-after", "page" );
}
protected void processPageref( HWPFDocumentCore hwpfDocument,
Element currentBlock, Range textRange, int currentTableLevel,
String pageref )
@ -606,4 +645,9 @@ public class WordToFoConverter extends AbstractWordConverter
return true;
}
public void setOutputCharactersLanguage( boolean outputCharactersLanguage )
{
this.outputCharactersLanguage = outputCharactersLanguage;
}
}

View File

@ -30,7 +30,7 @@ public class WordToFoUtils extends AbstractWordUtils
{
static void compactInlines( Element blockElement )
{
compactChildNodes( blockElement, "fo:inline" );
compactChildNodesR( blockElement, "fo:inline" );
}
public static void setBold( final Element element, final boolean bold )
@ -76,11 +76,11 @@ public class WordToFoUtils extends AbstractWordUtils
{
inline.setAttribute( "color", getColor24( characterRun.getIco24() ) );
}
if ( characterRun.getLanguageCode() != 0 )
final int opacity = (int) ( characterRun.getIco24() & 0xFF000000l ) >>> 24;
if ( opacity != 0 && opacity != 0xFF )
{
final String language = getLanguage( characterRun.getLanguageCode() );
if ( isNotEmpty( language ) )
inline.setAttribute( "language", language );
inline.setAttribute( "opacity",
getOpacity( characterRun.getIco24() ) );
}
if ( characterRun.isCapitalized() )
{
@ -200,6 +200,17 @@ public class WordToFoUtils extends AbstractWordUtils
element.setAttribute( "text-align", justification );
}
public static void setLanguage( final CharacterRun characterRun,
final Element inline )
{
if ( characterRun.getLanguageCode() != 0 )
{
final String language = getLanguage( characterRun.getLanguageCode() );
if ( isNotEmpty( language ) )
inline.setAttribute( "language", language );
}
}
public static void setParagraphProperties( Paragraph paragraph,
Element block )
{

View File

@ -495,6 +495,12 @@ public class WordToHtmlConverter extends AbstractWordConverter
}
}
@Override
protected void processPageBreak( HWPFDocumentCore wordDocument, Element flow )
{
flow.appendChild( htmlDocumentFacade.createLineBreak() );
}
protected void processPageref( HWPFDocumentCore hwpfDocument,
Element currentBlock, Range textRange, int currentTableLevel,
String pageref )

View File

@ -233,7 +233,7 @@ public class WordToHtmlUtils extends AbstractWordUtils
static void compactSpans( Element pElement )
{
compactChildNodes( pElement, "span" );
compactChildNodesR( pElement, "span" );
}
}

View File

@ -48,12 +48,16 @@ import org.apache.poi.hwpf.usermodel.TableRow;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.Entry;
import org.apache.poi.util.Beta;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@Beta
public class WordToTextConverter extends AbstractWordConverter
{
private static final POILogger logger = POILogFactory
.getLogger( WordToTextConverter.class );
public static String getText( DirectoryNode root ) throws Exception
{
@ -325,7 +329,10 @@ public class WordToTextConverter extends AbstractWordConverter
return false;
DirectoryNode directoryNode = (DirectoryNode) entry;
// even if no ExtractorFactory in classpath
/*
* even if there is no ExtractorFactory in classpath, still support
* included Word's objects
*/
if ( directoryNode.hasEntry( "WordDocument" ) )
{
String text = WordToTextConverter.getText( (DirectoryNode) entry );
@ -335,14 +342,27 @@ public class WordToTextConverter extends AbstractWordConverter
return true;
}
Object extractor;
try
{
Class<?> cls = Class
.forName( "org.apache.poi.extractor.ExtractorFactory" );
Method createExtractor = cls.getMethod( "createExtractor",
DirectoryNode.class );
Object extractor = createExtractor.invoke( null, directoryNode );
extractor = createExtractor.invoke( null, directoryNode );
}
catch ( Error exc )
{
// no extractor in classpath
logger.log( POILogger.WARN, "There is an OLE object entry '",
entry.getName(),
"', but there is no text extractor for this object type ",
"or text extractor factory is not available: ", "" + exc );
return false;
}
try
{
Method getText = extractor.getClass().getMethod( "getText" );
String text = (String) getText.invoke( extractor );
@ -351,12 +371,21 @@ public class WordToTextConverter extends AbstractWordConverter
+ UNICODECHAR_ZERO_WIDTH_SPACE ) );
return true;
}
catch ( ClassNotFoundException exc )
catch ( Exception exc )
{
// no extractor in classpath
logger.log( POILogger.ERROR,
"Unable to extract text from OLE entry '", entry.getName(),
"': ", exc, exc );
return false;
}
}
return false;
@Override
protected void processPageBreak( HWPFDocumentCore wordDocument, Element flow )
{
Element block = textDocumentFacade.createBlock();
block.appendChild( textDocumentFacade.createText( "\n" ) );
flow.appendChild( block );
}
@Override

View File

@ -72,9 +72,11 @@ public final class CHPX extends BytePropertyNode<CHPX>
}
CharacterProperties baseStyle = ss.getCharacterStyle( istd );
if (baseStyle == null)
baseStyle = new CharacterProperties();
CharacterProperties props = CharacterSprmUncompressor.uncompressCHP(
baseStyle, getGrpprl(), 0 );
;
return props;
}

View File

@ -208,23 +208,31 @@ public class PAPBinTable
final int startInclusive = lastParStart;
final int endExclusive = charIndex + 1;
boolean broken = false;
List<PAPX> papxs = new LinkedList<PAPX>();
for ( int papxIndex = lastPapxIndex; papxIndex < oldPapxSortedByEndPos
.size(); papxIndex++ )
{
broken = false;
PAPX papx = oldPapxSortedByEndPos.get( papxIndex );
assert papxIndex + 1 == oldPapxSortedByEndPos.size()
assert startInclusive == 0
|| papxIndex + 1 == oldPapxSortedByEndPos.size()
|| papx.getEnd() > startInclusive;
if ( papx.getEnd() - 1 > charIndex )
{
lastPapxIndex = papxIndex;
broken = true;
break;
}
papxs.add( papx );
}
if ( !broken )
{
lastPapxIndex = oldPapxSortedByEndPos.size() - 1;
}
if ( papxs.size() == 0 )
{

View File

@ -58,7 +58,7 @@ public final class CharacterSprmUncompressor extends SprmUncompressor
SprmOperation sprm = sprmIt.next();
if (sprm.getType() != 2) {
logger.log( POILogger.WARN, "Non-CHP SPRM returned by SprmIterator" );
logger.log( POILogger.WARN, "Non-CHP SPRM returned by SprmIterator: " + sprm );
continue;
}

View File

@ -17,10 +17,12 @@
package org.apache.poi.hwpf.usermodel;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.apache.poi.poifs.filesystem.DirectoryEntry;
import org.apache.poi.poifs.filesystem.Entry;
import org.apache.poi.util.Internal;
import org.apache.poi.util.POIUtils;
@Internal
public class ObjectPoolImpl implements ObjectsPool
@ -47,4 +49,11 @@ public class ObjectPoolImpl implements ObjectsPool
return null;
}
}
@Internal
public void writeTo( DirectoryEntry directoryEntry ) throws IOException
{
if ( _objectPool != null )
POIUtils.copyNodeRecursively( _objectPool, directoryEntry );
}
}

View File

@ -21,6 +21,8 @@ import java.lang.ref.WeakReference;
import java.util.List;
import java.util.NoSuchElementException;
import org.apache.poi.hwpf.model.BytePropertyNode;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.HWPFDocumentCore;
import org.apache.poi.hwpf.model.CHPX;
@ -770,16 +772,28 @@ public class Range { // TODO -instantiable superclass
return null;
}
int[] point = findRange( _paragraphs, _parStart,
Math.max( chpx.getStart(), _start ), chpx.getEnd() );
if ( point[0] >= _paragraphs.size() )
short istd;
if ( this instanceof Paragraph )
{
return null;
istd = ((Paragraph) this)._istd;
}
else
{
int[] point = findRange( _paragraphs,
Math.max( chpx.getStart(), _start ),
Math.min( chpx.getEnd(), _end ) );
PAPX papx = _paragraphs.get( point[0] );
short istd = papx.getIstd();
initParagraphs();
int parStart = Math.max( point[0], _parStart );
if ( parStart >= _paragraphs.size() )
{
return null;
}
PAPX papx = _paragraphs.get( point[0] );
istd = papx.getIstd();
}
CharacterRun chp = new CharacterRun( chpx, _doc.getStyleSheet(), istd,
this );
@ -924,7 +938,7 @@ public class Range { // TODO -instantiable superclass
*/
private void initParagraphs() {
if (!_parRangeFound) {
int[] point = findRange(_paragraphs, _parStart, _start, _end);
int[] point = findRange(_paragraphs, _start, _end);
_parStart = point[0];
_parEnd = point[1];
_parRangeFound = true;
@ -936,7 +950,7 @@ public class Range { // TODO -instantiable superclass
*/
private void initCharacterRuns() {
if (!_charRangeFound) {
int[] point = findRange(_characters, _charStart, _start, _end);
int[] point = findRange(_characters, _start, _end);
_charStart = point[0];
_charEnd = point[1];
_charRangeFound = true;
@ -955,6 +969,105 @@ public class Range { // TODO -instantiable superclass
}
}
private static int binarySearchStart( List<? extends PropertyNode<?>> rpl,
int start )
{
if ( rpl.get( 0 ).getStart() >= start )
return 0;
int low = 0;
int high = rpl.size() - 1;
while ( low <= high )
{
int mid = ( low + high ) >>> 1;
PropertyNode<?> node = rpl.get( mid );
if ( node.getStart() < start )
{
low = mid + 1;
}
else if ( node.getStart() > start )
{
high = mid - 1;
}
else
{
assert node.getStart() == start;
return mid;
}
}
assert low != 0;
return low - 1;
}
private static int binarySearchEnd( List<? extends PropertyNode<?>> rpl,
int foundStart, int end )
{
if ( rpl.get( rpl.size() - 1 ).getEnd() <= end )
return rpl.size() - 1;
int low = foundStart;
int high = rpl.size() - 1;
while ( low <= high )
{
int mid = ( low + high ) >>> 1;
PropertyNode<?> node = rpl.get( mid );
if ( node.getEnd() < end )
{
low = mid + 1;
}
else if ( node.getEnd() > end )
{
high = mid - 1;
}
else
{
assert node.getEnd() == end;
return mid;
}
}
assert 0 <= low && low < rpl.size();
return low;
}
/**
* Used to find the list indexes of a particular property.
*
* @param rpl
* A list of property nodes.
* @param min
* A hint on where to start looking.
* @param start
* The starting character offset.
* @param end
* The ending character offset.
* @return An int array of length 2. The first int is the start index and
* the second int is the end index.
*/
private int[] findRange( List<? extends PropertyNode<?>> rpl, int start,
int end )
{
int startIndex = binarySearchStart( rpl, start );
while ( startIndex > 0 && rpl.get( startIndex - 1 ).getStart() >= start )
startIndex--;
int endIndex = binarySearchEnd( rpl, startIndex, end );
while ( endIndex < rpl.size() - 1
&& rpl.get( endIndex + 1 ).getEnd() <= end )
endIndex--;
if ( startIndex < 0 || startIndex >= rpl.size()
|| startIndex > endIndex || endIndex < 0
|| endIndex >= rpl.size() )
throw new AssertionError();
return new int[] { startIndex, endIndex + 1 };
}
/**
* Used to find the list indexes of a particular property.
*
@ -971,7 +1084,7 @@ public class Range { // TODO -instantiable superclass
*/
private int[] findRange(List<? extends PropertyNode<?>> rpl, int min, int start, int end) {
int x = min;
if ( rpl.size() == min )
return new int[] { min, min };
@ -1138,7 +1251,7 @@ public class Range { // TODO -instantiable superclass
{
if ( _start < 0 )
throw new AssertionError();
if ( _start >= _text.length() )
if ( _start > _text.length() )
throw new AssertionError();
if ( _end < 0 )
throw new AssertionError();

View File

@ -20,6 +20,7 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.zip.ZipInputStream;
import org.apache.poi.POIDataSamples;
@ -90,6 +91,58 @@ public class HWPFTestDataSamples {
}
}
/**
* Open a remote sample from URL. opening is performd in two phases:
* (1) download content into a byte array
* (2) construct HWPFDocument
*
* @param sampleFileUrl the url to open
*/
public static HWPFDocument openRemoteFile( String sampleFileUrl )
{
final long start = System.currentTimeMillis();
try
{
InputStream is = new URL( sampleFileUrl ).openStream();
try
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try
{
IOUtils.copy( is, baos );
}
finally
{
baos.close();
}
final long endDownload = System.currentTimeMillis();
byte[] byteArray = baos.toByteArray();
logger.log( POILogger.DEBUG, "Downloaded in ",
Long.valueOf( endDownload - start ), " ms -- ",
Long.valueOf( byteArray.length ), " byte(s)" );
ByteArrayInputStream bais = new ByteArrayInputStream( byteArray );
HWPFDocument doc = new HWPFDocument( bais );
final long endParse = System.currentTimeMillis();
logger.log( POILogger.DEBUG, "Parsed in ",
Long.valueOf( endParse - start ), " ms" );
return doc;
}
finally
{
is.close();
}
}
catch ( IOException e )
{
throw new RuntimeException( e );
}
}
public static HWPFOldDocument openOldSampleFile(String sampleFileName) {
try {
InputStream is = POIDataSamples.getDocumentInstance().openResourceAsStream(sampleFileName);

View File

@ -0,0 +1,75 @@
package org.apache.poi.hwpf.converter;
import junit.framework.TestCase;
public class TestNumberFormatter extends TestCase
{
public void testRoman()
{
assertEquals( "i", NumberFormatter.getNumber( 1, 2 ) );
assertEquals( "ii", NumberFormatter.getNumber( 2, 2 ) );
assertEquals( "iii", NumberFormatter.getNumber( 3, 2 ) );
assertEquals( "iv", NumberFormatter.getNumber( 4, 2 ) );
assertEquals( "v", NumberFormatter.getNumber( 5, 2 ) );
assertEquals( "vi", NumberFormatter.getNumber( 6, 2 ) );
assertEquals( "vii", NumberFormatter.getNumber( 7, 2 ) );
assertEquals( "viii", NumberFormatter.getNumber( 8, 2 ) );
assertEquals( "ix", NumberFormatter.getNumber( 9, 2 ) );
assertEquals( "x", NumberFormatter.getNumber( 10, 2 ) );
assertEquals( "mdcvi", NumberFormatter.getNumber( 1606, 2 ) );
assertEquals( "mcmx", NumberFormatter.getNumber( 1910, 2 ) );
assertEquals( "mcmliv", NumberFormatter.getNumber( 1954, 2 ) );
}
public void testEnglish()
{
assertEquals( "a", NumberFormatter.getNumber( 1, 4 ) );
assertEquals( "z", NumberFormatter.getNumber( 26, 4 ) );
assertEquals( "aa", NumberFormatter.getNumber( 1 * 26 + 1, 4 ) );
assertEquals( "az", NumberFormatter.getNumber( 1 * 26 + 26, 4 ) );
assertEquals( "za", NumberFormatter.getNumber( 26 * 26 + 1, 4 ) );
assertEquals( "zz", NumberFormatter.getNumber( 26 * 26 + 26, 4 ) );
assertEquals( "aaa",
NumberFormatter.getNumber( 26 * 26 + 1 * 26 + 1, 4 ) );
assertEquals( "aaz",
NumberFormatter.getNumber( 26 * 26 + 1 * 26 + 26, 4 ) );
assertEquals( "aba",
NumberFormatter.getNumber( 1 * 26 * 26 + 2 * 26 + 1, 4 ) );
assertEquals( "aza",
NumberFormatter.getNumber( 1 * 26 * 26 + 26 * 26 + 1, 4 ) );
assertEquals( "azz",
NumberFormatter.getNumber( 26 * 26 + 26 * 26 + 26, 4 ) );
assertEquals( "baa",
NumberFormatter.getNumber( 2 * 26 * 26 + 1 * 26 + 1, 4 ) );
assertEquals( "zaa",
NumberFormatter.getNumber( 26 * 26 * 26 + 1 * 26 + 1, 4 ) );
assertEquals( "zzz",
NumberFormatter.getNumber( 26 * 26 * 26 + 26 * 26 + 26, 4 ) );
assertEquals(
"aaaa",
NumberFormatter.getNumber( 1 * 26 * 26 * 26 + 1 * 26 * 26 + 1
* 26 + 1, 4 ) );
assertEquals(
"azzz",
NumberFormatter.getNumber( 1 * 26 * 26 * 26 + 26 * 26 * 26 + 26
* 26 + 26, 4 ) );
assertEquals(
"zzzz",
NumberFormatter.getNumber( 26 * 26 * 26 * 26 + 26 * 26 * 26
+ 26 * 26 + 26, 4 ) );
for ( int i = 1; i < 1000000; i++ )
{
// make sure there is no exceptions
NumberFormatter.getNumber( i, 4 );
}
}
}

View File

@ -125,6 +125,22 @@ public class TestWordToFoConverter extends TestCase
"padding-end=\"0.0in\" padding-start=\"0.0in\" width=\"1.0770833in\"" );
}
public void testPageBreak() throws Exception
{
final String sampleFileName = "page-break.doc";
String result = getFoText( sampleFileName );
assertContains( result, "<fo:block break-before=\"page\"" );
}
public void testPageBreakBefore() throws Exception
{
final String sampleFileName = "page-break-before.doc";
String result = getFoText( sampleFileName );
assertContains( result, "<fo:block break-before=\"page\"" );
}
public void testPageref() throws Exception
{
final String sampleFileName = "pageref.doc";

View File

@ -130,7 +130,7 @@ public class TestWordToHtmlConverter extends TestCase
assertFalse( result.contains( "FORMTEXT" ) );
assertContains( result, "color:#28624f;" );
assertContains( result, "color:#4f6228;" );
assertContains( result, "Passport No and the date of expire" );
assertContains( result, "mfa.gov.cy" );
}

View File

@ -24,9 +24,13 @@ import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.HWPFTestDataSamples;
import org.apache.poi.hwpf.OldWordFileFormatException;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.Entry;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import java.io.IOException;
import java.io.InputStream;
/**
* Test the different routes to extracting text
*
@ -353,4 +357,27 @@ public final class TestWordExtractor extends TestCase {
assertEquals(p_text1_block, extractor.getText());
}
}
/**
* [RESOLVED FIXED] Bug 51686 - Update to POI 3.8 beta 4 causes
* ConcurrentModificationException in Tika's OfficeParser
*/
public void testBug51686() throws IOException
{
InputStream is = POIDataSamples.getDocumentInstance()
.openResourceAsStream( "Bug51686.doc" );
POIFSFileSystem fs = new POIFSFileSystem(is);
String text = null;
for (Entry entry : fs.getRoot()) {
if ("WordDocument".equals(entry.getName())) {
WordExtractor ex = new WordExtractor(fs);
text = ex.getText();
}
}
assertNotNull(text);
}
}

View File

@ -16,6 +16,7 @@
==================================================================== */
package org.apache.poi.hwpf.usermodel;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
@ -24,6 +25,8 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import junit.framework.TestCase;
import org.apache.commons.codec.digest.DigestUtils;
@ -508,14 +511,6 @@ public class TestBugs extends TestCase
}
}
/**
* Bug 51524 - PapBinTable constructor is slow
*/
public void test51524()
{
HWPFTestDataSamples.openSampleFileFromArchive( "Bug51524.zip" );
}
/**
* [RESOLVED FIXED] Bug 51604 - replace text fails for doc ( poi 3.8 beta
* release from download site )
@ -630,4 +625,38 @@ public class TestBugs extends TestCase
assertEquals( Arrays.toString( oldData ), Arrays.toString( newData ) );
}
/**
* [RESOLVED FIXED] Bug 51671 - HWPFDocument.write based on NPOIFSFileSystem
* throws a NullPointerException
*/
public void test51671() throws Exception
{
InputStream is = POIDataSamples.getDocumentInstance()
.openResourceAsStream( "empty.doc" );
NPOIFSFileSystem npoifsFileSystem = new NPOIFSFileSystem( is );
HWPFDocument hwpfDocument = new HWPFDocument(
npoifsFileSystem.getRoot() );
hwpfDocument.write( new ByteArrayOutputStream() );
}
/**
* Bug 51678 - Extracting text from Bug51524.zip is slow
* Bug 51524 - PapBinTable constructor is slow
*/
public void test51678And51524()
{
// YK: the test will run only if the poi.test.remote system property is set.
// TODO: refactor into something nicer!
if(System.getProperty("poi.test.remote") != null) {
String href = "http://domex.nps.edu/corp/files/govdocs1/007/007488.doc";
HWPFDocument hwpfDocument = HWPFTestDataSamples.openRemoteFile( href );
WordExtractor wordExtractor = new WordExtractor( hwpfDocument );
wordExtractor.getText();
}
}
}

View File

@ -42,7 +42,7 @@ public final class TestHWPFOldDocument extends HWPFTestCase {
// Check
assertEquals(1, doc.getRange().numSections());
assertEquals(1, doc.getRange().numParagraphs());
assertEquals(1, doc.getRange().numCharacterRuns());
assertEquals(2, doc.getRange().numCharacterRuns());
assertEquals(
"The quick brown fox jumps over the lazy dog\r",
@ -96,7 +96,7 @@ public final class TestHWPFOldDocument extends HWPFTestCase {
assertEquals(5, doc.getRange().getParagraph(4).numCharacterRuns());
assertEquals(1, doc.getRange().getParagraph(5).numCharacterRuns());
// Normal, superscript for 4th, normal
assertEquals(3, doc.getRange().getParagraph(6).numCharacterRuns());
assertEquals(4, doc.getRange().getParagraph(6).numCharacterRuns());
}
/**

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.