|
|||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
CombinedAttribute.java | 71.9% | 64.6% | 83.3% | 67.8% |
|
1 |
/*
|
|
2 |
* SimplyHTML, a word processor based on Java, HTML and CSS
|
|
3 |
* Copyright (C) 2002 Ulrich Hilger
|
|
4 |
*
|
|
5 |
* This program is free software; you can redistribute it and/or
|
|
6 |
* modify it under the terms of the GNU General Public License
|
|
7 |
* as published by the Free Software Foundation; either version 2
|
|
8 |
* of the License, or (at your option) any later version.
|
|
9 |
*
|
|
10 |
* This program is distributed in the hope that it will be useful,
|
|
11 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13 |
* GNU General Public License for more details.
|
|
14 |
*
|
|
15 |
* You should have received a copy of the GNU General Public License
|
|
16 |
* along with this program; if not, write to the Free Software
|
|
17 |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
18 |
*/
|
|
19 |
|
|
20 |
import javax.swing.text.AttributeSet;
|
|
21 |
import javax.swing.text.html.CSS;
|
|
22 |
import java.util.Enumeration;
|
|
23 |
import java.util.Vector;
|
|
24 |
import javax.swing.text.Element;
|
|
25 |
import javax.swing.text.Style;
|
|
26 |
|
|
27 |
/**
|
|
28 |
* A class to represent an attribute combining several other attributes.
|
|
29 |
*
|
|
30 |
* <p>The <a href="http://www.w3.org/TR/REC-CSS1">CSS 1.0 specification</a>
|
|
31 |
* defines 'shorthand properties' which can hold more than
|
|
32 |
* one value separated by blanks. Depending on the number of values inside
|
|
33 |
* the property the values are applied following a fixed ratio.</p>
|
|
34 |
*
|
|
35 |
* <p>Following is an excerpt of the spec for CSS property
|
|
36 |
* <code>border-width</code></p>
|
|
37 |
* <pre>
|
|
38 |
* There can be from one to four values, with the following interpretation:
|
|
39 |
* one value: all four border widths are set to that value
|
|
40 |
* two values: top and bottom border widths are set to the
|
|
41 |
* first value, right and left are set to the second
|
|
42 |
* three values: top is set to the first, right and left are set to
|
|
43 |
* the second, bottom is set to the third
|
|
44 |
* four values: top, right, bottom and left, respectively
|
|
45 |
* </pre>
|
|
46 |
*
|
|
47 |
* <p>In SimplyHTML this spec is used on properties margin,
|
|
48 |
* padding, border-width and border-color</p>
|
|
49 |
*
|
|
50 |
* @author Ulrich Hilger
|
|
51 |
* @author Light Development
|
|
52 |
* @author <a href="http://www.lightdev.com">http://www.lightdev.com</a>
|
|
53 |
* @author <a href="mailto:info@lightdev.com">info@lightdev.com</a>
|
|
54 |
* @author published under the terms and conditions of the
|
|
55 |
* GNU General Public License,
|
|
56 |
* for details see file gpl.txt in the distribution
|
|
57 |
* package of this software
|
|
58 |
*
|
|
59 |
* @version stage 11, April 27, 2003
|
|
60 |
*/
|
|
61 |
|
|
62 |
public class CombinedAttribute { |
|
63 |
|
|
64 |
/** index of top value */
|
|
65 |
public static final int ATTR_TOP = 0; |
|
66 |
|
|
67 |
/** index of right value */
|
|
68 |
public static final int ATTR_RIGHT = 1; |
|
69 |
|
|
70 |
/** index of bottom value */
|
|
71 |
public static final int ATTR_BOTTOM = 2; |
|
72 |
|
|
73 |
/** index of left value */
|
|
74 |
public static final int ATTR_LEFT = 3; |
|
75 |
|
|
76 |
/** the values of this <code>CombinedAttribute</code> */
|
|
77 |
private String[] values = new String[4]; |
|
78 |
|
|
79 |
/**
|
|
80 |
* the attribute key the values of this
|
|
81 |
* <code>CombinedAttribute</code> belong to
|
|
82 |
*/
|
|
83 |
private Object attributeKey;
|
|
84 |
|
|
85 |
/** indicates which sides were present in the attribute set */
|
|
86 |
private boolean[] present = new boolean[4]; |
|
87 |
|
|
88 |
/** table with attribute names from the source attribute set */
|
|
89 |
private Vector aNames = new Vector(); |
|
90 |
|
|
91 |
/** indicates if attributes of parent elements shall be used */
|
|
92 |
private boolean includeParents; |
|
93 |
|
|
94 |
/**
|
|
95 |
* construct a <code>CombinedAttribute</code> for a certain
|
|
96 |
* attribute out of a given set of attributes
|
|
97 |
*
|
|
98 |
* @param key the attribute key to get single attribute values from
|
|
99 |
* @param a the set of attributes to get the attribute of type 'key'
|
|
100 |
*/
|
|
101 | 86 |
public CombinedAttribute(Object key, AttributeSet a, boolean includeParents) { |
102 | 86 |
attributeKey = key; |
103 | 86 |
this.includeParents = includeParents;
|
104 |
|
|
105 |
// get names in this attribute set to filter out parent attributes later
|
|
106 | 86 |
Enumeration names = a.getAttributeNames(); |
107 | 86 |
while(names.hasMoreElements()) {
|
108 | 528 |
aNames.addElement(names.nextElement()); |
109 |
} |
|
110 |
|
|
111 |
// now load attributes into this object
|
|
112 | 86 |
Object attr = a.getAttribute(key); |
113 | 86 |
if(attr != null) { |
114 |
//System.out.println(" construct CombinedAttribute attr=" + attr);
|
|
115 | 1 |
copyValues(Util.tokenize(attr.toString(), " "));
|
116 |
} |
|
117 |
else {
|
|
118 | 85 |
copyValues(key, a); |
119 |
} |
|
120 |
} |
|
121 |
|
|
122 |
/**
|
|
123 |
* copy the values for individual border settings from a given
|
|
124 |
* set of attributes into the structure top, right, bottom, left of
|
|
125 |
* this <code>CombinedAttribute</code>
|
|
126 |
*
|
|
127 |
* <p>Used in cases where attributes are not found for a 'shorthand
|
|
128 |
* property' such as PADDING or MARGIN.</p>
|
|
129 |
*
|
|
130 |
* @param key the 'shorthand property' to copy individual attributes for
|
|
131 |
* @param a the set of attributes to copy from
|
|
132 |
*/
|
|
133 | 85 |
private void copyValues(Object key, AttributeSet a) { |
134 | 85 |
if(key.equals(CSS.Attribute.BORDER_WIDTH)) {
|
135 | 27 |
setValue(ATTR_TOP, CSS.Attribute.BORDER_TOP_WIDTH, a); |
136 | 27 |
setValue(ATTR_RIGHT, CSS.Attribute.BORDER_RIGHT_WIDTH, a); |
137 | 27 |
setValue(ATTR_BOTTOM, CSS.Attribute.BORDER_BOTTOM_WIDTH, a); |
138 | 27 |
setValue(ATTR_LEFT, CSS.Attribute.BORDER_LEFT_WIDTH, a); |
139 |
} |
|
140 | 58 |
else if(key.equals(CSS.Attribute.PADDING)) { |
141 | 29 |
setValue(ATTR_TOP, CSS.Attribute.PADDING_TOP, a); |
142 | 29 |
setValue(ATTR_RIGHT, CSS.Attribute.PADDING_RIGHT, a); |
143 | 29 |
setValue(ATTR_BOTTOM, CSS.Attribute.PADDING_BOTTOM, a); |
144 | 29 |
setValue(ATTR_LEFT, CSS.Attribute.PADDING_LEFT, a); |
145 |
} |
|
146 | 29 |
else if(key.equals(CSS.Attribute.MARGIN)) { |
147 | 29 |
setValue(ATTR_TOP, CSS.Attribute.MARGIN_TOP, a); |
148 | 29 |
setValue(ATTR_RIGHT, CSS.Attribute.MARGIN_RIGHT, a); |
149 | 29 |
setValue(ATTR_BOTTOM, CSS.Attribute.MARGIN_BOTTOM, a); |
150 | 29 |
setValue(ATTR_LEFT, CSS.Attribute.MARGIN_LEFT, a); |
151 |
} |
|
152 |
} |
|
153 |
|
|
154 |
/**
|
|
155 |
* set the value of a certain side from a given attribute key and
|
|
156 |
* set of attributes.
|
|
157 |
*
|
|
158 |
* @param side the side to set the value for, one of ATTR_TOP,
|
|
159 |
* ATTR_RIGHT, ATTR_BOTTOM and ATTR_LEFT
|
|
160 |
* @param key the attribute key to get the value from
|
|
161 |
* @param a the set of attributes to get the value from
|
|
162 |
*/
|
|
163 | 340 |
private void setValue(int side, Object key, AttributeSet a) { |
164 | 340 |
if((includeParents) || ((!includeParents) && (aNames.contains(key)))) { // filter out parent attributes |
165 | 116 |
Object attr = a.getAttribute(key); |
166 | 116 |
if(attr != null) { |
167 | 102 |
values[side] = attr.toString(); |
168 | 102 |
present[side] = true;
|
169 |
} |
|
170 |
else {
|
|
171 | 14 |
values[side] = defaultValue(attributeKey); |
172 | 14 |
present[side] = true;
|
173 |
} |
|
174 |
} |
|
175 |
else { // key not present, set default value |
|
176 | 224 |
values[side] = defaultValue(attributeKey); |
177 | 224 |
present[side] = false;
|
178 |
} |
|
179 |
} |
|
180 |
|
|
181 |
/**
|
|
182 |
* determine whether or not the set of attributes this
|
|
183 |
* <code>CombinedAttribute</code> was created from contained any
|
|
184 |
* of the attributes in this <code>CombinedAttribute</code>
|
|
185 |
*
|
|
186 |
* <p>Can be used for instance to determine whether or not this
|
|
187 |
* <code>CombinedAttribute</code> should be written</p>
|
|
188 |
*
|
|
189 |
* @return true, if this <code>CombinedAttribute</code> contains
|
|
190 |
* default values only, false if not
|
|
191 |
*/
|
|
192 | 78 |
public boolean isEmpty() { |
193 | 78 |
boolean notEmpty = false; |
194 | 78 |
int i = 0;
|
195 | 78 |
while(!notEmpty && i < present.length) {
|
196 | 246 |
notEmpty = present[i]; |
197 | 246 |
i++; |
198 |
} |
|
199 | 78 |
return !notEmpty;
|
200 |
} |
|
201 |
|
|
202 |
/**
|
|
203 |
* get the default value for a given key
|
|
204 |
*
|
|
205 |
* @param key the attribute key to get the default value for
|
|
206 |
*
|
|
207 |
* @return the default value for the given key
|
|
208 |
*/
|
|
209 | 238 |
private String defaultValue(Object key) {
|
210 | 238 |
String value = "0";
|
211 | 238 |
if(key.equals(CSS.Attribute.BORDER_COLOR)) {
|
212 | 0 |
value = "#000000";
|
213 |
} |
|
214 | 238 |
return value;
|
215 |
} |
|
216 |
|
|
217 |
/**
|
|
218 |
* get the side opposite of a given side
|
|
219 |
*
|
|
220 |
* @param side the side to get the opposite of
|
|
221 |
*
|
|
222 |
* @return the opposite side of the given side
|
|
223 |
*/
|
|
224 | 0 |
public int getOppositeSide(int side) { |
225 | 0 |
int oppositeSide = -1;
|
226 | 0 |
switch(side) {
|
227 | 0 |
case ATTR_TOP:
|
228 | 0 |
oppositeSide = ATTR_BOTTOM; |
229 | 0 |
break;
|
230 | 0 |
case ATTR_RIGHT:
|
231 | 0 |
oppositeSide = ATTR_LEFT; |
232 | 0 |
break;
|
233 | 0 |
case ATTR_BOTTOM:
|
234 | 0 |
oppositeSide = ATTR_TOP; |
235 | 0 |
break;
|
236 | 0 |
case ATTR_LEFT:
|
237 | 0 |
oppositeSide = ATTR_RIGHT; |
238 | 0 |
break;
|
239 |
} |
|
240 | 0 |
return oppositeSide;
|
241 |
} |
|
242 |
|
|
243 |
/**
|
|
244 |
* copy the atribute value(s) found in a 'shorthand property' such
|
|
245 |
* as PADDING or MARGIN into the structure top, right, bottom, left of
|
|
246 |
* this <code>CombinedAttribute</code>
|
|
247 |
*
|
|
248 |
* @param v the array of Strings holding the found values
|
|
249 |
*/
|
|
250 | 1 |
private void copyValues(String[] v) { |
251 | 1 |
switch(v.length) {
|
252 | 1 |
case 1:
|
253 | 1 |
for(int i = 0; i < values.length; i++) { |
254 | 4 |
values[i] = v[0]; |
255 |
} |
|
256 | 1 |
break;
|
257 | 0 |
case 2:
|
258 | 0 |
values[ATTR_TOP] = v[ATTR_TOP]; |
259 | 0 |
values[ATTR_RIGHT] = v[ATTR_RIGHT]; |
260 | 0 |
values[ATTR_BOTTOM] = v[ATTR_TOP]; |
261 | 0 |
values[ATTR_LEFT] = v[ATTR_RIGHT]; |
262 | 0 |
break;
|
263 | 0 |
case 3:
|
264 | 0 |
values[ATTR_TOP] = v[ATTR_TOP]; |
265 | 0 |
values[ATTR_RIGHT] = v[ATTR_RIGHT]; |
266 | 0 |
values[ATTR_BOTTOM] = v[ATTR_BOTTOM]; |
267 | 0 |
values[ATTR_LEFT] = v[ATTR_RIGHT]; |
268 | 0 |
break;
|
269 | 0 |
case 4:
|
270 | 0 |
for(int i = 0; i < values.length; i++) { |
271 | 0 |
values[i] = v[i]; |
272 |
} |
|
273 | 0 |
break;
|
274 |
} |
|
275 |
} |
|
276 |
|
|
277 |
/**
|
|
278 |
* set one attribute of this <code>CombinedAttribute</code>
|
|
279 |
*
|
|
280 |
* @param side the side to set the attribute for, one of ATTR_TOP,
|
|
281 |
* ATTR_RIGHT, ATTR_BOTTOM, ATTR_LEFT
|
|
282 |
* @param value the attribute value to set
|
|
283 |
*/
|
|
284 | 8 |
public void setAttribute(int side, String value) { |
285 | 8 |
values[side] = value; |
286 |
} |
|
287 |
|
|
288 |
/**
|
|
289 |
* get one attribute of this <code>CombinedAttribute</code>
|
|
290 |
*
|
|
291 |
* @param side the side to get the attribute for, one of ATTR_TOP,
|
|
292 |
* ATTR_RIGHT, ATTR_BOTTOM, ATTR_LEFT
|
|
293 |
*
|
|
294 |
* @return the attribute value for the specified side or null, if the
|
|
295 |
* attribute key provided in the constructor was not found
|
|
296 |
*/
|
|
297 | 33 |
public String getAttribute(int side) { |
298 | 33 |
return values[side];
|
299 |
} |
|
300 |
|
|
301 |
/**
|
|
302 |
* get the attribute key this <code>CombinedAttribute</code> represents
|
|
303 |
*
|
|
304 |
* @return the attribute key
|
|
305 |
*/
|
|
306 | 0 |
public Object getAttributeKey() {
|
307 | 0 |
return attributeKey;
|
308 |
} |
|
309 |
|
|
310 |
/**
|
|
311 |
* get all values of this <code>CombinedAttribute</code>
|
|
312 |
* as one attribute.
|
|
313 |
*
|
|
314 |
* @return a String having all values delimited by blanks
|
|
315 |
* in the order top right, bottom, left or null if no
|
|
316 |
* attributes were found
|
|
317 |
*/
|
|
318 | 35 |
public String getAttribute() {
|
319 | 35 |
String result = null;
|
320 | 35 |
StringBuffer buf = new StringBuffer();
|
321 | 35 |
if(values[0] != null) { |
322 | 35 |
buf.append(values[0]); |
323 | 35 |
int additionalValueCount = 3;
|
324 | 35 |
if(values[ATTR_RIGHT].equalsIgnoreCase(values[ATTR_LEFT])) {
|
325 | 35 |
--additionalValueCount; // total 3
|
326 | 35 |
if(values[ATTR_TOP].equalsIgnoreCase(values[ATTR_BOTTOM])) {
|
327 | 35 |
--additionalValueCount; // total 2
|
328 | 35 |
if(values[ATTR_TOP].equalsIgnoreCase(values[ATTR_RIGHT])) {
|
329 | 35 |
--additionalValueCount; // total 1
|
330 |
} |
|
331 |
} |
|
332 |
} |
|
333 | 35 |
appendValues(buf, additionalValueCount); |
334 | 35 |
result = buf.toString(); |
335 |
} |
|
336 | 35 |
return result;
|
337 |
} |
|
338 |
|
|
339 |
/**
|
|
340 |
* append a given number of values to a given output buffer
|
|
341 |
* starting with ATTR_RIGHT and necessarily continuing
|
|
342 |
* with ATTR_BOTTOM and ATTR_LEFT ( helper method to getAttribute() )
|
|
343 |
*
|
|
344 |
* @param buf the output buffer to append to
|
|
345 |
* @param count the number of values to append
|
|
346 |
*/
|
|
347 | 35 |
private void appendValues(StringBuffer buf, int count) { |
348 | 35 |
for(int i = 1; i < count + 1; i++) { |
349 | 0 |
buf.append(' '); |
350 | 0 |
buf.append(values[i]); |
351 |
} |
|
352 |
} |
|
353 |
} |
|