001: package com.xoetrope.svg;
002:
003: import com.kitfox.svg.SVGDiagram;
004: import com.kitfox.svg.SVGDisplayPanel;
005: import com.kitfox.svg.SVGElementException;
006: import com.kitfox.svg.SVGException;
007: import com.kitfox.svg.SVGRoot;
008: import com.kitfox.svg.animation.AnimationElement;
009: import com.xoetrope.carousel.build.BuildProperties;
010: import java.awt.Color;
011: import java.awt.Graphics;
012: import java.awt.Graphics2D;
013: import java.awt.Image;
014: import java.awt.Point;
015: import java.awt.Rectangle;
016: import java.awt.RenderingHints;
017: import java.awt.Robot;
018: import java.awt.event.ComponentAdapter;
019: import java.awt.event.ComponentEvent;
020: import java.awt.geom.Rectangle2D;
021: import java.awt.image.BufferedImage;
022: import java.beans.PropertyChangeEvent;
023: import java.beans.PropertyChangeListener;
024: import java.lang.ref.WeakReference;
025: import java.util.HashMap;
026: import java.util.WeakHashMap;
027: import javax.swing.JComponent;
028: import javax.swing.SwingUtilities;
029:
030: /**
031: *
032: *
033: * <p> Copyright (c) Xoetrope Ltd., 2001-2006, This software is licensed under
034: * the GNU Public License (GPL), please see license.txt for more details. If
035: * you make commercial use of this software you must purchase a commercial
036: * license from Xoetrope.</p>
037: * <p> $Revision: 1.2 $</p>
038: */
039: public class XSvgMagnifyingWindow extends JComponent {
040: private Point zoomLocation;
041: private float scaleFactor;
042: private SVGDiagram diagram;
043: private XSvgImageMap imageMap;
044: private SVGRoot root;
045: private int[] attr;
046: private int centre, left, right;
047: private double tileSize, width, height, previousX, previousY,
048: previousWidth, previousHeight, startWidth, startHeight;
049: private BufferedImage leftImage, centreImage, rightImage;
050: private Graphics2D buffer;
051: private boolean startThread, first, stop;
052: private WeakHashMap referenceMap;
053: private long previousTime;
054: private Integer[] keys;
055: private XRenderingSemaphore semaphore;
056:
057: /**
058: * Creates a new instance of XSvgMagnifyingWindow
059: * @param diagram provides a means of rendering the document as a Graphics2D object.
060: */
061: public XSvgMagnifyingWindow() {
062: scaleFactor = 2.0f;
063: startThread = true;
064: first = true;
065: centre = 0;
066: tileSize = 400.0;
067: setDoubleBuffered(true);
068: }
069:
070: /**
071: * Set the SVGDiagram instance that the magnifier will magnify.
072: * @param diagram the SVGDiagram instance to be used.
073: */
074: public void setDiagram(SVGDiagram diagram) {
075: this .diagram = diagram;
076:
077: if (referenceMap != null) {
078: referenceMap.clear();
079: first = true;
080: }
081: }
082:
083: /**
084: * Set the XSvgImageMap instance that the magnifier will use.
085: * @param diagram the XSvgImageMap instance to be used.
086: */
087: public void setImageMap(XSvgImageMap imageMap) {
088: this .imageMap = imageMap;
089: semaphore = imageMap.getSemaphore();
090: }
091:
092: /**
093: * Used to set the scale factor, which defines by how much the selected area of the SVG image is zoomed.
094: * @param scaleFactor the float specifying the scale factor.
095: */
096: public void setScaleFactor(float f) {
097: this .scaleFactor = f;
098: }
099:
100: /**
101: * Used to get the scale factor, which defines by how much the selected area of the SVG image is zoomed.
102: * @return scaleFactor the float specifying the scale factor.
103: */
104: public float getScaleFactor() {
105: return scaleFactor;
106: }
107:
108: /**
109: * Used to set which part of the SVG image will be zoomed.
110: * @param p the Point object specifying the area to be zoomed.
111: */
112: public void setZoomPoint(Point p) {
113: if (p != null) {
114: zoomLocation = p;
115: repaint();
116: }
117: }
118:
119: /**
120: * Calls the JComponent's paint method and scales the area that has been selected using setZoomPoint.
121: * The scaled area is then applied to the magnifying glass.
122: * @param g the delegate Graphics object passed to protect the rest of the paint code.
123: */
124: protected void paintComponent(Graphics g) {
125: if (diagram != null) {
126: renderTiles();
127:
128: if (zoomLocation != null) {
129: getParent().setBackground(Color.white);
130: Graphics2D g2d = (Graphics2D) g.create();
131: g2d.translate((((double) getWidth()) / 2.0),
132: (((double) getHeight()) / 2.0));
133:
134: int xTranslation = 0, yTranslation = 0;
135: if (centre != 0) {
136: xTranslation = (int) -((zoomLocation.getX() - ((tileSize / scaleFactor) * ((double) centre - 1))) * scaleFactor);
137: yTranslation = (int) -(zoomLocation.getY() * scaleFactor);
138: } else {
139: xTranslation = (int) -(zoomLocation.getX() * scaleFactor);
140: yTranslation = (int) -(zoomLocation.getY() * scaleFactor);
141: }
142:
143: try {
144: g2d.drawImage(leftImage, null, xTranslation
145: - (int) (tileSize), yTranslation);
146: g2d.drawImage(centreImage, null, xTranslation,
147: yTranslation);
148: g2d.drawImage(rightImage, null, xTranslation
149: + (int) (tileSize), yTranslation);
150: } catch (Exception ex) {
151: if (BuildProperties.DEBUG)
152: ex.printStackTrace();
153: }
154:
155: g2d.dispose();
156: }
157: }
158: }
159:
160: public void stopRenderer() {
161: stop = true;
162: startThread = true;
163: first = true;
164: }
165:
166: private void createKeys(int size) {
167: keys = new Integer[size];
168:
169: for (int i = 0; i < keys.length; i++) {
170: keys[i] = new Integer(i);
171: }
172: }
173:
174: private void renderTiles() {
175: if (startThread == true) {
176: startThread = false;
177: stop = false;
178: Thread t = new Thread(new Runnable() {
179: public void run() {
180: referenceMap = new WeakHashMap();
181:
182: imageMap
183: .addPropertyChangeListener(new PropertyChangeListener() {
184: public void propertyChange(
185: PropertyChangeEvent evt) {
186: SVGRoot root = diagram.getRoot();
187: double[] attr = root
188: .getPresAbsolute("viewBox")
189: .getDoubleList();
190:
191: referenceMap.clear();
192:
193: previousX = attr[0];
194: previousY = attr[1];
195: previousWidth = attr[2];
196: previousHeight = attr[3];
197: first = true;
198: }
199: });
200:
201: while (true) {
202: if (stop) {
203: return;
204: }
205:
206: semaphore.acquire();
207:
208: SVGRoot root = diagram.getRoot();
209: double[] attr = root.getPresAbsolute("viewBox")
210: .getDoubleList();
211:
212: if ((zoomLocation != null)
213: && (((previousX != attr[0]) || (previousY != attr[1])) || (centre != ((int) (zoomLocation
214: .getX()
215: / (tileSize / scaleFactor) + 1))))) {
216:
217: int previousCentre = centre;
218: boolean doLeft = false, doCentre = false, doRight = false;
219:
220: diagram.setIgnoringClipHeuristic(true);
221:
222: centre = (int) ((zoomLocation.getX() / (tileSize / scaleFactor)) + 1);
223: left = centre - 1;
224: right = centre + 1;
225:
226: try {
227: if (first == true) {
228: first = false;
229:
230: doLeft = true;
231: doCentre = true;
232: doRight = true;
233:
234: int keyAmt = (int) ((imageMap
235: .getWidth() / (tileSize / scaleFactor)) + 3.0);
236: createKeys(keyAmt);
237: } else if (centre == (previousCentre - 1)) {
238: if (!referenceMap
239: .containsKey(keys[previousCentre + 1])) {
240: WeakReference sr = new WeakReference(
241: rightImage);
242: referenceMap
243: .put(
244: keys[previousCentre + 1],
245: sr);
246: }
247: rightImage = centreImage;
248: centreImage = leftImage;
249:
250: if (referenceMap
251: .containsKey(keys[centre - 1])) {
252: WeakReference sr = (WeakReference) referenceMap
253: .get(keys[centre - 1]);
254: leftImage = (BufferedImage) sr
255: .get();
256:
257: if (leftImage == null) {
258: referenceMap
259: .remove(keys[centre - 1]);
260: doLeft = true;
261: }
262: } else {
263: doLeft = true;
264: }
265: } else if (centre == (previousCentre + 1)) {
266: if (!referenceMap
267: .containsKey(keys[previousCentre - 1])) {
268: WeakReference sr = new WeakReference(
269: leftImage);
270: referenceMap
271: .put(
272: keys[previousCentre - 1],
273: sr);
274: }
275: leftImage = centreImage;
276: centreImage = rightImage;
277:
278: if (referenceMap
279: .containsKey(keys[centre + 1])) {
280: WeakReference sr = (WeakReference) referenceMap
281: .get(keys[centre + 1]);
282: rightImage = (BufferedImage) sr
283: .get();
284:
285: if (rightImage == null) {
286: referenceMap
287: .remove(keys[centre + 1]);
288: doRight = true;
289: }
290: } else {
291: doRight = true;
292: }
293: } else {
294: doLeft = true;
295: doCentre = true;
296: doRight = true;
297: }
298:
299: if (doCentre) {
300: centreImage = new BufferedImage(
301: (int) (tileSize),
302: ((int) (imageMap
303: .getHeight() * scaleFactor)),
304: BufferedImage.TYPE_INT_ARGB);
305: Graphics2D centreBuffer = centreImage
306: .createGraphics();
307: centreBuffer
308: .setRenderingHint(
309: RenderingHints.KEY_ANTIALIASING,
310: RenderingHints.VALUE_ANTIALIAS_ON);
311: centreBuffer.scale(scaleFactor,
312: scaleFactor);
313: centreBuffer
314: .translate(
315: -((int) (tileSize / scaleFactor) * (centre - 1)),
316: 0);
317: root.render(centreBuffer);
318: centreBuffer.dispose();
319:
320: SwingUtilities
321: .invokeLater(new Runnable() {
322: public void run() {
323: repaint();
324: }
325: });
326: }
327:
328: if (doLeft) {
329: leftImage = new BufferedImage(
330: (int) (tileSize),
331: ((int) (imageMap
332: .getHeight() * scaleFactor)),
333: BufferedImage.TYPE_INT_ARGB);
334: Graphics2D leftBuffer = leftImage
335: .createGraphics();
336: leftBuffer
337: .setRenderingHint(
338: RenderingHints.KEY_ANTIALIASING,
339: RenderingHints.VALUE_ANTIALIAS_ON);
340: leftBuffer.scale(scaleFactor,
341: scaleFactor);
342: leftBuffer
343: .translate(
344: -((int) (tileSize / scaleFactor) * (left - 1)),
345: 0);
346: root.render(leftBuffer);
347: leftBuffer.dispose();
348: }
349:
350: if (doRight) {
351: rightImage = new BufferedImage(
352: (int) (tileSize),
353: ((int) (imageMap
354: .getHeight() * scaleFactor)),
355: BufferedImage.TYPE_INT_ARGB);
356: Graphics2D rightBuffer = rightImage
357: .createGraphics();
358: rightBuffer
359: .setRenderingHint(
360: RenderingHints.KEY_ANTIALIASING,
361: RenderingHints.VALUE_ANTIALIAS_ON);
362: rightBuffer.scale(scaleFactor,
363: scaleFactor);
364: rightBuffer
365: .translate(
366: -((int) (tileSize / scaleFactor) * (right - 1)),
367: 0);
368: root.render(rightBuffer);
369: rightBuffer.dispose();
370: }
371: } catch (Exception ex) {
372: if (BuildProperties.DEBUG)
373: ex.printStackTrace();
374: }
375:
376: SwingUtilities.invokeLater(new Runnable() {
377: public void run() {
378: repaint();
379: }
380: });
381: } else {
382: try {
383: Thread.currentThread().sleep(200);
384: } catch (Exception ex) {
385: if (BuildProperties.DEBUG)
386: ex.printStackTrace();
387: }
388: }
389:
390: semaphore.release();
391: }
392: }
393: });
394: t.start();
395: }
396: }
397: }
|