001/* An attribute for instance-specific documentation.
002
003 Copyright (c) 2006-2015 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.basic;
029
030import java.util.Iterator;
031import java.util.LinkedList;
032import java.util.List;
033
034import ptolemy.actor.gui.style.TextStyle;
035import ptolemy.actor.parameters.ParameterPort;
036import ptolemy.actor.parameters.PortParameter;
037import ptolemy.data.BooleanToken;
038import ptolemy.data.expr.SingletonParameter;
039import ptolemy.kernel.Entity;
040import ptolemy.kernel.Port;
041import ptolemy.kernel.util.Attribute;
042import ptolemy.kernel.util.IllegalActionException;
043import ptolemy.kernel.util.InternalErrorException;
044import ptolemy.kernel.util.KernelException;
045import ptolemy.kernel.util.NameDuplicationException;
046import ptolemy.kernel.util.NamedObj;
047import ptolemy.kernel.util.Settable;
048import ptolemy.kernel.util.SingletonAttribute;
049import ptolemy.kernel.util.StringAttribute;
050import ptolemy.kernel.util.Workspace;
051
052///////////////////////////////////////////////////////////////////
053//// DocAttribute
054
055/**
056 An attribute containing documentation for a Ptolemy II object.
057
058 @author Edward A. Lee
059 @version $Id$
060 @since Ptolemy II 5.2
061 @Pt.ProposedRating Red (eal)
062 @Pt.AcceptedRating Red (cxh)
063 */
064public class DocAttribute extends SingletonAttribute {
065
066    /** Construct a documentation attribute with the given name contained
067     *  by the specified entity. The container argument must not be null, or a
068     *  NullPointerException will be thrown.  This attribute will use the
069     *  workspace of the container for synchronization and version counts.
070     *  If the name argument is null, then the name is set to the empty string.
071     *  Increment the version of the workspace.
072     *  @param container The container.
073     *  @param name The name of this attribute.
074     *  @exception IllegalActionException If the attribute is not of an
075     *   acceptable class for the container, or if the name contains a period.
076     *  @exception NameDuplicationException If the name coincides with
077     *   an attribute already in the container.
078     */
079    public DocAttribute(NamedObj container, String name)
080            throws IllegalActionException, NameDuplicationException {
081        super(container, name);
082
083        description = new StringAttribute(this, "description");
084        TextStyle style = new TextStyle(description, "_style");
085        style.height.setExpression("10");
086        style.width.setExpression("70");
087
088        author = new StringAttribute(this, "author");
089        version = new StringAttribute(this, "version");
090        since = new StringAttribute(this, "since");
091
092        refreshParametersAndPorts();
093
094        // Hide the name, if this gets instantiated in Vergil.
095        SingletonParameter hide = new SingletonParameter(this, "_hideName");
096        hide.setToken(BooleanToken.TRUE);
097        hide.setVisibility(Settable.EXPERT);
098    }
099
100    /**
101     * Construct an empty DocAttribute.
102     */
103    public DocAttribute() {
104        super();
105    }
106
107    /**
108     * Construct a DocAttribute in a given workspace.
109     * @param workspace The workspace in which to construct the DocAttribute.
110     */
111    public DocAttribute(Workspace workspace) {
112        super(workspace);
113    }
114
115    ///////////////////////////////////////////////////////////////////
116    ////                         parameters                        ////
117
118    /** The author field. */
119    public StringAttribute author;
120
121    /** The description. */
122    public StringAttribute description;
123
124    /** The since field. */
125    public StringAttribute since;
126
127    /** The version field. */
128    public StringAttribute version;
129
130    ///////////////////////////////////////////////////////////////////
131    ////                         public methods                    ////
132
133    /** Return the documentation for the given parameter, or null if there
134     *  none.
135     *  @param name The name of the parameter.
136     *  @return The documentation for the given parameter, or null if there
137     *   is none.
138     */
139    public String getParameterDoc(String name) {
140        Attribute parameterAttribute = getAttribute(name + " (parameter)");
141        if (parameterAttribute instanceof Settable) {
142            return ((Settable) parameterAttribute).getExpression();
143        }
144        // Might be a port-parameter.  Try that.
145        parameterAttribute = getAttribute(name + " (port-parameter)");
146        if (parameterAttribute instanceof Settable) {
147            return ((Settable) parameterAttribute).getExpression();
148        }
149        // Might be a port-parameter misidentified as a port. Try that.
150        parameterAttribute = getAttribute(name + " (port)");
151        if (parameterAttribute instanceof Settable) {
152            return ((Settable) parameterAttribute).getExpression();
153        }
154        return null;
155    }
156
157    /** Return the documentation for the given port, or null if there
158     *  none.
159     *  @param name The name of the port.
160     *  @return The documentation for the given port, or null if there
161     *   is none.
162     */
163    public String getPortDoc(String name) {
164        StringAttribute portAttribute = (StringAttribute) getAttribute(
165                name + " (port)");
166        if (portAttribute != null) {
167            return portAttribute.getExpression();
168        }
169        return null;
170    }
171
172    /** For each parameter and port in the container, create a
173     *  parameter with the same name appended with either " (port)",
174     *  " (port-parameter)",
175     *  or " (parameter)".  For parameters, only those that are
176     *  settable are shown, and only if the visibility is "FULL".
177     *  This method also removes any parameters that have no
178     *  corresponding parameter or port in the container.
179     *  Since this method modifies the model by adding or
180     *  removing parameters to this attribute, it should be
181     *  called from inside a change request.
182     */
183    public void refreshParametersAndPorts() {
184        NamedObj container = getContainer();
185
186        // Remove any parameters that are no longer relevant.
187        // Operate on a copy of the attribute list to avoid
188        // ConcurrentModificationException.
189        List copy = new LinkedList(attributeList());
190        Iterator parameters = copy.iterator();
191        while (parameters.hasNext()) {
192            Attribute attribute = (Attribute) parameters.next();
193            String name = attribute.getName();
194            int n = name.indexOf(" (parameter)");
195            if (n >= 0) {
196                // Attribute is a parameter.
197                name = name.substring(0, n);
198                if (container.getAttribute(name) == null) {
199                    // Entry is obsolete.  Delete it.
200                    try {
201                        attribute.setContainer(null);
202                    } catch (KernelException ex) {
203                        // Should not occur.
204                        throw new InternalErrorException(ex);
205                    }
206                }
207            } else {
208                n = name.indexOf(" (port-parameter)");
209                if (n >= 0) {
210                    // Attribute is a port parameter.
211                    name = name.substring(0, n);
212                    if (!(container instanceof Entity)
213                            || ((Entity) container).getPort(name) == null) {
214                        // Entry is obsolete.  Delete it.
215                        try {
216                            attribute.setContainer(null);
217                        } catch (KernelException ex) {
218                            // Should not occur.
219                            throw new InternalErrorException(ex);
220                        }
221                    }
222                } else {
223                    n = name.indexOf(" (port)");
224                    if (n >= 0) {
225                        // Attribute is a port parameter.
226                        name = name.substring(0, n);
227                        if (!(container instanceof Entity)
228                                || ((Entity) container).getPort(name) == null) {
229                            // Entry is obsolete.  Delete it.
230                            try {
231                                attribute.setContainer(null);
232                            } catch (KernelException ex) {
233                                // Should not occur.
234                                throw new InternalErrorException(ex);
235                            }
236                        }
237                    }
238                }
239            }
240        }
241
242        parameters = container.attributeList(Settable.class).iterator();
243        while (parameters.hasNext()) {
244            NamedObj attribute = (NamedObj) parameters.next();
245            if (((Settable) attribute).getVisibility() == Settable.FULL) {
246                String modifier = " (parameter)";
247                if (attribute instanceof PortParameter) {
248                    modifier = " (port-parameter)";
249                }
250                String name = attribute.getName() + modifier;
251                if (getAttribute(name) == null) {
252                    try {
253                        // NOTE: Using a StringParameter here is a really poor choice.
254                        // It will try to parse anything with a dollar sign.
255                        // new StringParameter(this, name);
256                        new StringAttribute(this, name);
257                    } catch (KernelException e) {
258                        throw new InternalErrorException(e);
259                    }
260                }
261            }
262        }
263
264        if (container instanceof Entity) {
265            Iterator ports = ((Entity) container).portList().iterator();
266            while (ports.hasNext()) {
267                Port port = (Port) ports.next();
268                if (port instanceof ParameterPort) {
269                    // Skip this one.
270                    continue;
271                }
272                String name = port.getName() + " (port)";
273                if (getAttribute(name) == null) {
274                    try {
275                        new StringAttribute(this, name);
276                    } catch (KernelException e) {
277                        throw new InternalErrorException(e);
278                    }
279                }
280            }
281        }
282    }
283}