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 */
029
030package org.vectomatic.dom.svg;
031
032import org.vectomatic.dom.svg.impl.SVGElement;
033
034import com.google.gwt.core.client.JavaScriptException;
035
036/**
037 * All of the SVG DOM interfaces that correspond directly to elements in the
038 * SVG language (such as the {@link org.vectomatic.dom.svg.OMSVGPathElement}
039 * interface for the <a href='http://www.w3.org/TR/SVG11/paths.html#PathElement'
040 * title='path element specification'>path</a> element) derive from the {@link
041 * org.vectomatic.dom.svg.OMSVGElement} interface.
042 */
043public abstract class OMSVGElement extends OMElement {
044  protected OMSVGElement(SVGElement ot) {
045    super(ot);
046  }
047
048  // Implementation of the svg::SVGElement W3C IDL interface
049  /**
050   * Corresponds to attribute <code>xml:base</code> on the given element.
051   */
052  public final String getXmlbase() {
053    return ((SVGElement)ot).getXmlbase();
054  }
055  /**
056   * Corresponds to attribute <code>xml:base</code> on the given element.
057   * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) Raised on an attempt
058   * to change the value of a <a href="svgdom.html#ReadOnlyNodes">read only
059   * attribute</a>.
060   */
061  public final void setXmlbase(java.lang.String value) throws JavaScriptException {
062    ((SVGElement)ot).setXmlbase(value);
063  }
064  /**
065   * The nearest ancestor <a href='http://www.w3.org/TR/SVG11/struct.html#SVGElement'
066   * title='svg element specification'>svg</a> element. Null if the given element
067   * is the outermost <a href='http://www.w3.org/TR/SVG11/struct.html#SVGElement'
068   * title='svg element specification'>svg</a> element.
069   */
070  public final OMSVGSVGElement getOwnerSVGElement() {
071    return (OMSVGSVGElement)convert(((SVGElement)ot).getOwnerSVGElement());
072  }
073  /**
074   * The element which established the current viewport. Often, the nearest
075   * ancestor <a href='http://www.w3.org/TR/SVG11/struct.html#SVGElement' title='svg
076   * element specification'>svg</a> element. Null if the given element is the
077   * outermost <a href='http://www.w3.org/TR/SVG11/struct.html#SVGElement' title='svg
078   * element specification'>svg</a> element.
079   */
080  public final OMSVGElement getViewportElement() {
081    return (OMSVGElement)convert(((SVGElement)ot).getViewportElement());
082  }
083
084  /**
085   * Sets the 'id' attribute of the specified element
086   * @param value the value of the 'id' attribute
087   */
088  public final void setId(java.lang.String value) {
089    ((SVGElement)ot).setId(value);
090  }
091
092  // Implementation of the svg::Stylable W3C IDL interface
093  /**
094   * Returns the CSS style of this element
095   */
096  public OMSVGStyle getStyle() {
097        return ((SVGElement) ot).getStyle().cast();
098  }
099
100  /**
101   * Returns the CSS class name of this element. Note that
102   * in SVG, this class name can change over the time (there is
103   * a baseVal and an animVal).
104   * @return the CSS class name of this element
105   */
106  public final OMSVGAnimatedString getClassName() {
107    return ((SVGElement) ot).getClassName_();
108  }
109
110  /**
111   * Adds the specified class name to the baseVal CSS class name of this element
112   * @param className the class name to add
113   */
114  public final void addClassNameBaseVal(String className) {
115    assert (className != null) : "Unexpectedly null class name";
116
117    className = className.trim();
118    assert (className.length() != 0) : "Unexpectedly empty class name";
119
120    // Get the current style string.
121    String oldClassName = getClassName().getBaseVal();
122    int idx = oldClassName.indexOf(className);
123
124    // Calculate matching index.
125    while (idx != -1) {
126      if (idx == 0 || oldClassName.charAt(idx - 1) == ' ') {
127        int last = idx + className.length();
128        int lastPos = oldClassName.length();
129        if ((last == lastPos)
130            || ((last < lastPos) && (oldClassName.charAt(last) == ' '))) {
131          break;
132        }
133      }
134      idx = oldClassName.indexOf(className, idx + 1);
135    }
136
137    // Only add the style if it's not already present.
138    if (idx == -1) {
139      if (oldClassName.length() > 0) {
140        oldClassName += " ";
141      }
142      setClassNameBaseVal(oldClassName + className);
143    }
144  }
145
146  /**
147   * Removes the specified class name from the baseVal CSS class name of this element
148   * @param className the class name to remove
149   */
150  public final void removeClassNameBaseVal(String className) {
151    assert (className != null) : "Unexpectedly null class name";
152
153    className = className.trim();
154    assert (className.length() != 0) : "Unexpectedly empty class name";
155
156    // Get the current style string.
157    String oldStyle = getClassName().getBaseVal();
158    int idx = oldStyle.indexOf(className);
159
160    // Calculate matching index.
161    while (idx != -1) {
162      if (idx == 0 || oldStyle.charAt(idx - 1) == ' ') {
163        int last = idx + className.length();
164        int lastPos = oldStyle.length();
165        if ((last == lastPos)
166            || ((last < lastPos) && (oldStyle.charAt(last) == ' '))) {
167          break;
168        }
169      }
170      idx = oldStyle.indexOf(className, idx + 1);
171    }
172
173    // Don't try to remove the style if it's not there.
174    if (idx != -1) {
175      // Get the leading and trailing parts, without the removed name.
176      String begin = oldStyle.substring(0, idx).trim();
177      String end = oldStyle.substring(idx + className.length()).trim();
178
179      // Some contortions to make sure we don't leave extra spaces.
180      String newClassName;
181      if (begin.length() == 0) {
182        newClassName = end;
183      } else if (end.length() == 0) {
184        newClassName = begin;
185      } else {
186        newClassName = begin + " " + end;
187      }
188
189      setClassNameBaseVal(newClassName);
190    }
191  }
192
193  /**
194   * Replaces the specified class name in the baseVal CSS class name of this element
195   * with a new class name
196   * @param oldClassName the class name to replace
197   * @param newClassName the replacement class name
198   */
199  public final void replaceClassNameBaseVal(String oldClassName, String newClassName) {
200    removeClassNameBaseVal(oldClassName);
201    addClassNameBaseVal(newClassName);
202  }
203
204  /**
205   * Sets the baseVal CSS class name of this element to the specified value
206   * @param className the class name
207   */
208  public final void setClassNameBaseVal(String className) {
209    getClassName().setBaseVal(className);
210  }
211  
212  /**
213   * Returns the XML markup which corresponds to the subtree rooted
214   * at this element
215   * @return the XML markup which corresponds to the subtree rooted
216   * at this element
217   */
218  public final String getMarkup() {
219        return ((SVGElement) ot).getMarkup();
220  }
221}