001/* 002 * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package org.jdrupes.mdoclet.internal.doclets.formats.html; 027 028import javax.lang.model.element.Element; 029import javax.lang.model.element.ExecutableElement; 030import javax.lang.model.element.TypeElement; 031import javax.lang.model.type.DeclaredType; 032import javax.lang.model.type.TypeMirror; 033 034import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.ContentBuilder; 035import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.HtmlStyle; 036import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.Text; 037import org.jdrupes.mdoclet.internal.doclets.toolkit.BaseConfiguration; 038import org.jdrupes.mdoclet.internal.doclets.toolkit.Content; 039import org.jdrupes.mdoclet.internal.doclets.toolkit.util.Utils; 040 041/** 042 * HTML-specific information about a link. 043 */ 044public class HtmlLinkInfo { 045 046 /** 047 * Enumeration of different kinds of links. 048 */ 049 public enum Kind { 050 /** 051 * Link with just the element name as label. 052 */ 053 PLAIN, 054 /** 055 * Link with additional preview flag if appropriate. 056 */ 057 SHOW_PREVIEW, 058 /** 059 * Link with optional type parameters appended as plain text. 060 */ 061 SHOW_TYPE_PARAMS, 062 063 /** 064 * Link with optional type parameters included in the link label. 065 */ 066 SHOW_TYPE_PARAMS_IN_LABEL, 067 068 /** 069 * Link with optional type parameters and bounds appended as plain text. 070 */ 071 SHOW_TYPE_PARAMS_AND_BOUNDS, 072 /** 073 * Link with optional type parameters but no bounds rendered as separate links. 074 */ 075 LINK_TYPE_PARAMS, 076 /** 077 * Link with optional type parameters and bounds rendered as separate links. 078 */ 079 LINK_TYPE_PARAMS_AND_BOUNDS; 080 } 081 082 private final HtmlConfiguration configuration; 083 084 // The context of the link. 085 private Kind context = Kind.PLAIN; 086 087 // The fragment of the link. 088 private String fragment = ""; 089 090 // The member this link points to (if any). 091 private Element targetMember; 092 093 // Optional style for the link. 094 private HtmlStyle style = null; 095 096 // The class we want to link to. Null if we are not linking to a class. 097 private TypeElement typeElement; 098 099 // The executable element we want to link to. Null if we are not linking to 100 // an executable element. 101 private ExecutableElement executableElement; 102 103 // The Type we want to link to. Null if we are not linking to a type. 104 private TypeMirror type; 105 106 // True if this is a link to a VarArg. 107 private boolean isVarArg = false; 108 109 // The label for the link. 110 private Content label; 111 112 // True if we should print the type bounds for the type parameter. 113 private boolean showTypeBounds = true; 114 115 // True if type parameters should be rendered as links. 116 private boolean linkTypeParameters = true; 117 118 // By default, the link can be to the page it's already on. However, 119 // there are cases where we don't want this (e.g. heading of class page). 120 private boolean linkToSelf = true; 121 122 // True iff the preview flags should be skipped for this link. 123 private boolean skipPreview; 124 125 // True if type parameters should be separated by hard line breaks. 126 private boolean addLineBreaksInTypeParameters = false; 127 128 // True if additional <wbr> tags should be added to type parameters 129 private boolean addLineBreakOpportunitiesInTypeParameters = false; 130 131 // True if annotations on type parameters should be shown. 132 private boolean showTypeParameterAnnotations = false; 133 134 /** 135 * Construct a LinkInfo object. 136 * 137 * @param configuration the configuration data for the doclet 138 * @param context the context of the link. 139 * @param ee the member to link to. 140 */ 141 public HtmlLinkInfo(HtmlConfiguration configuration, Kind context, 142 ExecutableElement ee) { 143 this.configuration = configuration; 144 this.executableElement = ee; 145 setContext(context); 146 } 147 148 /** 149 * Construct a LinkInfo object. 150 * 151 * @param configuration the configuration data for the doclet 152 * @param context the context of the link. 153 * @param typeElement the class to link to. 154 */ 155 public HtmlLinkInfo(HtmlConfiguration configuration, Kind context, 156 TypeElement typeElement) { 157 this.configuration = configuration; 158 this.typeElement = typeElement; 159 setContext(context); 160 } 161 162 /** 163 * Construct a LinkInfo object. 164 * 165 * @param configuration the configuration data for the doclet 166 * @param context the context of the link. 167 * @param type the class to link to. 168 */ 169 public HtmlLinkInfo(HtmlConfiguration configuration, Kind context, 170 TypeMirror type) { 171 this.configuration = configuration; 172 this.type = type; 173 setContext(context); 174 } 175 176 /** 177 * Creates a copy of this HtmlLinkInfo instance with a different TypeMirror. 178 * This is used for contained types such as type parameters or array components. 179 * 180 * @param type the type mirror 181 * @return the new link info 182 */ 183 public HtmlLinkInfo forType(TypeMirror type) { 184 HtmlLinkInfo linkInfo = new HtmlLinkInfo(configuration, context, type); 185 linkInfo.showTypeBounds = showTypeBounds; 186 linkInfo.linkTypeParameters = linkTypeParameters; 187 linkInfo.linkToSelf = linkToSelf; 188 linkInfo.addLineBreaksInTypeParameters = addLineBreaksInTypeParameters; 189 linkInfo.showTypeParameterAnnotations = showTypeParameterAnnotations; 190 linkInfo.skipPreview = skipPreview; 191 return linkInfo; 192 } 193 194 /** 195 * Sets the typeElement 196 * @param typeElement the new typeElement object 197 */ 198 public void setTypeElement(TypeElement typeElement) { 199 this.typeElement = typeElement; 200 } 201 202 /** 203 * The class we want to link to. Null if we are not linking 204 * to a class. 205 */ 206 public TypeElement getTypeElement() { 207 return typeElement; 208 } 209 210 /** 211 * The executable element we want to link to. Null if we are not linking 212 * to an executable element. 213 */ 214 public ExecutableElement getExecutableElement() { 215 return executableElement; 216 } 217 218 /** 219 * The Type we want to link to. Null if we are not linking to a type. 220 */ 221 public TypeMirror getType() { 222 return type; 223 } 224 225 /** 226 * Set the label for the link. 227 * @param label plain-text label for the link 228 * @return this object 229 */ 230 public HtmlLinkInfo label(CharSequence label) { 231 this.label = Text.of(label); 232 return this; 233 } 234 235 /** 236 * Set the label for the link. 237 * @param label the new value 238 * @return this object 239 */ 240 public HtmlLinkInfo label(Content label) { 241 this.label = label; 242 return this; 243 } 244 245 /** 246 * {@return the label for the link} 247 */ 248 public Content getLabel() { 249 return label; 250 } 251 252 /** 253 * Sets the style to be used for the link. 254 * @param style the new style value 255 * @return this object 256 */ 257 public HtmlLinkInfo style(HtmlStyle style) { 258 this.style = style; 259 return this; 260 } 261 262 /** 263 * {@return the optional style for the link} 264 */ 265 public HtmlStyle getStyle() { 266 return style; 267 } 268 269 /** 270 * Set whether or not this is a link to a varargs parameter. 271 * @param varargs the new value 272 * @return this object 273 */ 274 public HtmlLinkInfo varargs(boolean varargs) { 275 this.isVarArg = varargs; 276 return this; 277 } 278 279 /** 280 * {@return true if this is a link to a vararg member} 281 */ 282 public boolean isVarArg() { 283 return isVarArg; 284 } 285 286 /** 287 * Set the fragment specifier for the link. 288 * @param fragment the new fragment value 289 * @return this object 290 */ 291 public HtmlLinkInfo fragment(String fragment) { 292 this.fragment = fragment; 293 return this; 294 } 295 296 /** 297 * {@return the fragment of the link} 298 */ 299 public String getFragment() { 300 return fragment; 301 } 302 303 /** 304 * Sets the addLineBreaksInTypeParameters flag for this link. 305 * @param addLineBreaksInTypeParameters the new value 306 * @return this object 307 */ 308 public HtmlLinkInfo addLineBreaksInTypeParameters( 309 boolean addLineBreaksInTypeParameters) { 310 this.addLineBreaksInTypeParameters = addLineBreaksInTypeParameters; 311 return this; 312 } 313 314 /** 315 * {@return true if type parameters should be separated by line breaks} 316 */ 317 public boolean addLineBreaksInTypeParameters() { 318 return addLineBreaksInTypeParameters; 319 } 320 321 /** 322 * Sets the addLineBreakOpportunitiesInTypeParameters flag for this link. 323 * @param addLineBreakOpportunities the new value 324 * @return this object 325 */ 326 public HtmlLinkInfo addLineBreakOpportunitiesInTypeParameters( 327 boolean addLineBreakOpportunities) { 328 this.addLineBreakOpportunitiesInTypeParameters 329 = addLineBreakOpportunities; 330 return this; 331 } 332 333 /** 334 * {@return true if line break opportunities should be added to type parameters} 335 */ 336 public boolean addLineBreakOpportunitiesInTypeParameters() { 337 return addLineBreakOpportunitiesInTypeParameters; 338 } 339 340 /** 341 * Set the linkToSelf flag for this link. 342 * @param linkToSelf the new value 343 * @return this object 344 */ 345 public HtmlLinkInfo linkToSelf(boolean linkToSelf) { 346 this.linkToSelf = linkToSelf; 347 return this; 348 } 349 350 /** 351 * {@return true if we should generate links to the current page} 352 */ 353 public boolean linkToSelf() { 354 return linkToSelf; 355 } 356 357 /** 358 * {@return true if type parameters should be rendered as links} 359 */ 360 public boolean linkTypeParameters() { 361 return linkTypeParameters; 362 } 363 364 /** 365 * Set the showTypeBounds flag for this link 366 * @param showTypeBounds the new value 367 */ 368 public void showTypeBounds(boolean showTypeBounds) { 369 this.showTypeBounds = showTypeBounds; 370 } 371 372 /** 373 * {@return true if we should print the type bounds for the type parameter} 374 */ 375 public boolean showTypeBounds() { 376 return showTypeBounds; 377 } 378 379 /** 380 * Set the showTypeParameterAnnotations flag for this link. 381 * @param showTypeParameterAnnotations the new value 382 * @return this object 383 */ 384 public HtmlLinkInfo 385 showTypeParameterAnnotations(boolean showTypeParameterAnnotations) { 386 this.showTypeParameterAnnotations = showTypeParameterAnnotations; 387 return this; 388 } 389 390 /** 391 * {@return true if annotations on type parameters should be shown} 392 */ 393 public boolean showTypeParameterAnnotations() { 394 return showTypeParameterAnnotations; 395 } 396 397 /** 398 * Set the member this link points to (if any). 399 * @param el the new member value 400 * @return this object 401 */ 402 public HtmlLinkInfo targetMember(Element el) { 403 this.targetMember = el; 404 return this; 405 } 406 407 /** 408 * {@return the member this link points to (if any)} 409 */ 410 public Element getTargetMember() { 411 return targetMember; 412 } 413 414 /** 415 * Set whether or not the preview flags should be skipped for this link. 416 * @param skipPreview the new value 417 * @return this object 418 */ 419 public HtmlLinkInfo skipPreview(boolean skipPreview) { 420 this.skipPreview = skipPreview; 421 return this; 422 } 423 424 /** 425 * {@return true iff the preview flags should be skipped for this link} 426 */ 427 public boolean isSkipPreview() { 428 return skipPreview; 429 } 430 431 /** 432 * {@return the link context} 433 */ 434 public Kind getContext() { 435 return context; 436 } 437 438 /** 439 * This method sets the link attributes to the appropriate values 440 * based on the context. 441 * 442 * @param c the context id to set. 443 */ 444 private void setContext(Kind c) { 445 linkTypeParameters = c == Kind.LINK_TYPE_PARAMS 446 || c == Kind.LINK_TYPE_PARAMS_AND_BOUNDS; 447 showTypeBounds = c == Kind.SHOW_TYPE_PARAMS_AND_BOUNDS 448 || c == Kind.LINK_TYPE_PARAMS_AND_BOUNDS; 449 context = c; 450 } 451 452 /** 453 * Return true if this link is linkable and false if we can't link to the 454 * desired place. 455 * 456 * @return true if this link is linkable and false if we can't link to the 457 * desired place. 458 */ 459 public boolean isLinkable() { 460 return configuration.utils.isLinkable(typeElement); 461 } 462 463 /** 464 * Returns true if links to declared types should include type parameters. 465 * 466 * @return true if type parameter links should be included 467 */ 468 public boolean showTypeParameters() { 469 // Type parameters for these kinds of links are either not desired 470 // or already included in the link label. 471 return context != Kind.PLAIN && context != Kind.SHOW_PREVIEW 472 && context != Kind.SHOW_TYPE_PARAMS_IN_LABEL; 473 } 474 475 /** 476 * Return the label for this class link. 477 * 478 * @param configuration the current configuration of the doclet. 479 * @return the label for this class link. 480 */ 481 public Content getClassLinkLabel(BaseConfiguration configuration) { 482 if (label != null && !label.isEmpty()) { 483 return label; 484 } else if (isLinkable()) { 485 Content tlabel = newContent(); 486 Utils utils = configuration.utils; 487 tlabel.add(type instanceof DeclaredType dt 488 && utils.isGenericType(dt.getEnclosingType()) 489 // If enclosing type is rendered as separate links only use 490 // own class name 491 ? typeElement.getSimpleName().toString() 492 : configuration.utils.getSimpleName(typeElement)); 493 return tlabel; 494 } else { 495 Content tlabel = newContent(); 496 tlabel.add(configuration.getClassName(typeElement)); 497 return tlabel; 498 } 499 } 500 501 /** 502 * {@return a new instance of a content object} 503 */ 504 protected Content newContent() { 505 return new ContentBuilder(); 506 } 507 508 @Override 509 public String toString() { 510 return "HtmlLinkInfo{" + 511 "typeElement=" + typeElement + 512 ", executableElement=" + executableElement + 513 ", type=" + type + 514 ", isVarArg=" + isVarArg + 515 ", label=" + label + 516 ", showTypeBounds=" + showTypeBounds + 517 ", linkTypeParameters=" + linkTypeParameters + 518 ", linkToSelf=" + linkToSelf + 519 ", addLineBreaksInTypeParameters=" + addLineBreaksInTypeParameters + 520 ", showTypeParameterAnnotations=" + showTypeParameterAnnotations + 521 ", context=" + context + 522 ", fragment=" + fragment + 523 ", style=" + style + '}'; 524 } 525}