initial support for excel auto-filters

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@983382 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yegor Kozlov 2010-08-08 11:11:38 +00:00
parent 7ff307c17a
commit 75656c36d9
23 changed files with 825 additions and 72 deletions

View 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>

View File

@ -33,10 +33,9 @@
</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>

View 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);

View 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");
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -150,6 +150,29 @@ public class LbsDataSubRecord extends SubRecord {
}
LbsDataSubRecord(){
}
/**
*
* @return a new instance of LbsDataSubRecord to construct auto-filters
* @see org.apache.poi.hssf.model.ComboboxShape#createObjRecord(org.apache.poi.hssf.usermodel.HSSFSimpleShape, int)
*/
public static LbsDataSubRecord newAutoFilterInstance(){
LbsDataSubRecord lbs = new LbsDataSubRecord();
lbs._cbFContinued = 0x1FEE; //autofilters seem to alway have this magic number
lbs._iSel = 0x000;
lbs._flags = 0x0301;
lbs._dropData = new LbsDropData();
lbs._dropData._wStyle = LbsDropData.STYLE_COMBO_SIMPLE_DROPDOWN;
// the number of lines to be displayed in the dropdown
lbs._dropData._cLine = 8;
return lbs;
}
/**
* @return true as LbsDataSubRecord is always the last sub-record
*/
@ -272,6 +295,19 @@ public class LbsDataSubRecord extends SubRecord {
* This structure specifies properties of the dropdown list control
*/
public static class LbsDropData {
/**
* Combo dropdown control
*/
public static int STYLE_COMBO_DROPDOWN = 0;
/**
* Combo Edit dropdown control
*/
public static int STYLE_COMBO_EDIT_DROPDOWN = 1;
/**
* Simple dropdown control (just the dropdown button)
*/
public static int STYLE_COMBO_SIMPLE_DROPDOWN = 2;
/**
* An unsigned integer that specifies the style of this dropdown.
*/
@ -298,6 +334,11 @@ public class LbsDataSubRecord extends SubRecord {
*/
private Byte _unused;
public LbsDropData(){
_str = "";
_unused = 0;
}
public LbsDropData(LittleEndianInput in){
_wStyle = in.readUShort();
_cLine = in.readUShort();
@ -308,6 +349,27 @@ public class LbsDataSubRecord extends SubRecord {
}
}
/**
* Set the style of this dropdown.
*
* Possible values:
* <p>
* 0 Combo dropdown control
* 1 Combo Edit dropdown control
* 2 Simple dropdown control (just the dropdown button)
*
*/
public void setStyle(int style){
_wStyle = style;
}
/**
* Set the number of lines to be displayed in the dropdown.
*/
public void setNumLines(int num){
_cLine = num;
}
public void serialize(LittleEndianOutput out) {
out.writeShort(_wStyle);
out.writeShort(_cLine);

View 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,

View 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);
}

View 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:

View File

@ -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;
}
}

View 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);
}

View 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();
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);
_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);
}
}

View 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;

View File

@ -0,0 +1,79 @@
/* ====================================================================
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.ss.usermodel;
/**
* Represents autofiltering for the specified worksheet.
*
* <p>
* Filtering data is a quick and easy way to find and work with a subset of data in a range of cells or table.
* For example, you can filter to see only the values that you specify, filter to see the top or bottom values,
* or filter to quickly see duplicate values.
* </p>
*
* TODO YK: For now (Aug 2010) POI only supports setting a basic autofilter on a range of cells.
* In future, when we support more auto-filter functions like custom criteria, sort, etc. we will add
* corresponding methods to this interface.
*/
public interface AutoFilter {
/**
* Apply a custom filter
*
* <p>
* A custom AutoFilter specifies an operator and a value.
* There can be at most two customFilters specified, and in that case the parent element
* specifies whether the two conditions are joined by 'and' or 'or'. For any cells whose
* values do not meet the specified criteria, the corresponding rows shall be hidden from
* view when the filter is applied.
* </p>
*
* <p>
* Example:
* <blockquote><pre>
* AutoFilter filter = sheet.setAutoFilter(CellRangeAddress.valueOf("A1:F200"));
* filter.applyFilter(0, FilterOperator.GreaterThanOrEqual", "0.2");
* filter.applyFilter(1, FilterOperator.LessThanOrEqual"", "0.5");
* </pre></blockquote>
* </p>
*
* @param columnIndex 0-based column index
* @param operator the operator to apply
* @param criteria top or bottom value used in the filter criteria.
*
* TODO YK: think how to combine AutoFilter with with DataValidationConstraint, they are really close relatives
* void applyFilter(int columnIndex, FilterOperator operator, String criteria);
*/
/**
* Apply a filter against a list of values
*
* <p>
* Example:
* <blockquote><pre>
* AutoFilter filter = sheet.setAutoFilter(CellRangeAddress.valueOf("A1:F200"));
* filter.applyFilter(0, "apache", "poi", "java", "api");
* </pre></blockquote>
* </p>
*
* @param columnIndex 0-based column index
* @param values the filter values
*
* void applyFilter(int columnIndex, String ... values);
*/
}

View 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);
}

View File

@ -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;
}
}

View 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);
}
}

View 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());
}
}

View File

@ -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));
}
}

View File

@ -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));
}
}

View 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
}
}