More code from bug #27511, now ported to the new style record code

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@600519 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2007-12-03 13:17:41 +00:00
parent 02564b5824
commit b97e94bf5c
4 changed files with 603 additions and 13 deletions

View File

@ -0,0 +1,590 @@
/* ====================================================================
Copyright 2002-2004 Apache Software Foundation
Licensed 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.BitField;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.StringUtil;
import org.apache.poi.hssf.util.HSSFCellRangeAddress;
import org.apache.poi.hssf.record.formula.Ptg;
import java.io.IOException;
import java.util.Stack;
import java.util.Hashtable;
import java.util.Enumeration;
/**
* Title: DV Record<P>
* Description: This record stores data validation settings and a list of cell ranges
* which contain these settings. The data validation settings of a sheet
* are stored in a sequential list of DV records. This list is followed by
* DVAL record(s)
* @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
* @version 2.0-pre
*/
public class DVRecord extends Record
{
public final static short sid = 0x01BE;
/**
* Option flags
*/
private int field_option_flags;
/**
* Title of the prompt box
*/
private String field_title_prompt;
/**
* Title of the error box
*/
private String field_title_error;
/**
* Text of the prompt box
*/
private String field_text_prompt;
/**
* Text of the error box
*/
private String field_text_error;
/**
* Size of the formula data for first condition
*/
private short field_size_first_formula;
/**
* Not used
*/
private short field_not_used_1 = 0x3FE0;
/**
* Formula data for first condition (RPN token array without size field)
*/
private Stack field_rpn_token_1 ;
/**
* Size of the formula data for second condition
*/
private short field_size_sec_formula;
/**
* Not used
*/
private short field_not_used_2 = 0x0000;
/**
* Formula data for second condition (RPN token array without size field)
*/
private Stack field_rpn_token_2 ;
/**
* Cell range address list with all affected ranges
*/
private HSSFCellRangeAddress field_regions;
public static final Integer STRING_PROMPT_TITLE = new Integer(0);
public static final Integer STRING_ERROR_TITLE = new Integer(1);
public static final Integer STRING_PROMPT_TEXT = new Integer(2);
public static final Integer STRING_ERROR_TEXT = new Integer(3);
private Hashtable _hash_strings ;
/**
* Option flags field
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
*/
private BitField opt_data_type = new BitField(0x0000000F);
private BitField opt_error_style = new BitField(0x00000070);
private BitField opt_string_list_formula = new BitField(0x00000080);
private BitField opt_empty_cell_allowed = new BitField(0x00000100);
private BitField opt_surppres_dropdown_arrow = new BitField(0x00000200);
private BitField opt_show_prompt_on_cell_selected = new BitField(0x00040000);
private BitField opt_show_error_on_invalid_value = new BitField(0x00080000);
private BitField opt_condition_operator = new BitField(0x00F00000);
public DVRecord()
{
}
/**
* Constructs a DV record and sets its fields appropriately.
*
* @param in the RecordInputstream to read the record from
*/
public DVRecord(RecordInputStream in)
{
super(in);
}
protected void validateSid(short id)
{
if (id != sid)
{
throw new RecordFormatException("NOT a valid DV RECORD");
}
}
protected void fillFields(RecordInputStream in)
{
field_rpn_token_1 = new Stack();
field_rpn_token_2 = new Stack();
this.field_option_flags = in.readInt();
this._hash_strings = new Hashtable(4);
StringHandler strHandler_prompt_title = new StringHandler( in );
this.field_title_prompt = strHandler_prompt_title.getStringData();
this._hash_strings.put(DVRecord.STRING_PROMPT_TITLE, strHandler_prompt_title);
StringHandler strHandler_error_title = new StringHandler( in );
this.field_title_error = strHandler_error_title.getStringData();
this._hash_strings.put(DVRecord.STRING_ERROR_TITLE, strHandler_error_title);
StringHandler strHandler_prompt_text = new StringHandler( in );
this.field_text_prompt = strHandler_prompt_text.getStringData();
this._hash_strings.put(DVRecord.STRING_PROMPT_TEXT, strHandler_prompt_text);
StringHandler strHandler_error_text = new StringHandler( in );
this.field_text_error = strHandler_error_text.getStringData();
this._hash_strings.put(DVRecord.STRING_ERROR_TEXT, strHandler_error_text);
this.field_size_first_formula = in.readShort();
this.field_not_used_1 = in.readShort();
//read first formula data condition
// Not sure if this was needed or not...
// try {
// in.skip(this.field_size_first_formula);
// } catch(IOException e) { throw new IllegalStateException(e); }
int token_pos = 0;
while (token_pos < this.field_size_first_formula)
{
Ptg ptg = Ptg.createPtg(in);
token_pos += ptg.getSize();
field_rpn_token_1.push(ptg);
}
this.field_size_sec_formula = in.readShort();
this.field_not_used_2 = in.readShort();
//read sec formula data condition
// Not sure if this was needed or not...
try {
in.skip(this.field_size_sec_formula);
} catch(IOException e) { throw new IllegalStateException(e); }
token_pos = 0;
while (token_pos < this.field_size_sec_formula)
{
Ptg ptg = Ptg.createPtg(in);
token_pos += ptg.getSize();
field_rpn_token_2.push(ptg);
}
//read cell range address list with all affected ranges
this.field_regions = new HSSFCellRangeAddress(in);
}
// --> start option flags
/**
* set the condition data type
* @param type - condition data type
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
*/
public void setDataType(int type)
{
this.field_option_flags = this.opt_data_type.setValue(this.field_option_flags, type);
}
/**
* get the condition data type
* @return the condition data type
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
*/
public int getDataType()
{
return this.opt_data_type.getValue(this.field_option_flags);
}
/**
* set the condition error style
* @param type - condition error style
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
*/
public void setErrorStyle(int style)
{
this.field_option_flags = this.opt_error_style.setValue(this.field_option_flags, style);
}
/**
* get the condition error style
* @return the condition error style
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
*/
public int getErrorStyle()
{
return this.opt_error_style.getValue(this.field_option_flags);
}
/**
* set if in list validations the string list is explicitly given in the formula
* @param type - true if in list validations the string list is explicitly given in the formula; false otherwise
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
*/
public void setListExplicitFormula(boolean explicit)
{
this.field_option_flags = this.opt_string_list_formula.setBoolean(this.field_option_flags, explicit);
}
/**
* return true if in list validations the string list is explicitly given in the formula, false otherwise
* @return true if in list validations the string list is explicitly given in the formula, false otherwise
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
*/
public boolean getListExplicitFormula()
{
return (this.opt_string_list_formula.isSet(this.field_option_flags));
}
/**
* set if empty values are allowed in cells
* @param type - true if empty values are allowed in cells, false otherwise
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
*/
public void setEmptyCellAllowed(boolean allowed)
{
this.field_option_flags = this.opt_empty_cell_allowed.setBoolean(this.field_option_flags, allowed);
}
/**
* return true if empty values are allowed in cells, false otherwise
* @return if empty values are allowed in cells, false otherwise
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
*/
public boolean getEmptyCellAllowed()
{
return (this.opt_empty_cell_allowed.isSet(this.field_option_flags));
}
/**
* set if drop down arrow should be surppressed when list validation is used
* @param type - true if drop down arrow should be surppressed when list validation is used, false otherwise
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
*/
public void setSurppresDropdownArrow(boolean surppress)
{
this.field_option_flags = this.opt_surppres_dropdown_arrow.setBoolean(this.field_option_flags, surppress);
}
/**
* return true if drop down arrow should be surppressed when list validation is used, false otherwise
* @return if drop down arrow should be surppressed when list validation is used, false otherwise
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
*/
public boolean getSurppresDropdownArrow()
{
return (this.opt_surppres_dropdown_arrow.isSet(this.field_option_flags));
}
/**
* set if a prompt window should appear when cell is selected
* @param type - true if a prompt window should appear when cell is selected, false otherwise
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
*/
public void setShowPromptOnCellSelected(boolean show)
{
this.field_option_flags = this.opt_show_prompt_on_cell_selected.setBoolean(this.field_option_flags, show);
}
/**
* return true if a prompt window should appear when cell is selected, false otherwise
* @return if a prompt window should appear when cell is selected, false otherwise
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
*/
public boolean getShowPromptOnCellSelected()
{
return (this.opt_show_prompt_on_cell_selected.isSet(this.field_option_flags));
}
/**
* set if an error window should appear when an invalid value is entered in the cell
* @param type - true if an error window should appear when an invalid value is entered in the cell, false otherwise
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
*/
public void setShowErrorOnInvalidValue(boolean show)
{
this.field_option_flags = this.opt_show_error_on_invalid_value.setBoolean(this.field_option_flags, show);
}
/**
* return true if an error window should appear when an invalid value is entered in the cell, false otherwise
* @return if an error window should appear when an invalid value is entered in the cell, false otherwise
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
*/
public boolean getShowErrorOnInvalidValue()
{
return (this.opt_show_error_on_invalid_value.isSet(this.field_option_flags));
}
/**
* set the condition operator
* @param type - condition operator
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
*/
public void setConditionOperator(int operator)
{
this.field_option_flags = this.opt_condition_operator.setValue(this.field_option_flags, operator);
}
/**
* get the condition operator
* @return the condition operator
* @see org.apache.poi.hssf.util.HSSFDataValidation utility class
*/
public int getConditionOperator()
{
return this.opt_condition_operator.getValue(this.field_option_flags);
}
// <-- end option flags
public void setFirstFormulaRPN( Stack rpn )
{
this.field_rpn_token_1 = rpn;
}
public void setFirstFormulaSize( short size )
{
this.field_size_first_formula = size;
}
public void setSecFormulaRPN( Stack rpn )
{
this.field_rpn_token_2 = rpn;
}
public void setSecFormulaSize( short size )
{
this.field_size_sec_formula = size;
}
public void setStringField( Integer type, String str_data )
{
if ( this._hash_strings == null )
{
this._hash_strings = new Hashtable();
}
StringHandler strHandler = new StringHandler();
if ( str_data == null )
{
str_data = "";
}
else
{
strHandler.setStringLength(str_data.length());
}
strHandler.setStringData(str_data);
strHandler.setUnicodeFlag((byte)0x00);
this._hash_strings.put( type, strHandler);
}
public String getStringField( Integer type )
{
return ((StringHandler)this._hash_strings.get(type)).getStringData();
}
public void setCellRangeAddress( HSSFCellRangeAddress range )
{
this.field_regions = range;
}
public HSSFCellRangeAddress getCellRangeAddress( )
{
return this.field_regions;
}
/**
* gets the option flags field.
* @return options - the option flags field
*/
public int getOptionFlags()
{
return this.field_option_flags;
}
public String toString()
{
/** @todo DVRecord string representation */
StringBuffer buffer = new StringBuffer();
return buffer.toString();
}
public int serialize(int offset, byte [] data)
{
int size = this.getRecordSize();
LittleEndian.putShort(data, 0 + offset, sid);
LittleEndian.putShort(data, 2 + offset, ( short ) (size-4));
int pos = 4;
LittleEndian.putInt(data, pos + offset, this.getOptionFlags());
pos += 4;
pos += ((StringHandler)this._hash_strings.get( DVRecord.STRING_PROMPT_TITLE )).serialize(pos+offset, data);
pos += ((StringHandler)this._hash_strings.get( DVRecord.STRING_ERROR_TITLE )).serialize(pos+offset, data);
pos += ((StringHandler)this._hash_strings.get( DVRecord.STRING_PROMPT_TEXT )).serialize(pos+offset, data);
pos += ((StringHandler)this._hash_strings.get( DVRecord.STRING_ERROR_TEXT )).serialize(pos+offset, data);
LittleEndian.putShort(data, offset+pos, this.field_size_first_formula);
pos += 2;
LittleEndian.putShort(data, offset+pos, this.field_not_used_1);
pos += 2;
for (int k = 0; k < this.field_rpn_token_1.size(); k++)
{
Ptg ptg = ( Ptg ) this.field_rpn_token_1.get(k);
ptg.writeBytes(data, pos+offset);
pos += ptg.getSize();
}
LittleEndian.putShort(data, offset+pos, this.field_size_sec_formula);
pos += 2;
LittleEndian.putShort(data, offset+pos, this.field_not_used_2);
pos += 2;
if ( this.field_size_sec_formula > 0 )
{
for (int k = 0; k < this.field_rpn_token_2.size(); k++)
{
Ptg ptg = ( Ptg ) this.field_rpn_token_2.get(k);
ptg.writeBytes(data, pos+offset);
pos += ptg.getSize();
}
}
this.field_regions.serialize(pos+offset, data);
return size;
}
public int getRecordSize()
{
int size = 4+4+2+2+2+2;//header+options_field+first_formula_size+first_unused+sec_formula_size+sec+unused;
if ( this._hash_strings != null )
{
Enumeration enum_keys = this._hash_strings.keys();
while ( enum_keys.hasMoreElements() )
{
size += ((StringHandler)this._hash_strings.get( (Integer)enum_keys.nextElement() )).getSize();
}
}
size += this.field_size_first_formula+ this.field_size_sec_formula;
size += this.field_regions.getSize();
return size;
}
public short getSid()
{
return this.sid;
}
/**@todo DVRecord = Serializare */
private class StringHandler
{
private int _string_length = 0x0001;
private byte _string_unicode_flag = 0x00;
private String _string_data = "0x00";
private int _start_offset;
private int _end_offset;
StringHandler()
{
}
StringHandler(RecordInputStream in)
{
this.fillFields(in);
}
protected void fillFields(RecordInputStream in)
{
this._string_length = in.readUShort();
this._string_unicode_flag = in.readByte();
if (this._string_unicode_flag == 1)
{
this._string_data = in.readUnicodeLEString(this._string_length);
}
else
{
this._string_data = in.readCompressedUnicode(this._string_length);
}
}
private void setStringData( String string_data )
{
this._string_data = string_data;
}
private String getStringData()
{
return this._string_data;
}
private int getEndOffset()
{
return this._end_offset;
}
public int serialize( int offset, byte[] data )
{
LittleEndian.putUShort(data, offset, this._string_length );
data[2 + offset] = this._string_unicode_flag;
if (this._string_unicode_flag == 1)
{
StringUtil.putUnicodeLE(this._string_data, data, 3 + offset);
}
else
{
StringUtil.putCompressedUnicode(this._string_data, data, 3 + offset);
}
return getSize();
}
private void setUnicodeFlag( byte flag )
{
this._string_unicode_flag = flag;
}
private void setStringLength( int len )
{
this._string_length = len;
}
private int getStringByteLength()
{
return (this._string_unicode_flag == 1) ? this._string_length * 2 : this._string_length;
}
public int getSize()
{
return 2 + 1 + getStringByteLength();
}
}
}

