vhardy      2003/07/09 06:31:45

  Modified:    samples/tests/spec/scripting use.svg
               test-references/samples/tests/spec/scripting use.png
               sources/org/apache/batik/bridge SVGUseElementBridge.java
  Log:
  Fixed bug 21358. It is now possible (even though sub-optimal) to modify the 
xlink:href on a <use> and to modify the content referenced by a <use>. See the 
samples/tests/spec/scripting/use.svg sample. New reference image for test.
  
  Revision  Changes    Path
  1.3       +90 -24    xml-batik/samples/tests/spec/scripting/use.svg
  
  Index: use.svg
  ===================================================================
  RCS file: /home/cvs/xml-batik/samples/tests/spec/scripting/use.svg,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- use.svg   24 Jul 2002 11:50:25 -0000      1.2
  +++ use.svg   9 Jul 2003 13:31:42 -0000       1.3
  @@ -24,18 +24,57 @@
       <text x="50%" y="45" class="title">x/y/transform update on &lt;use&gt;</text>
   
       <script type="text/ecmascript"> <![CDATA[
  +    var xlinkNS = 'http://www.w3.org/1999/xlink';
  +    var svgNS = 'http://www.w3.org/2000/svg';
   
       function runTest(){
           document.getElementById('x').setAttributeNS(null, 'x', '20');
           document.getElementById('y').setAttributeNS(null, 'y', '15');
           document.getElementById('transform').setAttributeNS(null, 'transform', 
'rotate(20)');
  +        document.getElementById('xlink').setAttributeNS(xlinkNS, 'xlink:href', 
'#symbol2');
  +
  +        var mutated = document.getElementById('mutatedSymbol');
  +        while(mutated.firstChild != null) {
  +            mutated.removeChild(mutated.firstChild);
  +        }
  +        var r = document.createElementNS(svgNS, 'rect');
  +        r.setAttributeNS(null, "x", "-10");
  +        r.setAttributeNS(null, "y", "-10");
  +        r.setAttributeNS(null, "width", "20");
  +        r.setAttributeNS(null, "height", "20");
  +        r.setAttributeNS(null, "stroke-width", "4");
  +        r.setAttributeNS(null, "stroke", "gold");
  +        r.setAttributeNS(null, "fill", "crimson");
  +        mutated.appendChild(r);
  +
  +        var t = document.createElementNS(svgNS, "text");
  +        mutated.appendChild(t);
  +        t.setAttributeNS(null, "text-anchor", "middle");
  +        t.setAttributeNS(null, "fill", "gold");
  +        t.setAttributeNS(null, "stroke", "none");
  +        t.setAttributeNS(null, "y", "5");
  +        var msg = document.createTextNode("Hello");
  +        t.appendChild(msg);
  +
  +        msg.data = "Hi";
       }
   
  -    ]]> </script>
  +    ]]> </script>        <rect id="symbol" x="-10" y="-10" width="20" height="20" />
  +
   
   
       <defs>    
           <rect id="symbol" x="-10" y="-10" width="20" height="20" />
  +        <rect id="symbol2" x="-10" y="-10" width="20" height="20" stroke-width="4" 
stroke="gold" fill="crimson" />
  +
  +        <g id="mutatedSymbolReference">
  +            <rect x="-10" y="-10" width="20" height="20" stroke-width="4" 
stroke="gold" fill="crimson" />
  +            <text text-anchor="middle" y="5" fill="gold" stroke="none">Hi</text>
  +        </g>
  +
  +        <g id="mutatedSymbol">
  +            <rect x="-12" y="-12" width="24" height="24" class="reference" />
  +        </g>
   
           <rect id="titleCell" x="-60" y="-15" width="120" height="20" />
           <rect id="tableCell" x="-60" y="-20" width="120" height="40" />
  @@ -90,7 +129,7 @@
           
       ]]></style>
   
  -    <g transform="translate(165, 160)">
  +    <g transform="translate(165, 120)">
           <g id="tableHeader" class="tableHeader">
               <g>
                   <use class="tableHeader" xlink:href="#titleCell" />
  @@ -147,31 +186,58 @@
   
           </g>
   
  -        <g onclick="runTest()">
  +        <g id="xlinkRow" transform="translate(0,145)">
  +            <g>
  +                <use class="tableCell" xlink:href="#tableCell" />
  +                <text class="tableCell">xlink:href</text>
  +            </g>
  +
  +            <g transform="translate(120,0)" >
  +                <use class="tableCell" xlink:href="#tableCell" />
  +                <use id="xlink" 
  +                     x="5" y="0"  class="symbol" xlink:href="#symbol"/>
  +                <use x="5" y="0"  class="reference" xlink:href="#symbol"/>
  +            </g>
  +
  +        </g>
  +
  +        <g id="mutation" transform="translate(0,185)">
  +            <g>
  +                <use class="tableCell" xlink:href="#tableCell" />
  +                <text class="tableCell">mutation</text>
  +            </g>
  +
  +            <g transform="translate(120,0)" >
  +                <use class="tableCell" xlink:href="#tableCell" />
  +                <use id="xlink" 
  +                     x="-25" y="0"  class="symbol" 
