Logo Search packages:      
Sourcecode: josm version File versions  Download package

Marker.java

// License: GPL. Copyright 2008 by Immanuel Scholz and others
package org.openstreetmap.josm.gui.layer.markerlayer;

import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.LinkedList;

import javax.swing.Icon;

import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.data.coor.EastNorth;
import org.openstreetmap.josm.data.coor.LatLon;
import org.openstreetmap.josm.data.gpx.GpxLink;
import org.openstreetmap.josm.data.gpx.WayPoint;
import org.openstreetmap.josm.gui.MapView;
import org.openstreetmap.josm.tools.ImageProvider;

/**
 * Basic marker class. Requires a position, and supports 
 * a custom icon and a name.
 * 
 * This class is also used to create appropriate Marker-type objects
 * when waypoints are imported.
 * 
 * It hosts a public list object, named makers, containing implementations of
 * the MarkerMaker interface. Whenever a Marker needs to be created, each 
 * object in makers is called with the waypoint parameters (Lat/Lon and tag
 * data), and the first one to return a Marker object wins.
 * 
 * By default, one the list contains one default "Maker" implementation that
 * will create AudioMarkers for .wav files, ImageMarkers for .png/.jpg/.jpeg 
 * files, and WebMarkers for everything else. (The creation of a WebMarker will
 * fail if there's no vaild URL in the <link> tag, so it might still make sense
 * to add Makers for such waypoints at the end of the list.)
 * 
 * The default implementation only looks at the value of the <link> tag inside
 * the <wpt> tag of the GPX file.
 * 
 * <h2>HowTo implement a new Marker</h2>
 * <ul>
 * <li> Subclass Marker or ButtonMarker and override <code>containsPoint</code>
 *      if you like to respond to user clicks</li>
 * <li> Override paint, if you want a custom marker look (not "a label and a symbol")</li>
 * <li> Implement MarkerCreator to return a new instance of your marker class</li>
 * <li> In you plugin constructor, add an instance of your MarkerCreator
 *      implementation either on top or bottom of Marker.markerProducers.
 *      Add at top, if your marker should overwrite an current marker or at bottom
 *      if you only add a new marker style.</li>
 * </ul>
 * 
 * @author Frederik Ramm <frederik@remote.org>
 */
