/* GNU LESSER GENERAL PUBLIC LICENSE Copyright (C) 2006 The Lobo Project This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Contact info: lobochief@users.sourceforge.net */ package org.lobobrowser.html.domimpl; import java.net.MalformedURLException; import java.net.URL; import java.util.logging.Level; import java.util.logging.Logger; import org.geopublishing.atlasViewer.http.AtlasProtocol; import org.geopublishing.atlasViewer.http.AtlasProtocolException; import org.lobobrowser.html.HtmlRendererContext; import org.lobobrowser.html.UserAgentContext; import org.lobobrowser.html.style.CSSUtilities; import org.lobobrowser.html.style.ColorRenderState; import org.lobobrowser.html.style.RenderState; import org.lobobrowser.html.style.TextDecorationRenderState; import org.lobobrowser.util.gui.ColorFactory; import org.w3c.dom.UserDataHandler; import org.w3c.dom.css.CSSStyleSheet; import org.w3c.dom.html2.HTMLBodyElement; import org.w3c.dom.html2.HTMLDocument; import org.w3c.dom.html2.HTMLLinkElement; import com.steadystate.css.dom.CSSStyleSheetImpl; public class HTMLLinkElementImpl extends HTMLAbstractUIElement implements HTMLLinkElement { private static final Logger logger = Logger .getLogger(HTMLLinkElementImpl.class.getName()); private static final boolean loggableInfo = logger.isLoggable(Level.INFO); private CSSStyleSheet styleSheet; public HTMLLinkElementImpl(String name) { super(name); } private boolean disabled; public boolean getDisabled() { return this.disabled; } public void setDisabled(boolean disabled) { this.disabled = disabled; CSSStyleSheet sheet = this.styleSheet; if (sheet != null) { sheet.setDisabled(disabled); } } public String getHref() { String href = this.getAttribute("href"); return href == null ? "" : href; } public void setHref(String href) { this.setAttribute("href", href); } public String getHreflang() { return this.getAttribute("hreflang"); } public void setHreflang(String hreflang) { this.setAttribute("hreflang", hreflang); } public String getMedia() { return this.getAttribute("media"); } public void setMedia(String media) { this.setAttribute("media", media); } public String getRel() { return this.getAttribute("rel"); } public void setRel(String rel) { this.setAttribute("rel", rel); } public String getRev() { return this.getAttribute("rev"); } public void setRev(String rev) { this.setAttribute("rev", rev); } public String getTarget() { String target = this.getAttribute("target"); if (target != null) { return target; } HTMLDocumentImpl doc = (HTMLDocumentImpl) this.document; return doc == null ? null : doc.getDefaultTarget(); } public void setTarget(String target) { this.setAttribute("target", target); } public String getType() { return this.getAttribute("type"); } public void setType(String type) { this.setAttribute("type", type); } @Override public Object setUserData(String key, Object data, UserDataHandler handler) { if (org.lobobrowser.html.parser.HtmlParser.MODIFYING_KEY.equals(key) && data != Boolean.TRUE) { this.processLink(); } else if (com.steadystate.css.dom.CSSStyleSheetImpl.KEY_DISABLED_CHANGED .equals(key)) { this.informDocumentInvalid(); } return super.setUserData(key, data, handler); } /** * If the LINK refers to a stylesheet document, this method loads and parses * it. */ protected void processLink() { this.styleSheet = null; String rel = this.getAttribute("rel"); if (rel != null) { String cleanRel = rel.trim().toLowerCase(); boolean isStyleSheet = cleanRel.equals("stylesheet"); boolean isAltStyleSheet = cleanRel.equals("alternate stylesheet"); if (isStyleSheet || isAltStyleSheet) { UserAgentContext uacontext = this.getUserAgentContext(); if (uacontext.isExternalCSSEnabled()) { String media = this.getMedia(); if (CSSUtilities.matchesMedia(media, uacontext)) { HTMLDocumentImpl doc = (HTMLDocumentImpl) this .getOwnerDocument(); try { boolean liflag = loggableInfo; long time1 = liflag ? System.currentTimeMillis() : 0; try { CSSStyleSheet sheet = CSSUtilities.parse(this, this.getHref(), doc, doc.getBaseURI(), false); if (sheet != null) { this.styleSheet = sheet; if (sheet instanceof CSSStyleSheetImpl) { CSSStyleSheetImpl sheetImpl = (CSSStyleSheetImpl) sheet; if (isAltStyleSheet) { sheetImpl.setDisabledOnly(true); } else { sheetImpl .setDisabledOnly(this.disabled); } } else { if (isAltStyleSheet) { sheet.setDisabled(true); } else { sheet.setDisabled(this.disabled); } } doc.addStyleSheet(sheet); } } finally { if (liflag) { long time2 = System.currentTimeMillis(); logger.info("processLink(): Loaded and parsed CSS (or attempted to) at URI=[" + this.getHref() + "] in " + (time2 - time1) + " ms."); } } } catch (MalformedURLException mfe) { this.warn("Will not parse CSS. URI=[" + this.getHref() + "] with BaseURI=[" + doc.getBaseURI() + "] does not appear to be a valid URI."); } catch (Throwable err) { this.warn( "Unable to parse CSS. URI=[" + this.getHref() + "].", err); } } } } } } public String getAbsoluteHref() { HtmlRendererContext rcontext = this.getHtmlRendererContext(); if (rcontext != null) { String href = this.getHref(); if (href != null && href.length() > 0) { String target = this.getTarget(); try { URL url = this.getFullURL(href); return url == null ? null : url.toExternalForm(); } catch (MalformedURLException mfu) { this.warn("Malformed URI: [" + href + "].", mfu); } } } return null; } public void navigate() { if (this.disabled) { return; } HtmlRendererContext rcontext = this.getHtmlRendererContext(); if (rcontext != null) { String href = this.getHref(); // MS.sn: // Avoid MalformedURLException by "controlled" // AtlasProtocolException to handle the Atlas // protocol at the catching point warn(href); if (AtlasProtocol.check(href)) throw new AtlasProtocolException(href); // MS.en: if (href != null && href.length() > 0) { String target = this.getTarget(); try { URL url = this.getFullURL(href); if (url == null) { this.warn("Unable to resolve URI: [" + href + "]."); } else { rcontext.linkClicked(this, url, target); } } catch (MalformedURLException mfu) { this.warn("Malformed URI: [" + href + "].", mfu); } } } } private java.awt.Color getLinkColor() { HTMLDocument doc = (HTMLDocument) this.document; if (doc != null) { HTMLBodyElement body = (HTMLBodyElement) doc.getBody(); if (body != null) { String vlink = body.getVLink(); String link = body.getLink(); if (vlink != null || link != null) { HtmlRendererContext rcontext = this .getHtmlRendererContext(); if (rcontext != null) { boolean visited = rcontext.isVisitedLink(this); String colorText = visited ? vlink : link; if (colorText != null) { return ColorFactory.getInstance().getColor( colorText); } } } } } return java.awt.Color.BLUE; } @Override protected RenderState createRenderState(RenderState prevRenderState) { if (this.hasAttribute("href")) { prevRenderState = new TextDecorationRenderState(prevRenderState, RenderState.MASK_TEXTDECORATION_UNDERLINE); prevRenderState = new ColorRenderState(prevRenderState, this.getLinkColor()); } return super.createRenderState(prevRenderState); } @Override public String toString() { // Javascript code often depends on this being exactly href. See // js9.html. // To change, perhaps add method to AbstractScriptableDelegate. return this.getHref(); } }