xlink:href="#mutatedSymbolReference"/>
  +                <use x="25" y="0"  class="reference" xlink:href="#mutatedSymbol"/>
  +            </g>
  +
  +        </g>
  +
  +        <g onclick="runTest()" transform="translate(0, 80)">
               <use class="button" xlink:href="#button" x="60" y="200" />
               <text class="button" x="60" y="200">Run Test</text>
           </g>
       </g>
    
  -<!--
  -  <use id="use" xlink:href="#Rect" x="20" y="40" width="100" height="80"
  -       transform="scale(1.2)" onclick="scale('use')" />
  -
  -  <a onclick="removeChangeAdd('use')">
  -        <text x="80" y="35" text-anchor="middle">Remove, modify, add</text>
  -  </a>
  -
  -  <a onclick="removeChangeAdd('rect')" transform="translate(160,0)">
  -        <text x="80" y="35" text-anchor="middle">Remove, modify, add</text>
  -  </a>
  -
  -  <rect id="rect" x="150" y="40" width="100" height="80" transform="scale(1.2)"
  -        style="fill:green; stroke:yellow" onclick="scale('rect')" />
  -
  -
  -  <text x="175" y="190" style="font-size:20pt; text-anchor:middle">
  -    Transform problem.
  -  </text>
  --->
  +
  +
  +    <script type="text/ecmascript"><![CDATA[
  +function onDone() {
  +    if (!(regardTestInstance == null)) {
  +        regardTestInstance.scriptDone();   
  +    } else {
  +        alert("This button only works when run in the regard framework");
  +    }
  +}
  +    ]]></script>
  +    <g id="done" transform="translate(195, 468)" cursor="pointer" 
onclick="onDone()">
  +        <rect rx="5" ry="5" width="60" height="25" fill="#eeeeee" stroke="black" />
  +        <text x="30" y="18" font-size="14" font-weight="bold" 
text-anchor="middle">Done</text>
  +    </g>
  +
  +
   </svg>
   
  
  
  
  1.3       +26 -28    xml-batik/test-references/samples/tests/spec/scripting/use.png
  
        <<Binary file>>
  
  
  1.33      +113 -2    
xml-batik/sources/org/apache/batik/bridge/SVGUseElementBridge.java
  
  Index: SVGUseElementBridge.java
  ===================================================================
  RCS file: 
