1 | /* ====================================================================
|
---|
2 | Licensed to the Apache Software Foundation (ASF) under one or more
|
---|
3 | contributor license agreements. See the NOTICE file distributed with
|
---|
4 | this work for additional information regarding copyright ownership.
|
---|
5 | The ASF licenses this file to You under the Apache License, Version 2.0
|
---|
6 | (the "License"); you may not use this file except in compliance with
|
---|
7 | the License. You may obtain a copy of the License at
|
---|
8 |
|
---|
9 | http://www.apache.org/licenses/LICENSE-2.0
|
---|
10 |
|
---|
11 | Unless required by applicable law or agreed to in writing, software
|
---|
12 | distributed under the License is distributed on an "AS IS" BASIS,
|
---|
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
---|
14 | See the License for the specific language governing permissions and
|
---|
15 | limitations under the License.
|
---|
16 | ==================================================================== */
|
---|
17 |
|
---|
18 | package org.apache.poi.hssf.record;
|
---|
19 |
|
---|
20 | import org.apache.poi.hssf.record.common.UnicodeString;
|
---|
21 | import org.apache.poi.hssf.record.formula.Ptg;
|
---|
22 | import org.apache.poi.ss.formula.Formula;
|
---|
23 | import org.apache.poi.ss.util.CellRangeAddress;
|
---|
24 | import org.apache.poi.ss.util.CellRangeAddressList;
|
---|
25 | import org.apache.poi.util.LittleEndianOutput;
|
---|
26 | import org.apache.poi.util.StringUtil;
|
---|
27 |
|
---|
28 | /**
|
---|
29 | * Title: DATAVALIDATION Record (0x01BE)<p/>
|
---|
30 | * Description: This record stores data validation settings and a list of cell ranges
|
---|
31 | * which contain these settings. The data validation settings of a sheet
|
---|
32 | * are stored in a sequential list of DV records. This list is followed by
|
---|
33 | * DVAL record(s)
|
---|
34 | * @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
|
---|
35 | * @author Josh Micich
|
---|
36 | */
|
---|
37 | public final class DVRecord extends StandardRecord {
|
---|
38 | public final static short sid = 0x01BE;
|
---|
39 |
|
---|
40 | /** Option flags */
|
---|
41 | private int _option_flags;
|
---|
42 | /** Title of the prompt box */
|
---|
43 | private UnicodeString _promptTitle;
|
---|
44 | /** Title of the error box */
|
---|
45 | private UnicodeString _errorTitle;
|
---|
46 | /** Text of the prompt box */
|
---|
47 | private UnicodeString _promptText;
|
---|
48 | /** Text of the error box */
|
---|
49 | private UnicodeString _errorText;
|
---|
50 | /** Not used - Excel seems to always write 0x3FE0 */
|
---|
51 | private short _not_used_1 = 0x3FE0;
|
---|
52 | /** Formula data for first condition (RPN token array without size field) */
|
---|
53 | private Formula _formula1;
|
---|
54 | /** Not used - Excel seems to always write 0x0000 */
|
---|
55 | private short _not_used_2 = 0x0000;
|
---|
56 | /** Formula data for second condition (RPN token array without size field) */
|
---|
57 | private Formula _formula2;
|
---|
58 | /** Cell range address list with all affected ranges */
|
---|
59 | private CellRangeAddressList _regions;
|
---|
60 |
|
---|
61 | /**
|
---|
62 | * Option flags field
|
---|
63 | *
|
---|
64 | * @see HSSFDataValidation utility class
|
---|
65 | */
|
---|
66 |
|
---|
67 | public DVRecord(RecordInputStream in) { // NO_UCD
|
---|
68 |
|
---|
69 | _option_flags = in.readInt();
|
---|
70 |
|
---|
71 | _promptTitle = readUnicodeString(in);
|
---|
72 | _errorTitle = readUnicodeString(in);
|
---|
73 | _promptText = readUnicodeString(in);
|
---|
74 | _errorText = readUnicodeString(in);
|
---|
75 |
|
---|
76 | int field_size_first_formula = in.readUShort();
|
---|
77 | _not_used_1 = in.readShort();
|
---|
78 |
|
---|
79 | // "You may not use unions, intersections or array constants in Data Validation criteria"
|
---|
80 |
|
---|
81 | // read first formula data condition
|
---|
82 | _formula1 = Formula.read(field_size_first_formula, in);
|
---|
83 |
|
---|
84 | int field_size_sec_formula = in.readUShort();
|
---|
85 | _not_used_2 = in.readShort();
|
---|
86 |
|
---|
87 | // read sec formula data condition
|
---|
88 | _formula2 = Formula.read(field_size_sec_formula, in);
|
---|
89 |
|
---|
90 | // read cell range address list with all affected ranges
|
---|
91 | _regions = new CellRangeAddressList(in);
|
---|
92 | }
|
---|
93 |
|
---|
94 | public String toString() {
|
---|
95 | StringBuffer sb = new StringBuffer();
|
---|
96 | sb.append("[DV]\n");
|
---|
97 | sb.append(" options=").append(Integer.toHexString(_option_flags));
|
---|
98 | sb.append(" title-prompt=").append(formatTextTitle(_promptTitle));
|
---|
99 | sb.append(" title-error=").append(formatTextTitle(_errorTitle));
|
---|
100 | sb.append(" text-prompt=").append(formatTextTitle(_promptText));
|
---|
101 | sb.append(" text-error=").append(formatTextTitle(_errorText));
|
---|
102 | sb.append("\n");
|
---|
103 | appendFormula(sb, "Formula 1:", _formula1);
|
---|
104 | appendFormula(sb, "Formula 2:", _formula2);
|
---|
105 | sb.append("Regions: ");
|
---|
106 | int nRegions = _regions.countRanges();
|
---|
107 | for(int i=0; i<nRegions; i++) {
|
---|
108 | if (i>0) {
|
---|
109 | sb.append(", ");
|
---|
110 | }
|
---|
111 | CellRangeAddress addr = _regions.getCellRangeAddress(i);
|
---|
112 | sb.append('(').append(addr.getFirstRow()).append(',').append(addr.getLastRow());
|
---|
113 | sb.append(',').append(addr.getFirstColumn()).append(',').append(addr.getLastColumn()).append(')');
|
---|
114 | }
|
---|
115 | sb.append("\n");
|
---|
116 | sb.append("[/DV]");
|
---|
117 |
|
---|
118 | return sb.toString();
|
---|
119 | }
|
---|
120 |
|
---|
121 | private static String formatTextTitle(UnicodeString us) {
|
---|
122 | String str = us.getString();
|
---|
123 | if (str.length() == 1 && str.charAt(0) == '\0') {
|
---|
124 | return "'\\0'";
|
---|
125 | }
|
---|
126 | return str;
|
---|
127 | }
|
---|
128 |
|
---|
129 | private static void appendFormula(StringBuffer sb, String label, Formula f) {
|
---|
130 | sb.append(label);
|
---|
131 |
|
---|
132 | if (f == null) {
|
---|
133 | sb.append("<empty>\n");
|
---|
134 | return;
|
---|
135 | }
|
---|
136 | Ptg[] ptgs = f.getTokens();
|
---|
137 | sb.append('\n');
|
---|
138 | for (int i = 0; i < ptgs.length; i++) {
|
---|
139 | sb.append('\t').append(ptgs[i].toString()).append('\n');
|
---|
140 | }
|
---|
141 | }
|
---|
142 |
|
---|
143 | public void serialize(LittleEndianOutput out) {
|
---|
144 |
|
---|
145 | out.writeInt(_option_flags);
|
---|
146 |
|
---|
147 | serializeUnicodeString(_promptTitle, out);
|
---|
148 | serializeUnicodeString(_errorTitle, out);
|
---|
149 | serializeUnicodeString(_promptText, out);
|
---|
150 | serializeUnicodeString(_errorText, out);
|
---|
151 | out.writeShort(_formula1.getEncodedTokenSize());
|
---|
152 | out.writeShort(_not_used_1);
|
---|
153 | _formula1.serializeTokens(out);
|
---|
154 |
|
---|
155 | out.writeShort(_formula2.getEncodedTokenSize());
|
---|
156 | out.writeShort(_not_used_2);
|
---|
157 | _formula2.serializeTokens(out);
|
---|
158 |
|
---|
159 | _regions.serialize(out);
|
---|
160 | }
|
---|
161 |
|
---|
162 | private static UnicodeString readUnicodeString(RecordInputStream in) {
|
---|
163 | return new UnicodeString(in);
|
---|
164 | }
|
---|
165 |
|
---|
166 | private static void serializeUnicodeString(UnicodeString us, LittleEndianOutput out) {
|
---|
167 | StringUtil.writeUnicodeString(out, us.getString());
|
---|
168 | }
|
---|
169 | private static int getUnicodeStringSize(UnicodeString us) {
|
---|
170 | String str = us.getString();
|
---|
171 | return 3 + str.length() * (StringUtil.hasMultibyte(str) ? 2 : 1);
|
---|
172 | }
|
---|
173 |
|
---|
174 | protected int getDataSize() {
|
---|
175 | int size = 4+2+2+2+2;//options_field+first_formula_size+first_unused+sec_formula_size+sec+unused;
|
---|
176 | size += getUnicodeStringSize(_promptTitle);
|
---|
177 | size += getUnicodeStringSize(_errorTitle);
|
---|
178 | size += getUnicodeStringSize(_promptText);
|
---|
179 | size += getUnicodeStringSize(_errorText);
|
---|
180 | size += _formula1.getEncodedTokenSize();
|
---|
181 | size += _formula2.getEncodedTokenSize();
|
---|
182 | size += _regions.getSize();
|
---|
183 | return size;
|
---|
184 | }
|
---|
185 |
|
---|
186 | public short getSid() {
|
---|
187 | return sid;
|
---|
188 | }
|
---|
189 |
|
---|
190 | /**
|
---|
191 | * Clones the object. Uses serialisation, as the
|
---|
192 | * contents are somewhat complex
|
---|
193 | */
|
---|
194 | public Object clone() {
|
---|
195 | return cloneViaReserialise();
|
---|
196 | }
|
---|
197 | }
|
---|