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}