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    package echopoint;
019    
020    import nextapp.echo.app.ImageReference;
021    import nextapp.echo.app.event.ActionEvent;
022    
023    import echopoint.internal.AbstractImage;
024    import echopoint.model.MapSection;
025    
026    import java.util.Collection;
027    import java.util.Collections;
028    import java.util.LinkedHashMap;
029    import java.util.Map;
030    
031    /**
032     * The <code>ImageMap</code> class provides a {@link nextapp.echo.app.Component}
033     * that allows a user to click on region(s) within a provided region.
034     *
035     * <p>A series of {@link echopoint.model.MapSection} instances are specified
036     * that indicate what areas on the region should produce an
037     * {@link nextapp.echo.app.event.ActionEvent}.</p>
038     *
039     * <p>The {@link echopoint.model.MapSection} instances are stored in a map
040     * keyed by by their {@link echopoint.model.MapSection#actionCommand} string.
041     * This means that there can be at  most one set of coordinates for a given
042     * {@link echopoint.model.MapSection#actionCommand}.</p>
043     *
044     * <p><b>Note:</b> Development of this component was sponsored by
045     * <a href='http://tcnbroadcasting.com/index.jsp' target='_top'>TCN
046     * Broadcasting</a>.  We are grateful for their support and sponsorship.</p>
047     *
048     * <p>The following shows sample usage of this component:</p>
049     * <pre>
050     *   import echopoint.ImageMap;
051     *   import echopoint.model.Point;
052     *   import echopoint.model.MapSection;
053     *   import echopoint.model.CircleSection;
054     *   import echopoint.model.RectangleSection;
055     *
056     *     ...
057     *     final Column column = new Column();
058     *     final String url = "image/imagemap.gif";
059     *     final ImageMap map = new ImageMap( url );
060     *     map.addActionListener( ... );
061     *
062     *     final Collection&lt;MapSection&gt; sections = new ArrayList&lt;MapSection&gt;();
063     *     sections.add( new CircleSection( new Point( 10, 10 ), 25, "circle" );
064     *     sections.add( new RectangleSection( new Point( 10, 10 ),
065     *        new Point( 25, 25 ), "rectangle", "Rectangular area" );
066     *     map.addSections( sections );
067     *
068     *     column.add( map );
069     * </pre>
070     *
071     * @author Rakesh 2008-10-19, Brad Baker (originally for EPNG)
072     * @version $Id: ImageMap.java 262 2009-12-18 21:29:16Z sptrakesh $
073     */
074    public class ImageMap extends AbstractImage
075    {
076      private static final long serialVersionUID = 1l;
077    
078      /**
079       * The map of {@link echopoint.model.MapSection}
080       * instances that represents the clickable sections in the map.  Note that
081       * this property is to be treated as read-only.
082       */
083      public static final String PROPERTY_SECTIONS = "sections";
084    
085      /** The action command that was triggered by user interaction with map. */
086      protected String actionCommand;
087    
088      /** Default constructor. */
089      public ImageMap() {}
090    
091      /**
092       * Create a new image map using the specified image to use as the region.
093       *
094       * @param image The image to use as the map region.
095       */
096      public ImageMap( final ImageReference image )
097      {
098        setImage( image );
099      }
100    
101      /**
102       * Create a new image map using the image from the specified URL.
103       *
104       * @param url The url to use as the source of the image to use in the map.
105       */
106      public ImageMap( final String url )
107      {
108        setImage( url );
109      }
110    
111      /**
112       * Return the value of the {@link #PROPERTY_SECTIONS} property.
113       *
114       * @return A read-only view of the  sections of the map configured for actions.
115       */
116      @SuppressWarnings( {"unchecked"} )
117      public Map<String,MapSection> getSections()
118      {
119        return Collections.unmodifiableMap(
120            (Map<String,MapSection>) get( PROPERTY_SECTIONS ) );
121      }
122    
123      /**
124       * Set the value of the {@link #PROPERTY_SECTIONS} property.
125       *
126       * @see #addSections
127       * @see #addSection
128       * @param sections The image to use as the map region.
129       */
130      public void setSections( final Map<String,MapSection> sections )
131      {
132        final LinkedHashMap<String,MapSection> map =
133            new LinkedHashMap<String,MapSection>( sections );
134        set( PROPERTY_SECTIONS, map );
135      }
136    
137      /**
138       * Add the specified collection of sections to the image map.
139       *
140       * @param sections The collection of sections to be added.
141       */
142      @SuppressWarnings( {"unchecked"} )
143      public void addSections( final Collection<MapSection> sections )
144      {
145        Map<String,MapSection> map =
146            (Map<String,MapSection>) get( PROPERTY_SECTIONS );
147        if ( map == null ) map = new LinkedHashMap<String,MapSection>();
148    
149        for ( MapSection section : sections )
150        {
151          if ( section.getActionCommand() != null )
152          {
153            map.put( section.getActionCommand(), section );
154          }
155        }
156    
157        setSections( map );
158      }
159    
160      /**
161       * Add the specified clickable section to the image map.
162       *
163       * @param section The section that is to be added.
164       */
165      @SuppressWarnings( {"unchecked"} )
166      public void addSection( final MapSection section )
167      {
168        if ( section.getActionCommand() == null ) return;
169    
170        Map<String,MapSection> map =
171            (Map<String,MapSection>) get( PROPERTY_SECTIONS );
172        if ( map == null ) map = new LinkedHashMap<String,MapSection>();
173        map.put( section.getActionCommand(), section );
174    
175        setSections( map );
176      }
177    
178      /**
179       * Remove the specified clickable section from the image map.
180       *
181       * @param section The section that is to be deleted.
182       */
183      @SuppressWarnings( {"unchecked"} )
184      public void removeSection( final MapSection section )
185      {
186        if ( section.getActionCommand() == null ) return;
187    
188        final Map<String,MapSection> map =
189            (Map<String,MapSection>) get( PROPERTY_SECTIONS );
190        if ( map != null ) map.remove( section.getActionCommand() );
191    
192        setSections( map );
193      }
194    
195      /**
196       * Remove all the clickable sections from the image map.
197       */
198      public void removeAllSections()
199      {
200        setSections( new LinkedHashMap<String,MapSection>() );
201      }
202    
203      /** {@inheritDoc} */
204      @Override
205      public void processInput( String name, Object value )
206      {
207        super.processInput( name, value );
208        if ( ACTION_COMMAND_PROPERTY.equals( name ) )
209        {
210          this.actionCommand = (String) value;
211        }
212        if ( INPUT_ACTION.equals( name ) )
213        {
214          fireActionPerformed( new ActionEvent( this, actionCommand ) );
215        }
216      }
217    }