]> source.dussan.org Git - poi.git/commitdiff
initial support for excel auto-filters
authorYegor Kozlov <yegor@apache.org>
Sun, 8 Aug 2010 11:11:38 +0000 (11:11 +0000)
committerYegor Kozlov <yegor@apache.org>
Sun, 8 Aug 2010 11:11:38 +0000 (11:11 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@983382 13f79535-47bb-0310-9956-ffa450edef68

23 files changed:
src/documentation/content/xdocs/spreadsheet/quick-guide.xml
src/documentation/content/xdocs/status.xml
src/java/org/apache/poi/hssf/dev/BiffViewer.java
src/java/org/apache/poi/hssf/model/AbstractShape.java
src/java/org/apache/poi/hssf/model/ComboboxShape.java [new file with mode: 0755]
src/java/org/apache/poi/hssf/record/AutoFilterInfoRecord.java [new file with mode: 0755]
src/java/org/apache/poi/hssf/record/FtCblsSubRecord.java [new file with mode: 0755]
src/java/org/apache/poi/hssf/record/LbsDataSubRecord.java
src/java/org/apache/poi/hssf/record/RecordFactory.java
src/java/org/apache/poi/hssf/record/SubRecord.java
src/java/org/apache/poi/hssf/record/UnknownRecord.java
src/java/org/apache/poi/hssf/usermodel/HSSFAutoFilter.java [new file with mode: 0755]
src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java
src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
src/java/org/apache/poi/hssf/usermodel/HSSFSimpleShape.java
src/java/org/apache/poi/ss/usermodel/AutoFilter.java [new file with mode: 0755]
src/java/org/apache/poi/ss/usermodel/Sheet.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFAutoFilter.java [new file with mode: 0755]
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
src/testcases/org/apache/poi/hssf/record/TestAutoFilterInfoRecord.java [new file with mode: 0755]
src/testcases/org/apache/poi/hssf/record/TestFtCblsSubRecord.java [new file with mode: 0755]
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFSheet.java

index a959090ac353fa56e1ea50ab5367d6aa5c302746..acd08d906317fed8b6dda06803aeb2a7cb2aa85b 100644 (file)
@@ -70,6 +70,7 @@
                     <li><link href="#Hyperlinks">Hyperlinks</link></li>
                     <li><link href="#Validation">Data Validation</link></li>
                     <li><link href="#Embedded">Embedded Objects</link></li>
+                    <li><link href="#Autofilter">Autofilters</link></li>
                 </ul>
             </section>
             <section><title>Features</title>
@@ -1638,5 +1639,14 @@ Examples:
   }
        </source>  
      </section>  
+     <anchor id="Autofilter"/>
+     <p>(Since POI-3.7)</p>
+     <section><title>Autofilters</title>
+       <source>
+    Workbook wb = new HSSFWorkbook(); //or new XSSFWorkbook();
+    Sheet sheet = wb.createSheet();
+    sheet.setAutoFilter(CellRangeAddress.valueOf("C5:F200"));
+       </source>
+     </section>  
     </body>
 </document>
index b58b3f41fee777671bb41fe2657ea7c08290f4e2..7f44b2b410fcc1989e877fdf42afd1be305036fb 100644 (file)
     </developers>
 
     <changes>
-<!--
-        <release version="3.7-beta2" date="2010-??-??">
+        <release version="3.7-beta3" date="2010-??-??">
+           <action dev="POI-DEVELOPERS" type="add">initial support for Excel autofilter</action>
         </release>
--->
         <release version="3.7-beta2" date="2010-08-09">
            <action dev="POI-DEVELOPERS" type="add">47990 - Support for .msg attachments within a MAPIMessage .msg</action>
            <action dev="POI-DEVELOPERS" type="fix">Improve handling and warnings when closing OPCPackage objects</action>
index ee6e159c4f2d3548185de36a88ffb1b1d1abef81..14818a8ab338b1fa762aa8fb8889abcbb2ac6183 100644 (file)
@@ -122,6 +122,7 @@ public final class BiffViewer {
                        case AxisParentRecord.sid:     return new AxisParentRecord(in);
                        case AxisRecord.sid:           return new AxisRecord(in);
                        case AxisUsedRecord.sid:       return new AxisUsedRecord(in);
+            case AutoFilterInfoRecord.sid: return new AutoFilterInfoRecord(in);
                        case BOFRecord.sid:            return new BOFRecord(in);
                        case BackupRecord.sid:         return new BackupRecord(in);
                        case BarRecord.sid:            return new BarRecord(in);
index 19878db797cebdc4506c68bc84ec0643bd0df4ce..31c1d1d8afbed90fd0b6cba770528004f6cc9ad1 100644 (file)
@@ -63,6 +63,9 @@ public abstract class AbstractShape
                 case HSSFSimpleShape.OBJECT_TYPE_RECTANGLE:
                     shape = new SimpleFilledShape( simpleShape, shapeId );
                     break;
+                case HSSFSimpleShape.OBJECT_TYPE_COMBO_BOX:
+                    shape = new ComboboxShape( simpleShape, shapeId );
+                    break;
                 default:
                     throw new IllegalArgumentException("Do not know how to handle this type of shape");
             }
