1/* 2 * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package jdk.javadoc.internal.doclets.formats.html; 27 28import java.util.List; 29 30import javax.lang.model.element.AnnotationMirror; 31import javax.lang.model.element.Element; 32import javax.lang.model.element.TypeElement; 33import javax.lang.model.type.TypeMirror; 34 35import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; 36import jdk.javadoc.internal.doclets.toolkit.Configuration; 37import jdk.javadoc.internal.doclets.toolkit.Content; 38import jdk.javadoc.internal.doclets.toolkit.util.DocPath; 39import jdk.javadoc.internal.doclets.toolkit.util.Utils; 40import jdk.javadoc.internal.doclets.toolkit.util.links.LinkFactory; 41import jdk.javadoc.internal.doclets.toolkit.util.links.LinkInfo; 42 43import static jdk.javadoc.internal.doclets.formats.html.LinkInfoImpl.Kind.MEMBER_TYPE_PARAMS; 44 45/** 46 * A factory that returns a link given the information about it. 47 * 48 * <p><b>This is NOT part of any supported API. 49 * If you write code that depends on this, you do so at your own risk. 50 * This code and its internal interfaces are subject to change or 51 * deletion without notice.</b> 52 * 53 * @author Jamie Ho 54 */ 55public class LinkFactoryImpl extends LinkFactory { 56 57 private final HtmlDocletWriter m_writer; 58 59 public LinkFactoryImpl(HtmlDocletWriter writer) { 60 m_writer = writer; 61 } 62 63 /** 64 * {@inheritDoc} 65 */ 66 @Override 67 protected Content newContent() { 68 return new ContentBuilder(); 69 } 70 71 /** 72 * {@inheritDoc} 73 */ 74 @Override 75 protected Content getClassLink(LinkInfo linkInfo) { 76 Configuration configuration = m_writer.configuration; 77 Utils utils = configuration.utils; 78 LinkInfoImpl classLinkInfo = (LinkInfoImpl) linkInfo; 79 boolean noLabel = linkInfo.label == null || linkInfo.label.isEmpty(); 80 TypeElement typeElement = classLinkInfo.typeElement; 81 // Create a tool tip if we are linking to a class or interface. Don't 82 // create one if we are linking to a member. 83 String title = ""; 84 if (classLinkInfo.where == null || classLinkInfo.where.length() == 0) { 85 boolean isTypeLink = classLinkInfo.type != null && 86 utils.isTypeVariable(utils.getComponentType(classLinkInfo.type)); 87 title = getClassToolTip(typeElement, isTypeLink); 88 } 89 Content label = classLinkInfo.getClassLinkLabel(m_writer.configuration); 90 91 Content link = new ContentBuilder(); 92 if (utils.isIncluded(typeElement)) { 93 if (configuration.isGeneratedDoc(typeElement)) { 94 DocPath filename = getPath(classLinkInfo); 95 if (linkInfo.linkToSelf || 96 !(DocPath.forName(utils, typeElement)).equals(m_writer.filename)) { 97 link.addContent(m_writer.getHyperLink( 98 filename.fragment(classLinkInfo.where), 99 label, 100 classLinkInfo.isStrong, classLinkInfo.styleName, 101 title, classLinkInfo.target)); 102 if (noLabel && !classLinkInfo.excludeTypeParameterLinks) { 103 link.addContent(getTypeParameterLinks(linkInfo)); 104 } 105 return link; 106 } 107 } 108 } else { 109 Content crossLink = m_writer.getCrossClassLink( 110 typeElement.getQualifiedName().toString(), classLinkInfo.where, 111 label, classLinkInfo.isStrong, classLinkInfo.styleName, 112 true); 113 if (crossLink != null) { 114 link.addContent(crossLink); 115 if (noLabel && !classLinkInfo.excludeTypeParameterLinks) { 116 link.addContent(getTypeParameterLinks(linkInfo)); 117 } 118 return link; 119 } 120 } 121 // Can't link so just write label. 122 link.addContent(label); 123 if (noLabel && !classLinkInfo.excludeTypeParameterLinks) { 124 link.addContent(getTypeParameterLinks(linkInfo)); 125 } 126 return link; 127 } 128 129 /** 130 * {@inheritDoc} 131 */ 132 @Override 133 protected Content getTypeParameterLink(LinkInfo linkInfo, TypeMirror typeParam) { 134 LinkInfoImpl typeLinkInfo = new LinkInfoImpl(m_writer.configuration, 135 ((LinkInfoImpl) linkInfo).getContext(), typeParam); 136 typeLinkInfo.excludeTypeBounds = linkInfo.excludeTypeBounds; 137 typeLinkInfo.excludeTypeParameterLinks = linkInfo.excludeTypeParameterLinks; 138 typeLinkInfo.linkToSelf = linkInfo.linkToSelf; 139 typeLinkInfo.isJava5DeclarationLocation = false; 140 return getLink(typeLinkInfo); 141 } 142 143 @Override 144 protected Content getTypeAnnotationLink(LinkInfo linkInfo, AnnotationMirror annotation) { 145 throw new RuntimeException("Not implemented yet!"); 146 } 147 148 @Override 149 public Content getTypeAnnotationLinks(LinkInfo linkInfo) { 150 Utils utils = ((LinkInfoImpl)linkInfo).utils; 151 ContentBuilder links = new ContentBuilder(); 152 List<? extends AnnotationMirror> annotations; 153 if (utils.isAnnotated(linkInfo.type)) { 154 annotations = linkInfo.type.getAnnotationMirrors(); 155 } else if (utils.isTypeVariable(linkInfo.type)) { 156 // TODO: use the context for now, and special case for Receiver_Types, 157 // which takes the default case. 158 switch (((LinkInfoImpl)linkInfo).context) { 159 case MEMBER_TYPE_PARAMS: 160 case EXECUTABLE_MEMBER_PARAM: 161 case CLASS_SIGNATURE: 162 Element element = utils.typeUtils.asElement(linkInfo.type); 163 annotations = element.getAnnotationMirrors(); 164 break; 165 default: 166 annotations = linkInfo.type.getAnnotationMirrors(); 167 break; 168 } 169 170 } else { 171 return links; 172 } 173 174 if (annotations.isEmpty()) 175 return links; 176 177 List<Content> annos = m_writer.getAnnotations(0, annotations, false, linkInfo.isJava5DeclarationLocation); 178 179 boolean isFirst = true; 180 for (Content anno : annos) { 181 if (!isFirst) { 182 links.addContent(" "); 183 } 184 links.addContent(anno); 185 isFirst = false; 186 } 187 if (!annos.isEmpty()) { 188 links.addContent(" "); 189 } 190 191 return links; 192 } 193 194 /** 195 * Given a class, return the appropriate tool tip. 196 * 197 * @param typeElement the class to get the tool tip for. 198 * @return the tool tip for the appropriate class. 199 */ 200 private String getClassToolTip(TypeElement typeElement, boolean isTypeLink) { 201 Configuration configuration = m_writer.configuration; 202 Utils utils = configuration.utils; 203 if (isTypeLink) { 204 return configuration.getText("doclet.Href_Type_Param_Title", 205 utils.getSimpleName(typeElement)); 206 } else if (utils.isInterface(typeElement)){ 207 return configuration.getText("doclet.Href_Interface_Title", 208 utils.getPackageName(utils.containingPackage(typeElement))); 209 } else if (utils.isAnnotationType(typeElement)) { 210 return configuration.getText("doclet.Href_Annotation_Title", 211 utils.getPackageName(utils.containingPackage(typeElement))); 212 } else if (utils.isEnum(typeElement)) { 213 return configuration.getText("doclet.Href_Enum_Title", 214 utils.getPackageName(utils.containingPackage(typeElement))); 215 } else { 216 return configuration.getText("doclet.Href_Class_Title", 217 utils.getPackageName(utils.containingPackage(typeElement))); 218 } 219 } 220 221 /** 222 * Return path to the given file name in the given package. So if the name 223 * passed is "Object.html" and the name of the package is "java.lang", and 224 * if the relative path is "../.." then returned string will be 225 * "../../java/lang/Object.html" 226 * 227 * @param linkInfo the information about the link. 228 */ 229 private DocPath getPath(LinkInfoImpl linkInfo) { 230 if (linkInfo.context == LinkInfoImpl.Kind.PACKAGE_FRAME) { 231 //Not really necessary to do this but we want to be consistent 232 //with 1.4.2 output. 233 return DocPath.forName(linkInfo.utils, linkInfo.typeElement); 234 } 235 return m_writer.pathToRoot.resolve(DocPath.forClass(linkInfo.utils, linkInfo.typeElement)); 236 } 237} 238