001/* 002 Interface encapsulating platform dependent code of the PlotterBase from the 003 platform independent parts. 004 005 @Copyright (c) 1998-2014 The Regents of the University of California. 006 All rights reserved. 007 008 Permission is hereby granted, without written agreement and without 009 license or royalty fees, to use, copy, modify, and distribute this 010 software and its documentation for any purpose, provided that the 011 above copyright notice and the following two paragraphs appear in all 012 copies of this software. 013 014 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 015 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 016 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 017 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 018 SUCH DAMAGE. 019 020 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 021 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 022 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 023 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 024 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 025 ENHANCEMENTS, OR MODIFICATIONS. 026 027 PT_COPYRIGHT_VERSION 2 028 COPYRIGHTENDKEY 029 */ 030 031package ptolemy.actor.lib.gui; 032 033import java.awt.Component; 034import java.awt.Container; 035import java.awt.event.WindowAdapter; 036import java.awt.event.WindowEvent; 037 038import javax.swing.SwingUtilities; 039 040import ptolemy.actor.gui.Configuration; 041import ptolemy.actor.gui.Effigy; 042import ptolemy.actor.gui.PlotEffigy; 043import ptolemy.actor.gui.PlotTableau; 044import ptolemy.actor.gui.PlotTableauFrame; 045import ptolemy.actor.gui.SizeAttribute; 046import ptolemy.actor.gui.WindowPropertiesAttribute; 047import ptolemy.kernel.util.IllegalActionException; 048import ptolemy.kernel.util.NameDuplicationException; 049import ptolemy.plot.Plot; 050import ptolemy.plot.PlotBox; 051import ptolemy.plot.PlotBoxInterface; 052 053/////////////////////////////////////////////////////////////////// 054//// PlotterBaseJavaSE 055 056/** 057 * Java SE implementation of PlotterBaseInterface. The code is largely based on 058 * the original platform dependent version of the PlotterBase but was moved here 059 * in order to support portability of the actor. 060 * @author Edward A. Lee Contributors: Anar Huseynov 061 * @version $Id$ 062 * @since Ptolemy II 10.0 063 * @Pt.ProposedRating Red (ahuseyno) 064 * @Pt.AcceptedRating Red (ahuseyno) 065 */ 066public class PlotterBaseJavaSE implements PlotterBaseInterface { 067 068 /** Show and then bing the frame to the front. */ 069 @Override 070 public void bringToFront() { 071 if (_frame != null) { 072 // show() used to call pack, which would override any manual 073 // changes in placement. No more. 074 _frame.show(); 075 _frame.toFront(); 076 } 077 } 078 079 /** 080 * Free up memory when closing. 081 */ 082 @Override 083 public void cleanUp() { 084 _tableau = null; 085 } 086 087 /** 088 * Get the plotter's frame. 089 * @return the plotter's frame. 090 * @see #setFrame(Object) 091 */ 092 @Override 093 public Object getFrame() { 094 return _frame; 095 } 096 097 /** 098 * Get the platform dependent container that contains the plotter. 099 * @return the platform dependent container. 100 * @see #setPlatformContainer(Object) 101 */ 102 @Override 103 public Object getPlatformContainer() { 104 return _container; 105 } 106 107 /** 108 * Get the plotter tableau. 109 * @return the plotter tableau. 110 */ 111 @Override 112 public Object getTableau() { 113 return _tableau; 114 } 115 116 /** 117 * Initialize the implementation. 118 * @param plotterBase the instance that created the implementation. 119 */ 120 @Override 121 public void init(PlotterBase plotterBase) { 122 _plotterBase = plotterBase; 123 } 124 125 /** 126 * Initialize the effigy of the plotter. 127 * @exception IllegalActionException If there is a problem initializing the effigy 128 */ 129 @Override 130 public void initializeEffigy() throws IllegalActionException { 131 // Need an effigy and a tableau so that menu ops work properly. 132 Effigy containerEffigy = Configuration 133 .findEffigy(_plotterBase.toplevel()); 134 135 if (containerEffigy == null) { 136 try { 137 containerEffigy = new PlotEffigy(_plotterBase.workspace()); 138 //containerEffigy.setModel(_plotterBase.toplevel()); 139 } catch (Exception ex) { 140 throw new IllegalActionException(_plotterBase, ex, 141 "Cannot find effigy for top level: " 142 + _plotterBase.toplevel().getFullName()); 143 } 144 } 145 146 try { 147 PlotEffigy plotEffigy; 148 // In PN models, there could be multiple of these running 149 // at the same time, in which case we may get a name collision. 150 // To prevent this, synchronize on the effigy. 151 synchronized (containerEffigy) { 152 plotEffigy = new PlotEffigy(containerEffigy, 153 containerEffigy.uniqueName("plot")); 154 } 155 // Specify that the associated plot is the one created here. 156 plotEffigy.setPlot(_plotterBase.plot); 157 // Specify that the associated Ptolemy model is this actor. 158 plotEffigy.setModel(_plotterBase); 159 160 // The default identifier is "Unnamed", which is no good for 161 // two reasons: Wrong title bar label, and it causes a save-as 162 // to destroy the original window. 163 plotEffigy.identifier.setExpression(_plotterBase.getFullName()); 164 165 _tableau = new PlotWindowTableau(plotEffigy, "tableau"); 166 167 setFrame(_tableau.frame); 168 } catch (Exception ex) { 169 throw new IllegalActionException(_plotterBase, null, ex, 170 "Error creating effigy and tableau"); 171 } 172 } 173 174 /** 175 * Initialize the effigy of the plotter. 176 * @exception IllegalActionException If there is a problem initializing the effigy 177 */ 178 @Override 179 public void initWindowAndSizeProperties() 180 throws IllegalActionException, NameDuplicationException { 181 _windowProperties = (WindowPropertiesAttribute) _plotterBase 182 .getAttribute("_windowProperties", 183 WindowPropertiesAttribute.class); 184 if (_windowProperties == null) { 185 _windowProperties = new WindowPropertiesAttribute(_plotterBase, 186 "_windowProperties"); 187 // Note that we have to force this to be persistent because 188 // there is no real mechanism for the value of the properties 189 // to be updated when the window is moved or resized. By 190 // making it persistent, when the model is saved, the 191 // attribute will determine the current size and position 192 // of the window and save it. 193 _windowProperties.setPersistent(true); 194 } 195 _plotSize = (SizeAttribute) _plotterBase.getAttribute("_plotSize", 196 SizeAttribute.class); 197 if (_plotSize == null) { 198 _plotSize = new SizeAttribute(_plotterBase, "_plotSize"); 199 _plotSize.setPersistent(true); 200 } 201 } 202 203 /** 204 * Create a new instance of the PlotBoxInterface implementation. 205 * @return a new instance of the PlotBoxInterface implementation. 206 */ 207 @Override 208 public PlotBoxInterface newPlot() { 209 return new Plot(); 210 } 211 212 /** 213 * Remove the plot from the current container, if there is one. 214 */ 215 @Override 216 public void remove() { 217 SwingUtilities.invokeLater(new Runnable() { 218 @Override 219 public void run() { 220 if (_plotterBase.plot != null) { 221 if (_container != null) { 222 _container.remove((Component) _plotterBase.plot); 223 _container.invalidate(); 224 _container.repaint(); 225 } else if (_frame != null) { 226 _frame.dispose(); 227 } 228 } 229 } 230 }); 231 } 232 233 /** 234 * Remove the plot from the frame if the container is null. 235 */ 236 @Override 237 public void removeNullContainer() { 238 // NOTE: This actor always shows the plot buttons, even if 239 // the plot is in a separate frame. They are very useful. 240 if (_container == null) { 241 // Dissociate with any container. 242 // NOTE: _remove() doesn't work here. Why? 243 if (_frame != null) { 244 _frame.dispose(); 245 } 246 247 _frame = null; 248 249 // If we forget the plot, then its properties get lost. 250 // Also, if the window is deleted during a run, the data 251 // will be lost. So do not forget the plot. 252 // plot = null; 253 return; 254 } 255 } 256 257 /** 258 * Set the frame of the plotter. 259 * @param frame The frame to set. 260 * @see #getFrame() 261 */ 262 @Override 263 public void setFrame(Object frame) { 264 if (_frame != null) { 265 _frame.removeWindowListener(_windowClosingAdapter); 266 } 267 268 if (frame == null) { 269 _frame = null; 270 return; 271 } 272 273 _frame = (PlotTableauFrame) frame; 274 275 _windowClosingAdapter = new WindowClosingAdapter(); 276 _frame.addWindowListener(_windowClosingAdapter); 277 278 _windowProperties.setProperties(_frame); 279 } 280 281 /** 282 * Set the platform dependent container of the plotter. 283 * The container can be AWT container or Android view. 284 * @param container the platform dependent container. 285 * @see #getPlatformContainer() 286 */ 287 @Override 288 public void setPlatformContainer(Object container) { 289 _container = (Container) container; 290 } 291 292 /** 293 * Set the title of the tableau. 294 * @param title the title to set. 295 */ 296 @Override 297 public void setTableauTitle(String title) { 298 if (_tableau != null) { 299 _tableau.setTitle(title); 300 } 301 } 302 303 /** 304 * Update size attribute of the plotter. 305 */ 306 @Override 307 public void updateSize() { 308 if (_plotSize != null) { 309 _plotSize.setSize((Component) _plotterBase.plot); 310 } 311 312 if (_frame != null) { 313 _frame.pack(); 314 } 315 } 316 317 /** 318 * Update values of the attributes. 319 */ 320 @Override 321 public void updateWindowAndSizeAttributes() { 322 if (_frame != null) { 323 _windowProperties.recordProperties(_frame); 324 } 325 326 if (_plotterBase.plot != null) { 327 _plotSize.recordSize((Component) _plotterBase.plot); 328 } 329 } 330 331 /////////////////////////////////////////////////////////////////// 332 //// protected variables //// 333 /** Container into which this plot should be placed. */ 334 protected Container _container; 335 336 /** Frame into which plot is placed, if any. */ 337 protected transient PlotTableauFrame _frame; 338 339 /** An attribute that contains the size of the plot. */ 340 protected SizeAttribute _plotSize; 341 342 /** The base instance that created the implementation. */ 343 protected PlotterBase _plotterBase; 344 345 /** The Plotter tableau. */ 346 protected PlotWindowTableau _tableau; 347 348 /** A reference to the listener for removal purposes. */ 349 protected WindowClosingAdapter _windowClosingAdapter; 350 351 /** An attribute tha contains the size and position of the window. */ 352 protected WindowPropertiesAttribute _windowProperties; 353 354 /////////////////////////////////////////////////////////////////// 355 //// inner classes //// 356 357 /** Tableau that creates a PlotterPlotFrame. 358 */ 359 protected class PlotWindowTableau extends PlotTableau { 360 /** Construct a new tableau for the model represented by the 361 * given effigy. 362 * @param container The container. 363 * @param name The name. 364 * @exception IllegalActionException If the container does not accept 365 * this entity (this should not occur). 366 * @exception NameDuplicationException If the name coincides with an 367 * attribute already in the container. 368 */ 369 public PlotWindowTableau(PlotEffigy container, String name) 370 throws IllegalActionException, NameDuplicationException { 371 super(container, name); 372 frame = new PlotTableauFrame(this, (PlotBox) _plotterBase.plot, 373 _plotterBase); 374 setFrame(frame); 375 } 376 377 /** The frame. */ 378 public PlotTableauFrame frame; 379 } 380 381 /** Listener for windowClosing action. */ 382 class WindowClosingAdapter extends WindowAdapter { 383 @Override 384 public void windowClosing(WindowEvent e) { 385 _plotterBase.cleanUp(); 386 } 387 } 388}