/* * [JavaFXAPI.java] * * Summary: Generate a reference to Oracle JavaFX API documentation both online and on local hard disk. * * Copyright: (c) 2016-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 1.0 2016-04-22 initial versions, similar to JavaAPI macro. */ package com.mindprod.htmlmacros.macro; import com.mindprod.common18.Misc; import com.mindprod.common18.ST; import com.mindprod.entities.EntifyStrings; import com.mindprod.fastcat.FastCat; import com.mindprod.htmlmacros.support.JDKandJREVersions; import com.mindprod.htmlmacros.support.Tools; import java.util.regex.Matcher; import java.util.regex.Pattern; import static com.mindprod.htmlmacros.support.JDKandJREVersions.*; import static java.lang.System.*; /** * Generate a reference to Oracle JavaFX API documentation both online and on local hard disk. * * @author Roedy Green, Canadian Mind Products * @version 1.0 2016-04-22 initial versions, similar to JavaAPI macro. * @since 2010 */ public final class JavaFXAPI extends Macro { // declarations /** * used to compose string to decorate links */ private static final String ORACLES = "Oracle’s "; /** * how to use the macro */ private static final String USAGE = "\nJavaFXAPI macro needs {reference to JavaFX API without /api with .html#xxx} // /method " + "{description} [notes]"; /** * split up package.class.method(parms) extra. Optional package, mandatory class, optimal method */ private static final Pattern SPLIT_FULL = Pattern.compile( "([\\d\\p{Lower}\\.]+)?([\\p{Upper}][\\p{Alpha}\\d_]*)(\\.[\\p{Lower}][\\d\\p{Alpha}_]*)?(\\(.*\\))?" ); /** * split, to catch case, no package, no class, mandatory method */ private static final Pattern SPLIT_METHOD = Pattern.compile( "([\\p{Lower}][\\d\\p{Alpha}_]*)(\\(.*\\))?" ); /** * split, to catch case when mandatory package, no class, no method */ private static final Pattern SPLIT_PACKAGE = Pattern.compile( "([\\d\\p{Lower}.]+)" ); /** * name of class we are linking to */ private static String className; /** * extra descriptive in for about what we are linking to. */ private static String freeform; /** * name of method we are linking to */ private static String methodName; /** * method parms we are linking to */ private static String methodParms; /** * name of package we are linking to */ private static String packageName; // /declarations // methods /** * Build HTML for link to JavaDoc in the current JDK. * * @param refWithSlashes reference with / instead of File.separatorChar . partial or complete url. * * @return generated HTML */ private static String buildLocalLinkToCurrentJDK( String refWithSlashes ) { // e.g. file://localhost/J:/Program%20Files/Java/jdk1.8.0_131/api/javafx/beans/binding/Binding.html final FastCat sb = new FastCat( 8 ); sb.append( "in the current " ); sb.append( "JDK " ); sb.append( RECOMMENDED_JDK_FULL_VERSION ); sb.append( " " ); return sb.toString(); }// /method /** * Build HTML for link to JavaDoc in the old JDKs. No longer links to ancient JDK too. * * @param refWithSlashes reference with / instead of File.separatorChar. partial or complete url. * * @return generated HTML */ private static String buildLocalLinkToOldJDK( String refWithSlashes ) { // e.g. file://localhost/J:/Program Files/Java/jdk1.5.0_22/api/javafx/beans/binding/Binding.html final FastCat sb = new FastCat( 7 ); sb.append( "in the old JDK " ); sb.append( OLD_JDK_FULL_VERSION ); sb.append( " " ); return sb.toString(); }// /method /** * Build HTML for link to JavaDoc in the old JDKs. No longer links to ancient JDK too. * * @param refWithSlashes reference with / instead of File.separatorChar. partial or complete url. * * @return generated HTML */ private static String buildWebLinkToJDK( String refWithSlashes ) { // e.g. http://docs.oracle.com/javase/8/docs/api/javax/swing/JApplet.html // only use latest web docs final FastCat sb = new FastCat( 4 ); // http://docs.oracle.com/javase/8/javafx/api/toc.htm sb.append( "on the web at Oracle.com" ); return sb.toString(); }// /method /** * parse and decorate the description * * @param refWithSlashes tail end of URL to javadoc for that class/method. * @param desc name of Java class/method * @param notes notes about what this class/method is for, or how to use it. * * @return desc decorated with additional descriptive info and html */ private static String elaborate( final String refWithSlashes, String desc, final String notes ) { // strip any leading the and trailing class desc = ST.chopLeadingString( desc, "the " ); desc = ST.chopTrailingString( desc, " class" ); desc = ST.chopTrailingString( desc, " method" ); final boolean isInterface = desc.endsWith( " interface" ); desc = ST.chopTrailingString( desc, " interface" ); desc = ST.chopTrailingString( desc, " package" ); splitDesc( desc ); // this is similar logic to Qualified, but qualified cannot handle (xxx). When it can, we can replace this logic. final FastCat sb = new FastCat( 29 ); sb.append( ORACLES + "JavaFX Javadoc on " ); if ( packageName.length() > 0 ) { sb.append( "" ); sb.append( packageName ); sb.append( "" ); } if ( className.length() > 0 ) { if ( isInterface ) { sb.append( "" ); } else { sb.append( "" ); } sb.append( className ); sb.append( "" ); } if ( methodName.length() > 0 ) { sb.append( "" ); sb.append( methodName ); sb.append( "" ); } if ( methodParms.length() > 0 ) { sb.append( "" ); sb.append( methodParms ); sb.append( "" ); } if ( freeform.length() > 0 ) { if ( packageName.length() == 0 && className.length() == 0 && methodName.length() == 0 && methodParms.length () == 0 ) { // if nothing but extra, highlight it. sb.append( "" ); sb.append( freeform ); sb.append( "" ); } else { sb.append( freeform ); } } if ( isInterface ) { sb.append( " interface" ); } else if ( refWithSlashes.endsWith( "package-summary.html" ) || packageName.length() > 0 && packageName.indexOf( ' ' ) < 0 && className.length() == 0 ) { sb.append( " package" ); } else if ( className.length() > 0 && className.indexOf( ' ' ) < 0 && methodName.length() == 0 ) { sb.append( " class" ); } else if ( methodName.length() > 0 && methodName.indexOf( ' ' ) < 0 && Character.isLowerCase( methodName.charAt( 0 ) ) ) { sb.append( " method" ); // otherwise is var, constant or something else. } if ( notes != null ) { sb.append( " : " ); sb.append( notes ); } return sb.toString(); }// /method /** * split the description up into fields, packageName, className, methodName, methodParms and extra. * * @param desc description from macro parm. */ private static void splitDesc( String desc ) { // has package.Class.method(parms)extra stuff, where various parts can be missing. final Matcher m1 = SPLIT_FULL.matcher( desc ); if ( m1.matches() ) { packageName = m1.group( 1 ); className = m1.group( 2 ); methodName = m1.group( 3 ); methodParms = m1.group( 4 ); freeform = null; } else { final Matcher m2 = SPLIT_PACKAGE.matcher( desc ); if ( m2.matches() ) { packageName = m2.group( 1 ); className = null; methodName = null; methodParms = null; freeform = null; } else { final Matcher m3 = SPLIT_METHOD.matcher( desc ); if ( m3.matches() ) { packageName = null; className = null; methodName = m3.group( 1 ); methodParms = m3.group( 2 ); freeform = null; } else { // does not match any of the standard patterns packageName = null; className = null; methodName = null; methodParms = null; freeform = desc; } } } if ( packageName == null ) { packageName = ""; } if ( className == null ) { className = ""; } if ( methodName == null ) { methodName = ""; } if ( methodParms == null ) { methodParms = ""; } if ( freeform == null ) { freeform = ""; } }// /method /** * Build HTML to describe the J: drive links. * * @return generated HTML */ private String buildJDriveDescription() { final FastCat sb = new FastCat( 3 ); sb.append( "on your local Windows J: drive." ); return sb.toString(); }// /method /** * Build HTML to for links to Oracle remote and local. * * @param refWithSlashes reference with / instead of File.separatorChar. partial or complete url. * @param elaborateDesc expanded human-readable description for the link. * * @return generated HTML */ private String buildTripleLinkToAPIDoc( String refWithSlashes, String elaborateDesc ) { refWithSlashes = Misc.miniURLEncode( refWithSlashes ); final FastCat sb = new FastCat( 15 ); sb.append( "
" ); sb.append( elaborateDesc ); sb.append( " : available:
\n" ); return sb.toString(); } /** * guts to Generate reference to a Oracle HTML document. * * @param ref usually a fully qualified referenced to sun or oracle site, * @param desc human description of what it is. * @param notes notes about what this class/method is for, or how to use it. * * @return expand href both to online and local. * @noinspection WeakerAccess */ private String expand( String ref, String desc, String notes ) { if ( ref.startsWith( "api" ) || ref.startsWith( "http:" ) || ref.startsWith( "/" ) ) { throw new IllegalArgumentException( "JavaFXAPI reference should start with a package name. e.g. javafx..." ); } if ( !( ref.startsWith( "javafx/" ) || ref.startsWith( "allclasses-frame.html" ) || ref.startsWith( "index-files/" ) || ref.startsWith( "org/omg/" ) || ref.startsWith( "org/w3c/" ) || ref.startsWith( "overview-frame.html" ) || ref.startsWith( "overview-tree.html" ) || ref.startsWith( "serialized-form.html" ) ) ) { //docs.oracle.com/javase/7/docs/jre/api/javaws/jnlp/index.html err.println( "Warning: JavaFXAPI reference to unknown package: " + ref + " on page " + fileBeingProcessed .toString() ); } // reference java/text/Normalizer.html -> http://docs.oracle.com/javase/7/docs/api/java/text/Normalizer.html return buildTripleLinkToAPIDoc( ref, elaborate( ref, desc, notes ) ); }// /method /** * typical use: macro JavaFXAPI javaFX javafx/beans/binding/Binding.html Binding * no lead http: * * @param parms link desc, not entified * @param quiet true if should suppress optional info. * @param verbose @return expanded macro HTML */ public final String expandMacro( String[] parms, final boolean quiet, final boolean verbose ) { if ( !quiet ) { out.print( "J" ); } if ( !( 2 <= parms.length && parms.length <= 3 ) ) { throw new IllegalArgumentException( USAGE ); } final String ref = parms[ 0 ]; if ( !ref.contains( ".html" ) ) { throw new IllegalArgumentException( "JavaFXAPI Missing .html in reference\n" + USAGE ); } final String desc = EntifyStrings.entifyHTML( parms[ 1 ] ); final String notes = parms.length > 2 ? parms[ 2 ] : null; return expand( ref, desc, notes ); }// /method // /methods }