001/* A tableau representing a plot window. 002 003 Copyright (c) 2000-2014 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_2 025 COPYRIGHTENDKEY 026 */ 027package ptolemy.actor.gui; 028 029import java.io.InputStream; 030import java.net.MalformedURLException; 031import java.net.URI; 032import java.net.URL; 033 034import javax.swing.JFrame; 035 036import ptolemy.kernel.attributes.URIAttribute; 037import ptolemy.kernel.util.Attribute; 038import ptolemy.kernel.util.IllegalActionException; 039import ptolemy.kernel.util.InternalErrorException; 040import ptolemy.kernel.util.NameDuplicationException; 041import ptolemy.kernel.util.NamedObj; 042import ptolemy.plot.Plot; 043import ptolemy.plot.PlotBox; 044import ptolemy.plot.plotml.PlotMLParser; 045import ptolemy.util.MessageHandler; 046 047/////////////////////////////////////////////////////////////////// 048//// PlotTableau 049 050/** 051 A tableau representing a plot in a toplevel window. 052 The URL that is viewed is given by the <i>uri</i> parameter, and 053 can be either an absolute URL, a system fileName, or a resource that 054 can be loaded relative to the classpath. For more information about how 055 the URL is specified, see MoMLApplication.specToURL(). 056 <p> 057 The plot frame itself must be an instance of PlotTableauFrame, 058 and must be created by the caller. 059 As with other tableaux, this is an entity that is contained by 060 an effigy of a model. 061 There can be any number of instances of this class in an effigy. 062 063 @author Edward A. Lee 064 @version $Id$ 065 @since Ptolemy II 2.1 066 @Pt.ProposedRating Yellow (eal) 067 @Pt.AcceptedRating Red (cxh) 068 @see Effigy 069 @see PlotTableauFrame 070 @see MoMLApplication#specToURL(String) 071 */ 072public class PlotTableau extends Tableau { 073 /** Construct a new tableau for the model represented by the given effigy. 074 * Use setFrame() to specify the plot frame after construction. 075 * @param container The container. 076 * @param name The name. 077 * @exception IllegalActionException If the container does not accept 078 * this entity (this should not occur). 079 * @exception NameDuplicationException If the name coincides with an 080 * attribute already in the container. 081 */ 082 public PlotTableau(Effigy container, String name) 083 throws IllegalActionException, NameDuplicationException { 084 super(container, name); 085 086 uri = new URIAttribute(this, "uri"); 087 } 088 089 /////////////////////////////////////////////////////////////////// 090 //// public parameters //// 091 092 /** The URI to display. */ 093 public URIAttribute uri; 094 095 /////////////////////////////////////////////////////////////////// 096 //// public methods //// 097 098 /** If the argument is the <i>uri</i> parameter, then open the 099 * specified URI and display its contents. 100 * @param attribute The attribute that changed. 101 * @exception IllegalActionException If the URL cannot be opened, 102 * or if the base class throws it. 103 */ 104 @Override 105 public void attributeChanged(Attribute attribute) 106 throws IllegalActionException { 107 if (attribute == uri) { 108 try { 109 URL toRead = new URL(uri.getURI().toString()); 110 _parseURL(toRead); 111 } catch (MalformedURLException ex) { 112 throw new IllegalActionException(this, ex, 113 "Invalid URL specification."); 114 } 115 } else { 116 super.attributeChanged(attribute); 117 } 118 } 119 120 /** Set the top-level window associated with this tableau. 121 * @param frame The top-level window associated with the tableau. 122 * @exception IllegalActionException If the frame is not an instance 123 * of PlotTableauFrame. 124 */ 125 @Override 126 public void setFrame(JFrame frame) throws IllegalActionException { 127 if (frame != null && !(frame instanceof PlotTableauFrame)) { 128 throw new IllegalActionException(this, 129 "Frame for PlotTableau must be an instance of " 130 + "PlotTableauFrame."); 131 } 132 133 super.setFrame(frame); 134 if (frame != null) { 135 ((PlotTableauFrame) frame).setTableau(this); 136 } 137 } 138 139 /** Make this tableau visible by calling setVisible(true), and 140 * raising or deiconifying its window. 141 * If no frame has been set, then create one, an instance of 142 * PlotTableauFrame. If a URL has been specified but not yet 143 * processed, then process it. 144 */ 145 @Override 146 public void show() { 147 JFrame frame = getFrame(); 148 149 if (frame == null) { 150 PlotTableauFrame newFrame = new PlotTableauFrame(this); 151 newFrame.plot.setButtons(true); 152 153 try { 154 setFrame(newFrame); 155 } catch (IllegalActionException ex) { 156 throw new InternalErrorException(ex); 157 } 158 } 159 160 if (_toRead != null) { 161 _parseURL(_toRead); 162 } 163 164 super.show(); 165 } 166 167 /////////////////////////////////////////////////////////////////// 168 //// private methods //// 169 170 /** Read from the specified URL in PlotML format. 171 * If there is no plot frame yet, then defer. 172 * Report any errors. 173 * @param url The URL to read from. 174 */ 175 private void _parseURL(URL url) { 176 try { 177 PlotTableauFrame frame = (PlotTableauFrame) getFrame(); 178 179 if (frame != null) { 180 // FIXME: Should use a HistogramMLParser to get a histogram 181 // view... But how can we know that is what is wanted? 182 PlotMLParser parser = new PlotMLParser((Plot) frame.plot); 183 InputStream stream = url.openStream(); 184 parser.parse(url, stream); 185 stream.close(); 186 _toRead = null; 187 } else { 188 // There is no plotter yet. Have to defer. 189 _toRead = url; 190 } 191 } catch (Exception ex) { 192 MessageHandler.error( 193 "Failed to read plot data: " + url.toExternalForm(), ex); 194 } 195 } 196 197 /////////////////////////////////////////////////////////////////// 198 //// private members //// 199 // URL of deferred read. 200 private URL _toRead = null; 201 202 /////////////////////////////////////////////////////////////////// 203 //// inner classes //// 204 205 /** A factory that creates a plot tableau for Ptolemy models. 206 */ 207 public static class Factory extends TableauFactory { 208 /** Create a factory with the given name and container. 209 * @param container The container. 210 * @param name The name. 211 * @exception IllegalActionException If the container is incompatible 212 * with this attribute. 213 * @exception NameDuplicationException If the name coincides with 214 * an attribute already in the container. 215 */ 216 public Factory(NamedObj container, String name) 217 throws IllegalActionException, NameDuplicationException { 218 super(container, name); 219 } 220 221 /////////////////////////////////////////////////////////////////// 222 //// public methods //// 223 224 /** If the specified effigy already contains a tableau named 225 * "plotTableau", then return that tableau; otherwise, create 226 * a new instance of PlotTableau in the specified 227 * effigy, and name it "plotTableau". If the specified 228 * effigy is not an instance of PlotEffigy, then do not 229 * create a tableau and return null. It is the 230 * responsibility of callers of this method to check the 231 * return value and call show(). 232 * 233 * @param effigy The effigy. 234 * @return A plot tableau, or null if one cannot be 235 * found or created. 236 * @exception Exception If the factory should be able to create a 237 * tableau for the effigy, but something goes wrong. 238 */ 239 @Override 240 public Tableau createTableau(Effigy effigy) throws Exception { 241 if (effigy instanceof PlotEffigy) { 242 // Indicate to the effigy that this factory contains effigies 243 // offering multiple views of the effigy data. 244 effigy.setTableauFactory(this); 245 246 // First see whether the effigy already contains an 247 // PlotTableau. 248 PlotTableau tableau = (PlotTableau) effigy 249 .getEntity("plotTableau"); 250 251 if (tableau == null) { 252 tableau = new PlotTableau(effigy, "plotTableau"); 253 } 254 255 PlotBox plotBox = (PlotBox) ((PlotEffigy) effigy).getPlot(); 256 257 if (plotBox != null) { 258 // Hook into the existing plot. 259 PlotTableauFrame plotterFrame = new PlotTableauFrame( 260 tableau, plotBox); 261 tableau.setFrame(plotterFrame); 262 } 263 264 URI uri = effigy.uri.getURI(); 265 266 if (uri != null) { 267 tableau.uri.setURI(uri); 268 } 269 270 // Don't call show() here. If show() is called here, 271 // then you can't set the size of the window after 272 // createTableau() returns. This will affect how 273 // centering works. 274 return tableau; 275 } else { 276 return null; 277 } 278 } 279 } 280}