git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@983382 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_7_BETA3
@@ -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> |
@@ -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> |
@@ -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); |
@@ -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"); | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); |
@@ -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, |
@@ -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); | |||
} |
@@ -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: |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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; | |||
@@ -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); | |||
*/ | |||
} |
@@ -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); | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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()); | |||
} | |||
} |
@@ -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)); | |||
} | |||
} |
@@ -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)); | |||
} | |||
} |
@@ -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 | |||
} | |||
} |