001    package com.sptci.echo2.style;
002    
003    import java.util.Map;
004    import java.util.concurrent.ConcurrentHashMap;
005    
006    import nextapp.echo2.app.Extent;
007    
008    /**
009     * A custom font class to use in styles.  This class by default uses
010     * {@link #TYPEFACE} as the {@link nextapp.echo2.app.Font.Typeface} and ensures
011     * consistent font typeface across the application.  It is recomended that you
012     * use the {@link #getInstance} method or its overloaded derivatives to avoid
013     * replication across sessions.
014     *
015     * <p>The following shows the recommended way to use this class:</p>
016     * <pre>
017     *   import com.sptci.echo2.style.Extent;
018     *   import com.sptci.echo2.style.Font;
019     *
020     *     ...
021     *     Font normalFont = Font.getInstance();
022     *     Font largeFont = Font.getInstance( Extent.getInstance( 14 ) );
023     *     Font boldFont = Font.getInstance( Font.BOLD );
024     * </pre>
025     *
026     * <p>&copy; Copyright 2006 Sans Pareil Technologies, Inc.</p>
027     * @author Rakesh Vidyadharan 2006-11-06
028     * @version $Id: Font.java 3334 2007-06-08 16:25:49Z rakesh $
029     */
030    public class Font extends nextapp.echo2.app.Font
031    {
032      /**
033       * The application wide default typeface.
034       */
035      public static final Typeface TYPEFACE = 
036        new Typeface( "Helvetica", new Typeface( "Verdana", TIMES_ROMAN ) );
037    
038      /**
039       * The default font size to use.
040       */
041      public static final Extent SIZE =
042          com.sptci.echo2.style.Extent.getInstance( 12, Extent.PX );
043    
044      /**
045       * The default font style to use.
046       */
047      public static final int STYLE = Font.PLAIN;
048      
049      /**
050       * The cache of reusable font instances.  A nested map structure is used
051       * to allow for future management based upon {@link
052       * nextapp.echo2.app.Font.Typeface} values.
053       */
054      protected static final Map<String,Map<String,Font>> cache =
055          new ConcurrentHashMap<String,Map<String,Font>>();
056      
057      /**
058       * The nested map used to store the fonts for the default {@link #TYPEFACE}.
059       */
060      protected static final Map<String,Font> defaultCache = getMap( getKey( TYPEFACE ) );
061    
062      /**
063       * Create a new instance of the font using the defaults for style
064       * and size.
065       *
066       * @deprecated Use {@link #getInstance()} instead.
067       */
068      @Deprecated public Font()
069      {
070        this( STYLE, SIZE );
071      }
072    
073      /**
074       * Create a new instance of the font using the specified style and
075       * default size.
076       *
077       * @deprecated Use {@link #getInstance( int )} instead.
078       * @param style The style to use for the font.  Styles are usually
079       *   specified using the constants in the {@link nextapp.echo2.app.Font}
080       *   class.
081       */
082      @Deprecated public Font( final int style )
083      {
084        this( style, SIZE );
085      }
086    
087      /**
088       * Create a new instance of the font using the specified size and
089       * default style.
090       *
091       * @deprecated Use {@link #getInstance( Extent )} instead.
092       * @param size The font size to use.
093       */
094      @Deprecated public Font( final Extent size )
095      {
096        this( STYLE, size );
097      }
098    
099      /**
100       * Create a new instance of the font using the specified style and
101       * size.
102       *
103       * @deprecated Use {@link #getInstance( int, Extent )} instead.
104       * @param style The style to use for the font.  Styles are usually
105       *   specified using the constants in the {@link nextapp.echo2.app.Font}
106       *   class.
107       * @param size The font size to use.
108       */
109      @Deprecated public Font( final int style, final Extent size )
110      {
111        super( TYPEFACE, style, size );
112      }
113      
114      /**
115       * Create a new instance of the font using the specified typeface chain,
116       * style and size.
117       *
118       * @deprecated Use {@link #getInstance( Font.Typeface, int, Extent )} instead.
119       * @param typeface The typeface chain to use for the font.
120       * @param style The style to use for the font.  Styles are usually
121       *   specified using the constants in the {@link nextapp.echo2.app.Font}
122       *   class.
123       * @param size The font size to use.
124       */
125      @Deprecated public Font( final Typeface typeface, final int style,
126          final Extent size )
127      {
128        super( typeface, style, size );
129      }
130        
131      /**
132       * Factory method to use to retrieve the cached default font instance.
133       * 
134       * @see #getInstance( int, Extent )
135       */
136      public static Font getInstance()
137      {
138        return getInstance( STYLE, SIZE );
139      }
140      
141      /**
142       * Factory method to use to retrieve a cached font instance.
143       * 
144       * <p><b>Note:</b> This method can be refactored to delegate to {@link
145       * #getInstance( Font.Typeface, Extent )}, however has been left as a separate
146       * implementation to avoid the lookup process involved in {@link
147       * #getKey}.</p>
148       * 
149       * @see #getKey( Extent )
150       * @see #defaultCache
151       * @param size The font size to use.
152       */
153      public static Font getInstance( final Extent size )
154      { 
155        final String key = getKey( size );
156        Font font = defaultCache.get( key );
157        
158        if ( font == null )
159        {
160          font = new Font( size );
161          defaultCache.put( key, font );
162        }
163        
164        return font;
165      }
166      
167      /**
168       * Factory method to use to retrieve a cached font instance.
169       * 
170       * @see #getInstance( int, Extent )
171       * @param style The style to use for the font.  Styles are usually
172       *   specified using the constants in the {@link nextapp.echo2.app.Font}
173       *   class.
174       */
175      public static Font getInstance( final int style )
176      {
177        return getInstance( style, SIZE );
178      }
179      
180      /**
181       * Factory method to use to retrieve a cached font instance.
182       * 
183       * <p><b>Note:</b> This method can be refactored to delegate to {@link
184       * #getInstance( Font.Typeface, int, Extent )}, however has been left as a
185       * separate implementation to avoid the normalisation process involved in
186       * {@link #getKey}.</p>
187       * 
188       * @see #getKey( int, Extent )
189       * @see #defaultCache
190       * @param style The style to use for the font.  Styles are usually
191       *   specified using the constants in the {@link nextapp.echo2.app.Font}
192       *   class.
193       * @param size The font size to use.
194       */
195      public static Font getInstance( final int style, final Extent size )
196      {   
197        final String key = getKey( style, size );
198        Font font = defaultCache.get( key );
199        
200        if ( font == null )
201        {
202          font = new Font( style, size );
203          defaultCache.put( key, font );
204        }
205        
206        return font;
207      }
208      
209      /**
210       * Factory method to use to retrieve a cached font instance.
211       *
212       * @deprecated Warning, you are creating a non-standard font.
213       * @see #getKey( Font.Typeface )
214       * @see #getKey( Extent )
215       * @see #getMap
216       * @param typeface The typeface chain to use for the font.
217       * @param size The font size to use.
218       */
219      public static Font getInstance( final Typeface typeface, final Extent size )
220      {
221        final Map<String,Font> map = getMap( getKey( typeface ) );    
222        final String key = getKey( size );
223        Font font = map.get( key );
224        
225        if ( font == null )
226        {
227          font = new Font( size );
228          map.put( key, font );
229        }
230        
231        return font;
232      }
233      
234      /**
235       * Factory method to use to retrieve a cached font instance.
236       *
237       * @deprecated Warning, you are creating a non-standard font.
238       * @param typeface The typeface chain to use for the font.
239       * @param style The style to use for the font.  Styles are usually
240       *   specified using the constants in the {@link nextapp.echo2.app.Font}
241       *   class.
242       * @param size The font size to use.
243       */
244      public static Font getInstance( final Typeface typeface, final int style,
245          final Extent size )
246      {
247        final Map<String,Font> map = getMap( getKey( typeface ) );    
248        final String key = getKey( style, size );
249        Font font = map.get( key );
250        
251        if ( font == null )
252        {
253          font = new Font( style, size );
254          map.put( key, font );
255        }
256        
257        return font;
258      }
259      
260      /**
261       * Return a key for the extent specified.
262       *
263       * @param size The extent whose key is to be returned.
264       * @return The normalised key for the extent.
265       */
266      protected static String getKey( final Extent size )
267      {  
268        return size.toString();
269      }
270       
271      /**
272       * Return a key for the style and extent specified.
273       *
274       * @param style The style to use for the font.
275       * @param size The extent whose key is to be returned.
276       * @return The normalised key for the extent.
277       */
278      protected static String getKey( final int style, final Extent size )
279      {
280        final StringBuilder builder = new StringBuilder();
281        builder.append( style ).append( "::" ).append( size.toString() );
282        return builder.toString();
283      }
284      
285      /**
286       * Return a key for the {@link nextapp.echo2.app.Font.Typeface}
287       * chain.
288       *
289       * @param typeface The typeface whose key chain is to be returned.
290       * @return The key for the typeface chain.
291       */
292      protected static String getKey( final Typeface typeface )
293      {
294        final StringBuilder builder = new StringBuilder();
295        Typeface tf = typeface;
296        builder.append( tf.getName() ).append( "," );
297           
298        while( ( tf = tf.getAlternate() ) != null )
299        {
300          builder.append( tf.getName() ).append( "," );
301        }
302        
303        return builder.toString();
304      }
305      
306      /**
307       * Return the embedded {@link java.util.Map} value in {@link #cache}.
308       *
309       * @param typeface The key for the {@link nextapp.echo2.app.Font.Typeface}.
310       * @return The embedded map.
311       */
312      protected static Map<String,Font> getMap( String typeface )
313      {
314        Map<String,Font> map = cache.get( typeface );
315        
316        if ( map == null )
317        {
318          map = new ConcurrentHashMap<String,Font>();
319          cache.put( typeface, map );
320        }
321        
322        return map;
323      }
324    }