1: package ;
2:
3: import ;
4: import ;
5:
6: import ;
7: import ;
8: import ;
9: import ;
10: import ;
11: import ;
12: import ;
13: import ;
14: import ;
15:
16: import ;
17: import ;
18: import ;
19: import ;
20: import ;
21: import ;
22: import ;
23: import ;
24: import ;
25: import ;
26:
27:
32: public class ImageView extends View
33: {
34:
37: class Observer
38: implements ImageObserver
39: {
40:
41: public boolean imageUpdate(Image image, int flags, int x, int y, int width, int height)
42: {
43: boolean widthChanged = false;
44: if ((flags & ImageObserver.WIDTH) != 0 && spans[X_AXIS] == null)
45: widthChanged = true;
46: boolean heightChanged = false;
47: if ((flags & ImageObserver.HEIGHT) != 0 && spans[Y_AXIS] == null)
48: heightChanged = true;
49: if (widthChanged || heightChanged)
50: safePreferenceChanged(ImageView.this, widthChanged, heightChanged);
51: boolean ret = (flags & ALLBITS) != 0;
52: return ret;
53: }
54:
55: }
56:
57:
61: boolean loadOnDemand;
62:
63:
66: Image image;
67:
68:
71: byte imageState = MediaTracker.LOADING;
72:
73:
76: private boolean reloadImage;
77:
78:
81: private boolean reloadProperties;
82:
83:
86: private boolean haveWidth;
87:
88:
91: private boolean haveHeight;
92:
93:
96: private boolean loading;
97:
98:
101: private int width;
102:
103:
106: private int height;
107:
108:
111: private ImageObserver observer;
112:
113:
118: Length[] spans;
119:
120:
123: private AttributeSet attributes;
124:
125:
130: public ImageView(Element element)
131: {
132: super(element);
133: spans = new Length[2];
134: observer = new Observer();
135: reloadProperties = true;
136: reloadImage = true;
137: loadOnDemand = false;
138: }
139:
140:
145: private void reloadImage()
146: {
147: loading = true;
148: reloadImage = false;
149: haveWidth = false;
150: haveHeight = false;
151: image = null;
152: width = 0;
153: height = 0;
154: try
155: {
156: loadImage();
157: updateSize();
158: }
159: finally
160: {
161: loading = false;
162: }
163: }
164:
165:
174: public float getAlignment(int axis)
175: {
176: AttributeSet attrs = getAttributes();
177: Object al = attrs.getAttribute(Attribute.ALIGN);
178:
179:
180: if (al == null)
181: return 0.0f;
182:
183: String align = al.toString();
184:
185: if (axis == View.X_AXIS)
186: {
187: if (align.equals("middle"))
188: return 0.5f;
189: else if (align.equals("left"))
190: return 0.0f;
191: else if (align.equals("right"))
192: return 1.0f;
193: else
194: return 0.0f;
195: }
196: else if (axis == View.Y_AXIS)
197: {
198: if (align.equals("middle"))
199: return 0.5f;
200: else if (align.equals("top"))
201: return 0.0f;
202: else if (align.equals("bottom"))
203: return 1.0f;
204: else
205: return 0.0f;
206: }
207: else
208: throw new IllegalArgumentException("axis " + axis);
209: }
210:
211:
218: public String getAltText()
219: {
220: Object rt = getAttributes().getAttribute(Attribute.ALT);
221: if (rt != null)
222: return rt.toString();
223: else
224: {
225: URL u = getImageURL();
226: if (u == null)
227: return "";
228: else
229: return u.getFile();
230: }
231: }
232:
233:
236: public AttributeSet getAttributes()
237: {
238: if (attributes == null)
239: attributes = getStyleSheet().getViewAttributes(this);
240: return attributes;
241: }
242:
243:
246: public Image getImage()
247: {
248: updateState();
249: return image;
250: }
251:
252:
260: public URL getImageURL()
261: {
262: Element el = getElement();
263: String src = (String) el.getAttributes().getAttribute(Attribute.SRC);
264: URL url = null;
265: if (src != null)
266: {
267: URL base = ((HTMLDocument) getDocument()).getBase();
268: try
269: {
270: url = new URL(base, src);
271: }
272: catch (MalformedURLException ex)
273: {
274:
275: }
276: }
277: return url;
278: }
279:
280:
286: public Icon getLoadingImageIcon()
287: {
288: return ImageViewIconFactory.getLoadingImageIcon();
289: }
290:
291:
298: public boolean getLoadsSynchronously()
299: {
300: return loadOnDemand;
301: }
302:
303:
308: public Icon getNoImageIcon()
309: {
310: return ImageViewIconFactory.getNoImageIcon();
311: }
312:
313:
324: public float getPreferredSpan(int axis)
325: {
326: Image image = getImage();
327:
328: if (axis == View.X_AXIS)
329: {
330: if (spans[axis] != null)
331: return spans[axis].getValue();
332: else if (image != null)
333: return image.getWidth(getContainer());
334: else
335: return getNoImageIcon().getIconWidth();
336: }
337: else if (axis == View.Y_AXIS)
338: {
339: if (spans[axis] != null)
340: return spans[axis].getValue();
341: else if (image != null)
342: return image.getHeight(getContainer());
343: else
344: return getNoImageIcon().getIconHeight();
345: }
346: else
347: throw new IllegalArgumentException("axis " + axis);
348: }
349:
350:
355: protected StyleSheet getStyleSheet()
356: {
357: HTMLDocument doc = (HTMLDocument) getDocument();
358: return doc.getStyleSheet();
359: }
360:
361:
367: public String getToolTipText(float x, float y, Shape shape)
368: {
369: return getAltText();
370: }
371:
372:
383: public void paint(Graphics g, Shape bounds)
384: {
385: updateState();
386: Rectangle r = bounds instanceof Rectangle ? (Rectangle) bounds
387: : bounds.getBounds();
388: Image image = getImage();
389: if (image != null)
390: {
391: g.drawImage(image, r.x, r.y, r.width, r.height, observer);
392: }
393: else
394: {
395: Icon icon = getNoImageIcon();
396: if (icon != null)
397: icon.paintIcon(getContainer(), g, r.x, r.y);
398: }
399: }
400:
401:
406: public void setLoadsSynchronously(boolean load_on_demand)
407: {
408: loadOnDemand = load_on_demand;
409: }
410:
411:
415: protected void setPropertiesFromAttributes()
416: {
417: AttributeSet atts = getAttributes();
418: StyleSheet ss = getStyleSheet();
419: float emBase = ss.getEMBase(atts);
420: float exBase = ss.getEXBase(atts);
421: spans[X_AXIS] = (Length) atts.getAttribute(CSS.Attribute.WIDTH);
422: if (spans[X_AXIS] != null)
423: {
424: spans[X_AXIS].setFontBases(emBase, exBase);
425: }
426: spans[Y_AXIS] = (Length) atts.getAttribute(CSS.Attribute.HEIGHT);
427: if (spans[Y_AXIS] != null)
428: {
429: spans[Y_AXIS].setFontBases(emBase, exBase);
430: }
431: }
432:
433:
438: public int viewToModel(float x, float y, Shape shape, Bias[] bias)
439: {
440: return getStartOffset();
441: }
442:
443:
453: public Shape modelToView(int pos, Shape area, Bias bias)
454: throws BadLocationException
455: {
456: return area;
457: }
458:
459:
464: public void setSize(float width, float height)
465: {
466: updateState();
467:
468: }
469:
470:
473: private void updateState()
474: {
475: if (reloadImage)
476: reloadImage();
477: if (reloadProperties)
478: setPropertiesFromAttributes();
479: }
480:
481:
484: private void loadImage()
485: {
486: URL src = getImageURL();
487: Image newImage = null;
488: if (src != null)
489: {
490:
491: Toolkit tk = Toolkit.getDefaultToolkit();
492: newImage = tk.getImage(src);
493: tk.prepareImage(newImage, -1, -1, observer);
494: if (newImage != null && getLoadsSynchronously())
495: {
496:
497: MediaTracker tracker = new MediaTracker(getContainer());
498: tracker.addImage(newImage, 0);
499: try
500: {
501: tracker.waitForID(0);
502: }
503: catch (InterruptedException ex)
504: {
505: Thread.interrupted();
506: }
507:
508: }
509: }
510: image = newImage;
511: }
512:
513:
516: private void updateSize()
517: {
518: int newW = 0;
519: int newH = 0;
520: Image newIm = getImage();
521: if (newIm != null)
522: {
523:
524: Length l = spans[X_AXIS];
525: if (l != null)
526: {
527: newW = (int) l.getValue();
528: haveWidth = true;
529: }
530: else
531: {
532: newW = newIm.getWidth(observer);
533: }
534:
535: l = spans[Y_AXIS];
536: if (l != null)
537: {
538: newH = (int) l.getValue();
539: haveHeight = true;
540: }
541: else
542: {
543: newW = newIm.getWidth(observer);
544: }
545:
546: Toolkit tk = Toolkit.getDefaultToolkit();
547: if (haveWidth || haveHeight)
548: tk.prepareImage(newIm, width, height, observer);
549: else
550: tk.prepareImage(newIm, -1, -1, observer);
551: }
552: }
553:
554:
562: void safePreferenceChanged(final View v, final boolean width,
563: final boolean height)
564: {
565: if (SwingUtilities.isEventDispatchThread())
566: {
567: Document doc = getDocument();
568: if (doc instanceof AbstractDocument)
569: ((AbstractDocument) doc).readLock();
570: try
571: {
572: preferenceChanged(v, width, height);
573: }
574: finally
575: {
576: if (doc instanceof AbstractDocument)
577: ((AbstractDocument) doc).readUnlock();
578: }
579: }
580: else
581: {
582: SwingUtilities.invokeLater(new Runnable()
583: {
584: public void run()
585: {
586: safePreferenceChanged(v, width, height);
587: }
588: });
589: }
590: }
591: }