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

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

findbugs: DP_DO_INSIDE_DO_PRIVILEGED + UWF_UNWRITTEN_FIELD + RC_REF_COMPARISON + OBL_UNSATISFIED_OBLIGATION_EXCEPTION_EDGE

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