ControllerMetadataViewer.java
001 /*
002  * ControllerMetadataViewer.java
003  *
004  * Copyright (c) 2012, The University of Sheffield. See the file COPYRIGHT.txt
005  * in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
006  *
007  * This file is part of GATE (see http://gate.ac.uk/), and is free software,
008  * licenced under the GNU Library General Public License, Version 2, June 1991
009  * (in the distribution as file licence.html, and also available at
010  * http://gate.ac.uk/gate/licence.html).
011  *
012  * Mark A. Greenwood, 08/11/2012
013  */
014 
015 package gate.gui;
016 
017 import gate.Controller;
018 import gate.Gate;
019 import gate.GateConstants;
020 import gate.Resource;
021 import gate.creole.AbstractVisualResource;
022 import gate.creole.ResourceInstantiationException;
023 import gate.creole.metadata.CreoleResource;
024 import gate.creole.metadata.GuiType;
025 
026 import java.awt.BorderLayout;
027 import java.awt.Font;
028 import java.io.StringReader;
029 import java.net.URL;
030 import java.util.Iterator;
031 import java.util.List;
032 
033 import javax.swing.JScrollPane;
034 import javax.xml.parsers.DocumentBuilder;
035 import javax.xml.parsers.DocumentBuilderFactory;
036 import javax.xml.parsers.ParserConfigurationException;
037 
038 import org.apache.commons.io.IOUtils;
039 import org.apache.commons.lang.StringEscapeUtils;
040 import org.apache.xerces.parsers.DOMParser;
041 import org.cyberneko.html.HTMLConfiguration;
042 import org.w3c.dom.Document;
043 import org.w3c.dom.Node;
044 import org.xhtmlrenderer.simple.XHTMLPanel;
045 import org.xhtmlrenderer.swing.BasicPanel;
046 import org.xhtmlrenderer.swing.FSMouseListener;
047 import org.xhtmlrenderer.swing.LinkListener;
048 import org.xhtmlrenderer.util.Configuration;
049 import org.xml.sax.InputSource;
050 
051 /**
052  * This viewer displays metadata associated with a GATE Controller. The location
053  * of the <code>metadata.xml</code> file is specified using the
054  <code>gate.app.MetadataURL</code> feature on the controller. Note that this
055  * feature must be a URL object and not a String. Currently the only way to
056  * specifiy a URL as a controler feature is to manually edit the saved xgapp
057  * file.
058  
059  @author Mark A. Greenwood
060  */
061 @CreoleResource(name = "About...", guiType = GuiType.LARGE, resourceDisplayed = "gate.Controller")
062 public class ControllerMetadataViewer extends AbstractVisualResource {
063 
064   private static final long serialVersionUID = -1161421403987238291L;
065 
066   private XHTMLPanel display = new XHTMLPanel();
067 
068   private DocumentBuilderFactory builderFactory = DocumentBuilderFactory
069       .newInstance();
070 
071   private DocumentBuilder builder = null;
072 
073   @SuppressWarnings("rawtypes")
074   @Override
075   public Resource init() throws ResourceInstantiationException {
076     setLayout(new BorderLayout());
077     add(new JScrollPane(display), BorderLayout.CENTER);
078 
079     try {
080       builder = builderFactory.newDocumentBuilder();
081     catch(ParserConfigurationException e) {
082       throw new ResourceInstantiationException(
083           "Unable to construct an XML parser", e);
084     }
085 
086     if(Configuration.isTrue("xr.use.listeners"true)) {
087       List l = display.getMouseTrackingListeners();
088       for(Iterator i = l.iterator(); i.hasNext();) {
089         FSMouseListener listener = (FSMouseListener)i.next();
090         if(listener instanceof LinkListener) {
091           display.removeMouseTrackingListener(listener);
092         }
093       }
094       display.addMouseTrackingListener(new LinkListener() {
095 
096         @Override
097         public void linkClicked(BasicPanel panel, String uri) {
098           //open any links in an actual web browser
099           MainFrame.getInstance().showHelpFrame(uri, null);
100         }
101       });
102     }
103 
104     return this;
105   }
106 
107   @Override
108   public void setTarget(Object target) {
109 
110     if(target == null)
111       throw new NullPointerException("received a null target");
112 
113     if(!(target instanceof Controller))
114       throw new IllegalArgumentException("not a controller");
115 
116     Controller controller = (Controller)target;
117 
118     if(!controller.getFeatures().containsKey("gate.app.MetadataURL"))
119       throw new IllegalArgumentException("no gate.app.MetadataURL feature");
120 
121     try {
122       URL metadata = (URL)controller.getFeatures().get("gate.app.MetadataURL");
123       URL longDesc = new URL(metadata, "long-desc.html");
124       URL iconDesc = new URL(metadata, "icon.png");
125 
126       Document document = builder.parse(metadata.openStream());
127 
128       Node text =
129           document.getDocumentElement().getElementsByTagName("pipeline-name")
130               .item(0).getFirstChild();
131 
132       Font font =
133           Gate.getUserConfig().getFont(GateConstants.TEXT_COMPONENTS_FONT);
134 
135       StringBuilder page = new StringBuilder();
136       page.append("<!DOCTYPE html>");
137       page.append("<html>");
138       page.append("<head>");
139       page.append("<style type='text/css'>body { font-family: ")
140           .append(font.getFamily()).append("; font-size: ")
141           .append(font.getSize()).append("pt }</style>");
142       page.append("</head>");
143       page.append("<body>");
144       page.append("<h1><img style='vertical-align: middle;' src='")
145           .append(StringEscapeUtils.escapeHtml(iconDesc.toString())).append("'/> ")
146           .append(StringEscapeUtils.escapeHtml(text.getTextContent())).append("</h1>");
147       page.append(IOUtils.toString(longDesc, "UTF-8"));
148       page.append("</body></html>");
149 
150       // parse using NekoHTML
151       HTMLConfiguration config = new HTMLConfiguration();
152       // Force element names to lower case to match XHTML requirements
153       // as that is what Flying Saucer expects
154       config.setProperty("http://cyberneko.org/html/properties/names/elems""lower");
155       DOMParser htmlParser = new DOMParser(config);
156       htmlParser.parse(new InputSource(new StringReader(page.toString())));
157       display.setDocument(htmlParser.getDocument(),
158           longDesc.toString());
159 
160     catch(Exception e) {
161       throw new IllegalArgumentException(e);
162     }
163   }
164 }