001 /*
002 * This file is part of the Echo Point Project. This project is a
003 * collection of Components that have extended the Echo Web Application
004 * Framework Version 3.
005 *
006 * Version: MPL 1.1
007 *
008 * The contents of this file are subject to the Mozilla Public License Version
009 * 1.1 (the "License"); you may not use this file except in compliance with
010 * the License. You may obtain a copy of the License at
011 * http://www.mozilla.org/MPL/
012 *
013 * Software distributed under the License is distributed on an "AS IS" basis,
014 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
015 * for the specific language governing rights and limitations under the
016 * License.
017 */
018
019 package echopoint;
020
021 import echopoint.event.TagEvent;
022 import echopoint.internal.AbstractContainer;
023 import echopoint.model.Tag;
024 import nextapp.echo.app.Color;
025 import nextapp.echo.app.Component;
026 import nextapp.echo.app.event.ActionListener;
027
028 import java.util.ArrayList;
029 import java.util.Collection;
030 import java.util.Collections;
031 import java.util.LinkedHashMap;
032 import java.util.Map;
033
034 /**
035 * A <a href='http://en.wikipedia.org/wiki/Tag_cloud'>tag cloud</a> component
036 * based on client-side code contribued by Tod. Please note that the tag
037 * model objects specified for this component should have a unique name
038 * property. This component supports the
039 * following style properties in addition to those defined in {@link
040 * nextapp.echo.app.Component}:
041 *
042 * <ul>
043 * <li><code>rolloverEnabled</code> - A flag used to indicate that the tag
044 * components should support change of style on mouse rollover.</li>
045 * <li><code>rolloverBackground</code> - The colour to use as the background
046 * of the tag element over which the mouse hovers.</li>
047 * <li><code>rolloverForeground</code> - The colour to use for the title
048 * of the tag element over which the mouse hovers.</li>
049 * </ul>
050 *
051 * <p><b>Note:</b> There is a bug in how updates to the tags properties are
052 * handled by the update manager at present. For the time-being, please
053 * remove and re-add the tag cloud to its parent if the tags have been
054 * updated during an event cycle (see {@code TagCloudTest} for example).</p>
055 *
056 * <p>The following shows sample usage of this component:</p>
057 * <pre>
058 * import echopoint.TagCloud;
059 * import echopoint.event.TagEvent;
060 * import echopoint.model.Tag;
061 * import nextapp.echo.app.Row;
062 *
063 * ...
064 * final Collection<Tag> tags = new LinkedHashSet<Tag>();
065 * tags.add( new Tag( "Java", 50 ) );
066 * tags.add( new Tag( "Objective-C", 25 ) );
067 * tags.add( new Tag( "Groovy", 10 ) );
068 * tags.add( new Tag( "JavaScript", 15 ) );
069 *
070 * final Row row = new Row();
071 * final TagCloud tc = new TagCloud();
072 * tc.setRolloverEnabled( true );
073 * tc.setRolloverBackground( new Color( 0xa1a1a1 ) );
074 * tc.setRolloverForeground( new Color( 0xc1c1c1 ) );
075 * tc.setTags( tags );
076 * row.add( tc );
077 *
078 * tc.addActionListener( new ActionListener()
079 * {
080 * public void actionPerformed( final ActionEvent event )
081 * {
082 * final TagEvent te = (TagEvent) event;
083 * if ( te.getTag() != null )
084 * {
085 * final Component content = Application.getContent().getTestArea();
086 * content.add( new Label( "Clicked Tag: " + te.getTag().getName() ) );
087 * }
088 * }
089 * });
090 * </pre>
091 *
092 * @author Rakesh 2008-07-20
093 * @version $Id: TagCloud.java 204 2009-05-20 18:50:57Z sptrakesh $
094 */
095 public class TagCloud extends AbstractContainer
096 {
097 private static final long serialVersionUID = 1l;
098
099 /** A flag indicating whether rollover is enabled for a tag. */
100 public static final String PROPERTY_ROLLOVER_ENABLED = "rolloverEnabled";
101
102 /** The rollover background for the tag element. */
103 public static final String PROPERTY_ROLLOVER_BACKGROUND = "rolloverBackground";
104
105 /** The rollover foreground for the tag element. */
106 public static final String PROPERTY_ROLLOVER_FOREGROUND = "rolloverForeground";
107
108 /**
109 * The collection of {@link echopoint.model.Tag} instances to be
110 * represented in the component.
111 */
112 public static final String PROPERTY_TAGS = "tags";
113
114 /**
115 * <b>TagCloud</b> is <i>NOT</i> allowed to have any children.
116 *
117 * @see nextapp.echo.app.Component#isValidChild(nextapp.echo.app.Component)
118 */
119 @Override
120 public boolean isValidChild( final Component child )
121 {
122 return false;
123 }
124
125 /**
126 * Return the value of the {@link #PROPERTY_ROLLOVER_ENABLED} property.
127 *
128 * @return The flag indicating whether rollover behaviour is enabled or not.
129 */
130 public boolean getRolloverEnabled()
131 {
132 final Boolean enabled = (Boolean) get( PROPERTY_ROLLOVER_ENABLED );
133 return ( enabled != null ) ? enabled : false;
134 }
135
136 /**
137 * Set the value of the {@link #PROPERTY_ROLLOVER_ENABLED} property.
138 *
139 * @param enabled The flag indicating whether rollover behaviour is to be
140 * enabled or not.
141 */
142 public void setRolloverEnabled( final boolean enabled )
143 {
144 set( PROPERTY_ROLLOVER_ENABLED, enabled );
145 }
146
147 /**
148 * Return the value of the {@link #PROPERTY_ROLLOVER_BACKGROUND} property.
149 *
150 * @return The colour used as the background while rolling over the tag.
151 */
152 public Color getRolloverBackground()
153 {
154 return (Color) get( PROPERTY_ROLLOVER_BACKGROUND );
155 }
156
157 /**
158 * Set the value of the {@link #PROPERTY_ROLLOVER_BACKGROUND} property.
159 *
160 * @param background The colour used as the background while rolling over.
161 */
162 public void setRolloverBackground( final Color background )
163 {
164 set( PROPERTY_ROLLOVER_BACKGROUND, background );
165 }
166
167 /**
168 * Return the value of the {@link #PROPERTY_ROLLOVER_BACKGROUND} property.
169 *
170 * @return The colour used as the foreground while rolling over the tag.
171 */
172 public Color getRolloverForeground()
173 {
174 return (Color) get( PROPERTY_ROLLOVER_FOREGROUND );
175 }
176
177 /**
178 * Set the value of the {@link #PROPERTY_ROLLOVER_BACKGROUND} property.
179 *
180 * @param foreground The colour used as the foreground while rolling over.
181 */
182 public void setRolloverForeground( final Color foreground )
183 {
184 set( PROPERTY_ROLLOVER_FOREGROUND, foreground );
185 }
186
187 /**
188 * Return the value of the {@link #PROPERTY_TAGS} property.
189 *
190 * @return A read-only view of the collection of tags instances.
191 */
192 @SuppressWarnings( {"unchecked"} )
193 public Collection<Tag> getTags()
194 {
195 final Map<String,Tag> map = (Map<String,Tag>) get( PROPERTY_TAGS );
196 return Collections.unmodifiableCollection( map.values() );
197 }
198
199 /**
200 * Return the collection of tags that represent the model for this component.
201 *
202 * @return The collection of tag instances.
203 */
204 @SuppressWarnings( {"unchecked"} )
205 protected Collection<Tag> getData()
206 {
207 final Map<String,Tag> map = (Map<String,Tag>) get( PROPERTY_TAGS );
208 return new ArrayList<Tag>( map.values() );
209 }
210
211 /**
212 * Return the tag identified by its name.
213 *
214 * @param name The unique name for the tag.
215 * @return The tag model object or {@code null} if no such tag exists.
216 */
217 @SuppressWarnings( {"unchecked"} )
218 public Tag getTag( final String name )
219 {
220 final Map<String,Tag> map = (Map<String,Tag>) get( PROPERTY_TAGS );
221 return map.get( name );
222 }
223
224 /**
225 * Set the value of the {@link #PROPERTY_TAGS} property. Note that there
226 * is not way to individually add/delete tag instances other than setting
227 * a new collection (or a modified version of the original collection you
228 * used to set the property).
229 *
230 * @param tags The collection of tag instances to be represented in this
231 * component. Please note that a {@link java.util.Set} implementation
232 * is preferred since this implementation requires unique tag names.
233 */
234 public void setTags( final Collection<Tag> tags )
235 {
236 final Map<String,Tag> map = new LinkedHashMap<String,Tag>();
237
238 for ( Tag tag : tags )
239 {
240 map.put( tag.getName(), tag );
241 }
242
243 set( PROPERTY_TAGS, map );
244 }
245
246 /** {@inheritDoc} */
247 @Override
248 public void addActionListener( final ActionListener listener )
249 {
250 super.addActionListener( listener );
251 }
252
253 /** {@inheritDoc} */
254 public void removeActionListener( final ActionListener listener )
255 {
256 super.removeActionListener( listener );
257 }
258
259 /** {@inheritDoc} */
260 @Override
261 public boolean hasActionListeners()
262 {
263 return super.hasActionListeners();
264 }
265
266 /** {@inheritDoc} */
267 @Override
268 public void processInput( String name, Object value )
269 {
270 super.processInput( name, value );
271 if ( INPUT_ACTION.equals( name ) )
272 {
273 final Tag tag = getTag( (String) value );
274 fireActionPerformed( new TagEvent( this, tag.getName(), tag ) );
275 }
276 }
277 }