001/* A GUI widget for configuring ports.
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 java.util.HashSet;
031import java.util.Iterator;
032import java.util.Locale;
033import java.util.Set;
034import java.util.StringTokenizer;
035
036import javax.swing.BoxLayout;
037
038import ptolemy.actor.TypedIOPort;
039import ptolemy.gui.Query;
040import ptolemy.gui.QueryListener;
041import ptolemy.kernel.Entity;
042import ptolemy.kernel.util.NamedObj;
043import ptolemy.kernel.util.StringAttribute;
044import ptolemy.moml.MoMLChangeRequest;
045import ptolemy.util.StringUtilities;
046
047///////////////////////////////////////////////////////////////////
048//// PortConfigurer
049
050/**
051 This class is an editor to configure the ports of an object.
052 It supports setting their input, output, and multiport properties,
053 and adding and removing ports.  Only ports that extend the TypedIOPort
054 class are listed, since more primitive ports cannot be configured
055 in this way.
056
057 @see Configurer
058 @author Steve Neuendorffer and Edward A. Lee
059 @version $Id$
060 @since Ptolemy II 1.0
061 @Pt.ProposedRating Yellow (eal)
062 @Pt.AcceptedRating Red (neuendor)
063 @deprecated This class is no longer used.  Use PortConfigurerDialog.
064 */
065@Deprecated
066@SuppressWarnings("serial")
067public class PortConfigurer extends Query implements QueryListener {
068    /** Construct a port configurer for the specified entity.
069     *  @param object The entity to configure.
070     */
071    public PortConfigurer(Entity object) {
072        super();
073        this.addQueryListener(this);
074        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
075
076        setTextWidth(15);
077
078        // The second column is for type designators.
079        setColumns(3);
080
081        _object = object;
082
083        Iterator ports = _object.portList().iterator();
084
085        while (ports.hasNext()) {
086            Object candidate = ports.next();
087
088            if (candidate instanceof TypedIOPort) {
089                TypedIOPort port = (TypedIOPort) candidate;
090                Set optionsDefault = new HashSet();
091
092                if (port.isInput()) {
093                    optionsDefault.add("input");
094                }
095
096                if (port.isOutput()) {
097                    optionsDefault.add("output");
098                }
099
100                if (port.isMultiport()) {
101                    optionsDefault.add("multiport");
102                }
103
104                addSelectButtons(port.getName(), port.getName(), _optionsArray,
105                        optionsDefault);
106
107                String typeEntryName = port.getName() + " type";
108                addLine(typeEntryName, typeEntryName,
109                        port.getType().toString());
110
111                // Add a column that controls on which side
112                // of the icon the port lies.
113                StringAttribute cardinal = (StringAttribute) port
114                        .getAttribute("_cardinal");
115                String cardinalValue = "SOUTH";
116
117                if (cardinal != null) {
118                    cardinalValue = cardinal.getExpression()
119                            .toUpperCase(Locale.getDefault());
120                } else if (port.isInput() && !port.isOutput()) {
121                    cardinalValue = "WEST";
122                } else if (port.isOutput() && !port.isInput()) {
123                    cardinalValue = "EAST";
124                }
125
126                addChoice(port.getName() + " cardinal",
127                        port.getName() + ": cardinal direction", _cardinals,
128                        cardinalValue);
129            }
130        }
131    }
132
133    ///////////////////////////////////////////////////////////////////
134    ////                         public methods                    ////
135
136    /** Apply the changes by configuring the ports that have changed.
137     */
138    public void apply() {
139        StringBuffer moml = new StringBuffer("<group>");
140        boolean foundOne = false;
141        Iterator ports = _object.portList().iterator();
142        NamedObj parent = null;
143
144        while (ports.hasNext()) {
145            Object candidate = ports.next();
146
147            if (candidate instanceof TypedIOPort) {
148                TypedIOPort port = (TypedIOPort) candidate;
149                String name = port.getName();
150
151                // Check whether the positioning information has changed.
152                String nameCardinal = name + " cardinal";
153
154                if (_changed.contains(nameCardinal)) {
155                    // The context for the MoML should be the first container
156                    // above this port in the hierarchy that defers its
157                    // MoML definition, or the immediate parent
158                    // if there is none.
159                    parent = port.getContainer();
160                    foundOne = true;
161                    moml.append("<port name=\"");
162                    moml.append(port.getName());
163                    moml.append("\">");
164
165                    String cardinalVal = getStringValue(nameCardinal);
166                    moml.append("<property name=\"_cardinal\" "
167                            + "class = \"ptolemy.kernel.util.StringAttribute\" "
168                            + "value = \"" + cardinalVal + "\"/>");
169                    moml.append("</port>");
170                }
171
172                // If either the I/O designation or the type changed,
173                // then generate additional MoML.
174                String typeEntryName = name + " type";
175
176                if (_changed.contains(name)
177                        || _changed.contains(typeEntryName)) {
178                    // Change to the type or I/O status.  Create a MoML command.
179                    String value = getStringValue(name);
180
181                    // First, parse the value, which may be a
182                    // comma-separated list.
183                    Set selectedValues = new HashSet();
184                    StringTokenizer tokenizer = new StringTokenizer(value, ",");
185
186                    while (tokenizer.hasMoreTokens()) {
187                        selectedValues.add(tokenizer.nextToken().trim());
188                    }
189
190                    // The context for the MoML should be the first container
191                    // above this port in the hierarchy that defers its
192                    // MoML definition, or the immediate parent
193                    // if there is none.
194                    parent = port.getContainer();
195                    foundOne = true;
196                    moml.append("<port name=\"");
197                    moml.append(port.getName());
198                    moml.append("\">");
199
200                    if (selectedValues.contains("input")) {
201                        moml.append("<property name=\"input\"/>");
202                    } else {
203                        moml.append(
204                                "<property name=\"input\" value=\"false\"/>");
205                    }
206
207                    if (selectedValues.contains("output")) {
208                        moml.append("<property name=\"output\"/>");
209                    } else {
210                        moml.append(
211                                "<property name=\"output\" value=\"false\"/>");
212                    }
213
214                    if (selectedValues.contains("multiport")) {
215                        moml.append("<property name=\"multiport\"/>");
216                    } else {
217                        moml.append(
218                                "<property name=\"multiport\" value=\"false\"/>");
219                    }
220
221                    if (_changed.contains(typeEntryName)) {
222                        // Type designation has changed.
223                        String type = getStringValue(typeEntryName);
224                        moml.append("<property name=\"_type\" "
225                                + "class = \"ptolemy.actor.TypeAttribute\" "
226                                + "value = \""
227                                + StringUtilities.escapeForXML(type) + "\"/>");
228                    }
229
230                    moml.append("</port>");
231                }
232            }
233        }
234
235        if (foundOne) {
236            moml.append("</group>");
237
238            MoMLChangeRequest request = new MoMLChangeRequest(this, // originator
239                    parent, // context
240                    moml.toString(), // MoML code
241                    null); // base
242
243            request.setUndoable(true);
244
245            // NOTE: There is no need to listen for completion
246            // or errors in this change request, since, in theory,
247            // it will just work.  Will someone report the error
248            // if one occurs?  I hope so...
249            parent.requestChange(request);
250        }
251    }
252
253    /** Called to notify that one of the entries has changed.
254     *  This simply sets a flag that enables application of the change
255     *  when the apply() method is called.
256     *  @param name The name of the entry that changed.
257     */
258    @Override
259    public void changed(String name) {
260        _changed.add(name);
261    }
262
263    ///////////////////////////////////////////////////////////////////
264    ////                         private variables                 ////
265    // Possible placements of ports.
266    private String[] _cardinals = { "NORTH", "SOUTH", "EAST", "WEST" };
267
268    // The set of names of ports that have changed.
269    private Set _changed = new HashSet();
270
271    // The object that this configurer configures.
272    private Entity _object;
273
274    // The possible configurations for a port.
275    private String[] _optionsArray = { "input", "output", "multiport" };
276}