001package com.hfg.svg;
002
003import com.hfg.util.Recursion;
004import com.hfg.util.StringUtil;
005import com.hfg.util.collection.CollectionUtil;
006import com.hfg.xml.XMLAttribute;
007import com.hfg.xml.XMLContainer;
008import com.hfg.xml.XMLNamespace;
009import com.hfg.html.HTML;
010import com.hfg.xml.XMLNode;
011import com.hfg.xml.XMLTag;
012
013import java.awt.*;
014import java.awt.geom.AffineTransform;
015import java.awt.geom.Rectangle2D;
016import java.util.List;
017
018//------------------------------------------------------------------------------
019/**
020 Object representation of an SVG (Scalable Vector Graphics) 'use' tag.
021 <p>
022 See <a href='http://www.w3.org/TR/SVG11/struct.html#UseElement'>http://www.w3.org/TR/SVG11/struct.html#UseElement</a>
023 </p>
024 @author J. Alex Taylor, hairyfatguy.com
025 */
026//------------------------------------------------------------------------------
027// com.hfg XML/HTML Coding Library
028//
029// This library is free software; you can redistribute it and/or
030// modify it under the terms of the GNU Lesser General Public
031// License as published by the Free Software Foundation; either
032// version 2.1 of the License, or (at your option) any later version.
033//
034// This library is distributed in the hope that it will be useful,
035// but WITHOUT ANY WARRANTY; without even the implied warranty of
036// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
037// Lesser General Public License for more details.
038//
039// You should have received a copy of the GNU Lesser General Public
040// License along with this library; if not, write to the Free Software
041// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
042//
043// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
044// jataylor@hairyfatguy.com
045//------------------------------------------------------------------------------
046
047public class SvgUse extends AbstractSvgNode implements SvgNode
048{
049   //##########################################################################
050   // CONSTRUCTORS
051   //##########################################################################
052
053   //---------------------------------------------------------------------------
054   public SvgUse(String inURL)
055   {
056      this(inURL, null);
057   }
058
059   //---------------------------------------------------------------------------
060   public SvgUse(String inURL, Point inLocation)
061   {
062      super(SVG.use);
063
064      XMLAttribute attr = new XMLAttribute(HTML.HREF, inURL);
065      attr.setNamespace(XMLNamespace.XLINK);
066      setAttribute(attr);
067
068      if (inLocation != null)
069      {
070         setAttribute(SvgAttr.x, (int) inLocation.getX());
071         setAttribute(SvgAttr.y, (int) inLocation.getY());
072      }
073   }
074
075   //---------------------------------------------------------------------------
076   public SvgUse(XMLTag inXMLTag)
077   {
078      super(SVG.use);
079
080      initFromXMLTag(inXMLTag);
081   }
082
083   //##########################################################################
084   // PUBLIC METHODS
085   //##########################################################################
086
087   //--------------------------------------------------------------------------
088   public String getURL()
089   {
090      return getAttributeValue(HTML.HREF);
091   }
092
093   //--------------------------------------------------------------------------
094   @Override
095   public void draw(Graphics2D g2)
096   {
097      // Save settings
098      Font   origFont   = g2.getFont();
099      Paint  origPaint  = g2.getPaint();
100      Stroke origStroke = g2.getStroke();
101      Color  origBackground = g2.getBackground();
102      AffineTransform origTransform = null;
103
104      if (getAttributeValue(SvgAttr.transform) != null)
105      {
106         origTransform = g2.getTransform();
107
108         applyTransform(g2, getAttributeValue(SvgAttr.transform));
109      }
110
111      Font locallyAdjustedFont = getAdjustedFont(origFont);
112      if (locallyAdjustedFont != null)
113      {
114         g2.setFont(locallyAdjustedFont);
115      }
116
117      AbstractSvgNode svgDefNode = null;
118
119      String url = getURL();
120      if (StringUtil.isSet(url)
121            && url.startsWith("#"))
122      {
123         svgDefNode = getLocallyReferencedDefNode();
124      }
125
126      if (svgDefNode != null)
127      {
128         svgDefNode.draw(g2);
129      }
130
131      // Restore settings
132      g2.setFont(origFont);
133      g2.setPaint(origPaint);
134      g2.setStroke(origStroke);
135      g2.setBackground(origBackground);
136      if (origTransform != null)
137      {
138         g2.setTransform(origTransform);
139      }
140   }
141
142   //---------------------------------------------------------------------------
143   @Override
144   public Rectangle2D getBoundsBox()
145   {
146      AbstractSvgNode svgDefNode = getLocallyReferencedDefNode();
147
148      Rectangle2D boundsBox = (svgDefNode != null ? svgDefNode.getBoundsBox() :  null);
149      if (boundsBox != null)
150      {
151         adjustBoundsForTransform(boundsBox);
152      }
153
154      return boundsBox;
155   }
156
157   //##########################################################################
158   // PRIVATE METHODS
159   //##########################################################################
160
161   //--------------------------------------------------------------------------
162   private AbstractSvgNode getLocallyReferencedDefNode()
163   {
164      AbstractSvgNode svgDefNode = null;
165
166      String url = getURL();
167      if (StringUtil.isSet(url)
168            && url.startsWith("#"))
169      {
170         // This is a little tricky. We need to find the def referenced by the URL
171         // by traversing up the DOM structure and then locating any matching defs.
172         XMLContainer parentNode = getParentNode();
173         while (parentNode.getParentNode() != null)
174         {
175            parentNode = parentNode.getParentNode();
176         }
177
178         List<XMLNode> defNodes = parentNode.getSubtagsByName(SVG.defs, Recursion.ON);
179         if (CollectionUtil.hasValues(defNodes))
180         {
181            for (XMLNode defNode : defNodes)
182            {
183               SvgDefs defs = (SvgDefs) defNode;
184               if (CollectionUtil.hasValues(defs.getSubtags()))
185               {
186                  for (XMLTag xmlTag : (List<XMLTag>) (Object) defs.getSubtags())
187                  {
188                     String id = xmlTag.getAttributeValue(SvgAttr.id);
189                     if (StringUtil.isSet(id)
190                         && id.equals(url.substring(1)))
191                     {
192                        svgDefNode = (AbstractSvgNode) xmlTag;
193                        break;
194                     }
195                  }
196               }
197
198               if (svgDefNode != null)
199               {
200                  break;
201               }
202            }
203         }
204      }
205
206      return svgDefNode;
207   }
208
209}