001/* An action to toggle displaying all port names.
002 * 
003 * Copyright (c) 2011 The Regents of the University of California.
004 * All rights reserved.
005 *
006 * '$Author: crawl $'
007 * '$Date: 2011-10-04 21:11:45 +0000 (Tue, 04 Oct 2011) $' 
008 * '$Revision: 28755 $'
009 * 
010 * Permission is hereby granted, without written agreement and without
011 * license or royalty fees, to use, copy, modify, and distribute this
012 * software and its documentation for any purpose, provided that the above
013 * copyright notice and the following two paragraphs appear in all copies
014 * of this software.
015 *
016 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
017 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
018 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
019 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
020 * SUCH DAMAGE.
021 *
022 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
023 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
024 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
025 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
026 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
027 * ENHANCEMENTS, OR MODIFICATIONS.
028 *
029 */
030
031package org.kepler.gui;
032
033import java.awt.event.ActionEvent;
034import java.util.Collections;
035import java.util.List;
036import java.util.Map;
037import java.util.WeakHashMap;
038
039import ptolemy.actor.gui.PtolemyFrame;
040import ptolemy.actor.gui.TableauFrame;
041import ptolemy.data.BooleanToken;
042import ptolemy.data.Token;
043import ptolemy.data.expr.Parameter;
044import ptolemy.kernel.CompositeEntity;
045import ptolemy.kernel.Entity;
046import ptolemy.kernel.Port;
047import ptolemy.kernel.util.Attribute;
048import ptolemy.kernel.util.IllegalActionException;
049import ptolemy.kernel.util.NamedObj;
050import ptolemy.moml.MoMLChangeRequest;
051import ptolemy.util.MessageHandler;
052import ptolemy.vergil.toolbox.FigureAction;
053
054/** An action to toggle displaying all port names.
055 * 
056 * @author Daniel Crawl
057 * @version $Id: ToggleAllPortNamesAction.java 28755 2011-10-04 21:11:45Z crawl $
058 *
059 */
060
061public class ToggleAllPortNamesAction extends FigureAction {
062
063    public ToggleAllPortNamesAction(TableauFrame frame) {
064        super("");
065        _parent = frame;
066    }
067
068    public void actionPerformed(ActionEvent event) {
069        super.actionPerformed(event);
070                
071        NamedObj model = ((PtolemyFrame)_parent).getModel().toplevel();
072     
073        // see if we've already toggled for this model
074        Boolean showNames = _modelMap.get(model);
075        if(showNames == null)
076        {
077            showNames = Boolean.TRUE;
078        }
079        
080        // toggle the names
081        _togglePortNames((Entity)model, showNames.booleanValue());
082        
083        // add this model to the map
084        _modelMap.put(model, !showNames.booleanValue());
085        
086        // perform an empty change request to repaint the canvas
087        MoMLChangeRequest change = new MoMLChangeRequest(model, model, "<group></group>");
088        change.setPersistent(true);
089        model.requestChange(change);
090    }
091    
092    /** Toggle the port names for an entity and any contained entities. */
093    private void _togglePortNames(Entity entity, boolean showNames)
094    {
095        List<?> portList = entity.portList();
096        for(Object obj : portList)
097        {
098            final Port port = (Port)obj;
099            final boolean isSet = _isPropertySet(port, "_showName");
100            final boolean isHidden = _isPropertySet(port, "_hide"); 
101            
102            if(showNames && !isSet && !isHidden)
103            {
104                try {
105                    new Parameter(port, "_showName", BooleanToken.TRUE);
106                } catch (Exception e) {
107                    MessageHandler.error("Unable to show port name for " +
108                        port.getFullName(), e);
109                }
110            }
111            else if(!showNames && isSet)
112            {
113                try {
114                    port.getAttribute("_showName").setContainer(null);
115                } catch (Exception e) {
116                    MessageHandler.error("Unable to remove _showName for " +
117                        port.getFullName(), e);
118                }
119            }
120        }
121        
122        // recursively toggle port names of contained entities
123        if(entity instanceof CompositeEntity)
124        {
125            List<?> entityList = ((CompositeEntity)entity).entityList();
126            for(Object entityObj : entityList)
127            {
128                _togglePortNames((Entity)entityObj, showNames);
129            }
130        }
131    }
132    
133    /** Return true if the property of the specified name is set for
134     *  the specified object. A property is specified if the specified
135     *  object contains an attribute with the specified name and that
136     *  attribute is either not a boolean-valued parameter, or it is a
137     *  boolean-valued parameter with value true.
138     *  FIXME copied from PortConfigurerDialog
139     *  @param object The object.
140     *  @param name The property name.
141     *  @return True if the property is set.
142     */
143    private boolean _isPropertySet(NamedObj object, String name) {
144        Attribute attribute = object.getAttribute(name);
145
146        if (attribute == null) {
147            return false;
148        }
149
150        if (attribute instanceof Parameter) {
151            try {
152                Token token = ((Parameter) attribute).getToken();
153
154                if (token instanceof BooleanToken) {
155                    if (!((BooleanToken) token).booleanValue()) {
156                        return false;
157                    }
158                }
159            } catch (IllegalActionException e) {
160                // Ignore, using default of true.
161            }
162        }
163
164        return true;
165    }
166
167    /** The parent frame. */
168    private TableauFrame _parent;
169    
170    /** A mapping from model to current toggle value. Each model will be toggled
171     *  independently. 
172     */
173    private static Map<NamedObj,Boolean> _modelMap =
174        Collections.synchronizedMap(new WeakHashMap<NamedObj,Boolean>());
175}