/* Utility methods to handle HTML Viewer about: calls
Copyright (c) 2003-2014 The Regents of the University of California.
All rights reserved.
Permission is hereby granted, without written agreement and without
license or royalty fees, to use, copy, modify, and distribute this
software and its documentation for any purpose, provided that the above
copyright notice and the following two paragraphs appear in all copies
of this software.
IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
ENHANCEMENTS, OR MODIFICATIONS.
PT_COPYRIGHT_VERSION_2
COPYRIGHTENDKEY
*/
package ptolemy.actor.gui;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.swing.JFrame;
import javax.swing.event.HyperlinkEvent;
import ptolemy.actor.CompositeActor;
import ptolemy.actor.Manager;
import ptolemy.data.ArrayToken;
import ptolemy.data.StringToken;
import ptolemy.data.expr.FileParameter;
import ptolemy.data.expr.Parameter;
import ptolemy.kernel.attributes.VersionAttribute;
import ptolemy.kernel.util.IllegalActionException;
import ptolemy.kernel.util.InternalErrorException;
import ptolemy.kernel.util.StringAttribute;
import ptolemy.util.FileUtilities;
import ptolemy.util.StringUtilities;
///////////////////////////////////////////////////////////////////
//// HTMLAbout
/**
This class contains static methods that are called
by when HTMLViewer.hyperlinkUpdate() is invoked on a hyperlink
that starts with about:
. This facility is primarily
used for testing.
@author Christopher Hylands
@version $Id: HTMLAbout.java 70402 2014-10-23 00:52:20Z cxh $
@since Ptolemy II 3.0
@Pt.ProposedRating Red (cxh)
@Pt.AcceptedRating Red (cxh)
@see HTMLViewer#hyperlinkUpdate(HyperlinkEvent)
*/
public class HTMLAbout {
// This class is separate from HTMLViewer because this class
// import lots of Ptolemy specify classes that HTMLViewer does
// otherwise need to import
///////////////////////////////////////////////////////////////////
//// public methods ////
/** Return a string containing HTML that describes the about:
* features.
*
*
If the configuration contains an _applicationName attribute
* then that attribute is used as the name of the application
* in the generated text. If _applicationName is not present,
* then the default name is "Ptolemy II".
*
*
If the configuration contains an _applicationDemos Parameter
* then that parameter is assumed to be an array of strings name
* naming HTML files that should be searched for demos and expanded.
* @param configuration The configuration to look for the
* _applicationName attribute in
* @return A string containing HTML that describes the about: features.
*/
public static String about(Configuration configuration) {
// Use an explicit version here - the name of the whatsNew file
// does not changes as quickly as the version.
String version = VersionAttribute.majorCurrentVersion();
String applicationName = "Ptolemy II";
try {
StringAttribute applicationNameAttribute = (StringAttribute) configuration
.getAttribute("_applicationName", StringAttribute.class);
if (applicationNameAttribute != null) {
applicationName = applicationNameAttribute.getExpression();
}
} catch (Throwable throwable) {
// Ignore and use the default applicationName
}
StringBuffer htmlBuffer = new StringBuffer();
htmlBuffer.append("
About " + applicationName
+ "" + "About " + applicationName
+ "
\n" + "The HTML Viewer in " + applicationName
+ " handles the about:
\n" + "tag specially.\n"
+ "
The following urls are handled:\n" + "\n"
+ "- "
+ "
about:configuration
"
+ "Expand the configuration (good way to test for "
+ "missing classes).\n"
+ " - "
+ "
about:expandLibrary
"
+ "Open a model and expand library tree (good way to test for "
+ "missing classes, check standard out).\n"
+ " - "
+ "
about:copyright
"
+ " Display information about the copyrights.\n");
if (_configurationExists("full")) {
htmlBuffer.append(" - "
+ "
about:checkCompleteDemos
"
+ "Check that each of the demos listed in the individual "
+ "files is present in "
+ "ptolemy/configs/doc/completeDemos.htm
.\n");
}
htmlBuffer.append("
\n\n");
_demosURLs = new LinkedList();
if (_configurationExists("full")) {
htmlBuffer
.append("Full
\n"
+ _aboutHTML("ptolemy/configs/doc/completeDemos.htm")
+ _aboutHTML("ptolemy/configs/doc/demos.htm")
+ _aboutHTML("ptolemy/configs/doc/whatsNew"
+ version + ".htm")
+ _aboutHTML("ptolemy/configs/doc/whatsNew8.0.htm")
+ _aboutHTML("ptolemy/configs/doc/whatsNew7.0.htm")
+ _aboutHTML("ptolemy/configs/doc/whatsNew6.0.htm")
+ _aboutHTML("ptolemy/configs/doc/whatsNew5.1.htm")
+ _aboutHTML("ptolemy/configs/doc/whatsNew5.0.htm")
+ _aboutHTML("ptolemy/configs/doc/whatsNew4.0.htm")
+ _aboutHTML("ptolemy/configs/doc/whatsNew3.0.2.htm"));
}
if (_configurationExists("bcvtb")) {
htmlBuffer
.append("BCVTB
\n"
+ _aboutHTML("ptolemy/configs/bcvtb/intro.htm")
+ _aboutHTML("ptolemy/configs/doc/completeDemosBcvtb.htm")
+ _aboutHTML("ptolemy/configs/doc/demosBcvtb.htm")
+ _aboutHTML("ptolemy/configs/doc/docsBcvtb.htm"));
}
// Don't include DSP here, it uses the Ptiny demos anyway.
if (_configurationExists("hyvisual")) {
htmlBuffer
.append("HyVisual
\n"
+ _aboutHTML("ptolemy/configs/hyvisual/intro.htm"));
}
if (_configurationExists("ptiny")) {
htmlBuffer
.append("Ptiny
\n"
+ _aboutHTML("ptolemy/configs/doc/completeDemosPtiny.htm")
+ _aboutHTML("ptolemy/configs/doc/demosPtiny.htm")
+ _aboutHTML("doc/mainVergilPtiny.htm"));
}
if (_configurationExists("ptinyKepler")) {
htmlBuffer
.append("Ptiny for Kepler
\n"
+ _aboutHTML("ptolemy/configs/kepler/doc-index.htm")
+ _aboutHTML("doc/mainVergilPtinyKepler.htm")
+ _aboutHTML("ptolemy/configs/doc/demosPtinyKepler.htm")
+ _aboutHTML("ptolemy/configs/doc/docsPtinyKepler.htm")
+ _aboutHTML("ptolemy/configs/doc/completeDemosPtinyKepler.htm"));
}
if (_configurationExists("visualsense")) {
htmlBuffer
.append("VisualSense
\n"
+ _aboutHTML("ptolemy/configs/visualsense/intro.htm"));
}
try {
// Check for the _applicationDemos parameter
Parameter applicationDemos = (Parameter) configuration
.getAttribute("_applicationDemos", Parameter.class);
if (applicationDemos != null) {
htmlBuffer.append("" + applicationName
+ "
\n");
ArrayToken demoTokens = (ArrayToken) applicationDemos
.getToken();
for (int i = 0; i < demoTokens.length(); i++) {
StringToken demoToken = (StringToken) demoTokens
.getElement(i);
htmlBuffer.append(_aboutHTML(demoToken.stringValue()));
System.out.println("HTMLAbout: adding "
+ demoToken.stringValue());
}
}
} catch (Exception ex) {
throw new InternalErrorException(configuration, ex,
"Bad configuration for " + applicationName);
}
htmlBuffer.append("
\n");
htmlBuffer.append("\n\n");
return htmlBuffer.toString();
}
/** Check that all the demos in otherDemos are in completeDemos.
* Be sure to call {@link #about(Configuration)} before calling this method.
* @param completeDemos A URL pointing to the completeDemos.htm file
* @return HTML listing demos in otherDemos that are not in completeDemos.
* @exception IOException If there is a problem reading the
* completeDemos.htm file.
*/
public static String checkCompleteDemos(String completeDemos)
throws IOException {
URL demosURL = _getDemoURL(completeDemos);
StringBuffer results = new StringBuffer(
"Results of checking for demos not listed in full "
+ "demos
\n"
+ "For each of the files below, we list demos that are "
+ "not included in "
+ "" + demosURL + "
\n");
List completeDemosList = _getURLs(demosURL, ".*.xml$", true, 1);
if (_demosURLs == null) {
throw new NullPointerException(
"_demosURLs is null. Call HTMLAbout.about(Configuration) first.");
}
Iterator demosFileNames = _demosURLs.iterator();
while (demosFileNames.hasNext()) {
String demosFileName = (String) demosFileNames.next();
URL demoURL = _getDemoURL(demosFileName);
if (demoURL != null) {
results.append("\n\n");
List demosList = _getURLs(demoURL, ".*.xml$", true, 0);
Iterator demos = demosList.iterator();
while (demos.hasNext()) {
String demo = (String) demos.next();
if (!completeDemosList.contains(demo)) {
try {
URL missingDemoURL = ConfigurationApplication
.specToURL(demo);
results.append(" - " + missingDemoURL + "
\n");
} catch (IOException ex) {
results.append(" - " + demo + "
\n");
}
}
}
results.append("
\n");
}
}
return results.toString();
}
/** Call Configuration.openModel() on relative URLs that match a regexp.
* files are linked to from an HTML file.
* @param demosFileName The name of the HTML file that contains links
* to the .xml, .htm and .html files.
* If this argument is the empty string, then
* "ptolemy/configs/doc/completeDemos.htm" is used.
* @param regexp The regular expression of the links we are interested
* in.
* @param configuration The configuration to open the files in.
* @return the URL of the HTML file that was searched.
* @exception Exception If there is a problem opening a model.
*/
public static URL generateLinks(String demosFileName, String regexp,
Configuration configuration) throws Exception {
URL demosURL = _getDemoURL(demosFileName);
List modelList = _getURLs(demosURL, regexp);
Iterator models = modelList.iterator();
while (models.hasNext()) {
String model = (String) models.next();
if (model.startsWith("ptdoc:")) {
Effigy context = configuration.getDirectory()
.entityList(Effigy.class).iterator().next();
HTMLViewer.getDocumentation(configuration, model.substring(6),
context);
} else {
URL modelURL = new URL(demosURL, model);
try {
configuration.openModel(demosURL, modelURL,
modelURL.toExternalForm());
} catch (Throwable throwable) {
throw new Exception("Failed to open '" + modelURL + "'",
throwable);
}
}
}
return demosURL;
}
/** Process an "about:" HyperlinkEvent.
* @param event The HyperlinkEvent to process. The description of
* the event should start with "about:". If there are no specific
* matches for the description, then a general usage message is
* returned.
* @param configuration The configuration in which we are operating.
* @return A URL that points to the results.
* @exception Throwable If there is a problem invoking the about
* task.
*/
public static URL hyperlinkUpdate(HyperlinkEvent event,
Configuration configuration) throws Throwable {
URL newURL = null;
if (event.getDescription().equals("about:allcopyrights")) {
// Note that if we have a link that is
// about:allcopyrights
// then event.getURL() will return null, so we have
// to use getDescription()
try {
newURL = _temporaryHTMLFile("generatecopyright", ".htm",
GenerateCopyrights.generateHTML(configuration));
} catch (SecurityException ex) {
// Could be that we were running with -sandbox and
// cannot write the temporary file.
newURL = FileUtilities.nameToURL(
"$CLASSPATH/ptolemy/configs/doc/copyright.htm", null,
null);
}
} else if (event.getDescription()
.startsWith("about:checkCompleteDemos")) {
newURL = _temporaryHTMLFile("checkCompleteDemos", ".htm",
checkCompleteDemos("ptolemy/configs/doc/completeDemos.htm"));
} else if (event.getDescription().startsWith("about:checkModelSizes")) {
// Expand all the local .xml files in the fragment
// and check their sizes and locations
URI aboutURI = new URI(event.getDescription());
URL demosURL = _getDemoURL(aboutURI.getFragment());
// Third arg is true so modelList should contain absolute URLs.
List modelList = _getURLs(demosURL, ".*(.htm|.html|.xml)", true, 2);
// Convert the list to a Set and avoid duplicates.
Set modelSet = new HashSet(modelList);
newURL = _temporaryHTMLFile("checkModelSizes", ".htm",
CheckModelSize.checkModelSize(configuration,
(String[]) modelSet.toArray(new String[modelSet
.size()])));
} else if (event.getDescription().equals("about:copyright")) {
// Note that if we have a link that is
// about:copyright
// then event.getURL() will return null, so we have
// to use getDescription()
try {
newURL = _temporaryHTMLFile(
"copyright",
".htm",
GenerateCopyrights
.generatePrimaryCopyrightHTML(configuration)
+ "Other copyrights\n"
+ "about this configuration \n"
+ "(may take a moment to run).\n"
+ "