001/* An editor factory for execution choice.
002 * 
003 * Copyright (c) 2012 The Regents of the University of California.
004 * All rights reserved.
005 *
006 * '$Author: crawl $'
007 * '$Date: 2015-09-04 20:53:26 +0000 (Fri, 04 Sep 2015) $' 
008 * '$Revision: 33870 $'
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 */
030package org.kepler.ddp.gui;
031
032import java.awt.Color;
033import java.awt.Frame;
034import java.awt.GridBagConstraints;
035import java.awt.GridBagLayout;
036import java.awt.event.ActionEvent;
037import java.awt.event.ActionListener;
038import java.io.File;
039import java.util.Arrays;
040import java.util.HashMap;
041import java.util.HashSet;
042import java.util.LinkedList;
043import java.util.List;
044import java.util.Map;
045import java.util.Set;
046
047import javax.swing.ButtonGroup;
048import javax.swing.JComboBox;
049import javax.swing.JFileChooser;
050import javax.swing.JLabel;
051import javax.swing.JPanel;
052import javax.swing.JRadioButton;
053import javax.swing.JTabbedPane;
054import javax.swing.JTextField;
055import javax.swing.SwingConstants;
056
057import org.apache.commons.io.FilenameUtils;
058import org.kepler.ddp.actor.ExecutionChoice;
059import org.kepler.gui.KeplerGraphFrame;
060import org.kepler.gui.ModelToFrameManager;
061import org.kepler.gui.frame.TabbedKeplerGraphFrame;
062
063import ptolemy.actor.TypedIOPort;
064import ptolemy.actor.gui.Configurer;
065import ptolemy.actor.gui.EditorFactory;
066import ptolemy.actor.lib.hoc.Refinement;
067import ptolemy.data.expr.Parameter;
068import ptolemy.gui.ComponentDialog;
069import ptolemy.gui.ExtensionFilenameFilter;
070import ptolemy.gui.JFileChooserBugFix;
071import ptolemy.gui.PtFileChooser;
072import ptolemy.gui.PtGUIUtilities;
073import ptolemy.gui.Query;
074import ptolemy.kernel.ComponentEntity;
075import ptolemy.kernel.CompositeEntity;
076import ptolemy.kernel.Port;
077import ptolemy.kernel.util.Attribute;
078import ptolemy.kernel.util.IllegalActionException;
079import ptolemy.kernel.util.NameDuplicationException;
080import ptolemy.kernel.util.NamedObj;
081import ptolemy.moml.MoMLChangeRequest;
082import ptolemy.util.MessageHandler;
083
084/** An editor factory to create an editor for ExecutionChoice. An
085 *  ExecutioChoiceEditorPane is used to configure the actor. This
086 *  class handles button presses and can display panes for adding,
087 *  removing, and renaming components, and exporting the execution
088 *  choices.
089 * 
090 *  @author Daniel Crawl
091 *  @version $Id: ExecutionChoiceEditorFactory.java 33870 2015-09-04 20:53:26Z crawl $
092 */
093public class ExecutionChoiceEditorFactory extends EditorFactory {
094
095    public ExecutionChoiceEditorFactory(NamedObj container, String name)
096            throws IllegalActionException, NameDuplicationException {
097        super(container, name);            
098    }
099
100    @Override
101    public void createEditor(NamedObj object, Frame parent) {
102
103        if(!(object instanceof ExecutionChoice)) {
104            MessageHandler.error("Object to edit must be ExecutionChoice.");
105            return;
106        }
107        
108        ExecutionChoice choice = (ExecutionChoice)object;
109        
110        try {
111            choice.addDefaults();
112        } catch (Exception e) {
113            MessageHandler.error("Error adding default input/outputs.", e);
114        }
115        
116        boolean done = false;
117        
118        Set<String> addedInputs = new HashSet<String>();
119        Set<String> addedOutputs = new HashSet<String>();
120        Set<String> addedParameters = new HashSet<String>();
121        Set<String> addedChoices = new HashSet<String>();
122        
123        // a set of Configure objects for the execution choice actor and
124        // each sub-workflow. if the user hits Cancel, escape, or the
125        // close window button (top-left or top-right of dialog), the
126        // Configure objects are used to restore the parameter values in
127        // the actor and for each sub-workflow.
128        Set<Configurer> configurers = new HashSet<Configurer>();
129
130        while(!done) {
131            final Configurer actorConfigurer = new Configurer(object);
132
133            configurers.clear();
134            configurers.add(actorConfigurer);
135            
136            for(Refinement refinement : choice.entityList(Refinement.class)) {
137                configurers.add(new Configurer(refinement));
138            }
139            
140            final ComponentDialog dialog = new ComponentDialog(parent, 
141                object.getFullName(), 
142                actorConfigurer,
143                new String[] {"Commit", "Types", "Rename", "Remove",
144                "Import", "Export", "Arguments", "Add", "Cancel"});
145            final String buttonPressed = dialog.buttonPressed();
146            
147            // if user pushed escape button, buttonPressed is empty.
148            if(buttonPressed.equals("Commit")) {
149                done = true;
150            } else if(buttonPressed.equals("Cancel")  || buttonPressed.isEmpty()) {
151                
152                // NOTE: Cancel only restores parameter values.
153                
154                for(Configurer configurer : configurers) {
155                        configurer.restore();
156                }
157                
158                // remove all added items
159                /*
160                for(String addedInput : addedInputs) {
161                    try {
162                        choice.removeInput(addedInput);
163                    } catch (Exception e) {
164                        MessageHandler.error("Error removing input " + addedInput, e);
165                    }
166                }
167                for(String addedOutput : addedOutputs) {
168                    try {
169                        choice.removeOutput(addedOutput);
170                    } catch (Exception e) {
171                        MessageHandler.error("Error removing output " + addedOutput, e);
172                    }
173                }
174                for(String addedParameter : addedParameters) {
175                    try {
176                        // FIXME parameter may have been added to refinement
177                        choice.removeParameter(addedParameter);
178                    } catch (Exception e) {
179                        MessageHandler.error("Error removing parameter " + addedParameter, e);
180                    }
181                }
182                for(String addedChoice : addedChoices) {
183                    try {
184                        choice.removeExecutionChoice(addedChoice);
185                    } catch (Exception e) {
186                        MessageHandler.error("Error removing execution choice " + addedChoice, e);
187                    }
188                }
189                */
190                
191                // TODO restore all removed items
192                
193                // TODO restore all renamed items
194                
195                // TODO restore all argument changes
196                
197                // TODO remove parameters add to refinements
198                
199                // TODO restore parameters removed from refinements
200                
201                // TODO restore parameters renamed in refinements
202                
203                // repaint canvas to remove any added ports
204                //_repaintCanvas(choice);
205
206                done = true;
207                
208            } else if(buttonPressed.equals("Add")) {
209                boolean doneAdding = false;
210                String addStr = null;
211                String newName = null;
212                String typeStr = null;
213                String argumentStr = null;
214                String choiceStr = null;
215                while(!doneAdding) {
216                    final AddPane addPane = new AddPane(choice);
217                    addPane.setAdd(addStr);
218                    addPane.setTextName(newName);
219                    addPane.setType(typeStr);
220                    addPane.setArgument(argumentStr);
221                    addPane.setChoice(choiceStr);
222                    final ComponentDialog addDialog = new ComponentDialog(parent,
223                            buttonPressed, addPane,
224                            new String[] {"Add", "Add & Continue", "Cancel"});
225                    String pressed = addDialog.buttonPressed();
226                    if(pressed.equals("Add") || pressed.equals("Add & Continue")) {
227                        try {
228                            addStr = addPane.getAdd();
229                            newName = addPane.getTextName();
230                            typeStr = addPane.getType();
231                            argumentStr = addPane.getArgument();
232                            choiceStr = addPane.getChoice();
233                            
234                            boolean chooseNewName = false;
235                            
236                            if(newName.isEmpty()) {
237                                MessageHandler.error("Please specify a name.");
238                            } else {
239                                if(addStr.equals("Input")) {
240                                    if(choice.getInputNames(true).contains(newName)) {
241                                        chooseNewName = true;
242                                    } else { 
243                                        choice.newInput(newName,
244                                            ExecutionChoice.IOType.valueOf(typeStr),
245                                            argumentStr);
246                                        addedInputs.add(newName);
247                                    }
248                                } else if(addStr.equals("Output")) {
249                                    if(choice.getOutputNames(true).contains(newName)) {
250                                        chooseNewName = true;
251                                    } else {
252                                        choice.newOutput(newName,
253                                            ExecutionChoice.IOType.valueOf(typeStr),
254                                            argumentStr);
255                                        addedOutputs.add(newName);
256                                    }
257                                } else if(addStr.equals("Parameter")) {
258                                    // use getAttribute() instead of getParameterNames()
259                                    // since the latter does not include all the parameters
260                                    if(choice.getAttribute(newName) != null) {
261                                        chooseNewName = true;
262                                    } else {
263                                        choice.newParameter(newName, argumentStr, null, choiceStr,
264                                                ExecutionChoice.ParameterType.valueOf(typeStr));
265                                        addedParameters.add(newName);
266                                    }
267                                } else if(addStr.equals("Execution Choice")) {
268                                        if(choice.getEntity(newName) != null) {
269                                                chooseNewName = true;
270                                        } else {
271                                                choice.newExecutionChoice(typeStr, newName);
272                                                addedChoices.add(newName);
273                                                
274                                                // if the choices are open in a frame, add a new tab for the new choice
275                                                KeplerGraphFrame frame = ModelToFrameManager.getInstance().getFrame(choice);
276                                                if(frame != null && (frame instanceof TabbedKeplerGraphFrame)) {
277                                                    ((TabbedKeplerGraphFrame)frame).
278                                                        addSubComposite((CompositeEntity)choice.getEntity(newName));
279                                                }
280                                        }
281                                }               
282                                
283                                if(chooseNewName) {
284                                    MessageHandler.error(addStr + " " + newName +
285                                            " is already used. Please choose a different name.");
286                                } else {
287                                    // execute an empty change request so that the new port
288                                    // appears (if we added a new port)
289                                    _repaintCanvas(choice);
290                                    
291                                    if(pressed.equals("Add")) {
292                                        doneAdding = true;
293                                    }
294                                }
295                            }
296                        } catch(IllegalActionException e) {
297                            MessageHandler.error("Error", e);
298                        } catch(NameDuplicationException e) {
299                            MessageHandler.error(addPane.getTextName() +
300                                    " already exists. Please choose a different name.", e);
301                        }
302                    } else if(addDialog.buttonPressed().equals("Cancel") ||
303                            addDialog.buttonPressed().isEmpty()) {
304                        doneAdding = true;
305                    }
306                }
307            } else if(buttonPressed.equals("Rename")) {
308                try {
309                    boolean doneRenaming = false;
310                    while(!doneRenaming) {
311                        RenamePane renamePane;
312                        try {
313                            renamePane = new RenamePane(choice);
314                        } catch (IllegalActionException e) {
315                            MessageHandler.error("Error creating Rename dialog.", e);
316                            break;
317                        }
318                        final ComponentDialog renameDialog = new ComponentDialog(parent,
319                                buttonPressed, renamePane);
320                        if(renameDialog.buttonPressed().equals("OK")) {
321                            Set<RenameInfo> renames = renamePane.getRenames();
322                            
323                            // first check all the renames to make sure that
324                            // there are no name conflicts.
325                            String newName = null;
326                            String type = null;
327                            NamedObj container = null;
328                            boolean chooseNewName = false;
329                            for(RenameInfo rename : renames) {
330                                type = rename._type;
331                                newName = rename._newName;
332                                container = rename._container;
333                                if(type.equals("Execution Choice")) {
334                                    if(choice.getEntity(newName) != null) {
335                                        chooseNewName = true;
336                                        break;
337                                    }
338                                } else if(type.equals("Input")) {
339                                    // TODO what if output name exists?
340                                    if(choice.getInputNames(true).contains(newName)) {
341                                        chooseNewName = true;
342                                        break;
343                                    }
344                                } else if(type.equals("Output")) {
345                                    if(choice.getOutputNames(true).contains(newName)) {
346                                        chooseNewName = true;
347                                        break;
348                                    }
349                                } else if(type.equals("Parameter")) {
350                                    if(container.getAttribute(newName) != null) {
351                                        chooseNewName = true;
352                                        break;
353                                    }
354                                }
355                            }
356                            
357                            if(chooseNewName) {
358                                MessageHandler.error(type + " " + newName +
359                                        " is already used. Please choose a different name.");
360                            } else {
361                                
362                                // perform each rename
363                                for(RenameInfo renameInfo : renamePane.getRenames()) {
364                                    //try {
365                                        if(renameInfo._type.equals("Execution Choice")) {
366                                            choice.renameExecutionChoice(renameInfo._oldName,
367                                                    renameInfo._newName);
368                                            
369                                            // if the choices are open in a frame, remove the tab for the choice
370                                            // that was removed.
371                                            KeplerGraphFrame frame = ModelToFrameManager.getInstance().getFrame(choice);
372                                            if(frame != null && (frame instanceof TabbedKeplerGraphFrame)) {
373                                                ((TabbedKeplerGraphFrame)frame).updateTabsForComposite(choice);
374                                            }
375
376                                        } else if(renameInfo._type.equals("Input")) {
377                                            choice.renameInput(renameInfo._oldName,
378                                                    renameInfo._newName);
379                                        } else if(renameInfo._type.equals("Output")) {
380                                            choice.renameOutput(renameInfo._oldName,
381                                                    renameInfo._newName);
382                                        } else if(renameInfo._type.equals("Parameter")) {
383                                            choice.renameParameter(renameInfo._oldName,
384                                                    renameInfo._newName, renameInfo._container);
385                                        }
386                                    //} catch(IllegalActionException e) {
387                                        //MessageHandler.error("Error renaming " + renameInfo._oldName, e);
388                                    //}
389                                }
390                                // execute an empty change request so that the new port
391                                // names appear (if we changed any port names)
392                                _repaintCanvas(choice);
393                                doneRenaming = true;
394                            }
395                        } else if(renameDialog.buttonPressed().equals("Cancel") ||
396                                renameDialog.buttonPressed().isEmpty()) {
397                            doneRenaming = true;
398                        }
399                    }
400                    
401                } catch(Exception e) {
402                    MessageHandler.error("Error renaming.", e);
403                }
404            } else if(buttonPressed.equals("Remove")) {
405                boolean doneRemoving = false;
406                while(!doneRemoving) {
407                    RemovePane removePane = null;
408                    try {
409                        removePane = new RemovePane(choice);
410                    } catch (IllegalActionException e) {
411                        MessageHandler.error("Error creating Remove dialog.", e);
412                    }
413                    
414                    if(removePane != null) {
415                        final ComponentDialog removeDialog = new ComponentDialog(parent,
416                                buttonPressed, removePane,
417                                new String[] {"Remove", "Remove & Continue", "Cancel"});
418                        String pressed = removeDialog.buttonPressed();
419                        
420                        doneRemoving = true;
421                        if(pressed.equals("Remove & Continue")) {
422                            doneRemoving = false;
423                        }
424                        
425                        if(pressed.equals("Remove") || pressed.equals("Remove & Continue")) {
426                            String removeStr = removePane.getRemove();
427                            String name = removePane.getTextName();
428                            if(name != null) {
429                                boolean removed = false;
430                                try {
431                                    if(removeStr.equals("Input")) {
432                                        if(MessageHandler.yesNoQuestion("Remove input " + name + "?")) {
433                                            choice.removeInput(name);
434                                            removed = true;
435                                            addedInputs.remove(name);
436                                        }
437                                    } else if(removeStr.equals("Output")) {
438                                        if(MessageHandler.yesNoQuestion("Remove output " + name + "?")) {
439                                            choice.removeOutput(name);
440                                            removed = true;
441                                            addedOutputs.remove(name);
442                                        }
443                                    } else if(removeStr.equals("Parameter")) {
444                                        if(MessageHandler.yesNoQuestion("Remove parameter " + name + "?")) {
445                                            final NamedObj container = removePane.getRemoveContainer();
446                                            if(container == choice) {
447                                                choice.removeParameter(name);
448                                                removed = true;
449                                                addedParameters.remove(name);
450                                            } else {
451                                                Attribute parameter = container.getAttribute(name);
452                                                parameter.setContainer(null);
453                                                removed = true;
454                                                // TODO undo stuff
455                                            }   
456                                                
457                                        }
458                                    } else if(removeStr.equals("Execution Choice")) {
459                                        if(MessageHandler.yesNoQuestion("Remove execution choice " +
460                                                name + " and all of its components?")) {
461                                            choice.removeExecutionChoice(name);
462                                            removed = true;
463                                            addedChoices.remove(name);
464                                            
465                                            // if the choices are open in a frame, remove the tab for the choice
466                                            // that was removed.
467                                            KeplerGraphFrame frame = ModelToFrameManager.getInstance().getFrame(choice);
468                                            if(frame != null && (frame instanceof TabbedKeplerGraphFrame)) {
469                                                ((TabbedKeplerGraphFrame)frame).updateTabsForComposite(choice);
470                                            }
471                                        }
472                                    }
473        
474                                    if(removed) {
475                                        // execute an empty change request so that removed port
476                                        // no longer shows on the canvas
477                                        _repaintCanvas(choice);
478                                    }                      
479                                } catch(Exception e) {
480                                    MessageHandler.error("Error removing " + name, e);
481                                }
482                            }
483                        }
484                    }
485                }
486            } else if(buttonPressed.equals("Export")) {
487                final ExportPane exportPane = new ExportPane(choice);
488                final ComponentDialog exportDialog = new ComponentDialog(parent,
489                        buttonPressed, exportPane);
490                if(exportDialog.buttonPressed().equals("OK")) {
491                    String name = exportPane.getChoiceName();
492                    if(name != null) {
493                        
494                        // Avoid white boxes in file chooser, see
495                        // http://bugzilla.ecoinformatics.org/show_bug.cgi?id=3801
496                        JFileChooserBugFix jFileChooserBugFix = new JFileChooserBugFix();
497                        Color background = null;
498                        PtFileChooser chooser = null;
499
500                        try {
501                            background = jFileChooserBugFix.saveBackground();
502                            chooser = new PtFileChooser(parent, "Export",
503                                JFileChooser.SAVE_DIALOG);
504
505                            String defaultFileName = name.replaceAll("\\s+", "") + ".xml";
506                            chooser.setSelectedFile(new File(defaultFileName));
507                            
508                            int returnVal = chooser.showDialog(parent, "Export");
509                            if (returnVal == JFileChooser.APPROVE_OPTION) {
510                                // process the given file
511                                File saveFile = chooser.getSelectedFile();
512                                
513                                if(saveFile.exists() && !PtGUIUtilities.useFileDialog()) {
514                                    if (!MessageHandler.yesNoQuestion("Overwrite \""
515                                            + saveFile.getName() + "\"?")) {
516                                        saveFile = null;
517                                    }
518                                }
519                                
520                                try {
521                                                                        choice.exportExecutionChoice(saveFile, name);
522                                                                } catch (Exception e) {
523                                                                        MessageHandler.error("Error exporting execution choice.", e);
524                                                                }
525                                
526                            }                   
527
528                        } finally {
529                            jFileChooserBugFix.restoreBackground(background);
530                        }
531
532                    }
533                }
534            } else if(buttonPressed.equals("Import")) {
535                
536                // Avoid white boxes in file chooser, see
537                // http://bugzilla.ecoinformatics.org/show_bug.cgi?id=3801
538                JFileChooserBugFix jFileChooserBugFix = new JFileChooserBugFix();
539                Color background = null;
540                PtFileChooser chooser = null;
541
542                try {
543                    background = jFileChooserBugFix.saveBackground();
544                    chooser = new PtFileChooser(parent, "Import",
545                        JFileChooser.OPEN_DIALOG);
546                    chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
547                    chooser.addChoosableFileFilter(new ExtensionFilenameFilter("xml"));
548                    
549                    
550                    int returnVal = chooser.showDialog(parent, "Import");
551                    if(returnVal == JFileChooser.APPROVE_OPTION) {
552                        
553                        // load the file as a new execution choice
554                        File loadFile = chooser.getSelectedFile();
555                        
556                        // ask the user for the name of the new execution choice
557
558                        String refinementName = null;
559                        boolean doneAskingName = false;
560                        
561                        while(!doneAskingName) {
562                        
563                                // set the default name to be the file name
564                                final ImportPane importPane = 
565                                                new ImportPane(FilenameUtils.removeExtension(loadFile.getName()));
566                                final ComponentDialog importDialog = new ComponentDialog(parent,
567                                        buttonPressed, importPane);
568                                if(importDialog.buttonPressed().equals("OK")) {
569                                        
570                                        // see if the name has already been chosen
571                                        refinementName = importPane.getChoiceName();
572                                        if(choice.getEntity(refinementName) != null) {
573                                                MessageHandler.error("The name " + refinementName +
574                                                                " is already used. Please choose a different name.");
575                                        } else {
576                                                doneAskingName = true;
577                                        }
578                
579                                } else if(importDialog.buttonPressed().equals("Cancel")) {
580                                        refinementName = null;
581                                        doneAskingName = true;
582                                }
583                        }
584                        
585                        // load the execution choice if a unique name was selected.
586                        if(refinementName != null) {
587                                try {
588                                        choice.newExecutionChoice(loadFile, refinementName);
589                                } catch(IllegalActionException e) {
590                                        MessageHandler.error("Error importing execution choice.", e);
591                                }
592                        }
593                        
594                    }
595                    
596                } finally {
597                    jFileChooserBugFix.restoreBackground(background);
598                }
599
600            } else if(buttonPressed.equals("Arguments")) {
601                ArgumentsPane argumentsPane = null;
602                try {
603                    argumentsPane = new ArgumentsPane(choice);
604                } catch (IllegalActionException e) {
605                    MessageHandler.error("Error creating Arguments dialog.", e);
606                }
607                
608                if(argumentsPane != null) {
609                    final ComponentDialog argumentsDialog = new ComponentDialog(parent,
610                            buttonPressed, argumentsPane);
611                    if(argumentsDialog.buttonPressed().equals("OK")) {
612                        try {
613                            argumentsPane.applyChanges();
614                        } catch(Exception e) {
615                            MessageHandler.error("Error changing arguments.", e);
616                        }
617                    }
618                }
619            } else if(buttonPressed.equals("Types")) {
620                TypesPane typesPane = null;
621                try {
622                    typesPane = new TypesPane(choice);
623                } catch (IllegalActionException e) {
624                    MessageHandler.error("Error creating Types dialog.", e);
625                }
626                
627                if(typesPane != null) {
628                    final ComponentDialog typesDialog = new ComponentDialog(parent,
629                            buttonPressed, typesPane);
630                    if(typesDialog.buttonPressed().equals("OK")) {
631                        try {
632                            typesPane.applyChanges();
633                        } catch(Exception e) {
634                            MessageHandler.error("Error changing types.", e);
635                        }
636                    }
637                }                
638            }
639        }        
640    }
641    
642    /** Repaint the canvas by executing an empty change request. */
643    private void _repaintCanvas(ExecutionChoice choice) {
644        MoMLChangeRequest change = 
645                new MoMLChangeRequest(this, this, "<group></group>");
646        change.setPersistent(false);
647        choice.requestChange(change);        
648    }
649
650    /** A utility pane for adding/removing. */
651    private static abstract class UtilPane extends JPanel implements ActionListener {
652        
653        public UtilPane(ExecutionChoice choice) {
654            _choice = choice;
655        }
656              
657        /** Get the type of the component added, e.g., if the component is
658         *  an execution choice, the type is the name of one of the templates.
659         */
660        public String getType() {
661            Object item = _typeComboBox.getSelectedItem();
662            if(item == null) {
663                return "";
664            }
665            // return toString() since item may not be a String, 
666            // e.g., it could be an ExecutionChoice.IOType
667            return item.toString();
668        }
669
670        /** Set the type of the component to be added. */
671        public void setType(String typeStr) {
672            if(typeStr != null) {
673                _typeComboBox.setSelectedItem(typeStr);
674            }
675        }
676        
677        /** Get the selected action component type,
678         *  e.g, input, output, parameter, execution choice.
679         */
680        protected String _getActionButtonSelected() {
681            for(JRadioButton button : _buttonMap.values()) {
682                if(button.isSelected()) {
683                    return button.getText();
684                }
685            }
686            return null;
687        }
688        
689        /** Set the selected action component. */
690        public void setActionButtonSelected(String buttonText) {
691            if(buttonText != null) {
692                for(JRadioButton button : _buttonMap.values()) {
693                    if(button.getText().equals(buttonText)) {
694                        button.setSelected(true);
695                    } else {
696                        button.setSelected(false);
697                    }
698                }
699            }
700        }        
701
702        /** Layout the top part of the pane with the radio buttons. */
703        protected void _doTopLayout(String actionStr, GridBagConstraints c) {
704            
705            c.fill = GridBagConstraints.HORIZONTAL;
706            c.anchor = GridBagConstraints.LINE_START;
707
708            c.gridx = 0;
709            c.gridy = 0;
710            add(new JLabel(actionStr + ":"), c);
711            
712            final ButtonGroup buttonGroup = new ButtonGroup();
713            JRadioButton inputButton = new JRadioButton("Input");
714            inputButton.setSelected(true);
715            inputButton.addActionListener(this);
716            buttonGroup.add(inputButton);
717            _buttonMap.put("Input", inputButton);
718            c.gridx = 1;
719            c.gridy++;
720            add(inputButton, c);
721            
722            JRadioButton outputButton = new JRadioButton("Output");
723            outputButton.addActionListener(this);
724            buttonGroup.add(outputButton);
725            _buttonMap.put("Output", outputButton);
726            c.gridy++;
727            add(outputButton, c);
728            
729            JRadioButton parameterButton = new JRadioButton("Parameter");
730            parameterButton.addActionListener(this);
731            buttonGroup.add(parameterButton);
732            _buttonMap.put("Parameter", parameterButton);
733            c.gridy++;
734            add(parameterButton, c);
735            
736            JRadioButton choiceButton = new JRadioButton("Execution Choice");
737            choiceButton.addActionListener(this);
738            buttonGroup.add(choiceButton);
739            _buttonMap.put("Execution Choice", choiceButton);
740            c.gridy++;
741            add(choiceButton, c);
742            
743            c.gridx = 0;
744            c.gridy++;
745            add(new JLabel("Name:"), c);            
746        }
747        
748        protected Map<String,JRadioButton> _buttonMap = new HashMap<String,JRadioButton>();
749        protected JComboBox<Object> _typeComboBox;
750        protected ExecutionChoice _choice;
751
752        /** The label for choice entry. */
753        protected JLabel _choiceLabel;
754        
755        /** The label for the type combobox. */
756        protected JLabel _typeLabel;
757        
758        /** The combobox to hold the names of execution choices. */
759        protected JComboBox<String> _choiceComboBox;
760
761    }
762    
763    /** A pane to add an input, output, or execution choice. */
764    private static class AddPane extends UtilPane {
765        
766        public AddPane(ExecutionChoice choice) {
767            
768            super(choice);
769            
770            GridBagLayout layout = new GridBagLayout();
771            setLayout(layout);
772                        
773            GridBagConstraints c = new GridBagConstraints();
774
775            _doTopLayout("Add", c);
776
777            _nameTextField = new JTextField("", 20);
778            c.gridx = 1;
779            add(_nameTextField, c);
780
781            c.gridx = 0;
782            c.gridy++;
783            _argumentLabel = new JLabel(ExecutionChoice.ARGUMENT_NAME + ":");
784            add(_argumentLabel, c);
785            
786            _argumentTextField = new JTextField("", 20);
787            c.gridx = 1;
788            add(_argumentTextField, c);
789            
790            c.gridx = 0;
791            c.gridy++;
792            _typeLabel = new JLabel("Type:");
793            add(_typeLabel, c);
794            
795            _typeComboBox = new JComboBox<Object>(ExecutionChoice.IOType.values());
796            _typeComboBox.addActionListener(this);
797            c.gridx = 1;
798            add(_typeComboBox, c);
799            
800            c.gridx = 0;
801            c.gridy++;
802            _choiceLabel = new JLabel("Choice:");
803            add(_choiceLabel, c);
804            _choiceLabel.setEnabled(false);
805            
806            _choiceComboBox = new JComboBox<String>();
807            _choiceComboBox.addItem(ExecutionChoice.ALL_CHOICES_NAME);
808                for(String name : _choice.getExecutionChoiceNames()) {
809                        _choiceComboBox.addItem(name);
810                }            
811                _choiceComboBox.addActionListener(this);
812            c.gridx = 1;
813            add(_choiceComboBox, c);
814            _choiceComboBox.setEnabled(false);
815        }
816
817        @Override
818        public void actionPerformed(ActionEvent event) {
819            
820            Object source = event.getSource();
821            // see if the type of component to add was changed
822            if(source instanceof JRadioButton) {
823                final String buttonText = (String) ((JRadioButton)source).getText();
824                _updateTypeComboBox(buttonText);
825            }
826            
827            _updateEnabledFields();
828        }
829        
830        /** Get the component added, i.e., input, output, execution choice. */
831        public String getAdd() {
832            return _getActionButtonSelected();
833        }
834        
835        /** Set the component to be added. */
836        public void setAdd(String addStr) {
837            if(addStr != null) {
838                setActionButtonSelected(addStr);
839                _updateTypeComboBox(addStr);
840                _updateEnabledFields();
841            }
842        }        
843       
844        /** Get the argument value. */
845        public String getArgument() {
846            return _argumentTextField.getText();
847        }
848
849        /** Set the argument. */
850        public void setArgument(String argumentStr) {
851            if(argumentStr != null) {
852                _argumentTextField.setText(argumentStr);
853            }
854        }
855
856        /** Get the name of the selected execution choice. */
857        public String getChoice() {
858            return (String) _choiceComboBox.getSelectedItem();
859        }
860
861        /** Set the name of the seleced execution choice. */
862        public void setChoice(String choiceStr) {
863            if(choiceStr != null) {
864                _choiceComboBox.setSelectedItem(choiceStr);
865            }            
866        }
867
868        /** Get the user-specified name of the component added. */
869        public String getTextName() {
870            return _nameTextField.getText();
871        }
872        
873        /** Set the name of the component to be added. */
874        public void setTextName(String newName) {
875            if(newName != null) {
876                _nameTextField.setText(newName);
877            }
878        }
879
880        /** Refill the type combo box based on the add type. */
881        protected void _updateTypeComboBox(String addStr) {
882            // remove all the types
883            _typeComboBox.removeAllItems();
884            // see if the add was set to input or output
885            if(addStr.equals("Input") || addStr.equals("Output")) {
886                for(ExecutionChoice.IOType type : ExecutionChoice.IOType.values()) {
887                    _typeComboBox.addItem(type);
888                }
889            } else if(addStr.equals("Parameter")) {
890                for(ExecutionChoice.ParameterType type : ExecutionChoice.ParameterType.values()) {
891                    _typeComboBox.addItem(type);
892                }    
893                } else {
894                        // add was set to execution choice, so load the template
895                        // names in the type combobox
896                        try {
897                                for(String name : _choice.getTemplateNames()) {
898                                        _typeComboBox.addItem(name);
899                                }
900                        } catch(IllegalActionException e) {
901                                MessageHandler.error("Error loading template names.", e);
902                }       
903                }
904        }
905
906        /** Enable or disable fields based on the selected radio button. */
907        private void _updateEnabledFields() {
908                
909                // get the type of component to add
910                String buttonText = _getActionButtonSelected();
911                
912            if(buttonText.equals("Execution Choice") || getType().equals("Data")) {
913                _argumentLabel.setEnabled(false);
914                _argumentTextField.setEnabled(false);
915            } else {                
916                _argumentLabel.setEnabled(true);
917                _argumentTextField.setEnabled(true);                                        
918            }
919            
920            // the choice combobox selects which choice to add the parameter to
921            if(buttonText.equals("Parameter")) {
922                _choiceLabel.setEnabled(true);
923                _choiceComboBox.setEnabled(true);
924            } else {
925                _choiceLabel.setEnabled(false);
926                _choiceComboBox.setEnabled(false);
927            }            
928        }
929
930        /** The name of the component. */
931        private JTextField _nameTextField;
932
933        /** The (optional) argument used with the component. */
934        private JTextField _argumentTextField;
935        
936        /** The label for argument entry. */
937        private JLabel _argumentLabel;
938        
939    }
940
941    /** A pane to remove an input, output, or execution choice. */
942    private static class RemovePane extends UtilPane {
943        
944        public RemovePane(ExecutionChoice choice) throws IllegalActionException {
945
946            super(choice);
947            
948            GridBagLayout layout = new GridBagLayout();
949            setLayout(layout);
950                        
951            GridBagConstraints c = new GridBagConstraints();
952
953            _doTopLayout("Remove", c);
954
955            _nameComboBox = new JComboBox<String>();
956            List<String> inputNames = _choice.getInputNames(true);
957            for(String inputName : inputNames) {
958                _nameComboBox.addItem(inputName);
959            } 
960            if(_nameComboBox.getItemCount() == 0) {
961                _nameComboBox.addItem(NONE_TO_REMOVE);
962                _nameComboBox.setEnabled(false);
963            }
964            c.gridx = 1;
965            add(_nameComboBox, c);
966
967            c.gridx = 0;
968            c.gridy++;
969            _choiceLabel = new JLabel("Choice:");
970            add(_choiceLabel, c);
971            _choiceLabel.setEnabled(false);
972            
973            _choiceComboBox = new JComboBox<String>();
974            _choiceComboBox.addItem(ExecutionChoice.ALL_CHOICES_NAME);
975            for(String name : choice.getExecutionChoiceNames()) {
976                _choiceComboBox.addItem(name);
977            }
978            _choiceComboBox.addActionListener(this);
979            c.gridx = 1;
980            add(_choiceComboBox, c);
981            _choiceComboBox.setEnabled(false);            
982        }
983
984        @Override
985        public void actionPerformed(ActionEvent event) {
986            
987            Object source = event.getSource();
988            
989            try {
990            
991                // see if the add combobox was changed
992                if(source instanceof JRadioButton) {
993                    _nameComboBox.removeAllItems();
994                    String typeStr = (String) ((JRadioButton)source).getText();
995                    if(typeStr.equals("Input")) {
996                        for(String name : _choice.getInputNames(true)) {
997                            _nameComboBox.addItem(name);
998                        }
999                    } else if(typeStr.equals("Output")) {
1000                        for(String name : _choice.getOutputNames(true)) {
1001                            _nameComboBox.addItem(name);
1002                        }
1003                    } else if(typeStr.equals("Parameter")) {
1004                        for(String name : _choice.getParameterNames()) {
1005                            _nameComboBox.addItem(name);
1006                        }
1007                    } else {
1008                        // add was set to execution choice, so load the template
1009                        // names in the type combobox
1010                        for(Refinement refinement : _choice.entityList(Refinement.class)) {
1011                            _nameComboBox.addItem(refinement.getDisplayName());
1012                        }
1013                    }
1014                                   
1015                    // the choice combobox denotes which execution choice 
1016                    // contains the parameter to remove.
1017                    if(typeStr.equals("Parameter")) {
1018                        _choiceLabel.setEnabled(true);
1019                        _choiceComboBox.setEnabled(true);
1020                    } else {
1021                        _choiceLabel.setEnabled(false);
1022                        _choiceComboBox.setEnabled(false);
1023                    }
1024                                
1025                } else if(source == _choiceComboBox) {
1026                    
1027                    _nameComboBox.removeAllItems();
1028                    String refinementName = (String) _choiceComboBox.getSelectedItem();
1029                    if(refinementName.equals(ExecutionChoice.ALL_CHOICES_NAME)) {
1030                        for(String name : _choice.getParameterNames()) {
1031                            _nameComboBox.addItem(name);
1032                        }
1033                    } else {
1034                        ComponentEntity<?> refinement = _choice.getEntity(refinementName);
1035                        for(Parameter parameter : refinement.attributeList(Parameter.class)) {
1036                            String name = parameter.getName();
1037                            // can't delete the commandLine parameter
1038                            if(!name.equals(ExecutionChoice.COMMAND_LINE_NAME) &&
1039                                    !name.startsWith("_")) {
1040                                _nameComboBox.addItem(name);
1041                            }
1042                        }
1043                    }
1044                }
1045                
1046                if(_nameComboBox.getItemCount() == 0) {
1047                    _nameComboBox.addItem(NONE_TO_REMOVE);
1048                    _nameComboBox.setEnabled(false);
1049                } else {
1050                    _nameComboBox.setEnabled(true);
1051                }
1052            } catch(IllegalActionException e) {
1053                MessageHandler.error("Error performing action.", e);
1054            }
1055        }
1056        
1057        /** Get the container of the parameter to remove. */
1058        public NamedObj getRemoveContainer() {
1059            String refinementName = (String) _choiceComboBox.getSelectedItem();
1060            if(refinementName.equals(ExecutionChoice.ALL_CHOICES_NAME)) {
1061                return _choice;
1062            } else {
1063                return _choice.getEntity(refinementName);
1064            }
1065        }
1066
1067        /** Get the user-specified name of the component removed. */
1068        public String getTextName() {
1069            String name = (String) _nameComboBox.getSelectedItem();
1070            if(!name.equals(NONE_TO_REMOVE)) {
1071                return name;
1072            }
1073            return null;
1074        }
1075        
1076        /** Get the type of component to be removed, 
1077         *  e.g., input, output, parameter, execution choice.
1078         */
1079        public String getRemove() {
1080            return _getActionButtonSelected();
1081        }
1082                
1083        private JComboBox<String> _nameComboBox;
1084        
1085        private static final String NONE_TO_REMOVE = "None to remove."; 
1086    }
1087    
1088    /** A utility class to hold rename information. */
1089    private static class RenameInfo {
1090        
1091        public RenameInfo(String newName, String oldName, String type, NamedObj container) {
1092            _newName = newName;
1093            _oldName = oldName;
1094            _type = type;
1095            _container = container;
1096        }
1097        
1098        private String _oldName;
1099        private String _newName;
1100        private String _type;
1101        private NamedObj _container;
1102    }
1103  
1104    /** A pane to rename inputs, outputs, or execution choices. */
1105    private static class RenamePane extends FieldsPane {
1106        
1107        public RenamePane(ExecutionChoice choice) throws IllegalActionException {   
1108            super(choice, true, true);            
1109        }
1110       
1111        /** Get rename information. */
1112        public Set<RenameInfo> getRenames() throws IllegalActionException {
1113            
1114            final Set<RenameInfo> renames = new HashSet<RenameInfo>();
1115            
1116            Query query = _queries.get(_choice);
1117            
1118            for(String name : _choice.getInputNames(true)) {
1119                String newName = query.getStringValue(name);
1120                if(!name.equals(newName)) {
1121                    renames.add(new RenameInfo(newName, name, "Input", _choice));
1122                }
1123            }
1124
1125            for(String name : _choice.getOutputNames(true)) {
1126                String newName = query.getStringValue(name);
1127                if(!name.equals(newName)) {
1128                    renames.add(new RenameInfo(newName, name, "Output", _choice));
1129                }
1130            }
1131
1132            for(String name : _choice.getParameterNames()) {
1133                String newName = query.getStringValue(name);
1134                if(!name.equals(newName)) {
1135                    renames.add(new RenameInfo(newName, name, "Parameter", _choice));
1136                }
1137            }
1138
1139            for(String name : _choice.getExecutionChoiceNames()) {
1140                String newName = query.getStringValue(name);
1141                if(!name.equals(newName)) {
1142                    renames.add(new RenameInfo(newName, name, "Execution Choice", _choice));
1143                }
1144            }
1145            
1146            // get the renames for parameters in refinements
1147            for(String executionName : _choice.getExecutionChoiceNames()) {
1148                ComponentEntity<?> container = _choice.getEntity(executionName);
1149                query = _queries.get(container);
1150                
1151                for(Parameter parameter : container.attributeList(Parameter.class)) {
1152                    String name = parameter.getName();
1153                    if(!name.equals(ExecutionChoice.COMMAND_LINE_NAME) &&
1154                            !name.startsWith("_")) {
1155                        String newName = query.getStringValue(name);
1156                        if(!name.equals(newName)) {
1157                            renames.add(new RenameInfo(newName, name, "Parameter", container));
1158                        }
1159                    }
1160                }
1161            }
1162
1163            return renames;
1164        }
1165        
1166        /** Add a set of renames to a query.
1167         * @param names the list of field names
1168         * @param choice the ExecutionChoice actor
1169         * @param container the container of the fields. this may be the same as choice.
1170         * @param query the query dialog to add the gui widgets to
1171         * @param noneMessage the text to display in the query if no fields are added.
1172         */
1173        @Override
1174        protected void _addFields(List<String> names, ExecutionChoice choice, 
1175                NamedObj container, Query query, String noneMessage) {
1176             
1177            if(!names.isEmpty()) {
1178                String[] namesArray = names.toArray(new String[names.size()]);
1179                Arrays.sort(namesArray);
1180                for(String name : names) {
1181                    query.addTextArea(name, name, name, _STRING_MODE_BACKGROUND_COLOR,
1182                            Color.BLACK, 1, Query.DEFAULT_ENTRY_WIDTH);
1183                }               
1184            } else {
1185                query.addText(noneMessage, Color.BLACK, SwingConstants.LEFT);
1186            }
1187        }
1188        
1189    }
1190    
1191    /** A pane to enter the name of an execution choice. */
1192    private static class ImportPane extends JPanel {
1193        
1194        /** Create a new ImportPane with the default name for the
1195         *  imported execution choice.
1196         */
1197        public ImportPane(String defaultName) {
1198                
1199                add(new JLabel("Execution Choice Name:"));
1200                
1201                _nameTextField = new JTextField(defaultName);
1202                add(_nameTextField);
1203        }
1204        
1205        /** Get the name of the execution choice. */
1206        public String getChoiceName() {
1207                return _nameTextField.getText();
1208        }
1209        
1210        /** A text field to enter the name. */
1211        private JTextField _nameTextField;
1212        
1213    }
1214    
1215    /** A pane to export an execution choice. */
1216    private static class ExportPane extends JPanel {
1217
1218        public ExportPane(ExecutionChoice choice) {
1219            
1220            add(new JLabel("Execution Choice:"));
1221            
1222            _choiceComboBox = new JComboBox<String>(choice.getExecutionChoiceNames().toArray(new String[0]));
1223            add(_choiceComboBox);
1224        }
1225
1226        /** Get the name of the selected execution choice. */
1227        public String getChoiceName() {
1228            return (String) _choiceComboBox.getSelectedItem();
1229        }
1230
1231        private JComboBox<String> _choiceComboBox;
1232    }
1233    
1234    private static class ArgumentsPane extends FieldsPane {
1235        
1236        public ArgumentsPane(ExecutionChoice choice) throws IllegalActionException {
1237            super(choice, false, false);            
1238        }
1239
1240        /** Update the argument parameters with new values from the dialog. */
1241        public void applyChanges() throws IllegalActionException, NameDuplicationException {
1242            
1243            for(Map.Entry<NamedObj, Query> entry : _queries.entrySet()) {
1244                final NamedObj container = entry.getKey();
1245                final Query query = entry.getValue();
1246
1247                Set<String> names = new HashSet<String>();
1248                if(container == _choice) {
1249                    // add inputs for file types
1250                    for(String inputName : _choice.getInputNames(false)) {
1251                        if(ExecutionChoice.getPortIOType(_choice.getPort(inputName))
1252                                == ExecutionChoice.IOType.File) {
1253                            names.add(inputName);
1254                        }
1255                    }
1256                    
1257                    // add output for file types
1258                    for(String outputName : _choice.getOutputNames(false)) {
1259                        if(ExecutionChoice.getPortIOType(_choice.getPort(outputName))
1260                                == ExecutionChoice.IOType.File) {
1261                            names.add(outputName);
1262                        }
1263                    }
1264                    
1265                    // add parameters
1266                    names.addAll(_choice.getParameterNames());
1267                } else {
1268                    // add the parameter names in the refinement
1269                    List<Parameter> parameters = container.attributeList(Parameter.class);
1270                    for(Parameter parameter : parameters) {
1271                        String name = parameter.getName();
1272                        if(!name.equals(ExecutionChoice.COMMAND_LINE_NAME) &&
1273                                !name.startsWith("_")) {
1274                            names.add(name);
1275                        }
1276                    }
1277                }
1278                
1279                // see if any values in the query were changed
1280                for(String name : names) {
1281                    String argument = ExecutionChoice.getArgument(container, name);
1282                    String newArgument = query.getStringValue(name);
1283                    if((argument == null && !newArgument.trim().isEmpty()) ||
1284                            (argument != null && !argument.equals(newArgument))) {
1285                        Parameter parameter = (Parameter) container.getAttribute(name);
1286                        ExecutionChoice.setArgument(parameter, newArgument);
1287                        //System.out.println(name + " changed " + argument + " to " + newArgument);
1288                    }
1289                }
1290            }
1291        }
1292        
1293        /** Add a set of arguments to a query.
1294         *  @param names the names of the components containing the arguments
1295         *  @param choice the ExecutionChoice containing the components with arguments.
1296         *  @param query the query in which to add the fields
1297         *  @param noneMessage the text to add to the query if names is empty.
1298         * 
1299         */
1300        @Override
1301        protected void _addFields(List<String> names, ExecutionChoice choice,
1302                NamedObj container, Query query, String noneMessage) throws IllegalActionException {
1303                 
1304            if(!names.isEmpty()) {
1305                    String[] namesArray = names.toArray(new String[names.size()]);
1306                    Arrays.sort(namesArray);
1307                    for(String name : names) {
1308                        String argument = ExecutionChoice.getArgument(container, name);
1309                        query.addTextArea(name,
1310                                name,
1311                                argument,
1312                                _STRING_MODE_BACKGROUND_COLOR,
1313                                Color.black,
1314                                1,
1315                                Query.DEFAULT_ENTRY_WIDTH);
1316                    }               
1317            } else {
1318                query.addText(noneMessage, Color.BLACK, SwingConstants.LEFT);
1319            }
1320        }
1321                
1322    }
1323    
1324    /** A dialog for changing the types of inputs, outputs, and parameters. */
1325    private static class TypesPane extends FieldsPane {
1326        
1327        public TypesPane(ExecutionChoice choice) throws IllegalActionException {
1328            super(choice, false, true);
1329        }
1330        
1331        /** Change the types. */
1332        public void applyChanges() throws IllegalActionException, NameDuplicationException {
1333            
1334            Query query = _queries.get(_choice);
1335            
1336            List<Port> ports = new LinkedList<Port>(_choice.portList());
1337            
1338            for(Port port : ports) {
1339                if(port != _choice.control.getPort()) {
1340                        String newTypeStr = query.getStringValue(port.getName());
1341                        ExecutionChoice.IOType newType = ExecutionChoice.IOType.valueOf(newTypeStr);
1342                        // see if the types are different
1343                        if(ExecutionChoice.getPortIOType(port) != newType) {
1344                                _choice.setPortIOType((TypedIOPort)port, newType);
1345                        }
1346                }
1347            }
1348
1349            for(String name : _choice.getParameterNames()) {
1350                String newTypeStr = query.getStringValue(name);
1351                ExecutionChoice.ParameterType newType = ExecutionChoice.ParameterType.valueOf(newTypeStr);
1352                // see if the types are different
1353                if(_choice.getParameterType(name) != newType) {
1354                        _choice.setParameterType(name, newType);
1355                }
1356            }
1357            
1358            // get the type changes for parameters in refinements
1359            for(String executionName : _choice.getExecutionChoiceNames()) {
1360                ComponentEntity<?> container = _choice.getEntity(executionName);
1361                query = _queries.get(container);
1362                
1363                for(Parameter parameter : container.attributeList(Parameter.class)) {
1364                    String name = parameter.getName();
1365                    if(!name.equals(ExecutionChoice.COMMAND_LINE_NAME) &&
1366                            !name.startsWith("_")) {
1367                        String newTypeStr = query.getStringValue(name);
1368                        ExecutionChoice.ParameterType newType = ExecutionChoice.ParameterType.valueOf(newTypeStr);
1369                        // see if the types are different
1370                        if(ExecutionChoice.getParameterType(container, name) != newType) {
1371                                ExecutionChoice.setParameterType(container, name, newType);
1372                        }
1373                    }
1374                }
1375            }
1376        }
1377        
1378        /** Add a set of fields and their types to a query.
1379         *  @param names the names of the fields
1380         *  @param choice the ExecutionChoice containing the fields.
1381         *  @param container the container of the fields. this may be the same as choice.
1382         *  @param query the query in which to add the fields
1383         *  @param noneMessage the text to add to the query if names is empty.
1384         */
1385        @Override
1386        protected void _addFields(List<String> names, ExecutionChoice choice,
1387                NamedObj container, Query query, String noneMessage) throws IllegalActionException {
1388             
1389            if(!names.isEmpty()) {
1390                String[] namesArray = names.toArray(new String[names.size()]);
1391                Arrays.sort(namesArray);
1392                for(String name : names) {
1393                    
1394                        boolean added = false;
1395                        if(container == choice) {
1396                                Port port = choice.getPort(name);
1397                                // see if the name belongs to a port or a parameter.
1398                                if(port != null) {
1399                                        ExecutionChoice.IOType type = ExecutionChoice.getPortIOType(port);
1400                                        query.addChoice(name, name, ExecutionChoice.IOType.values(), type);
1401                                        added = true;
1402                                }
1403                        }
1404                        
1405                    if(!added) {
1406                        ExecutionChoice.ParameterType type = ExecutionChoice.getParameterType(container, name);
1407                        query.addChoice(name, name, ExecutionChoice.ParameterType.values(), type);
1408                    }
1409                }               
1410            } else {
1411                query.addText(noneMessage, Color.BLACK, SwingConstants.LEFT);
1412            }
1413        }
1414    }
1415    
1416    /** A base class to display a pane for the inputs, outputs, parameters,
1417     *  and sub-workflows.
1418     */
1419    private static abstract class FieldsPane extends JPanel {
1420        
1421        /** Create a new pane listing the fields for an ExecutionChoice actor.
1422         * @param choice the ExecutionChoice actor 
1423         * @param includeChoices if true, include the list of refinements
1424         * @param includeDataPorts if true, the list of inputs and outputs
1425         * are the data and file ports. otherwise, the list is the file ports.
1426         */
1427        private FieldsPane(ExecutionChoice choice, boolean includeChoices, boolean includeDataPorts)
1428                throws IllegalActionException {
1429            
1430            _choice = choice;
1431            
1432            Query query = new Query();
1433            _queries.put(choice, query);
1434                              
1435            // NOTE: use empty spaces here to make the dialog wider otherwise the tabs
1436            // for refinements are stacked (linux) or do not appear (mac).
1437            
1438            // add inputs
1439            query.addText("File Input Parameters                                                              ",
1440                        Color.BLACK, SwingConstants.LEFT);
1441            _addFields(choice.getInputNames(includeDataPorts), choice, choice, query, "None");
1442            
1443            // add outputs
1444            query.addSeparator();
1445            query.addText("File Output Parameters                                                              ",
1446                        Color.BLACK, SwingConstants.LEFT);
1447            _addFields(choice.getOutputNames(includeDataPorts), choice, choice, query, "None");
1448            
1449            // add parameters
1450            query.addSeparator();
1451            query.addText("Additional Parameters                                                              ",
1452                        Color.BLACK, SwingConstants.LEFT);
1453            _addFields(choice.getParameterNames(), choice, choice, query, "None");
1454            
1455            // add execution choices
1456            if(includeChoices) {
1457                query.addSeparator();
1458                query.addText("Execution Choices", Color.BLACK, SwingConstants.LEFT);
1459                _addFields(choice.getExecutionChoiceNames(), choice, choice, query, "None");
1460            }
1461            
1462            JTabbedPane tabbedPane = new JTabbedPane();
1463            tabbedPane.addTab("Shared Options", query);
1464
1465            // add a tab for each refinement
1466            
1467            for(String executionName : choice.getExecutionChoiceNames()) {
1468                query = new Query();
1469                final ComponentEntity<?> container = choice.getEntity(executionName);
1470                _queries.put(container, query);
1471                
1472                // get the names and sort them
1473                final List<String> names = new LinkedList<String>();
1474                final List<Parameter> parameters = container.attributeList(Parameter.class);
1475                for(Parameter parameter : parameters) {
1476                    String name = parameter.getName();
1477                    if(!name.equals(ExecutionChoice.COMMAND_LINE_NAME) &&
1478                            !name.startsWith("_")) {
1479                        names.add(parameter.getName());
1480                    }
1481                }
1482                _addFields(names, choice, container, query, "No parameters.");
1483                
1484                tabbedPane.addTab(executionName, query);
1485            }
1486            
1487            add(tabbedPane);    
1488
1489        }
1490        
1491        /** Add the fields for a set of names.
1492         * @param names the list of field names
1493         * @param choice the ExecutionChoice actor
1494         * @param container the container of the fields. this may be the same as choice.
1495         * @param query the query dialog to add the gui widgets to
1496         * @param noneMessage the text to display in the query if no fields are added.
1497         */
1498        protected abstract void _addFields(List<String> names, ExecutionChoice choice,
1499                NamedObj container, Query query, String noneMessage) throws IllegalActionException;
1500        
1501        protected ExecutionChoice _choice;
1502        protected Map<NamedObj,Query> _queries = new HashMap<NamedObj,Query>(); 
1503
1504    }
1505    
1506    /** Background color for string mode edit boxes. */
1507    // FIXME copied from PtolemyQuery since private
1508    private static Color _STRING_MODE_BACKGROUND_COLOR = new Color(230, 255,
1509            255, 255);
1510
1511}