001/* An object that can create a tableau for a model.
002
003 Copyright (c) 1997-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
027
028 */
029package ptolemy.actor.gui;
030
031import java.net.URL;
032import java.util.Iterator;
033
034import javax.swing.SwingUtilities;
035
036import ptolemy.kernel.util.Attribute;
037import ptolemy.kernel.util.Configurable;
038import ptolemy.kernel.util.IllegalActionException;
039import ptolemy.kernel.util.NameDuplicationException;
040import ptolemy.kernel.util.NamedObj;
041import ptolemy.moml.MoMLChangeRequest;
042
043///////////////////////////////////////////////////////////////////
044//// TableauFactory
045
046/**
047 This class is an attribute that creates a tableau to view a specified effigy.
048 When a model is opened, if the top-level of that model contains this
049 attribute or a subclass, then that attribute handles constructing a tableau.
050 Otherwise, the configuration specifies which tableau is used.
051 A configuration contains an instance of this class, and uses it to create
052 a tableau for a model represented by an effigy.  This base class assumes
053 that it contains other tableau factories. Its createTableau() method defers
054 to each contained factory, in the order in which they were added,
055 until one is capable of creating a tableau for the specified effigy.
056 Subclasses of this class will usually be inner classes of a Tableau,
057 and will create the Tableau, or might themselves be aggregates of
058 instances of TextEditorTableauFactory.
059 <p>
060 When there are multiple distinct TableauFactory classes that are capable
061 of providing views on the same effigy, then instances of these
062 factories should be aggregated into a single factory contained herein.
063 Those instances can be presented as alternative views of the data when
064 any single view is opened.
065 <p>
066 There is a significant subtlety with respect to how Ptolemy II classes
067 are dealt with. Normally, when one looks inside an instance of a class,
068 what is opened is the class definition, not the instance. However,
069 if the instance contains an instance of TableauFactory, then what
070 is opened is the instance, not the class definition.  This is used,
071 for example, when the look inside behavior is customized on a per
072 instance basis.
073
074 @author Steve Neuendorffer and Edward A. Lee
075 @version $Id$
076 @since Ptolemy II 1.0
077 @Pt.ProposedRating Green (eal)
078 @Pt.AcceptedRating Yellow (celaine)
079 @see Configuration
080 @see Effigy
081 @see Tableau
082 */
083public class TableauFactory extends Attribute implements Configurable {
084    /** Create a factory with the given name and container.
085     *  @param container The container.
086     *  @param name The name.
087     *  @exception IllegalActionException If the container is incompatible
088     *   with this attribute.
089     *  @exception NameDuplicationException If the name coincides with
090     *   an attribute already in the container.
091     */
092    public TableauFactory(NamedObj container, String name)
093            throws IllegalActionException, NameDuplicationException {
094        super(container, name);
095    }
096
097    ///////////////////////////////////////////////////////////////////
098    ////                         public methods                    ////
099
100    /** Create a tableau for the specified effigy. The tableau will be
101     *  created with a new unique name with the specified effigy as its
102     *  container.  If this factory cannot create a tableau
103     *  for the given effigy (perhaps because the effigy is not of the
104     *  appropriate subclass), then return null.  This base class assumes
105     *  that it contains other tableau factories. This method defers
106     *  to each contained factory in order until one is capable of creating a
107     *  tableau for the specified effigy.  As with all attributes, the order
108     *  is simply the order of creation.  Subclasses of this class will
109     *  usually be inner classes of a Tableau, and will create the Tableau.
110     *  A subclass that actually creates a tableau is responsible for setting
111     *  the container of the tableau to the specified effigy, and for naming
112     *  the tableau.
113     *  Subclasses should not call show() in createTableau(), it is the
114     *  responsibility of the caller to check the return value and
115     *  call show() after doing things like adjusting the size.
116     *  @param effigy The model effigy.
117     *  @return A tableau for the effigy, or null if one cannot be created.
118     *  @exception Exception If the factory should be able to create a
119     *   Tableau for the effigy, but something goes wrong.
120     */
121    public Tableau createTableau(Effigy effigy) throws Exception {
122        Tableau tableau = null;
123        Iterator factories = attributeList(TableauFactory.class).iterator();
124
125        while (factories.hasNext() && tableau == null) {
126            TableauFactory factory = (TableauFactory) factories.next();
127            tableau = factory.createTableau(effigy);
128            if (tableau != null) {
129                factory._configureTableau(tableau);
130            }
131        }
132
133        return tableau;
134    }
135
136    /** Configure the tableau factory with data from the specified input source
137     *  (a URL) and/or textual data.  The data is recorded locally without
138     *  parsing.
139     *  @param base The base relative to which references within the input
140     *   are found, or null if this is not known, or there is none.
141     *  @param source The input source, which specifies a URL, or null
142     *   if none.
143     *  @param text Configuration information given as text, or null if
144     *   none.
145     *  @exception Exception If something goes wrong. No thrown in this class.
146     */
147    @Override
148    public void configure(URL base, String source, String text)
149            throws Exception {
150        _configureSource = source;
151        _configureText = text;
152    }
153
154    /** Return the input source that was specified the last time the configure
155     *  method was called.
156     *  @return The string representation of the input URL, or null if the
157     *  no source has been used to configure this object, or null if no
158     *  external source need be used to configure this object.
159     */
160    @Override
161    public String getConfigureSource() {
162        return _configureSource;
163    }
164
165    /** Return the text string that represents the current configuration of
166     *  this object.  Note that any configuration that was previously
167     *  specified using the source attribute need not be represented here
168     *  as well.
169     *  @return A configuration string, or null if no configuration
170     *  has been used to configure this object, or null if no
171     *  configuration string need be used to configure this object.
172     */
173    @Override
174    public String getConfigureText() {
175        return _configureText;
176    }
177
178    /** Configure the given tableau with the configuration data attached to this
179     *  tableau factory, if any.
180     *
181     *  @param tableau The tableau to be configured.
182     */
183    protected void _configureTableau(final Tableau tableau) {
184        if (_configureText != null) {
185            SwingUtilities.invokeLater(new Runnable() {
186                @Override
187                public void run() {
188                    MoMLChangeRequest request = new MoMLChangeRequest(this,
189                            tableau, _configureText);
190                    tableau.requestChange(request);
191                }
192            });
193        }
194    }
195
196    /** The input source that was specified the last time the configure method
197     *  was called.
198     */
199    private String _configureSource;
200
201    /** The text string that represents the current configuration of this
202     *  object.
203     */
204    private String _configureText;
205}