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

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

fix #11262 - Images not displayed correctly in Help Browser

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