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

Last change on this file since 2626 was 2295, checked in by stoecker, 15 years ago

reverted r2280, see #3665

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