001    package edu.nrao.sss.html;
002    
003    import java.io.IOException;
004    import java.io.Writer;
005    
006    import javax.swing.text.html.HTML;
007    
008    /**
009     * An HTML anchor ({@link javax.swing.text.html.HTML.Tag#A}).
010     * <p>
011     * <b>Version Info:</b>
012     * <table style="margin-left:2em">
013     *   <tr><td>$Revision: 1360 $</td></tr>
014     *   <tr><td>$Date: 2008-06-19 14:08:48 -0600 (Thu, 19 Jun 2008) $</td></tr>
015     *   <tr><td>$Author: dharland $</td></tr>
016     * </table></p>
017     * 
018     * @author David M. Harland
019     * @since 2007-03-20
020     */
021    public class HtmlAnchor
022      extends HtmlElement
023    {
024      private String displayText;
025      
026      /** Creates a new, unnamed, empty anchor. */
027      public HtmlAnchor()
028      {
029        this(null, null, null);
030      }
031      
032      /**
033       * Creates a new HTML anchor with the given properties.
034       * The text form of this anchor is:<pre>
035       * &lt;a name="<i>name</i>" href="<i>href</i>"&gt;<i>display</i>&lt/a&gt;
036       * </pre>
037       * 
038       * @param name the name of this anchor.
039       *             If this parameter is <i>null</i>, this anchor will have
040       *             no name.
041       *             
042       * @param href the HTML link associated with this anchor.
043       *             If this parameter is <i>null</i>, this anchor will have
044       *             no link.
045       *             
046       * @param display the text displayed on an HTML page for this anchor.
047       *                If this parameter is <i>null</i>, it will be converted
048       *                to the empty string (<tt>""</tt>).
049       */
050      public HtmlAnchor(String name, String href, String display)
051      {
052        super(HTML.Tag.A);
053        
054        if (name != null)
055          attributes.put(HTML.Attribute.NAME,
056                         new HtmlAttribute(HTML.Attribute.NAME, name));
057        
058        if (href != null)
059          attributes.put(HTML.Attribute.HREF,
060                         new HtmlAttribute(HTML.Attribute.HREF, href));
061        
062        displayText = (display == null) ? "" : display;
063      }
064      
065      /**
066       * Creates and returns a new HTML anchor by parsing {@code anchorTag}.
067       * 
068       * @param anchorTag the HTML form of this anchor.
069       * The expected form of the text is:
070       * <pre>  &lt;a name="name" href='absolute or relative URL'&gt;display text&lt;/a&gt;</pre>
071       * The anchor name can be "a" or "A"; you may even mix the capitalization in
072       * a single tag (&lt;A ...&gt;...&lt;/a&gt;).  Values may be quoted with
073       * either single (') or double (") quotes.  Leading and trailing whitespace
074       * is permitted and will be trimmed during parsing.</p>
075       *  
076       * @return a new HTML anchor by parsing {@code anchorTag}.
077       * 
078       * @throws IllegalArgumentException if anything goes wrong during parsing.
079       */
080      public static HtmlAnchor parse(String anchorTag)
081      {
082        try
083        {
084          HtmlAnchor anchor = new HtmlAnchor();
085          anchor.parseAnchor(anchorTag);
086          return anchor;
087        }
088        catch (Exception ex)
089        {
090          throw new IllegalArgumentException("Could not parse anchorTag [" +
091                                             anchorTag + "]: " +
092                                             ex.getMessage());
093        }
094      }
095      
096      @Override
097      public boolean isSimple()
098      {
099        return false;
100      }
101    
102      /**
103       * Sets the text to display for this anchor.
104       * 
105       * @param text the text to display for this anchor.  If this
106       *             parameter is <i>null</i>, it will be replaced by the
107       *             empty string (<tt>""</tt>).
108       */
109      public void setDisplayText(String text)
110      {
111        displayText = (text == null) ? "" : text;
112      }
113    
114      /**
115       * Returns the text to display for this anchor.
116       * 
117       * @return the text to display for this anchor.  This value is guaranteed
118       *         to be non-null, but it could be the empty string (<tt>""</tt>).
119       */
120      public String getDisplayText()
121      {
122        return displayText;
123      }
124    
125      /**
126       * Sets the value of this anchor tag based on the given text.
127       * <p>
128       * The expected form of the text is:
129       * <pre>  &lt;a name1="value1" name2='value two'&gt;display text&lt;/a&gt;</pre>
130       * The anchor name can be "a" or "A"; you may even mix the capitalization in
131       * a single tag (&lt;A ...&gt;...&lt;/a&gt;).  Values may be quoted with
132       * either single (') or double (") quotes.  Leading and trailing whitespace
133       * is permitted and will be trimmed during parsing.</p>
134       * <p>
135       * If anything goes wrong during parsing, an {@code IllegalArgumentException}
136       * is thrown.  All successfully parsed information up to the point of the
137       * exception will be maintained by this instance.</p>
138       * 
139       * @param anchorTag text representation of an HTML anchor.
140       */
141      private void parseAnchor(String anchorTag)
142      {
143        if (anchorTag == null)
144          throw new IllegalArgumentException("must not be null.");
145    
146        String text = anchorTag.trim();
147        
148        if (anchorTag.length() == 0)
149          throw new IllegalArgumentException("must not be empty.");
150        
151        if (!(text.startsWith("<a") || text.startsWith("<A")) ||
152            !(text.endsWith("</a>") || text.endsWith("</A>")))
153          throw new IllegalArgumentException(
154            "must start with '<a' and end with '</a>'.");
155    
156        int endOpenTagPos = text.indexOf('>');
157        
158        displayText = text.substring(endOpenTagPos+1,text.indexOf("</"));
159        
160        parseAttributes(text.substring(2, endOpenTagPos));
161      }
162      
163      //============================================================================
164      // WRITING
165      //============================================================================
166      
167      void writeContentsAsHtml(Writer device, int padding, int depth) throws IOException
168      {
169        device.write(displayText);
170      }
171      
172      //============================================================================
173      // CONVENIENCE METHODS
174      //============================================================================
175      
176      /**
177       * Returns <i>true</i> if this anchor has a non-<i>null</i> value for the
178       * <tt>HTML.Attribute.NAME</tt> type.
179       * 
180       * @return
181       *   <i>true</i> if this anchor has a non-<i>null</i> name.
182       */
183      public boolean hasName()
184      {
185        return getAttributeValue(HTML.Attribute.NAME) != null;
186      }
187      
188      /**
189       * Returns the name of this anchor, if any.  If this anchor has no name,
190       * <i>null</i> is returned.  This is a convenience method equivalent to
191       * the call <tt>getAttributeValue(HTML.Attribute.NAME)</tt>.
192       * 
193       * @return
194       *   the name of this anchor, or <i>null</i> if this anchor has no name.
195       */
196      public String getName()
197      {
198        return getAttributeValue(HTML.Attribute.NAME);
199      }
200      
201      /**
202       * Return <i>true</i> if this anchor has a non-<i>null</i> value for the
203       * <tt>HTML.Attribute.HREF</tt> type.
204       * 
205       * @return
206       *   <i>true</i> if this anchor has a non-<i>null</i> name.
207       */
208      public boolean hasUrlText()
209      {
210        return getAttributeValue(HTML.Attribute.HREF) != null;
211      }
212      
213      /**
214       * Returns the <tt>HREF</tt> value for this anchor, if any.
215       * If this anchor has no such value, <i>null</i> is returned.
216       * This is a convenience method equivalent to the call
217       * <tt>getAttributeValue(HTML.Attribute.NAME)</tt>.
218       * Beware that the text returned may be only a <i>relative</i>
219       * URL, not the entire URL.
220       * 
221       * @return
222       *   the href value of this anchor,
223       *   or <i>null</i> if this anchor has no such value.
224       */
225      public String getUrlText()
226      {
227        return getAttributeValue(HTML.Attribute.HREF);
228      }
229      
230      //============================================================================
231      // 
232      //============================================================================
233      
234      /*
235      public static void main(String[] args)
236      {
237        HtmlAnchor anchor = HtmlAnchor.parse(args[0]);
238        
239        for (String key : anchor.attributes.keySet())
240        {
241          System.out.println("["+key + "=" + anchor.attributes.get(key) + "]");
242        }
243        System.out.println("Display text [" + anchor.displayText + "]");
244        System.out.println(anchor.appendTo(null).toString());
245        System.out.println(HTML.getAttributeKey("class").toString());
246        System.out.println(HTML.NULL_ATTRIBUTE_VALUE + ", " + HTML.NULL_ATTRIBUTE_VALUE.length());
247      }
248      */
249    }