source: josm/trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapRendererFactory.java@ 6362

Last change on this file since 6362 was 6362, checked in by Don-vip, 10 years ago

Checkstyle:

  • private constructors for util classes
  • final classes
  • missing "else" statements
  • import cleanup
  • Property svn:eol-style set to native
File size: 11.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.osm.visitor.paint;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Graphics2D;
7import java.lang.reflect.Constructor;
8import java.lang.reflect.InvocationTargetException;
9import java.text.MessageFormat;
10import java.util.ArrayList;
11import java.util.Collections;
12import java.util.Iterator;
13import java.util.List;
14
15import org.openstreetmap.josm.Main;
16import org.openstreetmap.josm.gui.NavigatableComponent;
17import org.openstreetmap.josm.plugins.PluginHandler;
18import org.openstreetmap.josm.tools.CheckParameterUtil;
19
20/**
21 * <p>MapRendererFactory manages a list of map renderer classes and associated
22 * meta data (display name, description).</p>
23 *
24 * <p>Plugins can implement and supply their own map renderers.</p>
25 * <strong>Sample code in a plugin</strong>
26 * <pre>
27 * public class MyMapRenderer extends AbstractMapRenderer {
28 * // ....
29 * }
30 *
31 * // to be called when the plugin is created
32 * MapRendererFactory factory = MapRendererFactory.getInstance();
33 * factory.register(MyMapRenderer.class, "My map renderer", "This is is a fast map renderer");
34 * factory.activate(MyMapRenderer.class);
35 *
36 * </pre>
37 *
38 */
39public final class MapRendererFactory {
40
41 /** preference key for the renderer class name. Default: class name for {@link StyledMapRenderer}
42 *
43 */
44 static public final String PREF_KEY_RENDERER_CLASS_NAME = "mappaint.renderer-class-name";
45
46 static public class MapRendererFactoryException extends RuntimeException {
47 public MapRendererFactoryException() {
48 }
49
50 public MapRendererFactoryException(String message, Throwable cause) {
51 super(message, cause);
52 }
53
54 public MapRendererFactoryException(String message) {
55 super(message);
56 }
57
58 public MapRendererFactoryException(Throwable cause) {
59 super(cause);
60 }
61 }
62
63 static public class Descriptor {
64 private Class<? extends AbstractMapRenderer> renderer;
65 private String displayName;
66 private String description;
67
68 public Descriptor(Class<? extends AbstractMapRenderer> renderer, String displayName, String description) {
69 this.renderer = renderer;
70 this.displayName = displayName;
71 this.description = description;
72 }
73
74 public Class<? extends AbstractMapRenderer> getRenderer() {
75 return renderer;
76 }
77
78 public String getDisplayName() {
79 return displayName;
80 }
81
82 public String getDescription() {
83 return description;
84 }
85 }
86
87 static private MapRendererFactory instance;
88
89 /**
90 * Replies the unique instance
91 * @return instance of map rending class
92 */
93 public static MapRendererFactory getInstance() {
94 if (instance == null) {
95 instance = new MapRendererFactory();
96 }
97 return instance;
98 }
99
100 private static Class<?> loadRendererClass(String className) {
101 for (ClassLoader cl : PluginHandler.getResourceClassLoaders()) {
102 try {
103 return Class.forName(className, true, cl);
104 } catch (final ClassNotFoundException e) {
105 // ignore
106 }
107 }
108 Main.error(tr("Failed to load map renderer class ''{0}''. The class wasn''t found.", className));
109 return null;
110 }
111
112 private final List<Descriptor> descriptors = new ArrayList<Descriptor>();
113 private Class<? extends AbstractMapRenderer> activeRenderer = null;
114
115 private MapRendererFactory() {
116 registerDefaultRenderers();
117 String rendererClassName = Main.pref.get(PREF_KEY_RENDERER_CLASS_NAME, null);
118 if (rendererClassName != null) {
119 activateMapRenderer(rendererClassName);
120 } else {
121 activateDefault();
122 }
123 }
124
125 private void activateMapRenderer(String rendererClassName){
126 Class<?> c = loadRendererClass(rendererClassName);
127 if (c == null){
128 Main.error(tr("Can''t activate map renderer class ''{0}'', because the class wasn''t found.", rendererClassName));
129 Main.error(tr("Activating the standard map renderer instead."));
130 activateDefault();
131 } else if (! AbstractMapRenderer.class.isAssignableFrom(c)) {
132 Main.error(tr("Can''t activate map renderer class ''{0}'', because it isn''t a subclass of ''{1}''.", rendererClassName, AbstractMapRenderer.class.getName()));
133 Main.error(tr("Activating the standard map renderer instead."));
134 activateDefault();
135 } else {
136 Class<? extends AbstractMapRenderer> renderer = c.asSubclass(AbstractMapRenderer.class);
137 if (! isRegistered(renderer)) {
138 Main.error(tr("Can''t activate map renderer class ''{0}'', because it isn''t registered as map renderer.", rendererClassName));
139 Main.error(tr("Activating the standard map renderer instead."));
140 activateDefault();
141 } else {
142 activate(renderer);
143 }
144 }
145 }
146
147 private void registerDefaultRenderers() {
148 register(
149 WireframeMapRenderer.class,
150 tr("Wireframe Map Renderer"),
151 tr("Renders the map as simple wire frame.")
152 );
153 register(
154 StyledMapRenderer.class,
155 tr("Styled Map Renderer"),
156 tr("Renders the map using style rules in a set of style sheets.")
157 );
158 }
159
160 /**
161 * <p>Replies true, if {@code Renderer} is already a registered map renderer
162 * class.</p>
163 *
164 * @param renderer the map renderer class. Must not be null.
165 * @return true, if {@code Renderer} is already a registered map renderer
166 * class
167 * @throws IllegalArgumentException thrown if {@code renderer} is null
168 */
169 public boolean isRegistered(Class<? extends AbstractMapRenderer> renderer) throws IllegalArgumentException {
170 CheckParameterUtil.ensureParameterNotNull(renderer);
171 for (Descriptor d: descriptors) {
172 if (d.getRenderer().getName().equals(renderer.getName())) return true;
173 }
174 return false;
175 }
176
177 /**
178 * <p>Registers a map renderer class.</p>
179 *
180 * @param renderer the map renderer class. Must not be null.
181 * @param displayName the display name to be displayed in UIs (i.e. in the preference dialog)
182 * @param description the description
183 * @throws IllegalArgumentException thrown if {@code renderer} is null
184 * @throws IllegalStateException thrown if {@code renderer} is already registered
185 */
186 public void register(Class<? extends AbstractMapRenderer> renderer, String displayName, String description) throws IllegalArgumentException, IllegalStateException{
187 CheckParameterUtil.ensureParameterNotNull(renderer);
188 if (isRegistered(renderer))
189 throw new IllegalStateException(
190 // no I18n - this is a technical message
191 MessageFormat.format("Class ''{0}'' already registered a renderer", renderer.getName())
192 );
193 Descriptor d = new Descriptor(renderer, displayName, description);
194 descriptors.add(d);
195 }
196
197
198 /**
199 * <p>Unregisters a map renderer class.</p>
200 *
201 * <p>If the respective class is also the active renderer, the renderer is reset
202 * to the default renderer.</p>
203 *
204 * @param renderer the map renderer class. Must not be null.
205 *
206 */
207 public void unregister(Class<? extends AbstractMapRenderer> renderer) {
208 if (renderer == null) return;
209 if (!isRegistered(renderer)) return;
210 Iterator<Descriptor> it = descriptors.iterator();
211 while(it.hasNext()) {
212 Descriptor d = it.next();
213 if (d.getRenderer().getName().equals(renderer.getName())) {
214 it.remove();
215 break;
216 }
217 }
218 if (activeRenderer != null && activeRenderer.getName().equals(renderer.getName())) {
219 activateDefault();
220 }
221 }
222
223 /**
224 * <p>Activates a map renderer class.</p>
225 *
226 * <p>The renderer class must already be registered.</p>
227 *
228 * @param renderer the map renderer class. Must not be null.
229 * @throws IllegalArgumentException thrown if {@code renderer} is null
230 * @throws IllegalStateException thrown if {@code renderer} isn't registered yet
231 *
232 */
233 public void activate(Class<? extends AbstractMapRenderer> renderer) throws IllegalArgumentException, IllegalStateException{
234 CheckParameterUtil.ensureParameterNotNull(renderer);
235 if (!isRegistered(renderer))
236 throw new IllegalStateException(
237 // no I18n required
238 MessageFormat.format("Class ''{0}'' not registered as renderer. Can''t activate it.", renderer.getName())
239 );
240 this.activeRenderer = renderer;
241 Main.pref.put(PREF_KEY_RENDERER_CLASS_NAME, activeRenderer.getName());
242
243 }
244
245 /**
246 * <p>Activates the default map renderer.</p>
247 *
248 * @throws IllegalStateException thrown if the default renderer {@link StyledMapRenderer} isn't registered
249 *
250 */
251 public void activateDefault() throws IllegalStateException{
252 Class<? extends AbstractMapRenderer> defaultRenderer = StyledMapRenderer.class;
253 if (!isRegistered(defaultRenderer))
254 throw new IllegalStateException(
255 MessageFormat.format("Class ''{0}'' not registered as renderer. Can''t activate default renderer.", defaultRenderer.getName())
256 );
257 activate(defaultRenderer);
258 }
259
260 /**
261 * <p>Creates an instance of the currently active renderer.</p>
262 *
263 * @throws MapRendererFactoryException thrown if creating an instance fails
264 * @see AbstractMapRenderer#AbstractMapRenderer(Graphics2D, NavigatableComponent, boolean)
265 */
266 public AbstractMapRenderer createActiveRenderer(Graphics2D g, NavigatableComponent viewport, boolean isInactiveMode) throws MapRendererFactoryException{
267 try {
268 Constructor<?> c = activeRenderer.getConstructor(new Class<?>[]{Graphics2D.class, NavigatableComponent.class, boolean.class});
269 return AbstractMapRenderer.class.cast(c.newInstance(g, viewport, isInactiveMode));
270 } catch(NoSuchMethodException e){
271 throw new MapRendererFactoryException(e);
272 } catch (IllegalArgumentException e) {
273 throw new MapRendererFactoryException(e);
274 } catch (InstantiationException e) {
275 throw new MapRendererFactoryException(e);
276 } catch (IllegalAccessException e) {
277 throw new MapRendererFactoryException(e);
278 } catch (InvocationTargetException e) {
279 throw new MapRendererFactoryException(e.getCause());
280 }
281 }
282
283 /**
284 * <p>Replies the (unmodifiable) list of map renderer descriptors.</p>
285 *
286 * @return the descriptors
287 */
288 public List<Descriptor> getMapRendererDescriptors() {
289 return Collections.unmodifiableList(descriptors);
290 }
291
292 /**
293 * <p>Replies true, if currently the wireframe map renderer is active. Otherwise,
294 * false.</p>
295 *
296 * <p>There is a specific method for {@link WireframeMapRenderer} for legacy support.
297 * Until 03/2011 there were only two possible map renderers in JOSM: the wireframe
298 * renderer and the styled renderer. For the time being there are still UI elements
299 * (menu entries, etc.) which toggle between these two renderers only.</p>
300 *
301 * @return true, if currently the wireframe map renderer is active. Otherwise,
302 * false
303 */
304 public boolean isWireframeMapRendererActive() {
305 return activeRenderer != null && activeRenderer.getName().equals(WireframeMapRenderer.class.getName());
306 }
307}
Note: See TracBrowser for help on using the repository browser.