/* * Open Source Physics software is free software as described near the bottom of this code file. * * For additional information and documentation on Open Source Physics please see: * <http://www.opensourcephysics.org/> */ package org.opensourcephysics.tools; import java.net.MalformedURLException; import java.net.URL; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.filechooser.FileFilter; import org.opensourcephysics.controls.XML; import org.opensourcephysics.controls.XMLControl; import org.opensourcephysics.media.core.ImageVideoType; import org.opensourcephysics.media.core.VideoFileFilter; import org.opensourcephysics.media.core.VideoIO; /** * This represents a library resource. * * @author Douglas Brown * @version 1.0 */ public class LibraryResource implements Comparable<LibraryResource> { // static constants @SuppressWarnings("javadoc") public static final String META_AUTHOR = "Author"; //$NON-NLS-1$ @SuppressWarnings("javadoc") public static final String META_CONTACT = "Contact"; //$NON-NLS-1$ @SuppressWarnings("javadoc") public static final String META_KEYWORDS = "Keywords"; //$NON-NLS-1$ @SuppressWarnings("javadoc") public static final String[] META_TYPES = {META_AUTHOR, META_CONTACT, META_KEYWORDS}; @SuppressWarnings("javadoc") public static final String UNKNOWN_TYPE = "Unknown"; //$NON-NLS-1$ @SuppressWarnings("javadoc") public static final String COLLECTION_TYPE = "Collection"; //$NON-NLS-1$ @SuppressWarnings("javadoc") public static final String TRACKER_TYPE = "Tracker"; //$NON-NLS-1$ @SuppressWarnings("javadoc") public static final String EJS_TYPE = "EJS"; //$NON-NLS-1$ @SuppressWarnings("javadoc") public static final String VIDEO_TYPE = "Video"; //$NON-NLS-1$ @SuppressWarnings("javadoc") public static final String IMAGE_TYPE = "Image"; //$NON-NLS-1$ @SuppressWarnings("javadoc") public static final String HTML_TYPE = "HTML"; //$NON-NLS-1$ @SuppressWarnings("javadoc") public static final String PDF_TYPE = "PDF"; //$NON-NLS-1$ protected static final String[] RESOURCE_TYPES = {TRACKER_TYPE, EJS_TYPE, VIDEO_TYPE, IMAGE_TYPE, HTML_TYPE, PDF_TYPE, UNKNOWN_TYPE}; // static fields protected static List<String> allResourceTypes = new ArrayList<String>(); protected static Icon htmlIcon, videoIcon, trackerIcon, ejsIcon, pdfIcon, unknownIcon, imageIcon; protected static FileFilter[] imageFilters = new ImageVideoType().getFileFilters(); protected static DecimalFormat megabyteFormat; static { allResourceTypes.add(COLLECTION_TYPE); for (String next: RESOURCE_TYPES) allResourceTypes.add(next); String imageFile = "/org/opensourcephysics/resources/tools/images/html.gif"; //$NON-NLS-1$ htmlIcon = new ImageIcon(LibraryResource.class.getResource(imageFile)); imageFile = "/org/opensourcephysics/resources/tools/images/pdf.gif"; //$NON-NLS-1$ pdfIcon = new ImageIcon(LibraryResource.class.getResource(imageFile)); imageFile = "/org/opensourcephysics/resources/tools/images/video.gif"; //$NON-NLS-1$ videoIcon = new ImageIcon(LibraryResource.class.getResource(imageFile)); imageFile = "/org/opensourcephysics/resources/tools/images/portrait.gif"; //$NON-NLS-1$ imageIcon = new ImageIcon(LibraryResource.class.getResource(imageFile)); imageFile = "/org/opensourcephysics/resources/tools/images/tracker_icon_16.png"; //$NON-NLS-1$ trackerIcon = new ImageIcon(LibraryResource.class.getResource(imageFile)); imageFile = "/org/opensourcephysics/resources/tools/images/ejsicon.gif"; //$NON-NLS-1$ ejsIcon = new ImageIcon(LibraryResource.class.getResource(imageFile)); imageFile = "/org/opensourcephysics/resources/tools/images/question_mark.gif"; //$NON-NLS-1$ unknownIcon = new ImageIcon(LibraryResource.class.getResource(imageFile)); try { megabyteFormat = (DecimalFormat)NumberFormat.getInstance(); megabyteFormat.applyPattern("0.0"); //$NON-NLS-1$ } catch (Exception e) {} } // instance fields private String name=""; //$NON-NLS-1$ private String description=""; //$NON-NLS-1$ private String basePath=""; // base path for target and/or HTML //$NON-NLS-1$ private String htmlPath=""; // rel or abs path to HTML page that describes this resource //$NON-NLS-1$ protected String target=""; // rel or abs path to target //$NON-NLS-1$ private String type=UNKNOWN_TYPE; protected String displayName; private String thumbnail; private Map<String, String> properties = new TreeMap<String, String>(); private TreeSet<Metadata> metadata; protected LibraryCollection parent; protected String collectionPath; // used to open source collection of resources found in searches protected List<String> treePath; // used to define tree paths of resources found in searches /** * Constructor. * * @param name the name of the resource */ public LibraryResource(String name) { setName(name); } /** * Gets the name of this resource (never null). * * @return the name */ public String getName() { return name; } /** * Sets the name of this resource. * * @param aName the name * @return true if changed */ public boolean setName(String aName) { aName = aName==null? "": aName.trim(); //$NON-NLS-1$ if (!aName.equals(name)) { name = aName; return true; } return false; } /** * Gets the base path. * * @return the base path */ public String getBasePath() { return basePath; } /** * Sets the base path of this resource. * * @param path the base path * @return true if changed */ public boolean setBasePath(String path) { path = path==null? "": path.trim(); //$NON-NLS-1$ if (!path.equals(basePath)) { basePath = path; return true; } return false; } /** * Returns the first base path found in this or its ancestors. * * @return the base path */ protected String getInheritedBasePath() { if (!"".equals(basePath)) return basePath; //$NON-NLS-1$ if (parent!=null) return parent.getInheritedBasePath(); return basePath; } /** * Gets the target of this resource (file name or comPADRE command). * * @return the target */ public String getTarget() { return "".equals(target)? null: target; //$NON-NLS-1$ } /** * Gets the absolute path to the target. Note: this is needed for the * * @return the absolute target, or empty String if none */ private String getAbsoluteTarget() { if ("".equals(target)) return target; //$NON-NLS-1$ return XML.getResolvedPath(target, getInheritedBasePath()); } /** * Sets the target of this resource. * * @param path the target path * @return true if changed */ public boolean setTarget(String path) { path = path==null? "": path.trim(); //$NON-NLS-1$ if (!path.equals(target)) { thumbnail = null; target = path; path = path.toUpperCase(); if (path.endsWith(".TRK") || path.endsWith(".TRZ")) //$NON-NLS-1$ //$NON-NLS-2$ setType(LibraryResource.TRACKER_TYPE); else if (path.endsWith(".PDF")) //$NON-NLS-1$ setType(LibraryResource.PDF_TYPE); else if (path.indexOf("EJS")>-1) { //$NON-NLS-1$ setType(LibraryResource.EJS_TYPE); } else if (path.endsWith(".ZIP")) { //$NON-NLS-1$ final String base = getBasePath(); Runnable runner = new Runnable() { public void run() { String zipPath = XML.getResolvedPath(target, base); Set<String> files = ResourceLoader.getZipContents(zipPath); for (String next: files) { if (next.toUpperCase().endsWith(".TRK")) { //$NON-NLS-1$ setType(LibraryResource.TRACKER_TYPE); break; } } } }; new Thread(runner).start(); } else if (path.equals("")) { //$NON-NLS-1$ if (getHTMLPath()==null) setType(LibraryResource.UNKNOWN_TYPE); else setType(LibraryResource.HTML_TYPE); } else { boolean found = false; for (FileFilter next: imageFilters) { if (found) break; VideoFileFilter filter = (VideoFileFilter)next; for (String ext: filter.getExtensions()) { if (path.endsWith("."+ext.toUpperCase())) { //$NON-NLS-1$ setType(LibraryResource.IMAGE_TYPE); found = true; } } } for (String ext: VideoIO.getVideoExtensions()) { if (found) break; if (path.endsWith("."+ext.toUpperCase())) { //$NON-NLS-1$ setType(LibraryResource.VIDEO_TYPE); found = true; } } } return true; } return false; } /** * Gets the path to the html page displayed in the browser. * * @return the html path */ public String getHTMLPath() { return htmlPath; } /** * Sets the html path of this resource. * * @param path the html path * @return true if changed */ public boolean setHTMLPath(String path) { path = path==null? "": path.trim(); //$NON-NLS-1$ if (!path.equals(htmlPath)) { htmlPath = path; if (!(this instanceof LibraryCollection) && getTarget()==null) { if (path.equals("")) {//$NON-NLS-1$ setType(LibraryResource.UNKNOWN_TYPE); } else { setType(LibraryResource.HTML_TYPE); } } return true; } return false; } /** * Gets the absolute path to the html page displayed in the browser. * * @return the absolute html path, or empty String if none */ private String getAbsoluteHTMLPath() { if ("".equals(htmlPath)) return htmlPath; //$NON-NLS-1$ return XML.getResolvedPath(htmlPath, getInheritedBasePath()); } /** * Gets the description, which must be in html code. * * @return the description */ public String getDescription() { return description; } /** * Sets the description of this resource. * Note: the description must be in html code, since it is displayed * in the html pane of the LibraryTreePanel if the html path is empty. * * @param desc the description in HTML code * @return true if changed */ public boolean setDescription(String desc) { desc = desc==null? "": desc.trim(); //$NON-NLS-1$ if (!desc.equals(description)) { description = desc; return true; } return false; } /** * Gets the type of resource. * * @return the one of the static constant types defined in this class */ public String getType() { return type; } /** * Sets the type of this resource. * The types are static constants defined in this class. * * @param type the type * @return true if changed */ public boolean setType(String type) { if (this.type.equals(type)) return false; for (String next: allResourceTypes) { if (next.equals(type)) { this.type = next; return true; } } return false; } /** * Gets the metadata. * * @return the Set of Metadata (may be null) */ public TreeSet<Metadata> getMetadata() { return metadata; } /** * Gets the first metadata of a specified type. * @param key the type * @return Metadata, or null if none */ public Metadata getMetadata(String key) { if (metadata==null) return null; for (Metadata next: metadata) { if (next.data[0].equals(key)) return next; } return null; } /** * Sets the metadata. This replaces all previously added metadata. * * @param data a Set of Metadata (may be null) */ public void setMetadata(TreeSet<Metadata> data) { metadata = data; } /** * Adds a Metadata object to the metadata. * * @param data the Metadata */ public void addMetadata(Metadata data) { if (metadata==null) metadata = new TreeSet<Metadata>(); // standardize display of predefined metadata types for (String type: META_TYPES) { if (type.toLowerCase().equals(data.getData()[0])) { data.getData()[0] = type; } } metadata.add(data); } /** * Removes a Metadata object from the metadata. * * @param data the Metadata * @return true if removed */ public boolean removeMetadata(Metadata data) { if (metadata==null) metadata = new TreeSet<Metadata>(); for (Iterator<Metadata> it = metadata.iterator(); it.hasNext();) { if (it.next().equals(data)) { it.remove(); return true; } } return false; } /** * Sets an arbitrary String property. * * @param name the name of the property * @param value the value of the property */ public void setProperty(String name, String value) { properties.put(name, value); } /** * Gets a property value. May return null. * * @param name the name of the property * @return the value of the property */ public String getProperty(String name) { return properties.get(name); } /** * Returns the names of all defined properties. * @return a set of names */ public Set<String> getPropertyNames() { return properties.keySet(); } /** * Gets the icon for the tree node associated with this resource. * * @return the icon */ public Icon getIcon() { if (type==TRACKER_TYPE) return trackerIcon; if (type==EJS_TYPE) return ejsIcon; if (type==IMAGE_TYPE) return imageIcon; if (type==VIDEO_TYPE) return videoIcon; if (type==HTML_TYPE) return htmlIcon; if (type==PDF_TYPE) return pdfIcon; return null; } /** * Gets the thumbnail of this resource, if any. * * @return the thumbnail */ public String getThumbnail() { return thumbnail; } /** * Sets the thumbnail for this resource. * * @param imagePath the path to a thumbnail image */ public void setThumbnail(String imagePath) { thumbnail = imagePath; } /** * Gets the collection path for this resource. May return null. * * @return the collection path of this or an ancestor */ public String getCollectionPath() { if (collectionPath!=null) return collectionPath; if (parent!=null) return parent.getCollectionPath(); return null; } /** * Gets a title for tabs. May return null. * @param path the path to the xml file associated with this resource (may be null) * @return the title */ public String getTitle(String path) { // title is name of this resource or, if unnamed, file name or server and file name String title = getName(); if (title.equals("") && path!=null) { //$NON-NLS-1$ String fileName = XML.getName(path); String basePath = XML.getDirectoryPath(path); if (basePath.startsWith("http:")) { //$NON-NLS-1$ basePath = basePath.substring(5); while (basePath.startsWith("/")) { //$NON-NLS-1$ basePath = basePath.substring(1); } int i = basePath.indexOf("/"); //$NON-NLS-1$ if (i>-1) basePath = basePath.substring(0, i); title = basePath+": "+fileName; //$NON-NLS-1$ } else { title = XML.getName(path); } } displayName = title; return title; } @Override public String toString() { if (!getName().equals("")) return getName(); //$NON-NLS-1$ if (displayName!=null) return displayName; if (collectionPath!=null && parent==null) return getTitle(collectionPath); if (this instanceof LibraryCollection) return ToolsRes.getString("LibraryCollection.Name.Default"); //$NON-NLS-1$ return ToolsRes.getString("LibraryResource.Name.Default"); //$NON-NLS-1$ } /** * Compares this to the specified resource. * * @param resource the resource to compare * @return 0 if equal, otherwise alphabetical name order */ public int compareTo(LibraryResource resource) { final int BEFORE = -1; final int EQUAL = 0; final int AFTER = 1; if (this==resource) return EQUAL; // compare names int result = this.getName().compareTo(resource.getName()); if (result!=EQUAL) return result; // compare absolute targets String tar1 = this.getAbsoluteTarget(); String tar2 = resource.getAbsoluteTarget(); if (tar1!=null || tar2!=null) { if (tar1==null) return AFTER; if (tar2==null) return BEFORE; result = tar1.compareTo(tar2); } if (result!=EQUAL) return result; // compare HTML paths String html1 = this.getAbsoluteHTMLPath(); String html2 = resource.getAbsoluteHTMLPath(); if (html1!=null || html2!=null) { if (html1==null) return AFTER; if (html2==null) return BEFORE; result = html1.compareTo(html2); } if (result!=EQUAL) return result; // compare type result = this.getType().compareTo(resource.getType()); if (result!=EQUAL) return result; // // compare metadata // Set<Metadata> meta1 = this.getMetadata(); // Set<Metadata> meta2 = resource.getMetadata(); // if (meta1!=null || meta2!=null) { // if (meta1==null) return AFTER; // if (meta2==null) return BEFORE; // if (meta1.size()>meta2.size()) return BEFORE; // if (meta1.size()<meta2.size()) return AFTER; // // both have metadata sets of same size // for (Metadata next1: meta1) { // if (meta2.contains(next1)) continue; // same metadata in both // String key = next1.getData()[0]; // for (Metadata next2: meta2) { // // same key found // if (next2.getData()[0].equals(key)) { // return next1.getData()[1].compareTo(next2.getData()[1]); // } // } // } // } // if collection, compare child resources if (this instanceof LibraryCollection && resource instanceof LibraryCollection) { LibraryResource[] children1 = ((LibraryCollection)this).getResources(); LibraryResource[] children2 = ((LibraryCollection)resource).getResources(); if (children1.length>children2.length) return BEFORE; if (children1.length<children2.length) return AFTER; for (int i=0; i<children1.length; i++) { result = children1[i].compareTo(children2[i]); if (result!=EQUAL) return result; } } return EQUAL; } @Override public boolean equals(Object obj) { if (obj==null || !(obj instanceof LibraryResource)) return false; return compareTo((LibraryResource)obj)==0; } /** * Gets a clone of this resource. * * @return the clone */ public LibraryResource getClone() { boolean isCollection = this instanceof LibraryCollection; LibraryResource resource = isCollection? new LibraryCollection(getName()): new LibraryResource(getName()); resource.setBasePath(getBasePath()); resource.setTarget(getTarget()); resource.setHTMLPath(getHTMLPath()); resource.setDescription(getDescription()); resource.setType(getType()); for (String next: getPropertyNames()) { resource.setProperty(next, getProperty(next)); } if (getMetadata()!=null) { for (Metadata next: getMetadata()) { resource.addMetadata(new Metadata(next.getData()[0], next.getData()[1])); } } if (isCollection) { LibraryCollection thisCollection = (LibraryCollection)this; for (LibraryResource next: thisCollection.getResources()) { ((LibraryCollection)resource).addResource(next.getClone()); } } // lines below are for search results resource.collectionPath = getCollectionPath(); resource.treePath = getTreePath(null); return resource; } /** * Gets the tree path for this node. * @param pathComponents a List of Strings in root-to-leaf order that represent this path * @return the tree path */ protected List<String> getTreePath(List<String> pathComponents) { if (pathComponents==null) pathComponents = new ArrayList<String>(); if (parent!=null) parent.getTreePath(pathComponents); pathComponents.add(this.toString()); return pathComponents; } /** * Gets the html code for a resource with specified properties. * Note this code is for display in the LibraryBrowser, and has no stylesheet of its own. * * @param title the name of the resource * @param resourceType one of the LibraryResource defined types * @param thumbnailPath path to the thumbnail image file * @param description a description of the resource * @param authors authors * @param contact author contact information or institution * @param moreInfoURL link to external HTML with more information about the resource * @param attachment String[] {downloadURL, filename, sizeInBytes} (used for ComPADRE) * @param data Map of metadata names to values * * @return the html code */ public static String getHTMLCode(String title, String resourceType, String thumbnailPath, String description, String authors, String contact, String moreInfoURL, String[] attachment, Map<String, String> data) { StringBuffer buffer = new StringBuffer(); buffer.append ( "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">"); //$NON-NLS-1$ buffer.append( "\n <html>"); //$NON-NLS-1$ buffer.append( "\n <head>"); //$NON-NLS-1$ buffer.append( "\n"+getStyleSheetCode()); //$NON-NLS-1$ buffer.append( "\n <meta http-equiv=\"content-type\" content=\"text/html;charset=iso-8859-1\">"); //$NON-NLS-1$ if (data!=null) { for (String name: data.keySet()) { String value = data.get(name); buffer.append( "\n <meta name=\""+name+"\" content=\""+value+"\">"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } } if (title!=null && !title.equals("")) { //$NON-NLS-1$ buffer.append( "\n <title>"+title+"</title>"); //$NON-NLS-1$ //$NON-NLS-2$ } buffer.append( "\n </head>\n"); //$NON-NLS-1$ buffer.append( "\n <body>"); //$NON-NLS-1$ buffer.append(getHTMLBody(title, resourceType, thumbnailPath, description, authors, contact, moreInfoURL, attachment)); buffer.append( "\n </body>"); //$NON-NLS-1$ buffer.append( "\n </html>"); //$NON-NLS-1$ return buffer.toString(); } /** * Gets html <body> code for a resource with specified properties. * @param title the name of the resource * @param resourceType one of the LibraryResource defined types * @param thumbnailPath path to the thumbnail image file * @param description a description of the resource * @param authors authors * @param contact author contact information or institution * @param moreInfoURL link to external HTML with more information about the resource * @param attachment String[] {downloadURL, filename, sizeInBytes} (used for ComPADRE) * * @return the html path */ protected static String getHTMLBody(String title, String resourceType, String thumbnailPath, String description, String authors, String contact, String moreInfoURL, String[] attachment) { StringBuffer buffer = new StringBuffer(); if (title!=null && !title.equals("")) { //$NON-NLS-1$ buffer.append( "\n <h2>"+title+"</h2>"); //$NON-NLS-1$ //$NON-NLS-2$ } buffer.append( "\n <blockquote>"); //$NON-NLS-1$ if (resourceType!=null && !resourceType.equals("")) { //$NON-NLS-1$ if (allResourceTypes.contains(resourceType)) { resourceType = ToolsRes.getString("LibraryResource.Type."+resourceType); //$NON-NLS-1$ } buffer.append ( "\n <b>"+resourceType+"</b>"); //$NON-NLS-1$ //$NON-NLS-2$ } if (thumbnailPath!=null && !thumbnailPath.equals("")) { //$NON-NLS-1$ thumbnailPath = "<p><img src=\""+thumbnailPath+"\""; //$NON-NLS-1$ //$NON-NLS-2$ if (title!=null && !title.equals("")) { //$NON-NLS-1$ thumbnailPath += " alt=\""+title+"\""; //$NON-NLS-1$ //$NON-NLS-2$ } buffer.append ( "\n "+thumbnailPath+"></p>"); //$NON-NLS-1$ //$NON-NLS-2$ } if (description!=null && !description.equals("")) { //$NON-NLS-1$ if (!description.startsWith("<p>")) { //$NON-NLS-1$ description = "<p>"+insertLineBreaks(description)+"</p>"; //$NON-NLS-1$ //$NON-NLS-2$ } buffer.append( "\n "+description); //$NON-NLS-1$ } if (authors!=null && !authors.equals("")) { //$NON-NLS-1$ String authorTitle = ToolsRes.getString("LibraryTreePanel.Label.Author"); //$NON-NLS-1$ buffer.append( "\n <p><b>"+authorTitle+": </b>"+authors+"</p>"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } if (contact!=null && !contact.equals("")) { //$NON-NLS-1$ String contactTitle = ToolsRes.getString("LibraryTreePanel.Label.Contact"); //$NON-NLS-1$ buffer.append( "\n <p><b>"+contactTitle+": </b>"+contact+"</p>"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } if (attachment!=null && attachment[1]!=null) { String filename = attachment[1]; String resTitle = ToolsRes.getString("LibraryResource.Description.Resource"); //$NON-NLS-1$ int bytes = Integer.parseInt(attachment[2]); String size = " ("+megabyteFormat.format(bytes/1048576.0)+"MB)"; //$NON-NLS-1$ //$NON-NLS-2$ buffer.append( "\n <p><b>"+resTitle+": </b>"+filename+size+"</p>"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } if (moreInfoURL!=null && !moreInfoURL.equals("")) { //$NON-NLS-1$ try { new URL(moreInfoURL); // throws exception if malformed String infoTitle = ToolsRes.getString("LibraryComPADRE.Description.InfoField"); //$NON-NLS-1$ buffer.append( "\n <p><b>"+infoTitle+" </b><a href=\""+moreInfoURL+"\">"+moreInfoURL+"</a></p>"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ } catch (MalformedURLException e) { } } buffer.append( "\n </blockquote>"); //$NON-NLS-1$ return buffer.toString(); } /** * Returns the body style for a stylesheet. * * @return the body style */ protected static String getBodyStyle() { return "body {\n"+ //$NON-NLS-1$ " font-family: Verdana, Arial, Helvetica, sans-serif;\n"+ //$NON-NLS-1$ " font-size: 12pt;\n"+ //$NON-NLS-1$ " color: #405050;\n"+ //$NON-NLS-1$ " background-color: #FFFFFF;\n"+ //$NON-NLS-1$ "}\n"; //$NON-NLS-1$ } /** * Returns the H1 heading style for a stylesheet. * * @return the H1 heading style */ protected static String getH1Style() { return "h1 {\n"+ //$NON-NLS-1$ " font-size: 24pt;\n"+ //$NON-NLS-1$ " text-align: center;\n"+ //$NON-NLS-1$ "}\n"; //$NON-NLS-1$ } /** * Returns the H2 heading style for a stylesheet. * * @return the H2 heading style */ protected static String getH2Style() { return "h2 {\n"+ //$NON-NLS-1$ " font-size: 16pt;\n"+ //$NON-NLS-1$ "}\n"; //$NON-NLS-1$ } /** * Returns the H2 heading style for a stylesheet. * * @return the H2 heading style */ protected static String getStyleSheetCode() { return "<style TYPE=\"text/css\">\n"+ //$NON-NLS-1$ "<!--\n"+ //$NON-NLS-1$ getBodyStyle()+ getH1Style()+ getH2Style()+ "-->\n"+ //$NON-NLS-1$ "</style>\n"; //$NON-NLS-1$ } /** * Inserts HTML line breaks where new lines occur in text. * * @param text the text * @return the text with HTML line breaks */ protected static String insertLineBreaks(String text) { String[] parts = text.split("\n"); //$NON-NLS-1$ StringBuffer buf = new StringBuffer(); int last = parts.length-1; for (int i=0; i<=last; i++) { String next = parts[i]; buf.append(next); if (i<last) buf.append("<br>"); //$NON-NLS-1$ } return buf.toString(); } /** * A Comparable class for metadata key-value pairs. */ protected static class Metadata implements Comparable<Metadata> { private String[] data; public Metadata() { data = new String[] {"", ""}; //$NON-NLS-1$ //$NON-NLS-2$ } public Metadata(String key, String value) { key = key==null? "": key; //$NON-NLS-1$ value = value==null? "": value; //$NON-NLS-1$ data = new String[] {key, value}; } public String[] getData() { return data; } public void clearData() { data[0] = ""; //$NON-NLS-1$ data[1] = ""; //$NON-NLS-1$ } public int compareTo(Metadata meta) { int result = data[0].compareTo(meta.data[0]); return result==0? data[1].compareTo(meta.data[1]): result; } @Override public String toString() { return data[0]+": "+data[1]; //$NON-NLS-1$ } } /** * Returns an ObjectLoader to save and load data for this class. * * @return the object loader */ public static XML.ObjectLoader getLoader() { return new Loader(); } /** * The ObjectLoader class to save and load LibraryResource data. */ static class Loader implements XML.ObjectLoader { /** * Saves an object's data to an XMLControl. * * @param control the control to save to * @param obj the object to save */ public void saveObject(XMLControl control, Object obj) { LibraryResource res = (LibraryResource)obj; control.setValue("name", res.name); //$NON-NLS-1$ if (!"".equals(res.description)) //$NON-NLS-1$ control.setValue("description", res.description); //$NON-NLS-1$ if (!"".equals(res.htmlPath)) //$NON-NLS-1$ control.setValue("html_path", res.htmlPath); //$NON-NLS-1$ if (!"".equals(res.basePath)) //$NON-NLS-1$ control.setValue("base_path", res.basePath); //$NON-NLS-1$ if (!"".equals(res.target)) //$NON-NLS-1$ control.setValue("target", res.getTarget()); //$NON-NLS-1$ if (res.thumbnail!=null) control.setValue("thumbnail", res.getThumbnail()); //$NON-NLS-1$ if (!UNKNOWN_TYPE.equals(res.type)) control.setValue("type", res.type); //$NON-NLS-1$ if (res.metadata!=null && res.metadata.size()>0) { int len = res.metadata.size(); String[][] data = new String[len][]; int i = 0; for (Metadata next: res.metadata) { data[i] = next.data; i++; } control.setValue("metadata", data); //$NON-NLS-1$ } if (!res.getPropertyNames().isEmpty()) { ArrayList<String[]> props = new ArrayList<String[]>(); for (String name: res.getPropertyNames()) { props.add(new String[] {name, res.getProperty(name)}); } control.setValue("properties", props.toArray(new String[props.size()][2])); //$NON-NLS-1$ } } /** * Creates a new object. * * @param control the XMLControl with the object data * @return the newly created object */ public Object createObject(XMLControl control){ String name = control.getString("name"); //$NON-NLS-1$ return new LibraryResource(name); } /** * Loads an object with data from an XMLControl. * * @param control the control * @param obj the object * @return the loaded object */ public Object loadObject(XMLControl control, Object obj) { LibraryResource res = (LibraryResource)obj; // name is loaded in createObject() method res.setDescription(control.getString("description")); //$NON-NLS-1$ res.setBasePath(control.getString("base_path")); //$NON-NLS-1$ String target = control.getString("target"); //$NON-NLS-1$ if (target!=null) res.target = target; res.setHTMLPath(control.getString("html_path")); //$NON-NLS-1$ res.setType(control.getString("type")); //$NON-NLS-1$ res.setThumbnail(control.getString("thumbnail")); //$NON-NLS-1$ String[][] data = (String[][])control.getObject("metadata"); //$NON-NLS-1$ if (data!=null) { if (res.getMetadata()!=null) res.getMetadata().clear(); for (int i=0; i<data.length; i++) { String[] next = data[i]; res.addMetadata(new Metadata(next[0], next[1])); } } String[][] props = (String[][])control.getObject("properties"); //$NON-NLS-1$ if (props!=null) { for (String[] next: props) { res.setProperty(next[0], next[1]); } } return res; } } } /* * Open Source Physics software is free software; you can redistribute * it and/or modify it under the terms of the GNU General Public License (GPL) as * published by the Free Software Foundation; either version 2 of the License, * or(at your option) any later version. * Code that uses any portion of the code in the org.opensourcephysics package * or any subpackage (subdirectory) of this package must must also be be released * under the GNU GPL license. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA * or view the license online at http://www.gnu.org/copyleft/gpl.html * * Copyright (c) 2007 The Open Source Physics project * http://www.opensourcephysics.org */