001: /*
002: * Copyright 2000,2005 wingS development team.
003: *
004: * This file is part of wingS (http://wingsframework.org).
005: *
006: * wingS is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU Lesser General Public License
008: * as published by the Free Software Foundation; either version 2.1
009: * of the License, or (at your option) any later version.
010: *
011: * Please see COPYING for the complete licence.
012: */
013: package org.wings.style;
014:
015: import org.wings.Renderable;
016: import org.wings.util.SStringBuilder;
017: import org.wings.io.Device;
018:
019: import java.io.IOException;
020: import java.io.Serializable;
021: import java.util.*;
022:
023: /**
024: * A straightforward implementation of CSSPropertySet using a hash map.
025: *
026: * @author <a href="mailto:engels@mercatis.de">Holger Engels</a>
027: */
028: public class CSSAttributeSet implements Renderable, Serializable,
029: Cloneable {
030:
031: /** Empty immutable attribute set. */
032: public static final CSSAttributeSet EMPTY_ATTRIBUTESET = new CSSAttributeSet() {
033: private UnsupportedOperationException doThrow() {
034: return new UnsupportedOperationException(
035: "Cannot change values for the global EMPTY_ATTRIBUTESET. "
036: + "You attempted to modify this unmodifiable CSSPropertySet.");
037: }
038:
039: public String put(String name, String value) {
040: throw doThrow();
041: }
042:
043: public boolean putAll(CSSAttributeSet attributes) {
044: throw doThrow();
045: }
046: };
047:
048: /** The map holding <code>CSSProperty</code> to <code>String</code> */
049: private HashMap<CSSProperty, String> map;
050:
051: /** Cached String representation of this attribute set. */
052: private String cachedStringRepresentation;
053:
054: /**
055: * create a CSSPropertySet from the given HashMap.
056: */
057: private CSSAttributeSet(HashMap<CSSProperty, String> map) {
058: this .map = map;
059: }
060:
061: /**
062: * Creates a new, empty atribute set.
063: */
064: public CSSAttributeSet() {
065: }
066:
067: public CSSAttributeSet(CSSProperty cssProperty,
068: String cssPropertyValue) {
069: put(cssProperty, cssPropertyValue);
070: }
071:
072: /**
073: * Creates a new attribute set based on a supplied set of attributes.
074: *
075: * @param source the set of attributes
076: */
077: public CSSAttributeSet(CSSAttributeSet source) {
078: putAll(source);
079: }
080:
081: /**
082: * Checks whether the set of attributes is empty.
083: *
084: * @return true if the set is empty else false
085: */
086: public final boolean isEmpty() {
087: return map == null || map.isEmpty();
088: }
089:
090: /**
091: * Gets a count of the number of attributes.
092: *
093: * @return the count
094: */
095: public final int size() {
096: return map == null ? 0 : map.size();
097: }
098:
099: public final void clear() {
100: if (map != null) {
101: map.clear();
102: }
103: }
104:
105: /**
106: * Tells whether a given attribute is defined.
107: *
108: * @param name the attribute name
109: * @return true if the attribute is defined
110: */
111: public final boolean contains(CSSProperty name) {
112: return map != null && map.containsKey(name);
113: }
114:
115: /**
116: * Gets the Set of defined CSS property names.
117: *
118: * @return A set of {@link CSSProperty} for which this <code>CSSAttributeSet</code> contains a value.
119: */
120: public final Map<CSSProperty, String> properties() {
121: if (map != null) {
122: return Collections.unmodifiableMap(map);
123: } else {
124: return Collections.emptyMap();
125: }
126: }
127:
128: /**
129: * Gets the value of an css property.
130: *
131: * @param property the attribute property
132: * @return the value
133: */
134: public final String get(CSSProperty property) {
135: return map == null ? null : (String) map.get(property);
136: }
137:
138: /**
139: * Adds an attribute to the list.
140: *
141: * @param name the attribute name
142: * @param value the attribute value
143: */
144: public String put(CSSProperty name, String value) {
145: cachedStringRepresentation = null;
146: if (map == null) {
147: map = new HashMap<CSSProperty, String>(8);
148: }
149:
150: if (value == null)
151: return remove(name);
152: return (String) map.put(name, value);
153: }
154:
155: /**
156: * Adds a set of attributes to the list.
157: *
158: * @param attributes the set of attributes to add
159: */
160: public boolean putAll(CSSAttributeSet attributes) {
161: cachedStringRepresentation = null;
162: if (map == null)
163: map = new HashMap<CSSProperty, String>(8);
164:
165: boolean changed = false;
166: for (Map.Entry<CSSProperty, String> entry1 : attributes
167: .properties().entrySet()) {
168: Map.Entry entry = (Map.Entry) entry1;
169: CSSProperty property = (CSSProperty) entry.getKey();
170: changed = changed
171: || (put(property, (String) entry.getValue()) != null);
172: }
173: return changed;
174: }
175:
176: /**
177: * Removes an attribute from the list.
178: *
179: * @param name the attribute name
180: * @return The previous value for this CSS property
181: */
182: public String remove(CSSProperty name) {
183: cachedStringRepresentation = null;
184: return map == null ? null : (String) map.remove(name);
185: }
186:
187: // --- Object methods ---------------------------------
188:
189: /**
190: * Clones a set of attributes.
191: *
192: * @return the new set of attributes
193: */
194: @Override
195: public Object clone() {
196: if (isEmpty()) {
197: return new CSSAttributeSet();
198: } else {
199: return new CSSAttributeSet((HashMap) map.clone());
200: }
201: }
202:
203: @Override
204: public boolean equals(Object o) {
205: if (this == o)
206: return true;
207: if (o == null || getClass() != o.getClass())
208: return false;
209:
210: final CSSAttributeSet that = (CSSAttributeSet) o;
211:
212: return !(map != null ? !map.equals(that.map) : that.map != null);
213: }
214:
215: @Override
216: public int hashCode() {
217: return (map != null ? map.hashCode() : 0);
218: }
219:
220: // /**
221: // * Write style definition to the device. If include is true, write those
222: // * contained in the {@link java.util.List}. If include is false, write those not contained
223: // * in the {@link java.util.List}.
224: // * Basically this is a filter on the styles, so we can separate styles for
225: // * one logical component onto multiple real html elements.
226: // */
227: // private static void writeFiltered(Device d, Map map, Set l, boolean include) throws IOException {
228: // if (l == null) l = Collections.EMPTY_SET;
229: // if (map != null) {
230: // Iterator names = map.entrySet().iterator();
231: // while (names.hasNext()) {
232: // Map.Entry next = (Map.Entry) names.next();
233: // if ( !(l.contains(next.getKey()) ^ include) ) {
234: // d.print(next.getKey()).print(':')
235: // .print(next.getValue())
236: // .print(';');
237: // }
238: // }
239: // }
240: // }
241: //
242: // /**
243: // * Write style definition to the device. Write only those not contained
244: // * in the set.
245: // */
246: // public static void writeExcluding(Device d, Map map, Set l) throws IOException {
247: // writeFiltered(d, map, l, false);
248: // }
249: //
250: // /**
251: // * Write style definition to the device. Write only those contained
252: // * in the set.
253: // */
254: // public static void writeIncluding(Device d, Map map, Set l) throws IOException {
255: // writeFiltered(d, map, l, true);
256: // }
257:
258: /**
259: * Write style definition to the device
260: */
261: public void write(Device d) throws IOException {
262: d.print(toString());
263: }
264:
265: /**
266: * Converts the attribute set to a String.
267: *
268: * @return the string
269: */
270: @Override
271: public String toString() {
272: if (cachedStringRepresentation == null) {
273: final SStringBuilder builder = new SStringBuilder();
274: if (map != null) {
275: for (Map.Entry<CSSProperty, String> entry : map
276: .entrySet()) {
277: builder.append(entry.getKey());
278: builder.append(':');
279: builder.append(entry.getValue());
280: builder.append(';');
281: }
282: }
283: cachedStringRepresentation = builder.toString();
284: }
285: return cachedStringRepresentation;
286: }
287: }
|