View File

@ -75,7 +75,8 @@ public class RecordFactory
HorizontalPageBreakRecord.class, VerticalPageBreakRecord.class, HorizontalPageBreakRecord.class, VerticalPageBreakRecord.class,
WriteProtectRecord.class, FilePassRecord.class, PaneRecord.class, WriteProtectRecord.class, FilePassRecord.class, PaneRecord.class,
NoteRecord.class, ObjectProtectRecord.class, ScenarioProtectRecord.class, NoteRecord.class, ObjectProtectRecord.class, ScenarioProtectRecord.class,
FileSharingRecord.class, ChartTitleFormatRecord.class FileSharingRecord.class, ChartTitleFormatRecord.class,
DVRecord.class, DVALRecord.class
}; };
} }
private static Map recordsMap = recordsToMap(records); private static Map recordsMap = recordsToMap(records);

View File

@ -16,6 +16,7 @@
package org.apache.poi.hssf.util; package org.apache.poi.hssf.util;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
import java.util.ArrayList; import java.util.ArrayList;
@ -56,29 +57,27 @@ public class HSSFCellRangeAddress
* Construct a new HSSFCellRangeAddress object and sets its fields appropriately . * Construct a new HSSFCellRangeAddress object and sets its fields appropriately .
* Even this isn't an Excel record , I kept the same behavior for reading/writing * Even this isn't an Excel record , I kept the same behavior for reading/writing
* the object's data as for a regular record . * the object's data as for a regular record .
* @param data Excel's file stream data *
* @param offset the offset in Excel's file data * @param in the RecordInputstream to read the record from
*/ */
public HSSFCellRangeAddress( byte [] data, int offset ) public HSSFCellRangeAddress(RecordInputStream in)
{ {
this.fillFields(data, offset); this.fillFields(in);
} }
public void fillFields(byte [] data, int offset) public void fillFields(RecordInputStream in)
{ {
this.field_addr_number = LittleEndian.getShort(data, 0 + offset); this.field_addr_number = in.readShort();
this.field_regions_list = new ArrayList(this.field_addr_number); this.field_regions_list = new ArrayList(this.field_addr_number);
int pos = 2;
for (int k = 0; k < this.field_addr_number; k++) for (int k = 0; k < this.field_addr_number; k++)
{ {
short first_row = LittleEndian.getShort(data, pos + offset); short first_row = in.readShort();
short first_col = LittleEndian.getShort(data, pos + 2 + offset); short first_col = in.readShort();
short last_row = LittleEndian.getShort(data, pos + 4 + offset); short last_row = in.readShort();
short last_col = LittleEndian.getShort(data, pos + 6 + offset); short last_col = in.readShort();
AddrStructure region = new AddrStructure(first_row, first_col, last_row, last_col); AddrStructure region = new AddrStructure(first_row, first_col, last_row, last_col);
pos += 8;
this.field_regions_list.add(region); this.field_regions_list.add(region);
} }
} }