KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > nextapp > echo2 > app > MutableStyle


1 /*
2  * This file is part of the Echo Web Application Framework (hereinafter "Echo").
3  * Copyright (C) 2002-2005 NextApp, Inc.
4  *
5  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * Alternatively, the contents of this file may be used under the terms of
18  * either the GNU General Public License Version 2 or later (the "GPL"), or
19  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
20  * in which case the provisions of the GPL or the LGPL are applicable instead
21  * of those above. If you wish to allow use of your version of this file only
22  * under the terms of either the GPL or the LGPL, and not to allow others to
23  * use your version of this file under the terms of the MPL, indicate your
24  * decision by deleting the provisions above and replace them with the notice
25  * and other provisions required by the GPL or the LGPL. If you do not delete
26  * the provisions above, a recipient may use your version of this file under
27  * the terms of any one of the MPL, the GPL or the LGPL.
28  */

29
30 package nextapp.echo2.app;
31
32 import java.io.Serializable JavaDoc;
33 import java.util.Iterator JavaDoc;
34 import java.util.SortedMap JavaDoc;
35 import java.util.TreeMap JavaDoc;
36
37 /**
38  * A <code>Style</code> implementation which may be modified.
39  * Note that modifications to the <code>Style</code> will not necessarily be
40  * reflected in <code>Component</code>s that use the <code>Style</code>
41  * unless the <code>Component</code>s are specifically informed of the changes,
42  * i.e., by resetting the shared style of a <code>Component</code>.
43  * As such, shared <code>Style</code>s should not be updated once they are
44  * in use by <code>Component</code>s, as it will result in undefined behavior.
45  */

