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 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.Configuration; 37 import jdk.javadoc.internal.doclets.toolkit.Content; 38 import jdk.javadoc.internal.doclets.toolkit.util.DocPath; 39 import jdk.javadoc.internal.doclets.toolkit.util.Utils; 40 import jdk.javadoc.internal.doclets.toolkit.util.links.LinkFactory; 41 import jdk.javadoc.internal.doclets.toolkit.util.links.LinkInfo; 42 43 import 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 * @since 1.5 55 */ 56 public class LinkFactoryImpl extends LinkFactory { 57 58 private final HtmlDocletWriter m_writer; 59 60 public LinkFactoryImpl(HtmlDocletWriter writer) { 61 m_writer = writer; 62 } 63 64 /** 65 * {@inheritDoc} 66 */ 67 @Override 68 protected Content newContent() { 69 return new ContentBuilder(); 70 } 71 72 /** 73 * {@inheritDoc} 74 */ 75 @Override 76 protected Content getClassLink(LinkInfo linkInfo) { 77 Configuration configuration = m_writer.configuration; 78 Utils utils = configuration.utils; 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(m_writer.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 !(DocPath.forName(utils, typeElement)).equals(m_writer.filename)) { 98 link.addContent(m_writer.getHyperLink( 99 filename.fragment(classLinkInfo.where), 100 label, 101 classLinkInfo.isStrong, classLinkInfo.styleName, 102 title, classLinkInfo.target)); 103 if (noLabel && !classLinkInfo.excludeTypeParameterLinks) { 104 link.addContent(getTypeParameterLinks(linkInfo)); 105 } 106 return link; 107 } 108 } 109 } else { 110 Content crossLink = m_writer.getCrossClassLink( 111 typeElement.getQualifiedName().toString(), classLinkInfo.where, 112 label, classLinkInfo.isStrong, classLinkInfo.styleName, 113 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 protected Content getTypeAnnotationLink(LinkInfo linkInfo, AnnotationMirror annotation) { 146 throw new RuntimeException("Not implemented yet!"); 147 } 148 149 @Override 150 public Content getTypeAnnotationLinks(LinkInfo linkInfo) { 151 Utils utils = ((LinkInfoImpl)linkInfo).utils; 152 ContentBuilder links = new ContentBuilder(); 153 List<? extends AnnotationMirror> annotations; 154 if (utils.isAnnotated(linkInfo.type)) { 155 annotations = linkInfo.type.getAnnotationMirrors(); 156 } else if (utils.isTypeVariable(linkInfo.type)) { 157 // TODO: use the context for now, and special case for Receiver_Types, 158 // which takes the default case. 159 switch (((LinkInfoImpl)linkInfo).context) { 160 case MEMBER_TYPE_PARAMS: 161 case EXECUTABLE_MEMBER_PARAM: 162 case CLASS_SIGNATURE: 163 Element element = utils.typeUtils.asElement(linkInfo.type); 164 annotations = element.getAnnotationMirrors(); 165 break; 166 default: 167 annotations = linkInfo.type.getAnnotationMirrors(); 168 break; 169 } 170 171 } else { 172 return links; 173 } 174 175 if (annotations.isEmpty()) 176 return links; 177 178 List<Content> annos = m_writer.getAnnotations(0, annotations, false, linkInfo.isJava5DeclarationLocation); 179 180 boolean isFirst = true; 181 for (Content anno : annos) { 182 if (!isFirst) { 183 links.addContent(" "); 184 } 185 links.addContent(anno); 186 isFirst = false; 187 } 188 if (!annos.isEmpty()) { 189 links.addContent(" "); 190 } 191 192 return links; 193 } 194 195 /** 196 * Given a class, return the appropriate tool tip. 197 * 198 * @param typeElement the class to get the tool tip for. 199 * @return the tool tip for the appropriate class. 200 */ 201 private String getClassToolTip(TypeElement typeElement, boolean isTypeLink) { 202 Configuration configuration = m_writer.configuration; 203 Utils utils = configuration.utils; 204 if (isTypeLink) { 205 return configuration.getText("doclet.Href_Type_Param_Title", 206 utils.getSimpleName(typeElement)); 207 } else if (utils.isInterface(typeElement)){ 208 return configuration.getText("doclet.Href_Interface_Title", 209 utils.getPackageName(utils.containingPackage(typeElement))); 210 } else if (utils.isAnnotationType(typeElement)) { 211 return configuration.getText("doclet.Href_Annotation_Title", 212 utils.getPackageName(utils.containingPackage(typeElement))); 213 } else if (utils.isEnum(typeElement)) { 214 return configuration.getText("doclet.Href_Enum_Title", 215 utils.getPackageName(utils.containingPackage(typeElement))); 216 } else { 217 return configuration.getText("doclet.Href_Class_Title", 218 utils.getPackageName(utils.containingPackage(typeElement))); 219 } 220 } 221 222 /** 223 * Return path to the given file name in the given package. So if the name 224 * passed is "Object.html" and the name of the package is "java.lang", and 225 * if the relative path is "../.." then returned string will be 226 * "../../java/lang/Object.html" 227 * 228 * @param linkInfo the information about the link. 229 */ 230 private DocPath getPath(LinkInfoImpl linkInfo) { 231 if (linkInfo.context == LinkInfoImpl.Kind.PACKAGE_FRAME) { 232 //Not really necessary to do this but we want to be consistent 233 //with 1.4.2 output. 234 return DocPath.forName(linkInfo.utils, linkInfo.typeElement); 235 } 236 return m_writer.pathToRoot.resolve(DocPath.forClass(linkInfo.utils, linkInfo.typeElement)); 237 } 238 }