View Javadoc

1   package org.apache.maven.doxia.sink;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.Collections;
23  import java.util.Enumeration;
24  import java.util.LinkedHashMap;
25  import java.util.Map;
26  
27  import javax.swing.text.AttributeSet;
28  
29  /**
30   * Implementation of MutableAttributeSet using a LinkedHashMap.
31   *
32   * @author ltheussl
33   * @version $Id: SinkEventAttributeSet.java 1185112 2011-10-17 11:33:00Z ltheussl $
34   * @since 1.1
35   */
36  public class SinkEventAttributeSet
37      implements SinkEventAttributes, Cloneable
38  {
39      /**
40       * An unmodifiable attribute set containing only an underline attribute.
41       */
42      public static final SinkEventAttributes UNDERLINE;
43  
44      /**
45       * An unmodifiable attribute set containing only an overline attribute.
46       */
47      public static final SinkEventAttributes OVERLINE;
48  
49      /**
50       * An unmodifiable attribute set containing only a linethrough attribute.
51       */
52      public static final SinkEventAttributes LINETHROUGH;
53  
54      /**
55       * An unmodifiable attribute set containing only a boxed attribute.
56       */
57      public static final SinkEventAttributes BOXED;
58  
59      /**
60       * An unmodifiable attribute set containing only a bold attribute.
61       */
62      public static final SinkEventAttributes BOLD;
63  
64      /**
65       * An unmodifiable attribute set containing only an italic attribute.
66       */
67      public static final SinkEventAttributes ITALIC;
68  
69      /**
70       * An unmodifiable attribute set containing only a monospaced attribute.
71       */
72      public static final SinkEventAttributes MONOSPACED;
73  
74      /**
75       * An unmodifiable attribute set containing only a left attribute.
76       */
77      public static final SinkEventAttributes LEFT;
78  
79      /**
80       * An unmodifiable attribute set containing only a right attribute.
81       */
82      public static final SinkEventAttributes RIGHT;
83  
84      /**
85       * An unmodifiable attribute set containing only a center attribute.
86       */
87      public static final SinkEventAttributes CENTER;
88  
89      /**
90       * An unmodifiable attribute set containing only a justify attribute.
91       */
92      public static final SinkEventAttributes JUSTIFY;
93  
94  
95      static
96      {
97          UNDERLINE = new SinkEventAttributeSet( new String[] {DECORATION, "underline"} ).unmodifiable();
98          OVERLINE = new SinkEventAttributeSet( new String[] {DECORATION, "overline"} ).unmodifiable();
99          LINETHROUGH = new SinkEventAttributeSet( new String[] {DECORATION, "line-through"} ).unmodifiable();
100         BOXED = new SinkEventAttributeSet( new String[] {DECORATION, "boxed"} ).unmodifiable();
101 
102         BOLD = new SinkEventAttributeSet( new String[] {STYLE, "bold"} ).unmodifiable();
103         ITALIC = new SinkEventAttributeSet( new String[] {STYLE, "italic"} ).unmodifiable();
104         MONOSPACED = new SinkEventAttributeSet( new String[] {STYLE, "monospaced"} ).unmodifiable();
105 
106         LEFT = new SinkEventAttributeSet( new String[] {ALIGN, "left"} ).unmodifiable();
107         RIGHT = new SinkEventAttributeSet( new String[] {ALIGN, "right"} ).unmodifiable();
108         CENTER = new SinkEventAttributeSet( new String[] {ALIGN, "center"} ).unmodifiable();
109         JUSTIFY = new SinkEventAttributeSet( new String[] {ALIGN, "justify"} ).unmodifiable();
110     }
111 
112     private Map<String, Object> attribs;
113 
114     private AttributeSet resolveParent;
115 
116     /**
117      * Constructs a new, empty SinkEventAttributeSet with default size 5.
118      */
119     public SinkEventAttributeSet()
120     {
121         this( 5 );
122     }
123 
124     /**
125      * Constructs a new, empty SinkEventAttributeSet with the specified initial size.
126      *
127      * @param size the initial number of attribs.
128      */
129     public SinkEventAttributeSet( int size )
130     {
131         attribs = new LinkedHashMap<String, Object>( size );
132     }
133 
134     /**
135      * Constructs a new SinkEventAttributeSet with the attribute name-value
136      * mappings as given by the specified String array.
137      *
138      * @param attributes the specified String array. If the length of this array
139      * is not an even number, an IllegalArgumentException is thrown.
140      */
141     public SinkEventAttributeSet( String[] attributes )
142     {
143         int n = attributes.length;
144 
145         if ( ( n % 2 ) != 0 )
146         {
147             throw new IllegalArgumentException( "Missing attribute!" );
148         }
149 
150         attribs = new LinkedHashMap<String, Object>( n / 2 );
151 
152         for ( int i = 0; i < n; i += 2 )
153         {
154             attribs.put( attributes[i], attributes[i + 1] );
155         }
156     }
157 
158     /**
159      * Constructs a new SinkEventAttributeSet with the same attribute name-value
160      * mappings as in the specified AttributeSet.
161      *
162      * @param attributes the specified AttributeSet.
163      */
164     public SinkEventAttributeSet( AttributeSet attributes )
165     {
166         attribs = new LinkedHashMap<String, Object>( attributes.getAttributeCount() );
167 
168         Enumeration<?> names = attributes.getAttributeNames();
169 
170         while ( names.hasMoreElements() )
171         {
172             Object name = names.nextElement();
173 
174             attribs.put( name.toString(), attributes.getAttribute( name ) );
175         }
176     }
177 
178     /**
179      * Replace this AttributeSet by an unmodifiable view of itself.
180      * Any subsequent attempt to add, remove or modify the underlying mapping
181      * will result in an UnsupportedOperationException.
182      *
183      * @return an unmodifiable view of this AttributeSet.
184      *
185      * @since 1.1.1
186      */
187     public SinkEventAttributeSet unmodifiable()
188     {
189         this.attribs = Collections.unmodifiableMap( attribs );
190 
191         return this;
192     }
193 
194     /**
195      * Checks whether the set of attribs is empty.
196      *
197      * @return true if the set is empty.
198      */
199     public boolean isEmpty()
200     {
201         return attribs.isEmpty();
202     }
203 
204     /** {@inheritDoc} */
205     public int getAttributeCount()
206     {
207         return attribs.size();
208     }
209 
210     /** {@inheritDoc} */
211     public boolean isDefined( Object attrName )
212     {
213         return attribs.containsKey( attrName );
214     }
215 
216     /** {@inheritDoc} */
217     public boolean isEqual( AttributeSet attr )
218     {
219         return ( ( getAttributeCount() == attr.getAttributeCount() )
220                 && containsAttributes( attr ) );
221     }
222 
223     /** {@inheritDoc} */
224     public AttributeSet copyAttributes()
225     {
226         return ( (AttributeSet) clone() );
227     }
228 
229     /** {@inheritDoc} */
230     public Enumeration<String> getAttributeNames()
231     {
232         return Collections.enumeration( attribs.keySet() );
233     }
234 
235     /** {@inheritDoc} */
236     public Object getAttribute( Object key  )
237     {
238         Object value = attribs.get( key  );
239 
240         if ( value == null )
241         {
242             AttributeSet parent = getResolveParent();
243 
244             if ( parent != null )
245             {
246                 value = parent.getAttribute( key  );
247             }
248         }
249 
250         return value;
251     }
252 
253     /** {@inheritDoc} */
254     public boolean containsAttribute( Object name, Object value )
255     {
256         return value.equals( getAttribute( name ) );
257     }
258 
259     /** {@inheritDoc} */
260     public boolean containsAttributes( AttributeSet attributes )
261     {
262         boolean result = true;
263 
264         Enumeration<?> names = attributes.getAttributeNames();
265 
266         while ( result && names.hasMoreElements() )
267         {
268             Object name = names.nextElement();
269             result = attributes.getAttribute( name ).equals( getAttribute( name ) );
270         }
271 
272         return result;
273     }
274 
275     /**
276      * {@inheritDoc}
277      *
278      * Adds an attribute with the given name and value.
279      */
280     public void addAttribute( Object name, Object value )
281     {
282         attribs.put( name.toString(), value );
283     }
284 
285     /** {@inheritDoc} */
286     public void addAttributes( AttributeSet attributes  )
287     {
288         if ( attributes == null || attributes.getAttributeCount() == 0 )
289         {
290             return;
291         }
292 
293         Enumeration<?> names = attributes.getAttributeNames();
294 
295         while ( names.hasMoreElements() )
296         {
297             Object name = names.nextElement();
298 
299             addAttribute( name, attributes.getAttribute( name ) );
300         }
301     }
302 
303     /** {@inheritDoc} */
304     public void removeAttribute( Object name )
305     {
306         attribs.remove( name );
307     }
308 
309     /** {@inheritDoc} */
310     public void removeAttributes( Enumeration<?> names )
311     {
312         while ( names.hasMoreElements() )
313         {
314             removeAttribute( names.nextElement() );
315         }
316     }
317 
318     /** {@inheritDoc} */
319     public void removeAttributes( AttributeSet attributes  )
320     {
321         if ( attributes == null )
322         {
323             return;
324         }
325         else if ( attributes == this )
326         {
327             attribs.clear();
328         }
329         else
330         {
331             Enumeration<?> names = attributes.getAttributeNames();
332 
333             while ( names.hasMoreElements() )
334             {
335                 Object name = names.nextElement();
336                 Object value = attributes.getAttribute( name );
337 
338                 if ( value.equals( getAttribute( name ) ) )
339                 {
340                     removeAttribute( name );
341                 }
342             }
343         }
344     }
345 
346     /** {@inheritDoc} */
347     public AttributeSet getResolveParent()
348     {
349         return this.resolveParent;
350     }
351 
352     /** {@inheritDoc} */
353     public void setResolveParent( AttributeSet parent )
354     {
355         this.resolveParent = parent;
356     }
357 
358     /** {@inheritDoc} */
359     @Override
360     public Object clone()
361     {
362         SinkEventAttributeSet attr = new SinkEventAttributeSet( attribs.size() );
363         attr.attribs = new LinkedHashMap<String, Object>( attribs );
364 
365         if ( resolveParent != null )
366         {
367             attr.resolveParent = resolveParent.copyAttributes();
368         }
369 
370         return attr;
371     }
372 
373     /** {@inheritDoc} */
374     @Override
375     public int hashCode()
376     {
377         final int parentHash = ( resolveParent == null ? 0 : resolveParent.hashCode() );
378 
379         return attribs.hashCode() + parentHash;
380     }
381 
382     /** {@inheritDoc} */
383     @Override
384     public boolean equals( Object obj )
385     {
386         if ( this == obj )
387         {
388             return true;
389         }
390 
391         if ( obj instanceof SinkEventAttributeSet )
392         {
393             return isEqual( (SinkEventAttributeSet) obj  );
394         }
395 
396         return false;
397     }
398 
399     /** {@inheritDoc} */
400     @Override
401     public String toString()
402     {
403         StringBuilder s = new StringBuilder();
404         Enumeration<String> names = getAttributeNames();
405 
406         while ( names.hasMoreElements() )
407         {
408             String key = names.nextElement();
409             String value = getAttribute( key ).toString();
410 
411             s.append( ' ' ).append( key ).append( '=' ).append( value );
412         }
413 
414         return s.toString();
415     }
416 
417 }