001 /* 002 * $Id: LinkModel.java,v 1.9 2006/05/14 15:55:55 dmouse Exp $ 003 * 004 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021 022 package org.jdesktop.swingx; 023 024 import java.beans.PropertyChangeListener; 025 import java.beans.PropertyChangeSupport; 026 import java.net.MalformedURLException; 027 import java.net.URL; 028 import java.util.logging.Logger; 029 030 /** 031 * An bean which represents an URL link. 032 * 033 * Text, URL and visited are bound properties. Compares by Text. 034 * 035 * @author Mark Davidson 036 * @author Jeanette Winzenburg 037 */ 038 public class LinkModel implements Comparable { 039 040 private static final Logger LOG = Logger.getLogger(LinkModel.class 041 .getName()); 042 043 private String text; // display text 044 045 private URL url; // url of the link 046 047 private String target; // url target frame 048 049 private boolean visited = false; 050 051 private PropertyChangeSupport propertyChangeSupport; 052 053 public static final String VISITED_PROPERTY = "visited"; 054 055 // hack - this class assumes that the url always != null 056 // need to cleanup 057 private static String defaultURLString = "https://jdnc.dev.java.net"; 058 059 private static URL defaultURL; 060 061 /** 062 * 063 * @param text 064 * @param target 065 * @param url 066 */ 067 public LinkModel(String text, String target, URL url) { 068 setText(text); 069 setTarget(target); 070 setURL(url != null ? url : getDefaultURL()); 071 } 072 073 public LinkModel() { 074 this(" ", null, null); 075 } 076 077 public LinkModel(String text) { 078 this(text, null, null); 079 } 080 081 /** 082 * @param text text to that a renderer would display 083 * @param target the target that a URL should load into. 084 * @param template a string that represents a URL with 085 * &{N} place holders for string substitution 086 * @param args an array of strings which will be used for substitition 087 */ 088 public LinkModel(String text, String target, String template, String[] args) { 089 setText(text); 090 setTarget(target); 091 setURL(createURL(template, args)); 092 } 093 094 /** 095 * Set the display text. 096 */ 097 public void setText(String text) { 098 String old = getText(); 099 this.text = text; 100 firePropertyChange("text", old, getText()); 101 } 102 103 public String getText() { 104 if (text != null) { 105 return text; 106 } else if (url != null) { 107 return getURL().toString(); 108 } 109 return null; 110 } 111 112 public void setURLString(String howToURLString) { 113 URL url = null; 114 try { 115 url = new URL(howToURLString); 116 } catch (MalformedURLException e) { 117 url = getDefaultURL(); 118 LOG.warning("the given urlString is malformed: " + howToURLString + 119 "\n falling back to default url: " + url); 120 } 121 setURL(url); 122 } 123 124 private URL getDefaultURL() { 125 if (defaultURL == null) { 126 try { 127 defaultURL = new URL(defaultURLString); 128 } catch (MalformedURLException e) { 129 LOG.fine("should not happen - defaultURL is wellFormed: " 130 + defaultURLString); 131 } 132 } 133 return defaultURL; 134 } 135 136 /** 137 * Set the url and resets the visited flag. 138 * 139 * Think: keep list of visited urls here? 140 */ 141 public void setURL(URL url) { 142 if (url == null) { 143 throw new IllegalArgumentException("URL for link cannot be null"); 144 } 145 if (url.equals(getURL())) 146 return; 147 URL old = getURL(); 148 this.url = url; 149 firePropertyChange("URL", old, url); 150 setVisited(false); 151 } 152 153 public URL getURL() { 154 return url; 155 } 156 157 /** 158 * Create a URL from a template string that has place holders and an array 159 * of strings which will be substituted into the place holders. The place 160 * holders are represented as 161 * 162 * @{N} where N = { 1..n } 163 * <p> 164 * For example, if the template contains a string like: 165 * http://bugz.sfbay/cgi-bin/showbug?cat=@{1}&sub_cat=@{2} and a two 166 * arg array contains: java, classes_swing The resulting URL will be: 167 * http://bugz.sfbay/cgi-bin/showbug?cat=java&sub_cat=classes_swing 168 * <p> 169 * @param template a url string that contains the placeholders 170 * @param args an array of strings that will be substituted 171 */ 172 private URL createURL(String template, String[] args) { 173 URL url = null; 174 try { 175 String urlStr = template; 176 for (int i = 0; i < args.length; i++) { 177 urlStr = urlStr.replaceAll("@\\{" + (i + 1) + "\\}", args[i]); 178 } 179 url = new URL(urlStr); 180 } catch (MalformedURLException ex) { 181 // 182 } 183 return url; 184 } 185 186 /** 187 * Set the target that the URL should load into. This can be a uri 188 * representing another control or the name of a window or special targets. 189 * See: http://www.w3c.org/TR/html401/present/frames.html#adef-target 190 */ 191 public void setTarget(String target) { 192 this.target = target; 193 } 194 195 /** 196 * Return the target for the URL. 197 * 198 * @return value of the target. If null then "_blank" will be returned. 199 */ 200 public String getTarget() { 201 if (target != null) { 202 return target; 203 } else { 204 return "_blank"; 205 } 206 } 207 208 /** 209 * Sets a flag to indicate if the link has been visited. The state of this 210 * flag can be used to render the color of the link. 211 */ 212 public void setVisited(boolean visited) { 213 boolean old = getVisited(); 214 this.visited = visited; 215 firePropertyChange(VISITED_PROPERTY, old, getVisited()); 216 } 217 218 public boolean getVisited() { 219 return visited; 220 } 221 222 // ---------------------- property change notification 223 224 public void addPropertyChangeListener(PropertyChangeListener l) { 225 getPropertyChangeSupport().addPropertyChangeListener(l); 226 227 } 228 229 public void removePropertyChangeListener(PropertyChangeListener l) { 230 if (propertyChangeSupport == null) 231 return; 232 propertyChangeSupport.removePropertyChangeListener(l); 233 } 234 235 protected void firePropertyChange(String property, Object oldValue, 236 Object newValue) { 237 if (propertyChangeSupport == null) 238 return; 239 propertyChangeSupport.firePropertyChange(property, oldValue, newValue); 240 } 241 242 protected void firePropertyChange(String property, boolean oldValue, 243 boolean newValue) { 244 if (propertyChangeSupport == null) 245 return; 246 propertyChangeSupport.firePropertyChange(property, oldValue, newValue); 247 248 } 249 250 private PropertyChangeSupport getPropertyChangeSupport() { 251 if (propertyChangeSupport == null) { 252 propertyChangeSupport = new PropertyChangeSupport(this); 253 } 254 return propertyChangeSupport; 255 } 256 257 // Comparable interface for sorting. 258 public int compareTo(Object obj) { 259 if (obj == null) { 260 return 1; 261 } 262 if (obj == this) { 263 return 0; 264 } 265 return text.compareTo(((LinkModel) obj).text); 266 } 267 268 public boolean equals(Object obj) { 269 if (this == obj) { 270 return true; 271 } 272 if (obj != null && obj instanceof LinkModel) { 273 LinkModel other = (LinkModel) obj; 274 if (!getText().equals(other.getText())) { 275 return false; 276 } 277 278 if (!getTarget().equals(other.getTarget())) { 279 return false; 280 } 281 282 if (!getURL().equals(other.getURL())) { 283 return false; 284 } 285 return true; 286 } 287 return false; 288 } 289 290 @Override 291 public int hashCode() { 292 int result = 7; 293 294 result = 37 * result + ((getText() == null) ? 0 : getText().hashCode()); 295 result = 37 * result 296 + ((getTarget() == null) ? 1 : getTarget().hashCode()); 297 result = 37 * result + ((getURL() == null) ? 2 : getURL().hashCode()); 298 299 return result; 300 } 301 302 @Override 303 public String toString() { 304 305 StringBuffer buffer = new StringBuffer("["); 306 // RG: Fix for J2SE 5.0; Can't cascade append() calls because 307 // return type in StringBuffer and AbstractStringBuilder are different 308 buffer.append("url="); 309 buffer.append(url); 310 buffer.append(", target="); 311 buffer.append(target); 312 buffer.append(", text="); 313 buffer.append(text); 314 buffer.append("]"); 315 316 return buffer.toString(); 317 } 318 319 }