001/* UnitAttribute used to specify either a Unit Expression or Unit Equations.
002
003 Copyright (c) 2003-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_3
025 COPYRIGHTENDKEY
026 */
027package ptolemy.moml.unit;
028
029import java.io.IOException;
030import java.io.Writer;
031import java.util.Collection;
032import java.util.LinkedList;
033import java.util.List;
034import java.util.Vector;
035
036import ptolemy.kernel.util.AbstractSettableAttribute;
037import ptolemy.kernel.util.IllegalActionException;
038import ptolemy.kernel.util.NameDuplicationException;
039import ptolemy.kernel.util.NamedObj;
040import ptolemy.kernel.util.Settable;
041import ptolemy.kernel.util.ValueListener;
042import ptolemy.util.StringUtilities;
043
044///////////////////////////////////////////////////////////////////
045//// UnitAttribute
046
047/**
048 This class is used to implement the Unit Attribute. A
049 UnitsAttribute is either a UnitExpr, or a vector of
050 UnitConstraints.
051
052 @author Rowland R Johnson
053 @version $Id$
054 @since Ptolemy II 8.0
055 @Pt.ProposedRating Red (rowland)
056 @Pt.AcceptedRating Red (rowland)
057 */
058public class UnitAttribute extends AbstractSettableAttribute {
059    /** Construct a UnitsAttribute with no specific name, or container.
060     *  @exception IllegalActionException If the attribute is not of an
061     *  acceptable class for the container, or if the name contains a period.
062     *  @exception NameDuplicationException If the name coincides with
063     *  an attribute already in the container.
064     */
065    public UnitAttribute()
066            throws IllegalActionException, NameDuplicationException {
067        super();
068    }
069
070    /** Construct a UnitsAttribute with the specified name, and container.
071     * @param container Container
072     * @param name Name
073     * @exception IllegalActionException If the attribute is not of an
074     *  acceptable class for the container, or if the name contains a period.
075     *  @exception NameDuplicationException If the name coincides with
076     *  an attribute already in the container.
077     */
078    public UnitAttribute(NamedObj container, String name)
079            throws IllegalActionException, NameDuplicationException {
080        super(container, name);
081    }
082
083    ///////////////////////////////////////////////////////////////////
084    ////                         public methods                    ////
085
086    /** Add a listener to be notified when the value of this attribute changes.
087     *  If the listener is already on the list of listeners, then do nothing.
088     *  @param listener The listener to add.
089     */
090    @Override
091    public void addValueListener(ValueListener listener) {
092        if (_valueListeners == null) {
093            _valueListeners = new LinkedList();
094        }
095
096        if (!_valueListeners.contains(listener)) {
097            _valueListeners.add(listener);
098        }
099    }
100
101    /** Write a MoML description of the UnitsAttribute.  Nothing is
102     *  written if the value is null or "".
103     *  @param output The output stream to write to.
104     *  @param depth The depth in the hierarchy, to determine indenting.
105     *  @param name The name to use instead of the current name.
106     *  @exception IOException If an I/O error occurs.
107     *  @see ptolemy.kernel.util.NamedObj#exportMoML(Writer, int, String)
108     */
109    @Override
110    public void exportMoML(Writer output, int depth, String name)
111            throws IOException {
112        String value = getExpression();
113        String valueTerm = "";
114
115        if (value != null && !value.equals("")) {
116            valueTerm = " value=\"" + StringUtilities.escapeForXML(value)
117                    + "\"";
118
119            output.write(_getIndentPrefix(depth) + "<" + _elementName
120                    + " name=\"" + name + "\" class=\"" + getClassName() + "\""
121                    + valueTerm + ">\n");
122            _exportMoMLContents(output, depth + 1);
123            output.write(_getIndentPrefix(depth) + "</" + _elementName + ">\n");
124        }
125    }
126
127    /** Get the descriptive form of this attribute.
128     * @return a String that represents the descriptive form.
129     * @see ptolemy.kernel.util.Settable#getExpression()
130     */
131    @Override
132    public String getExpression() {
133        switch (_type) {
134        case _EXPRESSION: {
135            if (_unitExpr == null) {
136                return "";
137            }
138
139            return _unitExpr.descriptiveForm();
140        }
141
142        case _CONSTRAINTS: {
143            if (_unitConstraints == null) {
144                return "";
145            }
146
147            return getUnitConstraints().descriptiveForm();
148        }
149        }
150
151        return null;
152    }
153
154    /** Get the UnitConstraints.
155     * @return The UnitConstraints.
156     */
157    public UnitConstraints getUnitConstraints() {
158        return _unitConstraints;
159    }
160
161    /** Get the Unit Expression.
162     * @return The UnitExpr.
163     */
164    public UnitExpr getUnitExpr() {
165        return _unitExpr;
166    }
167
168    /** Get the visibility of this attribute, as set by setVisibility().
169     * The visibility is set by default to NONE.
170     * @return The visibility of this attribute.
171     * @see ptolemy.kernel.util.Settable#getVisibility()
172     */
173    @Override
174    public Visibility getVisibility() {
175        return _visibility;
176    }
177
178    /** Remove a listener from the list of listeners that is
179     *  notified when the value of this attribute changes.  If no such listener
180     *  exists, do nothing.
181     *  @param listener The listener to remove.
182     */
183    @Override
184    public void removeValueListener(ValueListener listener) {
185        if (_valueListeners != null) {
186            _valueListeners.remove(listener);
187        }
188    }
189
190    /** Set the expression. This method takes the descriptive form and
191     * determines the internal form (by parsing the descriptive form) and stores
192     * it.
193     * @param expression A String that is the descriptive form of either a Unit
194     * or a UnitEquation.
195     * @see ptolemy.kernel.util.Settable#setExpression(java.lang.String)
196     */
197    @Override
198    public void setExpression(String expression) throws IllegalActionException {
199        super.setExpression(expression);
200
201        try {
202            if (getName().equals("_unitConstraints")) {
203                Vector uEquations = UnitLibrary.getParser()
204                        .parseEquations(expression);
205                // Coverity: UParser.parseEquations() could return null.
206                if (uEquations != null) {
207                    UnitConstraints uConstraints = new UnitConstraints();
208
209                    for (int i = 0; i < uEquations.size(); i++) {
210                        uConstraints.addConstraint(
211                                (UnitEquation) uEquations.elementAt(i));
212                    }
213                    setUnitConstraints(uConstraints);
214                }
215            }
216
217            if (getName().equals("_units")) {
218                UnitExpr uExpr;
219                uExpr = UnitLibrary.getParser().parseUnitExpr(expression);
220                setUnitExpr(uExpr);
221            }
222        } catch (ParseException ex) {
223            throw new IllegalActionException(this, ex,
224                    "Can't parse the expression " + expression);
225        }
226    }
227
228    /** Set the UnitConstraints.
229     * @param constraints The UnitConstraints.
230     */
231    public void setUnitConstraints(UnitConstraints constraints) {
232        _unitConstraints = constraints;
233        _type = _CONSTRAINTS;
234    }
235
236    /** Set the Unit Expression.
237     * @param expr A UnitExpr.
238     */
239    public void setUnitExpr(UnitExpr expr) {
240        _unitExpr = expr;
241        _type = _EXPRESSION;
242    }
243
244    /** Set the visibility of this attribute.  The argument should be one
245     *  of the public static instances in Settable.
246     *  @param visibility The visibility of this attribute.
247     *  @see ptolemy.kernel.util.Settable#setVisibility(Settable.Visibility)
248     */
249    @Override
250    public void setVisibility(Visibility visibility) {
251        _visibility = visibility;
252    }
253
254    /* Not really relevant to current capability.
255     * But has to be included this class implements the Settable interface.
256     * @return Null, indicating that no other instances of Settable are
257     *   validated.
258     * @see ptolemy.kernel.util.Settable#validate()
259     */
260    @Override
261    public Collection validate() throws IllegalActionException {
262        return null;
263    }
264
265    ///////////////////////////////////////////////////////////////////
266    ////                         protected methods                 ////
267
268    /** Propagate the value of this object to the
269     *  specified object. The specified object is required
270     *  to be an instance of the same class as this one, or
271     *  a ClassCastException will be thrown.
272     *  @param destination Object to which to propagate the
273     *   value.
274     *  @exception IllegalActionException If the value cannot
275     *   be propagated.
276     */
277    @Override
278    protected void _propagateValue(NamedObj destination)
279            throws IllegalActionException {
280        ((Settable) destination).setExpression(getExpression());
281    }
282
283    ///////////////////////////////////////////////////////////////////
284    ////                         private variables                 ////
285    Visibility _visibility = Settable.NONE;
286
287    // Listeners for changes in value.
288    private List _valueListeners;
289
290    private UnitExpr _unitExpr = null;
291
292    private UnitConstraints _unitConstraints = null;
293
294    private int _type = -1;
295
296    private static final int _EXPRESSION = 0;
297
298    private static final int _CONSTRAINTS = 1;
299}