source: josm/trunk/src/org/openstreetmap/josm/gui/widgets/JosmImageView.java@ 9665

Last change on this file since 9665 was 9665, checked in by stoecker, 8 years ago

fix eol-style issues and similar formating stuff, see #12410

File size: 6.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.widgets;
3
4import java.awt.Graphics;
5import java.awt.Image;
6import java.awt.Shape;
7import java.lang.reflect.Field;
8import java.lang.reflect.InvocationTargetException;
9import java.lang.reflect.Method;
10import java.net.URL;
11
12import javax.swing.ImageIcon;
13import javax.swing.text.AttributeSet;
14import javax.swing.text.Element;
15import javax.swing.text.html.ImageView;
16
17import org.openstreetmap.josm.Main;
18import org.openstreetmap.josm.tools.ImageProvider;
19
20/**
21 * Specialized Image View allowing to display SVG images.
22 * @since 8933
23 */
24public class JosmImageView extends ImageView {
25
26 private static final int LOADING_FLAG = 1;
27 private static final int WIDTH_FLAG = 4;
28 private static final int HEIGHT_FLAG = 8;
29 private static final int RELOAD_FLAG = 16;
30 private static final int RELOAD_IMAGE_FLAG = 32;
31
32 private final Field imageField;
33 private final Field stateField;
34 private final Field widthField;
35 private final Field heightField;
36
37 /**
38 * Constructs a new {@code JosmImageView}.
39 * @param elem the element to create a view for
40 * @throws SecurityException see {@link Class#getDeclaredField} for details
41 * @throws NoSuchFieldException see {@link Class#getDeclaredField} for details
42 */
43 public JosmImageView(Element elem) throws NoSuchFieldException, SecurityException {
44 super(elem);
45 imageField = ImageView.class.getDeclaredField("image");
46 stateField = ImageView.class.getDeclaredField("state");
47 widthField = ImageView.class.getDeclaredField("width");
48 heightField = ImageView.class.getDeclaredField("height");
49 imageField.setAccessible(true);
50 stateField.setAccessible(true);
51 widthField.setAccessible(true);
52 heightField.setAccessible(true);
53 }
54
55 /**
56 * Makes sure the necessary properties and image is loaded.
57 */
58 private void sync() {
59 try {
60 int s = (int) stateField.get(this);
61 if ((s & RELOAD_IMAGE_FLAG) != 0) {
62 refreshImage();
63 }
64 s = (int) stateField.get(this);
65 if ((s & RELOAD_FLAG) != 0) {
66 synchronized (this) {
67 stateField.set(this, ((int) stateField.get(this) | RELOAD_FLAG) ^ RELOAD_FLAG);
68 }
69 setPropertiesFromAttributes();
70 }
71 } catch (IllegalArgumentException | IllegalAccessException |
72 InvocationTargetException | NoSuchMethodException | SecurityException e) {
73 Main.error(e);
74 }
75 }
76
77 /**
78 * Loads the image and updates the size accordingly. This should be
79 * invoked instead of invoking <code>loadImage</code> or
80 * <code>updateImageSize</code> directly.
81 * @throws IllegalAccessException see {@link Field#set} and {@link Method#invoke} for details
82 * @throws IllegalArgumentException see {@link Field#set} and {@link Method#invoke} for details
83 * @throws InvocationTargetException see {@link Method#invoke} for details
84 * @throws NoSuchMethodException see {@link Class#getDeclaredMethod} for details
85 * @throws SecurityException see {@link Class#getDeclaredMethod} for details
86 */
87 private void refreshImage() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException,
88 NoSuchMethodException, SecurityException {
89 synchronized (this) {
90 // clear out width/height/reloadimage flag and set loading flag
91 stateField.set(this, ((int) stateField.get(this) | LOADING_FLAG | RELOAD_IMAGE_FLAG | WIDTH_FLAG |
92 HEIGHT_FLAG) ^ (WIDTH_FLAG | HEIGHT_FLAG |
93 RELOAD_IMAGE_FLAG));
94 imageField.set(this, null);
95 widthField.set(this, 0);
96 heightField.set(this, 0);
97 }
98
99 try {
100 // Load the image
101 loadImage();
102
103 // And update the size params
104 Method updateImageSize = ImageView.class.getDeclaredMethod("updateImageSize");
105 updateImageSize.setAccessible(true);
106 updateImageSize.invoke(this);
107 } finally {
108 synchronized (this) {
109 // Clear out state in case someone threw an exception.
110 stateField.set(this, ((int) stateField.get(this) | LOADING_FLAG) ^ LOADING_FLAG);
111 }
112 }
113 }
114
115 /**
116 * Loads the image from the URL <code>getImageURL</code>. This should
117 * only be invoked from <code>refreshImage</code>.
118 * @throws IllegalAccessException see {@link Field#set} and {@link Method#invoke} for details
119 * @throws IllegalArgumentException see {@link Field#set} and {@link Method#invoke} for details
120 * @throws InvocationTargetException see {@link Method#invoke} for details
121 * @throws NoSuchMethodException see {@link Class#getDeclaredMethod} for details
122 * @throws SecurityException see {@link Class#getDeclaredMethod} for details
123 */
124 private void loadImage() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException,
125 NoSuchMethodException, SecurityException {
126 URL src = getImageURL();
127 if (src != null) {
128 String urlStr = src.toExternalForm();
129 if (urlStr.endsWith(".svg") || urlStr.endsWith(".svg?format=raw")) {
130 ImageIcon imgIcon = new ImageProvider(urlStr).setOptional(true).get();
131 imageField.set(this, imgIcon != null ? imgIcon.getImage() : null);
132 } else {
133 Method loadImage = ImageView.class.getDeclaredMethod("loadImage");
134 loadImage.setAccessible(true);
135 loadImage.invoke(this);
136 }
137 } else {
138 imageField.set(this, null);
139 }
140 }
141
142 @Override
143 public Image getImage() {
144 sync();
145 return super.getImage();
146 }
147
148 @Override
149 public AttributeSet getAttributes() {
150 sync();
151 return super.getAttributes();
152 }
153
154 @Override
155 public void paint(Graphics g, Shape a) {
156 sync();
157 super.paint(g, a);
158 }
159
160 @Override
161 public float getPreferredSpan(int axis) {
162 sync();
163 return super.getPreferredSpan(axis);
164 }
165
166 @Override
167 public void setSize(float width, float height) {
168 sync();
169 super.setSize(width, height);
170 }
171}
Note: See TracBrowser for help on using the repository browser.