46 public class MutableStyle
47 implements Style {
48     
49     private static final int GROW_RATE = 5 * 2; // Must be a multiple of 2.
50

51     private static final Object JavaDoc[] EMPTY = new Object JavaDoc[0];
52     
53     /**
54      * An <code>Iterator</code> which returns the names of properties which
55      * are set in the style.
56      */

57     private class PropertyNameIterator
58     implements Iterator JavaDoc {
59
60         private int index = 0;
61         
62         /**
63          * @see java.util.Iterator#hasNext()
64          */

65         public boolean hasNext() {
66             return index < length;
67         }
68         
69         /**
70          * @see java.util.Iterator#next()
71          */

72         public Object JavaDoc next() {
73             Object JavaDoc value = data[index];
74             index += 2;
75             return value;
76         }
77
78         /**
79          * @see java.util.Iterator#remove()
80          */

81         public void remove() {
82             throw new UnsupportedOperationException JavaDoc();
83         }
84     }
85     
86     /**
87      * A value object which stores the indexed values of a property.
88      */

89     public class IndexedPropertyValue
90     implements Serializable JavaDoc {
91
92         private SortedMap JavaDoc indicesToValues;
93         
94         /**
95          * Returns the value at the specified index.
96          *
97          * @param index the index
98          * @return the value
99          */

100         public Object JavaDoc getValue(int index) {
101             if (indicesToValues == null) {
102                 return null;
103             } else {
104                 return indicesToValues.get(new Integer JavaDoc(index));
105             }
106         }
107         
108         /**
109          * Returns the set property indices as an
110          * <code>Integer</code>-returning <code>Iterator</code>.
111          *
112          * @return an iterator over the indices
113          */

114         public Iterator JavaDoc getIndices() {
115             return indicesToValues.keySet().iterator();
116         }
117         
118         /**
119          * Determines if a value is set at the specified index.
120          *
121          * @param index the index
122          * @return true if a value is set
123          */

124         public boolean hasValue(int index) {
125             return indicesToValues != null && indicesToValues.containsKey(new Integer JavaDoc(index));
126         }
127         
128         /**
129          * Removes the value at the specified index.
130          *
131          * @param index the index
132          */

133         private void removeValue(int index) {
134             if (indicesToValues != null) {
135                 indicesToValues.remove(new Integer JavaDoc(index));
136                 if (indicesToValues.size() == 0) {
137                     indicesToValues = null;
138                 }
139             }
140         }
141         
142         /**
143          * Sets the value at the specified index.
144          *
145          * @param index the index
146          * @param value the new property value
147          */

148         private void setValue(int index, Object JavaDoc value) {
149             if (indicesToValues == null) {
150                 indicesToValues = new TreeMap JavaDoc();
151             }
152             indicesToValues.put(new Integer JavaDoc(index), value);
153         }
154     }
155     
156     private Object JavaDoc[] data = EMPTY;
157     int length = 0; // Number of items * 2;
158

159     /**
160      * Default constructor.
161      */

162     public MutableStyle() {
163         super();
164     }
165     
166     /**
167      * Adds the content of the specified style to this style.
168      *
169      * @param style the style to add
170      */

171     public void addStyleContent(Style style) {
172         Iterator JavaDoc nameIt = style.getPropertyNames();
173         while (nameIt.hasNext()) {
174             String JavaDoc name = (String JavaDoc) nameIt.next();
175             Object JavaDoc value = style.getProperty(name);
176             if (value instanceof IndexedPropertyValue) {
177                 IndexedPropertyValue indexedPropertyValue = (IndexedPropertyValue) value;
178                 Iterator JavaDoc indexIt = indexedPropertyValue.getIndices();
179                 while (indexIt.hasNext()) {
180                     int index = ((Integer JavaDoc) indexIt.next()).intValue();
181                     setIndexedProperty(name, index, indexedPropertyValue.getValue(index));
182                 }
183             } else {
184                 setProperty(name, value);
185             }
186         }
187     }
188     
189     /**
190      * @see nextapp.echo2.app.Style#getIndexedProperty(java.lang.String, int)
191      */

192     public Object JavaDoc getIndexedProperty(String JavaDoc propertyName, int propertyIndex) {
193         Object JavaDoc value = retrieveProperty(propertyName);
194         if (!(value instanceof IndexedPropertyValue)) {
195             return null;
196         }
197         return ((IndexedPropertyValue) value).getValue(propertyIndex);
198     }
199     
200     /**
201      * @see nextapp.echo2.app.Style#getProperty(java.lang.String)
202      */

203     public Object JavaDoc getProperty(String JavaDoc propertyName) {
204         return retrieveProperty(propertyName);
205     }
206     
207     /**
208      * @see nextapp.echo2.app.Style#getPropertyIndices(java.lang.String)
209      */

210     public Iterator JavaDoc getPropertyIndices(String JavaDoc propertyName) {
211         Object JavaDoc value = getProperty(propertyName);
212         if (!(value instanceof IndexedPropertyValue)) {
213             return null;
214         }
215         return ((IndexedPropertyValue) value).getIndices();
216     }
217     
218     /**
219      * @see nextapp.echo2.app.Style#getPropertyNames()
220      */

221     public Iterator JavaDoc getPropertyNames() {
222         return new PropertyNameIterator();
223     }
224     
225     /**
226      * @see nextapp.echo2.app.Style#isIndexedPropertySet(java.lang.String, int)
227      */

228     public boolean isIndexedPropertySet(String JavaDoc propertyName, int index) {
229         Object JavaDoc value = retrieveProperty(propertyName);
230         if (!(value instanceof IndexedPropertyValue)) {
231             return false;
232         }
233         return ((IndexedPropertyValue) value).hasValue(index);
234     }
235     
236     /**
237      * @see nextapp.echo2.app.Style#isPropertySet(java.lang.String)
238      */

239     public boolean isPropertySet(String JavaDoc propertyName) {
240         int propertyNameHashCode = propertyName.hashCode();
241         for (int i = 0; i < length; i += 2) {
242             if (propertyNameHashCode == data[i].hashCode() && propertyName.equals(data[i])) {
243                 return true;
244             }
245         }
246         return false;
247     }
248     
249     /**
250      * Removes a value of an indexed property from the <code>Style</code>.
251      *
252      * @param propertyName the name of the property
253      * @param propertyIndex the index of the property to remove
254      */

255     public void removeIndexedProperty(String JavaDoc propertyName, int propertyIndex) {
256         Object JavaDoc value = retrieveProperty(propertyName);
257         if (!(value instanceof IndexedPropertyValue)) {
258             return;
259         }
260         ((IndexedPropertyValue) value).removeValue(propertyIndex);
261     }
262     
263     /**
264      * Removes a property from the <code>Style</code>.
265      *
266      * @param propertyName the name of the property to remove
267      */

268     public void removeProperty(String JavaDoc propertyName) {
269         int propertyNameHashCode = propertyName.hashCode();
270         for (int i = 0; i < length; i += 2) {
271             if (propertyNameHashCode == data[i].hashCode() && propertyName.equals(data[i])) {
272                 data[i] = data[length - 2];
273                 data[i + 1] = data[length - 1];
274                 data[length - 2] = null;
275                 data[length - 1] = null;
276                 length -= 2;
277                 break;
278             }
279         }
280         
281         if (length == 0) {
282             data = EMPTY;
283         }
284     }
285     
286     /**
287      * Retrieves locally stored value of property.
288      *
289      * @param propertyName the name of the property
290      * @return the value of the property
291      */

292     private Object JavaDoc retrieveProperty(String JavaDoc propertyName) {
293         int propertyNameHashCode = propertyName.hashCode();
294         for (int i = 0; i < length; i += 2) {
295             if (propertyNameHashCode == data[i].hashCode() && propertyName.equals(data[i])) {
296                 return data[i + 1];
297             }
298         }
299         return null;
300     }
301     
302     /**
303      * Sets an indexed property of the <code>Style</code>
304      *
305      * @param propertyName the name of the property
306      * @param propertyIndex the index of the property
307      * @param propertyValue the value of the property
308      */

309     public void setIndexedProperty(String JavaDoc propertyName, int propertyIndex, Object JavaDoc propertyValue) {
310         Object JavaDoc value = retrieveProperty(propertyName);
311         if (!(value instanceof IndexedPropertyValue)) {
312             value = new IndexedPropertyValue();
313             setProperty(propertyName, value);
314         }
315         ((IndexedPropertyValue) value).setValue(propertyIndex, propertyValue);
316     }
317     
318     /**
319      * Sets a property of the <code>Style</code>.
320      * If <code>propertyValue</code> is null, the property will be
321      * removed.
322      *
323      * @param propertyName the name of the property
324      * @param propertyValue the value of the property
325      */

326     public void setProperty(String JavaDoc propertyName, Object JavaDoc propertyValue) {
327         if (propertyValue == null) {
328             removeProperty(propertyName);
329             return;
330         }
331         
332         if (data == EMPTY) {
333             data = new Object JavaDoc[GROW_RATE];
334         }
335
336         int propertyNameHashCode = propertyName.hashCode();
337         for (int i = 0; i < data.length; i += 2) {
338             if (data[i] == null) {
339                 // Property is not set, space remains to set property.
340
// Add property at end.
341
data[i] = propertyName;
342                 data[i + 1] = propertyValue;
343                 length += 2;
344                 return;
345             }
346             if (propertyNameHashCode == data[i].hashCode() && propertyName.equals(data[i])) {
347                 // Found property, overwrite.
348
data[i + 1] = propertyValue;
349                 return;
350             }
351         }
352         
353         // Array is full: grow array.
354
Object JavaDoc[] newData = new Object JavaDoc[data.length + GROW_RATE];
355         System.arraycopy(data, 0, newData, 0, data.length);
356         
357         newData[data.length] = propertyName;
358         newData[data.length + 1] = propertyValue;
359         length += 2;
360         data = newData;
361     }
362     
363     /**
364      * Returns the number of properties set.
365      *
366      * @return the number of properties set
367      */

368     public int size() {
369         return length / 2;
370     }
371     
372     /**
373      * Returns a debug representation.
374      *
375      * @see java.lang.Object#toString()
376      */

377     public String JavaDoc toString() {
378         StringBuffer JavaDoc out = new StringBuffer JavaDoc("MutableStyle {");
379         for (int i = 0; i < length; i += 2) {
380             out.append(data[i]);
381             out.append("=");
382             out.append(data[i + 1]);
383             if (i < length - 2) {
384                 out.append(", ");
385             }
386         }
387         out.append("}");
388         return out.toString();
389     }
390 }
391
Popular Tags