001/* An icon that displays specified text. 002 003 Copyright (c) 2003-2016 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 027 */ 028package ptolemy.vergil.icon; 029 030import java.lang.ref.WeakReference; 031import java.util.Iterator; 032import java.util.LinkedList; 033import java.util.List; 034import java.util.ListIterator; 035import java.util.NoSuchElementException; 036 037import diva.canvas.Figure; 038import ptolemy.kernel.util.IllegalActionException; 039import ptolemy.kernel.util.NameDuplicationException; 040import ptolemy.kernel.util.NamedObj; 041import ptolemy.kernel.util.Workspace; 042 043/////////////////////////////////////////////////////////////////// 044//// DynamicEditorIcon 045 046/** 047 An icon that provides for the possibility that figures may be 048 dynamically updated. While some icons are generally 'static' and it 049 is simplest to regenerate new figures when their attributes change, 050 other icons are more 'dynamic'. For instance, some icons might 051 display live video or a live plot. This icon provides some basic 052 infrastructure for dealing with such cases. 053 054 The main difficulty is that, by design, an icon cannot keep track of 055 the figures it creates, otherwise there is a possibility for memory 056 leaks or inconsistencies in the case of multiple views. This class 057 solves the problem by using a WeakReferences to keep track of 058 generated figures. These references do not prevent objects from being 059 garbage collected. This class also provides a 'safe' iterator that 060 can be used to traverse the weak references without the normal 061 associated nastiness. 062 063 @author Steve Neuendorffer 064 @version $Id$ 065 @since Ptolemy II 4.0 066 @Pt.ProposedRating Yellow (eal) 067 @Pt.AcceptedRating Red (johnr) 068 */ 069public class DynamicEditorIcon extends EditorIcon { 070 /** Construct an icon in the specified workspace and name. 071 * This constructor is typically used in conjunction with 072 * setContainerToBe() and createFigure() to create an icon 073 * and generate a figure without having to have write access 074 * to the workspace. 075 * If the workspace argument is null, then use the default workspace. 076 * The object is added to the directory of the workspace. 077 * @see #setContainerToBe(NamedObj) 078 * Increment the version number of the workspace. 079 * @param workspace The workspace that will list the attribute. 080 * @param name The name of this attribute. 081 * @exception IllegalActionException If the specified name contains 082 * a period. 083 */ 084 public DynamicEditorIcon(Workspace workspace, String name) 085 throws IllegalActionException { 086 super(workspace, name); 087 } 088 089 /** Create a new icon with the given name in the given container. 090 * @param container The container. 091 * @param name The name of the attribute. 092 * @exception IllegalActionException If the attribute is not of an 093 * acceptable class for the container. 094 * @exception NameDuplicationException If the name coincides with 095 * an attribute already in the container. 096 */ 097 public DynamicEditorIcon(NamedObj container, String name) 098 throws IllegalActionException, NameDuplicationException { 099 super(container, name); 100 } 101 102 /////////////////////////////////////////////////////////////////// 103 //// public methods //// 104 105 /** Clone the object into the specified workspace. The new object is 106 * <i>not</i> added to the directory of that workspace (you must do this 107 * yourself if you want it there). 108 * The result is an object with no container. 109 * @param workspace The workspace for the cloned object. 110 * @exception CloneNotSupportedException Not thrown in this base class 111 * @return The new Attribute. 112 */ 113 @Override 114 public Object clone(Workspace workspace) throws CloneNotSupportedException { 115 DynamicEditorIcon newObject = (DynamicEditorIcon) super.clone( 116 workspace); 117 newObject._figures = new LinkedList(); 118 return newObject; 119 } 120 121 /** Add the figure to the list of figures managed by this icon. 122 * A WeakReference object will be created that points to the figure 123 * which will not prevent it from being garbage collected. 124 * This method should be called in the createBackgroundFigure method 125 * with the figure that will be returned. 126 * @param newFigure A newly manufactured figure. 127 */ 128 protected void _addLiveFigure(Figure newFigure) { 129 synchronized (_figures) { 130 _figures.add(new WeakReference(newFigure)); 131 } 132 133 _trimLiveFigures(); 134 } 135 136 /** Return a regular iterator over the figures created by this 137 * icon which have not been garbage collected. The objects 138 * returned by the iterator are Figures, not WeakReferences. 139 * Furthermore, the objects returned by this iterator are 140 * guaranteed to not be null. 141 * @return an iterator. 142 */ 143 protected Iterator _liveFigureIterator() { 144 final Iterator iterator = _figures.listIterator(); 145 return new Iterator() { 146 @Override 147 public boolean hasNext() { 148 // Pull the next valid element out of the list of 149 // WeakReferences. 150 while (_object == null && iterator.hasNext()) { 151 _object = ((WeakReference) iterator.next()).get(); 152 153 if (_object == null) { 154 iterator.remove(); 155 } 156 } 157 158 return _object != null; 159 } 160 161 @Override 162 public Object next() throws NoSuchElementException { 163 // Just to make sure that someone wasn't stupid 164 // and didn't call hasNext(); 165 while (_object == null && iterator.hasNext()) { 166 _object = ((WeakReference) iterator.next()).get(); 167 168 if (_object == null) { 169 iterator.remove(); 170 } 171 } 172 173 if (_object == null) { 174 throw new NoSuchElementException("The iterator is empty."); 175 } else { 176 Object object = _object; 177 _object = null; 178 return object; 179 } 180 } 181 182 @Override 183 public void remove() throws UnsupportedOperationException { 184 throw new UnsupportedOperationException( 185 "The remove() operation is unsupported."); 186 } 187 188 private Object _object; 189 }; 190 } 191 192 /** Trim the list of figures to discard entries that are no longer 193 * live. 194 */ 195 protected void _trimLiveFigures() { 196 ListIterator figures = _figures.listIterator(); 197 198 while (figures.hasNext()) { 199 Object figure = ((WeakReference) figures.next()).get(); 200 201 if (figure == null) { 202 // The figure has been garbage collected, so we 203 // remove it from the list. 204 figures.remove(); 205 } 206 } 207 } 208 209 /////////////////////////////////////////////////////////////////// 210 //// protected variables //// 211 212 /** A list of weak references to figures that this has created. */ 213 protected List _figures = new LinkedList(); 214}