001/**********************************************
002 * Copyright (C) 2010 Lukas Laag
003 * This file is part of lib-gwt-svg.
004 * 
005 * libgwtsvg is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Lesser General Public License as published by
007 * the Free Software Foundation, either version 3 of the License, or
008 * (at your option) any later version.
009 * 
010 * libgwtsvg is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public License
016 * along with libgwtsvg.  If not, see http://www.gnu.org/licenses/
017 **********************************************/
018/*
019 * Copyright (c) 2004 World Wide Web Consortium,
020 *
021 * (Massachusetts Institute of Technology, European Research Consortium for
022 * Informatics and Mathematics, Keio University). All Rights Reserved. This
023 * work is distributed under the W3C(r) Software License [1] in the hope that
024 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied
025 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
026 *
027 * [1] http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
028 */
029package org.vectomatic.dom.svg;
030
031import org.vectomatic.dom.svg.impl.DOMEventBus;
032import org.vectomatic.dom.svg.utils.DOMHelper;
033import org.w3c.dom.DOMException;
034
035import com.google.gwt.core.client.JavaScriptException;
036import com.google.gwt.core.client.JavaScriptObject;
037import com.google.gwt.dom.client.Document;
038import com.google.gwt.dom.client.NativeEvent;
039import com.google.gwt.dom.client.Node;
040import com.google.gwt.event.dom.client.DomEvent;
041import com.google.gwt.event.shared.EventBus;
042import com.google.gwt.event.shared.EventHandler;
043import com.google.gwt.event.shared.GwtEvent;
044import com.google.gwt.event.shared.HandlerRegistration;
045import com.google.gwt.event.shared.HasHandlers;
046import com.google.gwt.event.shared.UmbrellaException;
047import com.google.gwt.user.client.Element;
048
049/**
050 * Wrapper class for DOM Node. Wrapper classes decorate native
051 * DOM objects with java-like capabilities: capability to implement
052 * interfaces, notably event handler interfaces.
053 * @author laaglu
054 * @author Michael Allan
055 */
056public class OMNode implements HasHandlers {
057        /**
058         * The DOM native overlay type wrapped by this object
059         */
060        protected final Node ot;
061        /**
062         * The event bus shared by all SVG objects
063         */
064        static protected EventBus eventBus = new DOMEventBus();
065
066        /**
067         * Constructor
068         * @param node The node to wrap
069         */
070        protected OMNode(Node node) {
071                assert getWrapper(node) == null : "node was already wrapped";
072                setWrapper(node, this);
073                this.ot = node;
074        }
075        
076        /**
077         * Sets the __wrapper property of the node.
078         */
079        private static native void setWrapper(Node node, OMNode wrapper) /*-{
080        node.__wrapper = wrapper;
081        }-*/;
082        
083        /**
084         * Returns the __wrapper property of the node.
085         */
086        private static native OMNode getWrapper(Node node) /*-{ 
087                return node.__wrapper; 
088        }-*/;
089        
090        /**
091         * Cleanup method for wrapper objects which are
092         * not needed by the application any more. It
093         * breaks the back-reference the native DOM object
094         * maintains on this wrapper type, in order to
095         * facilitate garbage collection. Use only if
096         * your code needs to run in a browser which is
097         * not equipped with an automatic DOM object-native 
098         * object cycle collector.
099         */
100        public void cleanup() {
101                setWrapper(ot, null);
102        }
103
104        /**
105         * Returns the event bus shared by all SVG objects
106         * @return the event bus shared by all SVG objects
107         */
108        public static EventBus getEventBus() {
109                return eventBus;
110        }
111    /**
112     * Fires the given event to the handlers listening to the event's type.
113     * <p>
114     * Any exceptions thrown by handlers will be bundled into a
115     * {@link UmbrellaException} and then re-thrown after all handlers have
116     * completed. An exception thrown by a handler will not prevent other handlers
117     * from executing.
118     * @param event the event
119     */
120        public void fireEvent(GwtEvent<?> event) {
121                revive(event);
122                eventBus.fireEventFromSource(event, this);
123        }
124        /**
125         * Revive the event. GWT does it by taking advantage of the
126         * fact that HandlerManager has package access to GwtEvent.
127         * Here we use a JSNI call to bypass scope restrictions
128         */
129        private static final native void revive(GwtEvent<?> event) /*-{
130          event.@com.google.gwt.event.shared.GwtEvent::revive()();
131        }-*/;
132        
133        /**
134         * Dispatches the specified event to this node
135         * event handlers
136         * @param event The event to dispatch
137         */
138        public void dispatch(NativeEvent event) {
139                // This call wraps the native event into a DomEvent
140                // and invokes fireEvent
141            DomEvent.fireNativeEvent(event, this, (Element)event.getCurrentEventTarget().cast());
142        }
143
144        /**
145         * Adds a DOM handler to this node's list of handlers
146         * @param <H> The handler type
147         * @param handler The DOM handler
148         * @param type The event type
149         * @return {@link HandlerRegistration} used to remove this handler
150         */
151        public final <H extends EventHandler> HandlerRegistration addDomHandler(
152                        final H handler, DomEvent.Type<H> type) {
153                assert handler != null : "handler must not be null";
154                assert type != null : "type must not be null";
155                DOMHelper.bindEventListener((Element)ot.cast(), type.getName());
156                return eventBus.addHandlerToSource(type, this, handler);
157        }
158
159        /**
160         * Adds a handler to this node's list of handlers
161         * @param <H> The handler type
162         * @param handler The handler
163         * @param type The event type
164         * @return {@link HandlerRegistration} used to remove this handler
165         */
166        public final <H extends EventHandler> HandlerRegistration addHandler(
167                        final H handler, GwtEvent.Type<H> type) {
168                return eventBus.addHandlerToSource(type, this, handler);
169        }
170
171        private static class Conversion<T extends OMNode> {
172                static {
173                        initialize();
174                }
175                private static final native void initialize() /*-{
176                        if ($wnd.otToWrapper == null) {
177                        $wnd.otToWrapper = new Object();
178                    }
179                        $wnd.otToWrapper["SVGAElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAElement::new(Lorg/vectomatic/dom/svg/impl/SVGAElement;)(elem); };
180                        $wnd.otToWrapper["SVGAltGlyphDefElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAltGlyphDefElement::new(Lorg/vectomatic/dom/svg/impl/SVGAltGlyphDefElement;)(elem); };
181                        $wnd.otToWrapper["SVGAltGlyphElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAltGlyphElement::new(Lorg/vectomatic/dom/svg/impl/SVGAltGlyphElement;)(elem); };
182                        $wnd.otToWrapper["SVGAltGlyphItemElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAltGlyphItemElement::new(Lorg/vectomatic/dom/svg/impl/SVGAltGlyphItemElement;)(elem); };
183                        $wnd.otToWrapper["SVGAnimateColorElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAnimateColorElement::new(Lorg/vectomatic/dom/svg/impl/SVGAnimateColorElement;)(elem); };
184                        $wnd.otToWrapper["SVGAnimateElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAnimateElement::new(Lorg/vectomatic/dom/svg/impl/SVGAnimateElement;)(elem); };
185                        $wnd.otToWrapper["SVGAnimateMotionElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAnimateMotionElement::new(Lorg/vectomatic/dom/svg/impl/SVGAnimateMotionElement;)(elem); };
186                        $wnd.otToWrapper["SVGAnimateTransformElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGAnimateTransformElement::new(Lorg/vectomatic/dom/svg/impl/SVGAnimateTransformElement;)(elem); };
187                        $wnd.otToWrapper["SVGCircleElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGCircleElement::new(Lorg/vectomatic/dom/svg/impl/SVGCircleElement;)(elem); };
188                        $wnd.otToWrapper["SVGClipPathElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGClipPathElement::new(Lorg/vectomatic/dom/svg/impl/SVGClipPathElement;)(elem); };
189                        $wnd.otToWrapper["SVGColorProfileElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGColorProfileElement::new(Lorg/vectomatic/dom/svg/impl/SVGColorProfileElement;)(elem); };
190                        $wnd.otToWrapper["SVGCursorElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGCursorElement::new(Lorg/vectomatic/dom/svg/impl/SVGCursorElement;)(elem); };
191                        $wnd.otToWrapper["SVGDefsElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGDefsElement::new(Lorg/vectomatic/dom/svg/impl/SVGDefsElement;)(elem); };
192                        $wnd.otToWrapper["SVGDescElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGDescElement::new(Lorg/vectomatic/dom/svg/impl/SVGDescElement;)(elem); };
193                        $wnd.otToWrapper["SVGDocument"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGDocument::new(Lorg/vectomatic/dom/svg/impl/SVGDocument;)(elem); };
194                        $wnd.otToWrapper["SVGEllipseElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGEllipseElement::new(Lorg/vectomatic/dom/svg/impl/SVGEllipseElement;)(elem); };
195                        $wnd.otToWrapper["SVGFEBlendElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEBlendElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEBlendElement;)(elem); };
196                        $wnd.otToWrapper["SVGFEColorMatrixElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEColorMatrixElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEColorMatrixElement;)(elem); };
197                        $wnd.otToWrapper["SVGFEComponentTransferElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEComponentTransferElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEComponentTransferElement;)(elem); };
198                        $wnd.otToWrapper["SVGFECompositeElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFECompositeElement::new(Lorg/vectomatic/dom/svg/impl/SVGFECompositeElement;)(elem); };
199                        $wnd.otToWrapper["SVGFEConvolveMatrixElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEConvolveMatrixElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEConvolveMatrixElement;)(elem); };
200                        $wnd.otToWrapper["SVGFEDiffuseLightingElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEDiffuseLightingElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEDiffuseLightingElement;)(elem); };
201                        $wnd.otToWrapper["SVGFEDisplacementMapElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEDisplacementMapElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEDisplacementMapElement;)(elem); };
202                        $wnd.otToWrapper["SVGFEDistantLightElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEDistantLightElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEDistantLightElement;)(elem); };
203                        $wnd.otToWrapper["SVGFEFloodElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEFloodElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEFloodElement;)(elem); };
204                        $wnd.otToWrapper["SVGFEFuncAElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEFuncAElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEFuncAElement;)(elem); };
205                        $wnd.otToWrapper["SVGFEFuncBElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEFuncBElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEFuncBElement;)(elem); };
206                        $wnd.otToWrapper["SVGFEFuncGElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEFuncGElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEFuncGElement;)(elem); };
207                        $wnd.otToWrapper["SVGFEFuncRElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEFuncRElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEFuncRElement;)(elem); };
208                        $wnd.otToWrapper["SVGFEGaussianBlurElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEGaussianBlurElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEGaussianBlurElement;)(elem); };
209                        $wnd.otToWrapper["SVGFEImageElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEImageElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEImageElement;)(elem); };
210                        $wnd.otToWrapper["SVGFEMergeElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEMergeElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEMergeElement;)(elem); };
211                        $wnd.otToWrapper["SVGFEMergeNodeElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEMergeNodeElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEMergeNodeElement;)(elem); };
212                        $wnd.otToWrapper["SVGFEMorphologyElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEMorphologyElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEMorphologyElement;)(elem); };
213                        $wnd.otToWrapper["SVGFEOffsetElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEOffsetElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEOffsetElement;)(elem); };
214                        $wnd.otToWrapper["SVGFEPointLightElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFEPointLightElement::new(Lorg/vectomatic/dom/svg/impl/SVGFEPointLightElement;)(elem); };
215                        $wnd.otToWrapper["SVGFESpecularLightingElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFESpecularLightingElement::new(Lorg/vectomatic/dom/svg/impl/SVGFESpecularLightingElement;)(elem); };
216                        $wnd.otToWrapper["SVGFESpotLightElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFESpotLightElement::new(Lorg/vectomatic/dom/svg/impl/SVGFESpotLightElement;)(elem); };
217                        $wnd.otToWrapper["SVGFETileElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFETileElement::new(Lorg/vectomatic/dom/svg/impl/SVGFETileElement;)(elem); };
218                        $wnd.otToWrapper["SVGFETurbulenceElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFETurbulenceElement::new(Lorg/vectomatic/dom/svg/impl/SVGFETurbulenceElement;)(elem); };
219                        $wnd.otToWrapper["SVGFilterElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFilterElement::new(Lorg/vectomatic/dom/svg/impl/SVGFilterElement;)(elem); };
220                        $wnd.otToWrapper["SVGFontElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFontElement::new(Lorg/vectomatic/dom/svg/impl/SVGFontElement;)(elem); };
221                        $wnd.otToWrapper["SVGFontFaceElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFontFaceElement::new(Lorg/vectomatic/dom/svg/impl/SVGFontFaceElement;)(elem); };
222                        $wnd.otToWrapper["SVGFontFaceFormatElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFontFaceFormatElement::new(Lorg/vectomatic/dom/svg/impl/SVGFontFaceFormatElement;)(elem); };
223                        $wnd.otToWrapper["SVGFontFaceNameElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFontFaceNameElement::new(Lorg/vectomatic/dom/svg/impl/SVGFontFaceNameElement;)(elem); };
224                        $wnd.otToWrapper["SVGFontFaceSrcElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFontFaceSrcElement::new(Lorg/vectomatic/dom/svg/impl/SVGFontFaceSrcElement;)(elem); };
225                        $wnd.otToWrapper["SVGFontFaceUriElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGFontFaceUriElement::new(Lorg/vectomatic/dom/svg/impl/SVGFontFaceUriElement;)(elem); };
226                        $wnd.otToWrapper["SVGForeignObjectElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGForeignObjectElement::new(Lorg/vectomatic/dom/svg/impl/SVGForeignObjectElement;)(elem); };
227                        $wnd.otToWrapper["SVGGElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGGElement::new(Lorg/vectomatic/dom/svg/impl/SVGGElement;)(elem); };
228                        $wnd.otToWrapper["SVGGlyphElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGGlyphElement::new(Lorg/vectomatic/dom/svg/impl/SVGGlyphElement;)(elem); };
229                        $wnd.otToWrapper["SVGGlyphRefElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGGlyphRefElement::new(Lorg/vectomatic/dom/svg/impl/SVGGlyphRefElement;)(elem); };
230                        $wnd.otToWrapper["SVGHKernElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGHKernElement::new(Lorg/vectomatic/dom/svg/impl/SVGHKernElement;)(elem); };
231                        $wnd.otToWrapper["SVGImageElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGImageElement::new(Lorg/vectomatic/dom/svg/impl/SVGImageElement;)(elem); };
232                        $wnd.otToWrapper["SVGLinearGradientElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGLinearGradientElement::new(Lorg/vectomatic/dom/svg/impl/SVGLinearGradientElement;)(elem); };
233                        $wnd.otToWrapper["SVGLineElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGLineElement::new(Lorg/vectomatic/dom/svg/impl/SVGLineElement;)(elem); };
234                        $wnd.otToWrapper["SVGMarkerElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGMarkerElement::new(Lorg/vectomatic/dom/svg/impl/SVGMarkerElement;)(elem); };
235                        $wnd.otToWrapper["SVGMaskElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGMaskElement::new(Lorg/vectomatic/dom/svg/impl/SVGMaskElement;)(elem); };
236                        $wnd.otToWrapper["SVGMetadataElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGMetadataElement::new(Lorg/vectomatic/dom/svg/impl/SVGMetadataElement;)(elem); };
237                        $wnd.otToWrapper["SVGMissingGlyphElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGMissingGlyphElement::new(Lorg/vectomatic/dom/svg/impl/SVGMissingGlyphElement;)(elem); };
238                        $wnd.otToWrapper["SVGMPathElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGMPathElement::new(Lorg/vectomatic/dom/svg/impl/SVGMPathElement;)(elem); };
239                        $wnd.otToWrapper["SVGPathElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGPathElement::new(Lorg/vectomatic/dom/svg/impl/SVGPathElement;)(elem); };
240                        $wnd.otToWrapper["SVGPatternElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGPatternElement::new(Lorg/vectomatic/dom/svg/impl/SVGPatternElement;)(elem); };
241                        $wnd.otToWrapper["SVGPolygonElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGPolygonElement::new(Lorg/vectomatic/dom/svg/impl/SVGPolygonElement;)(elem); };
242                        $wnd.otToWrapper["SVGPolylineElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGPolylineElement::new(Lorg/vectomatic/dom/svg/impl/SVGPolylineElement;)(elem); };
243                        $wnd.otToWrapper["SVGRadialGradientElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGRadialGradientElement::new(Lorg/vectomatic/dom/svg/impl/SVGRadialGradientElement;)(elem); };
244                        $wnd.otToWrapper["SVGRectElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGRectElement::new(Lorg/vectomatic/dom/svg/impl/SVGRectElement;)(elem); };
245                        $wnd.otToWrapper["SVGRectElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGRectElement::new(Lorg/vectomatic/dom/svg/impl/SVGRectElement;)(elem); };
246                        $wnd.otToWrapper["SVGScriptElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGScriptElement::new(Lorg/vectomatic/dom/svg/impl/SVGScriptElement;)(elem); };
247                        $wnd.otToWrapper["SVGSetElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGSetElement::new(Lorg/vectomatic/dom/svg/impl/SVGSetElement;)(elem); };
248                        $wnd.otToWrapper["SVGStopElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGStopElement::new(Lorg/vectomatic/dom/svg/impl/SVGStopElement;)(elem); };
249                        $wnd.otToWrapper["SVGStyleElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGStyleElement::new(Lorg/vectomatic/dom/svg/impl/SVGStyleElement;)(elem); };
250                        $wnd.otToWrapper["SVGSVGElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGSVGElement::new(Lorg/vectomatic/dom/svg/impl/SVGSVGElement;)(elem); };
251                        $wnd.otToWrapper["SVGSwitchElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGSwitchElement::new(Lorg/vectomatic/dom/svg/impl/SVGSwitchElement;)(elem); };
252                        $wnd.otToWrapper["SVGSymbolElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGSymbolElement::new(Lorg/vectomatic/dom/svg/impl/SVGSymbolElement;)(elem); };
253                        $wnd.otToWrapper["SVGTextElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGTextElement::new(Lorg/vectomatic/dom/svg/impl/SVGTextElement;)(elem); };
254                        $wnd.otToWrapper["SVGTextPathElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGTextPathElement::new(Lorg/vectomatic/dom/svg/impl/SVGTextPathElement;)(elem); };
255                        $wnd.otToWrapper["SVGTitleElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGTitleElement::new(Lorg/vectomatic/dom/svg/impl/SVGTitleElement;)(elem); };
256                        $wnd.otToWrapper["SVGTRefElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGTRefElement::new(Lorg/vectomatic/dom/svg/impl/SVGTRefElement;)(elem); };
257                        $wnd.otToWrapper["SVGTSpanElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGTSpanElement::new(Lorg/vectomatic/dom/svg/impl/SVGTSpanElement;)(elem); };
258                        $wnd.otToWrapper["SVGUseElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGUseElement::new(Lorg/vectomatic/dom/svg/impl/SVGUseElement;)(elem); };
259                        $wnd.otToWrapper["SVGViewElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGViewElement::new(Lorg/vectomatic/dom/svg/impl/SVGViewElement;)(elem); };
260                        $wnd.otToWrapper["SVGVKernElement"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGVKernElement::new(Lorg/vectomatic/dom/svg/impl/SVGVKernElement;)(elem); };
261                }-*/;
262                T result;
263                Conversion(Node node) {
264                        convert(node);
265                }
266                private final native void convert(Node node) /*-{
267                        var wrapper = null;
268                        if (node != null) {
269                            var type = @org.vectomatic.dom.svg.utils.DOMHelper::getType(Lcom/google/gwt/core/client/JavaScriptObject;)(node);
270                            if (type) {
271                                var ctor = $wnd.otToWrapper[type];
272                                if (ctor != null) {
273                                        wrapper = ctor(node);
274                                } else {
275                                        if (node.nodeType == 1) {
276                                                wrapper = @org.vectomatic.dom.svg.OMElement::new(Lcom/google/gwt/dom/client/Element;)(node);
277                                        } else if (node.nodeType == 2) {
278                                                wrapper = @org.vectomatic.dom.svg.OMAttr::new(Lorg/vectomatic/dom/svg/impl/Attr;)(node);
279                                        } else if (node.nodeType == 3) {
280                                                wrapper = @org.vectomatic.dom.svg.OMText::new(Lcom/google/gwt/dom/client/Text;)(node);
281                                        } else if (node.nodeType == 9) {
282                                                        wrapper = @org.vectomatic.dom.svg.OMSVGDocument::new(Lorg/vectomatic/dom/svg/impl/SVGDocument;)(node);
283                                        } else {
284                                                wrapper = @org.vectomatic.dom.svg.OMNode::new(Lcom/google/gwt/dom/client/Node;)(node);
285                                        }
286                                }
287                            }
288                        }
289                this.@org.vectomatic.dom.svg.OMNode.Conversion::result = wrapper;
290            }-*/;
291        }
292        
293        /**
294         * Returns the wrapper for the specified overlay type node, automatically constructing
295         * a new wrapper if the node was previously unwrapped.
296         * @param <T> the node type
297         * @param obj The overlay type node
298         * @return The node wrapper
299         */
300        public static <T extends OMNode> T convert(Node obj) {
301                // Misleading to parametize by T here, because we cannot guarantee type safety.
302                // The explicit cast below is liable to failure, and so is the implicit cast in
303                // Conversion.  Instead we might try overloading the convert methods, as with a
304                // convert(Element) that safely casts to OMElement.  (Later)
305                @SuppressWarnings("unchecked") T wrapper = (T)getWrapper(obj);
306                if (wrapper == null) wrapper = new Conversion<T>(obj).result;
307                return wrapper;
308        }
309        
310        private static class ListConversion<T extends Iterable<? extends OMNode>> {
311                static {
312                        initialize();
313                }
314                private static final native void initialize() /*-{
315                        if ($wnd.otToWrapper == null) {
316                        $wnd.otToWrapper = new Object();
317                    }
318                        $wnd.otToWrapper["NodeList"] = function(elem) { return @org.vectomatic.dom.svg.OMNodeList::new(Lcom/google/gwt/dom/client/NodeList;)(elem); };
319                        $wnd.otToWrapper["SVGLengthList"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGLengthList::new(Lcom/google/gwt/core/client/JavaScriptObject;)(elem); };
320                        $wnd.otToWrapper["SVGNumberList"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGNumberList::new(Lcom/google/gwt/core/client/JavaScriptObject;)(elem); };
321                        $wnd.otToWrapper["SVGPathSegList"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGPathSegList::new(Lcom/google/gwt/core/client/JavaScriptObject;)(elem); };
322                        $wnd.otToWrapper["SVGPointList"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGPointList::new(Lcom/google/gwt/core/client/JavaScriptObject;)(elem); };
323                        $wnd.otToWrapper["SVGStringList"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGStringList::new(Lcom/google/gwt/core/client/JavaScriptObject;)(elem); };
324                        $wnd.otToWrapper["SVGTransformList"] = function(elem) { return @org.vectomatic.dom.svg.OMSVGTransformList::new(Lcom/google/gwt/core/client/JavaScriptObject;)(elem); };
325                }-*/;
326                T result;
327                ListConversion(JavaScriptObject list) {
328                        convert(list);
329                }
330                private final native void convert(JavaScriptObject list) /*-{
331                        var wrapper = null;
332                    var type = @org.vectomatic.dom.svg.utils.DOMHelper::getType(Lcom/google/gwt/core/client/JavaScriptObject;)(list);
333                    if (type) {
334                        var ctor = $wnd.otToWrapper[type];
335                        if (ctor != null) {
336                                wrapper = ctor(list);
337                        }
338                    }
339                this.@org.vectomatic.dom.svg.OMNode.ListConversion::result = wrapper;
340            }-*/;
341        }
342        
343        /**
344         * Generates a wrapper around an overlay type list
345         * @param <T> the list type
346         * @param obj The overlay type list
347         * @return The list wrapper
348         */
349        public static <T extends Iterable<? extends OMNode>> T convertList(JavaScriptObject obj) {
350                return new ListConversion<T>(obj).result;
351        }
352
353        /**
354         * Returns the wrapped node
355         * @return the wrapped node
356         */
357        public Node getNode() {
358                return ot;
359        }
360                
361        // Implementation of the dom::Node W3C IDL interface
362    /**
363     * The name of this node, depending on its type.
364     * @return name of this node
365     */
366        public final String getNodeName() {
367                return ot.getNodeName();
368        }
369
370    /**
371     * The value of this node, depending on its type. 
372     * When it is defined to be <code>null</code>, setting it has no effect, 
373     * including if the node is read-only.
374     */
375        public final String getNodeValue() {
376                return ot.getNodeValue();
377        }
378
379    /**
380     * The value of this node, depending on its type; see the table above. 
381     * When it is defined to be <code>null</code>, setting it has no effect, 
382     * including if the node is read-only.
383     * @param value The node value
384     * @exception DOMException
385     *   NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly and if 
386     *   it is not defined to be <code>null</code>.
387     */
388        public final void setNodeValue(String value) throws JavaScriptException {
389                ot.setNodeValue(value);
390        }
391
392    /**
393     * A code representing the type of the underlying object.
394     * @return A code representing the type of the underlying object
395     */
396        public final short getNodeType() {
397                return ot.getNodeType();
398        }
399
400    /**
401     * The parent of this node. All nodes, except <code>OMAttr</code>, 
402     * <code>OMDocument</code> may have a parent. 
403     * However, if a node has just been created and not yet added to the 
404     * tree, or if it has been removed from the tree, this is 
405     * <code>null</code>.
406     * @return The parent of this node
407     */
408        public OMNode getParentNode() {
409                Node parentNode = ot.getParentNode();
410                return (parentNode != null) ? convert(parentNode) : null;
411        }
412        
413    /**
414     * A <code>OMNodeList</code> that contains all children of this node. If 
415     * there are no children, this is a <code>OMNodeList</code> containing no 
416     * nodes.
417     * @return A <code>OMNodeList</code> that contains all children of this node. If 
418     */
419        public <T extends OMNode> OMNodeList<T> getChildNodes() {
420                return new OMNodeList<T>(ot.getChildNodes());
421        }
422
423    /**
424     * The first child of this node. If there is no such node, this returns 
425     * <code>null</code>.
426     * @return The first child of this node.
427     */
428        public OMNode getFirstChild() {
429                Node firstChild = ot.getFirstChild();
430                return (firstChild != null) ? convert(firstChild) : null;
431        }
432
433    /**
434     * The last child of this node. If there is no such node, this returns 
435     * <code>null</code>.
436     * @return The last child of this node. 
437     */
438        public OMNode getLastChild() {
439                Node lastChild = ot.getLastChild();
440                return (lastChild != null) ? convert(lastChild) : null;
441        }
442        
443        /**
444     * Returns the local part of the qualified name of this node.
445     * <br>For nodes of any type other than <code>ELEMENT_NODE</code> and 
446     * <code>ATTRIBUTE_NODE</code> and nodes created with a DOM Level 1 
447     * method, such as <code>Document.createElement()</code>, this is always 
448     * <code>null</code>.
449     * @return The local part of the qualified name of this node
450     */
451        public final String getLocalName() {
452                return DOMHelper.getLocalName(ot);
453        }
454
455    /**
456     * The node immediately preceding this node. If there is no such node, 
457     * this returns <code>null</code>.
458     * @return The node immediately preceding this node.
459     */
460        public OMNode getPreviousSibling() {
461                Node previousSibling = ot.getPreviousSibling();
462                return (previousSibling != null) ? convert(previousSibling) : null;
463        }
464
465        /**
466     * The namespace URI of the specified node, or <code>null</code> if it is 
467     * unspecified (see ).
468     * <br>This is not a computed value that is the result of a namespace 
469     * lookup based on an examination of the namespace declarations in 
470     * scope. It is merely the namespace URI given at creation time.
471     * <br>For nodes of any type other than <code>ELEMENT_NODE</code> and 
472     * <code>ATTRIBUTE_NODE</code> and nodes created with a DOM Level 1 
473     * method, such as <code>Document.createElement()</code>, this is always 
474     * <code>null</code>.
475     * <p ><b>Note:</b> Per the <em>Namespaces in XML</em> Specification [<a href='http://www.w3.org/TR/1999/REC-xml-names-19990114/'>XML Namespaces</a>]
476     *  an attribute does not inherit its namespace from the element it is 
477     * attached to. If an attribute is not explicitly given a namespace, it 
478     * simply has no namespace.
479     * @return The namespace URI of this node
480     */
481        public String getNamespaceURI() {
482                return DOMHelper.getNamespaceURI(ot);
483        }
484    /**
485     * The node immediately following this node. If there is no such node, 
486     * this returns <code>null</code>.
487     * @return The node immediately following this node.
488     */
489        public OMNode getNextSibling() {
490                Node nextSibling = ot.getNextSibling();
491                return (nextSibling != null) ? convert(nextSibling) : null;
492        }
493
494    /**
495     * The <code>OMDocument</code> object associated with this node. This is 
496     * also the <code>OMDocument</code> object used to create new nodes. When 
497     * this node is a <code>OMNode</code> 
498     * which is not used with any <code>OMDocument</code> yet, this is 
499     * <code>null</code>.
500     * @return The <code>OMDocument</code> object associated with this node.
501     */
502        public final OMDocument getOwnerDocument() {
503                Document document = ot.getOwnerDocument();
504                return (document != null) ? (OMDocument)convert(document) : null;
505        }
506
507    /**
508     * Inserts the node <code>newChild</code> before the existing child node 
509     * <code>refChild</code>. If <code>refChild</code> is <code>null</code>, 
510     * insert <code>newChild</code> at the end of the list of children.
511     * <br>If <code>newChild</code> is a <code>DocumentFragment</code> object, 
512     * all of its children are inserted, in the same order, before 
513     * <code>refChild</code>. If the <code>newChild</code> is already in the 
514     * tree, it is first removed.
515     * <p ><b>Note:</b>  Inserting a node before itself is implementation 
516     * dependent. 
517     * @param newChild The node to insert.
518     * @param refChild The reference node, i.e., the node before which the 
519     *   new node must be inserted.
520     * @return The node being inserted.
521     * @exception DOMException
522     *   HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not 
523     *   allow children of the type of the <code>newChild</code> node, or if 
524     *   the node to insert is one of this node's ancestors or this node 
525     *   itself, or if this node is of type <code>Document</code> and the 
526     *   DOM application attempts to insert a second 
527     *   <code>DocumentType</code> or <code>Element</code> node.
528     *   <br>WRONG_DOCUMENT_ERR: Raised if <code>newChild</code> was created 
529     *   from a different document than the one that created this node.
530     *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly or 
531     *   if the parent of the node being inserted is readonly.
532     *   <br>NOT_FOUND_ERR: Raised if <code>refChild</code> is not a child of 
533     *   this node.
534     *   <br>NOT_SUPPORTED_ERR: if this node is of type <code>Document</code>, 
535     *   this exception might be raised if the DOM implementation doesn't 
536     *   support the insertion of a <code>DocumentType</code> or 
537     *   <code>Element</code> node.
538     */
539        public OMNode insertBefore(OMNode newChild, OMNode refChild) throws JavaScriptException {
540                ot.insertBefore(newChild.ot, refChild != null ? refChild.ot : null);
541                return newChild;
542        }
543
544    /**
545     * Replaces the child node <code>oldChild</code> with <code>newChild</code>
546     *  in the list of children, and returns the <code>oldChild</code> node.
547     * <br>If <code>newChild</code> is a <code>DocumentFragment</code> object, 
548     * <code>oldChild</code> is replaced by all of the 
549     * <code>DocumentFragment</code> children, which are inserted in the 
550     * same order. If the <code>newChild</code> is already in the tree, it 
551     * is first removed.
552     * <p ><b>Note:</b>  Replacing a node with itself is implementation 
553     * dependent. 
554     * @param newChild The new node to put in the child list.
555     * @param oldChild The node being replaced in the list.
556     * @return The node replaced.
557     * @exception DOMException
558     *   HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not 
559     *   allow children of the type of the <code>newChild</code> node, or if 
560     *   the node to put in is one of this node's ancestors or this node 
561     *   itself, or if this node is of type <code>Document</code> and the 
562     *   result of the replacement operation would add a second 
563     *   <code>DocumentType</code> or <code>Element</code> on the 
564     *   <code>Document</code> node.
565     *   <br>WRONG_DOCUMENT_ERR: Raised if <code>newChild</code> was created 
566     *   from a different document than the one that created this node.
567     *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node or the parent of 
568     *   the new node is readonly.
569     *   <br>NOT_FOUND_ERR: Raised if <code>oldChild</code> is not a child of 
570     *   this node.
571     *   <br>NOT_SUPPORTED_ERR: if this node is of type <code>Document</code>, 
572     *   this exception might be raised if the DOM implementation doesn't 
573     *   support the replacement of the <code>DocumentType</code> child or 
574     *   <code>Element</code> child.
575     */
576        public OMNode replaceChild(OMNode newChild, OMNode oldChild) throws JavaScriptException {
577                ot.replaceChild(newChild.ot, oldChild.ot);
578                return oldChild;
579        }
580
581          /**
582     * Removes the child node indicated by <code>oldChild</code> from the list 
583     * of children, and returns it.
584     * @param oldChild The node being removed.
585     * @return The node removed.
586     * @exception DOMException
587     *   NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
588     *   <br>NOT_FOUND_ERR: Raised if <code>oldChild</code> is not a child of 
589     *   this node.
590     *   <br>NOT_SUPPORTED_ERR: if this node is of type <code>Document</code>, 
591     *   this exception might be raised if the DOM implementation doesn't 
592     *   support the removal of the <code>DocumentType</code> child or the 
593     *   <code>Element</code> child.
594     */
595        public OMNode removeChild(OMNode oldChild) throws JavaScriptException {
596                ot.removeChild(oldChild.ot);
597                return oldChild;
598        }
599
600    /**
601     * Adds the node <code>newChild</code> to the end of the list of children 
602     * of this node. If the <code>newChild</code> is already in the tree, it 
603     * is first removed.
604     * @param newChild The node to add.If it is a 
605     *   <code>DocumentFragment</code> object, the entire contents of the 
606     *   document fragment are moved into the child list of this node
607     * @return The node added.
608     * @exception DOMException
609     *   HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not 
610     *   allow children of the type of the <code>newChild</code> node, or if 
611     *   the node to append is one of this node's ancestors or this node 
612     *   itself, or if this node is of type <code>Document</code> and the 
613     *   DOM application attempts to append a second 
614     *   <code>DocumentType</code> or <code>Element</code> node.
615     *   <br>WRONG_DOCUMENT_ERR: Raised if <code>newChild</code> was created 
616     *   from a different document than the one that created this node.
617     *   <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly or 
618     *   if the previous parent of the node being inserted is readonly.
619     *   <br>NOT_SUPPORTED_ERR: if the <code>newChild</code> node is a child 
620     *   of the <code>Document</code> node, this exception might be raised 
621     *   if the DOM implementation doesn't support the removal of the 
622     *   <code>DocumentType</code> child or <code>Element</code> child.
623     */
624        public OMNode appendChild(OMNode newChild) throws JavaScriptException {
625                ot.appendChild(newChild.ot);
626                return newChild;
627        }
628
629    /**
630     * Returns whether this node has any children.
631     * @return Returns <code>true</code> if this node has any children, 
632     *   <code>false</code> otherwise.
633     */
634        public final boolean hasChildNodes() {
635                return ot.hasChildNodes();
636        }
637
638    /**
639     * Returns a duplicate of this node, i.e., serves as a generic copy 
640     * constructor for nodes. The duplicate node has no parent (
641     * <code>parentNode</code> is <code>null</code>) and no user data. User 
642     * data associated to the imported node is not carried over. However, if 
643     * any <code>UserDataHandlers</code> has been specified along with the 
644     * associated data these handlers will be called with the appropriate 
645     * parameters before this method returns.
646     * <br>Cloning an <code>Element</code> copies all attributes and their 
647     * values, including those generated by the XML processor to represent 
648     * defaulted attributes, but this method does not copy any children it 
649     * contains unless it is a deep clone. This includes text contained in 
650     * an the <code>Element</code> since the text is contained in a child 
651     * <code>Text</code> node. Cloning an <code>Attr</code> directly, as 
652     * opposed to be cloned as part of an <code>Element</code> cloning 
653     * operation, returns a specified attribute (<code>specified</code> is 
654     * <code>true</code>). Cloning an <code>Attr</code> always clones its 
655     * children, since they represent its value, no matter whether this is a 
656     * deep clone or not. Cloning an <code>EntityReference</code> 
657     * automatically constructs its subtree if a corresponding 
658     * <code>Entity</code> is available, no matter whether this is a deep 
659     * clone or not. Cloning any other type of node simply returns a copy of 
660     * this node.
661     * <br>Note that cloning an immutable subtree results in a mutable copy, 
662     * but the children of an <code>EntityReference</code> clone are readonly
663     * . In addition, clones of unspecified <code>Attr</code> nodes are 
664     * specified. And, cloning <code>Document</code>, 
665     * <code>DocumentType</code>, <code>Entity</code>, and 
666     * <code>Notation</code> nodes is implementation dependent.
667     * @param deep If <code>true</code>, recursively clone the subtree under 
668     *   the specified node; if <code>false</code>, clone only the node 
669     *   itself (and its attributes, if it is an <code>Element</code>).
670     * @return The duplicate node.
671     */
672        public OMNode cloneNode(boolean deep) {
673                return convert(ot.cloneNode(deep));
674        }
675
676    /**
677     *  Puts all <code>Text</code> nodes in the full depth of the sub-tree 
678     * underneath this <code>Node</code>, including attribute nodes, into a 
679     * "normal" form where only structure (e.g., elements, comments, 
680     * processing instructions, CDATA sections, and entity references) 
681     * separates <code>Text</code> nodes, i.e., there are neither adjacent 
682     * <code>Text</code> nodes nor empty <code>Text</code> nodes. This can 
683     * be used to ensure that the DOM view of a document is the same as if 
684     * it were saved and re-loaded, and is useful when operations (such as 
685     * XPointer [<a href='http://www.w3.org/TR/2003/REC-xptr-framework-20030325/'>XPointer</a>]
686     *  lookups) that depend on a particular document tree structure are to 
687     * be used. If the parameter "normalize-characters" of the 
688     * <code>DOMConfiguration</code> object attached to the 
689     * <code>Node.ownerDocument</code> is <code>true</code>, this method 
690     * will also fully normalize the characters of the <code>Text</code> 
691     * nodes. 
692     * <p ><b>Note:</b> In cases where the document contains 
693     * <code>CDATASections</code>, the normalize operation alone may not be 
694     * sufficient, since XPointers do not differentiate between 
695     * <code>Text</code> nodes and <code>CDATASection</code> nodes.
696     */
697        public final void normalize() {
698                DOMHelper.normalize(ot);
699        }
700        
701        @Override
702        public String toString() {
703                return ot.toString();
704        }
705}