diff --git a/src/java/org/apache/poi/hssf/model/ComboboxShape.java b/src/java/org/apache/poi/hssf/model/ComboboxShape.java
new file mode 100755 (executable)
index 0000000..df697c7
--- /dev/null
@@ -0,0 +1,114 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+
+package org.apache.poi.hssf.model;
+
+import org.apache.poi.ddf.*;
+import org.apache.poi.hssf.record.*;
+import org.apache.poi.hssf.usermodel.*;
+
+/**
+ * Represents a combobox shape.
+ * 
+ * @author Yegor Kozlov
+ */
+public class ComboboxShape
+        extends AbstractShape {
+    private EscherContainerRecord spContainer;
+    private ObjRecord objRecord;
+
+    /**
+     * Creates the low evel records for a combobox.
+     *
+     * @param hssfShape The highlevel shape.
+     * @param shapeId   The shape id to use for this shape.
+     */
+    ComboboxShape(HSSFSimpleShape hssfShape, int shapeId) {
+        spContainer = createSpContainer(hssfShape, shapeId);
+        objRecord = createObjRecord(hssfShape, shapeId);
+    }
+
+    /**
+     * Creates the low level OBJ record for this shape.
+     */
+    private ObjRecord createObjRecord(HSSFSimpleShape shape, int shapeId) {
+        ObjRecord obj = new ObjRecord();
+        CommonObjectDataSubRecord c = new CommonObjectDataSubRecord();
+        c.setObjectType(HSSFSimpleShape.OBJECT_TYPE_COMBO_BOX);
+        c.setObjectId(shapeId);
+        c.setLocked(true);
+        c.setPrintable(false);
+        c.setAutofill(true);
+        c.setAutoline(false);
+
+        LbsDataSubRecord l = LbsDataSubRecord.newAutoFilterInstance();
+
+        EndSubRecord e = new EndSubRecord();
+
+        obj.addSubRecord(c);
+        obj.addSubRecord(l);
+        obj.addSubRecord(e);
+
+        return obj;
+    }
+
+    /**
+     * Generates the escher shape records for this shape.
+     */
+    private EscherContainerRecord createSpContainer(HSSFSimpleShape shape, int shapeId) {
+        EscherContainerRecord spContainer = new EscherContainerRecord();
+        EscherSpRecord sp = new EscherSpRecord();
+        EscherOptRecord opt = new EscherOptRecord();
+        EscherClientDataRecord clientData = new EscherClientDataRecord();
+
+        spContainer.setRecordId(EscherContainerRecord.SP_CONTAINER);
+        spContainer.setOptions((short) 0x000F);
+        sp.setRecordId(EscherSpRecord.RECORD_ID);
+        sp.setOptions((short) ((EscherAggregate.ST_HOSTCONTROL << 4) | 0x2));
+
+        sp.setShapeId(shapeId);
+        sp.setFlags(EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE);
+        opt.setRecordId(EscherOptRecord.RECORD_ID);
+        opt.addEscherProperty(new EscherBoolProperty(EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 17039620));
+        opt.addEscherProperty(new EscherBoolProperty(EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x00080008));
+        opt.addEscherProperty(new EscherBoolProperty(EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x00080000));
+        opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GROUPSHAPE__PRINT, 0x00020000));
+
+        HSSFClientAnchor userAnchor = (HSSFClientAnchor) shape.getAnchor();
+        userAnchor.setAnchorType(1);
+        EscherRecord anchor = createAnchor(userAnchor);
+        clientData.setRecordId(EscherClientDataRecord.RECORD_ID);
+        clientData.setOptions((short) 0x0000);
+
+        spContainer.addChildRecord(sp);
+        spContainer.addChildRecord(opt);
+        spContainer.addChildRecord(anchor);
+        spContainer.addChildRecord(clientData);
+
+        return spContainer;
+    }
+
+    public EscherContainerRecord getSpContainer() {
+        return spContainer;
+    }
+
+    public ObjRecord getObjRecord() {
+        return objRecord;
+    }
+
+}
\ No newline at end of file
diff --git a/src/java/org/apache/poi/hssf/record/AutoFilterInfoRecord.java b/src/java/org/apache/poi/hssf/record/AutoFilterInfoRecord.java
new file mode 100755 (executable)
index 0000000..881cf3b
--- /dev/null
@@ -0,0 +1,101 @@
+
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+
+package org.apache.poi.hssf.record;
+
+import org.apache.poi.util.LittleEndianOutput;
+
+/**
+ * The AutoFilterInfo record specifies the number of columns that have AutoFilter enabled
+ * and indicates the beginning of the collection of AutoFilter records.
+ *
+ * @author Yegor Kozlov
+ */
+
+public final class AutoFilterInfoRecord
+    extends StandardRecord
+{
+    public final static short sid = 0x9D;
+    /**
+     * Number of AutoFilter drop-down arrows on the sheet
+     */
+    private short             _cEntries;   // = 0;
+
+    public AutoFilterInfoRecord()
+    {
+    }
+
+    public AutoFilterInfoRecord(RecordInputStream in)
+    {
+        _cEntries = in.readShort();
+    }
+
+    /**
+     * set the number of AutoFilter drop-down arrows on the sheet
+     *
+     * @param num  the number of AutoFilter drop-down arrows on the sheet
+     */
+
+    public void setNumEntries(short num)
+    {
+        _cEntries = num;
+    }
+
+    /**
+     * get the number of AutoFilter drop-down arrows on the sheet
+     *
+     * @return the number of AutoFilter drop-down arrows on the sheet
+     */
+
+    public short getNumEntries()
+    {
+        return _cEntries;
+    }
+
+    public String toString()
+    {
+        StringBuffer buffer = new StringBuffer();
+
+        buffer.append("[AUTOFILTERINFO]\n");
+        buffer.append("    .numEntries          = ")
+            .append(_cEntries).append("\n");
+        buffer.append("[/AUTOFILTERINFO]\n");
+        return buffer.toString();
+    }
+
+    public void serialize(LittleEndianOutput out) {
+        out.writeShort(_cEntries);
+    }
+
+    protected int getDataSize() {
+        return 2;
+    }
+
+    public short getSid()
+    {
+        return sid;
+    }
+
+    @Override
+    public Object clone()
+    {
+       return cloneViaReserialise();
+    }
+    
+}
\ No newline at end of file
diff --git a/src/java/org/apache/poi/hssf/record/FtCblsSubRecord.java b/src/java/org/apache/poi/hssf/record/FtCblsSubRecord.java
new file mode 100755 (executable)
index 0000000..517add9
--- /dev/null
@@ -0,0 +1,101 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.record;
+
+import org.apache.poi.util.HexDump;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
+
+
+/**
+ * This structure appears as part of an Obj record that represents a checkbox or radio button.
+ *
+ * @author Yegor Kozlov
+ */
+public final class FtCblsSubRecord extends SubRecord {
+    public final static short sid = 0x0C;
+    private static final int ENCODED_SIZE = 20;
+
+    private byte[] reserved;
+
+    /**
+     * Construct a new <code>FtCblsSubRecord</code> and
+     * fill its data with the default values
+     */
+    public FtCblsSubRecord()
+    {
+        reserved = new byte[ENCODED_SIZE];
+    }
+
+    public FtCblsSubRecord(LittleEndianInput in, int size) {
+        if (size != ENCODED_SIZE) {
+            throw new RecordFormatException("Unexpected size (" + size + ")");
+        }
+        //just grab the raw data
+        byte[] buf = new byte[size];
+        in.readFully(buf);
+        reserved = buf;
+    }
+
+    /**
+     * Convert this record to string.
+     * Used by BiffViewer and other utilities.
+     */
+    public String toString()
+    {
+        StringBuffer buffer = new StringBuffer();
+
+        buffer.append("[FtCbls ]").append("\n");
+        buffer.append("  size     = ").append(getDataSize()).append("\n");
+        buffer.append("  reserved = ").append(HexDump.toHex(reserved)).append("\n");
+        buffer.append("[/FtCbls ]").append("\n");
+        return buffer.toString();
+    }
+
+    /**
+     * Serialize the record data into the supplied array of bytes
+     *
+     * @param out the stream to serialize into
+     */
+    public void serialize(LittleEndianOutput out) {
+        out.writeShort(sid);
+        out.writeShort(reserved.length);
+        out.write(reserved);
+    }
+
+       protected int getDataSize() {
+        return reserved.length;
+    }
+
+    /**
+     * @return id of this record.
+     */
+    public short getSid()
+    {
+        return sid;
+    }
+
+    public Object clone() {
+        FtCblsSubRecord rec = new FtCblsSubRecord();
+        byte[] recdata = new byte[reserved.length];
+        System.arraycopy(reserved, 0, recdata, 0, recdata.length);
+        rec.reserved = recdata;
+        return rec;
+    }
+
+}
\ No newline at end of file
index 57ebb203965e77c9c65682c02b5eda99c16a7068..779523a9698db209c7ee2bab4e264bc095ca87d0 100755 (executable)
@@ -150,6 +150,29 @@ public class LbsDataSubRecord extends SubRecord {
 \r
     }\r
 \r
