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: AttributeSet attrs = getAttributes();
327:
328: Image image = getImage();
329:
330: if (axis == View.X_AXIS)
331: {
332: if (spans[axis] != null)
333: return spans[axis].getValue();
334: else if (image != null)
335: return image.getWidth(getContainer());
336: else
337: return getNoImageIcon().getIconWidth();
338: }
339: else if (axis == View.Y_AXIS)
340: {
341: if (spans[axis] != null)
342: return spans[axis].getValue();
343: else if (image != null)
344: return image.getHeight(getContainer());
345: else
346: return getNoImageIcon().getIconHeight();
347: }
348: else
349: throw new IllegalArgumentException("axis " + axis);
350: }
351:
352:
357: protected StyleSheet getStyleSheet()
358: {
359: HTMLDocument doc = (HTMLDocument) getDocument();
360: return doc.getStyleSheet();
361: }
362:
363:
369: public String getToolTipText(float x, float y, Shape shape)
370: {
371: return getAltText();
372: }
373:
374:
385: public void paint(Graphics g, Shape bounds)
386: {
387: updateState();
388: Rectangle r = bounds instanceof Rectangle ? (Rectangle) bounds
389: : bounds.getBounds();
390: Image image = getImage();
391: if (image != null)
392: {
393: g.drawImage(image, r.x, r.y, r.width, r.height, observer);
394: }
395: else
396: {
397: Icon icon = getNoImageIcon();
398: if (icon != null)
399: icon.paintIcon(getContainer(), g, r.x, r.y);
400: }
401: }
402:
403:
408: public void setLoadsSynchronously(boolean load_on_demand)
409: {
410: loadOnDemand = load_on_demand;
411: }
412:
413:
417: protected void setPropertiesFromAttributes()
418: {
419: AttributeSet atts = getAttributes();
420: StyleSheet ss = getStyleSheet();
421: float emBase = ss.getEMBase(atts);
422: float exBase = ss.getEXBase(atts);
423: spans[X_AXIS] = (Length) atts.getAttribute(CSS.Attribute.WIDTH);
424: if (spans[X_AXIS] != null)
425: {
426: spans[X_AXIS].setFontBases(emBase, exBase);
427: }
428: spans[Y_AXIS] = (Length) atts.getAttribute(CSS.Attribute.HEIGHT);
429: if (spans[Y_AXIS] != null)
430: {
431: spans[Y_AXIS].setFontBases(emBase, exBase);
432: }
433: }
434:
435:
440: public int viewToModel(float x, float y, Shape shape, Bias[] bias)
441: {
442: return getStartOffset();
443: }
444:
445:
455: public Shape modelToView(int pos, Shape area, Bias bias)
456: throws BadLocationException
457: {
458: return area;
459: }
460:
461:
466: public void setSize(float width, float height)
467: {
468: updateState();
469:
470: }
471:
472:
475: private void updateState()
476: {
477: if (reloadImage)
478: reloadImage();
479: if (reloadProperties)
480: setPropertiesFromAttributes();
481: }
482:
483:
486: private void loadImage()
487: {
488: URL src = getImageURL();
489: Image newImage = null;
490: if (src != null)
491: {
492:
493: Toolkit tk = Toolkit.getDefaultToolkit();
494: newImage = tk.getImage(src);
495: tk.prepareImage(newImage, -1, -1, observer);
496: if (newImage != null && getLoadsSynchronously())
497: {
498:
499: MediaTracker tracker = new MediaTracker(getContainer());
500: tracker.addImage(newImage, 0);
501: try
502: {
503: tracker.waitForID(0);
504: }
505: catch (InterruptedException ex)
506: {
507: Thread.interrupted();
508: }
509:
510: }
511: }
512: image = newImage;
513: }
514:
515:
518: private void updateSize()
519: {
520: int newW = 0;
521: int newH = 0;
522: Image newIm = getImage();
523: if (newIm != null)
524: {
525: AttributeSet atts = getAttributes();
526:
527: Length l = spans[X_AXIS];
528: if (l != null)
529: {
530: newW = (int) l.getValue();
531: haveWidth = true;
532: }
533: else
534: {
535: newW = newIm.getWidth(observer);
536: }
537:
538: l = spans[Y_AXIS];
539: if (l != null)
540: {
541: newH = (int) l.getValue();
542: haveHeight = true;
543: }
544: else
545: {
546: newW = newIm.getWidth(observer);
547: }
548:
549: Toolkit tk = Toolkit.getDefaultToolkit();
550: if (haveWidth || haveHeight)
551: tk.prepareImage(newIm, width, height, observer);
552: else
553: tk.prepareImage(newIm, -1, -1, observer);
554: }
555: }
556:
557:
565: void safePreferenceChanged(final View v, final boolean width,
566: final boolean height)
567: {
568: if (SwingUtilities.isEventDispatchThread())
569: {
570: Document doc = getDocument();
571: if (doc instanceof AbstractDocument)
572: ((AbstractDocument) doc).readLock();
573: try
574: {
575: preferenceChanged(v, width, height);
576: }
577: finally
578: {
579: if (doc instanceof AbstractDocument)
580: ((AbstractDocument) doc).readUnlock();
581: }
582: }
583: else
584: {
585: SwingUtilities.invokeLater(new Runnable()
586: {
587: public void run()
588: {
589: safePreferenceChanged(v, width, height);
590: }
591: });
592: }
593: }
594: }