001/* A GUI widget for renaming an object.
002
003 Copyright (c) 1998-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.actor.gui;
029
030import javax.swing.BoxLayout;
031
032import ptolemy.data.BooleanToken;
033import ptolemy.data.Token;
034import ptolemy.data.expr.Parameter;
035import ptolemy.gui.Query;
036import ptolemy.gui.QueryListener;
037import ptolemy.kernel.Port;
038import ptolemy.kernel.util.AbstractSettableAttribute;
039import ptolemy.kernel.util.Attribute;
040import ptolemy.kernel.util.ChangeListener;
041import ptolemy.kernel.util.ChangeRequest;
042import ptolemy.kernel.util.IllegalActionException;
043import ptolemy.kernel.util.NamedObj;
044import ptolemy.moml.MoMLChangeRequest;
045import ptolemy.util.MessageHandler;
046import ptolemy.util.StringUtilities;
047
048///////////////////////////////////////////////////////////////////
049//// RenameConfigurer
050
051/**
052 This class is an editor widget to rename an object.
053
054 @see Configurer
055 @author Edward A. Lee
056 @version $Id$
057 @since Ptolemy II 1.0
058 @Pt.ProposedRating Yellow (eal)
059 @Pt.AcceptedRating Red (neuendor)
060 */
061@SuppressWarnings("serial")
062public class RenameConfigurer extends Query
063        implements ChangeListener, QueryListener {
064    /** Construct a rename configurer for the specified entity.
065     *  @param object The entity to configure.
066     */
067    public RenameConfigurer(NamedObj object) {
068        super();
069        this.addQueryListener(this);
070        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
071        setTextWidth(25);
072        _object = object;
073        addLine(_NAME_LABEL, _NAME_LABEL, object.getName());
074        addTextArea(_DISPLAY_NAME_LABEL, _DISPLAY_NAME_LABEL,
075                object.getDisplayName());
076
077        // By default, names are not shown for ports, and are shown
078        // for everything else.  Note that ports are a little confusing,
079        // because names are _always_ shown for external ports inside
080        // a composite actor.  This dialog determines whether they will
081        // be shown on the outside of the composite actor.
082        boolean nameShowing = false;
083
084        if (object instanceof Port) {
085            nameShowing = _isPropertySet(_object, "_showName");
086        } else {
087            nameShowing = !_isPropertySet(_object, "_hideName");
088        }
089
090        // Don't include the Show name check box for
091        // AbstractSettableAttributes We choose
092        // AbstractSettableAttribute because we don't want the
093        // "Show name" check box for RequireVersion, which eventually
094        // extends AbstractSettableAttribute, but we do want the
095        // "Show name" check box for Director, which extends Attribute.
096        // See
097        // http://bugzilla.ecoinformatics.org/show_bug.cgi?id=3363
098        if (!(object instanceof AbstractSettableAttribute)) {
099            addCheckBox("Show name", "Show name", nameShowing);
100        }
101    }
102
103    ///////////////////////////////////////////////////////////////////
104    ////                         public methods                    ////
105
106    /** Apply the changes by renaming the object.
107     */
108    public void apply() {
109        if (_changed) {
110            String newName = StringUtilities
111                    .escapeForXML(getStringValue(_NAME_LABEL));
112            String displayName = StringUtilities
113                    .escapeForXML(getStringValue(_DISPLAY_NAME_LABEL));
114
115            NamedObj parent = _object.getContainer();
116            if (parent == null) {
117                // Hitting F2 in an empty model and renaming the canvas can result in a NPE.
118                // See https://chess.eecs.berkeley.edu/bugzilla/show_bug.cgi?id=355
119                MessageHandler.message(
120                        "Please save the model before changing the name.");
121                return;
122            }
123            String oldName = StringUtilities.escapeForXML(_object.getName());
124            String oldDisplayName = StringUtilities
125                    .escapeForXML(_object.getDisplayName());
126
127            StringBuffer moml = new StringBuffer("<");
128            String elementName = _object.getElementName();
129            moml.append(elementName);
130            moml.append(" name=\"");
131            moml.append(oldName);
132            moml.append("\">");
133            if (!oldName.equals(newName)) {
134                moml.append("<rename name=\"");
135                moml.append(newName);
136                moml.append("\"/>");
137            }
138            if (!oldDisplayName.equals(displayName)) {
139                moml.append("<display name=\"");
140                moml.append(displayName);
141                moml.append("\"/>");
142            }
143
144            // Don't include the Show name check box for AbstractSettableAttributes
145            // http://bugzilla.ecoinformatics.org/show_bug.cgi?id=3363
146            if (!(_object instanceof AbstractSettableAttribute)) {
147                // Remove or show name.
148                boolean showName = getBooleanValue("Show name");
149
150                if (_object instanceof Port) {
151                    boolean previousShowName = _isPropertySet(_object,
152                            "_showName");
153
154                    if (showName != previousShowName) {
155                        if (showName) {
156                            moml.append("<property name=\"_showName\" "
157                                    + "class=\"ptolemy.data.expr.SingletonParameter\""
158                                    + " value=\"true\"/>");
159                        } else {
160                            if (!(_object.getAttribute(
161                                    "_showName") instanceof Parameter)) {
162                                moml.append(
163                                        "<deleteProperty name=\"_showName\"/>");
164                            } else {
165                                moml.append("<property name=\"_showName\" "
166                                        + "class=\"ptolemy.data.expr.SingletonParameter\""
167                                        + " value=\"false\"/>");
168                            }
169                        }
170                    }
171                } else {
172                    boolean previousShowName = !_isPropertySet(_object,
173                            "_hideName");
174
175                    if (showName != previousShowName) {
176                        if (showName) {
177                            if (!(_object.getAttribute(
178                                    "_hideName") instanceof Parameter)) {
179                                moml.append(
180                                        "<deleteProperty name=\"_hideName\"/>");
181                            } else {
182                                moml.append("<property name=\"_hideName\" "
183                                        + "class=\"ptolemy.data.expr.SingletonParameter\""
184                                        + " value=\"false\"/>");
185                            }
186                        } else {
187                            moml.append("<property name=\"_hideName\" "
188                                    + "class=\"ptolemy.data.expr.SingletonParameter\""
189                                    + " value=\"true\"/>");
190                        }
191                    }
192                }
193            }
194
195            moml.append("</");
196            moml.append(elementName);
197            moml.append(">");
198
199            MoMLChangeRequest request = new MoMLChangeRequest(this, // originator
200                    parent, // context
201                    moml.toString(), // MoML code
202                    null); // base
203
204            request.addChangeListener(this);
205            request.setUndoable(true);
206            parent.requestChange(request);
207        }
208    }
209
210    /** React to the fact that the change has been successfully executed
211     *  by doing nothing.
212     *  @param change The change that has been executed.
213     */
214    @Override
215    public void changeExecuted(ChangeRequest change) {
216        // Nothing to do.
217    }
218
219    /** React to the fact that the change has failed by reporting it.
220     *  @param change The change that was attempted.
221     *  @param exception The exception that resulted.
222     */
223    @Override
224    public void changeFailed(ChangeRequest change, Exception exception) {
225        // Ignore if this is not the originator.
226        if (change != null && change.getSource() != this) {
227            return;
228        }
229
230        if (change != null && !change.isErrorReported()) {
231            change.setErrorReported(true);
232            MessageHandler.error("Rename failed: ", exception);
233        }
234    }
235
236    /** Called to notify that one of the entries has changed.
237     *  This simply sets a flag that enables application of the change
238     *  when the apply() method is called.
239     *  @param name The name of the entry that changed.
240     */
241    @Override
242    public void changed(String name) {
243        _changed = true;
244    }
245
246    /**
247     * Get the object upon which this RenameConfigurer is operating.
248     * @return The object.
249     */
250    public NamedObj getObject() {
251        // This method makes it possible to determine which object is being
252        // renamed.  This is especially useful when dealing with the
253        // MoMLChangeRequest generated by this class from other classes.
254        return _object;
255    }
256
257    ///////////////////////////////////////////////////////////////////
258    ////                         private methods                   ////
259
260    /** Return true if the property of the specified name is set for
261     *  the specified object. A property is specified if the specified
262     *  object contains an attribute with the specified name and that
263     *  attribute is either not a boolean-valued parameter, or it is
264     *  a boolean-valued parameter with value true.
265     *  @param object The object.
266     *  @param name The property name.
267     *  @return True if the property is set.
268     */
269    private boolean _isPropertySet(NamedObj object, String name) {
270        Attribute attribute = object.getAttribute(name);
271
272        if (attribute == null) {
273            return false;
274        }
275
276        if (attribute instanceof Parameter) {
277            try {
278                Token token = ((Parameter) attribute).getToken();
279
280                if (token instanceof BooleanToken) {
281                    if (!((BooleanToken) token).booleanValue()) {
282                        return false;
283                    }
284                }
285            } catch (IllegalActionException e) {
286                // Ignore, using default of true.
287            }
288        }
289
290        return true;
291    }
292
293    ///////////////////////////////////////////////////////////////////
294    ////                         private variables                 ////
295    // Indicator that the name has changed.
296    private boolean _changed = false;
297
298    // The object that this configurer configures.
299    private NamedObj _object;
300
301    private static String _NAME_LABEL = "Name";
302    private static String _DISPLAY_NAME_LABEL = "Display name";
303}