2017-02-08 02:47:30 -05:00
|
|
|
/* ====================================================================
|
|
|
|
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.ss.formula.ptg.Ptg;
|
|
|
|
import org.apache.poi.util.HexDump;
|
|
|
|
import org.apache.poi.util.LittleEndianInput;
|
|
|
|
import org.apache.poi.util.LittleEndianOutput;
|
|
|
|
import org.apache.poi.util.StringUtil;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This structure specifies the properties of a list or drop-down list embedded object in a sheet.
|
|
|
|
*/
|
|
|
|
public class LbsDataSubRecord extends SubRecord {
|
|
|
|
|
|
|
|
public static final int sid = 0x0013;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* From [MS-XLS].pdf 2.5.147 FtLbsData:
|
|
|
|
*
|
|
|
|
* An unsigned integer that indirectly specifies whether
|
|
|
|
* some of the data in this structure appear in a subsequent Continue record.
|
|
|
|
* If _cbFContinued is 0x00, all of the fields in this structure except sid and _cbFContinued
|
|
|
|
* MUST NOT exist. If this entire structure is contained within the same record,
|
|
|
|
* then _cbFContinued MUST be greater than or equal to the size, in bytes,
|
|
|
|
* of this structure, not including the four bytes for the ft and _cbFContinued fields
|
|
|
|
*/
|
|
|
|
private int _cbFContinued;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* a formula that specifies the range of cell values that are the items in this list.
|
|
|
|
*/
|
|
|
|
private int _unknownPreFormulaInt;
|
|
|
|
private Ptg _linkPtg;
|
|
|
|
private Byte _unknownPostFormulaByte;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An unsigned integer that specifies the number of items in the list.
|
|
|
|
*/
|
|
|
|
private int _cLines;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An unsigned integer that specifies the one-based index of the first selected item in this list.
|
|
|
|
* A value of 0x00 specifies there is no currently selected item.
|
|
|
|
*/
|
|
|
|
private int _iSel;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* flags that tell what data follows
|
|
|
|
*/
|
|
|
|
private int _flags;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An ObjId that specifies the edit box associated with this list.
|
|
|
|
* A value of 0x00 specifies that there is no edit box associated with this list.
|
|
|
|
*/
|
|
|
|
private int _idEdit;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An optional LbsDropData that specifies properties for this dropdown control.
|
|
|
|
* This field MUST exist if and only if the containing Obj?s cmo.ot is equal to 0x14.
|
|
|
|
*/
|
|
|
|
private LbsDropData _dropData;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An optional array of strings where each string specifies an item in the list.
|
|
|
|
* The number of elements in this array, if it exists, MUST be {@link #_cLines}
|
|
|
|
*/
|
|
|
|
private String[] _rgLines;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An optional array of booleans that specifies
|
|
|
|
* which items in the list are part of a multiple selection
|
|
|
|
*/
|
|
|
|
private boolean[] _bsels;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param in the stream to read data from
|
|
|
|
* @param cbFContinued the seconf short in the record header
|
|
|
|
* @param cmoOt the containing Obj's {@link CommonObjectDataSubRecord#field_1_objectType}
|
|
|
|
*/
|
|
|
|
public LbsDataSubRecord(LittleEndianInput in, int cbFContinued, int cmoOt) {
|
|
|
|
_cbFContinued = cbFContinued;
|
|
|
|
|
|
|
|
int encodedTokenLen = in.readUShort();
|
|
|
|
if (encodedTokenLen > 0) {
|
|
|
|
int formulaSize = in.readUShort();
|
|
|
|
_unknownPreFormulaInt = in.readInt();
|
|
|
|
|
|
|
|
Ptg[] ptgs = Ptg.readTokens(formulaSize, in);
|
|
|
|
if (ptgs.length != 1) {
|
|
|
|
throw new RecordFormatException("Read " + ptgs.length
|
|
|
|
+ " tokens but expected exactly 1");
|
|
|
|
}
|
|
|
|
_linkPtg = ptgs[0];
|
|
|
|
switch (encodedTokenLen - formulaSize - 6) {
|
|
|
|
case 1:
|
|
|
|
_unknownPostFormulaByte = in.readByte();
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
_unknownPostFormulaByte = null;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new RecordFormatException("Unexpected leftover bytes");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_cLines = in.readUShort();
|
|
|
|
_iSel = in.readUShort();
|
|
|
|
_flags = in.readUShort();
|
|
|
|
_idEdit = in.readUShort();
|
|
|
|
|
|
|
|
// From [MS-XLS].pdf 2.5.147 FtLbsData:
|
|
|
|
// This field MUST exist if and only if the containing Obj?s cmo.ot is equal to 0x14.
|
|
|
|
if(cmoOt == 0x14) {
|
|
|
|
_dropData = new LbsDropData(in);
|
|
|
|
}
|
|
|
|
|
|
|
|
// From [MS-XLS].pdf 2.5.147 FtLbsData:
|
|
|
|
// This array MUST exist if and only if the fValidPlex flag (0x2) is set
|
|
|
|
if((_flags & 0x2) != 0) {
|
|
|
|
_rgLines = new String[_cLines];
|
|
|
|
for(int i=0; i < _cLines; i++) {
|
|
|
|
_rgLines[i] = StringUtil.readUnicodeString(in);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// bits 5-6 in the _flags specify the type
|
|
|
|
// of selection behavior this list control is expected to support
|
|
|
|
|
|
|
|
// From [MS-XLS].pdf 2.5.147 FtLbsData:
|
|
|
|
// This array MUST exist if and only if the wListType field is not equal to 0.
|
|
|
|
if(((_flags >> 4) & 0x2) != 0) {
|
|
|
|
_bsels = new boolean[_cLines];
|
|
|
|
for(int i=0; i < _cLines; i++) {
|
|
|
|
_bsels[i] = in.readByte() == 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
LbsDataSubRecord(){
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @return a new instance of LbsDataSubRecord to construct auto-filters
|
|
|
|
* @see org.apache.poi.hssf.usermodel.HSSFCombobox
|
|
|
|
*/
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
@Override
|
|
|
|
public boolean isTerminating(){
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected int getDataSize() {
|
|
|
|
int result = 2; // 2 initial shorts
|
|
|
|
|
|
|
|
// optional link formula
|
|
|
|
if (_linkPtg != null) {
|
|
|
|
result += 2; // encoded Ptg size
|
|
|
|
result += 4; // unknown int
|
|
|
|
result += _linkPtg.getSize();
|
|
|
|
if (_unknownPostFormulaByte != null) {
|
|
|
|
result += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result += 4 * 2; // 4 shorts
|
|
|
|
if(_dropData != null) {
|
|
|
|
result += _dropData.getDataSize();
|
|
|
|
}
|
|
|
|
if(_rgLines != null) {
|
|
|
|
for(String str : _rgLines){
|
|
|
|
result += StringUtil.getEncodedSize(str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(_bsels != null) {
|
|
|
|
result += _bsels.length;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void serialize(LittleEndianOutput out) {
|
|
|
|
out.writeShort(sid);
|
|
|
|
out.writeShort(_cbFContinued);
|
|
|
|
|
|
|
|
if (_linkPtg == null) {
|
|
|
|
out.writeShort(0);
|
|
|
|
} else {
|
|
|
|
int formulaSize = _linkPtg.getSize();
|
|
|
|
int linkSize = formulaSize + 6;
|
|
|
|
if (_unknownPostFormulaByte != null) {
|
|
|
|
linkSize++;
|
|
|
|
}
|
|
|
|
out.writeShort(linkSize);
|
|
|
|
out.writeShort(formulaSize);
|
|
|
|
out.writeInt(_unknownPreFormulaInt);
|
|
|
|
_linkPtg.write(out);
|
|
|
|
if (_unknownPostFormulaByte != null) {
|
|
|
|
out.writeByte(_unknownPostFormulaByte.intValue());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out.writeShort(_cLines);
|
|
|
|
out.writeShort(_iSel);
|
|
|
|
out.writeShort(_flags);
|
|
|
|
out.writeShort(_idEdit);
|
|
|
|
|
|
|
|
if(_dropData != null) {
|
|
|
|
_dropData.serialize(out);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(_rgLines != null) {
|
|
|
|
for(String str : _rgLines){
|
|
|
|
StringUtil.writeUnicodeString(out, str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(_bsels != null) {
|
|
|
|
for(boolean val : _bsels){
|
|
|
|
out.writeByte(val ? 1 : 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public LbsDataSubRecord clone() {
|
|
|
|
// TODO: is immutable ???
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
StringBuffer sb = new StringBuffer(256);
|
|
|
|
|
|
|
|
sb.append("[ftLbsData]\n");
|
|
|
|
sb.append(" .unknownShort1 =").append(HexDump.shortToHex(_cbFContinued)).append("\n");
|
|
|
|
sb.append(" .formula = ").append('\n');
|
|
|
|
if(_linkPtg != null) {
|
|
|
|
sb.append(_linkPtg.toString()).append(_linkPtg.getRVAType()).append('\n');
|
|
|
|
}
|
|
|
|
sb.append(" .nEntryCount =").append(HexDump.shortToHex(_cLines)).append("\n");
|
|
|
|
sb.append(" .selEntryIx =").append(HexDump.shortToHex(_iSel)).append("\n");
|
|
|
|
sb.append(" .style =").append(HexDump.shortToHex(_flags)).append("\n");
|
|
|
|
sb.append(" .unknownShort10=").append(HexDump.shortToHex(_idEdit)).append("\n");
|
|
|
|
if(_dropData != null) {
|
|
|
|
sb.append('\n').append(_dropData.toString());
|
|
|
|
}
|
|
|
|
sb.append("[/ftLbsData]\n");
|
|
|
|
return sb.toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @return the formula that specifies the range of cell values that are the items in this list.
|
|
|
|
*/
|
|
|
|
public Ptg getFormula(){
|
|
|
|
return _linkPtg;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the number of items in the list
|
|
|
|
*/
|
|
|
|
public int getNumberOfItems(){
|
|
|
|
return _cLines;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This structure specifies properties of the dropdown list control
|
|
|
|
*/
|
|
|
|
public static class LbsDropData {
|
|
|
|
/**
|
|
|
|
* Combo dropdown control
|
|
|
|
*/
|
|
|
|
public static final int STYLE_COMBO_DROPDOWN = 0;
|
|
|
|
/**
|
|
|
|
* Combo Edit dropdown control
|
|
|
|
*/
|
|
|
|
public static final int STYLE_COMBO_EDIT_DROPDOWN = 1;
|
|
|
|
/**
|
|
|
|
* Simple dropdown control (just the dropdown button)
|
|
|
|
*/
|
|
|
|
public static final int STYLE_COMBO_SIMPLE_DROPDOWN = 2;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An unsigned integer that specifies the style of this dropdown.
|
|
|
|
*/
|
|
|
|
private int _wStyle;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An unsigned integer that specifies the number of lines to be displayed in the dropdown.
|
|
|
|
*/
|
|
|
|
private int _cLine;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An unsigned integer that specifies the smallest width in pixels allowed for the dropdown window
|
|
|
|
*/
|
|
|
|
private int _dxMin;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* a string that specifies the current string value in the dropdown
|
|
|
|
*/
|
|
|
|
private final String _str;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Optional, undefined and MUST be ignored.
|
|
|
|
* This field MUST exist if and only if the size of str in bytes is an odd number
|
|
|
|
*/
|
|
|
|
private Byte _unused;
|
|
|
|
|
|
|
|
public LbsDropData(){
|
|
|
|
_str = "";
|
|
|
|
_unused = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
public LbsDropData(LittleEndianInput in){
|
|
|
|
_wStyle = in.readUShort();
|
|
|
|
_cLine = in.readUShort();
|
|
|
|
_dxMin = in.readUShort();
|
|
|
|
_str = StringUtil.readUnicodeString(in);
|
|
|
|
if(StringUtil.getEncodedSize(_str) % 2 != 0){
|
|
|
|
_unused = in.readByte();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the style of this dropdown.<p>
|
|
|
|
*
|
|
|
|
* Possible values:
|
|
|
|
* <ul>
|
|
|
|
* <li>0: Combo dropdown control</li>
|
|
|
|
* <li>1: Combo Edit dropdown control</li>
|
|
|
|
* <li>2: Simple dropdown control (just the dropdown button)</li>
|
|
|
|
* </ul>
|
|
|
|
*
|
|
|
|
* @param style the style - see possible values
|
|
|
|
*/
|
|
|
|
public void setStyle(int style){
|
|
|
|
_wStyle = style;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the number of lines to be displayed in the dropdown.
|
|
|
|
*
|
|
|
|
* @param num 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);
|
|
|
|
out.writeShort(_dxMin);
|
|
|
|
StringUtil.writeUnicodeString(out, _str);
|
|
|
|
if(_unused != null) {
|
|
|
|
out.writeByte(_unused);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getDataSize() {
|
|
|
|
int size = 6;
|
|
|
|
size += StringUtil.getEncodedSize(_str);
|
|
|
|
if(_unused != null) {
|
|
|
|
size++;
|
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString(){
|
|
|
|
StringBuffer sb = new StringBuffer();
|
|
|
|
sb.append("[LbsDropData]\n");
|
|
|
|
sb.append(" ._wStyle: ").append(_wStyle).append('\n');
|
|
|
|
sb.append(" ._cLine: ").append(_cLine).append('\n');
|
|
|
|
sb.append(" ._dxMin: ").append(_dxMin).append('\n');
|
|
|
|
sb.append(" ._str: ").append(_str).append('\n');
|
|
|
|
if(_unused != null) {
|
|
|
|
sb.append(" ._unused: ").append(_unused).append('\n');
|
|
|
|
}
|
|
|
|
sb.append("[/LbsDropData]\n");
|
|
|
|
|
|
|
|
return sb.toString();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|