001: /* ====================================================================
002: Copyright 2002-2004 Apache Software Foundation
003:
004: Licensed under the Apache License, Version 2.0 (the "License");
005: you may not use this file except in compliance with the License.
006: You may obtain a copy of the License at
007:
008: http://www.apache.org/licenses/LICENSE-2.0
009:
010: Unless required by applicable law or agreed to in writing, software
011: distributed under the License is distributed on an "AS IS" BASIS,
012: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: See the License for the specific language governing permissions and
014: limitations under the License.
015: ==================================================================== */
016:
017: package org.apache.poi.hssf.record;
018:
019: import org.apache.poi.util.BitField;
020: import org.apache.poi.util.LittleEndian;
021: import org.apache.poi.util.StringUtil;
022: import org.apache.poi.hssf.util.HSSFCellRangeAddress;
023: import org.apache.poi.hssf.record.formula.Ptg;
024:
025: import java.io.IOException;
026: import java.util.Stack;
027: import java.util.Hashtable;
028: import java.util.Enumeration;
029:
030: /**
031: * Title: DV Record<P>
032: * Description: This record stores data validation settings and a list of cell ranges
033: * which contain these settings. The data validation settings of a sheet
034: * are stored in a sequential list of DV records. This list is followed by
035: * DVAL record(s)
036: * @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
037: * @version 2.0-pre
038: */
039: public class DVRecord extends Record {
040: public final static short sid = 0x01BE;
041:
042: /**
043: * Option flags
044: */
045: private int field_option_flags;
046:
047: /**
048: * Title of the prompt box
049: */
050: private String field_title_prompt;
051:
052: /**
053: * Title of the error box
054: */
055: private String field_title_error;
056:
057: /**
058: * Text of the prompt box
059: */
060: private String field_text_prompt;
061:
062: /**
063: * Text of the error box
064: */
065: private String field_text_error;
066:
067: /**
068: * Size of the formula data for first condition
069: */
070: private short field_size_first_formula;
071:
072: /**
073: * Not used
074: */
075: private short field_not_used_1 = 0x3FE0;
076:
077: /**
078: * Formula data for first condition (RPN token array without size field)
079: */
080: private Stack field_rpn_token_1;
081:
082: /**
083: * Size of the formula data for second condition
084: */
085: private short field_size_sec_formula;
086:
087: /**
088: * Not used
089: */
090: private short field_not_used_2 = 0x0000;
091:
092: /**
093: * Formula data for second condition (RPN token array without size field)
094: */
095: private Stack field_rpn_token_2;
096:
097: /**
098: * Cell range address list with all affected ranges
099: */
100: private HSSFCellRangeAddress field_regions;
101:
102: public static final Integer STRING_PROMPT_TITLE = new Integer(0);
103: public static final Integer STRING_ERROR_TITLE = new Integer(1);
104: public static final Integer STRING_PROMPT_TEXT = new Integer(2);
105: public static final Integer STRING_ERROR_TEXT = new Integer(3);
106: private Hashtable _hash_strings;
107:
108: /**
109: * Option flags field
110: * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
111: */
112: private BitField opt_data_type = new BitField(0x0000000F);
113: private BitField opt_error_style = new BitField(0x00000070);
114: private BitField opt_string_list_formula = new BitField(0x00000080);
115: private BitField opt_empty_cell_allowed = new BitField(0x00000100);
116: private BitField opt_surppres_dropdown_arrow = new BitField(
117: 0x00000200);
118: private BitField opt_show_prompt_on_cell_selected = new BitField(
119: 0x00040000);
120: private BitField opt_show_error_on_invalid_value = new BitField(
121: 0x00080000);
122: private BitField opt_condition_operator = new BitField(0x00F00000);
123:
124: public DVRecord() {
125: }
126:
127: /**
128: * Constructs a DV record and sets its fields appropriately.
129: *
130: * @param in the RecordInputstream to read the record from
131: */
132:
133: public DVRecord(RecordInputStream in) {
134: super (in);
135: }
136:
137: protected void validateSid(short id) {
138: if (id != sid) {
139: throw new RecordFormatException("NOT a valid DV RECORD");
140: }
141: }
142:
143: protected void fillFields(RecordInputStream in) {
144: field_rpn_token_1 = new Stack();
145: field_rpn_token_2 = new Stack();
146:
147: this .field_option_flags = in.readInt();
148: this ._hash_strings = new Hashtable(4);
149:
150: StringHandler strHandler_prompt_title = new StringHandler(in);
151: this .field_title_prompt = strHandler_prompt_title
152: .getStringData();
153: this ._hash_strings.put(DVRecord.STRING_PROMPT_TITLE,
154: strHandler_prompt_title);
155:
156: StringHandler strHandler_error_title = new StringHandler(in);
157: this .field_title_error = strHandler_error_title.getStringData();
158: this ._hash_strings.put(DVRecord.STRING_ERROR_TITLE,
159: strHandler_error_title);
160:
161: StringHandler strHandler_prompt_text = new StringHandler(in);
162: this .field_text_prompt = strHandler_prompt_text.getStringData();
163: this ._hash_strings.put(DVRecord.STRING_PROMPT_TEXT,
164: strHandler_prompt_text);
165:
166: StringHandler strHandler_error_text = new StringHandler(in);
167: this .field_text_error = strHandler_error_text.getStringData();
168: this ._hash_strings.put(DVRecord.STRING_ERROR_TEXT,
169: strHandler_error_text);
170:
171: this .field_size_first_formula = in.readShort();
172: this .field_not_used_1 = in.readShort();
173:
174: //read first formula data condition
175: // Not sure if this was needed or not...
176: // try {
177: // in.skip(this.field_size_first_formula);
178: // } catch(IOException e) { throw new IllegalStateException(e); }
179:
180: int token_pos = 0;
181: while (token_pos < this .field_size_first_formula) {
182: Ptg ptg = Ptg.createPtg(in);
183: token_pos += ptg.getSize();
184: field_rpn_token_1.push(ptg);
185: }
186:
187: this .field_size_sec_formula = in.readShort();
188: this .field_not_used_2 = in.readShort();
189:
190: //read sec formula data condition
191: // Not sure if this was needed or not...
192: try {
193: in.skip(this .field_size_sec_formula);
194: } catch (IOException e) {
195: throw new IllegalStateException(e);
196: }
197:
198: token_pos = 0;
199: while (token_pos < this .field_size_sec_formula) {
200: Ptg ptg = Ptg.createPtg(in);
201: token_pos += ptg.getSize();
202: field_rpn_token_2.push(ptg);
203: }
204:
205: //read cell range address list with all affected ranges
206: this .field_regions = new HSSFCellRangeAddress(in);
207: }
208:
209: // --> start option flags
210: /**
211: * set the condition data type
212: * @param type - condition data type
213: * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
214: */
215: public void setDataType(int type) {
216: this .field_option_flags = this .opt_data_type.setValue(
217: this .field_option_flags, type);
218: }
219:
220: /**
221: * get the condition data type
222: * @return the condition data type
223: * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
224: */
225: public int getDataType() {
226: return this .opt_data_type.getValue(this .field_option_flags);
227: }
228:
229: /**
230: * set the condition error style
231: * @param type - condition error style
232: * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
233: */
234: public void setErrorStyle(int style) {
235: this .field_option_flags = this .opt_error_style.setValue(
236: this .field_option_flags, style);
237: }
238:
239: /**
240: * get the condition error style
241: * @return the condition error style
242: * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
243: */
244: public int getErrorStyle() {
245: return this .opt_error_style.getValue(this .field_option_flags);
246: }
247:
248: /**
249: * set if in list validations the string list is explicitly given in the formula
250: * @param type - true if in list validations the string list is explicitly given in the formula; false otherwise
251: * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
252: */
253: public void setListExplicitFormula(boolean explicit) {
254: this .field_option_flags = this .opt_string_list_formula
255: .setBoolean(this .field_option_flags, explicit);
256: }
257:
258: /**
259: * return true if in list validations the string list is explicitly given in the formula, false otherwise
260: * @return true if in list validations the string list is explicitly given in the formula, false otherwise
261: * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
262: */
263: public boolean getListExplicitFormula() {
264: return (this .opt_string_list_formula
265: .isSet(this .field_option_flags));
266: }
267:
268: /**
269: * set if empty values are allowed in cells
270: * @param type - true if empty values are allowed in cells, false otherwise
271: * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
272: */
273: public void setEmptyCellAllowed(boolean allowed) {
274: this .field_option_flags = this .opt_empty_cell_allowed
275: .setBoolean(this .field_option_flags, allowed);
276: }
277:
278: /**
279: * return true if empty values are allowed in cells, false otherwise
280: * @return if empty values are allowed in cells, false otherwise
281: * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
282: */
283: public boolean getEmptyCellAllowed() {
284: return (this .opt_empty_cell_allowed
285: .isSet(this .field_option_flags));
286: }
287:
288: /**
289: * set if drop down arrow should be surppressed when list validation is used
290: * @param type - true if drop down arrow should be surppressed when list validation is used, false otherwise
291: * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
292: */
293: public void setSurppresDropdownArrow(boolean surppress) {
294: this .field_option_flags = this .opt_surppres_dropdown_arrow
295: .setBoolean(this .field_option_flags, surppress);
296: }
297:
298: /**
299: * return true if drop down arrow should be surppressed when list validation is used, false otherwise
300: * @return if drop down arrow should be surppressed when list validation is used, false otherwise
301: * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
302: */
303: public boolean getSurppresDropdownArrow() {
304: return (this .opt_surppres_dropdown_arrow
305: .isSet(this .field_option_flags));
306: }
307:
308: /**
309: * set if a prompt window should appear when cell is selected
310: * @param type - true if a prompt window should appear when cell is selected, false otherwise
311: * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
312: */
313: public void setShowPromptOnCellSelected(boolean show) {
314: this .field_option_flags = this .opt_show_prompt_on_cell_selected
315: .setBoolean(this .field_option_flags, show);
316: }
317:
318: /**
319: * return true if a prompt window should appear when cell is selected, false otherwise
320: * @return if a prompt window should appear when cell is selected, false otherwise
321: * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
322: */
323: public boolean getShowPromptOnCellSelected() {
324: return (this .opt_show_prompt_on_cell_selected
325: .isSet(this .field_option_flags));
326: }
327:
328: /**
329: * set if an error window should appear when an invalid value is entered in the cell
330: * @param type - true if an error window should appear when an invalid value is entered in the cell, false otherwise
331: * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
332: */
333: public void setShowErrorOnInvalidValue(boolean show) {
334: this .field_option_flags = this .opt_show_error_on_invalid_value
335: .setBoolean(this .field_option_flags, show);
336: }
337:
338: /**
339: * return true if an error window should appear when an invalid value is entered in the cell, false otherwise
340: * @return if an error window should appear when an invalid value is entered in the cell, false otherwise
341: * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
342: */
343: public boolean getShowErrorOnInvalidValue() {
344: return (this .opt_show_error_on_invalid_value
345: .isSet(this .field_option_flags));
346: }
347:
348: /**
349: * set the condition operator
350: * @param type - condition operator
351: * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
352: */
353: public void setConditionOperator(int operator) {
354: this .field_option_flags = this .opt_condition_operator.setValue(
355: this .field_option_flags, operator);
356: }
357:
358: /**
359: * get the condition operator
360: * @return the condition operator
361: * @see org.apache.poi.hssf.util.HSSFDataValidation utility class
362: */
363: public int getConditionOperator() {
364: return this .opt_condition_operator
365: .getValue(this .field_option_flags);
366: }
367:
368: // <-- end option flags
369:
370: public void setFirstFormulaRPN(Stack rpn) {
371: this .field_rpn_token_1 = rpn;
372: }
373:
374: public void setFirstFormulaSize(short size) {
375: this .field_size_first_formula = size;
376: }
377:
378: public void setSecFormulaRPN(Stack rpn) {
379: this .field_rpn_token_2 = rpn;
380: }
381:
382: public void setSecFormulaSize(short size) {
383: this .field_size_sec_formula = size;
384: }
385:
386: public void setStringField(Integer type, String str_data) {
387: if (this ._hash_strings == null) {
388: this ._hash_strings = new Hashtable();
389: }
390: StringHandler strHandler = new StringHandler();
391: if (str_data == null) {
392: str_data = "";
393: } else {
394: strHandler.setStringLength(str_data.length());
395: }
396: strHandler.setStringData(str_data);
397:
398: strHandler.setUnicodeFlag((byte) 0x00);
399: this ._hash_strings.put(type, strHandler);
400: }
401:
402: public String getStringField(Integer type) {
403: return ((StringHandler) this ._hash_strings.get(type))
404: .getStringData();
405: }
406:
407: public void setCellRangeAddress(HSSFCellRangeAddress range) {
408: this .field_regions = range;
409: }
410:
411: public HSSFCellRangeAddress getCellRangeAddress() {
412: return this .field_regions;
413: }
414:
415: /**
416: * gets the option flags field.
417: * @return options - the option flags field
418: */
419: public int getOptionFlags() {
420: return this .field_option_flags;
421: }
422:
423: public String toString() {
424: /** @todo DVRecord string representation */
425: StringBuffer buffer = new StringBuffer();
426:
427: return buffer.toString();
428: }
429:
430: public int serialize(int offset, byte[] data) {
431: int size = this .getRecordSize();
432: LittleEndian.putShort(data, 0 + offset, sid);
433: LittleEndian.putShort(data, 2 + offset, (short) (size - 4));
434:
435: int pos = 4;
436: LittleEndian.putInt(data, pos + offset, this .getOptionFlags());
437: pos += 4;
438: pos += ((StringHandler) this ._hash_strings
439: .get(DVRecord.STRING_PROMPT_TITLE)).serialize(pos
440: + offset, data);
441: pos += ((StringHandler) this ._hash_strings
442: .get(DVRecord.STRING_ERROR_TITLE)).serialize(pos
443: + offset, data);
444: pos += ((StringHandler) this ._hash_strings
445: .get(DVRecord.STRING_PROMPT_TEXT)).serialize(pos
446: + offset, data);
447: pos += ((StringHandler) this ._hash_strings
448: .get(DVRecord.STRING_ERROR_TEXT)).serialize(pos
449: + offset, data);
450: LittleEndian.putShort(data, offset + pos,
451: this .field_size_first_formula);
452: pos += 2;
453: LittleEndian
454: .putShort(data, offset + pos, this .field_not_used_1);
455: pos += 2;
456:
457: for (int k = 0; k < this .field_rpn_token_1.size(); k++) {
458: Ptg ptg = (Ptg) this .field_rpn_token_1.get(k);
459: ptg.writeBytes(data, pos + offset);
460: pos += ptg.getSize();
461: }
462:
463: LittleEndian.putShort(data, offset + pos,
464: this .field_size_sec_formula);
465: pos += 2;
466: LittleEndian
467: .putShort(data, offset + pos, this .field_not_used_2);
468: pos += 2;
469: if (this .field_size_sec_formula > 0) {
470: for (int k = 0; k < this .field_rpn_token_2.size(); k++) {
471: Ptg ptg = (Ptg) this .field_rpn_token_2.get(k);
472: ptg.writeBytes(data, pos + offset);
473: pos += ptg.getSize();
474: }
475: }
476: this .field_regions.serialize(pos + offset, data);
477: return size;
478: }
479:
480: public int getRecordSize() {
481: int size = 4 + 4 + 2 + 2 + 2 + 2;//header+options_field+first_formula_size+first_unused+sec_formula_size+sec+unused;
482: if (this ._hash_strings != null) {
483: Enumeration enum_keys = this ._hash_strings.keys();
484: while (enum_keys.hasMoreElements()) {
485: size += ((StringHandler) this ._hash_strings
486: .get((Integer) enum_keys.nextElement()))
487: .getSize();
488: }
489: }
490: size += this .field_size_first_formula
491: + this .field_size_sec_formula;
492: size += this .field_regions.getSize();
493: return size;
494: }
495:
496: public short getSid() {
497: return this .sid;
498: }
499:
500: /**@todo DVRecord = Serializare */
501:
502: private class StringHandler {
503: private int _string_length = 0x0001;
504: private byte _string_unicode_flag = 0x00;
505: private String _string_data = "0x00";
506: private int _start_offset;
507: private int _end_offset;
508:
509: StringHandler() {
510:
511: }
512:
513: StringHandler(RecordInputStream in) {
514: this .fillFields(in);
515: }
516:
517: protected void fillFields(RecordInputStream in) {
518: this ._string_length = in.readUShort();
519: this ._string_unicode_flag = in.readByte();
520: if (this ._string_unicode_flag == 1) {
521: this ._string_data = in
522: .readUnicodeLEString(this ._string_length);
523: } else {
524: this ._string_data = in
525: .readCompressedUnicode(this ._string_length);
526: }
527: }
528:
529: private void setStringData(String string_data) {
530: this ._string_data = string_data;
531: }
532:
533: private String getStringData() {
534: return this ._string_data;
535: }
536:
537: private int getEndOffset() {
538: return this ._end_offset;
539: }
540:
541: public int serialize(int offset, byte[] data) {
542: LittleEndian.putUShort(data, offset, this ._string_length);
543: data[2 + offset] = this ._string_unicode_flag;
544: if (this ._string_unicode_flag == 1) {
545: StringUtil.putUnicodeLE(this ._string_data, data,
546: 3 + offset);
547: } else {
548: StringUtil.putCompressedUnicode(this ._string_data,
549: data, 3 + offset);
550: }
551: return getSize();
552: }
553:
554: private void setUnicodeFlag(byte flag) {
555: this ._string_unicode_flag = flag;
556: }
557:
558: private void setStringLength(int len) {
559: this ._string_length = len;
560: }
561:
562: private int getStringByteLength() {
563: return (this ._string_unicode_flag == 1) ? this ._string_length * 2
564: : this ._string_length;
565: }
566:
567: public int getSize() {
568: return 2 + 1 + getStringByteLength();
569: }
570: }
571: }
|