]> source.dussan.org Git - poi.git/commitdiff
Test and fix for bug #46441
authorAndreas Beeker <kiwiwings@apache.org>
Fri, 2 Jan 2015 22:57:05 +0000 (22:57 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Fri, 2 Jan 2015 22:57:05 +0000 (22:57 +0000)
Use generics on Shape.getEscherChild() and SimpleShape.getClientDataRecord() to minimize casting
Unify access to Shape.getEscherOptRecord()

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1649152 13f79535-47bb-0310-9956-ffa450edef68

19 files changed:
src/java/org/apache/poi/ddf/EscherArrayProperty.java
src/java/org/apache/poi/ddf/EscherColorRef.java [new file with mode: 0644]
src/java/org/apache/poi/util/Units.java
src/scratchpad/src/org/apache/poi/hslf/model/ActiveXShape.java
src/scratchpad/src/org/apache/poi/hslf/model/Fill.java
src/scratchpad/src/org/apache/poi/hslf/model/Freeform.java
src/scratchpad/src/org/apache/poi/hslf/model/MovieShape.java
src/scratchpad/src/org/apache/poi/hslf/model/Picture.java
src/scratchpad/src/org/apache/poi/hslf/model/Shape.java
src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java
src/scratchpad/src/org/apache/poi/hslf/model/ShapeGroup.java
src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java
src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java
src/scratchpad/src/org/apache/poi/hslf/model/Slide.java
src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java
src/scratchpad/testcases/org/apache/poi/hslf/model/TestBackground.java
src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java
src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java
test-data/slideshow/bug46441.ppt [new file with mode: 0644]

index 01e2f5c36504ad37246861e2bc23f9359a4cdc45..880057e0ff3382f05356c5016e3cd39cbd088d18 100644 (file)
 
 package org.apache.poi.ddf;
 
-import org.apache.poi.util.LittleEndian;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
 import org.apache.poi.util.HexDump;
+import org.apache.poi.util.LittleEndian;
 
 /**
  * Escher array properties are the most wierd construction ever invented
@@ -26,7 +29,7 @@ import org.apache.poi.util.HexDump;
  *
  * @author Glen Stampoultzis (glens at superlinksoftware.com)
  */
-public final class EscherArrayProperty extends EscherComplexProperty {
+public final class EscherArrayProperty extends EscherComplexProperty implements Iterable<byte[]> {
     /**
      * The size of the header that goes at the
      *  start of the array, before the data
@@ -205,4 +208,24 @@ public final class EscherArrayProperty extends EscherComplexProperty {
         }
         return sizeOfElements;
     }
+
+    public Iterator<byte[]> iterator() {
+        return new Iterator<byte[]>(){
+            int idx = 0;
+            public boolean hasNext() {
+                return (idx < getNumberOfElementsInArray());
+            }
+            
+            public byte[] next() {
+                if (!hasNext()) throw new NoSuchElementException();
+                return getElement(idx++);
+            }
+            
+            public void remove() {
+                throw new UnsupportedOperationException("not yet implemented");
+            }
+        };
+    }
+    
+    
 }
diff --git a/src/java/org/apache/poi/ddf/EscherColorRef.java b/src/java/org/apache/poi/ddf/EscherColorRef.java
new file mode 100644 (file)
index 0000000..dd2626b
--- /dev/null
@@ -0,0 +1,283 @@
+/* ====================================================================\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.ddf;\r
+\r
+import org.apache.poi.util.BitField;\r
+import org.apache.poi.util.LittleEndian;\r
+\r
+/**\r
+ * An OfficeArtCOLORREF structure entry which also handles color extension opid data\r
+ */\r
+public class EscherColorRef {\r
+    int opid = -1;\r
+    int colorRef = 0;\r
+\r
+    public enum SysIndexSource {\r
+        /** Use the fill color of the shape. */\r
+        FILL_COLOR(0xF0),\r
+        /** If the shape contains a line, use the line color of the shape. Otherwise, use the fill color. */\r
+        LINE_OR_FILL_COLOR(0xF1),\r
+        /** Use the line color of the shape. */\r
+        LINE_COLOR(0xF2),\r
+        /** Use the shadow color of the shape. */\r
+        SHADOW_COLOR(0xF3),\r
+        /** Use the current, or last-used, color. */\r
+        CURRENT_OR_LAST_COLOR(0xF4),\r
+        /** Use the fill background color of the shape. */\r
+        FILL_BACKGROUND_COLOR(0xF5),\r
+        /** Use the line background color of the shape. */\r
+        LINE_BACKGROUND_COLOR(0xF6),\r
+        /** If the shape contains a fill, use the fill color of the shape. Otherwise, use the line color. */\r
+        FILL_OR_LINE_COLOR(0xF7)\r
+        ;\r
+        int value;\r
+        SysIndexSource(int value) { this.value = value; }\r
+    }\r
+\r
+    /**\r
+     * The following enum specifies values that indicate special procedural properties that\r
+     * are used to modify the color components of another color. These values are combined with\r
+     * those of the {@link SysIndexSource} enum or with a user-specified color.\r
+     * The first six values are mutually exclusive.\r
+     */\r
+    public enum SysIndexProcedure {\r
+        /**\r
+         * Darken the color by the value that is specified in the blue field.\r
+         * A blue value of 0xFF specifies that the color is to be left unchanged,\r
+         * whereas a blue value of 0x00 specifies that the color is to be completely darkened.\r
+         */\r
+        DARKEN_COLOR(0x01),\r
+        /**\r
+         * Lighten the color by the value that is specified in the blue field.\r
+         * A blue value of 0xFF specifies that the color is to be left unchanged,\r
+         * whereas a blue value of 0x00 specifies that the color is to be completely lightened.\r
+         */\r
+        LIGHTEN_COLOR(0x02),\r
+        /**\r
+         * Add a gray level RGB value. The blue field contains the gray level to add:\r
+         * NewColor = SourceColor + gray\r
+         */\r
+        ADD_GRAY_LEVEL(0x03),\r
+        /**\r
+         * Subtract a gray level RGB value. The blue field contains the gray level to subtract:\r
+         * NewColor = SourceColor - gray\r
+         */\r
+        SUB_GRAY_LEVEL(0x04),\r
+        /**\r
+         * Reverse-subtract a gray level RGB value. The blue field contains the gray level from\r
+         * which to subtract:\r
+         * NewColor = gray - SourceColor\r
+         */\r
+        REVERSE_GRAY_LEVEL(0x05),\r
+        /**\r
+         * If the color component being modified is less than the parameter contained in the blue\r
+         * field, set it to the minimum intensity. If the color component being modified is greater\r
+         * than or equal to the parameter, set it to the maximum intensity.\r
+         */\r
+        THRESHOLD(0x06),\r
+        /**\r
+         * After making other modifications, invert the color.\r
+         * This enum value is only for documentation and won't be directly returned.\r
+         */\r
+        INVERT_AFTER(0x20),\r
+        /**\r
+         * After making other modifications, invert the color by toggling just the high bit of each\r
+         * color channel.\r
+         * This enum value is only for documentation and won't be directly returned.\r
+         */\r
+        INVERT_HIGHBIT_AFTER(0x40)\r
+        ;\r
+        BitField mask;\r
+        SysIndexProcedure(int mask) {\r
+            this.mask = new BitField(mask);\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * A bit that specifies whether the system color scheme will be used to determine the color. \r
+     * A value of 0x1 specifies that green and red will be treated as an unsigned 16-bit index\r
+     * into the system color table. Values less than 0x00F0 map directly to system colors.\r
+     */\r
+    private static final BitField FLAG_SYS_INDEX     = new BitField(0x10000000);\r
+\r
+    /**\r
+     * A bit that specifies whether the current application-defined color scheme will be used\r
+     * to determine the color. A value of 0x1 specifies that red will be treated as an index\r
+     * into the current color scheme table. If this value is 0x1, green and blue MUST be 0x00.\r
+     */\r
+    private static final BitField FLAG_SCHEME_INDEX  = new BitField(0x08000000);\r
+    \r
+    /**\r
+     * A bit that specifies whether the color is a standard RGB color.\r
+     * 0x0 : The RGB color MAY use halftone dithering to display.\r
+     * 0x1 : The color MUST be a solid color.\r
+     */\r
+    private static final BitField FLAG_SYSTEM_RGB    = new BitField(0x04000000);\r
+    \r
+    /**\r
+     * A bit that specifies whether the current palette will be used to determine the color.\r
+     * A value of 0x1 specifies that red, green, and blue contain an RGB value that will be\r
+     * matched in the current color palette. This color MUST be solid.\r
+     */\r
+    private static final BitField FLAG_PALETTE_RGB   = new BitField(0x02000000);\r
+\r
+    /**\r
+     * A bit that specifies whether the current palette will be used to determine the color.\r
+     * A value of 0x1 specifies that green and red will be treated as an unsigned 16-bit index into \r
+     * the current color palette. This color MAY be dithered. If this value is 0x1, blue MUST be 0x00.\r
+     */\r
+    private static final BitField FLAG_PALETTE_INDEX = new BitField(0x01000000);\r
+    \r
+    /**\r
+     * An unsigned integer that specifies the intensity of the blue color channel. A value\r
+     * of 0x00 has the minimum blue intensity. A value of 0xFF has the maximum blue intensity.\r
+     */\r
+    private static final BitField FLAG_BLUE          = new BitField(0x00FF0000);\r
+    \r
+    /**\r
+     * An unsigned integer that specifies the intensity of the green color channel. A value\r
+     * of 0x00 has the minimum green intensity. A value of 0xFF has the maximum green intensity.\r
+     */\r
+    private static final BitField FLAG_GREEN         = new BitField(0x0000FF00);\r
+    \r
+    /**\r
+     * An unsigned integer that specifies the intensity of the red color channel. A value\r
+     * of 0x00 has the minimum red intensity. A value of 0xFF has the maximum red intensity.\r
+     */\r
+    private static final BitField FLAG_RED           = new BitField(0x000000FF);\r
+    \r
+    public EscherColorRef(int colorRef) {\r
+        this.colorRef = colorRef;\r
+    }\r
+    \r
+    public EscherColorRef(byte[] source, int start, int len) {\r
+        assert(len == 4 || len == 6);\r
+        \r
+        int offset = start;\r
+        if (len == 6) {\r
+            opid = LittleEndian.getUShort(source, offset);\r
+            offset += 2;\r
+        }\r
+        colorRef = LittleEndian.getInt(source, offset);\r
+    }\r
+    \r
+    public boolean hasSysIndexFlag() {\r
+        return FLAG_SYS_INDEX.isSet(colorRef);\r
+    }\r
+    \r
+    public void setSysIndexFlag(boolean flag) {\r
+        FLAG_SYS_INDEX.setBoolean(colorRef, flag);\r
+    }\r
+    \r
+    public boolean hasSchemeIndexFlag() {\r
+        return FLAG_SCHEME_INDEX.isSet(colorRef);\r
+    }\r
+    \r
+    public void setSchemeIndexFlag(boolean flag) {\r
+        FLAG_SCHEME_INDEX.setBoolean(colorRef, flag);\r
+    }\r
+    \r
+    public boolean hasSystemRGBFlag() {\r
+        return FLAG_SYSTEM_RGB.isSet(colorRef);\r
+    }\r
+    \r
+    public void setSystemRGBFlag(boolean flag) {\r
+        FLAG_SYSTEM_RGB.setBoolean(colorRef, flag);\r
+    }\r
+    \r
+    public boolean hasPaletteRGBFlag() {\r
+        return FLAG_PALETTE_RGB.isSet(colorRef);\r
+    }\r
+    \r
+    public void setPaletteRGBFlag(boolean flag) {\r
+        FLAG_PALETTE_RGB.setBoolean(colorRef, flag);\r
+    }\r
+    \r
+    public boolean hasPaletteIndexFlag() {\r
+        return FLAG_PALETTE_INDEX.isSet(colorRef);\r
+    }\r
+    \r
+    public void setPaletteIndexFlag(boolean flag) {\r
+        FLAG_PALETTE_INDEX.setBoolean(colorRef, flag);\r
+    }\r
+\r
+    public int[] getRGB() {\r
+        int rgb[] = {\r
+            FLAG_RED.getValue(colorRef),\r
+            FLAG_GREEN.getValue(colorRef),\r
+            FLAG_BLUE.getValue(colorRef)\r
+        };\r
+        return rgb;\r
+    }\r
+    \r
+    /**\r
+     * @return {@link SysIndexSource} if {@link #hasSysIndexFlag()} is {@code true}, otherwise null\r
+     */\r
+    public SysIndexSource getSysIndexSource() {\r
+        if (!hasSysIndexFlag()) return null;\r
+        int val = FLAG_RED.getValue(colorRef);\r
+        for (SysIndexSource sis : SysIndexSource.values()) {\r
+            if (sis.value == val) return sis;\r
+        }\r
+        return null;\r
+    }\r
+    \r
+    /**\r
+     * Return the {@link SysIndexProcedure} - for invert flag use {@link #getSysIndexInvert()}\r
+     * @return {@link SysIndexProcedure} if {@link #hasSysIndexFlag()} is {@code true}, otherwise null\r
+     */\r
+    public SysIndexProcedure getSysIndexProcedure() {\r
+        if (!hasSysIndexFlag()) return null;\r
+        int val = FLAG_RED.getValue(colorRef);\r
+        for (SysIndexProcedure sip : SysIndexProcedure.values()) {\r
+            if (sip == SysIndexProcedure.INVERT_AFTER || sip == SysIndexProcedure.INVERT_HIGHBIT_AFTER) continue;\r
+            if (sip.mask.isSet(val)) return sip;\r
+        }\r
+        return null;\r
+    }\r
+    \r
+    /**\r
+     * @return 0 for no invert flag, 1 for {@link SysIndexProcedure#INVERT_AFTER} and\r
+     * 2 for {@link SysIndexProcedure#INVERT_HIGHBIT_AFTER} \r
+     */\r
+    public int getSysIndexInvert() {\r
+        if (!hasSysIndexFlag()) return 0;\r
+        int val = FLAG_GREEN.getValue(colorRef);\r
+        if ((SysIndexProcedure.INVERT_AFTER.mask.isSet(val))) return 1;\r
+        if ((SysIndexProcedure.INVERT_HIGHBIT_AFTER.mask.isSet(val))) return 2;\r
+        return 0;\r
+    }\r
+    \r
+    /**\r
+     * @return index of the scheme color or -1 if {@link #hasSchemeIndexFlag()} is {@code false}\r
+     * \r
+     * @see org.apache.poi.hslf.record.ColorSchemeAtom#getColor(int)\r
+     */\r
+    public int getSchemeIndex() {\r
+        if (!hasSchemeIndexFlag()) return -1;\r
+        return FLAG_RED.getValue(colorRef);\r
+    }\r
+    \r
+    /**\r
+     * @return index of current palette (color) or -1 if {@link #hasPaletteIndexFlag()} is {@code false}\r
+     */\r
+    public int getPaletteIndex() {\r
+        if (!hasPaletteIndexFlag()) return -1;\r
+        return (FLAG_GREEN.getValue(colorRef) << 8) & FLAG_RED.getValue(colorRef);\r
+    }\r
+}\r
index 91584b2ad55a46f7fe02e04feee95be00dfae689..d402156abd077fec8d2aba26ab30623a51e3a58a 100644 (file)
@@ -40,4 +40,19 @@ public class Units {
     public static double toPoints(long emu){\r
         return (double)emu/EMU_PER_POINT;\r
     }\r
+    \r
+    /**\r
+     * Converts a value of type FixedPoint to a decimal number\r
+     *\r
+     * @param fixedPoint\r
+     * @return decimal number\r
+     * \r
+     * @see <a href="http://msdn.microsoft.com/en-us/library/dd910765(v=office.12).aspx">[MS-OSHARED] - 2.2.1.6 FixedPoint</a>\r
+     */\r
+    public static double fixedPointToDecimal(int fixedPoint) {\r
+        int i = (fixedPoint >> 16);\r
+        int f = (fixedPoint >> 0) & 0xFFFF;\r
+        double decimal = (i + f/65536.0);\r
+        return decimal;\r
+    }\r
 }\r
index 13ec66bb6f39617855ddd984fa8ef8f094cc7174..525f673c3eeac8fa0f5b35d412ab291e08859880 100644 (file)
@@ -123,7 +123,7 @@ public final class ActiveXShape extends Picture {
 
     public int getControlIndex(){
         int idx = -1;
-        OEShapeAtom oe = (OEShapeAtom)getClientDataRecord(RecordTypes.OEShapeAtom.typeID);
+        OEShapeAtom oe = getClientDataRecord(RecordTypes.OEShapeAtom.typeID);
         if(oe != null) idx = oe.getOptions();
         return idx;
     }
index 036219a2588cb3012d06737fed34252b0bbbcd79..5302e267d0064636288a7c9acd592170b82f48a7 100644 (file)
 
 package org.apache.poi.hslf.model;
 
-import org.apache.poi.ddf.*;
-import org.apache.poi.hslf.record.*;
+import java.awt.Color;
+import java.util.List;
+
+import org.apache.poi.ddf.EscherBSERecord;
+import org.apache.poi.ddf.EscherContainerRecord;
+import org.apache.poi.ddf.EscherOptRecord;
+import org.apache.poi.ddf.EscherProperties;
+import org.apache.poi.ddf.EscherRecord;
+import org.apache.poi.ddf.EscherSimpleProperty;
+import org.apache.poi.hslf.record.Document;
 import org.apache.poi.hslf.usermodel.PictureData;
 import org.apache.poi.hslf.usermodel.SlideShow;
-import org.apache.poi.util.POILogger;
 import org.apache.poi.util.POILogFactory;
-import java.util.List;
-
-import java.awt.*;
+import org.apache.poi.util.POILogger;
 
 /**
  * Represents functionality provided by the 'Fill Effects' dialog in PowerPoint.
@@ -112,16 +117,16 @@ public final class Fill {
      * @return type of fill
      */
     public int getFillType(){
-        EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
-        EscherSimpleProperty prop = (EscherSimpleProperty)Shape.getEscherProperty(opt, EscherProperties.FILL__FILLTYPE);
+        EscherOptRecord opt = shape.getEscherOptRecord();
+        EscherSimpleProperty prop = Shape.getEscherProperty(opt, EscherProperties.FILL__FILLTYPE);
         return prop == null ? FILL_SOLID : prop.getPropertyValue();
     }
 
     /**
      */
     protected void afterInsert(Sheet sh){
-        EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
-        EscherSimpleProperty p = (EscherSimpleProperty)Shape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
+        EscherOptRecord opt = shape.getEscherOptRecord();
+        EscherSimpleProperty p = Shape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
         if(p != null) {
             int idx = p.getPropertyValue();
             EscherBSERecord bse = getEscherBSERecord(idx);
@@ -138,12 +143,12 @@ public final class Fill {
         SlideShow ppt = sheet.getSlideShow();
         Document doc = ppt.getDocumentRecord();
         EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer();
-        EscherContainerRecord bstore = (EscherContainerRecord)Shape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
+        EscherContainerRecord bstore = Shape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
         if(bstore == null) {
             logger.log(POILogger.DEBUG, "EscherContainerRecord.BSTORE_CONTAINER was not found ");
             return null;
         }
-        List lst = bstore.getChildRecords();
+        List<EscherRecord> lst = bstore.getChildRecords();
         return (EscherBSERecord)lst.get(idx-1);
     }
 
@@ -154,7 +159,7 @@ public final class Fill {
      * @param type type of the fill
      */
     public void setFillType(int type){
-        EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
+        EscherOptRecord opt = shape.getEscherOptRecord();
         Shape.setEscherProperty(opt, EscherProperties.FILL__FILLTYPE, type);
     }
 
@@ -162,8 +167,8 @@ public final class Fill {
      * Foreground color
      */
     public Color getForegroundColor(){
-        EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
-        EscherSimpleProperty p = (EscherSimpleProperty)Shape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST);
+        EscherOptRecord opt = shape.getEscherOptRecord();
+        EscherSimpleProperty p = Shape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST);
 
         if(p != null && (p.getPropertyValue() & 0x10) == 0) return null;
 
@@ -175,7 +180,7 @@ public final class Fill {
      * Foreground color
      */
     public void setForegroundColor(Color color){
-        EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
+        EscherOptRecord opt = shape.getEscherOptRecord();
         if (color == null) {
             Shape.setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150000);
         }
@@ -190,8 +195,8 @@ public final class Fill {
      * Background color
      */
     public Color getBackgroundColor(){
-        EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
-        EscherSimpleProperty p = (EscherSimpleProperty)Shape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST);
+        EscherOptRecord opt = shape.getEscherOptRecord();
+        EscherSimpleProperty p = Shape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST);
 
         if(p != null && (p.getPropertyValue() & 0x10) == 0) return null;
 
@@ -202,7 +207,7 @@ public final class Fill {
      * Background color
      */
     public void setBackgroundColor(Color color){
-        EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
+        EscherOptRecord opt = shape.getEscherOptRecord();
         if (color == null) {
             Shape.setEscherProperty(opt, EscherProperties.FILL__FILLBACKCOLOR, -1);
         }
@@ -216,8 +221,8 @@ public final class Fill {
      * <code>PictureData</code> object used in a texture, pattern of picture fill.
      */
     public PictureData getPictureData(){
-        EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
-        EscherSimpleProperty p = (EscherSimpleProperty)Shape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
+        EscherOptRecord opt = shape.getEscherOptRecord();
+        EscherSimpleProperty p = Shape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
         if (p == null) return null;
 
         SlideShow ppt = shape.getSheet().getSlideShow();
@@ -225,7 +230,7 @@ public final class Fill {
         Document doc = ppt.getDocumentRecord();
 
         EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer();
-        EscherContainerRecord bstore = (EscherContainerRecord)Shape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
+        EscherContainerRecord bstore = Shape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
 
         java.util.List<EscherRecord> lst = bstore.getChildRecords();
         int idx = p.getPropertyValue();
@@ -249,7 +254,7 @@ public final class Fill {
      * @param idx 0-based index of the picture added to this ppt by <code>SlideShow.addPicture</code> method.
      */
     public void setPictureData(int idx){
-        EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
+        EscherOptRecord opt = shape.getEscherOptRecord();
         Shape.setEscherProperty(opt, (short)(EscherProperties.FILL__PATTERNTEXTURE + 0x4000), idx);
         if( idx != 0 ) {
             if( shape.getSheet() != null ) {
index ca647f32d023d5b402a5607cb356c3be0080df1e..82f46b5e1cc92500c724b93077a046fd6283c073 100644 (file)
@@ -179,11 +179,11 @@ public final class Freeform extends AutoShape {
         EscherOptRecord opt = getEscherOptRecord();
         opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__SHAPEPATH, 0x4));
 
-        EscherArrayProperty verticesProp = (EscherArrayProperty)getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__VERTICES + 0x4000));
-        if(verticesProp == null) verticesProp = (EscherArrayProperty)getEscherProperty(opt, EscherProperties.GEOMETRY__VERTICES);
+        EscherArrayProperty verticesProp = getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__VERTICES + 0x4000));
+        if(verticesProp == null) verticesProp = getEscherProperty(opt, EscherProperties.GEOMETRY__VERTICES);
 
-        EscherArrayProperty segmentsProp = (EscherArrayProperty)getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__SEGMENTINFO + 0x4000));
-        if(segmentsProp == null) segmentsProp = (EscherArrayProperty)getEscherProperty(opt, EscherProperties.GEOMETRY__SEGMENTINFO);
+        EscherArrayProperty segmentsProp = getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__SEGMENTINFO + 0x4000));
+        if(segmentsProp == null) segmentsProp = getEscherProperty(opt, EscherProperties.GEOMETRY__SEGMENTINFO);
 
         //sanity check
         if(verticesProp == null) {
index 9d066ac9441b94628069019cb13f74ab6c465109..93e8a124fcf21301ca0a9aeaacfc9d044e88f76a 100644 (file)
@@ -116,10 +116,10 @@ public final class MovieShape extends Picture {
      * @param idx  the index of the movie
      */
     public void setMovieIndex(int idx){
-        OEShapeAtom oe = (OEShapeAtom)getClientDataRecord(RecordTypes.OEShapeAtom.typeID);
+        OEShapeAtom oe = getClientDataRecord(RecordTypes.OEShapeAtom.typeID);
         oe.setOptions(idx);
 
-        AnimationInfo an = (AnimationInfo)getClientDataRecord(RecordTypes.AnimationInfo.typeID);
+        AnimationInfo an = getClientDataRecord(RecordTypes.AnimationInfo.typeID);
         if(an != null) {
             AnimationInfoAtom ai = an.getAnimationInfoAtom();
             ai.setDimColor(0x07000000);
@@ -131,7 +131,7 @@ public final class MovieShape extends Picture {
     }
 
     public void setAutoPlay(boolean flag){
-        AnimationInfo an = (AnimationInfo)getClientDataRecord(RecordTypes.AnimationInfo.typeID);
+        AnimationInfo an = getClientDataRecord(RecordTypes.AnimationInfo.typeID);
         if(an != null){
             an.getAnimationInfoAtom().setFlag(AnimationInfoAtom.Automatic, flag);
             updateClientData();
@@ -139,7 +139,7 @@ public final class MovieShape extends Picture {
     }
 
     public boolean  isAutoPlay(){
-        AnimationInfo an = (AnimationInfo)getClientDataRecord(RecordTypes.AnimationInfo.typeID);
+        AnimationInfo an = getClientDataRecord(RecordTypes.AnimationInfo.typeID);
         if(an != null){
             return an.getAnimationInfoAtom().getFlag(AnimationInfoAtom.Automatic);
         }
@@ -150,7 +150,7 @@ public final class MovieShape extends Picture {
      * @return UNC or local path to a video file
      */
     public String getPath(){
-        OEShapeAtom oe = (OEShapeAtom)getClientDataRecord(RecordTypes.OEShapeAtom.typeID);
+        OEShapeAtom oe = getClientDataRecord(RecordTypes.OEShapeAtom.typeID);
         int idx = oe.getOptions();
 
         SlideShow ppt = getSheet().getSlideShow();
index ea6777deec2126e72be7b57f48abc9fbbdd0bfec..eda9d25056ee1764cd261a77e26f17764faa96ea 100644 (file)
@@ -41,6 +41,7 @@ import org.apache.poi.hslf.usermodel.PictureData;
 import org.apache.poi.hslf.usermodel.SlideShow;
 import org.apache.poi.util.POILogger;
 import org.apache.poi.util.StringUtil;
+import org.apache.poi.util.Units;
 
 
 /**
@@ -120,7 +121,7 @@ public class Picture extends SimpleShape {
      */
     public int getPictureIndex(){
         EscherOptRecord opt = getEscherOptRecord();
-        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.BLIP__BLIPTODISPLAY);
+        EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.BLIP__BLIPTODISPLAY);
         return prop == null ? 0 : prop.getPropertyValue();
     }
 
@@ -202,7 +203,7 @@ public class Picture extends SimpleShape {
         SlideShow ppt = getSheet().getSlideShow();
         Document doc = ppt.getDocumentRecord();
         EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer();
-        EscherContainerRecord bstore = (EscherContainerRecord)Shape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
+        EscherContainerRecord bstore = Shape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
         if(bstore == null) {
             logger.log(POILogger.DEBUG, "EscherContainerRecord.BSTORE_CONTAINER was not found ");
             return null;
@@ -223,7 +224,7 @@ public class Picture extends SimpleShape {
      */
     public String getPictureName(){
         EscherOptRecord opt = getEscherOptRecord();
-        EscherComplexProperty prop = (EscherComplexProperty)getEscherProperty(opt, EscherProperties.BLIP__BLIPFILENAME);
+        EscherComplexProperty prop = getEscherProperty(opt, EscherProperties.BLIP__BLIPFILENAME);
         if (prop == null) return null;
         String name = StringUtil.getFromUnicodeLE(prop.getComplexData());
         return name.trim();
@@ -289,16 +290,11 @@ public class Picture extends SimpleShape {
     
     /**
      * @return the fractional property or 0 if not defined
-     *
-     * @see <a href="http://msdn.microsoft.com/en-us/library/dd910765(v=office.12).aspx">2.2.1.6 FixedPoint</a>
      */
     private static double getFractProp(EscherOptRecord opt, short propertyId) {
-        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, propertyId);
+        EscherSimpleProperty prop = getEscherProperty(opt, propertyId);
         if (prop == null) return 0;
         int fixedPoint = prop.getPropertyValue();
-        int i = (fixedPoint >> 16);
-        int f = (fixedPoint >> 0) & 0xFFFF;
-        double fp = i + f/65536.0;
-        return fp;
+        return Units.fixedPointToDecimal(fixedPoint);
     }
 }
\ No newline at end of file
index 1ae07e2b8dd4402467b590c21e5ca5bd8acb1417..4a136611ca7c0c00dd895329537c9b06c152be0e 100644 (file)
@@ -21,6 +21,7 @@ import org.apache.poi.ddf.*;
 import org.apache.poi.hslf.record.ColorSchemeAtom;
 import org.apache.poi.util.POILogger;
 import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.Units;
 
 import java.util.*;
 import java.awt.*;
@@ -129,7 +130,7 @@ public abstract class Shape {
      * @see org.apache.poi.hslf.record.RecordTypes
      */
     public int getShapeType(){
-        EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
+        EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
         return spRecord.getShapeType();
     }
 
@@ -138,7 +139,7 @@ public abstract class Shape {
      * @see org.apache.poi.hslf.record.RecordTypes
      */
     public void setShapeType(int type){
-        EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
+        EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
         spRecord.setShapeType( (short) type );
         spRecord.setVersion( (short) 0x2 );
     }
@@ -161,15 +162,15 @@ public abstract class Shape {
      * @return the anchor of this shape
      */
     public Rectangle2D getAnchor2D(){
-        EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
+        EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
         int flags = spRecord.getFlags();
         Rectangle2D anchor=null;
         if ((flags & EscherSpRecord.FLAG_CHILD) != 0){
-            EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(_escherContainer, EscherChildAnchorRecord.RECORD_ID);
+            EscherChildAnchorRecord rec = getEscherChild(EscherChildAnchorRecord.RECORD_ID);
             anchor = new java.awt.Rectangle();
             if(rec == null){
                 logger.log(POILogger.WARN, "EscherSpRecord.FLAG_CHILD is set but EscherChildAnchorRecord was not found");
-                EscherClientAnchorRecord clrec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID);
+                EscherClientAnchorRecord clrec = getEscherChild(EscherClientAnchorRecord.RECORD_ID);
                 anchor = new java.awt.Rectangle();
                 anchor = new Rectangle2D.Float(
                     (float)clrec.getCol1()*POINT_DPI/MASTER_DPI,
@@ -187,7 +188,7 @@ public abstract class Shape {
             }
         }
         else {
-            EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID);
+            EscherClientAnchorRecord rec = getEscherChild(EscherClientAnchorRecord.RECORD_ID);
             anchor = new java.awt.Rectangle();
             anchor = new Rectangle2D.Float(
                 (float)rec.getCol1()*POINT_DPI/MASTER_DPI,
@@ -210,17 +211,17 @@ public abstract class Shape {
      * @param anchor new anchor
      */
     public void setAnchor(Rectangle2D anchor){
-        EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
+        EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
         int flags = spRecord.getFlags();
         if ((flags & EscherSpRecord.FLAG_CHILD) != 0){
-            EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(_escherContainer, EscherChildAnchorRecord.RECORD_ID);
+            EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(EscherChildAnchorRecord.RECORD_ID);
             rec.setDx1((int)(anchor.getX()*MASTER_DPI/POINT_DPI));
             rec.setDy1((int)(anchor.getY()*MASTER_DPI/POINT_DPI));
             rec.setDx2((int)((anchor.getWidth() + anchor.getX())*MASTER_DPI/POINT_DPI));
             rec.setDy2((int)((anchor.getHeight() + anchor.getY())*MASTER_DPI/POINT_DPI));
         }
         else {
-            EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID);
+            EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(EscherClientAnchorRecord.RECORD_ID);
             rec.setFlag((short)(anchor.getY()*MASTER_DPI/POINT_DPI));
             rec.setCol1((short)(anchor.getX()*MASTER_DPI/POINT_DPI));
             rec.setDx1((short)(((anchor.getWidth() + anchor.getX())*MASTER_DPI/POINT_DPI)));
@@ -246,29 +247,21 @@ public abstract class Shape {
      *
      * @return escher record or <code>null</code> if not found.
      */
-    public static EscherRecord getEscherChild(EscherContainerRecord owner, int recordId){
-        for ( Iterator<EscherRecord> iterator = owner.getChildIterator(); iterator.hasNext(); )
-        {
-            EscherRecord escherRecord = iterator.next();
-            if (escherRecord.getRecordId() == recordId)
-                return escherRecord;
-        }
-        return null;
+    public static <T extends EscherRecord> T getEscherChild(EscherContainerRecord owner, int recordId){
+        return owner.getChildById((short)recordId);
     }
 
+    public <T extends EscherRecord> T getEscherChild(int recordId){
+        return _escherContainer.getChildById((short)recordId);
+    }
+    
     /**
      * Returns  escher property by id.
      *
      * @return escher property or <code>null</code> if not found.
      */
-     public static EscherProperty getEscherProperty(EscherOptRecord opt, int propId){
-        if(opt != null) for ( Iterator iterator = opt.getEscherProperties().iterator(); iterator.hasNext(); )
-        {
-            EscherProperty prop = (EscherProperty) iterator.next();
-            if (prop.getPropertyNumber() == propId)
-                return prop;
-        }
-        return null;
+     public static <T extends EscherProperty> T getEscherProperty(EscherOptRecord opt, int propId){
+        return opt.lookup(propId);
     }
 
     /**
@@ -279,11 +272,11 @@ public abstract class Shape {
      * @param value     value of the property. If value = -1 then the property is removed.
      */
      public static void setEscherProperty(EscherOptRecord opt, short propId, int value){
-        java.util.List props = opt.getEscherProperties();
-        for ( Iterator iterator = props.iterator(); iterator.hasNext(); ) {
-            EscherProperty prop = (EscherProperty) iterator.next();
-            if (prop.getId() == propId){
+        java.util.List<EscherProperty> props = opt.getEscherProperties();
+        for ( Iterator<EscherProperty> iterator = props.iterator(); iterator.hasNext(); ) {
+            if (iterator.next().getPropertyNumber() == propId){
                 iterator.remove();
+                break;
             }
         }
         if (value != -1) {
@@ -310,7 +303,7 @@ public abstract class Shape {
      */
    public int getEscherProperty(short propId){
         EscherOptRecord opt = getEscherOptRecord();
-        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, propId);
+        EscherSimpleProperty prop = getEscherProperty(opt, propId);
         return prop == null ? 0 : prop.getPropertyValue();
     }
 
@@ -321,7 +314,7 @@ public abstract class Shape {
      */
    public int getEscherProperty(short propId, int defaultValue){
         EscherOptRecord opt = getEscherOptRecord();
-        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, propId);
+        EscherSimpleProperty prop = getEscherProperty(opt, propId);
         return prop == null ? defaultValue : prop.getPropertyValue();
     }
 
@@ -365,32 +358,30 @@ public abstract class Shape {
 
     Color getColor(short colorProperty, short opacityProperty, int defaultColor){
         EscherOptRecord opt = getEscherOptRecord();
-        EscherSimpleProperty p = (EscherSimpleProperty)getEscherProperty(opt, colorProperty);
+        EscherSimpleProperty p = getEscherProperty(opt, colorProperty);
         if(p == null && defaultColor == -1) return null;
 
-        int val = p == null ? defaultColor : p.getPropertyValue();
-
-        int a = (val >> 24) & 0xFF;
-        int b = (val >> 16) & 0xFF;
-        int g = (val >> 8) & 0xFF;
-        int r = (val >> 0) & 0xFF;
+        int val = (p == null) ? defaultColor : p.getPropertyValue();
 
-        boolean fPaletteIndex = (a & 1) != 0;
-        boolean fPaletteRGB = (a & (1 << 1)) != 0;
-        boolean fSystemRGB = (a & (1 << 2)) != 0;
-        boolean fSchemeIndex = (a & (1 << 3)) != 0;
-        boolean fSysIndex = (a & (1 << 4)) != 0;
+        EscherColorRef ecr = new EscherColorRef(val);
+        
+        boolean fPaletteIndex = ecr.hasPaletteIndexFlag();
+        boolean fPaletteRGB = ecr.hasPaletteRGBFlag();
+        boolean fSystemRGB = ecr.hasSystemRGBFlag();
+        boolean fSchemeIndex = ecr.hasSchemeIndexFlag();
+        boolean fSysIndex = ecr.hasSysIndexFlag();
+        
+        int rgb[] = ecr.getRGB();
 
         Sheet sheet = getSheet();
-        if (fSchemeIndex && sheet != null)
-        {
+        if (fSchemeIndex && sheet != null) {
             //red is the index to the color scheme
             ColorSchemeAtom ca = sheet.getColorScheme();
-            int schemeColor = ca.getColor(r);
+            int schemeColor = ca.getColor(ecr.getSchemeIndex());
 
-            r = (schemeColor >> 0) & 0xFF;
-            g = (schemeColor >> 8) & 0xFF;
-            b = (schemeColor >> 16) & 0xFF;
+            rgb[0] = (schemeColor >> 0) & 0xFF;
+            rgb[1] = (schemeColor >> 8) & 0xFF;
+            rgb[2] = (schemeColor >> 16) & 0xFF;
         } else if (fPaletteIndex){
             //TODO
         } else if (fPaletteRGB){
@@ -401,13 +392,11 @@ public abstract class Shape {
             //TODO
         }
 
-        EscherSimpleProperty op = (EscherSimpleProperty)getEscherProperty(opt, opacityProperty);
+        EscherSimpleProperty op = getEscherProperty(opt, opacityProperty);
         int defaultOpacity = 0x00010000;
-        int opacity = op == null ? defaultOpacity : op.getPropertyValue();
-        int i = (opacity >> 16);
-        int f = (opacity >> 0) & 0xFFFF ;
-        double alpha = (i + f/65536.0)*255;
-        return new Color(r, g, b, (int)alpha);
+        int opacity = (op == null) ? defaultOpacity : op.getPropertyValue();
+        double alpha = Units.fixedPointToDecimal(opacity)*255.0;
+        return new Color(rgb[0], rgb[1], rgb[2], (int)alpha);
     }
 
     Color toRGB(int val){
@@ -436,7 +425,7 @@ public abstract class Shape {
      * @return id for the shape.
      */
     public int getShapeId(){
-        EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
+        EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
         return spRecord == null ? 0 : spRecord.getShapeId();
     }
 
@@ -446,7 +435,7 @@ public abstract class Shape {
      * @param id of the shape
      */
     public void setShapeId(int id){
-        EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
+        EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
         if(spRecord != null) spRecord.setShapeId(id);
     }
 
@@ -484,7 +473,48 @@ public abstract class Shape {
         return getLogicalAnchor2D();
     }
     
-    protected EscherOptRecord getEscherOptRecord() {
-        return (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
+    public EscherOptRecord getEscherOptRecord() {
+        return getEscherChild(EscherOptRecord.RECORD_ID);
+    }
+    
+    /**
+     * Whether the shape is horizontally flipped
+     *
+     * @return whether the shape is horizontally flipped
+     */
+     public boolean getFlipHorizontal(){
+        EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
+        return (spRecord.getFlags()& EscherSpRecord.FLAG_FLIPHORIZ) != 0;
+    }
+
+    /**
+     * Whether the shape is vertically flipped
+     *
+     * @return whether the shape is vertically flipped
+     */
+    public boolean getFlipVertical(){
+        EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
+        return (spRecord.getFlags()& EscherSpRecord.FLAG_FLIPVERT) != 0;
+    }
+
+    /**
+     * Rotation angle in degrees
+     *
+     * @return rotation angle in degrees
+     */
+    public int getRotation(){
+        int rot = getEscherProperty(EscherProperties.TRANSFORM__ROTATION);
+        int angle = (rot >> 16) % 360;
+
+        return angle;
+    }
+
+    /**
+     * Rotate this shape
+     *
+     * @param theta the rotation angle in degrees
+     */
+    public void setRotation(int theta){
+        setEscherProperty(EscherProperties.TRANSFORM__ROTATION, (theta << 16));
     }
 }
index 215835d5be8d267fbd1b2b7ceead3e436feb72aa..c3843c29117d6794c87d50f1d1eaef624215fe86 100644 (file)
@@ -62,7 +62,7 @@ public final class ShapeFactory {
         if(opt != null){
             try {
                 EscherPropertyFactory f = new EscherPropertyFactory();
-                List props = f.createProperties( opt.serialize(), 8, opt.getInstance() );
+                List<EscherProperty> props = f.createProperties( opt.serialize(), 8, opt.getInstance() );
                 EscherSimpleProperty p = (EscherSimpleProperty)props.get(0);
                 if(p.getPropertyNumber() == 0x39F && p.getPropertyValue() == 1){
                     group = new Table(spContainer, parent);
@@ -91,8 +91,8 @@ public final class ShapeFactory {
                 break;
             case ShapeTypes.HostControl:
             case ShapeTypes.PictureFrame: {
-                InteractiveInfo info = (InteractiveInfo)getClientDataRecord(spContainer, RecordTypes.InteractiveInfo.typeID);
-                OEShapeAtom oes = (OEShapeAtom)getClientDataRecord(spContainer, RecordTypes.OEShapeAtom.typeID);
+                InteractiveInfo info = getClientDataRecord(spContainer, RecordTypes.InteractiveInfo.typeID);
+                OEShapeAtom oes = getClientDataRecord(spContainer, RecordTypes.OEShapeAtom.typeID);
                 if(info != null && info.getInteractiveInfoAtom() != null){
                     switch(info.getInteractiveInfoAtom().getAction()){
                         case InteractiveInfoAtom.ACTION_OLE:
@@ -115,7 +115,7 @@ public final class ShapeFactory {
                 shape = new Line(spContainer, parent);
                 break;
             case ShapeTypes.NotPrimitive: {
-                EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(spContainer, EscherOptRecord.RECORD_ID);
+                EscherOptRecord opt = Shape.getEscherChild(spContainer, EscherOptRecord.RECORD_ID);
                 EscherProperty prop = Shape.getEscherProperty(opt, EscherProperties.GEOMETRY__VERTICES);
                 if(prop != null)
                     shape = new Freeform(spContainer, parent);
@@ -134,7 +134,8 @@ public final class ShapeFactory {
 
     }
 
-    protected static Record getClientDataRecord(EscherContainerRecord spContainer, int recordType) {
+    @SuppressWarnings("unchecked")
+    protected static <T extends Record> T getClientDataRecord(EscherContainerRecord spContainer, int recordType) {
         Record oep = null;
         for (Iterator<EscherRecord> it = spContainer.getChildIterator(); it.hasNext();) {
             EscherRecord obj = it.next();
@@ -143,12 +144,12 @@ public final class ShapeFactory {
                 Record[] records = Record.findChildRecords(data, 8, data.length - 8);
                 for (int j = 0; j < records.length; j++) {
                     if (records[j].getRecordType() == recordType) {
-                        return records[j];
+                        return (T)records[j];
                     }
                 }
             }
         }
-        return oep;
+        return (T)oep;
     }
 
 }
index fe9b4216872566883ae03d05ee00af4480741403..796b248ac5c36efc7bf2a93e25deb03b245d73a2 100644 (file)
@@ -100,9 +100,7 @@ public class ShapeGroup extends Shape{
      */
     public void setAnchor(java.awt.Rectangle anchor){
 
-        EscherContainerRecord spContainer = (EscherContainerRecord)_escherContainer.getChild(0);
-
-        EscherClientAnchorRecord clientAnchor = (EscherClientAnchorRecord)getEscherChild(spContainer, EscherClientAnchorRecord.RECORD_ID);
+        EscherClientAnchorRecord clientAnchor = getEscherChild(EscherClientAnchorRecord.RECORD_ID);
         //hack. internal variable EscherClientAnchorRecord.shortRecord can be
         //initialized only in fillFields(). We need to set shortRecord=false;
         byte[] header = new byte[16];
@@ -116,7 +114,7 @@ public class ShapeGroup extends Shape{
         clientAnchor.setDx1((short)((anchor.width + anchor.x)*MASTER_DPI/POINT_DPI));
         clientAnchor.setRow1((short)((anchor.height + anchor.y)*MASTER_DPI/POINT_DPI));
 
-        EscherSpgrRecord spgr = (EscherSpgrRecord)getEscherChild(spContainer, EscherSpgrRecord.RECORD_ID);
+        EscherSpgrRecord spgr = getEscherChild(EscherSpgrRecord.RECORD_ID);
 
         spgr.setRectX1(anchor.x*MASTER_DPI/POINT_DPI);
         spgr.setRectY1(anchor.y*MASTER_DPI/POINT_DPI);
@@ -131,8 +129,7 @@ public class ShapeGroup extends Shape{
      * @param anchor the coordinate space of this group
      */
     public void setCoordinates(Rectangle2D anchor){
-        EscherContainerRecord spContainer = (EscherContainerRecord)_escherContainer.getChild(0);
-        EscherSpgrRecord spgr = (EscherSpgrRecord)getEscherChild(spContainer, EscherSpgrRecord.RECORD_ID);
+        EscherSpgrRecord spgr = getEscherChild(EscherSpgrRecord.RECORD_ID);
 
         int x1 = (int)Math.round(anchor.getX()*MASTER_DPI/POINT_DPI);
         int y1 = (int)Math.round(anchor.getY()*MASTER_DPI/POINT_DPI);
@@ -153,8 +150,7 @@ public class ShapeGroup extends Shape{
      * @return the coordinate space of this group
      */
     public Rectangle2D getCoordinates(){
-        EscherContainerRecord spContainer = (EscherContainerRecord)_escherContainer.getChild(0);
-        EscherSpgrRecord spgr = (EscherSpgrRecord)getEscherChild(spContainer, EscherSpgrRecord.RECORD_ID);
+        EscherSpgrRecord spgr = getEscherChild(EscherSpgrRecord.RECORD_ID);
 
         Rectangle2D.Float anchor = new Rectangle2D.Float();
         anchor.x = (float)spgr.getRectX1()*POINT_DPI/MASTER_DPI;
@@ -237,12 +233,11 @@ public class ShapeGroup extends Shape{
      * @return the anchor of this shape group
      */
     public Rectangle2D getAnchor2D(){
-        EscherContainerRecord spContainer = (EscherContainerRecord)_escherContainer.getChild(0);
-        EscherClientAnchorRecord clientAnchor = (EscherClientAnchorRecord)getEscherChild(spContainer, EscherClientAnchorRecord.RECORD_ID);
+        EscherClientAnchorRecord clientAnchor = getEscherChild(EscherClientAnchorRecord.RECORD_ID);
         Rectangle2D.Float anchor = new Rectangle2D.Float();
         if(clientAnchor == null){
             logger.log(POILogger.INFO, "EscherClientAnchorRecord was not found for shape group. Searching for EscherChildAnchorRecord.");
-            EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(spContainer, EscherChildAnchorRecord.RECORD_ID);
+            EscherChildAnchorRecord rec = getEscherChild(EscherChildAnchorRecord.RECORD_ID);
             anchor = new Rectangle2D.Float(
                 (float)rec.getDx1()*POINT_DPI/MASTER_DPI,
                 (float)rec.getDy1()*POINT_DPI/MASTER_DPI,
@@ -266,8 +261,7 @@ public class ShapeGroup extends Shape{
      * @return type of the shape.
      */
     public int getShapeType(){
-        EscherContainerRecord groupInfoContainer = (EscherContainerRecord)_escherContainer.getChild(0);
-        EscherSpRecord spRecord = groupInfoContainer.getChildById(EscherSpRecord.RECORD_ID);
+        EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID);
         return spRecord.getOptions() >> 4;
     }
 
@@ -291,4 +285,10 @@ public class ShapeGroup extends Shape{
 
         graphics.setTransform(at);
     }
+
+    @Override
+    public <T extends EscherRecord> T getEscherChild(int recordId){
+        EscherContainerRecord groupInfoContainer = (EscherContainerRecord)_escherContainer.getChild(0);
+        return groupInfoContainer.getChildById((short)recordId);
+    }
 }
index e912edf528d7d3462793a8d6cb3c1cd3e13ce19c..c5256b1d2a7cc61f57a25b3fdd54e64864eb66dd 100644 (file)
@@ -484,7 +484,7 @@ public abstract class Sheet {
                     placeholderId = oep.getPlaceholderId();
                 } else {
                     //special case for files saved in Office 2007
-                    RoundTripHFPlaceholder12 hldr = (RoundTripHFPlaceholder12)tx.getClientDataRecord(RecordTypes.RoundTripHFPlaceholder12.typeID);
+                    RoundTripHFPlaceholder12 hldr = tx.getClientDataRecord(RecordTypes.RoundTripHFPlaceholder12.typeID);
                     if(hldr != null) placeholderId = hldr.getPlaceholderId();
                 }
                 if(placeholderId == type){
index 4a8bdf692e66b9f4492fbc5e03e779d3a9798069..34db620951942ff04ecdf17ad29ddb0f0f0030c0 100644 (file)
@@ -23,9 +23,16 @@ import java.awt.geom.AffineTransform;
 import java.awt.geom.Rectangle2D;
 import java.io.ByteArrayOutputStream;
 import java.util.ArrayList;
-import java.util.List;
 
-import org.apache.poi.ddf.*;
+import org.apache.poi.ddf.DefaultEscherRecordFactory;
+import org.apache.poi.ddf.EscherChildAnchorRecord;
+import org.apache.poi.ddf.EscherClientAnchorRecord;
+import org.apache.poi.ddf.EscherClientDataRecord;
+import org.apache.poi.ddf.EscherContainerRecord;
+import org.apache.poi.ddf.EscherOptRecord;
+import org.apache.poi.ddf.EscherProperties;
+import org.apache.poi.ddf.EscherRecord;
+import org.apache.poi.ddf.EscherSimpleProperty;
 import org.apache.poi.ddf.EscherSpRecord;
 import org.apache.poi.hslf.exceptions.HSLFException;
 import org.apache.poi.hslf.record.InteractiveInfo;
@@ -103,7 +110,7 @@ public abstract class SimpleShape extends Shape {
      */
     public double getLineWidth(){
         EscherOptRecord opt = getEscherOptRecord();
-        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.LINESTYLE__LINEWIDTH);
+        EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINEWIDTH);
         double width = prop == null ? DEFAULT_LINE_WIDTH : (double)prop.getPropertyValue()/EMU_PER_POINT;
         return width;
     }
@@ -139,7 +146,7 @@ public abstract class SimpleShape extends Shape {
     public Color getLineColor(){
         EscherOptRecord opt = getEscherOptRecord();
 
-        EscherSimpleProperty p = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH);
+        EscherSimpleProperty p = getEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH);
         if(p != null && (p.getPropertyValue() & 0x8) == 0) return null;
 
         Color clr = getColor(EscherProperties.LINESTYLE__COLOR, EscherProperties.LINESTYLE__OPACITY, -1);
@@ -154,7 +161,7 @@ public abstract class SimpleShape extends Shape {
     public int getLineDashing(){
         EscherOptRecord opt = getEscherOptRecord();
 
-        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.LINESTYLE__LINEDASHING);
+        EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINEDASHING);
         return prop == null ? Line.PEN_SOLID : prop.getPropertyValue();
     }
 
@@ -186,7 +193,7 @@ public abstract class SimpleShape extends Shape {
      */
     public int getLineStyle(){
         EscherOptRecord opt = getEscherOptRecord();
-        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.LINESTYLE__LINESTYLE);
+        EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINESTYLE);
         return prop == null ? Line.LINE_SIMPLE : prop.getPropertyValue();
     }
 
@@ -206,47 +213,6 @@ public abstract class SimpleShape extends Shape {
         getFill().setForegroundColor(color);
     }
 
-    /**
-     * Whether the shape is horizontally flipped
-     *
-     * @return whether the shape is horizontally flipped
-     */
-     public boolean getFlipHorizontal(){
-        EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
-        return (spRecord.getFlags()& EscherSpRecord.FLAG_FLIPHORIZ) != 0;
-    }
-
-    /**
-     * Whether the shape is vertically flipped
-     *
-     * @return whether the shape is vertically flipped
-     */
-    public boolean getFlipVertical(){
-        EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
-        return (spRecord.getFlags()& EscherSpRecord.FLAG_FLIPVERT) != 0;
-    }
-
-    /**
-     * Rotation angle in degrees
-     *
-     * @return rotation angle in degrees
-     */
-    public int getRotation(){
-        int rot = getEscherProperty(EscherProperties.TRANSFORM__ROTATION);
-        int angle = (rot >> 16) % 360;
-
-        return angle;
-    }
-
-    /**
-     * Rotate this shape
-     *
-     * @param theta the rotation angle in degrees
-     */
-    public void setRotation(int theta){
-        setEscherProperty(EscherProperties.TRANSFORM__ROTATION, (theta << 16));
-    }
-
     /**
      *
      * @return 'absolute' anchor of this shape relative to the parent sheet
@@ -256,17 +222,13 @@ public abstract class SimpleShape extends Shape {
 
         //if it is a groupped shape see if we need to transform the coordinates
         if (_parent != null){
-            List<Shape> lst = new ArrayList<Shape>();
-            lst.add(_parent);
-            Shape top = _parent;
-            while(top.getParent() != null) {
-                top = top.getParent();
-                lst.add(top);
+            ArrayList<ShapeGroup> lst = new ArrayList<ShapeGroup>();
+            for (Shape top=this; (top = top.getParent()) != null; ) {
+                lst.add(0, (ShapeGroup)top);
             }
 
             AffineTransform tx = new AffineTransform();
-            for(int i = lst.size() - 1; i >= 0; i--) {
-                ShapeGroup prnt = (ShapeGroup)lst.get(i);
+            for(ShapeGroup prnt : lst) {
                 Rectangle2D exterior = prnt.getAnchor2D();
                 Rectangle2D interior = prnt.getCoordinates();
 
@@ -276,6 +238,7 @@ public abstract class SimpleShape extends Shape {
                 tx.translate(exterior.getX(), exterior.getY());
                 tx.scale(scaleX, scaleY);
                 tx.translate(-interior.getX(), -interior.getY());
+                
             }
             anchor = tx.createTransformedShape(anchor).getBounds2D();
         }
@@ -314,12 +277,13 @@ public abstract class SimpleShape extends Shape {
      *
      * @param recordType type of the record to search
      */
-    protected Record getClientDataRecord(int recordType) {
+    @SuppressWarnings("unchecked")
+    protected <T extends Record> T getClientDataRecord(int recordType) {
 
         Record[] records = getClientRecords();
         if(records != null) for (int i = 0; i < records.length; i++) {
             if(records[i].getRecordType() == recordType){
-                return records[i];
+                return (T)records[i];
             }
         }
         return null;
@@ -332,7 +296,7 @@ public abstract class SimpleShape extends Shape {
      */
     protected Record[] getClientRecords() {
         if(_clientData == null){
-            EscherRecord r = Shape.getEscherChild(getSpContainer(), EscherClientDataRecord.RECORD_ID);
+            EscherRecord r = getEscherChild(EscherClientDataRecord.RECORD_ID);
             //ddf can return EscherContainerRecord with recordId=EscherClientDataRecord.RECORD_ID
             //convert in to EscherClientDataRecord on the fly
             if(r != null && !(r instanceof EscherClientDataRecord)){
index 79ef820ac8455f29efc9fbc5348e0c055c0872c9..9e040c1677f49811109bb27e8af49ae77eff1af5 100644 (file)
@@ -88,7 +88,7 @@ public final class Slide extends Sheet
                // Grab text from SlideListWithTexts entries
                int i=0;
                for(i=0; i<textRuns.size(); i++) {
-                       _runs[i] = (TextRun)textRuns.get(i);
+                       _runs[i] = textRuns.get(i);
             _runs[i].setSheet(this);
                }
                // Grab text from slide's PPDrawing
index 77af6eab9b82f3f21a121bf74ae0dc9b825cff2d..b585d61e1bc408c460d9ecd1539af64ae418b785 100644 (file)
@@ -225,7 +225,7 @@ public abstract class TextShape extends SimpleShape {
 
     protected EscherTextboxWrapper getEscherTextboxWrapper(){
         if(_txtbox == null){
-            EscherTextboxRecord textRecord = (EscherTextboxRecord)Shape.getEscherChild(_escherContainer, EscherTextboxRecord.RECORD_ID);
+            EscherTextboxRecord textRecord = getEscherChild(EscherTextboxRecord.RECORD_ID);
             if(textRecord != null) _txtbox = new EscherTextboxWrapper(textRecord);
         }
         return _txtbox;
@@ -281,7 +281,7 @@ public abstract class TextShape extends SimpleShape {
      */
     public int getVerticalAlignment(){
         EscherOptRecord opt = getEscherOptRecord();
-        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT);
+        EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT);
         int valign = TextShape.AnchorTop;
         if (prop == null){
             /**
@@ -352,7 +352,7 @@ public abstract class TextShape extends SimpleShape {
      */
     public float getMarginBottom(){
         EscherOptRecord opt = getEscherOptRecord();
-        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM);
+        EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM);
         int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue();
         return (float)val/EMU_PER_POINT;
     }
@@ -377,7 +377,7 @@ public abstract class TextShape extends SimpleShape {
      */
     public float getMarginLeft(){
         EscherOptRecord opt = getEscherOptRecord();
-        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTLEFT);
+        EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__TEXTLEFT);
         int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue();
         return (float)val/EMU_PER_POINT;
     }
@@ -402,7 +402,7 @@ public abstract class TextShape extends SimpleShape {
      */
     public float getMarginRight(){
         EscherOptRecord opt = getEscherOptRecord();
-        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTRIGHT);
+        EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__TEXTRIGHT);
         int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue();
         return (float)val/EMU_PER_POINT;
     }
@@ -426,7 +426,7 @@ public abstract class TextShape extends SimpleShape {
      */
     public float getMarginTop(){
         EscherOptRecord opt = getEscherOptRecord();
-        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTTOP);
+        EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__TEXTTOP);
         int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue();
         return (float)val/EMU_PER_POINT;
     }
@@ -450,7 +450,7 @@ public abstract class TextShape extends SimpleShape {
      */
     public int getWordWrap(){
         EscherOptRecord opt = getEscherOptRecord();
-        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__WRAPTEXT);
+        EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__WRAPTEXT);
         return prop == null ? WrapSquare : prop.getPropertyValue();
     }
 
@@ -469,7 +469,7 @@ public abstract class TextShape extends SimpleShape {
      */
     public int getTextId(){
         EscherOptRecord opt = getEscherOptRecord();
-        EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__TEXTID);
+        EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__TEXTID);
         return prop == null ? 0 : prop.getPropertyValue();
     }
 
@@ -561,7 +561,7 @@ public abstract class TextShape extends SimpleShape {
                 logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx);
             }
         } else {
-            EscherSpRecord escherSpRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
+            EscherSpRecord escherSpRecord = getEscherChild(EscherSpRecord.RECORD_ID);
             int shapeId = escherSpRecord.getShapeId();
             if(runs != null) for (int i = 0; i < runs.length; i++) {
                 if(runs[i].getShapeId() == shapeId){
@@ -593,7 +593,7 @@ public abstract class TextShape extends SimpleShape {
      * @return <code>OEPlaceholderAtom</code> or <code>null</code> if not found
      */
     public OEPlaceholderAtom getPlaceholderAtom(){
-        return (OEPlaceholderAtom)getClientDataRecord(RecordTypes.OEPlaceholderAtom.typeID);
+        return getClientDataRecord(RecordTypes.OEPlaceholderAtom.typeID);
     }
 
     /**
index 55082abe9905f42b11896801c28e68a14ec12d65..41c5c58a3fc2c17630a3d8be85d55ad52e27b2c4 100644 (file)
 
 package org.apache.poi.hslf.model;
 
-import junit.framework.TestCase;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
-import java.io.*;
-import java.awt.*;
+import java.awt.Color;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.util.List;
 
-import org.apache.poi.ddf.*;
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.ddf.EscherBSERecord;
+import org.apache.poi.ddf.EscherContainerRecord;
+import org.apache.poi.ddf.EscherOptRecord;
+import org.apache.poi.ddf.EscherProperties;
+import org.apache.poi.ddf.EscherRecord;
+import org.apache.poi.ddf.EscherSimpleProperty;
+import org.apache.poi.hslf.HSLFSlideShow;
 import org.apache.poi.hslf.record.Document;
 import org.apache.poi.hslf.usermodel.SlideShow;
-import org.apache.poi.hslf.HSLFSlideShow;
-import org.apache.poi.POIDataSamples;
+import org.junit.Test;
 
 
 /**
@@ -35,13 +43,14 @@ import org.apache.poi.POIDataSamples;
  *
  * @author Yegor Kozlov
  */
-public final class TestBackground extends TestCase {
+public final class TestBackground {
     private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
 
     /**
      * Default background for slide, shape and slide master.
      */
-    public void testDefaults() {
+    @Test
+    public void defaults() {
         SlideShow ppt = new SlideShow();
 
         assertEquals(Fill.FILL_SOLID, ppt.getSlidesMasters()[0].getBackground().getFill().getFillType());
@@ -57,7 +66,8 @@ public final class TestBackground extends TestCase {
     /**
      * Read fill information from an reference ppt file
      */
-    public void testReadBackground() throws Exception {
+    @Test
+    public void readBackground() throws Exception {
         SlideShow ppt = new SlideShow(_slTests.openResourceAsStream("backgrounds.ppt"));
         Fill fill;
         Shape shape;
@@ -88,7 +98,8 @@ public final class TestBackground extends TestCase {
     /**
      * Create a ppt with various fill effects
      */
-    public void testBackgroundPicture() throws Exception {
+    @Test
+    public void backgroundPicture() throws Exception {
         SlideShow ppt = new SlideShow();
         Slide slide;
         Fill fill;
@@ -191,8 +202,8 @@ public final class TestBackground extends TestCase {
     }
 
     private int getFillPictureRefCount(Shape shape, Fill fill) {
-        EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID);
-        EscherSimpleProperty p = (EscherSimpleProperty)Shape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
+        EscherOptRecord opt = shape.getEscherOptRecord();
+        EscherSimpleProperty p = Shape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE);
         if(p != null) {
             int idx = p.getPropertyValue();
 
@@ -200,8 +211,8 @@ public final class TestBackground extends TestCase {
             SlideShow ppt = sheet.getSlideShow();
             Document doc = ppt.getDocumentRecord();
             EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer();
-            EscherContainerRecord bstore = (EscherContainerRecord)Shape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
-            List lst = bstore.getChildRecords();
+            EscherContainerRecord bstore = Shape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
+            List<EscherRecord> lst = bstore.getChildRecords();
             return ((EscherBSERecord)lst.get(idx-1)).getRef();
         }
         return 0;
index 6018cf5f52692533c4e70cbaf4c2324e9da4d467..b3e4f6ac9952902f71dae7ba5f34427195426353 100644 (file)
 
 package org.apache.poi.hslf.model;
 
-import junit.framework.TestCase;
-import org.apache.poi.hslf.usermodel.SlideShow;
-import org.apache.poi.hslf.usermodel.RichTextRun;
-import org.apache.poi.hslf.HSLFSlideShow;
-import org.apache.poi.ddf.*;
-import org.apache.poi.POIDataSamples;
-
-import java.awt.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.awt.Color;
+import java.awt.Dimension;
 import java.awt.Rectangle;
-import java.io.ByteArrayOutputStream;
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
 
+import org.apache.poi.POIDataSamples;
+import org.apache.poi.ddf.EscherDgRecord;
+import org.apache.poi.ddf.EscherDggRecord;
+import org.apache.poi.ddf.EscherOptRecord;
+import org.apache.poi.ddf.EscherProperties;
+import org.apache.poi.ddf.EscherSimpleProperty;
+import org.apache.poi.hslf.HSLFSlideShow;
+import org.apache.poi.hslf.usermodel.RichTextRun;
+import org.apache.poi.hslf.usermodel.SlideShow;
+import org.junit.Before;
+import org.junit.Test;
+
 /**
  * Test drawing shapes via Graphics2D
  *
  * @author Yegor Kozlov
  */
-public final class TestShapes extends TestCase {
+public final class TestShapes {
     private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
 
     private SlideShow ppt;
     private SlideShow pptB;
 
-    protected void setUp() throws Exception {
-               ppt = new SlideShow(_slTests.openResourceAsStream("empty.ppt"));
-
-               pptB = new SlideShow(_slTests.openResourceAsStream("empty_textbox.ppt"));
+    @Before
+    public void setUp() throws Exception {
+        InputStream is1 = null, is2 = null;
+        try {
+            is1 = _slTests.openResourceAsStream("empty.ppt");
+            ppt = new SlideShow(is1);
+            is2 = _slTests.openResourceAsStream("empty_textbox.ppt");
+            pptB = new SlideShow(is2);
+        } finally {
+            is1.close();
+            is2.close();
+        }
     }
 
-    public void testGraphics() throws Exception {
+    @Test
+    public void graphics() throws Exception {
         Slide slide = ppt.createSlide();
 
         Line line = new Line();
@@ -92,7 +114,8 @@ public final class TestShapes extends TestCase {
      * Verify that we can read TextBox shapes
      * @throws Exception
      */
-    public void testTextBoxRead() throws Exception {
+    @Test
+    public void textBoxRead() throws Exception {
         ppt = new SlideShow(_slTests.openResourceAsStream("with_textbox.ppt"));
         Slide sl = ppt.getSlides()[0];
         Shape[] sh = sl.getShapes();
@@ -127,7 +150,8 @@ public final class TestShapes extends TestCase {
      * Verify that we can add TextBox shapes to a slide
      * and set some of the style attributes
      */
-    public void testTextBoxWriteBytes() throws Exception {
+    @Test
+    public void textBoxWriteBytes() throws Exception {
         ppt = new SlideShow();
         Slide sl = ppt.createSlide();
         RichTextRun rt;
@@ -180,7 +204,8 @@ public final class TestShapes extends TestCase {
     /**
      * Test with an empty text box
      */
-    public void testEmptyTextBox() {
+    @Test
+    public void emptyTextBox() {
        assertEquals(2, pptB.getSlides().length);
        Slide s1 = pptB.getSlides()[0];
        Slide s2 = pptB.getSlides()[1];
@@ -194,7 +219,8 @@ public final class TestShapes extends TestCase {
      * If you iterate over text shapes in a slide and collect them in a set
      * it must be the same as returned by Slide.getTextRuns().
      */
-    public void testTextBoxSet() throws Exception {
+    @Test
+    public void textBoxSet() throws Exception {
         textBoxSet("with_textbox.ppt");
         textBoxSet("basic_test_ppt_file.ppt");
         textBoxSet("next_test_ppt_file.ppt");
@@ -207,13 +233,13 @@ public final class TestShapes extends TestCase {
         SlideShow ppt = new SlideShow(_slTests.openResourceAsStream(filename));
         Slide[] sl = ppt.getSlides();
         for (int k = 0; k < sl.length; k++) {
-            ArrayList lst1 = new ArrayList();
+            ArrayList<String> lst1 = new ArrayList<String>();
             TextRun[] txt = sl[k].getTextRuns();
             for (int i = 0; i < txt.length; i++) {
                 lst1.add(txt[i].getText());
             }
 
-            ArrayList lst2 = new ArrayList();
+            ArrayList<String> lst2 = new ArrayList<String>();
             Shape[] sh = sl[k].getShapes();
             for (int i = 0; i < sh.length; i++) {
                 if (sh[i] instanceof TextShape){
@@ -229,7 +255,8 @@ public final class TestShapes extends TestCase {
     /**
      * Test adding shapes to <code>ShapeGroup</code>
      */
-    public void testShapeGroup() throws Exception {
+    @Test
+    public void shapeGroup() throws Exception {
         SlideShow ppt = new SlideShow();
 
         Slide slide = ppt.createSlide();
@@ -280,7 +307,8 @@ public final class TestShapes extends TestCase {
     /**
      * Test functionality of Sheet.removeShape(Shape shape)
      */
-    public void testRemoveShapes() throws IOException {
+    @Test
+    public void removeShapes() throws IOException {
         String file = "with_textbox.ppt";
         SlideShow ppt = new SlideShow(_slTests.openResourceAsStream(file));
         Slide sl = ppt.getSlides()[0];
@@ -304,21 +332,23 @@ public final class TestShapes extends TestCase {
         assertEquals("expected 0 shaped in " + file, 0, sl.getShapes().length);
     }
 
-    public void testLineWidth() {
+    @Test
+    public void lineWidth() {
         SimpleShape sh = new AutoShape(ShapeTypes.RightTriangle);
 
-        EscherOptRecord opt = (EscherOptRecord)SimpleShape.getEscherChild(sh.getSpContainer(), EscherOptRecord.RECORD_ID);
-        EscherSimpleProperty prop = (EscherSimpleProperty)SimpleShape.getEscherProperty(opt, EscherProperties.LINESTYLE__LINEWIDTH);
+        EscherOptRecord opt = sh.getEscherOptRecord();
+        EscherSimpleProperty prop = SimpleShape.getEscherProperty(opt, EscherProperties.LINESTYLE__LINEWIDTH);
         assertNull(prop);
-        assertEquals(SimpleShape.DEFAULT_LINE_WIDTH, sh.getLineWidth());
+        assertEquals(SimpleShape.DEFAULT_LINE_WIDTH, sh.getLineWidth(), 0);
 
         sh.setLineWidth(1.0);
-        prop = (EscherSimpleProperty)SimpleShape.getEscherProperty(opt, EscherProperties.LINESTYLE__LINEWIDTH);
+        prop = SimpleShape.getEscherProperty(opt, EscherProperties.LINESTYLE__LINEWIDTH);
         assertNotNull(prop);
-        assertEquals(1.0, sh.getLineWidth());
+        assertEquals(1.0, sh.getLineWidth(), 0);
     }
 
-    public void testShapeId() {
+    @Test
+    public void shapeId() {
         SlideShow ppt = new SlideShow();
         Slide slide = ppt.createSlide();
         Shape shape = null;
@@ -367,7 +397,8 @@ public final class TestShapes extends TestCase {
         assertEquals(numClusters + 1, dgg.getNumIdClusters());
     }
 
-    public void testLineColor() throws IOException {
+    @Test
+    public void lineColor() throws IOException {
         SlideShow ppt = new SlideShow(_slTests.openResourceAsStream("51731.ppt"));
         Shape[] shape = ppt.getSlides()[0].getShapes();
 
@@ -384,11 +415,11 @@ public final class TestShapes extends TestCase {
         TextShape sh3 = (TextShape)shape[2];
         assertEquals("Text in a black border", sh3.getText());
         assertEquals(Color.black, sh3.getLineColor());
-        assertEquals(0.75, sh3.getLineWidth());
+        assertEquals(0.75, sh3.getLineWidth(), 0);
 
         TextShape sh4 = (TextShape)shape[3];
         assertEquals("Border width is 5 pt", sh4.getText());
         assertEquals(Color.black, sh4.getLineColor());
-        assertEquals(5.0, sh4.getLineWidth());
+        assertEquals(5.0, sh4.getLineWidth(), 0);
     }
 }
index d3a759c9bf9e5721c8d466c6efbecf1d4fb8da9c..67d250a4b646ef575e1fbd3e1e65abed84242f10 100644 (file)
@@ -37,9 +37,14 @@ import java.util.Set;
 import junit.framework.AssertionFailedError;
 
 import org.apache.poi.POIDataSamples;
+import org.apache.poi.ddf.EscherArrayProperty;
+import org.apache.poi.ddf.EscherColorRef;
+import org.apache.poi.ddf.EscherOptRecord;
+import org.apache.poi.ddf.EscherProperties;
 import org.apache.poi.hslf.HSLFSlideShow;
 import org.apache.poi.hslf.HSLFTestDataSamples;
 import org.apache.poi.hslf.exceptions.OldPowerPointFormatException;
+import org.apache.poi.hslf.model.AutoShape;
 import org.apache.poi.hslf.model.Background;
 import org.apache.poi.hslf.model.Fill;
 import org.apache.poi.hslf.model.HeadersFooters;
@@ -59,7 +64,9 @@ import org.apache.poi.hslf.record.Record;
 import org.apache.poi.hslf.record.SlideListWithText;
 import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
 import org.apache.poi.hslf.record.TextHeaderAtom;
+import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.StringUtil;
+import org.apache.poi.util.Units;
 import org.junit.Test;
 
 /**
@@ -625,4 +632,36 @@ public final class TestBugs {
             inputStream.close();
         }
     }
+    
+    @Test
+    public void bug46441() throws Exception {
+        InputStream inputStream = new FileInputStream(_slTests.getFile("bug46441.ppt"));
+        try {
+            SlideShow slideShow = new SlideShow(inputStream);
+            AutoShape as = (AutoShape)slideShow.getSlides()[0].getShapes()[0];
+            EscherOptRecord opt = as.getEscherOptRecord();
+            EscherArrayProperty ep = Shape.getEscherProperty(opt, EscherProperties.FILL__SHADECOLORS);
+            double exp[][] = {
+                // r, g, b, position
+                { 94, 158, 255, 0 },
+                { 133, 194, 255, 0.399994 },
+                { 196, 214, 235, 0.699997 },
+                { 255, 235, 250, 1 }                    
+            };
+            
+            int i = 0;
+            for (byte data[] : ep) {
+                EscherColorRef ecr = new EscherColorRef(data, 0, 4);
+                int rgb[] = ecr.getRGB();
+                double pos = Units.fixedPointToDecimal(LittleEndian.getInt(data, 4));
+                assertEquals((int)exp[i][0], rgb[0]);
+                assertEquals((int)exp[i][1], rgb[1]);
+                assertEquals((int)exp[i][2], rgb[2]);
+                assertEquals(exp[i][3], pos, 0.01);
+                i++;
+            }
+        } finally {
+            inputStream.close();
+        }
+    }
 }
diff --git a/test-data/slideshow/bug46441.ppt b/test-data/slideshow/bug46441.ppt
new file mode 100644 (file)
index 0000000..a7a019c
Binary files /dev/null and b/test-data/slideshow/bug46441.ppt differ