1 /* 2 * Copyright (c) 2003, 2018, 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 26 package jdk.javadoc.internal.doclets.formats.html; 27 28 import java.util.List; 29 30 import javax.lang.model.element.AnnotationMirror; 31 import javax.lang.model.element.Element; 32 import javax.lang.model.element.TypeElement; 33 import javax.lang.model.type.TypeMirror; 34 35 import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; 36 import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; 37 import jdk.javadoc.internal.doclets.toolkit.Content; 38 import jdk.javadoc.internal.doclets.toolkit.Resources; 39 import jdk.javadoc.internal.doclets.toolkit.util.DocPath; 40 import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; 41 import jdk.javadoc.internal.doclets.toolkit.util.links.LinkFactory; 42 import jdk.javadoc.internal.doclets.toolkit.util.links.LinkInfo; 43 44 /** 45 * A factory that returns a link given the information about it. 46 * 47 * <p><b>This is NOT part of any supported API. 48 * If you write code that depends on this, you do so at your own risk. 49 * This code and its internal interfaces are subject to change or 50 * deletion without notice.</b> 51 * 52 * @author Jamie Ho 53 */ 54 public class LinkFactoryImpl extends LinkFactory { 55 56 private final HtmlDocletWriter m_writer; 57 private final DocPaths docPaths; 58 59 public LinkFactoryImpl(HtmlDocletWriter writer) { 60 super(writer.configuration.utils); 61 m_writer = writer; 62 docPaths = writer.configuration.docPaths; 63 } 64 65 /** 66 * {@inheritDoc} 67 */ 68 @Override 69 protected Content newContent() { 70 return new ContentBuilder(); 71 } 72 73 /** 74 * {@inheritDoc} 75 */ 76 @Override 77 protected Content getClassLink(LinkInfo linkInfo) { 78 BaseConfiguration configuration = m_writer.configuration; 79 LinkInfoImpl classLinkInfo = (LinkInfoImpl) linkInfo; 80 boolean noLabel = linkInfo.label == null || linkInfo.label.isEmpty(); 81 TypeElement typeElement = classLinkInfo.typeElement; 82 // Create a tool tip if we are linking to a class or interface. Don't 83 // create one if we are linking to a member. 84 String title = ""; 85 if (classLinkInfo.where == null || classLinkInfo.where.length() == 0) { 86 boolean isTypeLink = classLinkInfo.type != null && 87 utils.isTypeVariable(utils.getComponentType(classLinkInfo.type)); 88 title = getClassToolTip(typeElement, isTypeLink); 89 } 90 Content label = classLinkInfo.getClassLinkLabel(configuration); 91 92 Content link = new ContentBuilder(); 93 if (utils.isIncluded(typeElement)) { 94 if (configuration.isGeneratedDoc(typeElement)) { 95 DocPath filename = getPath(classLinkInfo); 96 if (linkInfo.linkToSelf || 97 !(docPaths.forName(typeElement)).equals(m_writer.filename)) { 98 link.addContent(m_writer.links.createLink( 99 filename.fragment(classLinkInfo.where), 100 label, 101 classLinkInfo.isStrong, 102 title, 103 classLinkInfo.target)); 104 if (noLabel && !classLinkInfo.excludeTypeParameterLinks) { 105 link.addContent(getTypeParameterLinks(linkInfo)); 106 } 107 return link; 108 } 109 } 110 } else { 111 Content crossLink = m_writer.getCrossClassLink( 112 typeElement.getQualifiedName().toString(), classLinkInfo.where, 113 label, classLinkInfo.isStrong, true); 114 if (crossLink != null) { 115 link.addContent(crossLink); 116 if (noLabel && !classLinkInfo.excludeTypeParameterLinks) { 117 link.addContent(getTypeParameterLinks(linkInfo)); 118 } 119 return link; 120 } 121 } 122 // Can't link so just write label. 123 link.addContent(label); 124 if (noLabel && !classLinkInfo.excludeTypeParameterLinks) { 125 link.addContent(getTypeParameterLinks(linkInfo)); 126 } 127 return link; 128 } 129 130 /** 131 * {@inheritDoc} 132 */ 133 @Override 134 protected Content getTypeParameterLink(LinkInfo linkInfo, TypeMirror typeParam) { 135 LinkInfoImpl typeLinkInfo = new LinkInfoImpl(m_writer.configuration, 136 ((LinkInfoImpl) linkInfo).getContext(), typeParam); 137 typeLinkInfo.excludeTypeBounds = linkInfo.excludeTypeBounds; 138 typeLinkInfo.excludeTypeParameterLinks = linkInfo.excludeTypeParameterLinks; 139 typeLinkInfo.linkToSelf = linkInfo.linkToSelf; 140 typeLinkInfo.isJava5DeclarationLocation = false; 141 return getLink(typeLinkInfo); 142 } 143 144 @Override 145 public Content getTypeAnnotationLinks(LinkInfo linkInfo) { 146 ContentBuilder links = new ContentBuilder(); 147 List<? extends AnnotationMirror> annotations; 148 if (utils.isAnnotated(linkInfo.type)) { 149 annotations = linkInfo.type.getAnnotationMirrors(); 150 } else if (utils.isTypeVariable(linkInfo.type)) { 151 // TODO: use the context for now, and special case for Receiver_Types, 152 // which takes the default case. 153 switch (((LinkInfoImpl)linkInfo).context) { 154 case MEMBER_TYPE_PARAMS: 155 case EXECUTABLE_MEMBER_PARAM: 156 case CLASS_SIGNATURE: 157 Element element = utils.typeUtils.asElement(linkInfo.type); 158 annotations = element.getAnnotationMirrors(); 159 break; 160 default: 161 annotations = linkInfo.type.getAnnotationMirrors(); 162 break; 163 } 164 165 } else { 166 return links; 167 } 168 169 if (annotations.isEmpty()) 170 return links; 171 172 List<Content> annos = m_writer.getAnnotations(0, annotations, false, linkInfo.isJava5DeclarationLocation); 173 174 boolean isFirst = true; 175 for (Content anno : annos) { 176 if (!isFirst) { 177 links.addContent(" "); 178 } 179 links.addContent(anno); 180 isFirst = false; 181 } 182 if (!annos.isEmpty()) { 183 links.addContent(" "); 184 } 185 186 return links; 187 } 188 189 /** 190 * Given a class, return the appropriate tool tip. 191 * 192 * @param typeElement the class to get the tool tip for. 193 * @return the tool tip for the appropriate class. 194 */ 195 private String getClassToolTip(TypeElement typeElement, boolean isTypeLink) { 196 Resources resources = m_writer.configuration.getResources(); 197 if (isTypeLink) { 198 return resources.getText("doclet.Href_Type_Param_Title", 199 utils.getSimpleName(typeElement)); 200 } else if (utils.isInterface(typeElement)){ 201 return resources.getText("doclet.Href_Interface_Title", 202 utils.getPackageName(utils.containingPackage(typeElement))); 203 } else if (utils.isAnnotationType(typeElement)) { 204 return resources.getText("doclet.Href_Annotation_Title", 205 utils.getPackageName(utils.containingPackage(typeElement))); 206 } else if (utils.isEnum(typeElement)) { 207 return resources.getText("doclet.Href_Enum_Title", 208 utils.getPackageName(utils.containingPackage(typeElement))); 209 } else { 210 return resources.getText("doclet.Href_Class_Title", 211 utils.getPackageName(utils.containingPackage(typeElement))); 212 } 213 } 214 215 /** 216 * Return path to the given file name in the given package. So if the name 217 * passed is "Object.html" and the name of the package is "java.lang", and 218 * if the relative path is "../.." then returned string will be 219 * "../../java/lang/Object.html" 220 * 221 * @param linkInfo the information about the link. 222 */ 223 private DocPath getPath(LinkInfoImpl linkInfo) { 224 if (linkInfo.context == LinkInfoImpl.Kind.PACKAGE_FRAME) { 225 //Not really necessary to do this but we want to be consistent 226 //with 1.4.2 output. 227 return docPaths.forName(linkInfo.typeElement); 228 } 229 return m_writer.pathToRoot.resolve(docPaths.forClass(linkInfo.typeElement)); 230 } 231 }