001/* Attribute that contains attributes that identify the containing model.
002
003 Copyright (c) 2004-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 */
028package ptolemy.vergil.kernel.attributes;
029
030import java.text.DateFormat;
031import java.util.Date;
032
033import ptolemy.data.BooleanToken;
034import ptolemy.data.expr.Parameter;
035import ptolemy.data.expr.SingletonParameter;
036import ptolemy.kernel.Entity;
037import ptolemy.kernel.InstantiableNamedObj;
038import ptolemy.kernel.attributes.URIAttribute;
039import ptolemy.kernel.util.Attribute;
040import ptolemy.kernel.util.IllegalActionException;
041import ptolemy.kernel.util.InternalErrorException;
042import ptolemy.kernel.util.NameDuplicationException;
043import ptolemy.kernel.util.Nameable;
044import ptolemy.kernel.util.Settable;
045import ptolemy.kernel.util.SingletonAttribute;
046import ptolemy.kernel.util.StringAttribute;
047import ptolemy.util.StringUtilities;
048import ptolemy.vergil.icon.BoxedValuesIcon;
049
050///////////////////////////////////////////////////////////////////
051//// IDAttribute
052
053/**
054 This attribute identifies the containing model, showing its name, base
055 class, last modified date, author, and contributors information.
056 Of these, only the contributors information is editable.
057 For the others, they are inferred from either the model itself or the
058 operations on the model.
059 Unfortunately, the changes will not be shown on the display until the
060 model is saved, closed and re-opened.
061 <p>
062 @author Edward A. Lee
063 @version $Id$
064 @since Ptolemy II 4.1
065 @Pt.ProposedRating Yellow (eal)
066 @Pt.AcceptedRating Red (cxh)
067 */
068public class IDAttribute extends SingletonAttribute {
069    /** Construct an attribute with the given name contained by the
070     *  specified container. The container argument must not be null, or a
071     *  NullPointerException will be thrown.  This attribute will use the
072     *  workspace of the container for synchronization and version counts.
073     *  If the name argument is null, then the name is set to the empty
074     *  string. Increment the version of the workspace.
075     *  @param container The container.
076     *  @param name The name of this attribute.
077     *  @exception IllegalActionException If the attribute is not of an
078     *   acceptable class for the container, or if the name contains a period.
079     *  @exception NameDuplicationException If the name coincides with
080     *   an attribute already in the container.
081     */
082    public IDAttribute(Entity container, String name)
083            throws IllegalActionException, NameDuplicationException {
084        super(container, name);
085
086        // name for the model
087        this.name = new StringAttribute(this, "name");
088        this.name.setExpression(container.getName());
089
090        // This should not be persistent, in case the name changes outside
091        // of this parameter.
092        this.name.setPersistent(false);
093
094        // This should not be editable, since the name is set by saveAs.
095        this.name.setVisibility(Settable.NOT_EDITABLE);
096
097        // FIXME: Need to listen for changes to the name.
098        // How to do that?
099        // The current design is also a solution in that the name of this
100        // attribute and model must be consistent with the name of the file.
101        // boolean isClass = false;
102        //if (container instanceof InstantiableNamedObj) {
103        /* isClass = */((InstantiableNamedObj) container).isClassDefinition();
104        //}
105
106        String className = container.getClassName();
107
108        baseClass = new StringAttribute(this, "baseClass");
109        baseClass.setExpression(className);
110
111        // This should not be persistent, because the base class
112        // is set already, generally.
113        baseClass.setPersistent(false);
114
115        // Cannot change the base class.
116        baseClass.setVisibility(Settable.NOT_EDITABLE);
117
118        URIAttribute modelURI = (URIAttribute) container.getAttribute("_uri",
119                URIAttribute.class);
120
121        if (modelURI != null) {
122            StringAttribute definedIn = new StringAttribute(this, "definedIn");
123            definedIn.setExpression(modelURI.getURI().toString());
124            definedIn.setPersistent(false);
125            definedIn.setVisibility(Settable.NOT_EDITABLE);
126        }
127
128        // The date when this model is created.
129        // Actually, it is the date when this attribute is created.
130        // We assume that when the model is created, this attribute
131        // is also created.
132        // We may force this to happen.:-) Further more, we may force
133        // that only the top level contains an model ID.
134        created = new StringAttribute(this, "created");
135        created.setExpression(
136                DateFormat.getDateTimeInstance().format(new Date()));
137        created.setVisibility(Settable.NOT_EDITABLE);
138        created.setPersistent(true);
139
140        // The date when this model is modified.
141        // Everytime the model gets modified, the updateContent method
142        // defined below is called and the lastUpdated attribute gets
143        // updated.
144        lastUpdated = new StringAttribute(this, "lastUpdated");
145        _updateDate();
146        lastUpdated.setVisibility(Settable.NOT_EDITABLE);
147        lastUpdated.setPersistent(true);
148
149        // The name of the author who creates the model.
150        // This attribute can not be changed so that the
151        // intellectual property (IP) is preserved.
152        author = new StringAttribute(this, "author");
153        author.setVisibility(Settable.NOT_EDITABLE);
154
155        String userName = null;
156
157        try {
158            userName = StringUtilities.getProperty("user.name");
159        } catch (Exception ex) {
160            System.out.println("Warning, in IDAttribute, failed to read "
161                    + "'user.name' property (-sandbox or applets always cause "
162                    + "this)");
163        }
164
165        if (userName != null) {
166            author.setExpression(userName);
167        }
168
169        author.setPersistent(true);
170
171        // The names of the contributors who modify the model.
172        contributors = new StringAttribute(this, "contributors");
173
174        String contributorsNames = "";
175        contributors.setExpression(contributorsNames);
176        author.setPersistent(true);
177
178        // Hide the name of this ID attribute.
179        SingletonParameter hide = new SingletonParameter(this, "_hideName");
180        hide.setToken(BooleanToken.TRUE);
181        hide.setVisibility(Settable.EXPERT);
182
183        BoxedValuesIcon icon = new BoxedValuesIcon(this, "_icon");
184        icon.setPersistent(false);
185
186        // No need to display any parameters when the "_showParameters"
187        // preference asks for such display because presumably all the
188        // parameters are reflected in the visual display already.
189        Parameter hideAllParameters = new Parameter(this, "_hideAllParameters");
190        hideAllParameters.setVisibility(Settable.EXPERT);
191        hideAllParameters.setExpression("true");
192    }
193
194    ///////////////////////////////////////////////////////////////////
195    ////                         attributes                        ////
196
197    /** The author of the model. */
198    public StringAttribute author;
199
200    /** The contributors of the model. */
201    public StringAttribute contributors;
202
203    /** The date that this model was created. */
204    public StringAttribute created;
205
206    /** The base class of the containing class or entity. */
207    public StringAttribute baseClass;
208
209    /** A boolean indicating whether the container is a class or an
210     *  instance.  This is a string that must have value "true" or
211     *  "false".
212     */
213    public StringAttribute isClass;
214
215    /** The date that this model was last updated. */
216    public StringAttribute lastUpdated;
217
218    /** The name of the containing class or entity. */
219    public StringAttribute name;
220
221    ///////////////////////////////////////////////////////////////////
222    ////                         public methods                    ////
223
224    /** React to a change in an attribute.  If the attribute is <i>name</i>,
225     *  then change the name of the container to match.
226     *  @param attribute The attribute that changed.
227     *  @exception IllegalActionException If the change is not acceptable
228     *   to this container (not thrown in this base class).
229     */
230    @Override
231    public void attributeChanged(Attribute attribute)
232            throws IllegalActionException {
233        if (attribute == name) {
234            Nameable container = getContainer();
235
236            try {
237                container.setName(name.getExpression());
238            } catch (NameDuplicationException e) {
239                throw new IllegalActionException(this, e,
240                        "Cannot change the name of the container to match.");
241            }
242        } else {
243            super.attributeChanged(attribute);
244        }
245    }
246
247    /** Update the modification date of this attribute.
248     */
249    @Override
250    public void updateContent() throws InternalErrorException {
251        super.updateContent();
252        _updateDate();
253    }
254
255    ///////////////////////////////////////////////////////////////////
256    ////                         private methods                   ////
257
258    /** Set the current date for the <i>lastUpdated</i> parameter.
259     */
260    private void _updateDate() {
261        try {
262            lastUpdated.setExpression(
263                    DateFormat.getDateTimeInstance().format(new Date()));
264        } catch (IllegalActionException e) {
265            throw new InternalErrorException(e);
266        }
267    }
268}