00059 public class Marker implements ActionListener {

      public EastNorth eastNorth;
      public final String text;
      public final Icon symbol;
      public final MarkerLayer parentLayer;
      public double time; /* avbsolute time of marker since epocj */
      public double offset; /* time offset in seconds from the gpx point from which it was derived,
                                           may be adjusted later to sync with other data, so not final */

      /**
       * Plugins can add their Marker creation stuff at the bottom or top of this list
       * (depending on whether they want to override default behaviour or just add new
       * stuff).
       */
00074       public static LinkedList<MarkerProducers> markerProducers = new LinkedList<MarkerProducers>();

      // Add one Maker specifying the default behaviour.
      static {
            Marker.markerProducers.add(new MarkerProducers() {
                  public Marker createMarker(WayPoint wpt, File relativePath, MarkerLayer parentLayer, double time, double offset) {
                        String uri = null;
                        // cheapest way to check whether "link" object exists and is a non-empty
                        // collection of GpxLink objects...
                        try {
                              for (GpxLink oneLink : (Collection<GpxLink>) wpt.attr.get("link")) {
                                    uri = oneLink.uri;
                                    break;
                              }
                        } catch (Exception ex) {}

                        // Try a relative file:// url, if the link is not in an URL-compatible form
                if (relativePath != null && uri != null && !isWellFormedAddress(uri))
                    uri = new File(relativePath.getParentFile(), uri).toURI().toString();

                String name_desc = "";
                if (wpt.attr.containsKey("name")) {
                  name_desc = wpt.getString("name");
                } else if (wpt.attr.containsKey("desc")) {
                    name_desc = wpt.getString("desc");
                }
                
                if (uri == null)
                    return new Marker(wpt.latlon, name_desc, wpt.getString("symbol"), parentLayer, time, offset);
                else if (uri.endsWith(".wav"))
                    return AudioMarker.create(wpt.latlon, name_desc, uri, parentLayer, time, offset);
                else if (uri.endsWith(".png") || uri.endsWith(".jpg") || uri.endsWith(".jpeg") || uri.endsWith(".gif"))
                              return ImageMarker.create(wpt.latlon, uri, parentLayer, time, offset);
                        else
                              return WebMarker.create(wpt.latlon, uri, parentLayer, time, offset);
                  }

                  private boolean isWellFormedAddress(String link) {
                        try {
                              new URL(link);
                              return true;
                        } catch (MalformedURLException x) {
                              return false;
                        }
            }
            });
      }

      public Marker(LatLon ll, String text, String iconName, MarkerLayer parentLayer, double time, double offset) {
            eastNorth = Main.proj.latlon2eastNorth(ll); 
            this.text = text;
            this.offset = offset;
            this.time = time;
            Icon symbol = ImageProvider.getIfAvailable("markers",iconName);
            if (symbol == null)
                  symbol = ImageProvider.getIfAvailable("symbols",iconName);
            if (symbol == null)
                  symbol = ImageProvider.getIfAvailable("nodes",iconName);
            this.symbol = symbol;
            this.parentLayer = parentLayer;
      }

      /**
       * Checks whether the marker display area contains the given point.
       * Markers not interested in mouse clicks may always return false.
       * 
       * @param p The point to check
       * @return <code>true</code> if the marker "hotspot" contains the point.
       */
00143       public boolean containsPoint(Point p) {
            return false;
      }

      /**
       * Called when the mouse is clicked in the marker's hotspot. Never
       * called for markers which always return false from containsPoint.
       * 
       * @param ev A dummy ActionEvent
       */
00153       public void actionPerformed(ActionEvent ev) {
      }

      /**
       * Paints the marker.
       * @param g graphics context
       * @param mv map view
       * @param mousePressed true if the left mouse button is pressed
       */
00162       public void paint(Graphics g, MapView mv, boolean mousePressed, String show) {
            Point screen = mv.getPoint(eastNorth);
            if (symbol != null && show.equalsIgnoreCase("show")) {
                  symbol.paintIcon(mv, g, screen.x-symbol.getIconWidth()/2, screen.y-symbol.getIconHeight()/2);
            } else {
                  g.drawLine(screen.x-2, screen.y-2, screen.x+2, screen.y+2);
                  g.drawLine(screen.x+2, screen.y-2, screen.x-2, screen.y+2);
            }

            if ((text != null) && (show.equalsIgnoreCase("show")))
                  g.drawString(text, screen.x+4, screen.y+2);
      }

      /**
       * Returns an object of class Marker or one of its subclasses
       * created from the parameters given.
       *
       * @param ll lat/lon for marker
       * @param data hash containing keys and values from the GPX waypoint structure
       * @param relativePath An path to use for constructing relative URLs or 
       *        <code>null</code> for no relative URLs
       * @param offset double in seconds as the time offset of this marker from 
       *            the GPX file from which it was derived (if any).  
       * @return a new Marker object
       */
00187       public static Marker createMarker(WayPoint wpt, File relativePath, MarkerLayer parentLayer, double time, double offset) {
            for (MarkerProducers maker : Marker.markerProducers) {
                  Marker marker = maker.createMarker(wpt, relativePath, parentLayer, time, offset);
                  if (marker != null)
                        return marker;
            }
            return null;
      }
      
      /**
       * Returns an AudioMarker derived from this Marker and the provided uri
       * Subclasses of specific marker types override this to return null as they can't
       * be turned into AudioMarkers. This includes AudioMarkers themselves, as they 
       * already have audio.  
       * 
       * @param uri uri of wave file
       * @return AudioMarker
       */
      
00206       public AudioMarker audioMarkerFromMarker(String uri) {
            AudioMarker audioMarker = AudioMarker.create(Main.proj.eastNorth2latlon(this.eastNorth), this.text, uri, this.parentLayer, this.time, this.offset);
            return audioMarker;
      }
}

Generated by  Doxygen 1.6.0   Back to index