\r
protected XSLFGroupShape(CTGroupShape shape, XSLFSheet sheet){\r
super(shape,sheet);\r
- _shapes = sheet.buildShapes(shape);\r
+ _shapes = XSLFSheet.buildShapes(shape, sheet);\r
_grpSpPr = shape.getGrpSpPr();\r
}\r
\r
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+\r
+\r
+package org.apache.poi.xslf.usermodel;\r
+\r
+import java.io.ByteArrayInputStream;\r
+import java.io.IOException;\r
+\r
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;\r
+import org.apache.poi.openxml4j.opc.OPCPackage;\r
+import org.apache.poi.openxml4j.opc.PackagePart;\r
+import org.apache.poi.openxml4j.opc.PackagePartName;\r
+import org.apache.poi.openxml4j.opc.PackagingURIHelper;\r
+import org.apache.poi.sl.usermodel.Shape;\r
+import org.apache.poi.util.Internal;\r
+import org.apache.xmlbeans.XmlException;\r
+import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;\r
+\r
+/**\r
+ * Experimental class for metro blobs, i.e. an alternative escher property\r
+ * containing an ooxml representation of the shape.\r
+ * This is the helper class for HSLFMetroShape to dive into OOXML classes\r
+ */\r
+@Internal\r
+public class XSLFMetroShape {\r
+ /*\r
+ * parses the metro bytes to a XSLF shape\r
+ */\r
+ public static Shape<?,?> parseShape(byte metroBytes[])\r
+ throws InvalidFormatException, IOException, XmlException {\r
+ PackagePartName shapePN = PackagingURIHelper.createPartName("/drs/shapexml.xml");\r
+ OPCPackage pkg = null;\r
+ try {\r
+ pkg = OPCPackage.open(new ByteArrayInputStream(metroBytes));\r
+ PackagePart shapePart = pkg.getPart(shapePN);\r
+ CTGroupShape gs = CTGroupShape.Factory.parse(shapePart.getInputStream());\r
+ XSLFGroupShape xgs = new XSLFGroupShape(gs, null);\r
+ return xgs.getShapes().get(0); \r
+ } finally {\r
+ if (pkg != null) {\r
+ pkg.close();\r
+ }\r
+ }\r
+ }\r
+}\r
throw new IllegalStateException("SlideShow was not found");
}
- protected List<XSLFShape> buildShapes(CTGroupShape spTree){
+ protected static List<XSLFShape> buildShapes(CTGroupShape spTree, XSLFSheet sheet){
List<XSLFShape> shapes = new ArrayList<XSLFShape>();
for(XmlObject ch : spTree.selectPath("*")){
if(ch instanceof CTShape){ // simple shape
- XSLFAutoShape shape = XSLFAutoShape.create((CTShape)ch, this);
+ XSLFAutoShape shape = XSLFAutoShape.create((CTShape)ch, sheet);
shapes.add(shape);
} else if (ch instanceof CTGroupShape){
- shapes.add(new XSLFGroupShape((CTGroupShape)ch, this));
+ shapes.add(new XSLFGroupShape((CTGroupShape)ch, sheet));
} else if (ch instanceof CTConnector){
- shapes.add(new XSLFConnectorShape((CTConnector)ch, this));
+ shapes.add(new XSLFConnectorShape((CTConnector)ch, sheet));
} else if (ch instanceof CTPicture){
- shapes.add(new XSLFPictureShape((CTPicture)ch, this));
+ shapes.add(new XSLFPictureShape((CTPicture)ch, sheet));
} else if (ch instanceof CTGraphicalObjectFrame){
- XSLFGraphicFrame shape = XSLFGraphicFrame.create((CTGraphicalObjectFrame)ch, this);
+ XSLFGraphicFrame shape = XSLFGraphicFrame.create((CTGraphicalObjectFrame)ch, sheet);
shapes.add(shape);
}
}
_drawing = new XSLFDrawing(this, cgs);
}
if (_shapes == null) {
- _shapes = buildShapes(cgs);
+ _shapes = buildShapes(cgs, this);
}
}
import static org.junit.Assert.assertTrue;\r
\r
import java.awt.Color;\r
+import java.io.File;\r
import java.io.IOException;\r
import java.util.List;\r
\r
+import org.apache.poi.POIDataSamples;\r
+import org.apache.poi.hslf.usermodel.HSLFTextShape;\r
import org.apache.poi.sl.usermodel.SimpleShape.Placeholder;\r
+import org.apache.poi.sl.usermodel.SlideShow;\r
+import org.apache.poi.sl.usermodel.SlideShowFactory;\r
import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;\r
import org.apache.poi.sl.usermodel.VerticalAlignment;\r
import org.apache.poi.xslf.XSLFTestDataSamples;\r
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;\r
import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;\r
\r
-/**\r
- * @author Yegor Kozlov\r
- */\r
public class TestXSLFTextShape {\r
\r
@Test\r
\r
ppt.close();\r
}\r
+ \r
+ @Test\r
+ public void metroBlob() throws IOException {\r
+ File f = POIDataSamples.getSlideShowInstance().getFile("bug52297.ppt");\r
+ SlideShow<?,?> ppt = SlideShowFactory.create(f);\r
+ HSLFTextShape sh = (HSLFTextShape)ppt.getSlides().get(1).getShapes().get(3);\r
+ XSLFAutoShape xsh = (XSLFAutoShape)sh.getMetroShape();\r
+ String textExp = " ___ ___ ___ ________ __ _______ ___ ___________ __________ __ _____ ___ ___ ___ _______ ____ ______ ___________ _____________ ___ _______ ______ ____ ______ __ ___________ __________ ___ _________ _____ ________ __________ ___ _______ __________ ";\r
+ String textAct = xsh.getText();\r
+ ppt.close();\r
+ assertEquals(textExp, textAct);\r
+ }\r
}
\ No newline at end of file
--- /dev/null
+/* ====================================================================\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to You under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hslf.model;\r
+\r
+import java.lang.reflect.Method;\r
+\r
+import org.apache.poi.ddf.AbstractEscherOptRecord;\r
+import org.apache.poi.ddf.EscherComplexProperty;\r
+import org.apache.poi.ddf.EscherProperties;\r
+import org.apache.poi.ddf.EscherTertiaryOptRecord;\r
+import org.apache.poi.hslf.usermodel.HSLFShape;\r
+import org.apache.poi.sl.usermodel.Shape;\r
+import org.apache.poi.util.Internal;\r
+import org.apache.poi.util.POILogFactory;\r
+import org.apache.poi.util.POILogger;\r
+\r
+/**\r
+ * Experimental class for metro blobs, i.e. an alternative escher property\r
+ * containing an ooxml representation of the shape\r
+ */\r
+@Internal\r
+public class HSLFMetroShape<T extends Shape<?,?>> {\r
+ private static final POILogger LOGGER = POILogFactory.getLogger(HSLFMetroShape.class);\r
+ \r
+ private final HSLFShape shape;\r
+\r
+ public HSLFMetroShape(HSLFShape shape) {\r
+ this.shape = shape;\r
+ }\r
+ \r
+ /**\r
+ * @return the bytes of the metro blob, which are bytes of an OPCPackage, i.e. a zip stream \r
+ */\r
+ public byte[] getMetroBytes() {\r
+ AbstractEscherOptRecord opt = shape.getEscherChild(EscherTertiaryOptRecord.RECORD_ID);\r
+ if (opt != null) {\r
+ EscherComplexProperty ep = (EscherComplexProperty)opt.lookup(EscherProperties.GROUPSHAPE__METROBLOB);\r
+ if (ep != null) {\r
+ return ep.getComplexData();\r
+ }\r
+ }\r
+ return null;\r
+ }\r
+ \r
+ /**\r
+ * @return the metro blob shape or null if either there's no metro blob or the ooxml classes\r
+ * aren't in the classpath\r
+ */\r
+ @SuppressWarnings("unchecked")\r
+ public T getShape() {\r
+ byte metroBytes[] = getMetroBytes();\r
+ if (metroBytes == null) {\r
+ return null;\r
+ }\r
+ \r
+ // org.apache.poi.xslf.usermodel.XSLFMetroShape\r
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();\r
+ try {\r
+ Class<?> ms = cl.loadClass("org.apache.poi.xslf.usermodel.XSLFMetroShape");\r
+ Method m = ms.getMethod("parseShape", byte[].class);\r
+ return (T)m.invoke(null, new Object[]{metroBytes});\r
+ } catch (Exception e) {\r
+ LOGGER.log(POILogger.ERROR, "can't process metro blob, check if all dependencies for POI OOXML are in the classpath.", e);\r
+ return null;\r
+ }\r
+ }\r
+}\r
+\r
// TODO Auto-generated method stub
}
+
+ @Override
+ public boolean getFollowMasterGraphics() {
+ return getFollowMasterObjects();
+ }
}
package org.apache.poi.hslf.usermodel;
-import org.apache.poi.ddf.*;
-import org.apache.poi.sl.usermodel.*;
+import org.apache.poi.ddf.EscherContainerRecord;
+import org.apache.poi.ddf.EscherProperties;
+import org.apache.poi.sl.usermodel.ShapeContainer;
+import org.apache.poi.sl.usermodel.ShapeType;
+import org.apache.poi.sl.usermodel.TextBox;
+import org.apache.poi.sl.usermodel.VerticalAlignment;
/**
* Represents a TextFrame shape in PowerPoint.
setVerticalAlignment(VerticalAlignment.TOP);
setEscherProperty(EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x20002);
}
-
}
}\r
return sb.toString();\r
}\r
+ \r
+ @Override\r
+ public String toString() {\r
+ StringBuilder sb = new StringBuilder();\r
+ for (HSLFTextRun r : getTextRuns()) {\r
+ sb.append(r.getRawText());\r
+ }\r
+ return toExternalString(sb.toString(), getRunType());\r
+ }\r
\r
/**\r
* Returns a new string with line breaks converted into internal ppt\r
import org.apache.poi.ddf.EscherSimpleProperty;
import org.apache.poi.ddf.EscherTextboxRecord;
import org.apache.poi.hslf.exceptions.HSLFException;
+import org.apache.poi.hslf.model.HSLFMetroShape;
import org.apache.poi.hslf.record.EscherTextboxWrapper;
import org.apache.poi.hslf.record.InteractiveInfo;
import org.apache.poi.hslf.record.InteractiveInfoAtom;
*/
public static final int WrapThrough = 4;
-
+
/**
* TextRun object which holds actual text and format data
*/
/**
* This setting is used for supporting a deprecated alignment
- *
+ *
* @see <a href=""></a>
*/
boolean alignToBaseline = false;
-
+
/**
* Used to calculate text bounds
*/
super.afterInsert(sh);
storeText();
-
+
EscherTextboxWrapper thisTxtbox = getEscherTextboxWrapper();
if(thisTxtbox != null){
_escherContainer.addChildRecord(thisTxtbox.getEscherRecord());
-
+
PPDrawing ppdrawing = sh.getPPDrawing();
ppdrawing.addTextboxWrapper(thisTxtbox);
// Ensure the escher layer knows about the added records
protected EscherTextboxWrapper getEscherTextboxWrapper(){
if(_txtbox != null) return _txtbox;
-
+
EscherTextboxRecord textRecord = getEscherChild(EscherTextboxRecord.RECORD_ID);
if (textRecord == null) return null;
-
+
HSLFSheet sheet = getSheet();
if (sheet != null) {
PPDrawing drawing = sheet.getPPDrawing();
}
}
}
-
+
_txtbox = new EscherTextboxWrapper(textRecord);
return _txtbox;
}
anchor.setSize(200, (int)anchor.getHeight());
setAnchor(anchor);
}
- double height = getTextHeight();
+ double height = getTextHeight();
height += 1; // add a pixel to compensate rounding errors
-
+
anchor.setRect(anchor.getX(), anchor.getY(), anchor.getWidth(), height);
setAnchor(anchor);
-
+
return anchor;
- }
-
+ }
+
/**
* Returns the type of the text, from the TextHeaderAtom.
* Possible values can be seen from TextHeaderAtom
paras.get(0).setRunType(type);
}
}
-
+
/**
* Returns the type of vertical alignment for the text.
* One of the <code>Anchor*</code> constants defined in this class.
alignToBaseline = (align == AnchorBottomBaseline || align == AnchorBottomCenteredBaseline
|| align == AnchorTopBaseline || align == AnchorTopCenteredBaseline);
-
+
return align;
}
align = new int[]{AnchorBottom, AnchorBottomCentered, AnchorBottomBaseline, AnchorBottomCenteredBaseline};
break;
}
-
+
int align2 = align[(isCentered ? 1 : 0)+(alignToBaseline ? 2 : 0)];
-
+
setEscherProperty(EscherProperties.TEXT__ANCHORTEXT, align2);
}
-
+
/**
* @return true, if vertical alignment is relative to baseline
- * this is only used for older versions less equals Office 2003
+ * this is only used for older versions less equals Office 2003
*/
public boolean isAlignToBaseline() {
getAlignment();
this.alignToBaseline = alignToBaseline;
setAlignment(isHorizontalCentered(), getVerticalAlignment());
}
-
+
@Override
public boolean isHorizontalCentered() {
int va = getAlignment();
public void setHorizontalCentered(Boolean isCentered) {
setAlignment(isCentered, getVerticalAlignment());
}
-
+
@Override
public VerticalAlignment getVerticalAlignment() {
int va = getAlignment();
* Returns the distance (in points) between the edge of the text frame
* and the edge of the inscribed rectangle of the shape that contains the text.
* Default value is 1/20 inch.
- *
+ *
* @param propId the id of the inset edge
* @return the inset in points
*/
AbstractEscherOptRecord opt = getEscherOptRecord();
EscherSimpleProperty prop = getEscherProperty(opt, propId);
int val = prop == null ? (int)(Units.toEMU(Units.POINT_DPI)*defaultInch) : prop.getPropertyValue();
- return Units.toPoints(val);
+ return Units.toPoints(val);
}
/**
*/
private void setInset(short propId, double margin){
setEscherProperty(propId, Units.toEMU(margin));
- }
-
+ }
+
/**
* Returns the value indicating word wrap.
*
EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__WRAPTEXT);
return prop == null ? WrapSquare : prop.getPropertyValue();
}
-
+
/**
* Specifies how the text should be wrapped
*
public void setWordWrap(boolean wrap) {
setWordWrapEx(wrap ? WrapSquare : WrapNone);
}
-
+
/**
* @return id for the text.
*/
@Override
public List<HSLFTextParagraph> getTextParagraphs(){
if (!_paragraphs.isEmpty()) return _paragraphs;
-
+
_txtbox = getEscherTextboxWrapper();
if (_txtbox == null) {
_paragraphs.addAll(HSLFTextParagraph.createEmptyParagraph());
// there are actually TextBoxRecords without extra data - see #54722
_paragraphs = HSLFTextParagraph.createEmptyParagraph(_txtbox);
}
-
+
if (_paragraphs.isEmpty()) {
logger.log(POILogger.WARN, "TextRecord didn't contained any text lines");
}
for (HSLFTextParagraph p : _paragraphs) {
p.setParentShape(this);
}
-
+
return _paragraphs;
}
// them to \n
String text = rawText.replace('\r','\n').replace('\u000b', replChr);
*/
-
+
/**
* Return <code>OEPlaceholderAtom</code>, the atom that describes a placeholder.
*
return HSLFTextParagraph.toExternalString(rawText, getRunType());
}
-
+
// Update methods follow
/**
* Adds the supplied text onto the end of the TextParagraphs,
* creating a new RichTextRun for it to sit in.
- *
+ *
* @param text the text string used by this object.
*/
public HSLFTextRun appendText(String text, boolean newParagraph) {
setTextId(text.hashCode());
return htr;
}
-
+
/**
* Saves the modified paragraphs/textrun to the records.
* Also updates the styles to the correct text length.
/**
* Returns the array of all hyperlinks in this text run
- *
+ *
* @return the array of all hyperlinks in this text run or <code>null</code>
* if not found.
*/
}
}
-
+
+ /**
+ * Get alternative representation of text shape stored as metro blob escher property.
+ * The returned shape is the first shape in stored group shape of the metro blob
+ *
+ * @return null, if there's no alternative representation, otherwise the text shape
+ */
+ public TextShape<?,?> getMetroShape() {
+ HSLFMetroShape<TextShape<?,?>> mbs = new HSLFMetroShape<TextShape<?,?>>(this);
+ return mbs.getShape();
+ }
}
\ No newline at end of file