0001: /*
0002:
0003: Licensed to the Apache Software Foundation (ASF) under one or more
0004: contributor license agreements. See the NOTICE file distributed with
0005: this work for additional information regarding copyright ownership.
0006: The ASF licenses this file to You under the Apache License, Version 2.0
0007: (the "License"); you may not use this file except in compliance with
0008: the License. You may obtain a copy of the License at
0009:
0010: http://www.apache.org/licenses/LICENSE-2.0
0011:
0012: Unless required by applicable law or agreed to in writing, software
0013: distributed under the License is distributed on an "AS IS" BASIS,
0014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0015: See the License for the specific language governing permissions and
0016: limitations under the License.
0017:
0018: */
0019: package org.apache.batik.bridge;
0020:
0021: import java.io.BufferedReader;
0022: import java.io.InputStream;
0023: import java.io.InputStreamReader;
0024: import java.io.IOException;
0025: import java.io.OutputStream;
0026: import java.io.OutputStreamWriter;
0027: import java.io.Reader;
0028: import java.io.StringReader;
0029: import java.io.UnsupportedEncodingException;
0030: import java.io.Writer;
0031:
0032: import java.net.URL;
0033: import java.net.URLConnection;
0034:
0035: import java.util.HashMap;
0036: import java.util.Map;
0037: import java.util.Timer;
0038: import java.util.TimerTask;
0039: import java.util.zip.GZIPOutputStream;
0040: import java.util.zip.DeflaterOutputStream;
0041:
0042: import org.apache.batik.dom.GenericDOMImplementation;
0043: import org.apache.batik.dom.events.NodeEventTarget;
0044: import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
0045: import org.apache.batik.dom.svg.SVGOMDocument;
0046: import org.apache.batik.dom.util.SAXDocumentFactory;
0047: import org.apache.batik.dom.util.XLinkSupport;
0048: import org.apache.batik.script.Interpreter;
0049: import org.apache.batik.script.InterpreterException;
0050: import org.apache.batik.script.ScriptEventWrapper;
0051: import org.apache.batik.util.EncodingUtilities;
0052: import org.apache.batik.util.ParsedURL;
0053: import org.apache.batik.util.RunnableQueue;
0054: import org.apache.batik.util.SVGConstants;
0055: import org.apache.batik.util.XMLConstants;
0056: import org.apache.batik.util.XMLResourceDescriptor;
0057:
0058: import org.w3c.dom.Document;
0059: import org.w3c.dom.Element;
0060: import org.w3c.dom.Node;
0061: import org.w3c.dom.events.Event;
0062: import org.w3c.dom.events.EventListener;
0063: import org.w3c.dom.events.MutationEvent;
0064: import org.w3c.dom.svg.SVGDocument;
0065:
0066: /**
0067: * This class contains the informations needed by the SVG scripting.
0068: *
0069: * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
0070: * @version $Id: ScriptingEnvironment.java 478160 2006-11-22 13:35:06Z dvholten $
0071: */
0072: public class ScriptingEnvironment extends BaseScriptingEnvironment {
0073:
0074: /**
0075: * Used in 'parseXML()'.
0076: */
0077: protected static final String FRAGMENT_PREFIX = "<svg xmlns='"
0078: + SVGConstants.SVG_NAMESPACE_URI + "' xmlns:xlink='"
0079: + XLinkSupport.XLINK_NAMESPACE_URI + "'>";
0080:
0081: protected static final String FRAGMENT_SUFFIX = "</svg>";
0082:
0083: public static final String[] SVG_EVENT_ATTRS = { "onabort", // SVG element
0084: "onerror", // SVG element
0085: "onresize", // SVG element
0086: "onscroll", // SVG element
0087: "onunload", // SVG element
0088: "onzoom", // SVG element
0089:
0090: "onbegin", // SMIL
0091: "onend", // SMIL
0092: "onrepeat", // SMIL
0093:
0094: "onfocusin", // UI Events
0095: "onfocusout", // UI Events
0096: "onactivate", // UI Events
0097: "onclick", // UI Events
0098:
0099: "onmousedown", // UI Events
0100: "onmouseup", // UI Events
0101: "onmouseover", // UI Events
0102: "onmouseout", // UI Events
0103: "onmousemove", // UI Events
0104:
0105: "onkeypress", // UI Events
0106: "onkeydown", // UI Events
0107: "onkeyup" // UI Events
0108: };
0109:
0110: public static final String[] SVG_DOM_EVENT = { "SVGAbort", // SVG element
0111: "SVGError", // SVG element
0112: "SVGResize", // SVG element
0113: "SVGScroll", // SVG element
0114: "SVGUnload", // SVG element
0115: "SVGZoom", // SVG element
0116:
0117: "beginEvent", // SMIL
0118: "endEvent", // SMIL
0119: "repeatEvent", // SMIL
0120:
0121: "DOMFocusIn", // UI Events
0122: "DOMFocusOut", // UI Events
0123: "DOMActivate", // UI Events
0124: "click", // UI Events
0125: "mousedown", // UI Events
0126: "mouseup", // UI Events
0127: "mouseover", // UI Events
0128: "mouseout", // UI Events
0129: "mousemove", // UI Events
0130: "keypress", // UI Events
0131: "keydown", // UI Events
0132: "keyup" // UI Events
0133: };
0134:
0135: /**
0136: * The timer for periodic or delayed tasks.
0137: */
0138: protected Timer timer = new Timer(true);
0139:
0140: /**
0141: * The update manager.
0142: */
0143: protected UpdateManager updateManager;
0144:
0145: /**
0146: * The update runnable queue.
0147: */
0148: protected RunnableQueue updateRunnableQueue;
0149:
0150: /**
0151: * The DOMNodeInserted event listener.
0152: */
0153: protected EventListener domNodeInsertedListener;
0154:
0155: /**
0156: * The DOMNodeRemoved event listener.
0157: */
0158: protected EventListener domNodeRemovedListener;
0159:
0160: /**
0161: * The DOMAttrModified event listener.
0162: */
0163: protected EventListener domAttrModifiedListener;
0164:
0165: /**
0166: * The SVGAbort event listener.
0167: */
0168: protected EventListener svgAbortListener = new ScriptingEventListener(
0169: "onabort");
0170:
0171: /**
0172: * The SVGError event listener.
0173: */
0174: protected EventListener svgErrorListener = new ScriptingEventListener(
0175: "onerror");
0176:
0177: /**
0178: * The SVGResize event listener.
0179: */
0180: protected EventListener svgResizeListener = new ScriptingEventListener(
0181: "onresize");
0182:
0183: /**
0184: * The SVGScroll event listener.
0185: */
0186: protected EventListener svgScrollListener = new ScriptingEventListener(
0187: "onscroll");
0188:
0189: /**
0190: * The SVGUnload event listener.
0191: */
0192: protected EventListener svgUnloadListener = new ScriptingEventListener(
0193: "onunload");
0194:
0195: /**
0196: * The SVGZoom event listener.
0197: */
0198: protected EventListener svgZoomListener = new ScriptingEventListener(
0199: "onzoom");
0200:
0201: /**
0202: * The begin event listener.
0203: */
0204: protected EventListener beginListener = new ScriptingEventListener(
0205: "onbegin");
0206:
0207: /**
0208: * The end event listener.
0209: */
0210: protected EventListener endListener = new ScriptingEventListener(
0211: "onend");
0212:
0213: /**
0214: * The repeat event listener.
0215: */
0216: protected EventListener repeatListener = new ScriptingEventListener(
0217: "onrepeat");
0218:
0219: /**
0220: * The focusin event listener.
0221: */
0222: protected EventListener focusinListener = new ScriptingEventListener(
0223: "onfocusin");
0224:
0225: /**
0226: * The focusout event listener.
0227: */
0228: protected EventListener focusoutListener = new ScriptingEventListener(
0229: "onfocusout");
0230:
0231: /**
0232: * The activate event listener.
0233: */
0234: protected EventListener activateListener = new ScriptingEventListener(
0235: "onactivate");
0236:
0237: /**
0238: * The click event listener.
0239: */
0240: protected EventListener clickListener = new ScriptingEventListener(
0241: "onclick");
0242:
0243: /**
0244: * The mousedown event listener.
0245: */
0246: protected EventListener mousedownListener = new ScriptingEventListener(
0247: "onmousedown");
0248:
0249: /**
0250: * The mouseup event listener.
0251: */
0252: protected EventListener mouseupListener = new ScriptingEventListener(
0253: "onmouseup");
0254:
0255: /**
0256: * The mouseover event listener.
0257: */
0258: protected EventListener mouseoverListener = new ScriptingEventListener(
0259: "onmouseover");
0260:
0261: /**
0262: * The mouseout event listener.
0263: */
0264: protected EventListener mouseoutListener = new ScriptingEventListener(
0265: "onmouseout");
0266:
0267: /**
0268: * The mousemove event listener.
0269: */
0270: protected EventListener mousemoveListener = new ScriptingEventListener(
0271: "onmousemove");
0272:
0273: /**
0274: * The keypress event listener.
0275: */
0276: protected EventListener keypressListener = new ScriptingEventListener(
0277: "onkeypress");
0278:
0279: /**
0280: * The keydown event listener.
0281: */
0282: protected EventListener keydownListener = new ScriptingEventListener(
0283: "onkeydown");
0284:
0285: /**
0286: * The keyup event listener.
0287: */
0288: protected EventListener keyupListener = new ScriptingEventListener(
0289: "onkeyup");
0290:
0291: protected EventListener[] listeners = { svgAbortListener,
0292: svgErrorListener, svgResizeListener, svgScrollListener,
0293: svgUnloadListener, svgZoomListener,
0294:
0295: beginListener, endListener, repeatListener,
0296:
0297: focusinListener, focusoutListener, activateListener,
0298: clickListener,
0299:
0300: mousedownListener, mouseupListener, mouseoverListener,
0301: mouseoutListener, mousemoveListener,
0302:
0303: keypressListener, keydownListener, keyupListener };
0304:
0305: Map attrToDOMEvent = new HashMap(SVG_EVENT_ATTRS.length);
0306: Map attrToListener = new HashMap(SVG_EVENT_ATTRS.length);
0307: {
0308: for (int i = 0; i < SVG_EVENT_ATTRS.length; i++) {
0309: attrToDOMEvent.put(SVG_EVENT_ATTRS[i], SVG_DOM_EVENT[i]);
0310: attrToListener.put(SVG_EVENT_ATTRS[i], listeners[i]);
0311: }
0312: }
0313:
0314: /**
0315: * Creates a new ScriptingEnvironment.
0316: * @param ctx the bridge context
0317: */
0318: public ScriptingEnvironment(BridgeContext ctx) {
0319: super (ctx);
0320: updateManager = ctx.getUpdateManager();
0321: updateRunnableQueue = updateManager.getUpdateRunnableQueue();
0322:
0323: // Add the scripting listeners.
0324: addScriptingListeners(document.getDocumentElement());
0325:
0326: // Add the listeners responsible of updating the event attributes
0327: addDocumentListeners();
0328: }
0329:
0330: /**
0331: * Adds DOM listeners to the document.
0332: */
0333: protected void addDocumentListeners() {
0334: domNodeInsertedListener = new DOMNodeInsertedListener();
0335: domNodeRemovedListener = new DOMNodeRemovedListener();
0336: domAttrModifiedListener = new DOMAttrModifiedListener();
0337: NodeEventTarget et = (NodeEventTarget) document;
0338: et
0339: .addEventListenerNS(
0340: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0341: "DOMNodeInserted", domNodeInsertedListener,
0342: false, null);
0343: et.addEventListenerNS(XMLConstants.XML_EVENTS_NAMESPACE_URI,
0344: "DOMNodeRemoved", domNodeRemovedListener, false, null);
0345: et
0346: .addEventListenerNS(
0347: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0348: "DOMAttrModified", domAttrModifiedListener,
0349: false, null);
0350: }
0351:
0352: /**
0353: * Removes DOM listeners from the document.
0354: */
0355: protected void removeDocumentListeners() {
0356: NodeEventTarget et = (NodeEventTarget) document;
0357: et.removeEventListenerNS(XMLConstants.XML_EVENTS_NAMESPACE_URI,
0358: "DOMNodeInserted", domNodeInsertedListener, false);
0359: et.removeEventListenerNS(XMLConstants.XML_EVENTS_NAMESPACE_URI,
0360: "DOMNodeRemoved", domNodeRemovedListener, false);
0361: et.removeEventListenerNS(XMLConstants.XML_EVENTS_NAMESPACE_URI,
0362: "DOMAttrModified", domAttrModifiedListener, false);
0363: }
0364:
0365: /**
0366: * Creates a new Window object.
0367: */
0368: public org.apache.batik.script.Window createWindow(
0369: Interpreter interp, String lang) {
0370: return new Window(interp, lang);
0371: }
0372:
0373: /**
0374: * Runs an event handler.
0375: */
0376: public void runEventHandler(String script, Event evt, String lang,
0377: String desc) {
0378: Interpreter interpreter = getInterpreter(lang);
0379: if (interpreter == null)
0380: return;
0381:
0382: try {
0383: checkCompatibleScriptURL(lang, docPURL);
0384:
0385: Object event;
0386: if (evt instanceof ScriptEventWrapper) {
0387: event = ((ScriptEventWrapper) evt).getEventObject();
0388: } else {
0389: event = evt;
0390: }
0391: interpreter.bindObject(EVENT_NAME, event);
0392: interpreter.bindObject(ALTERNATE_EVENT_NAME, event);
0393: interpreter.evaluate(new StringReader(script), desc);
0394: } catch (IOException ioe) {
0395: // Do nothing, can't really happen with StringReader
0396: } catch (InterpreterException ie) {
0397: handleInterpreterException(ie);
0398: } catch (SecurityException se) {
0399: handleSecurityException(se);
0400: }
0401: }
0402:
0403: /**
0404: * Interrupts the periodic tasks and dispose this ScriptingEnvironment.
0405: */
0406: public void interrupt() {
0407: timer.cancel();
0408: // Remove the scripting listeners.
0409: removeScriptingListeners(document.getDocumentElement());
0410:
0411: // Remove the listeners responsible of updating the event attributes
0412: removeDocumentListeners();
0413: }
0414:
0415: /**
0416: * Adds the scripting listeners to the given element and all of
0417: * its descendants.
0418: */
0419: public void addScriptingListeners(Node node) {
0420: if (node.getNodeType() == Node.ELEMENT_NODE) {
0421: addScriptingListenersOn((Element) node);
0422: }
0423:
0424: // Adds the listeners to the children
0425: for (Node n = node.getFirstChild(); n != null; n = n
0426: .getNextSibling()) {
0427: addScriptingListeners(n);
0428: }
0429: }
0430:
0431: /**
0432: * Adds the scripting listeners to the given element.
0433: */
0434: protected void addScriptingListenersOn(Element elt) {
0435: // Attach the listeners
0436: NodeEventTarget target = (NodeEventTarget) elt;
0437: if (SVGConstants.SVG_NAMESPACE_URI
0438: .equals(elt.getNamespaceURI())) {
0439: if (SVGConstants.SVG_SVG_TAG.equals(elt.getLocalName())) {
0440: // <svg> listeners
0441: if (elt.hasAttributeNS(null, "onabort")) {
0442: target.addEventListenerNS(
0443: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0444: "SVGAbort", svgAbortListener, false, null);
0445: }
0446: if (elt.hasAttributeNS(null, "onerror")) {
0447: target.addEventListenerNS(
0448: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0449: "SVGError", svgErrorListener, false, null);
0450: }
0451: if (elt.hasAttributeNS(null, "onresize")) {
0452: target
0453: .addEventListenerNS(
0454: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0455: "SVGResize", svgResizeListener,
0456: false, null);
0457: }
0458: if (elt.hasAttributeNS(null, "onscroll")) {
0459: target
0460: .addEventListenerNS(
0461: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0462: "SVGScroll", svgScrollListener,
0463: false, null);
0464: }
0465: if (elt.hasAttributeNS(null, "onunload")) {
0466: target
0467: .addEventListenerNS(
0468: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0469: "SVGUnload", svgUnloadListener,
0470: false, null);
0471: }
0472: if (elt.hasAttributeNS(null, "onzoom")) {
0473: target.addEventListenerNS(
0474: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0475: "SVGZoom", svgZoomListener, false, null);
0476: }
0477: } else {
0478: String name = elt.getLocalName();
0479: if (name.equals(SVGConstants.SVG_SET_TAG)
0480: || name.startsWith("animate")) {
0481: // animation listeners
0482: if (elt.hasAttributeNS(null, "onbegin")) {
0483: target.addEventListenerNS(
0484: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0485: "beginEvent", beginListener, false,
0486: null);
0487: }
0488: if (elt.hasAttributeNS(null, "onend")) {
0489: target.addEventListenerNS(
0490: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0491: "endEvent", endListener, false, null);
0492: }
0493: if (elt.hasAttributeNS(null, "onrepeat")) {
0494: target.addEventListenerNS(
0495: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0496: "repeatEvent", repeatListener, false,
0497: null);
0498: }
0499: return;
0500: }
0501: }
0502: }
0503:
0504: // UI listeners
0505: if (elt.hasAttributeNS(null, "onfocusin")) {
0506: target.addEventListenerNS(
0507: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0508: "DOMFocusIn", focusinListener, false, null);
0509: }
0510: if (elt.hasAttributeNS(null, "onfocusout")) {
0511: target.addEventListenerNS(
0512: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0513: "DOMFocusOut", focusoutListener, false, null);
0514: }
0515: if (elt.hasAttributeNS(null, "onactivate")) {
0516: target.addEventListenerNS(
0517: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0518: "DOMActivate", activateListener, false, null);
0519: }
0520: if (elt.hasAttributeNS(null, "onclick")) {
0521: target.addEventListenerNS(
0522: XMLConstants.XML_EVENTS_NAMESPACE_URI, "click",
0523: clickListener, false, null);
0524: }
0525: if (elt.hasAttributeNS(null, "onmousedown")) {
0526: target.addEventListenerNS(
0527: XMLConstants.XML_EVENTS_NAMESPACE_URI, "mousedown",
0528: mousedownListener, false, null);
0529: }
0530: if (elt.hasAttributeNS(null, "onmouseup")) {
0531: target.addEventListenerNS(
0532: XMLConstants.XML_EVENTS_NAMESPACE_URI, "mouseup",
0533: mouseupListener, false, null);
0534: }
0535: if (elt.hasAttributeNS(null, "onmouseover")) {
0536: target.addEventListenerNS(
0537: XMLConstants.XML_EVENTS_NAMESPACE_URI, "mouseover",
0538: mouseoverListener, false, null);
0539: }
0540: if (elt.hasAttributeNS(null, "onmouseout")) {
0541: target.addEventListenerNS(
0542: XMLConstants.XML_EVENTS_NAMESPACE_URI, "mouseout",
0543: mouseoutListener, false, null);
0544: }
0545: if (elt.hasAttributeNS(null, "onmousemove")) {
0546: target.addEventListenerNS(
0547: XMLConstants.XML_EVENTS_NAMESPACE_URI, "mousemove",
0548: mousemoveListener, false, null);
0549: }
0550: if (elt.hasAttributeNS(null, "onkeypress")) {
0551: target.addEventListenerNS(
0552: XMLConstants.XML_EVENTS_NAMESPACE_URI, "keypress",
0553: keypressListener, false, null);
0554: }
0555: if (elt.hasAttributeNS(null, "onkeydown")) {
0556: target.addEventListenerNS(
0557: XMLConstants.XML_EVENTS_NAMESPACE_URI, "keydown",
0558: keydownListener, false, null);
0559: }
0560: if (elt.hasAttributeNS(null, "onkeyup")) {
0561: target.addEventListenerNS(
0562: XMLConstants.XML_EVENTS_NAMESPACE_URI, "keyup",
0563: keyupListener, false, null);
0564: }
0565: }
0566:
0567: /**
0568: * Removes the scripting listeners from the given element and all
0569: * of its descendants.
0570: */
0571: protected void removeScriptingListeners(Node node) {
0572: if (node.getNodeType() == Node.ELEMENT_NODE) {
0573: // Detach the listeners
0574: removeScriptingListenersOn((Element) node);
0575: }
0576:
0577: // Removes the listeners from the children
0578: for (Node n = node.getFirstChild(); n != null; n = n
0579: .getNextSibling()) {
0580: removeScriptingListeners(n);
0581: }
0582: }
0583:
0584: /**
0585: * Removes the scripting listeners from the given element.
0586: */
0587: protected void removeScriptingListenersOn(Element elt) {
0588: NodeEventTarget target = (NodeEventTarget) elt;
0589: if (SVGConstants.SVG_NAMESPACE_URI
0590: .equals(elt.getNamespaceURI())) {
0591: if (SVGConstants.SVG_SVG_TAG.equals(elt.getLocalName())) {
0592: // <svg> listeners
0593: target.removeEventListenerNS(
0594: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0595: "SVGAbort", svgAbortListener, false);
0596: target.removeEventListenerNS(
0597: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0598: "SVGError", svgErrorListener, false);
0599: target.removeEventListenerNS(
0600: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0601: "SVGResize", svgResizeListener, false);
0602: target.removeEventListenerNS(
0603: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0604: "SVGScroll", svgScrollListener, false);
0605: target.removeEventListenerNS(
0606: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0607: "SVGUnload", svgUnloadListener, false);
0608: target.removeEventListenerNS(
0609: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0610: "SVGZoom", svgZoomListener, false);
0611: } else {
0612: String name = elt.getLocalName();
0613: if (name.equals(SVGConstants.SVG_SET_TAG)
0614: || name.startsWith("animate")) {
0615: // animation listeners
0616: target.removeEventListenerNS(
0617: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0618: "beginEvent", beginListener, false);
0619: target.removeEventListenerNS(
0620: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0621: "endEvent", endListener, false);
0622: target.removeEventListenerNS(
0623: XMLConstants.XML_EVENTS_NAMESPACE_URI,
0624: "repeatEvent", repeatListener, false);
0625: return;
0626: }
0627: }
0628: }
0629:
0630: // UI listeners
0631: target.removeEventListenerNS(
0632: XMLConstants.XML_EVENTS_NAMESPACE_URI, "DOMFocusIn",
0633: focusinListener, false);
0634: target.removeEventListenerNS(
0635: XMLConstants.XML_EVENTS_NAMESPACE_URI, "DOMFocusOut",
0636: focusoutListener, false);
0637: target.removeEventListenerNS(
0638: XMLConstants.XML_EVENTS_NAMESPACE_URI, "DOMActivate",
0639: activateListener, false);
0640: target.removeEventListenerNS(
0641: XMLConstants.XML_EVENTS_NAMESPACE_URI, "click",
0642: clickListener, false);
0643: target.removeEventListenerNS(
0644: XMLConstants.XML_EVENTS_NAMESPACE_URI, "mousedown",
0645: mousedownListener, false);
0646: target.removeEventListenerNS(
0647: XMLConstants.XML_EVENTS_NAMESPACE_URI, "mouseup",
0648: mouseupListener, false);
0649: target.removeEventListenerNS(
0650: XMLConstants.XML_EVENTS_NAMESPACE_URI, "mouseover",
0651: mouseoverListener, false);
0652: target.removeEventListenerNS(
0653: XMLConstants.XML_EVENTS_NAMESPACE_URI, "mouseout",
0654: mouseoutListener, false);
0655: target.removeEventListenerNS(
0656: XMLConstants.XML_EVENTS_NAMESPACE_URI, "mousemove",
0657: mousemoveListener, false);
0658: target.removeEventListenerNS(
0659: XMLConstants.XML_EVENTS_NAMESPACE_URI, "keypress",
0660: keypressListener, false);
0661: target.removeEventListenerNS(
0662: XMLConstants.XML_EVENTS_NAMESPACE_URI, "keydown",
0663: keydownListener, false);
0664: target.removeEventListenerNS(
0665: XMLConstants.XML_EVENTS_NAMESPACE_URI, "keyup",
0666: keyupListener, false);
0667: }
0668:
0669: /**
0670: * Updates the registration of a listener on the given element.
0671: */
0672: protected void updateScriptingListeners(Element elt, String attr) {
0673: String domEvt = (String) attrToDOMEvent.get(attr);
0674: if (domEvt == null) {
0675: return; // Not an event attr.
0676: }
0677: EventListener listener = (EventListener) attrToListener
0678: .get(attr);
0679: NodeEventTarget target = (NodeEventTarget) elt;
0680: if (elt.hasAttributeNS(null, attr)) {
0681: target.addEventListenerNS(
0682: XMLConstants.XML_EVENTS_NAMESPACE_URI, domEvt,
0683: listener, false, null);
0684: } else {
0685: target.removeEventListenerNS(
0686: XMLConstants.XML_EVENTS_NAMESPACE_URI, domEvt,
0687: listener, false);
0688: }
0689: }
0690:
0691: /**
0692: * To interpret a script.
0693: */
0694: protected class EvaluateRunnable implements Runnable {
0695: protected Interpreter interpreter;
0696: protected String script;
0697:
0698: public EvaluateRunnable(String s, Interpreter interp) {
0699: interpreter = interp;
0700: script = s;
0701: }
0702:
0703: public void run() {
0704: try {
0705: interpreter.evaluate(script);
0706: } catch (InterpreterException ie) {
0707: handleInterpreterException(ie);
0708: }
0709: }
0710: }
0711:
0712: /**
0713: * To interpret a script.
0714: */
0715: protected class EvaluateIntervalRunnable implements Runnable {
0716: /**
0717: * Incremented each time this runnable is added to the queue.
0718: */
0719: public int count;
0720: public boolean error;
0721:
0722: protected Interpreter interpreter;
0723: protected String script;
0724:
0725: public EvaluateIntervalRunnable(String s, Interpreter interp) {
0726: interpreter = interp;
0727: script = s;
0728: }
0729:
0730: public void run() {
0731: synchronized (this ) {
0732: if (error)
0733: return;
0734: count--;
0735: }
0736: try {
0737: interpreter.evaluate(script);
0738: } catch (InterpreterException ie) {
0739: handleInterpreterException(ie);
0740: synchronized (this ) {
0741: error = true;
0742: }
0743: } catch (Exception e) {
0744: if (userAgent != null) {
0745: userAgent.displayError(e);
0746: } else {
0747: e.printStackTrace(); // No UA so just output...
0748: }
0749: synchronized (this ) {
0750: error = true;
0751: }
0752: }
0753: }
0754: }
0755:
0756: /**
0757: * To call a Runnable.
0758: */
0759: protected class EvaluateRunnableRunnable implements Runnable {
0760: /**
0761: * Incremented each time this runnable is put in the queue.
0762: */
0763: public int count;
0764: public boolean error;
0765:
0766: protected Runnable runnable;
0767:
0768: public EvaluateRunnableRunnable(Runnable r) {
0769: runnable = r;
0770: }
0771:
0772: public void run() {
0773: synchronized (this ) {
0774: if (error)
0775: return;
0776: count--;
0777: }
0778: try {
0779: runnable.run();
0780: } catch (Exception e) {
0781: if (userAgent != null) {
0782: userAgent.displayError(e);
0783: } else {
0784: e.printStackTrace(); // No UA so just output...
0785: }
0786: synchronized (this ) {
0787: error = true;
0788: }
0789: }
0790: }
0791: }
0792:
0793: /**
0794: * Represents the window object of this environment.
0795: */
0796: protected class Window implements org.apache.batik.script.Window {
0797:
0798: /**
0799: * The associated interpreter.
0800: */
0801: protected Interpreter interpreter;
0802:
0803: /**
0804: * The associated language.
0805: */
0806: protected String language;
0807:
0808: /**
0809: * Creates a new Window for the given language.
0810: */
0811: public Window(Interpreter interp, String lang) {
0812: interpreter = interp;
0813: language = lang;
0814: }
0815:
0816: /**
0817: * Implements {@link
0818: * org.apache.batik.script.Window#setInterval(String,long)}.
0819: */
0820: public Object setInterval(final String script, long interval) {
0821: TimerTask tt = new TimerTask() {
0822: EvaluateIntervalRunnable eir = new EvaluateIntervalRunnable(
0823: script, interpreter);
0824:
0825: public void run() {
0826: synchronized (eir) {
0827: if (eir.count > 1)
0828: return;
0829: eir.count++;
0830: }
0831: synchronized (updateRunnableQueue.getIteratorLock()) {
0832: if (updateRunnableQueue.getThread() == null) {
0833: cancel();
0834: return;
0835: }
0836: updateRunnableQueue.invokeLater(eir);
0837: }
0838: synchronized (eir) {
0839: if (eir.error)
0840: cancel();
0841: }
0842: }
0843: };
0844:
0845: timer.schedule(tt, interval, interval);
0846: return tt;
0847: }
0848:
0849: /**
0850: * Implements {@link
0851: * org.apache.batik.script.Window#setInterval(Runnable,long)}.
0852: */
0853: public Object setInterval(final Runnable r, long interval) {
0854: TimerTask tt = new TimerTask() {
0855: EvaluateRunnableRunnable eihr = new EvaluateRunnableRunnable(
0856: r);
0857:
0858: public void run() {
0859: synchronized (eihr) {
0860: if (eihr.count > 1)
0861: return;
0862: eihr.count++;
0863: }
0864: updateRunnableQueue.invokeLater(eihr);
0865: synchronized (eihr) {
0866: if (eihr.error)
0867: cancel();
0868: }
0869: }
0870: };
0871:
0872: timer.schedule(tt, interval, interval);
0873: return tt;
0874: }
0875:
0876: /**
0877: * Implements {@link
0878: * org.apache.batik.script.Window#clearInterval(Object)}.
0879: */
0880: public void clearInterval(Object interval) {
0881: if (interval == null)
0882: return;
0883: ((TimerTask) interval).cancel();
0884: }
0885:
0886: /**
0887: * Implements {@link
0888: * org.apache.batik.script.Window#setTimeout(String,long)}.
0889: */
0890: public Object setTimeout(final String script, long timeout) {
0891: TimerTask tt = new TimerTask() {
0892: public void run() {
0893: updateRunnableQueue
0894: .invokeLater(new EvaluateRunnable(script,
0895: interpreter));
0896: }
0897: };
0898:
0899: timer.schedule(tt, timeout);
0900: return tt;
0901: }
0902:
0903: /**
0904: * Implements {@link
0905: * org.apache.batik.script.Window#setTimeout(Runnable,long)}.
0906: */
0907: public Object setTimeout(final Runnable r, long timeout) {
0908: TimerTask tt = new TimerTask() {
0909: public void run() {
0910: updateRunnableQueue.invokeLater(new Runnable() {
0911: public void run() {
0912: try {
0913: r.run();
0914: } catch (Exception e) {
0915: if (userAgent != null) {
0916: userAgent.displayError(e);
0917: }
0918: }
0919: }
0920: });
0921: }
0922: };
0923:
0924: timer.schedule(tt, timeout);
0925: return tt;
0926: }
0927:
0928: /**
0929: * Implements {@link
0930: * org.apache.batik.script.Window#clearTimeout(Object)}.
0931: */
0932: public void clearTimeout(Object timeout) {
0933: if (timeout == null)
0934: return;
0935: ((TimerTask) timeout).cancel();
0936: }
0937:
0938: /**
0939: * Implements {@link
0940: * org.apache.batik.script.Window#parseXML(String,Document)}.
0941: */
0942: public Node parseXML(String text, Document doc) {
0943: // System.err.println("Text: " + text);
0944: // Try and parse it as an SVGDocument
0945: SAXSVGDocumentFactory df = new SAXSVGDocumentFactory(
0946: XMLResourceDescriptor.getXMLParserClassName());
0947: URL urlObj = null;
0948: if ((doc != null) && (doc instanceof SVGOMDocument))
0949: urlObj = ((SVGOMDocument) doc).getURLObject();
0950: if (urlObj == null) {
0951: urlObj = ((SVGOMDocument) bridgeContext.getDocument())
0952: .getURLObject();
0953: }
0954: String uri = (urlObj == null) ? "" : urlObj.toString();
0955: try {
0956: Document d = df.createDocument(uri, new StringReader(
0957: text));
0958: if (doc == null)
0959: return d;
0960:
0961: Node result = doc.createDocumentFragment();
0962: result.appendChild(doc.importNode(d
0963: .getDocumentElement(), true));
0964: return result;
0965: } catch (Exception ex) {
0966: /* nothing */
0967: }
0968:
0969: if ((doc != null) && (doc instanceof SVGOMDocument)) {
0970: // Try and parse with an 'svg' element wrapper - for
0971: // things like '<rect ../>' - ensure that rect ends up
0972: // in SVG namespace - xlink namespace is declared etc...
0973:
0974: // Only do this when generating a doc fragment, since
0975: // a 'rect' element can not be root of SVG Document
0976: // (only an svg element can be).
0977: StringBuffer sb = new StringBuffer(FRAGMENT_PREFIX
0978: .length()
0979: + text.length() + FRAGMENT_SUFFIX.length());
0980: sb.append(FRAGMENT_PREFIX);
0981: sb.append(text);
0982: sb.append(FRAGMENT_SUFFIX);
0983: String newText = sb.toString();
0984: try {
0985: Document d = df.createDocument(uri,
0986: new StringReader(newText));
0987: // No document given so make doc fragment from our
0988: // new Document.
0989: if (doc == null)
0990: doc = d;
0991: for (Node n = d.getDocumentElement()
0992: .getFirstChild(); n != null; n = n
0993: .getNextSibling()) {
0994: if (n.getNodeType() == Node.ELEMENT_NODE) {
0995: n = doc.importNode(n, true);
0996: Node result = doc.createDocumentFragment();
0997: result.appendChild(n);
0998: return result;
0999: }
1000: }
1001: } catch (Exception exc) {
1002: /* nothing - try something else*/
1003: }
1004: }
1005:
1006: // Parse as a generic XML document.
1007: SAXDocumentFactory sdf;
1008: if (doc != null) {
1009: sdf = new SAXDocumentFactory(doc.getImplementation(),
1010: XMLResourceDescriptor.getXMLParserClassName());
1011: } else {
1012: sdf = new SAXDocumentFactory(
1013: new GenericDOMImplementation(),
1014: XMLResourceDescriptor.getXMLParserClassName());
1015: }
1016: try {
1017: Document d = sdf.createDocument(uri, new StringReader(
1018: text));
1019: if (doc == null)
1020: return d;
1021:
1022: Node result = doc.createDocumentFragment();
1023: result.appendChild(doc.importNode(d
1024: .getDocumentElement(), true));
1025: return result;
1026: } catch (Exception ext) {
1027: if (userAgent != null)
1028: userAgent.displayError(ext);
1029: }
1030:
1031: return null;
1032: }
1033:
1034: /**
1035: * Implements {@link
1036: * org.apache.batik.script.Window#getURL(String,org.apache.batik.script.Window.URLResponseHandler)}.
1037: */
1038: public void getURL(String uri,
1039: org.apache.batik.script.Window.URLResponseHandler h) {
1040: getURL(uri, h, null);
1041: }
1042:
1043: static final String DEFLATE = "deflate";
1044: static final String GZIP = "gzip";
1045: static final String UTF_8 = "UTF-8";
1046:
1047: /**
1048: * Implements {@link
1049: * org.apache.batik.script.Window#getURL(String,org.apache.batik.script.Window.URLResponseHandler,String)}.
1050: */
1051: public void getURL(
1052: final String uri,
1053: final org.apache.batik.script.Window.URLResponseHandler h,
1054: final String enc) {
1055: Thread t = new Thread() {
1056: public void run() {
1057: try {
1058: URL burl;
1059: burl = ((SVGOMDocument) document)
1060: .getURLObject();
1061: final ParsedURL purl = new ParsedURL(burl, uri);
1062: String e = null;
1063: if (enc != null) {
1064: e = EncodingUtilities.javaEncoding(enc);
1065: e = ((e == null) ? enc : e);
1066: }
1067:
1068: InputStream is = purl.openStream();
1069: Reader r;
1070: if (e == null) {
1071: // Not really a char encoding.
1072: r = new InputStreamReader(is);
1073: } else {
1074: try {
1075: r = new InputStreamReader(is, e);
1076: } catch (UnsupportedEncodingException uee) {
1077: // Try with no encoding.
1078: r = new InputStreamReader(is);
1079: }
1080: }
1081: r = new BufferedReader(r);
1082: final StringBuffer sb = new StringBuffer();
1083: int read;
1084: char[] buf = new char[4096];
1085: while ((read = r.read(buf, 0, buf.length)) != -1) {
1086: sb.append(buf, 0, read);
1087: }
1088: r.close();
1089:
1090: updateRunnableQueue.invokeLater(new Runnable() {
1091: public void run() {
1092: try {
1093: h.getURLDone(true, purl
1094: .getContentType(), sb
1095: .toString());
1096: } catch (Exception e) {
1097: if (userAgent != null) {
1098: userAgent.displayError(e);
1099: }
1100: }
1101: }
1102: });
1103: } catch (Exception e) {
1104: if (e instanceof SecurityException) {
1105: userAgent.displayError(e);
1106: }
1107: updateRunnableQueue.invokeLater(new Runnable() {
1108: public void run() {
1109: try {
1110: h.getURLDone(false, null, null);
1111: } catch (Exception e) {
1112: if (userAgent != null) {
1113: userAgent.displayError(e);
1114: }
1115: }
1116: }
1117: });
1118: }
1119: }
1120:
1121: };
1122: t.setPriority(Thread.MIN_PRIORITY);
1123: t.start();
1124: }
1125:
1126: public void postURL(String uri, String content,
1127: org.apache.batik.script.Window.URLResponseHandler h) {
1128: postURL(uri, content, h, "text/plain", null);
1129: }
1130:
1131: public void postURL(String uri, String content,
1132: org.apache.batik.script.Window.URLResponseHandler h,
1133: String mimeType) {
1134: postURL(uri, content, h, mimeType, null);
1135: }
1136:
1137: public void postURL(
1138: final String uri,
1139: final String content,
1140: final org.apache.batik.script.Window.URLResponseHandler h,
1141: final String mimeType, final String fEnc) {
1142: Thread t = new Thread() {
1143: public void run() {
1144: try {
1145: URL burl;
1146: burl = ((SVGOMDocument) document)
1147: .getURLObject();
1148: URL url;
1149: if (burl != null)
1150: url = new URL(burl, uri);
1151: else
1152: url = new URL(uri);
1153: final URLConnection conn = url.openConnection();
1154: conn.setDoOutput(true);
1155: conn.setDoInput(true);
1156: conn.setUseCaches(false);
1157: conn.setRequestProperty("Content-Type",
1158: mimeType);
1159:
1160: OutputStream os = conn.getOutputStream();
1161: String e = null, enc = fEnc;
1162: if (enc != null) {
1163: if (enc.startsWith(DEFLATE)) {
1164: os = new DeflaterOutputStream(os);
1165:
1166: if (enc.length() > DEFLATE.length())
1167: enc = enc.substring(DEFLATE
1168: .length() + 1);
1169: else
1170: enc = "";
1171: conn.setRequestProperty(
1172: "Content-Encoding", DEFLATE);
1173: }
1174: if (enc.startsWith(GZIP)) {
1175: os = new GZIPOutputStream(os);
1176: if (enc.length() > GZIP.length())
1177: enc = enc
1178: .substring(GZIP.length() + 1);
1179: else
1180: enc = "";
1181: conn.setRequestProperty(
1182: "Content-Encoding", DEFLATE);
1183: }
1184: if (enc.length() != 0) {
1185: e = EncodingUtilities.javaEncoding(enc);
1186: if (e == null)
1187: e = UTF_8;
1188: } else {
1189: e = UTF_8;
1190: }
1191: }
1192: Writer w;
1193: if (e == null)
1194: w = new OutputStreamWriter(os);
1195: else
1196: w = new OutputStreamWriter(os, e);
1197: w.write(content);
1198: w.flush();
1199: w.close();
1200: os.close();
1201:
1202: InputStream is = conn.getInputStream();
1203: Reader r;
1204: e = UTF_8;
1205: if (e == null)
1206: r = new InputStreamReader(is);
1207: else
1208: r = new InputStreamReader(is, e);
1209: r = new BufferedReader(r);
1210:
1211: final StringBuffer sb = new StringBuffer();
1212: int read;
1213: char[] buf = new char[4096];
1214: while ((read = r.read(buf, 0, buf.length)) != -1) {
1215: sb.append(buf, 0, read);
1216: }
1217: r.close();
1218:
1219: updateRunnableQueue.invokeLater(new Runnable() {
1220: public void run() {
1221: try {
1222: h.getURLDone(true, conn
1223: .getContentType(), sb
1224: .toString());
1225: } catch (Exception e) {
1226: if (userAgent != null) {
1227: userAgent.displayError(e);
1228: }
1229: }
1230: }
1231: });
1232: } catch (Exception e) {
1233: if (e instanceof SecurityException) {
1234: userAgent.displayError(e);
1235: }
1236: updateRunnableQueue.invokeLater(new Runnable() {
1237: public void run() {
1238: try {
1239: h.getURLDone(false, null, null);
1240: } catch (Exception e) {
1241: if (userAgent != null) {
1242: userAgent.displayError(e);
1243: }
1244: }
1245: }
1246: });
1247: }
1248: }
1249:
1250: };
1251: t.setPriority(Thread.MIN_PRIORITY);
1252: t.start();
1253: }
1254:
1255: /**
1256: * Displays an alert dialog box.
1257: */
1258: public void alert(String message) {
1259: if (userAgent != null) {
1260: userAgent.showAlert(message);
1261: }
1262: }
1263:
1264: /**
1265: * Displays a confirm dialog box.
1266: */
1267: public boolean confirm(String message) {
1268: if (userAgent != null) {
1269: return userAgent.showConfirm(message);
1270: }
1271: return false;
1272: }
1273:
1274: /**
1275: * Displays an input dialog box.
1276: */
1277: public String prompt(String message) {
1278: if (userAgent != null) {
1279: return userAgent.showPrompt(message);
1280: }
1281: return null;
1282: }
1283:
1284: /**
1285: * Displays an input dialog box, given the default value.
1286: */
1287: public String prompt(String message, String defVal) {
1288: if (userAgent != null) {
1289: return userAgent.showPrompt(message, defVal);
1290: }
1291: return null;
1292: }
1293:
1294: /**
1295: * Returns the current BridgeContext.
1296: */
1297: public BridgeContext getBridgeContext() {
1298: return bridgeContext;
1299: }
1300:
1301: /**
1302: * Returns the associated interpreter.
1303: */
1304: public Interpreter getInterpreter() {
1305: return interpreter;
1306: }
1307: }
1308:
1309: /**
1310: * The listener class for 'DOMNodeInserted' event.
1311: */
1312: protected class DOMNodeInsertedListener implements EventListener {
1313: public void handleEvent(Event evt) {
1314: addScriptingListeners((Node) evt.getTarget());
1315: }
1316: }
1317:
1318: /**
1319: * The listener class for 'DOMNodeRemoved' event.
1320: */
1321: protected class DOMNodeRemovedListener implements EventListener {
1322: public void handleEvent(Event evt) {
1323: removeScriptingListeners((Node) evt.getTarget());
1324: }
1325: }
1326:
1327: protected class DOMAttrModifiedListener implements EventListener {
1328: public void handleEvent(Event evt) {
1329: MutationEvent me = (MutationEvent) evt;
1330: if (me.getAttrChange() != MutationEvent.MODIFICATION)
1331: updateScriptingListeners((Element) me.getTarget(), me
1332: .getAttrName());
1333: }
1334: }
1335:
1336: /**
1337: * To handle a scripting event.
1338: */
1339: protected class ScriptingEventListener implements EventListener {
1340:
1341: /**
1342: * The script attribute.
1343: */
1344: protected String attribute;
1345:
1346: /**
1347: * Creates a new ScriptingEventListener.
1348: */
1349: public ScriptingEventListener(String attr) {
1350: attribute = attr;
1351: }
1352:
1353: /**
1354: * Runs the script.
1355: */
1356: public void handleEvent(Event evt) {
1357: Element elt = (Element) evt.getCurrentTarget();
1358: // Evaluate the script
1359: String script = elt.getAttributeNS(null, attribute);
1360: if (script.length() == 0)
1361: return;
1362:
1363: DocumentLoader dl = bridgeContext.getDocumentLoader();
1364: SVGDocument d = (SVGDocument) elt.getOwnerDocument();
1365: int line = dl.getLineNumber(elt);
1366: final String desc = Messages.formatMessage(
1367: EVENT_SCRIPT_DESCRIPTION, new Object[] {
1368: d.getURL(), attribute, new Integer(line) });
1369:
1370: // Find the scripting language
1371: Element e = elt;
1372: while (e != null
1373: && (!SVGConstants.SVG_NAMESPACE_URI.equals(e
1374: .getNamespaceURI()) || !SVGConstants.SVG_SVG_TAG
1375: .equals(e.getLocalName()))) {
1376: e = SVGUtilities.getParentElement(e);
1377: }
1378: if (e == null)
1379: return;
1380:
1381: String lang = e.getAttributeNS(null,
1382: SVGConstants.SVG_CONTENT_SCRIPT_TYPE_ATTRIBUTE);
1383:
1384: runEventHandler(script, evt, lang, desc);
1385: }
1386: }
1387: }
|