source: josm/trunk/src/org/openstreetmap/josm/gui/layer/markerlayer/Marker.java@ 547

Last change on this file since 547 was 547, checked in by david, 16 years ago

much improved audio handling: threaded audio, controls, sync with waypoints

File size: 7.7 KB
Line 
1// License: GPL. Copyright 2008 by Immanuel Scholz and others
2package org.openstreetmap.josm.gui.layer.markerlayer;
3
4import java.awt.Graphics;
5import java.awt.Point;
6import java.awt.event.ActionEvent;
7import java.awt.event.ActionListener;
8import java.io.File;
9import java.net.MalformedURLException;
10import java.net.URL;
11import java.util.Collection;
12import java.util.HashMap;
13import java.util.LinkedList;
14import java.util.Map;
15
16import javax.swing.Icon;
17
18import org.openstreetmap.josm.Main;
19import org.openstreetmap.josm.data.coor.EastNorth;
20import org.openstreetmap.josm.data.coor.LatLon;
21import org.openstreetmap.josm.data.gpx.GpxLink;
22import org.openstreetmap.josm.data.gpx.WayPoint;
23import org.openstreetmap.josm.gui.MapView;
24import org.openstreetmap.josm.tools.ImageProvider;
25
26/**
27 * Basic marker class. Requires a position, and supports
28 * a custom icon and a name.
29 *
30 * This class is also used to create appropriate Marker-type objects
31 * when waypoints are imported.
32 *
33 * It hosts a public list object, named makers, containing implementations of
34 * the MarkerMaker interface. Whenever a Marker needs to be created, each
35 * object in makers is called with the waypoint parameters (Lat/Lon and tag
36 * data), and the first one to return a Marker object wins.
37 *
38 * By default, one the list contains one default "Maker" implementation that
39 * will create AudioMarkers for .wav files, ImageMarkers for .png/.jpg/.jpeg
40 * files, and WebMarkers for everything else. (The creation of a WebMarker will
41 * fail if there's no vaild URL in the <link> tag, so it might still make sense
42 * to add Makers for such waypoints at the end of the list.)
43 *
44 * The default implementation only looks at the value of the <link> tag inside
45 * the <wpt> tag of the GPX file.
46 *
47 * <h2>HowTo implement a new Marker</h2>
48 * <ul>
49 * <li> Subclass Marker or ButtonMarker and override <code>containsPoint</code>
50 * if you like to respond to user clicks</li>
51 * <li> Override paint, if you want a custom marker look (not "a label and a symbol")</li>
52 * <li> Implement MarkerCreator to return a new instance of your marker class</li>
53 * <li> In you plugin constructor, add an instance of your MarkerCreator
54 * implementation either on top or bottom of Marker.markerProducers.
55 * Add at top, if your marker should overwrite an current marker or at bottom
56 * if you only add a new marker style.</li>
57 * </ul>
58 *
59 * @author Frederik Ramm <frederik@remote.org>
60 */
61public class Marker implements ActionListener {
62
63 public final EastNorth eastNorth;
64 public final String text;
65 public final Icon symbol;
66 public double offset; /* time offset in seconds from the gpx point from which it was derived,
67 may be adjusted later to sync with other data, so not final */
68
69 /**
70 * Plugins can add their Marker creation stuff at the bottom or top of this list
71 * (depending on whether they want to override default behaviour or just add new
72 * stuff).
73 */
74 public static LinkedList<MarkerProducers> markerProducers = new LinkedList<MarkerProducers>();
75
76 // Add one Maker specifying the default behaviour.
77 static {
78 Marker.markerProducers.add(new MarkerProducers() {
79 public Marker createMarker(WayPoint wpt, File relativePath) {
80 return createMarker(wpt, relativePath, 0.0);
81 }
82
83 public Marker createMarker(WayPoint wpt, File relativePath, double offset) {
84 String uri = null;
85 // cheapest way to check whether "link" object exists and is a non-empty
86 // collection of GpxLink objects...
87 try {
88 for (GpxLink oneLink : (Collection<GpxLink>) wpt.attr.get("link")) {
89 uri = oneLink.uri;
90 break;
91 }
92 } catch (Exception ex) {};
93
94 // Try a relative file:// url, if the link is not in an URL-compatible form
95 if (relativePath != null && uri != null && !isWellFormedAddress(uri))
96 uri = new File(relativePath, uri).toURI().toString();
97
98 String name_desc = "";
99 if (wpt.attr.containsKey("name")) {
100 name_desc = wpt.getString("name");
101 } else if (wpt.attr.containsKey("desc")) {
102 name_desc = wpt.getString("desc");
103 }
104
105 if (uri == null)
106 return new Marker(wpt.latlon, name_desc, wpt.getString("symbol"), offset);
107 else if (uri.endsWith(".wav"))
108 return AudioMarker.create(wpt.latlon, name_desc, uri, offset);
109 else if (uri.endsWith(".png") || uri.endsWith(".jpg") || uri.endsWith(".jpeg") || uri.endsWith(".gif"))
110 return ImageMarker.create(wpt.latlon, uri, offset);
111 else
112 return WebMarker.create(wpt.latlon, uri, offset);
113 }
114
115 private boolean isWellFormedAddress(String link) {
116 try {
117 new URL(link);
118 return true;
119 } catch (MalformedURLException x) {
120 return false;
121 }
122 }
123 });
124 }
125
126 public Marker(LatLon ll, String text, String iconName, double offset) {
127 eastNorth = Main.proj.latlon2eastNorth(ll);
128 this.text = text;
129 this.offset = offset;
130 Icon symbol = ImageProvider.getIfAvailable("markers",iconName);
131 if (symbol == null)
132 symbol = ImageProvider.getIfAvailable("symbols",iconName);
133 if (symbol == null)
134 symbol = ImageProvider.getIfAvailable("nodes",iconName);
135 this.symbol = symbol;
136 }
137
138 /**
139 * Checks whether the marker display area contains the given point.
140 * Markers not interested in mouse clicks may always return false.
141 *
142 * @param p The point to check
143 * @return <code>true</code> if the marker "hotspot" contains the point.
144 */
145 public boolean containsPoint(Point p) {
146 return false;
147 }
148
149 /**
150 * Called when the mouse is clicked in the marker's hotspot. Never
151 * called for markers which always return false from containsPoint.
152 *
153 * @param ev A dummy ActionEvent
154 */
155 public void actionPerformed(ActionEvent ev) {
156 }
157
158 /**
159 * Paints the marker.
160 * @param g graphics context
161 * @param mv map view
162 * @param mousePressed true if the left mouse button is pressed
163 */
164 public void paint(Graphics g, MapView mv, boolean mousePressed, String show) {
165 Point screen = mv.getPoint(eastNorth);
166 if (symbol != null) {
167 symbol.paintIcon(mv, g, screen.x-symbol.getIconWidth()/2, screen.y-symbol.getIconHeight()/2);
168 } else {
169 g.drawLine(screen.x-2, screen.y-2, screen.x+2, screen.y+2);
170 g.drawLine(screen.x+2, screen.y-2, screen.x-2, screen.y+2);
171 }
172
173 if ((text != null) && (show.equalsIgnoreCase("show")))
174 g.drawString(text, screen.x+4, screen.y+2);
175 }
176
177 /**
178 * Returns an object of class Marker or one of its subclasses
179 * created from the parameters given.
180 *
181 * @param ll lat/lon for marker
182 * @param data hash containing keys and values from the GPX waypoint structure
183 * @param relativePath An path to use for constructing relative URLs or
184 * <code>null</code> for no relative URLs
185 * @param offset double in seconds as the time offset of this marker from
186 * the GPX file from which it was derived (if any).
187 * @return a new Marker object
188 */
189 public static Marker createMarker(WayPoint wpt, File relativePath, double offset) {
190 for (MarkerProducers maker : Marker.markerProducers) {
191 Marker marker = maker.createMarker(wpt, relativePath, offset);
192 if (marker != null)
193 return marker;
194 }
195 return null;
196 }
197
198 /**
199 * Returns an AudioMarker derived from this Marker and the provided uri
200 * Subclasses of specific marker types override this to return null as they can't
201 * be turned into AudioMarkers. This includes AudioMarkers themselves, as they
202 * already have audio.
203 *
204 * @param uri uri of wave file
205 * @return AudioMarker
206 */
207
208 public AudioMarker audioMarkerFromMarker(String uri) {
209 AudioMarker audioMarker = AudioMarker.create(Main.proj.eastNorth2latlon(this.eastNorth), this.text, uri, this.offset);
210 return audioMarker;
211 }
212}
Note: See TracBrowser for help on using the repository browser.