001: /*
002:
003: Licensed to the Apache Software Foundation (ASF) under one or more
004: contributor license agreements. See the NOTICE file distributed with
005: this work for additional information regarding copyright ownership.
006: The ASF licenses this file to You under the Apache License, Version 2.0
007: (the "License"); you may not use this file except in compliance with
008: the License. You may obtain a copy of the License at
009:
010: http://www.apache.org/licenses/LICENSE-2.0
011:
012: Unless required by applicable law or agreed to in writing, software
013: distributed under the License is distributed on an "AS IS" BASIS,
014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: See the License for the specific language governing permissions and
016: limitations under the License.
017:
018: */
019: package org.apache.batik.bridge.svg12;
020:
021: import org.apache.batik.bridge.AbstractGraphicsNodeBridge;
022: import org.apache.batik.bridge.Bridge;
023: import org.apache.batik.bridge.BridgeContext;
024: import org.apache.batik.bridge.GVTBuilder;
025: import org.apache.batik.bridge.SVGUtilities;
026: import org.apache.batik.bridge.ScriptingEnvironment;
027: import org.apache.batik.bridge.UpdateManager;
028: import org.apache.batik.dom.svg12.BindableElement;
029: import org.apache.batik.gvt.CompositeGraphicsNode;
030: import org.apache.batik.gvt.GraphicsNode;
031:
032: import org.w3c.dom.Element;
033: import org.w3c.dom.Node;
034: import org.w3c.dom.events.MutationEvent;
035:
036: /**
037: * Bridge class for foreign namespace elements that can be bound with sXBL.
038: *
039: * @author <a href="mailto:cam%40mcc%2eid%2eau">Cameron McCormack</a>
040: * @version $Id: BindableElementBridge.java 475477 2006-11-15 22:44:28Z cam $
041: */
042: public class BindableElementBridge extends AbstractGraphicsNodeBridge
043: implements SVG12BridgeUpdateHandler {
044:
045: /**
046: * Constructs a new bridge for custom elements.
047: */
048: public BindableElementBridge() {
049: }
050:
051: /**
052: * Returns "*" to indicate a default bridge.
053: */
054: public String getNamespaceURI() {
055: return "*";
056: }
057:
058: /**
059: * Returns "*" to indicate a default bridge.
060: */
061: public String getLocalName() {
062: return "*";
063: }
064:
065: /**
066: * Returns a new instance of this bridge.
067: */
068: public Bridge getInstance() {
069: return new BindableElementBridge();
070: }
071:
072: /**
073: * Creates a <tt>GraphicsNode</tt> according to the specified parameters.
074: *
075: * @param ctx the bridge context to use
076: * @param e the element that describes the graphics node to build
077: * @return a graphics node that represents the specified element
078: */
079: public GraphicsNode createGraphicsNode(BridgeContext ctx, Element e) {
080: // 'requiredFeatures', 'requiredExtensions' and 'systemLanguage'
081: if (!SVGUtilities.matchUserAgent(e, ctx.getUserAgent())) {
082: return null;
083: }
084:
085: CompositeGraphicsNode gn = buildCompositeGraphicsNode(ctx, e,
086: null);
087:
088: return gn;
089: }
090:
091: /**
092: * Creates a <tt>GraphicsNode</tt> from the input element and
093: * populates the input <tt>CompositeGraphicsNode</tt>
094: *
095: * @param ctx the bridge context to use
096: * @param e the element that describes the graphics node to build
097: * @param gn the CompositeGraphicsNode where the use graphical
098: * content will be appended. The composite node is emptied
099: * before appending new content.
100: */
101: public CompositeGraphicsNode buildCompositeGraphicsNode(
102: BridgeContext ctx, Element e, CompositeGraphicsNode gn) {
103:
104: BindableElement be = (BindableElement) e;
105: Element shadowTree = be.getXblShadowTree();
106:
107: UpdateManager um = ctx.getUpdateManager();
108: ScriptingEnvironment se = um == null ? null : um
109: .getScriptingEnvironment();
110:
111: if (se != null && shadowTree != null) {
112: se.addScriptingListeners(shadowTree);
113: }
114:
115: if (gn == null) {
116: gn = new CompositeGraphicsNode();
117: associateSVGContext(ctx, e, gn);
118: } else {
119: int s = gn.size();
120: for (int i = 0; i < s; i++) {
121: gn.remove(0);
122: }
123: }
124:
125: GVTBuilder builder = ctx.getGVTBuilder();
126:
127: if (shadowTree != null) {
128: GraphicsNode shadowNode = builder.build(ctx, shadowTree);
129: if (shadowNode != null) {
130: gn.add(shadowNode);
131: }
132: } else {
133: for (Node m = e.getFirstChild(); m != null; m = m
134: .getNextSibling()) {
135: if (m.getNodeType() == Node.ELEMENT_NODE) {
136: GraphicsNode n = builder.build(ctx, (Element) m);
137: if (n != null) {
138: gn.add(n);
139: }
140: }
141: }
142: }
143:
144: return gn;
145: }
146:
147: public void dispose() {
148: BindableElement be = (BindableElement) e;
149: if (be != null && be.getCSSFirstChild() != null) {
150: disposeTree(be.getCSSFirstChild());
151: }
152:
153: super .dispose();
154: }
155:
156: /**
157: * Creates the GraphicsNode depending on the GraphicsNodeBridge
158: * implementation.
159: */
160: protected GraphicsNode instantiateGraphicsNode() {
161: return null; // nothing to do, createGraphicsNode is fully overriden
162: }
163:
164: /**
165: * Returns false as the custom element is a not container.
166: */
167: public boolean isComposite() {
168: return false;
169: }
170:
171: /**
172: * Builds using the specified BridgeContext and element, the
173: * specified graphics node.
174: *
175: * @param ctx the bridge context to use
176: * @param e the element that describes the graphics node to build
177: * @param node the graphics node to build
178: */
179: public void buildGraphicsNode(BridgeContext ctx, Element e,
180: GraphicsNode node) {
181:
182: initializeDynamicSupport(ctx, e, node);
183: }
184:
185: // BridgeUpdateHandler implementation //////////////////////////////////
186:
187: /**
188: * Invoked when an MutationEvent of type 'DOMNodeInserted' is fired.
189: */
190: public void handleDOMNodeInsertedEvent(MutationEvent evt) {
191: // Only rebuild the graphics tree if this custom element is not bound.
192: BindableElement be = (BindableElement) e;
193: Element shadowTree = be.getXblShadowTree();
194:
195: if (shadowTree == null && evt.getTarget() instanceof Element) {
196: handleElementAdded((CompositeGraphicsNode) node, e,
197: (Element) evt.getTarget());
198: }
199: }
200:
201: /**
202: * Invoked when a bindable element's binding has changed.
203: */
204: public void handleBindingEvent(Element bindableElement,
205: Element shadowTree) {
206: CompositeGraphicsNode gn = node.getParent();
207: gn.remove(node);
208: disposeTree(e);
209:
210: handleElementAdded(gn, e.getParentNode(), e);
211: }
212:
213: /**
214: * Invoked when the xblChildNodes property has changed because a
215: * descendant xbl:content element has updated its selected nodes.
216: */
217: public void handleContentSelectionChangedEvent(
218: ContentSelectionChangedEvent csce) {
219: }
220:
221: /**
222: * Rebuild the graphics tree.
223: */
224: protected void handleElementAdded(CompositeGraphicsNode gn,
225: Node parent, Element childElt) {
226: // build the graphics node
227: GVTBuilder builder = ctx.getGVTBuilder();
228: GraphicsNode childNode = builder.build(ctx, childElt);
229: if (childNode == null) {
230: return; // the added element is not a graphic element
231: }
232:
233: // Find the index where the GraphicsNode should be added
234: int idx = -1;
235: for (Node ps = childElt.getPreviousSibling(); ps != null; ps = ps
236: .getPreviousSibling()) {
237: if (ps.getNodeType() != Node.ELEMENT_NODE)
238: continue;
239: Element pse = (Element) ps;
240: GraphicsNode psgn = ctx.getGraphicsNode(pse);
241: while ((psgn != null) && (psgn.getParent() != gn)) {
242: // In some cases the GN linked is
243: // a child (in particular for images).
244: psgn = psgn.getParent();
245: }
246: if (psgn == null)
247: continue;
248: idx = gn.indexOf(psgn);
249: if (idx == -1)
250: continue;
251: break;
252: }
253: // insert after prevSibling, if
254: // it was -1 this becomes 0 (first slot)
255: idx++;
256: gn.add(idx, childNode);
257: }
258: }
|