+    LbsDataSubRecord(){\r
+\r
+    }\r
+\r
+    /**\r
+     *\r
+     * @return a new instance of LbsDataSubRecord to construct auto-filters\r
+     * @see org.apache.poi.hssf.model.ComboboxShape#createObjRecord(org.apache.poi.hssf.usermodel.HSSFSimpleShape, int)\r
+     */\r
+    public static LbsDataSubRecord newAutoFilterInstance(){\r
+        LbsDataSubRecord lbs = new LbsDataSubRecord();\r
+        lbs._cbFContinued = 0x1FEE;  //autofilters seem to alway have this magic number\r
+        lbs._iSel = 0x000;\r
+\r
+        lbs._flags = 0x0301;\r
+        lbs._dropData = new LbsDropData();\r
+        lbs._dropData._wStyle = LbsDropData.STYLE_COMBO_SIMPLE_DROPDOWN;\r
+\r
+        // the number of lines to be displayed in the dropdown\r
+        lbs._dropData._cLine = 8;\r
+        return lbs;\r
+    }\r
+\r
     /**\r
      * @return true as LbsDataSubRecord is always the last sub-record\r
      */\r
@@ -272,6 +295,19 @@ public class LbsDataSubRecord extends SubRecord {
      * This structure specifies properties of the dropdown list control\r
      */\r
     public static class LbsDropData {\r
+        /**\r
+         * Combo dropdown control\r
+         */\r
+        public static int STYLE_COMBO_DROPDOWN = 0;\r
+        /**\r
+         * Combo Edit dropdown control\r
+         */\r
+        public static int STYLE_COMBO_EDIT_DROPDOWN = 1;\r
+        /**\r
+         * Simple dropdown control (just the dropdown button)\r
+         */\r
+        public static int STYLE_COMBO_SIMPLE_DROPDOWN = 2;\r
+\r
         /**\r
          *  An unsigned integer that specifies the style of this dropdown. \r
          */\r
@@ -298,6 +334,11 @@ public class LbsDataSubRecord extends SubRecord {
          */\r
         private Byte _unused;\r
 \r
+        public LbsDropData(){\r
+            _str = "";\r
+            _unused = 0;\r
+        }\r
+\r
         public LbsDropData(LittleEndianInput in){\r
             _wStyle = in.readUShort();\r
             _cLine = in.readUShort();\r
@@ -308,6 +349,27 @@ public class LbsDataSubRecord extends SubRecord {
             }\r
         }\r
 \r
+        /**\r
+         *  Set the style of this dropdown.\r
+         *\r
+         * Possible values:\r
+         *  <p>\r
+         *  0  Combo dropdown control\r
+         *  1  Combo Edit dropdown control\r
+         *  2  Simple dropdown control (just the dropdown button)\r
+         *\r
+         */\r
+        public void setStyle(int style){\r
+            _wStyle = style;\r
+        }\r
+\r
+        /**\r
+         * Set the number of lines to be displayed in the dropdown.\r
+         */\r
+        public void setNumLines(int num){\r
+            _cLine = num;\r
+        }\r
+\r
         public void serialize(LittleEndianOutput out) {\r
             out.writeShort(_wStyle);\r
             out.writeShort(_cLine);\r
index 029b7e0413dbaa6917bb227ee21c76c128475c64..68c97bd7da09d681df5f2cc005683de456d2029a 100644 (file)
@@ -107,7 +107,8 @@ public final class RecordFactory {
        @SuppressWarnings("unchecked")
        private static final Class<? extends Record>[] recordClasses = new Class[] {
                ArrayRecord.class,
-               BackupRecord.class,
+        AutoFilterInfoRecord.class,
+        BackupRecord.class,
                BlankRecord.class,
                BOFRecord.class,
                BookBoolRecord.class,
index 59b01cf35dd75c4dbf594a797ec140b82eebf76b..fd54acc0a7ae4c7cdc5e5077f10e4bd23f39d8e3 100644 (file)
@@ -57,6 +57,8 @@ public abstract class SubRecord {
                                return new NoteStructureSubRecord(in, secondUShort);
                        case LbsDataSubRecord.sid:
                                return new LbsDataSubRecord(in, secondUShort, cmoOt);
+            case FtCblsSubRecord.sid:
+                return new FtCblsSubRecord(in, secondUShort);
                }
                return new UnknownSubRecord(in, sid, secondUShort);
        }
index 20b352456d11b66366db96b4ea1cf64eab0c2e5c..3e04d0f8bf96db73ca10a9b0f3c0711daa15bb34 100644 (file)
@@ -139,7 +139,6 @@ public final class UnknownRecord extends StandardRecord {
                        case SORT_0090: return "SORT"; // Sorting Options
                        case 0x0094: return "LHRECORD"; // .WK? File Conversion Information
                        case STANDARDWIDTH_0099: return "STANDARDWIDTH"; //Standard Column Width
-                       case 0x009D: return "AUTOFILTERINFO"; // Drop-Down Arrow Count
                        case SCL_00A0: return "SCL"; // Window Zoom Magnification
                        case 0x00AE: return "SCENMAN"; // Scenario Output Data
 
@@ -241,6 +240,7 @@ public final class UnknownRecord extends StandardRecord {
                        case 0x101B:
                        case 0x101D:
                        case 0x101E:
+                       case 0x101F:
                        case 0x1020:
                        case 0x1021:
                        case 0x1022:
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFAutoFilter.java b/src/java/org/apache/poi/hssf/usermodel/HSSFAutoFilter.java
new file mode 100755 (executable)
index 0000000..8baa139
--- /dev/null
@@ -0,0 +1,32 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.usermodel;
+import org.apache.poi.ss.usermodel.AutoFilter;
+
+/**
+ * Represents autofiltering for the specified worksheet.
+ *
+ * @author Yegor Kozlov
+ */
+public final class HSSFAutoFilter implements AutoFilter {
+    private HSSFSheet _sheet;
+
+    HSSFAutoFilter(HSSFSheet sheet){
+        _sheet = sheet;
+    }
+}
\ No newline at end of file
index 859181d7acb44b14f3c84c8b29efe275caa09b3b..0f7cde94201c1e0e703508ac4d5fdfe7d164c4a6 100644 (file)
@@ -157,6 +157,20 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
         return shape;
     }
 
+    /**
+     * YK: used to create autofilters
+     *
+     * @see org.apache.poi.hssf.usermodel.HSSFSheet#setAutoFilter(int, int, int, int)
+     */
+     HSSFSimpleShape createComboBox(HSSFAnchor anchor)
+     {
+         HSSFSimpleShape shape = new HSSFSimpleShape(null, anchor);
+         shape.setShapeType(HSSFSimpleShape.OBJECT_TYPE_COMBO_BOX);
+         shape.anchor = anchor;
+         _shapes.add(shape);
+         return shape;
+     }
+
     public HSSFComment createCellComment(ClientAnchor anchor) {
         return createComment((HSSFAnchor)anchor);
     }
index 33af66680e2175390681797ef2c96f83267cb403..283032ee4da17331e0679d287e8037d97b8b36ed 100644 (file)
@@ -34,21 +34,13 @@ import org.apache.poi.ddf.EscherRecord;
 import org.apache.poi.hssf.model.HSSFFormulaParser;
 import org.apache.poi.hssf.model.InternalSheet;
 import org.apache.poi.hssf.model.InternalWorkbook;
-import org.apache.poi.hssf.record.CellValueRecordInterface;
-import org.apache.poi.hssf.record.DVRecord;
-import org.apache.poi.hssf.record.EscherAggregate;
-import org.apache.poi.hssf.record.ExtendedFormatRecord;
-import org.apache.poi.hssf.record.NoteRecord;
-import org.apache.poi.hssf.record.Record;
-import org.apache.poi.hssf.record.RowRecord;
-import org.apache.poi.hssf.record.SCLRecord;
-import org.apache.poi.hssf.record.WSBoolRecord;
-import org.apache.poi.hssf.record.WindowTwoRecord;
+import org.apache.poi.hssf.record.*;
 import org.apache.poi.hssf.record.aggregates.DataValidityTable;
 import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
 import org.apache.poi.hssf.record.aggregates.WorksheetProtectionBlock;
 import org.apache.poi.hssf.record.formula.FormulaShifter;
 import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.hssf.record.formula.Area3DPtg;
 import org.apache.poi.hssf.util.PaneInformation;
 import org.apache.poi.hssf.util.Region;
 import org.apache.poi.ss.SpreadsheetVersion;
@@ -1573,15 +1565,17 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
      * @return  The new patriarch.
      */
     public HSSFPatriarch createDrawingPatriarch() {
-        // Create the drawing group if it doesn't already exist.
-        _book.createDrawingGroup();
-
-        _sheet.aggregateDrawingRecords(_book.getDrawingManager(), true);
-        EscherAggregate agg = (EscherAggregate) _sheet.findFirstRecordBySid(EscherAggregate.sid);
-        _patriarch = new HSSFPatriarch(this, agg);
-        agg.clear();     // Initially the behaviour will be to clear out any existing shapes in the sheet when
-                         // creating a new patriarch.
-        agg.setPatriarch(_patriarch);
+        if(_patriarch == null){
+            // Create the drawing group if it doesn't already exist.
+            _book.createDrawingGroup();
+
+            _sheet.aggregateDrawingRecords(_book.getDrawingManager(), true);
+            EscherAggregate agg = (EscherAggregate) _sheet.findFirstRecordBySid(EscherAggregate.sid);
+            _patriarch = new HSSFPatriarch(this, agg);
+            agg.clear();     // Initially the behaviour will be to clear out any existing shapes in the sheet when
+                             // creating a new patriarch.
+            agg.setPatriarch(_patriarch);
+        }
         return _patriarch;
     }
 
@@ -2000,5 +1994,39 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
                return new HSSFDataValidationHelper(this);
        }
     
-    
+    public HSSFAutoFilter setAutoFilter(CellRangeAddress range) {
+
+
+        InternalWorkbook workbook = _workbook.getWorkbook();
+        int sheetIndex = _workbook.getSheetIndex(this);
+
+        NameRecord name = workbook.getSpecificBuiltinRecord(NameRecord.BUILTIN_FILTER_DB, sheetIndex+1);
+
+        if (name == null) {
+            name = workbook.createBuiltInName(NameRecord.BUILTIN_FILTER_DB, sheetIndex+1);
+        }
+
+        // The built-in name must consist of a single Area3d Ptg.
+        Area3DPtg ptg = new Area3DPtg(range.getFirstRow(), range.getLastRow(),
+                range.getFirstColumn(), range.getLastColumn(),
+                false, false, false, false, sheetIndex);
+        name.setNameDefinition(new Ptg[]{ptg});
+
+        AutoFilterInfoRecord r = new AutoFilterInfoRecord();
+        // the number of columns that have AutoFilter enabled.
+        int numcols = 1 + range.getLastColumn() - range.getFirstColumn();
+        r.setNumEntries((short)numcols);
+        int idx = _sheet.findFirstRecordLocBySid(DimensionsRecord.sid);
+        _sheet.getRecords().add(idx, r);
+
+        //create a combobox control for each column
+        HSSFPatriarch p = createDrawingPatriarch();
+        for(int col = range.getFirstColumn(); col <= range.getLastColumn(); col++){
+            p.createComboBox(new HSSFClientAnchor(0,0,0,0,
+                    (short)col, range.getFirstRow(), (short)(col+1), range.getFirstRow()+1));
+        }
+        
+        return new HSSFAutoFilter(this);
+    }
+
 }
index dca653ad8d232cb978ae6b8f1fb62c8ef66e5169..0e4df4067208313c26a7babff4f6c15047eb69b3 100644 (file)
@@ -46,7 +46,7 @@ public class HSSFSimpleShape
 //    public final static short       OBJECT_TYPE_SCROLL_BAR         = 17;
 //    public final static short       OBJECT_TYPE_LIST_BOX           = 18;
 //    public final static short       OBJECT_TYPE_GROUP_BOX          = 19;
-//    public final static short       OBJECT_TYPE_COMBO_BOX          = 20;
+    public final static short       OBJECT_TYPE_COMBO_BOX          = 20;
     public final static short       OBJECT_TYPE_COMMENT            = 25;
 //    public final static short       OBJECT_TYPE_MICROSOFT_OFFICE_DRAWING = 30;
 
diff --git a/src/java/org/apache/poi/ss/usermodel/AutoFilter.java b/src/java/org/apache/poi/ss/usermodel/AutoFilter.java
new file mode 100755 (executable)
index 0000000..82c7a43
--- /dev/null
@@ -0,0 +1,79 @@
+/* ====================================================================\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
+package org.apache.poi.ss.usermodel;\r
+\r
+/**\r
+ * Represents autofiltering for the specified worksheet.\r
+ *\r
+ * <p>\r
+ * Filtering data is a quick and easy way to find and work with a subset of data in a range of cells or table.\r
+ * For example, you can filter to see only the values that you specify, filter to see the top or bottom values,\r
+ * or filter to quickly see duplicate values.\r
+ * </p>\r
+ *\r
+ * TODO YK: For now (Aug 2010) POI only supports setting a basic autofilter on a range of cells.\r
+ * In future, when we support more auto-filter functions like custom criteria, sort, etc. we will add\r
+ * corresponding methods to this interface.\r
+ */\r
+public interface AutoFilter {\r
+    /**\r
+     * Apply a custom filter\r
+     *\r
+     * <p>\r
+     * A custom AutoFilter specifies an operator and a value.\r
+     * There can be at most two customFilters specified, and in that case the parent element\r
+     * specifies whether the two conditions are joined by 'and' or 'or'. For any cells whose\r
+     * values do not meet the specified criteria, the corresponding rows shall be hidden from\r
+     * view when the filter is applied.\r
+     * </p>\r
+     *\r
+     * <p>\r
+     * Example:\r
+     * <blockquote><pre>\r
+     *  AutoFilter filter = sheet.setAutoFilter(CellRangeAddress.valueOf("A1:F200"));\r
+     *  filter.applyFilter(0, FilterOperator.GreaterThanOrEqual", "0.2");\r
+     *  filter.applyFilter(1, FilterOperator.LessThanOrEqual"", "0.5");\r
+     * </pre></blockquote>\r
+     * </p>\r
+     *\r
+     * @param columnIndex 0-based column index\r
+     * @param operator the operator to apply\r
+     * @param criteria top or bottom value used in the filter criteria.\r
+     *\r
+     * TODO YK: think how to combine AutoFilter with with DataValidationConstraint, they are really close relatives\r
+     * void applyFilter(int columnIndex, FilterOperator operator, String criteria);\r
+     */\r
+\r
+\r
+    /**\r
+     * Apply a filter against a list of values\r
+     *\r
+     * <p>\r
+     * Example:\r
+     * <blockquote><pre>\r
+     *  AutoFilter filter = sheet.setAutoFilter(CellRangeAddress.valueOf("A1:F200"));\r
+     *  filter.applyFilter(0, "apache", "poi", "java", "api");\r
+     * </pre></blockquote>\r
+     * </p>\r
+     *\r
+     * @param columnIndex 0-based column index\r
+     * @param values the filter values\r
+     *\r
+     * void applyFilter(int columnIndex, String ... values);\r
+     */\r
+    \r
+}\r
index bad9c5c7191781cb3ead2aa3e4cf55fb3cf7a1c2..b4a1dbc0e6008abfc8cbceb2e24c73faa51406c9 100644 (file)
@@ -806,4 +806,12 @@ public interface Sheet extends Iterable<Row> {
         * @param dataValidation The Data validation object settings
         */
        public void addValidationData(DataValidation dataValidation);
+
+    /**
+     * Enable filtering for a range of cells
+     * 
+     * @param range the range of cells to filter
+     */
+    AutoFilter setAutoFilter(CellRangeAddress range);
+    
 }
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFAutoFilter.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFAutoFilter.java
new file mode 100755 (executable)
index 0000000..d363ab3
--- /dev/null
@@ -0,0 +1,33 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.xssf.usermodel;
+import org.apache.poi.ss.usermodel.AutoFilter;
+
+/**
+ * Represents autofiltering for the specified worksheet.
+ *
+ * @author Yegor Kozlov
+ */
+public final class XSSFAutoFilter implements AutoFilter {
+    private XSSFSheet _sheet;
+
+    XSSFAutoFilter(XSSFSheet sheet){
+        _sheet = sheet;
+    }
+
+}
\ No newline at end of file
index 26c4694055555565afc35b9198012cb504217be4..815a351663f6c805dd2b43e08c6b9a26835f5c7e 100644 (file)
@@ -61,41 +61,7 @@ import org.apache.poi.xssf.usermodel.helpers.XSSFRowShifter;
 import org.apache.xmlbeans.XmlException;
 import org.apache.xmlbeans.XmlOptions;
 import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBreak;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellFormula;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCommentList;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDataValidation;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDataValidations;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDrawing;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHeaderFooter;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHyperlink;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTLegacyDrawing;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCell;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCells;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTOutlinePr;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageBreak;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageMargins;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageSetUpPr;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPane;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPrintOptions;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSelection;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetData;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetFormatPr;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetPr;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetProtection;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetView;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetViews;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellFormulaType;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPaneState;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorksheetDocument;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
 
 /**
  * High level representation of a SpreadsheetML worksheet.
@@ -2918,4 +2884,16 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
                dataValidations.setCount(currentCount + 1);
 
        }
+
+    public XSSFAutoFilter setAutoFilter(CellRangeAddress range) {
+        CTAutoFilter af = worksheet.getAutoFilter();
+        if(af == null) af = worksheet.addNewAutoFilter();
+
+        CellRangeAddress norm = new CellRangeAddress(range.getFirstRow(), range.getLastRow(),
+                range.getFirstColumn(), range.getLastColumn());
+        String ref = norm.formatAsString();
+        af.setRef(ref);
+
+        return new XSSFAutoFilter(this);
+    }
 }
index 680865ed6906e15dc8cf7a8cacec93130796321f..a07e5c20b9aeb09d0164cb0bee44a48fad803535 100644 (file)
@@ -971,4 +971,12 @@ public final class TestXSSFSheet extends BaseTestSheet {
         assertEquals(3, xrow[2].getR());
 
     }
+
+    public void testSetAutoFilter() {
+        XSSFWorkbook wb = new XSSFWorkbook();
+        XSSFSheet sheet = wb.createSheet();
+        sheet.setAutoFilter(CellRangeAddress.valueOf("A1:D100"));
+
+        assertEquals("A1:D100", sheet.getCTWorksheet().getAutoFilter().getRef());
+    }
 }
diff --git a/src/testcases/org/apache/poi/hssf/record/TestAutoFilterInfoRecord.java b/src/testcases/org/apache/poi/hssf/record/TestAutoFilterInfoRecord.java
new file mode 100755 (executable)
index 0000000..e435408
--- /dev/null
@@ -0,0 +1,77 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.record;
+
+import junit.framework.TestCase;
+import org.apache.poi.ddf.EscherClientDataRecord;
+import org.apache.poi.ddf.EscherContainerRecord;
+import org.apache.poi.ddf.EscherDggRecord;
+import org.apache.poi.ddf.EscherSpRecord;
+import org.apache.poi.hssf.model.DrawingManager2;
+import org.apache.poi.util.HexDump;
+import org.apache.poi.util.HexRead;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Arrays;
+
+/**
+ * Tests the AutoFilterInfoRecord class.
+ *
+ * @author Yegor Kozlov
+ */
+public final class TestAutoFilterInfoRecord extends TestCase {
+    private byte[] data = new byte[] {
+        0x05, 0x00
+    };
+
+    public void testRead() {
+
+        AutoFilterInfoRecord record = new AutoFilterInfoRecord(TestcaseRecordInputStream.create(AutoFilterInfoRecord.sid, data));
+
+        assertEquals(AutoFilterInfoRecord.sid, record.getSid());
+        assertEquals(data.length, record.getDataSize());
+        assertEquals(5, record.getNumEntries());
+        record.setNumEntries((short)3);
+        assertEquals(3, record.getNumEntries());
+    }
+
+    public void testWrite() {
+        AutoFilterInfoRecord record = new AutoFilterInfoRecord();
+        record.setNumEntries((short)3);
+
+        byte [] ser = record.serialize();
+        assertEquals(ser.length - 4, data.length);
+        record = new AutoFilterInfoRecord(TestcaseRecordInputStream.create(ser));
+        assertEquals(3, record.getNumEntries());
+    }
+
+    public void testClone()
+    {
+        AutoFilterInfoRecord record = new AutoFilterInfoRecord();
+        record.setNumEntries((short)3);
+        byte[] src = record.serialize();
+
+        AutoFilterInfoRecord cloned = (AutoFilterInfoRecord)record.clone();
+        assertEquals(3, record.getNumEntries());
+        byte[] cln = cloned.serialize();
+
+        assertEquals(record.getDataSize(), cloned.getDataSize());
+        assertTrue(Arrays.equals(src, cln));
+    }
+}
\ No newline at end of file
diff --git a/src/testcases/org/apache/poi/hssf/record/TestFtCblsSubRecord.java b/src/testcases/org/apache/poi/hssf/record/TestFtCblsSubRecord.java
new file mode 100755 (executable)
index 0000000..3d71a8c
--- /dev/null
@@ -0,0 +1,66 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.record;
+
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+
+/**
+ * Tests the serialization and deserialization of the FtCblsSubRecord
+ * class works correctly.
+ *
+ * @author Yegor Kozlov
+ */
+public final class TestFtCblsSubRecord extends TestCase {
+    private byte[] data = new byte[] {
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00,
+        0x01, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00
+    };
+
+    public void testRead() {
+
+        FtCblsSubRecord record = new FtCblsSubRecord(TestcaseRecordInputStream.create(FtCblsSubRecord.sid, data), data.length);
+
+        assertEquals(FtCblsSubRecord.sid, record.getSid());
+        assertEquals(data.length, record.getDataSize());
+    }
+
+    public void testWrite() {
+        FtCblsSubRecord record = new FtCblsSubRecord();
+        assertEquals(FtCblsSubRecord.sid, record.getSid());
+        assertEquals(data.length, record.getDataSize());
+
+        byte [] ser = record.serialize();
+        assertEquals(ser.length - 4, data.length);
+
+    }
+
+    public void testClone()
+    {
+        FtCblsSubRecord record = new FtCblsSubRecord();
+        byte[] src = record.serialize();
+
+        FtCblsSubRecord cloned = (FtCblsSubRecord)record.clone();
+        byte[] cln = cloned.serialize();
+
+        assertEquals(record.getDataSize(), cloned.getDataSize());
+        assertTrue(Arrays.equals(src, cln));
+    }
+}
\ No newline at end of file
index c041a94ad49c3f082fe39a3921d7d83253128f97..19cf47e1c0bd14322e7eab12853c724397522e6c 100644 (file)
@@ -27,18 +27,11 @@ import org.apache.poi.ddf.EscherDgRecord;
 import org.apache.poi.hssf.HSSFITestDataProvider;
 import org.apache.poi.hssf.HSSFTestDataSamples;
 import org.apache.poi.hssf.model.DrawingManager2;
-import org.apache.poi.hssf.record.DimensionsRecord;
-import org.apache.poi.hssf.record.GridsetRecord;
-import org.apache.poi.hssf.record.HCenterRecord;
-import org.apache.poi.hssf.record.ObjectProtectRecord;
-import org.apache.poi.hssf.record.PasswordRecord;
-import org.apache.poi.hssf.record.ProtectRecord;
-import org.apache.poi.hssf.record.Record;
-import org.apache.poi.hssf.record.SCLRecord;
-import org.apache.poi.hssf.record.ScenarioProtectRecord;
-import org.apache.poi.hssf.record.VCenterRecord;
-import org.apache.poi.hssf.record.WSBoolRecord;
-import org.apache.poi.hssf.record.WindowTwoRecord;
+import org.apache.poi.hssf.model.InternalWorkbook;
+import org.apache.poi.hssf.model.InternalSheet;
+import org.apache.poi.hssf.record.*;
+import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.hssf.record.formula.Area3DPtg;
 import org.apache.poi.hssf.record.aggregates.WorksheetProtectionBlock;
 import org.apache.poi.hssf.usermodel.RecordInspector.RecordCollector;
 import org.apache.poi.ss.usermodel.BaseTestSheet;
@@ -291,13 +284,23 @@ public final class TestHSSFSheet extends BaseTestSheet {
         assertEquals(0, r6.getOutlineLevel());
     }
 
+    public void testCreateDrawings() {
+        HSSFWorkbook workbook = new HSSFWorkbook();
+        HSSFSheet sheet = workbook.createSheet();
+        HSSFPatriarch p1 = sheet.createDrawingPatriarch();
+        HSSFPatriarch p2 = sheet.createDrawingPatriarch();
+        assertSame(p1, p2);
+    }
+
     public void testGetDrawings() {
         HSSFWorkbook wb1c = HSSFTestDataSamples.openSampleWorkbook("WithChart.xls");
         HSSFWorkbook wb2c = HSSFTestDataSamples.openSampleWorkbook("WithTwoCharts.xls");
 
         // 1 chart sheet -> data on 1st, chart on 2nd
         assertNotNull(wb1c.getSheetAt(0).getDrawingPatriarch());
+        assertSame(wb1c.getSheetAt(0).getDrawingPatriarch(), wb1c.getSheetAt(0).getDrawingPatriarch());
         assertNotNull(wb1c.getSheetAt(1).getDrawingPatriarch());
+        assertSame(wb1c.getSheetAt(1).getDrawingPatriarch(), wb1c.getSheetAt(1).getDrawingPatriarch());
         assertFalse(wb1c.getSheetAt(0).getDrawingPatriarch().containsChart());
         assertTrue(wb1c.getSheetAt(1).getDrawingPatriarch().containsChart());
 
@@ -860,4 +863,37 @@ public final class TestHSSFSheet extends BaseTestSheet {
         s.setRightToLeft(true);
         assertEquals(true, s.isRightToLeft());
     }
+
+    public void testAutoFilter(){
+        HSSFWorkbook wb = new HSSFWorkbook();
+        HSSFSheet sh = wb.createSheet();
+        InternalWorkbook iwb = wb.getWorkbook();
+        InternalSheet ish = sh.getSheet();
+
+        assertNull( iwb.getSpecificBuiltinRecord(NameRecord.BUILTIN_FILTER_DB, 1) );
+        assertNull( ish.findFirstRecordBySid(AutoFilterInfoRecord.sid) );
+
+        CellRangeAddress range = CellRangeAddress.valueOf("A1:B10");
+        sh.setAutoFilter(range);
+
+        NameRecord name = iwb.getSpecificBuiltinRecord(NameRecord.BUILTIN_FILTER_DB, 1);
+        assertNotNull( name );
+
+        // The built-in name for auto-filter must consist of a single Area3d Ptg.
+        Ptg[] ptg = name.getNameDefinition();
+        assertEquals("The built-in name for auto-filter must consist of a single Area3d Ptg", 1, ptg.length);
+        assertTrue("The built-in name for auto-filter must consist of a single Area3d Ptg", ptg[0] instanceof Area3DPtg);
+
+        Area3DPtg aref = (Area3DPtg)ptg[0];
+        assertEquals(range.getFirstColumn(), aref.getFirstColumn());
+        assertEquals(range.getFirstRow(), aref.getFirstRow());
+        assertEquals(range.getLastColumn(), aref.getLastColumn());
+        assertEquals(range.getLastRow(), aref.getLastRow());
+
+        // verify  AutoFilterInfoRecord
+        AutoFilterInfoRecord afilter = (AutoFilterInfoRecord)ish.findFirstRecordBySid(AutoFilterInfoRecord.sid);
+        assertNotNull(afilter );
+        assertEquals(2, afilter.getNumEntries()); //filter covers two columns
+
+    }
 }