/home/cvs/xml-batik/sources/org/apache/batik/bridge/SVGUseElementBridge.java,v
  retrieving revision 1.32
  retrieving revision 1.33
  diff -u -r1.32 -r1.33
  --- SVGUseElementBridge.java  11 Jun 2003 22:07:25 -0000      1.32
  +++ SVGUseElementBridge.java  9 Jul 2003 13:31:44 -0000       1.33
  @@ -34,6 +34,12 @@
    * @version $Id$
    */
   public class SVGUseElementBridge extends AbstractGraphicsNodeBridge {
  +    /*
  +     * Used to handle mutation of the referenced content. This is
  +     * only used in dynamic context and only for reference to local
  +     * content.
  +     */
  +    protected ReferencedElementMutationListener l;
   
       /**
        * Constructs a new bridge for the &lt;use> element.
  @@ -67,6 +73,25 @@
               return null;
           }
   
  +        CompositeGraphicsNode gn = buildCompositeGraphicsNode(ctx, e, 
  +                                                              null, null);
  +
  +        return gn;
  +    }
  +
  +    /**
  +     * Creates a <tt>GraphicsNode</tt> from the input element and
  +     * populates the input <tt>CompositeGraphicsNode</tt>
  +     *
  +     * @param ctx the bridge context to use
  +     * @param e the element that describes the graphics node to build
  +     * @param gn the CompositeGraphicsNode where the use graphical 
  +     *        content will be appended. The composite node is emptied
  +     *        before appending new content.
  +     */
  +    public CompositeGraphicsNode buildCompositeGraphicsNode(BridgeContext ctx, 
Element e,
  +                                                            CompositeGraphicsNode 
gn,
  +                                                            
ReferencedElementMutationListener l) {
           // get the referenced element
           String uri = XLinkSupport.getXLinkHref(e);
           if (uri.length() == 0)
  @@ -142,8 +167,19 @@
           GraphicsNode refNode = builder.build(ctx, g);
   
           ///////////////////////////////////////////////////////////////////////
  +        boolean update = true;
  +        if (gn == null) {
  +            gn = new CompositeGraphicsNode();
  +            update = false;
  +        }
  +
  +        if (update) {
  +            int s = gn.size();
  +            for (int i=0; i<s; i++) {
  +                gn.remove(0);
  +            }
  +        }
   
  -        CompositeGraphicsNode gn = new CompositeGraphicsNode();
           gn.getChildren().add(refNode);
   
           gn.setTransform(computeTransform(e, ctx));
  @@ -159,6 +195,59 @@
           if (r != null) {
               gn.setBackgroundEnable(r);
           }
  +
  +        ///////////////////////////////////////////////////////////////////////
  +        
  +        // Handle mutations on content referenced in the same file if
  +        // we are in a dynamic context.
  +        if (isLocal && ctx.isDynamic()) {
  +            if (l == null) {
  +                l = new ReferencedElementMutationListener();
  +                l.target = (EventTarget)refElement;
  +            } else {
  +                // Remove event listeners
  +                EventTarget target = l.target;
  +                target.removeEventListener("DOMAttrModified",
  +                                           l,
  +                                           true);
  +                
  +                target.removeEventListener("DOMNodeInserted",
  +                                           l,
  +                                           true);
  +                
  +                target.removeEventListener("DOMNodeRemoved",
  +                                           l,
  +                                           true);
  +                
  +                target.removeEventListener("DOMCharacterDataModified",
  +                                           l,
  +                                           true);
  +            }
  +        
  +            EventTarget target = (EventTarget)refElement;
  +            l.target = target;
  +            
  +            target.addEventListener("DOMAttrModified",
  +                                    l,
  +                                    true);
  +            ctx.storeEventListener(target, "DOMAttrModified", l, true);
  +            
  +            target.addEventListener("DOMNodeInserted",
  +                                    l,
  +                                    true);
  +            ctx.storeEventListener(target, "DOMNodeInserted", l, true);
  +            
  +            target.addEventListener("DOMNodeRemoved",
  +                                    l,
  +                                    true);
  +            ctx.storeEventListener(target, "DOMNodeRemoved", l, true);
  +            
  +            target.addEventListener("DOMCharacterDataModified",
  +                                    l,
  +                                    true);
  +            ctx.storeEventListener(target, "DOMCharacterDataModified", l, true);
  +        }
  +        
           return gn;
       }
   
  @@ -262,6 +351,22 @@
           }
       }
   
  +    /**
  +     * Used to handle modifications to the referenced content
  +     */
  +    public class ReferencedElementMutationListener implements EventListener {
  +        EventTarget target;
  +
  +        public void handleEvent(Event evt) {
  +            // We got a mutation in the referenced content. We need to 
  +            // build the content again, just in case.
  +            // Note that this is way sub-optimal, because multiple changes
  +            // to the referenced content will cause multiple updates to the
  +            // referencing <use>. However, this provides the desired behavior
  +            buildCompositeGraphicsNode(ctx, e, (CompositeGraphicsNode)node, this);
  +        }
  +    }
  +
       // BridgeUpdateHandler implementation //////////////////////////////////
   
       /**
  @@ -269,12 +374,18 @@
        */
       public void handleDOMAttrModifiedEvent(MutationEvent evt) {
           String attrName = evt.getAttrName();
  +        Node evtNode = evt.getRelatedNode();
  +
           if (attrName.equals(SVG_X_ATTRIBUTE) ||
               attrName.equals(SVG_Y_ATTRIBUTE) ||
               attrName.equals(SVG_TRANSFORM_ATTRIBUTE)) {
               String s = evt.getNewValue();
               node.setTransform(computeTransform(e, ctx));
               handleGeometryChanged();
  +        } else if (( XLinkSupport.XLINK_NAMESPACE_URI.equals
  +                     (evtNode.getNamespaceURI()) ) 
  +                   && SVG_HREF_ATTRIBUTE.equals(evtNode.getLocalName()) ){
  +            buildCompositeGraphicsNode(ctx, e, (CompositeGraphicsNode)node, l);
           }
       }
   }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to