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